Commit | Line | Data |
---|---|---|
af3855dd SA |
1 | /* |
2 | * Copyright 2015 Simon Arlott | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License version 2 as | |
6 | * published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, | |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | * GNU General Public License for more details. | |
12 | * | |
13 | * Derived from bcm63138_nand.c: | |
14 | * Copyright © 2015 Broadcom Corporation | |
15 | * | |
16 | * Derived from bcm963xx_4.12L.06B_consumer/shared/opensource/include/bcm963xx/63268_map_part.h: | |
17 | * Copyright 2000-2010 Broadcom Corporation | |
18 | * | |
19 | * Derived from bcm963xx_4.12L.06B_consumer/shared/opensource/flash/nandflash.c: | |
20 | * Copyright 2000-2010 Broadcom Corporation | |
21 | */ | |
22 | ||
23 | #include <linux/device.h> | |
24 | #include <linux/io.h> | |
25 | #include <linux/ioport.h> | |
26 | #include <linux/module.h> | |
27 | #include <linux/of.h> | |
28 | #include <linux/of_address.h> | |
29 | #include <linux/platform_device.h> | |
30 | #include <linux/slab.h> | |
31 | ||
32 | #include "brcmnand.h" | |
33 | ||
34 | struct bcm6368_nand_soc { | |
35 | struct brcmnand_soc soc; | |
36 | void __iomem *base; | |
37 | }; | |
38 | ||
39 | #define BCM6368_NAND_INT 0x00 | |
40 | #define BCM6368_NAND_STATUS_SHIFT 0 | |
41 | #define BCM6368_NAND_STATUS_MASK (0xfff << BCM6368_NAND_STATUS_SHIFT) | |
42 | #define BCM6368_NAND_ENABLE_SHIFT 16 | |
43 | #define BCM6368_NAND_ENABLE_MASK (0xffff << BCM6368_NAND_ENABLE_SHIFT) | |
44 | #define BCM6368_NAND_BASE_ADDR0 0x04 | |
45 | #define BCM6368_NAND_BASE_ADDR1 0x0c | |
46 | ||
47 | enum { | |
48 | BCM6368_NP_READ = BIT(0), | |
49 | BCM6368_BLOCK_ERASE = BIT(1), | |
50 | BCM6368_COPY_BACK = BIT(2), | |
51 | BCM6368_PAGE_PGM = BIT(3), | |
52 | BCM6368_CTRL_READY = BIT(4), | |
53 | BCM6368_DEV_RBPIN = BIT(5), | |
54 | BCM6368_ECC_ERR_UNC = BIT(6), | |
55 | BCM6368_ECC_ERR_CORR = BIT(7), | |
56 | }; | |
57 | ||
58 | static bool bcm6368_nand_intc_ack(struct brcmnand_soc *soc) | |
59 | { | |
60 | struct bcm6368_nand_soc *priv = | |
61 | container_of(soc, struct bcm6368_nand_soc, soc); | |
62 | void __iomem *mmio = priv->base + BCM6368_NAND_INT; | |
63 | u32 val = brcmnand_readl(mmio); | |
64 | ||
65 | if (val & (BCM6368_CTRL_READY << BCM6368_NAND_STATUS_SHIFT)) { | |
66 | /* Ack interrupt */ | |
67 | val &= ~BCM6368_NAND_STATUS_MASK; | |
68 | val |= BCM6368_CTRL_READY << BCM6368_NAND_STATUS_SHIFT; | |
69 | brcmnand_writel(val, mmio); | |
70 | return true; | |
71 | } | |
72 | ||
73 | return false; | |
74 | } | |
75 | ||
76 | static void bcm6368_nand_intc_set(struct brcmnand_soc *soc, bool en) | |
77 | { | |
78 | struct bcm6368_nand_soc *priv = | |
79 | container_of(soc, struct bcm6368_nand_soc, soc); | |
80 | void __iomem *mmio = priv->base + BCM6368_NAND_INT; | |
81 | u32 val = brcmnand_readl(mmio); | |
82 | ||
83 | /* Don't ack any interrupts */ | |
84 | val &= ~BCM6368_NAND_STATUS_MASK; | |
85 | ||
86 | if (en) | |
87 | val |= BCM6368_CTRL_READY << BCM6368_NAND_ENABLE_SHIFT; | |
88 | else | |
89 | val &= ~(BCM6368_CTRL_READY << BCM6368_NAND_ENABLE_SHIFT); | |
90 | ||
91 | brcmnand_writel(val, mmio); | |
92 | } | |
93 | ||
94 | static int bcm6368_nand_probe(struct platform_device *pdev) | |
95 | { | |
96 | struct device *dev = &pdev->dev; | |
97 | struct bcm6368_nand_soc *priv; | |
98 | struct brcmnand_soc *soc; | |
99 | struct resource *res; | |
100 | ||
101 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | |
102 | if (!priv) | |
103 | return -ENOMEM; | |
104 | soc = &priv->soc; | |
105 | ||
106 | res = platform_get_resource_byname(pdev, | |
107 | IORESOURCE_MEM, "nand-int-base"); | |
af3855dd SA |
108 | priv->base = devm_ioremap_resource(dev, res); |
109 | if (IS_ERR(priv->base)) | |
110 | return PTR_ERR(priv->base); | |
111 | ||
112 | soc->ctlrdy_ack = bcm6368_nand_intc_ack; | |
113 | soc->ctlrdy_set_enabled = bcm6368_nand_intc_set; | |
114 | ||
115 | /* Disable and ack all interrupts */ | |
116 | brcmnand_writel(0, priv->base + BCM6368_NAND_INT); | |
117 | brcmnand_writel(BCM6368_NAND_STATUS_MASK, | |
118 | priv->base + BCM6368_NAND_INT); | |
119 | ||
120 | return brcmnand_probe(pdev, soc); | |
121 | } | |
122 | ||
123 | static const struct of_device_id bcm6368_nand_of_match[] = { | |
124 | { .compatible = "brcm,nand-bcm6368" }, | |
125 | {}, | |
126 | }; | |
127 | MODULE_DEVICE_TABLE(of, bcm6368_nand_of_match); | |
128 | ||
129 | static struct platform_driver bcm6368_nand_driver = { | |
130 | .probe = bcm6368_nand_probe, | |
131 | .remove = brcmnand_remove, | |
132 | .driver = { | |
133 | .name = "bcm6368_nand", | |
134 | .pm = &brcmnand_pm_ops, | |
135 | .of_match_table = bcm6368_nand_of_match, | |
136 | } | |
137 | }; | |
138 | module_platform_driver(bcm6368_nand_driver); | |
139 | ||
140 | MODULE_LICENSE("GPL"); | |
141 | MODULE_AUTHOR("Simon Arlott"); | |
142 | MODULE_DESCRIPTION("NAND driver for BCM6368"); |