1
2
3
4
5
6
7
8
9
10
11#include <linux/interrupt.h>
12#include <linux/kernel.h>
13#include <linux/of.h>
14#include <linux/of_platform.h>
15#include <linux/spinlock.h>
16#include <linux/module.h>
17#include <asm/io.h>
18#include <asm/prom.h>
19#include <asm/mpc52xx.h>
20#include <asm/time.h>
21
22#include <linux/fsl/bestcomm/bestcomm.h>
23#include <linux/fsl/bestcomm/bestcomm_priv.h>
24#include <linux/fsl/bestcomm/gen_bd.h>
25
26MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
27MODULE_DESCRIPTION("MPC5200 LocalPlus FIFO device driver");
28MODULE_LICENSE("GPL");
29
30#define LPBFIFO_REG_PACKET_SIZE (0x00)
31#define LPBFIFO_REG_START_ADDRESS (0x04)
32#define LPBFIFO_REG_CONTROL (0x08)
33#define LPBFIFO_REG_ENABLE (0x0C)
34#define LPBFIFO_REG_BYTES_DONE_STATUS (0x14)
35#define LPBFIFO_REG_FIFO_DATA (0x40)
36#define LPBFIFO_REG_FIFO_STATUS (0x44)
37#define LPBFIFO_REG_FIFO_CONTROL (0x48)
38#define LPBFIFO_REG_FIFO_ALARM (0x4C)
39
40struct mpc52xx_lpbfifo {
41 struct device *dev;
42 phys_addr_t regs_phys;
43 void __iomem *regs;
44 int irq;
45 spinlock_t lock;
46
47 struct bcom_task *bcom_tx_task;
48 struct bcom_task *bcom_rx_task;
49 struct bcom_task *bcom_cur_task;
50
51
52 struct mpc52xx_lpbfifo_request *req;
53 int dma_irqs_enabled;
54};
55
56
57static struct mpc52xx_lpbfifo lpbfifo;
58
59
60
61
62static void mpc52xx_lpbfifo_kick(struct mpc52xx_lpbfifo_request *req)
63{
64 size_t transfer_size = req->size - req->pos;
65 struct bcom_bd *bd;
66 void __iomem *reg;
67 u32 *data;
68 int i;
69 int bit_fields;
70 int dma = !(req->flags & MPC52XX_LPBFIFO_FLAG_NO_DMA);
71 int write = req->flags & MPC52XX_LPBFIFO_FLAG_WRITE;
72 int poll_dma = req->flags & MPC52XX_LPBFIFO_FLAG_POLL_DMA;
73
74
75 out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000);
76
77
78 out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x00000001);
79 if (!dma) {
80
81
82
83
84
85
86
87
88
89 if (transfer_size > 512)
90 transfer_size = 512;
91
92
93 if (write) {
94 reg = lpbfifo.regs + LPBFIFO_REG_FIFO_DATA;
95 data = req->data + req->pos;
96 for (i = 0; i < transfer_size; i += 4)
97 out_be32(reg, *data++);
98 }
99
100
101 out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x00000301);
102 } else {
103
104
105
106
107
108
109
110 if (write) {
111 out_be32(lpbfifo.regs + LPBFIFO_REG_FIFO_ALARM, 0x1e4);
112 out_8(lpbfifo.regs + LPBFIFO_REG_FIFO_CONTROL, 7);
113 lpbfifo.bcom_cur_task = lpbfifo.bcom_tx_task;
114 } else {
115 out_be32(lpbfifo.regs + LPBFIFO_REG_FIFO_ALARM, 0x1ff);
116 out_8(lpbfifo.regs + LPBFIFO_REG_FIFO_CONTROL, 0);
117 lpbfifo.bcom_cur_task = lpbfifo.bcom_rx_task;
118
119 if (poll_dma) {
120 if (lpbfifo.dma_irqs_enabled) {
121 disable_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task));
122 lpbfifo.dma_irqs_enabled = 0;
123 }
124 } else {
125 if (!lpbfifo.dma_irqs_enabled) {
126 enable_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task));
127 lpbfifo.dma_irqs_enabled = 1;
128 }
129 }
130 }
131
132 bd = bcom_prepare_next_buffer(lpbfifo.bcom_cur_task);
133 bd->status = transfer_size;
134 if (!write) {
135
136
137
138
139
140
141
142
143
144
145
146
147 transfer_size += 4;
148 }
149 bd->data[0] = req->data_phys + req->pos;
150 bcom_submit_next_buffer(lpbfifo.bcom_cur_task, NULL);
151
152
153 bit_fields = 0x00000201;
154
155
156 if (write && (!poll_dma))
157 bit_fields |= 0x00000100;
158 out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, bit_fields);
159 }
160
161
162 out_be32(lpbfifo.regs + LPBFIFO_REG_START_ADDRESS,
163 req->offset + req->pos);
164 out_be32(lpbfifo.regs + LPBFIFO_REG_PACKET_SIZE, transfer_size);
165
166 bit_fields = req->cs << 24 | 0x000008;
167 if (!write)
168 bit_fields |= 0x010000;
169 out_be32(lpbfifo.regs + LPBFIFO_REG_CONTROL, bit_fields);
170
171
172 if (!lpbfifo.req->defer_xfer_start)
173 out_8(lpbfifo.regs + LPBFIFO_REG_PACKET_SIZE, 0x01);
174 if (dma)
175 bcom_enable(lpbfifo.bcom_cur_task);
176}
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219static irqreturn_t mpc52xx_lpbfifo_irq(int irq, void *dev_id)
220{
221 struct mpc52xx_lpbfifo_request *req;
222 u32 status = in_8(lpbfifo.regs + LPBFIFO_REG_BYTES_DONE_STATUS);
223 void __iomem *reg;
224 u32 *data;
225 int count, i;
226 int do_callback = 0;
227 u32 ts;
228 unsigned long flags;
229 int dma, write, poll_dma;
230
231 spin_lock_irqsave(&lpbfifo.lock, flags);
232 ts = mftb();
233
234 req = lpbfifo.req;
235 if (!req) {
236 spin_unlock_irqrestore(&lpbfifo.lock, flags);
237 pr_err("bogus LPBFIFO IRQ\n");
238 return IRQ_HANDLED;
239 }
240
241 dma = !(req->flags & MPC52XX_LPBFIFO_FLAG_NO_DMA);
242 write = req->flags & MPC52XX_LPBFIFO_FLAG_WRITE;
243 poll_dma = req->flags & MPC52XX_LPBFIFO_FLAG_POLL_DMA;
244
245 if (dma && !write) {
246 spin_unlock_irqrestore(&lpbfifo.lock, flags);
247 pr_err("bogus LPBFIFO IRQ (dma and not writing)\n");
248 return IRQ_HANDLED;
249 }
250
251 if ((status & 0x01) == 0) {
252 goto out;
253 }
254
255
256 if (status & 0x10) {
257 out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000);
258 do_callback = 1;
259 goto out;
260 }
261
262
263 count = in_be32(lpbfifo.regs + LPBFIFO_REG_BYTES_DONE_STATUS);
264 count &= 0x00ffffff;
265
266 if (!dma && !write) {
267
268 reg = lpbfifo.regs + LPBFIFO_REG_FIFO_DATA;
269 data = req->data + req->pos;
270 for (i = 0; i < count; i += 4)
271 *data++ = in_be32(reg);
272 }
273
274
275 req->pos += count;
276
277
278 if (req->size - req->pos)
279 mpc52xx_lpbfifo_kick(req);
280 else
281 do_callback = 1;
282
283 out:
284
285 out_8(lpbfifo.regs + LPBFIFO_REG_BYTES_DONE_STATUS, 0x01);
286
287 if (dma && (status & 0x11)) {
288
289
290
291
292
293
294
295
296
297
298 bcom_retrieve_buffer(lpbfifo.bcom_cur_task, &status, NULL);
299 }
300 req->last_byte = ((u8 *)req->data)[req->size - 1];
301
302
303
304 if (do_callback)
305 lpbfifo.req = NULL;
306
307 if (irq != 0)
308 req->irq_count++;
309
310 req->irq_ticks += mftb() - ts;
311 spin_unlock_irqrestore(&lpbfifo.lock, flags);
312
313
314 if (do_callback && req->callback)
315 req->callback(req);
316
317 return IRQ_HANDLED;
318}
319
320
321
322
323
324
325static irqreturn_t mpc52xx_lpbfifo_bcom_irq(int irq, void *dev_id)
326{
327 struct mpc52xx_lpbfifo_request *req;
328 unsigned long flags;
329 u32 status;
330 u32 ts;
331
332 spin_lock_irqsave(&lpbfifo.lock, flags);
333 ts = mftb();
334
335 req = lpbfifo.req;
336 if (!req || (req->flags & MPC52XX_LPBFIFO_FLAG_NO_DMA)) {
337 spin_unlock_irqrestore(&lpbfifo.lock, flags);
338 return IRQ_HANDLED;
339 }
340
341 if (irq != 0)
342 req->irq_count++;
343
344 if (!bcom_buffer_done(lpbfifo.bcom_cur_task)) {
345 spin_unlock_irqrestore(&lpbfifo.lock, flags);
346
347 req->buffer_not_done_cnt++;
348 if ((req->buffer_not_done_cnt % 1000) == 0)
349 pr_err("transfer stalled\n");
350
351 return IRQ_HANDLED;
352 }
353
354 bcom_retrieve_buffer(lpbfifo.bcom_cur_task, &status, NULL);
355
356 req->last_byte = ((u8 *)req->data)[req->size - 1];
357
358 req->pos = status & 0x00ffffff;
359
360
361 lpbfifo.req = NULL;
362
363
364 req->irq_ticks += mftb() - ts;
365 spin_unlock_irqrestore(&lpbfifo.lock, flags);
366
367 if (req->callback)
368 req->callback(req);
369
370 return IRQ_HANDLED;
371}
372
373
374
375
376void mpc52xx_lpbfifo_poll(void)
377{
378 struct mpc52xx_lpbfifo_request *req = lpbfifo.req;
379 int dma = !(req->flags & MPC52XX_LPBFIFO_FLAG_NO_DMA);
380 int write = req->flags & MPC52XX_LPBFIFO_FLAG_WRITE;
381
382
383
384
385 if (dma && write)
386 mpc52xx_lpbfifo_irq(0, NULL);
387 else
388 mpc52xx_lpbfifo_bcom_irq(0, NULL);
389}
390EXPORT_SYMBOL(mpc52xx_lpbfifo_poll);
391
392
393
394
395
396int mpc52xx_lpbfifo_submit(struct mpc52xx_lpbfifo_request *req)
397{
398 unsigned long flags;
399
400 if (!lpbfifo.regs)
401 return -ENODEV;
402
403 spin_lock_irqsave(&lpbfifo.lock, flags);
404
405
406 if (lpbfifo.req) {
407 spin_unlock_irqrestore(&lpbfifo.lock, flags);
408 return -EBUSY;
409 }
410
411
412 lpbfifo.req = req;
413 req->irq_count = 0;
414 req->irq_ticks = 0;
415 req->buffer_not_done_cnt = 0;
416 req->pos = 0;
417
418 mpc52xx_lpbfifo_kick(req);
419 spin_unlock_irqrestore(&lpbfifo.lock, flags);
420 return 0;
421}
422EXPORT_SYMBOL(mpc52xx_lpbfifo_submit);
423
424int mpc52xx_lpbfifo_start_xfer(struct mpc52xx_lpbfifo_request *req)
425{
426 unsigned long flags;
427
428 if (!lpbfifo.regs)
429 return -ENODEV;
430
431 spin_lock_irqsave(&lpbfifo.lock, flags);
432
433
434
435
436
437 if (lpbfifo.req && !lpbfifo.req->defer_xfer_start) {
438 spin_unlock_irqrestore(&lpbfifo.lock, flags);
439 return -EBUSY;
440 }
441
442
443
444
445
446 if (lpbfifo.req && lpbfifo.req == req &&
447 lpbfifo.req->defer_xfer_start) {
448 out_8(lpbfifo.regs + LPBFIFO_REG_PACKET_SIZE, 0x01);
449 }
450
451 spin_unlock_irqrestore(&lpbfifo.lock, flags);
452 return 0;
453}
454EXPORT_SYMBOL(mpc52xx_lpbfifo_start_xfer);
455
456void mpc52xx_lpbfifo_abort(struct mpc52xx_lpbfifo_request *req)
457{
458 unsigned long flags;
459
460 spin_lock_irqsave(&lpbfifo.lock, flags);
461 if (lpbfifo.req == req) {
462
463 bcom_gen_bd_rx_reset(lpbfifo.bcom_rx_task);
464 bcom_gen_bd_tx_reset(lpbfifo.bcom_tx_task);
465 out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000);
466 lpbfifo.req = NULL;
467 }
468 spin_unlock_irqrestore(&lpbfifo.lock, flags);
469}
470EXPORT_SYMBOL(mpc52xx_lpbfifo_abort);
471
472static int mpc52xx_lpbfifo_probe(struct platform_device *op)
473{
474 struct resource res;
475 int rc = -ENOMEM;
476
477 if (lpbfifo.dev != NULL)
478 return -ENOSPC;
479
480 lpbfifo.irq = irq_of_parse_and_map(op->dev.of_node, 0);
481 if (!lpbfifo.irq)
482 return -ENODEV;
483
484 if (of_address_to_resource(op->dev.of_node, 0, &res))
485 return -ENODEV;
486 lpbfifo.regs_phys = res.start;
487 lpbfifo.regs = of_iomap(op->dev.of_node, 0);
488 if (!lpbfifo.regs)
489 return -ENOMEM;
490
491 spin_lock_init(&lpbfifo.lock);
492
493
494 out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000);
495
496
497 rc = request_irq(lpbfifo.irq, mpc52xx_lpbfifo_irq, 0,
498 "mpc52xx-lpbfifo", &lpbfifo);
499 if (rc)
500 goto err_irq;
501
502
503 lpbfifo.bcom_rx_task =
504 bcom_gen_bd_rx_init(2, res.start + LPBFIFO_REG_FIFO_DATA,
505 BCOM_INITIATOR_SCLPC, BCOM_IPR_SCLPC,
506 16*1024*1024);
507 if (!lpbfifo.bcom_rx_task)
508 goto err_bcom_rx;
509
510 rc = request_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task),
511 mpc52xx_lpbfifo_bcom_irq, 0,
512 "mpc52xx-lpbfifo-rx", &lpbfifo);
513 if (rc)
514 goto err_bcom_rx_irq;
515
516 lpbfifo.dma_irqs_enabled = 1;
517
518
519 lpbfifo.bcom_tx_task =
520 bcom_gen_bd_tx_init(2, res.start + LPBFIFO_REG_FIFO_DATA,
521 BCOM_INITIATOR_SCLPC, BCOM_IPR_SCLPC);
522 if (!lpbfifo.bcom_tx_task)
523 goto err_bcom_tx;
524
525 lpbfifo.dev = &op->dev;
526 return 0;
527
528 err_bcom_tx:
529 free_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task), &lpbfifo);
530 err_bcom_rx_irq:
531 bcom_gen_bd_rx_release(lpbfifo.bcom_rx_task);
532 err_bcom_rx:
533 err_irq:
534 iounmap(lpbfifo.regs);
535 lpbfifo.regs = NULL;
536
537 dev_err(&op->dev, "mpc52xx_lpbfifo_probe() failed\n");
538 return -ENODEV;
539}
540
541
542static int mpc52xx_lpbfifo_remove(struct platform_device *op)
543{
544 if (lpbfifo.dev != &op->dev)
545 return 0;
546
547
548 out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000);
549
550
551 free_irq(bcom_get_task_irq(lpbfifo.bcom_tx_task), &lpbfifo);
552 bcom_gen_bd_tx_release(lpbfifo.bcom_tx_task);
553
554
555 free_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task), &lpbfifo);
556 bcom_gen_bd_rx_release(lpbfifo.bcom_rx_task);
557
558 free_irq(lpbfifo.irq, &lpbfifo);
559 iounmap(lpbfifo.regs);
560 lpbfifo.regs = NULL;
561 lpbfifo.dev = NULL;
562
563 return 0;
564}
565
566static const struct of_device_id mpc52xx_lpbfifo_match[] = {
567 { .compatible = "fsl,mpc5200-lpbfifo", },
568 {},
569};
570MODULE_DEVICE_TABLE(of, mpc52xx_lpbfifo_match);
571
572static struct platform_driver mpc52xx_lpbfifo_driver = {
573 .driver = {
574 .name = "mpc52xx-lpbfifo",
575 .of_match_table = mpc52xx_lpbfifo_match,
576 },
577 .probe = mpc52xx_lpbfifo_probe,
578 .remove = mpc52xx_lpbfifo_remove,
579};
580module_platform_driver(mpc52xx_lpbfifo_driver);
581