Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/powerpc/sysdev/fsl_lbc.c
26424 views
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 <[email protected]>
9
* Author: Jack Lan <[email protected]>
10
* Author: Roy Zang <[email protected]>
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(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(&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(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(&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(&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, 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(dev->dev.of_node, 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(dev->dev.of_node, 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(fsl_lbc_ctrl_dev, dev->dev.of_node);
312
if (ret < 0)
313
goto err;
314
315
ret = request_irq(fsl_lbc_ctrl_dev->irq[0], fsl_lbc_ctrl_irq, 0,
316
"fsl-lbc", 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(dev->dev.of_node, 1);
325
if (fsl_lbc_ctrl_dev->irq[1]) {
326
ret = request_irq(fsl_lbc_ctrl_dev->irq[1], fsl_lbc_ctrl_irq,
327
IRQF_SHARED, "fsl-lbc-err", 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(fsl_lbc_ctrl_dev->regs);
345
kfree(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(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(&lbc_syscore_pm_ops);
429
#endif
430
return platform_driver_register(&fsl_lbc_ctrl_driver);
431
}
432
subsys_initcall(fsl_lbc_init);
433
434