aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
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
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')
-rw-r--r--arch/powerpc/Kconfig7
-rw-r--r--arch/powerpc/include/asm/fsl_lbc.h33
-rw-r--r--arch/powerpc/sysdev/fsl_lbc.c231
3 files changed, 228 insertions, 43 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 631e5a0fb6ab..44df1bac9701 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -687,9 +687,12 @@ config 4xx_SOC
687 bool 687 bool
688 688
689config FSL_LBC 689config FSL_LBC
690 bool 690 bool "Freescale Local Bus support"
691 depends on FSL_SOC
691 help 692 help
692 Freescale Localbus support 693 Enables reporting of errors from the Freescale local bus
694 controller. Also contains some common code used by
695 drivers for specific local bus peripherals.
693 696
694config FSL_GTM 697config FSL_GTM
695 bool 698 bool
diff --git a/arch/powerpc/include/asm/fsl_lbc.h b/arch/powerpc/include/asm/fsl_lbc.h
index 1b5a21041f9b..06a11124dde1 100644
--- a/arch/powerpc/include/asm/fsl_lbc.h
+++ b/arch/powerpc/include/asm/fsl_lbc.h
@@ -1,9 +1,10 @@
1/* Freescale Local Bus Controller 1/* Freescale Local Bus Controller
2 * 2 *
3 * Copyright (c) 2006-2007 Freescale Semiconductor 3 * Copyright © 2006-2007, 2010 Freescale Semiconductor
4 * 4 *
5 * Authors: Nick Spence <nick.spence@freescale.com>, 5 * Authors: Nick Spence <nick.spence@freescale.com>,
6 * Scott Wood <scottwood@freescale.com> 6 * Scott Wood <scottwood@freescale.com>
7 * Jack Lan <jack.lan@freescale.com>
7 * 8 *
8 * This program is free software; you can redistribute it and/or modify 9 * 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 10 * it under the terms of the GNU General Public License as published by
@@ -26,6 +27,8 @@
26#include <linux/compiler.h> 27#include <linux/compiler.h>
27#include <linux/types.h> 28#include <linux/types.h>
28#include <linux/io.h> 29#include <linux/io.h>
30#include <linux/device.h>
31#include <linux/spinlock.h>
29 32
30struct fsl_lbc_bank { 33struct fsl_lbc_bank {
31 __be32 br; /**< Base Register */ 34 __be32 br; /**< Base Register */
@@ -125,13 +128,23 @@ struct fsl_lbc_regs {
125#define LTESR_ATMW 0x00800000 128#define LTESR_ATMW 0x00800000
126#define LTESR_ATMR 0x00400000 129#define LTESR_ATMR 0x00400000
127#define LTESR_CS 0x00080000 130#define LTESR_CS 0x00080000
131#define LTESR_UPM 0x00000002
128#define LTESR_CC 0x00000001 132#define LTESR_CC 0x00000001
129#define LTESR_NAND_MASK (LTESR_FCT | LTESR_PAR | LTESR_CC) 133#define LTESR_NAND_MASK (LTESR_FCT | LTESR_PAR | LTESR_CC)
134#define LTESR_MASK (LTESR_BM | LTESR_FCT | LTESR_PAR | LTESR_WP \
135 | LTESR_ATMW | LTESR_ATMR | LTESR_CS | LTESR_UPM \
136 | LTESR_CC)
137#define LTESR_CLEAR 0xFFFFFFFF
138#define LTECCR_CLEAR 0xFFFFFFFF
139#define LTESR_STATUS LTESR_MASK
140#define LTEIR_ENABLE LTESR_MASK
141#define LTEDR_ENABLE 0x00000000
130 __be32 ltedr; /**< Transfer Error Disable Register */ 142 __be32 ltedr; /**< Transfer Error Disable Register */
131 __be32 lteir; /**< Transfer Error Interrupt Register */ 143 __be32 lteir; /**< Transfer Error Interrupt Register */
132 __be32 lteatr; /**< Transfer Error Attributes Register */ 144 __be32 lteatr; /**< Transfer Error Attributes Register */
133 __be32 ltear; /**< Transfer Error Address Register */ 145 __be32 ltear; /**< Transfer Error Address Register */
134 u8 res6[0xC]; 146 __be32 lteccr; /**< Transfer Error ECC Register */
147 u8 res6[0x8];
135 __be32 lbcr; /**< Configuration Register */ 148 __be32 lbcr; /**< Configuration Register */
136#define LBCR_LDIS 0x80000000 149#define LBCR_LDIS 0x80000000
137#define LBCR_LDIS_SHIFT 31 150#define LBCR_LDIS_SHIFT 31
@@ -265,7 +278,23 @@ static inline void fsl_upm_end_pattern(struct fsl_upm *upm)
265 cpu_relax(); 278 cpu_relax();
266} 279}
267 280
281/* overview of the fsl lbc controller */
282
283struct fsl_lbc_ctrl {
284 /* device info */
285 struct device *dev;
286 struct fsl_lbc_regs __iomem *regs;
287 int irq;
288 wait_queue_head_t irq_wait;
289 spinlock_t lock;
290 void *nand;
291
292 /* status read from LTESR by irq handler */
293 unsigned int irq_status;
294};
295
268extern int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, 296extern int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base,
269 u32 mar); 297 u32 mar);
298extern struct fsl_lbc_ctrl *fsl_lbc_ctrl_dev;
270 299
271#endif /* __ASM_FSL_LBC_H */ 300#endif /* __ASM_FSL_LBC_H */
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);