mirror of
https://github.com/torvalds/linux.git
synced 2026-06-07 14:04:54 +02:00
serial: 8250_dma: support rockchip dma transfer
Change-Id: I0735c41c7d55770eb24c6dede62d623ae8285bdd Signed-off-by: Huibin Hong <huibin.hong@rock-chips.com>
This commit is contained in:
parent
064129e223
commit
e019b9df43
|
|
@ -46,6 +46,9 @@ struct uart_8250_dma {
|
|||
unsigned char tx_running;
|
||||
unsigned char tx_err;
|
||||
unsigned char rx_running;
|
||||
#ifdef CONFIG_ARCH_ROCKCHIP
|
||||
size_t rx_index;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct old_serial_port {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,12 @@
|
|||
|
||||
#include "8250.h"
|
||||
|
||||
#ifdef CONFIG_ARCH_ROCKCHIP
|
||||
#define MAX_TX_BYTES 64
|
||||
#define MAX_FIFO_SIZE 64
|
||||
#define UART_RFL_16550A 0x21
|
||||
#endif
|
||||
|
||||
static void __dma_tx_complete(void *param)
|
||||
{
|
||||
struct uart_8250_port *p = param;
|
||||
|
|
@ -42,6 +48,39 @@ static void __dma_tx_complete(void *param)
|
|||
spin_unlock_irqrestore(&p->port.lock, flags);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARCH_ROCKCHIP
|
||||
|
||||
static void __dma_rx_complete(void *param)
|
||||
{
|
||||
struct uart_8250_port *p = param;
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
struct tty_port *tty_port = &p->port.state->port;
|
||||
struct dma_tx_state state;
|
||||
unsigned int count = 0, cur_index = 0;
|
||||
|
||||
dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
|
||||
cur_index = dma->rx_size - state.residue;
|
||||
|
||||
if (cur_index == dma->rx_index)
|
||||
return;
|
||||
else if (cur_index > dma->rx_index)
|
||||
count = cur_index - dma->rx_index;
|
||||
else
|
||||
count = dma->rx_size - dma->rx_index;
|
||||
|
||||
tty_insert_flip_string(tty_port, dma->rx_buf + dma->rx_index, count);
|
||||
|
||||
if (cur_index < dma->rx_index) {
|
||||
tty_insert_flip_string(tty_port, dma->rx_buf, cur_index);
|
||||
count += cur_index;
|
||||
}
|
||||
|
||||
p->port.icount.rx += count;
|
||||
dma->rx_index = cur_index;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void __dma_rx_complete(void *param)
|
||||
{
|
||||
struct uart_8250_port *p = param;
|
||||
|
|
@ -61,6 +100,8 @@ static void __dma_rx_complete(void *param)
|
|||
tty_flip_buffer_push(tty_port);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int serial8250_tx_dma(struct uart_8250_port *p)
|
||||
{
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
|
|
@ -78,7 +119,12 @@ int serial8250_tx_dma(struct uart_8250_port *p)
|
|||
}
|
||||
|
||||
dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
|
||||
|
||||
#ifdef CONFIG_ARCH_ROCKCHIP
|
||||
if (dma->tx_size < MAX_TX_BYTES) {
|
||||
ret = -EBUSY;
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
desc = dmaengine_prep_slave_single(dma->txchan,
|
||||
dma->tx_addr + xmit->tail,
|
||||
dma->tx_size, DMA_MEM_TO_DEV,
|
||||
|
|
@ -111,6 +157,64 @@ int serial8250_tx_dma(struct uart_8250_port *p)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARCH_ROCKCHIP
|
||||
|
||||
int serial8250_rx_dma(struct uart_8250_port *p)
|
||||
{
|
||||
unsigned int rfl, i = 0, fcr = 0, cur_index = 0;
|
||||
unsigned char buf[MAX_FIFO_SIZE];
|
||||
struct uart_port *port = &p->port;
|
||||
struct tty_port *tty_port = &p->port.state->port;
|
||||
struct dma_tx_state state;
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
|
||||
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_T_TRIG_10 | UART_FCR_R_TRIG_11;
|
||||
serial_port_out(port, UART_FCR, fcr);
|
||||
|
||||
do {
|
||||
dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
|
||||
cur_index = dma->rx_size - state.residue;
|
||||
} while (cur_index % dma->rxconf.src_maxburst);
|
||||
|
||||
rfl = serial_port_in(port, UART_RFL_16550A);
|
||||
while (i < rfl)
|
||||
buf[i++] = serial_port_in(port, UART_RX);
|
||||
|
||||
__dma_rx_complete(p);
|
||||
|
||||
tty_insert_flip_string(tty_port, buf, i);
|
||||
p->port.icount.rx += i;
|
||||
tty_flip_buffer_push(tty_port);
|
||||
|
||||
if (fcr)
|
||||
serial_port_out(port, UART_FCR, p->fcr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int serial8250_start_rx_dma(struct uart_8250_port *p)
|
||||
{
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
|
||||
desc = dmaengine_prep_dma_cyclic(dma->rxchan, dma->rx_addr,
|
||||
dma->rx_size, dma->rx_size,
|
||||
DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT |
|
||||
DMA_CTRL_ACK);
|
||||
if (!desc)
|
||||
return -EBUSY;
|
||||
|
||||
dma->rx_running = 1;
|
||||
desc->callback = NULL;
|
||||
desc->callback_param = NULL;
|
||||
|
||||
dma->rx_cookie = dmaengine_submit(desc);
|
||||
dma_async_issue_pending(dma->rxchan);
|
||||
dma->rx_index = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int serial8250_rx_dma(struct uart_8250_port *p)
|
||||
{
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
|
|
@ -136,6 +240,8 @@ int serial8250_rx_dma(struct uart_8250_port *p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void serial8250_rx_dma_flush(struct uart_8250_port *p)
|
||||
{
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
|
|
@ -163,11 +269,19 @@ int serial8250_request_dma(struct uart_8250_port *p)
|
|||
dma->rxconf.direction = DMA_DEV_TO_MEM;
|
||||
dma->rxconf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
dma->rxconf.src_addr = rx_dma_addr + UART_RX;
|
||||
#ifdef CONFIG_ARCH_ROCKCHIP
|
||||
if ((p->port.fifosize / 4) < 16)
|
||||
dma->rxconf.src_maxburst = p->port.fifosize / 4;
|
||||
else
|
||||
dma->rxconf.src_maxburst = 16;
|
||||
#endif
|
||||
|
||||
dma->txconf.direction = DMA_MEM_TO_DEV;
|
||||
dma->txconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
dma->txconf.dst_addr = tx_dma_addr + UART_TX;
|
||||
|
||||
#ifdef CONFIG_ARCH_ROCKCHIP
|
||||
dma->txconf.dst_maxburst = 16;
|
||||
#endif
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
|
||||
|
|
@ -211,8 +325,13 @@ int serial8250_request_dma(struct uart_8250_port *p)
|
|||
dmaengine_slave_config(dma->txchan, &dma->txconf);
|
||||
|
||||
/* RX buffer */
|
||||
#ifdef CONFIG_ARCH_ROCKCHIP
|
||||
if (!dma->rx_size)
|
||||
dma->rx_size = PAGE_SIZE * 2;
|
||||
#else
|
||||
if (!dma->rx_size)
|
||||
dma->rx_size = PAGE_SIZE;
|
||||
#endif
|
||||
|
||||
dma->rx_buf = dma_alloc_coherent(dma->rxchan->device->dev, dma->rx_size,
|
||||
&dma->rx_addr, GFP_KERNEL);
|
||||
|
|
@ -234,7 +353,10 @@ int serial8250_request_dma(struct uart_8250_port *p)
|
|||
}
|
||||
|
||||
dev_dbg_ratelimited(p->port.dev, "got both dma channels\n");
|
||||
|
||||
#ifdef CONFIG_ARCH_ROCKCHIP
|
||||
/* start dma for rx*/
|
||||
serial8250_start_rx_dma(p);
|
||||
#endif
|
||||
return 0;
|
||||
err:
|
||||
dma_release_channel(dma->txchan);
|
||||
|
|
@ -257,7 +379,9 @@ void serial8250_release_dma(struct uart_8250_port *p)
|
|||
dma->rx_addr);
|
||||
dma_release_channel(dma->rxchan);
|
||||
dma->rxchan = NULL;
|
||||
|
||||
#ifdef CONFIG_ARCH_ROCKCHIP
|
||||
dma->rx_running = 0;
|
||||
#endif
|
||||
/* Release TX resources */
|
||||
dmaengine_terminate_sync(dma->txchan);
|
||||
dma_unmap_single(dma->txchan->device->dev, dma->tx_addr,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user