diff options
| -rw-r--r-- | drivers/tty/serial/imx.c | 405 |
1 files changed, 400 insertions, 5 deletions
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 79d1943c2e79..90655b875bab 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c | |||
| @@ -48,9 +48,11 @@ | |||
| 48 | #include <linux/of.h> | 48 | #include <linux/of.h> |
| 49 | #include <linux/of_device.h> | 49 | #include <linux/of_device.h> |
| 50 | #include <linux/io.h> | 50 | #include <linux/io.h> |
| 51 | #include <linux/dma-mapping.h> | ||
| 51 | 52 | ||
| 52 | #include <asm/irq.h> | 53 | #include <asm/irq.h> |
| 53 | #include <linux/platform_data/serial-imx.h> | 54 | #include <linux/platform_data/serial-imx.h> |
| 55 | #include <linux/platform_data/dma-imx.h> | ||
| 54 | 56 | ||
| 55 | /* Register definitions */ | 57 | /* Register definitions */ |
| 56 | #define URXD0 0x0 /* Receiver Register */ | 58 | #define URXD0 0x0 /* Receiver Register */ |
| @@ -82,6 +84,7 @@ | |||
| 82 | #define UCR1_ADBR (1<<14) /* Auto detect baud rate */ | 84 | #define UCR1_ADBR (1<<14) /* Auto detect baud rate */ |
| 83 | #define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */ | 85 | #define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */ |
| 84 | #define UCR1_IDEN (1<<12) /* Idle condition interrupt */ | 86 | #define UCR1_IDEN (1<<12) /* Idle condition interrupt */ |
| 87 | #define UCR1_ICD_REG(x) (((x) & 3) << 10) /* idle condition detect */ | ||
| 85 | #define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */ | 88 | #define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */ |
| 86 | #define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */ | 89 | #define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */ |
| 87 | #define UCR1_IREN (1<<7) /* Infrared interface enable */ | 90 | #define UCR1_IREN (1<<7) /* Infrared interface enable */ |
| @@ -90,6 +93,7 @@ | |||
| 90 | #define UCR1_SNDBRK (1<<4) /* Send break */ | 93 | #define UCR1_SNDBRK (1<<4) /* Send break */ |
| 91 | #define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */ | 94 | #define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */ |
| 92 | #define IMX1_UCR1_UARTCLKEN (1<<2) /* UART clock enabled, i.mx1 only */ | 95 | #define IMX1_UCR1_UARTCLKEN (1<<2) /* UART clock enabled, i.mx1 only */ |
| 96 | #define UCR1_ATDMAEN (1<<2) /* Aging DMA Timer Enable */ | ||
| 93 | #define UCR1_DOZE (1<<1) /* Doze */ | 97 | #define UCR1_DOZE (1<<1) /* Doze */ |
| 94 | #define UCR1_UARTEN (1<<0) /* UART enabled */ | 98 | #define UCR1_UARTEN (1<<0) /* UART enabled */ |
| 95 | #define UCR2_ESCI (1<<15) /* Escape seq interrupt enable */ | 99 | #define UCR2_ESCI (1<<15) /* Escape seq interrupt enable */ |
| @@ -125,6 +129,7 @@ | |||
| 125 | #define UCR4_ENIRI (1<<8) /* Serial infrared interrupt enable */ | 129 | #define UCR4_ENIRI (1<<8) /* Serial infrared interrupt enable */ |
| 126 | #define UCR4_WKEN (1<<7) /* Wake interrupt enable */ | 130 | #define UCR4_WKEN (1<<7) /* Wake interrupt enable */ |
| 127 | #define UCR4_REF16 (1<<6) /* Ref freq 16 MHz */ | 131 | #define UCR4_REF16 (1<<6) /* Ref freq 16 MHz */ |
| 132 | #define UCR4_IDDMAEN (1<<6) /* DMA IDLE Condition Detected */ | ||
| 128 | #define UCR4_IRSC (1<<5) /* IR special case */ | 133 | #define UCR4_IRSC (1<<5) /* IR special case */ |
| 129 | #define UCR4_TCEN (1<<3) /* Transmit complete interrupt enable */ | 134 | #define UCR4_TCEN (1<<3) /* Transmit complete interrupt enable */ |
| 130 | #define UCR4_BKEN (1<<2) /* Break condition interrupt enable */ | 135 | #define UCR4_BKEN (1<<2) /* Break condition interrupt enable */ |
| @@ -209,6 +214,19 @@ struct imx_port { | |||
| 209 | struct clk *clk_ipg; | 214 | struct clk *clk_ipg; |
| 210 | struct clk *clk_per; | 215 | struct clk *clk_per; |
| 211 | const struct imx_uart_data *devdata; | 216 | const struct imx_uart_data *devdata; |
| 217 | |||
| 218 | /* DMA fields */ | ||
| 219 | unsigned int dma_is_inited:1; | ||
| 220 | unsigned int dma_is_enabled:1; | ||
| 221 | unsigned int dma_is_rxing:1; | ||
| 222 | unsigned int dma_is_txing:1; | ||
| 223 | struct dma_chan *dma_chan_rx, *dma_chan_tx; | ||
| 224 | struct scatterlist rx_sgl, tx_sgl[2]; | ||
| 225 | void *rx_buf; | ||
| 226 | unsigned int rx_bytes, tx_bytes; | ||
| 227 | struct work_struct tsk_dma_rx, tsk_dma_tx; | ||
| 228 | unsigned int dma_tx_nents; | ||
| 229 | wait_queue_head_t dma_wait; | ||
| 212 | }; | 230 | }; |
| 213 | 231 | ||
| 214 | struct imx_port_ucrs { | 232 | struct imx_port_ucrs { |
| @@ -399,6 +417,13 @@ static void imx_stop_tx(struct uart_port *port) | |||
| 399 | return; | 417 | return; |
| 400 | } | 418 | } |
| 401 | 419 | ||
| 420 | /* | ||
| 421 | * We are maybe in the SMP context, so if the DMA TX thread is running | ||
| 422 | * on other cpu, we have to wait for it to finish. | ||
| 423 | */ | ||
| 424 | if (sport->dma_is_enabled && sport->dma_is_txing) | ||
| 425 | return; | ||
| 426 | |||
| 402 | temp = readl(sport->port.membase + UCR1); | 427 | temp = readl(sport->port.membase + UCR1); |
| 403 | writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1); | 428 | writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1); |
| 404 | } | 429 | } |
| @@ -411,6 +436,13 @@ static void imx_stop_rx(struct uart_port *port) | |||
| 411 | struct imx_port *sport = (struct imx_port *)port; | 436 | struct imx_port *sport = (struct imx_port *)port; |
| 412 | unsigned long temp; | 437 | unsigned long temp; |
| 413 | 438 | ||
| 439 | /* | ||
| 440 | * We are maybe in the SMP context, so if the DMA TX thread is running | ||
| 441 | * on other cpu, we have to wait for it to finish. | ||
| 442 | */ | ||
| 443 | if (sport->dma_is_enabled && sport->dma_is_rxing) | ||
| 444 | return; | ||
| 445 | |||
| 414 | temp = readl(sport->port.membase + UCR2); | 446 | temp = readl(sport->port.membase + UCR2); |
| 415 | writel(temp & ~UCR2_RXEN, sport->port.membase + UCR2); | 447 | writel(temp & ~UCR2_RXEN, sport->port.membase + UCR2); |
| 416 | } | 448 | } |
| @@ -446,6 +478,95 @@ static inline void imx_transmit_buffer(struct imx_port *sport) | |||
| 446 | imx_stop_tx(&sport->port); | 478 | imx_stop_tx(&sport->port); |
| 447 | } | 479 | } |
| 448 | 480 | ||
| 481 | static void dma_tx_callback(void *data) | ||
| 482 | { | ||
| 483 | struct imx_port *sport = data; | ||
| 484 | struct scatterlist *sgl = &sport->tx_sgl[0]; | ||
| 485 | struct circ_buf *xmit = &sport->port.state->xmit; | ||
| 486 | unsigned long flags; | ||
| 487 | |||
| 488 | dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); | ||
| 489 | |||
| 490 | sport->dma_is_txing = 0; | ||
| 491 | |||
| 492 | /* update the stat */ | ||
| 493 | spin_lock_irqsave(&sport->port.lock, flags); | ||
| 494 | xmit->tail = (xmit->tail + sport->tx_bytes) & (UART_XMIT_SIZE - 1); | ||
| 495 | sport->port.icount.tx += sport->tx_bytes; | ||
| 496 | spin_unlock_irqrestore(&sport->port.lock, flags); | ||
| 497 | |||
| 498 | dev_dbg(sport->port.dev, "we finish the TX DMA.\n"); | ||
| 499 | |||
| 500 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) | ||
| 501 | uart_write_wakeup(&sport->port); | ||
| 502 | |||
| 503 | if (waitqueue_active(&sport->dma_wait)) { | ||
| 504 | wake_up(&sport->dma_wait); | ||
| 505 | dev_dbg(sport->port.dev, "exit in %s.\n", __func__); | ||
| 506 | return; | ||
| 507 | } | ||
| 508 | |||
| 509 | schedule_work(&sport->tsk_dma_tx); | ||
| 510 | } | ||
| 511 | |||
| 512 | static void dma_tx_work(struct work_struct *w) | ||
| 513 | { | ||
| 514 | struct imx_port *sport = container_of(w, struct imx_port, tsk_dma_tx); | ||
| 515 | struct circ_buf *xmit = &sport->port.state->xmit; | ||
| 516 | struct scatterlist *sgl = sport->tx_sgl; | ||
| 517 | struct dma_async_tx_descriptor *desc; | ||
| 518 | struct dma_chan *chan = sport->dma_chan_tx; | ||
| 519 | struct device *dev = sport->port.dev; | ||
| 520 | enum dma_status status; | ||
| 521 | unsigned long flags; | ||
| 522 | int ret; | ||
| 523 | |||
| 524 | status = chan->device->device_tx_status(chan, (dma_cookie_t)0, NULL); | ||
| 525 | if (DMA_IN_PROGRESS == status) | ||
| 526 | return; | ||
| 527 | |||
| 528 | spin_lock_irqsave(&sport->port.lock, flags); | ||
| 529 | sport->tx_bytes = uart_circ_chars_pending(xmit); | ||
| 530 | if (sport->tx_bytes == 0) { | ||
| 531 | spin_unlock_irqrestore(&sport->port.lock, flags); | ||
| 532 | return; | ||
| 533 | } | ||
| 534 | |||
| 535 | if (xmit->tail > xmit->head) { | ||
| 536 | sport->dma_tx_nents = 2; | ||
| 537 | sg_init_table(sgl, 2); | ||
| 538 | sg_set_buf(sgl, xmit->buf + xmit->tail, | ||
| 539 | UART_XMIT_SIZE - xmit->tail); | ||
| 540 | sg_set_buf(sgl + 1, xmit->buf, xmit->head); | ||
| 541 | } else { | ||
| 542 | sport->dma_tx_nents = 1; | ||
| 543 | sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes); | ||
| 544 | } | ||
| 545 | spin_unlock_irqrestore(&sport->port.lock, flags); | ||
| 546 | |||
| 547 | ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); | ||
| 548 | if (ret == 0) { | ||
| 549 | dev_err(dev, "DMA mapping error for TX.\n"); | ||
| 550 | return; | ||
| 551 | } | ||
| 552 | desc = dmaengine_prep_slave_sg(chan, sgl, sport->dma_tx_nents, | ||
| 553 | DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT); | ||
| 554 | if (!desc) { | ||
| 555 | dev_err(dev, "We cannot prepare for the TX slave dma!\n"); | ||
| 556 | return; | ||
| 557 | } | ||
| 558 | desc->callback = dma_tx_callback; | ||
| 559 | desc->callback_param = sport; | ||
| 560 | |||
| 561 | dev_dbg(dev, "TX: prepare to send %lu bytes by DMA.\n", | ||
| 562 | uart_circ_chars_pending(xmit)); | ||
| 563 | /* fire it */ | ||
| 564 | sport->dma_is_txing = 1; | ||
| 565 | dmaengine_submit(desc); | ||
| 566 | dma_async_issue_pending(chan); | ||
| 567 | return; | ||
| 568 | } | ||
| 569 | |||
