diff options
-rw-r--r-- | drivers/serial/amba-pl011.c | 508 | ||||
-rw-r--r-- | include/linux/amba/serial.h | 7 |
2 files changed, 513 insertions, 2 deletions
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index f741a8b51400..ab025dc52fa4 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c | |||
@@ -7,6 +7,7 @@ | |||
7 | * | 7 | * |
8 | * Copyright 1999 ARM Limited | 8 | * Copyright 1999 ARM Limited |
9 | * Copyright (C) 2000 Deep Blue Solutions Ltd. | 9 | * Copyright (C) 2000 Deep Blue Solutions Ltd. |
10 | * Copyright (C) 2010 ST-Ericsson SA | ||
10 | * | 11 | * |
11 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License as published by | 13 | * it under the terms of the GNU General Public License as published by |
@@ -48,6 +49,9 @@ | |||
48 | #include <linux/amba/serial.h> | 49 | #include <linux/amba/serial.h> |
49 | #include <linux/clk.h> | 50 | #include <linux/clk.h> |
50 | #include <linux/slab.h> | 51 | #include <linux/slab.h> |
52 | #include <linux/dmaengine.h> | ||
53 | #include <linux/dma-mapping.h> | ||
54 | #include <linux/scatterlist.h> | ||
51 | 55 | ||
52 | #include <asm/io.h> | 56 | #include <asm/io.h> |
53 | #include <asm/sizes.h> | 57 | #include <asm/sizes.h> |
@@ -88,6 +92,14 @@ static struct vendor_data vendor_st = { | |||
88 | .oversampling = true, | 92 | .oversampling = true, |
89 | }; | 93 | }; |
90 | 94 | ||
95 | /* Deals with DMA transactions */ | ||
96 | struct pl011_dmatx_data { | ||
97 | struct dma_chan *chan; | ||
98 | struct scatterlist sg; | ||
99 | char *buf; | ||
100 | bool queued; | ||
101 | }; | ||
102 | |||
91 | /* | 103 | /* |
92 | * We wrap our port structure around the generic uart_port. | 104 | * We wrap our port structure around the generic uart_port. |
93 | */ | 105 | */ |
@@ -95,6 +107,7 @@ struct uart_amba_port { | |||
95 | struct uart_port port; | 107 | struct uart_port port; |
96 | struct clk *clk; | 108 | struct clk *clk; |
97 | const struct vendor_data *vendor; | 109 | const struct vendor_data *vendor; |
110 | unsigned int dmacr; /* dma control reg */ | ||
98 | unsigned int im; /* interrupt mask */ | 111 | unsigned int im; /* interrupt mask */ |
99 | unsigned int old_status; | 112 | unsigned int old_status; |
100 | unsigned int fifosize; /* vendor-specific */ | 113 | unsigned int fifosize; /* vendor-specific */ |
@@ -102,22 +115,500 @@ struct uart_amba_port { | |||
102 | unsigned int lcrh_rx; /* vendor-specific */ | 115 | unsigned int lcrh_rx; /* vendor-specific */ |
103 | bool autorts; | 116 | bool autorts; |
104 | char type[12]; | 117 | char type[12]; |
118 | #ifdef CONFIG_DMA_ENGINE | ||
119 | /* DMA stuff */ | ||
120 | bool using_dma; | ||
121 | struct pl011_dmatx_data dmatx; | ||
122 | #endif | ||
123 | }; | ||
124 | |||
125 | /* | ||
126 | * All the DMA operation mode stuff goes inside this ifdef. | ||
127 | * This assumes that you have a generic DMA device interface, | ||
128 | * no custom DMA interfaces are supported. | ||
129 | */ | ||
130 | #ifdef CONFIG_DMA_ENGINE | ||
131 | |||
132 | #define PL011_DMA_BUFFER_SIZE PAGE_SIZE | ||
133 | |||
134 | static void pl011_dma_probe_initcall(struct uart_amba_port *uap) | ||
135 | { | ||
136 | /* DMA is the sole user of the platform data right now */ | ||
137 | struct amba_pl011_data *plat = uap->port.dev->platform_data; | ||
138 | struct dma_slave_config tx_conf = { | ||
139 | .dst_addr = uap->port.mapbase + UART01x_DR, | ||
140 | .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, | ||
141 | .direction = DMA_TO_DEVICE, | ||
142 | .dst_maxburst = uap->fifosize >> 1, | ||
143 | }; | ||
144 | struct dma_chan *chan; | ||
145 | dma_cap_mask_t mask; | ||
146 | |||
147 | /* We need platform data */ | ||
148 | if (!plat || !plat->dma_filter) { | ||
149 | dev_info(uap->port.dev, "no DMA platform data\n"); | ||
150 | return; | ||
151 | } | ||
152 | |||
153 | /* Try to acquire a generic DMA engine slave channel */ | ||
154 | dma_cap_zero(mask); | ||
155 | dma_cap_set(DMA_SLAVE, mask); | ||
156 | |||
157 | chan = dma_request_channel(mask, plat->dma_filter, plat->dma_tx_param); | ||
158 | if (!chan) { | ||
159 | dev_err(uap->port.dev, "no TX DMA channel!\n"); | ||
160 | return; | ||
161 | } | ||
162 | |||
163 | dmaengine_slave_config(chan, &tx_conf); | ||
164 | uap->dmatx.chan = chan; | ||
165 | |||
166 | dev_info(uap->port.dev, "DMA channel TX %s\n", | ||
167 | dma_chan_name(uap->dmatx.chan)); | ||
168 | } | ||
169 | |||
170 | #ifndef MODULE | ||
171 | /* | ||
172 | * Stack up the UARTs and let the above initcall be done at device | ||
173 | * initcall time, because the serial driver is called as an arch | ||
174 | * initcall, and at this time the DMA subsystem is not yet registered. | ||
175 | * At this point the driver will switch over to using DMA where desired. | ||
176 | */ | ||
177 | struct dma_uap { | ||
178 | struct list_head node; | ||
179 | struct uart_amba_port *uap; | ||
105 | }; | 180 | }; |
106 | 181 | ||
182 | static LIST_HEAD(pl011_dma_uarts); | ||
183 | |||
184 | static int __init pl011_dma_initcall(void) | ||
185 | { | ||
186 | struct list_head *node, *tmp; | ||
187 | |||
188 | list_for_each_safe(node, tmp, &pl011_dma_uarts) { | ||
189 | struct dma_uap *dmau = list_entry(node, struct dma_uap, node); | ||
190 | pl011_dma_probe_initcall(dmau->uap); | ||
191 | list_del(node); | ||
192 | kfree(dmau); | ||
193 | } | ||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | device_initcall(pl011_dma_initcall); | ||
198 | |||
199 | static void pl011_dma_probe(struct uart_amba_port *uap) | ||
200 | { | ||
201 | struct dma_uap *dmau = kzalloc(sizeof(struct dma_uap), GFP_KERNEL); | ||
202 | if (dmau) { | ||
203 | dmau->uap = uap; | ||
204 | list_add_tail(&dmau->node, &pl011_dma_uarts); | ||
205 | } | ||
206 | } | ||
207 | #else | ||
208 | static void pl011_dma_probe(struct uart_amba_port *uap) | ||
209 | { | ||
210 | pl011_dma_probe_initcall(uap); | ||
211 | } | ||
212 | #endif | ||
213 | |||
214 | static void pl011_dma_remove(struct uart_amba_port *uap) | ||
215 | { | ||
216 | /* TODO: remove the initcall if it has not yet executed */ | ||
217 | if (uap->dmatx.chan) | ||
218 | dma_release_channel(uap->dmatx.chan); | ||
219 | } | ||
220 | |||
221 | |||
222 | /* Forward declare this for the refill routine */ | ||
223 | static int pl011_dma_tx_refill(struct uart_amba_port *uap); | ||
224 | |||
225 | /* | ||
226 | * The current DMA TX buffer has been sent. | ||
227 | * Try to queue up another DMA buffer. | ||
228 | */ | ||
229 | static void pl011_dma_tx_callback(void *data) | ||
230 | { | ||
231 | struct uart_amba_port *uap = data; | ||
232 | struct pl011_dmatx_data *dmatx = &uap->dmatx; | ||
233 | unsigned long flags; | ||
234 | u16 dmacr; | ||
235 | |||
236 | spin_lock_irqsave(&uap->port.lock, flags); | ||
237 | if (uap->dmatx.queued) | ||
238 | dma_unmap_sg(dmatx->chan->device->dev, &dmatx->sg, 1, | ||
239 | DMA_TO_DEVICE); | ||
240 | |||
241 | dmacr = uap->dmacr; | ||
242 | uap->dmacr = dmacr & ~UART011_TXDMAE; | ||
243 | writew(uap->dmacr, uap->port.membase + UART011_DMACR); | ||
244 | |||
245 | /* | ||
246 | * If TX DMA was disabled, it means that we've stopped the DMA for | ||
247 | * some reason (eg, XOFF received, or we want to send an X-char.) | ||
248 | * | ||
249 | * Note: we need to be careful here of a potential race between DMA | ||
250 | * and the rest of the driver - if the driver disables TX DMA while | ||
251 | * a TX buffer completing, we must update the tx queued status to | ||
252 | * get further refills (hence we check dmacr). | ||
253 | */ | ||
254 | if (!(dmacr & UART011_TXDMAE) || uart_tx_stopped(&uap->port) || | ||
255 | uart_circ_empty(&uap->port.state->xmit)) { | ||
256 | uap->dmatx.queued = false; | ||
257 | spin_unlock_irqrestore(&uap->port.lock, flags); | ||
258 | return; | ||
259 | } | ||
260 | |||
261 | if (pl011_dma_tx_refill(uap) <= 0) { | ||
262 | /* | ||
263 | * We didn't queue a DMA buffer for some reason, but we | ||
264 | * have data pending to be sent. Re-enable the TX IRQ. | ||
265 | */ | ||
266 | uap->im |= UART011_TXIM; | ||
267 | writew(uap->im, uap->port.membase + UART011_IMSC); | ||
268 | } | ||
269 | spin_unlock_irqrestore(&uap->port.lock, flags); | ||
270 | } | ||
271 | |||
272 | /* | ||
273 | * Try to refill the TX DMA buffer. | ||
274 | * Locking: called with port lock held and IRQs disabled. | ||
275 | * Returns: | ||
276 | * 1 if we queued up a TX DMA buffer. | ||
277 | * 0 if we didn't want to handle this by DMA | ||
278 | * <0 on error | ||
279 | */ | ||
280 | static int pl011_dma_tx_refill(struct uart_amba_port *uap) | ||
281 | { | ||
282 | struct pl011_dmatx_data *dmatx = &uap->dmatx; | ||
283 | struct dma_chan *chan = dmatx->chan; | ||
284 | struct dma_device *dma_dev = chan->device; | ||
285 | struct dma_async_tx_descriptor *desc; | ||
286 | struct circ_buf *xmit = &uap->port.state->xmit; | ||
287 | unsigned int count; | ||
288 | |||
289 | /* | ||
290 | * Try to avoid the overhead involved in using DMA if the | ||
291 | * transaction fits in the first half of the FIFO, by using | ||
292 | * the standard interrupt handling. This ensures that we | ||
293 | * issue a uart_write_wakeup() at the appropriate time. | ||
294 | */ | ||
295 | count = uart_circ_chars_pending(xmit); | ||
296 | if (count < (uap->fifosize >> 1)) { | ||
297 | uap->dmatx.queued = false; | ||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | /* | ||
302 | * Bodge: don't send the last character by DMA, as this | ||
303 | * will prevent XON from notifying us to restart DMA. | ||
304 | */ | ||
305 | count -= 1; | ||
306 | |||
307 | /* Else proceed to copy the TX chars to the DMA buffer and fire DMA */ | ||
308 | if (count > PL011_DMA_BUFFER_SIZE) | ||
309 | count = PL011_DMA_BUFFER_SIZE; | ||
310 | |||
311 | if (xmit->tail < xmit->head) | ||
312 | memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], count); | ||
313 | else { | ||
314 | size_t first = UART_XMIT_SIZE - xmit->tail; | ||
315 | size_t second = xmit->head; | ||
316 | |||
317 | memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], first); | ||
318 | if (second) | ||
319 | memcpy(&dmatx->buf[first], &xmit->buf[0], second); | ||
320 | } | ||
321 | |||
322 | dmatx->sg.length = count; | ||
323 | |||
324 | if (dma_map_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE) != 1) { | ||
325 | uap->dmatx.queued = false; | ||
326 | dev_dbg(uap->port.dev, "unable to map TX DMA\n"); | ||
327 | return -EBUSY; | ||
328 | } | ||
329 | |||
330 | desc = dma_dev->device_prep_slave_sg(chan, &dmatx->sg, 1, DMA_TO_DEVICE, | ||
331 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | ||
332 | if (!desc) { | ||
333 | dma_unmap_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE); | ||
334 | uap->dmatx.queued = false; | ||
335 | /* | ||
336 | * If DMA cannot be used right now, we complete this | ||
337 | * transaction via IRQ and let the TTY layer retry. | ||
338 | */ | ||
339 | dev_dbg(uap->port.dev, "TX DMA busy\n"); | ||
340 | return -EBUSY; | ||
341 | } | ||
342 | |||
343 | /* Some data to go along to the callback */ | ||
344 | desc->callback = pl011_dma_tx_callback; | ||
345 | desc->callback_param = uap; | ||
346 | |||
347 | /* All errors should happen at prepare time */ | ||
348 | dmaengine_submit(desc); | ||
349 | |||
350 | /* Fire the DMA transaction */ | ||
351 | dma_dev->device_issue_pending(chan); | ||
352 | |||
353 | uap->dmacr |= UART011_TXDMAE; | ||
354 | writew(uap->dmacr, uap->port.membase + UART011_DMACR); | ||
355 | uap->dmatx.queued = true; | ||
356 | |||
357 | /* | ||
358 | * Now we know that DMA will fire, so advance the ring buffer | ||
359 | * with the stuff we just dispatched. | ||
360 | */ | ||
361 | xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); | ||
362 | uap->port.icount.tx += count; | ||
363 | |||
364 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) | ||
365 | uart_write_wakeup(&uap->port); | ||
366 | |||
367 | return 1; | ||
368 | } | ||
369 | |||
370 | /* | ||
371 | * We received a transmit interrupt without a pending X-char but with | ||
372 | * pending characters. | ||
373 | * Locking: called with port lock held and IRQs disabled. | ||
374 | * Returns: | ||
375 | * false if we want to use PIO to transmit | ||
376 | * true if we queued a DMA buffer | ||
377 | */ | ||
378 | static bool pl011_dma_tx_irq(struct uart_amba_port *uap) | ||
379 | { | ||
380 | if (!uap->using_dma) | ||
381 | return false; | ||
382 | |||
383 | /* | ||
384 | * If we already have a TX buffer queued, but received a | ||
385 | * TX interrupt, it will be because we've just sent an X-char. | ||
386 | * Ensure the TX DMA is enabled and the TX IRQ is disabled. | ||
387 | */ | ||
388 | if (uap->dmatx.queued) { | ||
389 | uap->dmacr |= UART011_TXDMAE; | ||
390 | writew(uap->dmacr, uap->port.membase + UART011_DMACR); | ||
391 | uap->im &= ~UART011_TXIM; | ||
392 | writew(uap->im, uap->port.membase + UART011_IMSC); | ||
393 | return true; | ||
394 | } | ||
395 | |||
396 | /* | ||
397 | * We don't have a TX buffer queued, so try to queue one. | ||
398 | * If we succesfully queued a buffer, mask the TX IRQ. | ||
399 | */ | ||
400 | if (pl011_dma_tx_refill(uap) > 0) { | ||
401 | uap->im &= ~UART011_TXIM; | ||
402 | writew(uap->im, uap->port.membase + UART011_IMSC); | ||
403 | return true; | ||
404 | } | ||
405 | return false; | ||
406 | } | ||
407 | |||
408 | /* | ||
409 | * Stop the DMA transmit (eg, due to received XOFF). | ||
410 | * Locking: called with port lock held and IRQs disabled. | ||
411 | */ | ||
412 | static inline void pl011_dma_tx_stop(struct uart_amba_port *uap) | ||
413 | { | ||
414 | if (uap->dmatx.queued) { | ||
415 | uap->dmacr &= ~UART011_TXDMAE; | ||
416 | writew(uap->dmacr, uap->port.membase + UART011_DMACR); | ||
417 | } | ||
418 | } | ||
419 | |||
420 | /* | ||
421 | * Try to start a DMA transmit, or in the case of an XON/OFF | ||
422 | * character queued for send, try to get that character out ASAP. | ||
423 | * Locking: called with port lock held and IRQs disabled. | ||
424 | * Returns: | ||
425 | * false if we want the TX IRQ to be enabled | ||
426 | * true if we have a buffer queued | ||
427 | */ | ||
428 | static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) | ||
429 | { | ||
430 | u16 dmacr; | ||
431 | |||
432 | if (!uap->using_dma) | ||
433 | return false; | ||
434 | |||
435 | if (!uap->port.x_char) { | ||
436 | /* no X-char, try to push chars out in DMA mode */ | ||
437 | bool ret = true; | ||
438 | |||
439 | if (!uap->dmatx.queued) { | ||
440 | if (pl011_dma_tx_refill(uap) > 0) { | ||
441 | uap->im &= ~UART011_TXIM; | ||
442 | ret = true; | ||
443 | } else { | ||
444 | uap->im |= UART011_TXIM; | ||
445 | ret = false; | ||
446 | } | ||
447 | writew(uap->im, uap->port.membase + UART011_IMSC); | ||
448 | } else if (!(uap->dmacr & UART011_TXDMAE)) { | ||
449 | uap->dmacr |= UART011_TXDMAE; | ||
450 | writew(uap->dmacr, | ||
451 | uap->port.membase + UART011_DMACR); | ||
452 | } | ||
453 | return ret; | ||
454 | } | ||
455 | |||
456 | /* | ||
457 | * We have an X-char to send. Disable DMA to prevent it loading | ||
458 | * the TX fifo, and then see if we can stuff it into the FIFO. | ||
459 | */ | ||
460 | dmacr = uap->dmacr; | ||
461 | uap->dmacr &= ~UART011_TXDMAE; | ||
462 | writew(uap->dmacr, uap->port.membase + UART011_DMACR); | ||
463 | |||
464 | if (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) { | ||
465 | /* | ||
466 | * No space in the FIFO, so enable the transmit interrupt | ||
467 | * so we know when there is space. Note that once we've | ||
468 | * loaded the character, we should just re-enable DMA. | ||
469 | */ | ||
470 | return false; | ||
471 | } | ||
472 | |||
473 | writew(uap->port.x_char, uap->port.membase + UART01x_DR); | ||
474 | uap->port.icount.tx++; | ||
475 | uap->port.x_char = 0; | ||
476 | |||
477 | /* Success - restore the DMA state */ | ||
478 | uap->dmacr = dmacr; | ||
479 | writew(dmacr, uap->port.membase + UART011_DMACR); | ||
480 | |||
481 | return true; | ||
482 | } | ||
483 | |||
484 | /* | ||
485 | * Flush the transmit buffer. | ||
486 | * Locking: called with port lock held and IRQs disabled. | ||
487 | */ | ||
488 | static void pl011_dma_flush_buffer(struct uart_port *port) | ||
489 | { | ||
490 | struct uart_amba_port *uap = (struct uart_amba_port *)port; | ||
491 | |||
492 | if (!uap->using_dma) | ||
493 | return; | ||
494 | |||
495 | /* Avoid deadlock with the DMA engine callback */ | ||
496 | spin_unlock(&uap->port.lock); | ||
497 | dmaengine_terminate_all(uap->dmatx.chan); | ||
498 | spin_lock(&uap->port.lock); | ||
499 | if (uap->dmatx.queued) { | ||
500 | dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1, | ||
501 | DMA_TO_DEVICE); | ||
502 | uap->dmatx.queued = false; | ||
503 | uap->dmacr &= ~UART011_TXDMAE; | ||
504 | writew(uap->dmacr, uap->port.membase + UART011_DMACR); | ||
505 | } | ||
506 | } | ||
507 | |||
508 | |||
509 | static void pl011_dma_startup(struct uart_amba_port *uap) | ||
510 | { | ||
511 | if (!uap->dmatx.chan) | ||
512 | return; | ||
513 | |||
514 | uap->dmatx.buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL); | ||
515 | if (!uap->dmatx.buf) { | ||
516 | dev_err(uap->port.dev, "no memory for DMA TX buffer\n"); | ||
517 | uap->port.fifosize = uap->fifosize; | ||
518 | return; | ||
519 | } | ||
520 | |||
521 | sg_init_one(&uap->dmatx.sg, uap->dmatx.buf, PL011_DMA_BUFFER_SIZE); | ||
522 | |||
523 | /* The DMA buffer is now the FIFO the TTY subsystem can use */ | ||
524 | uap->port.fifosize = PL011_DMA_BUFFER_SIZE; | ||
525 | uap->using_dma = true; | ||
526 | |||
527 | /* Turn on DMA error (RX/TX will be enabled on demand) */ | ||
528 | uap->dmacr |= UART011_DMAONERR; | ||
529 | writew(uap->dmacr, uap->port.membase + UART011_DMACR); | ||
530 | } | ||
531 | |||
532 | static void pl011_dma_shutdown(struct uart_amba_port *uap) | ||
533 | { | ||
534 | if (!uap->using_dma) | ||
535 | return; | ||
536 | |||
537 | /* Disable RX and TX DMA */ | ||
538 | while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY) | ||
539 | barrier(); | ||
540 | |||
541 | spin_lock_irq(&uap->port.lock); | ||
542 | uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE); | ||
543 | writew(uap->dmacr, uap->port.membase + UART011_DMACR); | ||
544 | spin_unlock_irq(&uap->port.lock); | ||
545 | |||
546 | /* In theory, this should already be done by pl011_dma_flush_buffer */ | ||
547 | dmaengine_terminate_all(uap->dmatx.chan); | ||
548 | if (uap->dmatx.queued) { | ||
549 | dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1, | ||
550 | DMA_TO_DEVICE); | ||
551 | uap->dmatx.queued = false; | ||
552 | } | ||
553 | |||
554 | kfree(uap->dmatx.buf); | ||
555 | |||
556 | uap->using_dma = false; | ||
557 | } | ||
558 | |||
559 | #else | ||
560 | /* Blank functions if the DMA engine is not available */ | ||
561 | static inline void pl011_dma_probe(struct uart_amba_port *uap) | ||
562 | { | ||
563 | } | ||
564 | |||
565 | static inline void pl011_dma_remove(struct uart_amba_port *uap) | ||
566 | { | ||
567 | } | ||
568 | |||
569 | static inline void pl011_dma_startup(struct uart_amba_port *uap) | ||
570 | { | ||
571 | } | ||
572 | |||
573 | static inline void pl011_dma_shutdown(struct uart_amba_port *uap) | ||
574 | { | ||
575 | } | ||
576 | |||
577 | static inline bool pl011_dma_tx_irq(struct uart_amba_port *uap) | ||
578 | { | ||
579 | return false; | ||
580 | } | ||
581 | |||
582 | static inline void pl011_dma_tx_stop(struct uart_amba_port *uap) | ||
583 | { | ||
584 | } | ||
585 | |||
586 | static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) | ||
587 | { | ||
588 | return false; | ||
589 | } | ||
590 | |||
591 | #define pl011_dma_flush_buffer NULL | ||
592 | #endif | ||
593 | |||
594 | |||
107 | static void pl011_stop_tx(struct uart_port *port) | 595 | static void pl011_stop_tx(struct uart_port *port) |
108 | { | 596 | { |
109 | struct uart_amba_port *uap = (struct uart_amba_port *)port; | 597 | struct uart_amba_port *uap = (struct uart_amba_port *)port; |
110 | 598 | ||
111 | uap->im &= ~UART011_TXIM; | 599 | uap->im &= ~UART011_TXIM; |
112 | writew(uap->im, uap->port.membase + UART011_IMSC); | 600 | writew(uap->im, uap->port.membase + UART011_IMSC); |
601 | pl011_dma_tx_stop(uap); | ||
113 | } | 602 | } |
114 | 603 | ||
115 | static void pl011_start_tx(struct uart_port *port) | 604 | static void pl011_start_tx(struct uart_port *port) |
116 | { | 605 | { |
117 | struct uart_amba_port *uap = (struct uart_amba_port *)port; | 606 | struct uart_amba_port *uap = (struct uart_amba_port *)port; |
118 | 607 | ||
119 | uap->im |= UART011_TXIM; | 608 | if (!pl011_dma_tx_start(uap)) { |
120 | writew(uap->im, uap->port.membase + UART011_IMSC); | 609 | uap->im |= UART011_TXIM; |
610 | writew(uap->im, uap->port.membase + UART011_IMSC); | ||
611 | } | ||
121 | } | 612 | } |
122 | 613 | ||
123 | static void pl011_stop_rx(struct uart_port *port) | 614 | static void pl011_stop_rx(struct uart_port *port) |
@@ -204,6 +695,10 @@ static void pl011_tx_chars(struct uart_amba_port *uap) | |||
204 | return; | 695 | return; |
205 | } | 696 | } |
206 | 697 | ||
698 | /* If we are using DMA mode, try to send some characters. */ | ||
699 | if (pl011_dma_tx_irq(uap)) | ||
700 | return; | ||
701 | |||
207 | count = uap->fifosize >> 1; | 702 | count = uap->fifosize >> 1; |
208 | do { | 703 | do { |
209 | writew(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR); | 704 | writew(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR); |
@@ -434,6 +929,9 @@ static int pl011_startup(struct uart_port *port) | |||
434 | */ | 929 | */ |
435 | uap->old_status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY; | 930 | uap->old_status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY; |
436 | 931 | ||
932 | /* Startup DMA */ | ||
933 | pl011_dma_startup(uap); | ||
934 | |||
437 | /* | 935 | /* |
438 | * Finally, enable interrupts | 936 | * Finally, enable interrupts |
439 | */ | 937 | */ |
@@ -473,6 +971,8 @@ static void pl011_shutdown(struct uart_port *port) | |||
473 | writew(0xffff, uap->port.membase + UART011_ICR); | 971 | writew(0xffff, uap->port.membase + UART011_ICR); |
474 | spin_unlock_irq(&uap->port.lock); | 972 | spin_unlock_irq(&uap->port.lock); |
475 | 973 | ||
974 | pl011_dma_shutdown(uap); | ||
975 | |||
476 | /* | 976 | /* |
477 | * Free the interrupt | 977 | * Free the interrupt |
478 | */ | 978 | */ |
@@ -691,6 +1191,7 @@ static struct uart_ops amba_pl011_pops = { | |||
691 | .break_ctl = pl011_break_ctl, | 1191 | .break_ctl = pl011_break_ctl, |
692 | .startup = pl011_startup, | 1192 | .startup = pl011_startup, |
693 | .shutdown = pl011_shutdown, | 1193 | .shutdown = pl011_shutdown, |
1194 | .flush_buffer = pl011_dma_flush_buffer, | ||
694 | .set_termios = pl011_set_termios, | 1195 | .set_termios = pl011_set_termios, |
695 | .type = pl011_type, | 1196 | .type = pl011_type, |
696 | .release_port = pl010_release_port, | 1197 | .release_port = pl010_release_port, |
@@ -883,6 +1384,7 @@ static int pl011_probe(struct amba_device *dev, struct amba_id *id) | |||
883 | uap->port.ops = &amba_pl011_pops; | 1384 | uap->port.ops = &amba_pl011_pops; |
884 | uap->port.flags = UPF_BOOT_AUTOCONF; | 1385 | uap->port.flags = UPF_BOOT_AUTOCONF; |
885 | uap->port.line = i; | 1386 | uap->port.line = i; |
1387 | pl011_dma_probe(uap); | ||
886 | 1388 | ||
887 | snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev)); | 1389 | snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev)); |
888 | 1390 | ||
@@ -893,6 +1395,7 @@ static int pl011_probe(struct amba_device *dev, struct amba_id *id) | |||
893 | if (ret) { | 1395 | if (ret) { |
894 | amba_set_drvdata(dev, NULL); | 1396 | amba_set_drvdata(dev, NULL); |
895 | amba_ports[i] = NULL; | 1397 | amba_ports[i] = NULL; |
1398 | pl011_dma_remove(uap); | ||
896 | clk_put(uap->clk); | 1399 | clk_put(uap->clk); |
897 | unmap: | 1400 | unmap: |
898 | iounmap(base); | 1401 | iounmap(base); |
@@ -916,6 +1419,7 @@ static int pl011_remove(struct amba_device *dev) | |||
916 | if (amba_ports[i] == uap) | 1419 | if (amba_ports[i] == uap) |
917 | amba_ports[i] = NULL; | 1420 | amba_ports[i] = NULL; |
918 | 1421 | ||
1422 | pl011_dma_remove(uap); | ||
919 | iounmap(uap->port.membase); | 1423 | iounmap(uap->port.membase); |
920 | clk_put(uap->clk); | 1424 | clk_put(uap->clk); |
921 | kfree(uap); | 1425 | kfree(uap); |
diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h index 6021588ba0a8..577f22eb9225 100644 --- a/include/linux/amba/serial.h +++ b/include/linux/amba/serial.h | |||
@@ -180,6 +180,13 @@ struct amba_device; /* in uncompress this is included but amba/bus.h is not */ | |||
180 | struct amba_pl010_data { | 180 | struct amba_pl010_data { |
181 | void (*set_mctrl)(struct amba_device *dev, void __iomem *base, unsigned int mctrl); | 181 | void (*set_mctrl)(struct amba_device *dev, void __iomem *base, unsigned int mctrl); |
182 | }; | 182 | }; |
183 | |||
184 | struct dma_chan; | ||
185 | struct amba_pl011_data { | ||
186 | bool (*dma_filter)(struct dma_chan *chan, void *filter_param); | ||
187 | void *dma_rx_param; | ||
188 | void *dma_tx_param; | ||
189 | }; | ||
183 | #endif | 190 | #endif |
184 | 191 | ||
185 | #endif | 192 | #endif |