aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev/fsl_lbc.c
diff options
context:
space:
mode:
authorRoy Zang <tie-fei.zang@freescale.com>2010-10-18 03:22:31 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2010-10-25 10:40:54 -0400
commit3ab8f2a2e7011c5e83363b42950757e46ef06824 (patch)
treefba4b482e3a5e789dc884ebcc85a0329180f7ca1 /arch/powerpc/sysdev/fsl_lbc.c
parent1cd844fe43cb6464b34dea504930c1a15e4ad38d (diff)
P4080/eLBC: Make Freescale elbc interrupt common to elbc devices
Move Freescale elbc interrupt from nand driver to elbc driver. Then all elbc devices can use the interrupt instead of ONLY nand. For former nand driver, it had the two functions: 1. detecting nand flash partitions; 2. registering elbc interrupt. Now, second function is removed to fsl_lbc.c. Signed-off-by: Lan Chunhe-B25806 <b25806@freescale.com> Signed-off-by: Roy Zang <tie-fei.zang@freescale.com> Reviewed-by: Anton Vorontsov <cbouatmailru@gmail.com> Cc: Wood Scott-B07421 <B07421@freescale.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'arch/powerpc/sysdev/fsl_lbc.c')
-rw-r--r--arch/powerpc/sysdev/fsl_lbc.c231
1 files changed, 192 insertions, 39 deletions
diff --git a/arch/powerpc/sysdev/fsl_lbc.c b/arch/powerpc/sysdev/fsl_lbc.c
index dceb8d1a843d..91c9c53b1845 100644
--- a/arch/powerpc/sysdev/fsl_lbc.c
+++ b/arch/powerpc/sysdev/fsl_lbc.c
@@ -1,9 +1,12 @@
1/* 1/*
2 * Freescale LBC and UPM routines. 2 * Freescale LBC and UPM routines.
3 * 3 *
4 * Copyright (c) 2007-2008 MontaVista Software, Inc. 4 * Copyright © 2007-2008 MontaVista Software, Inc.
5 * Copyright © 2010 Freescale Semiconductor
5 * 6 *
6 * Author: Anton Vorontsov <avorontsov@ru.mvista.com> 7 * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
8 * Author: Jack Lan <Jack.Lan@freescale.com>
9 * Author: Roy Zang <tie-fei.zang@freescale.com>
7 * 10 *
8 * This program is free software; you can redistribute it and/or modify 11 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 12 * it under the terms of the GNU General Public License as published by
@@ -19,39 +22,16 @@
19#include <linux/types.h> 22#include <linux/types.h>
20#include <linux/io.h> 23#include <linux/io.h>
21#include <linux/of.h> 24#include <linux/of.h>
25#include <linux/slab.h>
26#include <linux/platform_device.h>
27#include <linux/interrupt.h>
28#include <linux/mod_devicetable.h>
22#include <asm/prom.h> 29#include <asm/prom.h>
23#include <asm/fsl_lbc.h> 30#include <asm/fsl_lbc.h>
24 31
25static spinlock_t fsl_lbc_lock = __SPIN_LOCK_UNLOCKED(fsl_lbc_lock); 32static spinlock_t fsl_lbc_lock = __SPIN_LOCK_UNLOCKED(fsl_lbc_lock);
26static struct fsl_lbc_regs __iomem *fsl_lbc_regs; 33struct fsl_lbc_ctrl *fsl_lbc_ctrl_dev;
27 34EXPORT_SYMBOL(fsl_lbc_ctrl_dev);
28static char __initdata *compat_lbc[] = {
29 "fsl,pq2-localbus",
30 "fsl,pq2pro-localbus",
31 "fsl,pq3-localbus",
32 "fsl,elbc",
33};
34
35static int __init fsl_lbc_init(void)
36{
37 struct device_node *lbus;
38 int i;
39
40 for (i = 0; i < ARRAY_SIZE(compat_lbc); i++) {
41 lbus = of_find_compatible_node(NULL, NULL, compat_lbc[i]);
42 if (lbus)
43 goto found;
44 }
45 return -ENODEV;
46
47found:
48 fsl_lbc_regs = of_iomap(lbus, 0);
49 of_node_put(lbus);
50 if (!fsl_lbc_regs)
51 return -ENOMEM;
52 return 0;
53}
54arch_initcall(fsl_lbc_init);
55 35
56/** 36/**
57 * fsl_lbc_find - find Localbus bank 37 * fsl_lbc_find - find Localbus bank
@@ -65,13 +45,15 @@ arch_initcall(fsl_lbc_init);
65int fsl_lbc_find(phys_addr_t addr_base) 45int fsl_lbc_find(phys_addr_t addr_base)
66{ 46{
67 int i; 47 int i;
48 struct fsl_lbc_regs __iomem *lbc;
68 49
69 if (!fsl_lbc_regs) 50 if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
70 return -ENODEV; 51 return -ENODEV;
71 52
72 for (i = 0; i < ARRAY_SIZE(fsl_lbc_regs->bank); i++) { 53 lbc = fsl_lbc_ctrl_dev->regs;
73 __be32 br = in_be32(&fsl_lbc_regs->bank[i].br); 54 for (i = 0; i < ARRAY_SIZE(lbc->bank); i++) {
74 __be32 or = in_be32(&fsl_lbc_regs->bank[i].or); 55 __be32 br = in_be32(&lbc->bank[i].br);
56 __be32 or = in_be32(&lbc->bank[i].or);
75 57
76 if (br & BR_V && (br & or & BR_BA) == addr_base) 58 if (br & BR_V && (br & or & BR_BA) == addr_base)
77 return i; 59 return i;
@@ -94,22 +76,27 @@ int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm)
94{ 76{
95 int bank; 77 int bank;
96 __be32 br; 78 __be32 br;
79 struct fsl_lbc_regs __iomem *lbc;
97 80
98 bank = fsl_lbc_find(addr_base); 81 bank = fsl_lbc_find(addr_base);
99 if (bank < 0) 82 if (bank < 0)
100 return bank; 83 return bank;
101 84
102 br = in_be32(&fsl_lbc_regs->bank[bank].br); 85 if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
86 return -ENODEV;
87
88 lbc = fsl_lbc_ctrl_dev->regs;
89 br = in_be32(&lbc->bank[bank].br);
103 90
104 switch (br & BR_MSEL) { 91 switch (br & BR_MSEL) {
105 case BR_MS_UPMA: 92 case BR_MS_UPMA:
106 upm->mxmr = &fsl_lbc_regs->mamr; 93 upm->mxmr = &lbc->mamr;
107 break; 94 break;
108 case BR_MS_UPMB: 95 case BR_MS_UPMB:
109 upm->mxmr = &fsl_lbc_regs->mbmr; 96 upm->mxmr = &lbc->mbmr;
110 break; 97 break;
111 case BR_MS_UPMC: 98 case BR_MS_UPMC:
112 upm->mxmr = &fsl_lbc_regs->mcmr; 99 upm->mxmr = &lbc->mcmr;
113 break; 100 break;
114 default: 101 default:
115 return -EINVAL; 102 return -EINVAL;
@@ -148,9 +135,12 @@ int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar)
148 int ret = 0; 135 int ret = 0;
149 unsigned long flags; 136 unsigned long flags;
150 137
138 if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
139 return -ENODEV;
140
151 spin_lock_irqsave(&fsl_lbc_lock, flags); 141 spin_lock_irqsave(&fsl_lbc_lock, flags);
152 142
153 out_be32(&fsl_lbc_regs->mar, mar); 143 out_be32(&fsl_lbc_ctrl_dev->regs->mar, mar);
154 144
155 switch (upm->width) { 145 switch (upm->width) {
156 case 8: 146 case 8:
@@ -172,3 +162,166 @@ int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar)
172 return ret; 162 return ret;
173} 163}
174EXPORT_SYMBOL(fsl_upm_run_pattern); 164EXPORT_SYMBOL(fsl_upm_run_pattern);
165
166static int __devinit fsl_lbc_ctrl_init(struct fsl_lbc_ctrl *ctrl)
167{
168 struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
169
170 /* clear event registers */
171 setbits32(&lbc->ltesr, LTESR_CLEAR);
172 out_be32(&lbc->lteatr, 0);
173 out_be32(&lbc->ltear, 0);
174 out_be32(&lbc->lteccr, LTECCR_CLEAR);
175 out_be32(&lbc->ltedr, LTEDR_ENABLE);
176
177 /* Enable interrupts for any detected events */
178 out_be32(&lbc->lteir, LTEIR_ENABLE);
179
180 return 0;
181}
182
183/*
184 * NOTE: This interrupt is used to report localbus events of various kinds,
185 * such as transaction errors on the chipselects.
186 */
187
188static irqreturn_t fsl_lbc_ctrl_irq(int irqno, void *data)
189{
190 struct fsl_lbc_ctrl *ctrl = data;
191 struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
192 u32 status;
193
194 status = in_be32(&lbc->ltesr);
195 if (!status)
196 return IRQ_NONE;
197
198 out_be32(&lbc->ltesr, LTESR_CLEAR);
199 out_be32(&lbc->lteatr, 0);
200 out_be32(&lbc->ltear, 0);
201 ctrl->irq_status = status;
202
203 if (status & LTESR_BM)
204 dev_err(ctrl->dev, "Local bus monitor time-out: "
205 "LTESR 0x%08X\n", status);
206 if (status & LTESR_WP)
207 dev_err(ctrl->dev, "Write protect error: "
208 "LTESR 0x%08X\n", status);
209 if (status & LTESR_ATMW)
210 dev_err(ctrl->dev, "Atomic write error: "
211 "LTESR 0x%08X\n", status);
212 if (status & LTESR_ATMR)
213 dev_err(ctrl->dev, "Atomic read error: "
214 "LTESR 0x%08X\n", status);
215 if (status & LTESR_CS)
216 dev_err(ctrl->dev, "Chip select error: "
217 "LTESR 0x%08X\n", status);
218 if (status & LTESR_UPM)
219 ;
220 if (status & LTESR_FCT) {
221 dev_err(ctrl->dev, "FCM command time-out: "
222 "LTESR 0x%08X\n", status);
223 smp_wmb();
224 wake_up(&ctrl->irq_wait);
225 }
226 if (status & LTESR_PAR) {
227 dev_err(ctrl->dev, "Parity or Uncorrectable ECC error: "
228 "LTESR 0x%08X\n", status);
229 smp_wmb();
230 wake_up(&ctrl->irq_wait);
231 }
232 if (status & LTESR_CC) {
233 smp_wmb();
234 wake_up(&ctrl->irq_wait);
235 }
236 if (status & ~LTESR_MASK)
237 dev_err(ctrl->dev, "Unknown error: "
238 "LTESR 0x%08X\n", status);
239 return IRQ_HANDLED;
240}
241
242/*
243 * fsl_lbc_ctrl_probe
244 *
245 * called by device layer when it finds a device matching
246 * one our driver can handled. This code allocates all of
247 * the resources needed for the controller only. The
248 * resources for the NAND banks themselves are allocated
249 * in the chip probe function.
250*/
251
252static int __devinit fsl_lbc_ctrl_probe(struct platform_device *dev)
253{
254 int ret;
255
256 if (!dev->dev.of_node) {
257 dev_err(&dev->dev, "Device OF-Node is NULL");
258 return -EFAULT;
259 }
260
261 fsl_lbc_ctrl_dev = kzalloc(sizeof(*fsl_lbc_ctrl_dev), GFP_KERNEL);
262 if (!fsl_lbc_ctrl_dev)
263 return -ENOMEM;
264
265 dev_set_drvdata(&dev->dev, fsl_lbc_ctrl_dev);
266
267 spin_lock_init(&fsl_lbc_ctrl_dev->lock);
268 init_waitqueue_head(&fsl_lbc_ctrl_dev->irq_wait);
269
270 fsl_lbc_ctrl_dev->regs = of_iomap(dev->dev.of_node, 0);
271 if (!fsl_lbc_ctrl_dev->regs) {
272 dev_err(&dev->dev, "failed to get memory region\n");
273 ret = -ENODEV;
274 goto err;
275 }
276
277 fsl_lbc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0);
278 if (fsl_lbc_ctrl_dev->irq == NO_IRQ) {
279 dev_err(&dev->dev, "failed to get irq resource\n");
280 ret = -ENODEV;
281 goto err;
282 }
283
284 fsl_lbc_ctrl_dev->dev = &dev->dev;
285
286 ret = fsl_lbc_ctrl_init(fsl_lbc_ctrl_dev);
287 if (ret < 0)
288 goto err;
289
290 ret = request_irq(fsl_lbc_ctrl_dev->irq, fsl_lbc_ctrl_irq, 0,
291 "fsl-lbc", fsl_lbc_ctrl_dev);
292 if (ret != 0) {
293 dev_err(&dev->dev, "failed to install irq (%d)\n",
294 fsl_lbc_ctrl_dev->irq);
295 ret = fsl_lbc_ctrl_dev->irq;
296 goto err;
297 }
298
299 return 0;
300
301err:
302 iounmap(fsl_lbc_ctrl_dev->regs);
303 kfree(fsl_lbc_ctrl_dev);
304 return ret;
305}
306
307static const struct of_device_id fsl_lbc_match[] = {
308 { .compatible = "fsl,elbc", },
309 { .compatible = "fsl,pq3-localbus", },
310 { .compatible = "fsl,pq2-localbus", },
311 { .compatible = "fsl,pq2pro-localbus", },
312 {},
313};
314
315static struct platform_driver fsl_lbc_ctrl_driver = {
316 .driver = {
317 .name = "fsl-lbc",
318 .of_match_table = fsl_lbc_match,
319 },
320 .probe = fsl_lbc_ctrl_probe,
321};
322
323static int __init fsl_lbc_init(void)
324{
325 return platform_driver_register(&fsl_lbc_ctrl_driver);
326}
327module_init(fsl_lbc_init);