1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Freescale LBC and UPM routines. |
4 | * |
5 | * Copyright © 2007-2008 MontaVista Software, Inc. |
6 | * Copyright © 2010 Freescale Semiconductor |
7 | * |
8 | * Author: Anton Vorontsov <avorontsov@ru.mvista.com> |
9 | * Author: Jack Lan <Jack.Lan@freescale.com> |
10 | * Author: Roy Zang <tie-fei.zang@freescale.com> |
11 | */ |
12 | |
13 | #include <linux/init.h> |
14 | #include <linux/export.h> |
15 | #include <linux/kernel.h> |
16 | #include <linux/compiler.h> |
17 | #include <linux/spinlock.h> |
18 | #include <linux/types.h> |
19 | #include <linux/io.h> |
20 | #include <linux/of.h> |
21 | #include <linux/of_address.h> |
22 | #include <linux/of_irq.h> |
23 | #include <linux/slab.h> |
24 | #include <linux/sched.h> |
25 | #include <linux/platform_device.h> |
26 | #include <linux/interrupt.h> |
27 | #include <linux/mod_devicetable.h> |
28 | #include <linux/syscore_ops.h> |
29 | #include <asm/fsl_lbc.h> |
30 | |
31 | static DEFINE_SPINLOCK(fsl_lbc_lock); |
32 | struct fsl_lbc_ctrl *fsl_lbc_ctrl_dev; |
33 | EXPORT_SYMBOL(fsl_lbc_ctrl_dev); |
34 | |
35 | /** |
36 | * fsl_lbc_addr - convert the base address |
37 | * @addr_base: base address of the memory bank |
38 | * |
39 | * This function converts a base address of lbc into the right format for the |
40 | * BR register. If the SOC has eLBC then it returns 32bit physical address |
41 | * else it converts a 34bit local bus physical address to correct format of |
42 | * 32bit address for BR register (Example: MPC8641). |
43 | */ |
44 | u32 fsl_lbc_addr(phys_addr_t addr_base) |
45 | { |
46 | struct device_node *np = fsl_lbc_ctrl_dev->dev->of_node; |
47 | u32 addr = addr_base & 0xffff8000; |
48 | |
49 | if (of_device_is_compatible(device: np, "fsl,elbc" )) |
50 | return addr; |
51 | |
52 | return addr | ((addr_base & 0x300000000ull) >> 19); |
53 | } |
54 | EXPORT_SYMBOL(fsl_lbc_addr); |
55 | |
56 | /** |
57 | * fsl_lbc_find - find Localbus bank |
58 | * @addr_base: base address of the memory bank |
59 | * |
60 | * This function walks LBC banks comparing "Base address" field of the BR |
61 | * registers with the supplied addr_base argument. When bases match this |
62 | * function returns bank number (starting with 0), otherwise it returns |
63 | * appropriate errno value. |
64 | */ |
65 | int fsl_lbc_find(phys_addr_t addr_base) |
66 | { |
67 | int i; |
68 | struct fsl_lbc_regs __iomem *lbc; |
69 | |
70 | if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs) |
71 | return -ENODEV; |
72 | |
73 | lbc = fsl_lbc_ctrl_dev->regs; |
74 | for (i = 0; i < ARRAY_SIZE(lbc->bank); i++) { |
75 | u32 br = in_be32(&lbc->bank[i].br); |
76 | u32 or = in_be32(&lbc->bank[i].or); |
77 | |
78 | if (br & BR_V && (br & or & BR_BA) == fsl_lbc_addr(addr_base)) |
79 | return i; |
80 | } |
81 | |
82 | return -ENOENT; |
83 | } |
84 | EXPORT_SYMBOL(fsl_lbc_find); |
85 | |
86 | /** |
87 | * fsl_upm_find - find pre-programmed UPM via base address |
88 | * @addr_base: base address of the memory bank controlled by the UPM |
89 | * @upm: pointer to the allocated fsl_upm structure |
90 | * |
91 | * This function fills fsl_upm structure so you can use it with the rest of |
92 | * UPM API. On success this function returns 0, otherwise it returns |
93 | * appropriate errno value. |
94 | */ |
95 | int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm) |
96 | { |
97 | int bank; |
98 | u32 br; |
99 | struct fsl_lbc_regs __iomem *lbc; |
100 | |
101 | bank = fsl_lbc_find(addr_base); |
102 | if (bank < 0) |
103 | return bank; |
104 | |
105 | if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs) |
106 | return -ENODEV; |
107 | |
108 | lbc = fsl_lbc_ctrl_dev->regs; |
109 | br = in_be32(&lbc->bank[bank].br); |
110 | |
111 | switch (br & BR_MSEL) { |
112 | case BR_MS_UPMA: |
113 | upm->mxmr = &lbc->mamr; |
114 | break; |
115 | case BR_MS_UPMB: |
116 | upm->mxmr = &lbc->mbmr; |
117 | break; |
118 | case BR_MS_UPMC: |
119 | upm->mxmr = &lbc->mcmr; |
120 | break; |
121 | default: |
122 | return -EINVAL; |
123 | } |
124 | |
125 | switch (br & BR_PS) { |
126 | case BR_PS_8: |
127 | upm->width = 8; |
128 | break; |
129 | case BR_PS_16: |
130 | upm->width = 16; |
131 | break; |
132 | case BR_PS_32: |
133 | upm->width = 32; |
134 | break; |
135 | default: |
136 | return -EINVAL; |
137 | } |
138 | |
139 | return 0; |
140 | } |
141 | EXPORT_SYMBOL(fsl_upm_find); |
142 | |
143 | /** |
144 | * fsl_upm_run_pattern - actually run an UPM pattern |
145 | * @upm: pointer to the fsl_upm structure obtained via fsl_upm_find |
146 | * @io_base: remapped pointer to where memory access should happen |
147 | * @mar: MAR register content during pattern execution |
148 | * |
149 | * This function triggers dummy write to the memory specified by the io_base, |
150 | * thus UPM pattern actually executed. Note that mar usage depends on the |
151 | * pre-programmed AMX bits in the UPM RAM. |
152 | */ |
153 | int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar) |
154 | { |
155 | int ret = 0; |
156 | unsigned long flags; |
157 | |
158 | if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs) |
159 | return -ENODEV; |
160 | |
161 | spin_lock_irqsave(&fsl_lbc_lock, flags); |
162 | |
163 | out_be32(&fsl_lbc_ctrl_dev->regs->mar, mar); |
164 | |
165 | switch (upm->width) { |
166 | case 8: |
167 | out_8(io_base, 0x0); |
168 | break; |
169 | case 16: |
170 | out_be16(io_base, 0x0); |
171 | break; |
172 | case 32: |
173 | out_be32(io_base, 0x0); |
174 | break; |
175 | default: |
176 | ret = -EINVAL; |
177 | break; |
178 | } |
179 | |
180 | spin_unlock_irqrestore(lock: &fsl_lbc_lock, flags); |
181 | |
182 | return ret; |
183 | } |
184 | EXPORT_SYMBOL(fsl_upm_run_pattern); |
185 | |
186 | static int fsl_lbc_ctrl_init(struct fsl_lbc_ctrl *ctrl, |
187 | struct device_node *node) |
188 | { |
189 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; |
190 | |
191 | /* clear event registers */ |
192 | setbits32(&lbc->ltesr, LTESR_CLEAR); |
193 | out_be32(&lbc->lteatr, 0); |
194 | out_be32(&lbc->ltear, 0); |
195 | out_be32(&lbc->lteccr, LTECCR_CLEAR); |
196 | out_be32(&lbc->ltedr, LTEDR_ENABLE); |
197 | |
198 | /* Set the monitor timeout value to the maximum for erratum A001 */ |
199 | if (of_device_is_compatible(device: node, "fsl,elbc" )) |
200 | clrsetbits_be32(&lbc->lbcr, LBCR_BMT, LBCR_BMTPS); |
201 | |
202 | return 0; |
203 | } |
204 | |
205 | /* |
206 | * NOTE: This interrupt is used to report localbus events of various kinds, |
207 | * such as transaction errors on the chipselects. |
208 | */ |
209 | |
210 | static irqreturn_t fsl_lbc_ctrl_irq(int irqno, void *data) |
211 | { |
212 | struct fsl_lbc_ctrl *ctrl = data; |
213 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; |
214 | u32 status; |
215 | unsigned long flags; |
216 | |
217 | spin_lock_irqsave(&fsl_lbc_lock, flags); |
218 | status = in_be32(&lbc->ltesr); |
219 | if (!status) { |
220 | spin_unlock_irqrestore(lock: &fsl_lbc_lock, flags); |
221 | return IRQ_NONE; |
222 | } |
223 | |
224 | out_be32(&lbc->ltesr, LTESR_CLEAR); |
225 | out_be32(&lbc->lteatr, 0); |
226 | out_be32(&lbc->ltear, 0); |
227 | ctrl->irq_status = status; |
228 | |
229 | if (status & LTESR_BM) |
230 | dev_err(ctrl->dev, "Local bus monitor time-out: " |
231 | "LTESR 0x%08X\n" , status); |
232 | if (status & LTESR_WP) |
233 | dev_err(ctrl->dev, "Write protect error: " |
234 | "LTESR 0x%08X\n" , status); |
235 | if (status & LTESR_ATMW) |
236 | dev_err(ctrl->dev, "Atomic write error: " |
237 | "LTESR 0x%08X\n" , status); |
238 | if (status & LTESR_ATMR) |
239 | dev_err(ctrl->dev, "Atomic read error: " |
240 | "LTESR 0x%08X\n" , status); |
241 | if (status & LTESR_CS) |
242 | dev_err(ctrl->dev, "Chip select error: " |
243 | "LTESR 0x%08X\n" , status); |
244 | if (status & LTESR_FCT) { |
245 | dev_err(ctrl->dev, "FCM command time-out: " |
246 | "LTESR 0x%08X\n" , status); |
247 | smp_wmb(); |
248 | wake_up(&ctrl->irq_wait); |
249 | } |
250 | if (status & LTESR_PAR) { |
251 | dev_err(ctrl->dev, "Parity or Uncorrectable ECC error: " |
252 | "LTESR 0x%08X\n" , status); |
253 | smp_wmb(); |
254 | wake_up(&ctrl->irq_wait); |
255 | } |
256 | if (status & LTESR_CC) { |
257 | smp_wmb(); |
258 | wake_up(&ctrl->irq_wait); |
259 | } |
260 | if (status & ~LTESR_MASK) |
261 | dev_err(ctrl->dev, "Unknown error: " |
262 | "LTESR 0x%08X\n" , status); |
263 | spin_unlock_irqrestore(lock: &fsl_lbc_lock, flags); |
264 | return IRQ_HANDLED; |
265 | } |
266 | |
267 | /* |
268 | * fsl_lbc_ctrl_probe |
269 | * |
270 | * called by device layer when it finds a device matching |
271 | * one our driver can handled. This code allocates all of |
272 | * the resources needed for the controller only. The |
273 | * resources for the NAND banks themselves are allocated |
274 | * in the chip probe function. |
275 | */ |
276 | |
277 | static int fsl_lbc_ctrl_probe(struct platform_device *dev) |
278 | { |
279 | int ret; |
280 | |
281 | if (!dev->dev.of_node) { |
282 | dev_err(&dev->dev, "Device OF-Node is NULL" ); |
283 | return -EFAULT; |
284 | } |
285 | |
286 | fsl_lbc_ctrl_dev = kzalloc(sizeof(*fsl_lbc_ctrl_dev), GFP_KERNEL); |
287 | if (!fsl_lbc_ctrl_dev) |
288 | return -ENOMEM; |
289 | |
290 | dev_set_drvdata(dev: &dev->dev, data: fsl_lbc_ctrl_dev); |
291 | |
292 | spin_lock_init(&fsl_lbc_ctrl_dev->lock); |
293 | init_waitqueue_head(&fsl_lbc_ctrl_dev->irq_wait); |
294 | |
295 | fsl_lbc_ctrl_dev->regs = of_iomap(node: dev->dev.of_node, index: 0); |
296 | if (!fsl_lbc_ctrl_dev->regs) { |
297 | dev_err(&dev->dev, "failed to get memory region\n" ); |
298 | ret = -ENODEV; |
299 | goto err; |
300 | } |
301 | |
302 | fsl_lbc_ctrl_dev->irq[0] = irq_of_parse_and_map(node: dev->dev.of_node, index: 0); |
303 | if (!fsl_lbc_ctrl_dev->irq[0]) { |
304 | dev_err(&dev->dev, "failed to get irq resource\n" ); |
305 | ret = -ENODEV; |
306 | goto err; |
307 | } |
308 | |
309 | fsl_lbc_ctrl_dev->dev = &dev->dev; |
310 | |
311 | ret = fsl_lbc_ctrl_init(ctrl: fsl_lbc_ctrl_dev, node: dev->dev.of_node); |
312 | if (ret < 0) |
313 | goto err; |
314 | |
315 | ret = request_irq(irq: fsl_lbc_ctrl_dev->irq[0], handler: fsl_lbc_ctrl_irq, flags: 0, |
316 | name: "fsl-lbc" , dev: fsl_lbc_ctrl_dev); |
317 | if (ret != 0) { |
318 | dev_err(&dev->dev, "failed to install irq (%d)\n" , |
319 | fsl_lbc_ctrl_dev->irq[0]); |
320 | ret = fsl_lbc_ctrl_dev->irq[0]; |
321 | goto err; |
322 | } |
323 | |
324 | fsl_lbc_ctrl_dev->irq[1] = irq_of_parse_and_map(node: dev->dev.of_node, index: 1); |
325 | if (fsl_lbc_ctrl_dev->irq[1]) { |
326 | ret = request_irq(irq: fsl_lbc_ctrl_dev->irq[1], handler: fsl_lbc_ctrl_irq, |
327 | IRQF_SHARED, name: "fsl-lbc-err" , dev: fsl_lbc_ctrl_dev); |
328 | if (ret) { |
329 | dev_err(&dev->dev, "failed to install irq (%d)\n" , |
330 | fsl_lbc_ctrl_dev->irq[1]); |
331 | ret = fsl_lbc_ctrl_dev->irq[1]; |
332 | goto err1; |
333 | } |
334 | } |
335 | |
336 | /* Enable interrupts for any detected events */ |
337 | out_be32(&fsl_lbc_ctrl_dev->regs->lteir, LTEIR_ENABLE); |
338 | |
339 | return 0; |
340 | |
341 | err1: |
342 | free_irq(fsl_lbc_ctrl_dev->irq[0], fsl_lbc_ctrl_dev); |
343 | err: |
344 | iounmap(addr: fsl_lbc_ctrl_dev->regs); |
345 | kfree(objp: fsl_lbc_ctrl_dev); |
346 | fsl_lbc_ctrl_dev = NULL; |
347 | return ret; |
348 | } |
349 | |
350 | #ifdef CONFIG_SUSPEND |
351 | |
352 | /* save lbc registers */ |
353 | static int fsl_lbc_syscore_suspend(void) |
354 | { |
355 | struct fsl_lbc_ctrl *ctrl; |
356 | struct fsl_lbc_regs __iomem *lbc; |
357 | |
358 | ctrl = fsl_lbc_ctrl_dev; |
359 | if (!ctrl) |
360 | goto out; |
361 | |
362 | lbc = ctrl->regs; |
363 | if (!lbc) |
364 | goto out; |
365 | |
366 | ctrl->saved_regs = kmalloc(sizeof(struct fsl_lbc_regs), GFP_KERNEL); |
367 | if (!ctrl->saved_regs) |
368 | return -ENOMEM; |
369 | |
370 | _memcpy_fromio(ctrl->saved_regs, lbc, sizeof(struct fsl_lbc_regs)); |
371 | |
372 | out: |
373 | return 0; |
374 | } |
375 | |
376 | /* restore lbc registers */ |
377 | static void fsl_lbc_syscore_resume(void) |
378 | { |
379 | struct fsl_lbc_ctrl *ctrl; |
380 | struct fsl_lbc_regs __iomem *lbc; |
381 | |
382 | ctrl = fsl_lbc_ctrl_dev; |
383 | if (!ctrl) |
384 | goto out; |
385 | |
386 | lbc = ctrl->regs; |
387 | if (!lbc) |
388 | goto out; |
389 | |
390 | if (ctrl->saved_regs) { |
391 | _memcpy_toio(lbc, ctrl->saved_regs, |
392 | sizeof(struct fsl_lbc_regs)); |
393 | kfree(objp: ctrl->saved_regs); |
394 | ctrl->saved_regs = NULL; |
395 | } |
396 | |
397 | out: |
398 | return; |
399 | } |
400 | #endif /* CONFIG_SUSPEND */ |
401 | |
402 | static const struct of_device_id fsl_lbc_match[] = { |
403 | { .compatible = "fsl,elbc" , }, |
404 | { .compatible = "fsl,pq3-localbus" , }, |
405 | { .compatible = "fsl,pq2-localbus" , }, |
406 | { .compatible = "fsl,pq2pro-localbus" , }, |
407 | {}, |
408 | }; |
409 | |
410 | #ifdef CONFIG_SUSPEND |
411 | static struct syscore_ops lbc_syscore_pm_ops = { |
412 | .suspend = fsl_lbc_syscore_suspend, |
413 | .resume = fsl_lbc_syscore_resume, |
414 | }; |
415 | #endif |
416 | |
417 | static struct platform_driver fsl_lbc_ctrl_driver = { |
418 | .driver = { |
419 | .name = "fsl-lbc" , |
420 | .of_match_table = fsl_lbc_match, |
421 | }, |
422 | .probe = fsl_lbc_ctrl_probe, |
423 | }; |
424 | |
425 | static int __init fsl_lbc_init(void) |
426 | { |
427 | #ifdef CONFIG_SUSPEND |
428 | register_syscore_ops(ops: &lbc_syscore_pm_ops); |
429 | #endif |
430 | return platform_driver_register(&fsl_lbc_ctrl_driver); |
431 | } |
432 | subsys_initcall(fsl_lbc_init); |
433 | |