aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev
diff options
context:
space:
mode:
authorPrabhakar Kushwaha <prabhakar@freescale.com>2011-12-27 07:09:13 -0500
committerKumar Gala <galak@kernel.crashing.org>2012-01-04 16:41:22 -0500
commita20cbdeffce247a2b6fb83cd8d22433994068565 (patch)
tree119cc7b52f56aecfe871e24580291eedefecb555 /arch/powerpc/sysdev
parentf706bed1144e0fdad2b583549fc366afd4a1e9f1 (diff)
powerpc/fsl: Add support for Integrated Flash Controller
Integrated Flash Controller supports various flashes like NOR, NAND and other devices using NOR, NAND and GPCM Machine available on it. IFC supports four chip selects. Signed-off-by: Dipen Dudhat <Dipen.Dudhat@freescale.com> Signed-off-by: Scott Wood <scottwood@freescale.com> Signed-off-by: Li Yang <leoli@freescale.com> Signed-off-by: Liu Shuo <b35362@freescale.com> Signed-off-by: Prabhakar Kushwaha <prabhakar@freescale.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/sysdev')
-rw-r--r--arch/powerpc/sysdev/Makefile1
-rw-r--r--arch/powerpc/sysdev/fsl_ifc.c310
2 files changed, 311 insertions, 0 deletions
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 8dea5935b21f..5e37b4717864 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o
17obj-$(CONFIG_FSL_PCI) += fsl_pci.o $(fsl-msi-obj-y) 17obj-$(CONFIG_FSL_PCI) += fsl_pci.o $(fsl-msi-obj-y)
18obj-$(CONFIG_FSL_PMC) += fsl_pmc.o 18obj-$(CONFIG_FSL_PMC) += fsl_pmc.o
19obj-$(CONFIG_FSL_LBC) += fsl_lbc.o 19obj-$(CONFIG_FSL_LBC) += fsl_lbc.o
20obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
20obj-$(CONFIG_FSL_GTM) += fsl_gtm.o 21obj-$(CONFIG_FSL_GTM) += fsl_gtm.o
21obj-$(CONFIG_FSL_85XX_CACHE_SRAM) += fsl_85xx_l2ctlr.o fsl_85xx_cache_sram.o 22obj-$(CONFIG_FSL_85XX_CACHE_SRAM) += fsl_85xx_l2ctlr.o fsl_85xx_cache_sram.o
22obj-$(CONFIG_SIMPLE_GPIO) += simple_gpio.o 23obj-$(CONFIG_SIMPLE_GPIO) += simple_gpio.o
diff --git a/arch/powerpc/sysdev/fsl_ifc.c b/arch/powerpc/sysdev/fsl_ifc.c
new file mode 100644
index 000000000000..b31f19f61031
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_ifc.c
@@ -0,0 +1,310 @@
1/*
2 * Copyright 2011 Freescale Semiconductor, Inc
3 *
4 * Freescale Integrated Flash Controller
5 *
6 * Author: Dipen Dudhat <Dipen.Dudhat@freescale.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22#include <linux/init.h>
23#include <linux/module.h>
24#include <linux/kernel.h>
25#include <linux/compiler.h>
26#include <linux/spinlock.h>
27#include <linux/types.h>
28#include <linux/slab.h>
29#include <linux/io.h>
30#include <linux/of.h>
31#include <linux/of_device.h>
32#include <linux/platform_device.h>
33#include <asm/prom.h>
34#include <asm/fsl_ifc.h>
35
36struct fsl_ifc_ctrl *fsl_ifc_ctrl_dev;
37EXPORT_SYMBOL(fsl_ifc_ctrl_dev);
38
39/*
40 * convert_ifc_address - convert the base address
41 * @addr_base: base address of the memory bank
42 */
43unsigned int convert_ifc_address(phys_addr_t addr_base)
44{
45 return addr_base & CSPR_BA;
46}
47EXPORT_SYMBOL(convert_ifc_address);
48
49/*
50 * fsl_ifc_find - find IFC bank
51 * @addr_base: base address of the memory bank
52 *
53 * This function walks IFC banks comparing "Base address" field of the CSPR
54 * registers with the supplied addr_base argument. When bases match this
55 * function returns bank number (starting with 0), otherwise it returns
56 * appropriate errno value.
57 */
58int fsl_ifc_find(phys_addr_t addr_base)
59{
60 int i = 0;
61
62 if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->regs)
63 return -ENODEV;
64
65 for (i = 0; i < ARRAY_SIZE(fsl_ifc_ctrl_dev->regs->cspr_cs); i++) {
66 __be32 cspr = in_be32(&fsl_ifc_ctrl_dev->regs->cspr_cs[i].cspr);
67 if (cspr & CSPR_V && (cspr & CSPR_BA) ==
68 convert_ifc_address(addr_base))
69 return i;
70 }
71
72 return -ENOENT;
73}
74EXPORT_SYMBOL(fsl_ifc_find);
75
76static int __devinit fsl_ifc_ctrl_init(struct fsl_ifc_ctrl *ctrl)
77{
78 struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
79
80 /*
81 * Clear all the common status and event registers
82 */
83 if (in_be32(&ifc->cm_evter_stat) & IFC_CM_EVTER_STAT_CSER)
84 out_be32(&ifc->cm_evter_stat, IFC_CM_EVTER_STAT_CSER);
85
86 /* enable all error and events */
87 out_be32(&ifc->cm_evter_en, IFC_CM_EVTER_EN_CSEREN);
88
89 /* enable all error and event interrupts */
90 out_be32(&ifc->cm_evter_intr_en, IFC_CM_EVTER_INTR_EN_CSERIREN);
91 out_be32(&ifc->cm_erattr0, 0x0);
92 out_be32(&ifc->cm_erattr1, 0x0);
93
94 return 0;
95}
96
97static int fsl_ifc_ctrl_remove(struct platform_device *dev)
98{
99 struct fsl_ifc_ctrl *ctrl = dev_get_drvdata(&dev->dev);
100
101 free_irq(ctrl->nand_irq, ctrl);
102 free_irq(ctrl->irq, ctrl);
103
104 irq_dispose_mapping(ctrl->nand_irq);
105 irq_dispose_mapping(ctrl->irq);
106
107 iounmap(ctrl->regs);
108
109 dev_set_drvdata(&dev->dev, NULL);
110 kfree(ctrl);
111
112 return 0;
113}
114
115/*
116 * NAND events are split between an operational interrupt which only
117 * receives OPC, and an error interrupt that receives everything else,
118 * including non-NAND errors. Whichever interrupt gets to it first
119 * records the status and wakes the wait queue.
120 */
121static DEFINE_SPINLOCK(nand_irq_lock);
122
123static u32 check_nand_stat(struct fsl_ifc_ctrl *ctrl)
124{
125 struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
126 unsigned long flags;
127 u32 stat;
128
129 spin_lock_irqsave(&nand_irq_lock, flags);
130
131 stat = in_be32(&ifc->ifc_nand.nand_evter_stat);
132 if (stat) {
133 out_be32(&ifc->ifc_nand.nand_evter_stat, stat);
134 ctrl->nand_stat = stat;
135 wake_up(&ctrl->nand_wait);
136 }
137
138 spin_unlock_irqrestore(&nand_irq_lock, flags);
139
140 return stat;
141}
142
143static irqreturn_t fsl_ifc_nand_irq(int irqno, void *data)
144{
145 struct fsl_ifc_ctrl *ctrl = data;
146
147 if (check_nand_stat(ctrl))
148 return IRQ_HANDLED;
149
150 return IRQ_NONE;
151}
152
153/*
154 * NOTE: This interrupt is used to report ifc events of various kinds,
155 * such as transaction errors on the chipselects.
156 */
157static irqreturn_t fsl_ifc_ctrl_irq(int irqno, void *data)
158{
159 struct fsl_ifc_ctrl *ctrl = data;
160 struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
161 u32 err_axiid, err_srcid, status, cs_err, err_addr;
162 irqreturn_t ret = IRQ_NONE;
163
164 /* read for chip select error */
165 cs_err = in_be32(&ifc->cm_evter_stat);
166 if (cs_err) {
167 dev_err(ctrl->dev, "transaction sent to IFC is not mapped to"
168 "any memory bank 0x%08X\n", cs_err);
169 /* clear the chip select error */
170 out_be32(&ifc->cm_evter_stat, IFC_CM_EVTER_STAT_CSER);
171
172 /* read error attribute registers print the error information */
173 status = in_be32(&ifc->cm_erattr0);
174 err_addr = in_be32(&ifc->cm_erattr1);
175
176 if (status & IFC_CM_ERATTR0_ERTYP_READ)
177 dev_err(ctrl->dev, "Read transaction error"
178 "CM_ERATTR0 0x%08X\n", status);
179 else
180 dev_err(ctrl->dev, "Write transaction error"
181 "CM_ERATTR0 0x%08X\n", status);
182
183 err_axiid = (status & IFC_CM_ERATTR0_ERAID) >>
184 IFC_CM_ERATTR0_ERAID_SHIFT;
185 dev_err(ctrl->dev, "AXI ID of the error"
186 "transaction 0x%08X\n", err_axiid);
187
188 err_srcid = (status & IFC_CM_ERATTR0_ESRCID) >>
189 IFC_CM_ERATTR0_ESRCID_SHIFT;
190 dev_err(ctrl->dev, "SRC ID of the error"
191 "transaction 0x%08X\n", err_srcid);
192
193 dev_err(ctrl->dev, "Transaction Address corresponding to error"
194 "ERADDR 0x%08X\n", err_addr);
195
196 ret = IRQ_HANDLED;
197 }
198
199 if (check_nand_stat(ctrl))
200 ret = IRQ_HANDLED;
201
202 return ret;
203}
204
205/*
206 * fsl_ifc_ctrl_probe
207 *
208 * called by device layer when it finds a device matching
209 * one our driver can handled. This code allocates all of
210 * the resources needed for the controller only. The
211 * resources for the NAND banks themselves are allocated
212 * in the chip probe function.
213*/
214static int __devinit fsl_ifc_ctrl_probe(struct platform_device *dev)
215{
216 int ret = 0;
217
218
219 dev_info(&dev->dev, "Freescale Integrated Flash Controller\n");
220
221 fsl_ifc_ctrl_dev = kzalloc(sizeof(*fsl_ifc_ctrl_dev), GFP_KERNEL);
222 if (!fsl_ifc_ctrl_dev)
223 return -ENOMEM;
224
225 dev_set_drvdata(&dev->dev, fsl_ifc_ctrl_dev);
226
227 /* IOMAP the entire IFC region */
228 fsl_ifc_ctrl_dev->regs = of_iomap(dev->dev.of_node, 0);
229 if (!fsl_ifc_ctrl_dev->regs) {
230 dev_err(&dev->dev, "failed to get memory region\n");
231 ret = -ENODEV;
232 goto err;
233 }
234
235 /* get the Controller level irq */
236 fsl_ifc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0);
237 if (fsl_ifc_ctrl_dev->irq == NO_IRQ) {
238 dev_err(&dev->dev, "failed to get irq resource "
239 "for IFC\n");
240 ret = -ENODEV;
241 goto err;
242 }
243
244 /* get the nand machine irq */
245 fsl_ifc_ctrl_dev->nand_irq =
246 irq_of_parse_and_map(dev->dev.of_node, 1);
247 if (fsl_ifc_ctrl_dev->nand_irq == NO_IRQ) {
248 dev_err(&dev->dev, "failed to get irq resource "
249 "for NAND Machine\n");
250 ret = -ENODEV;
251 goto err;
252 }
253
254 fsl_ifc_ctrl_dev->dev = &dev->dev;
255
256 ret = fsl_ifc_ctrl_init(fsl_ifc_ctrl_dev);
257 if (ret < 0)
258 goto err;
259
260 init_waitqueue_head(&fsl_ifc_ctrl_dev->nand_wait);
261
262 ret = request_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_irq, IRQF_SHARED,
263 "fsl-ifc", fsl_ifc_ctrl_dev);
264 if (ret != 0) {
265 dev_err(&dev->dev, "failed to install irq (%d)\n",
266 fsl_ifc_ctrl_dev->irq);
267 goto err_irq;
268 }
269
270 ret = request_irq(fsl_ifc_ctrl_dev->nand_irq, fsl_ifc_nand_irq, 0,
271 "fsl-ifc-nand", fsl_ifc_ctrl_dev);
272 if (ret != 0) {
273 dev_err(&dev->dev, "failed to install irq (%d)\n",
274 fsl_ifc_ctrl_dev->nand_irq);
275 goto err_nandirq;
276 }
277
278 return 0;
279
280err_nandirq:
281 free_irq(fsl_ifc_ctrl_dev->nand_irq, fsl_ifc_ctrl_dev);
282 irq_dispose_mapping(fsl_ifc_ctrl_dev->nand_irq);
283err_irq:
284 free_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_dev);
285 irq_dispose_mapping(fsl_ifc_ctrl_dev->irq);
286err:
287 return ret;
288}
289
290static const struct of_device_id fsl_ifc_match[] = {
291 {
292 .compatible = "fsl,ifc",
293 },
294 {},
295};
296
297static struct platform_driver fsl_ifc_ctrl_driver = {
298 .driver = {
299 .name = "fsl-ifc",
300 .of_match_table = fsl_ifc_match,
301 },
302 .probe = fsl_ifc_ctrl_probe,
303 .remove = fsl_ifc_ctrl_remove,
304};
305
306module_platform_driver(fsl_ifc_ctrl_driver);
307
308MODULE_LICENSE("GPL");
309MODULE_AUTHOR("Freescale Semiconductor");
310MODULE_DESCRIPTION("Freescale Integrated Flash Controller driver");