Skip to content

Commit

Permalink
serial: 8250_dma: support rockchip dma transfer
Browse files Browse the repository at this point in the history
Change-Id: I0735c41c7d55770eb24c6dede62d623ae8285bdd
Signed-off-by: Huibin Hong <huibin.hong@rock-chips.com>
  • Loading branch information
Huibin Hong authored and rkhuangtao committed Jul 26, 2021
1 parent fc7855d commit ec403a4
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 4 deletions.
12 changes: 12 additions & 0 deletions drivers/tty/serial/8250/8250.h
Expand Up @@ -48,6 +48,9 @@ struct uart_8250_dma {
unsigned char tx_running;
unsigned char tx_err;
unsigned char rx_running;
#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI)
size_t rx_index;
#endif
};

struct old_serial_port {
Expand Down Expand Up @@ -305,6 +308,9 @@ static inline int is_omap1510_8250(struct uart_8250_port *pt)
#ifdef CONFIG_SERIAL_8250_DMA
extern int serial8250_tx_dma(struct uart_8250_port *);
extern int serial8250_rx_dma(struct uart_8250_port *);
#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI)
extern int serial8250_start_rx_dma(struct uart_8250_port *);
#endif
extern void serial8250_rx_dma_flush(struct uart_8250_port *);
extern int serial8250_request_dma(struct uart_8250_port *);
extern void serial8250_release_dma(struct uart_8250_port *);
Expand All @@ -317,6 +323,12 @@ static inline int serial8250_rx_dma(struct uart_8250_port *p)
{
return -1;
}
#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI)
static inline int serial8250_start_rx_dma(struct uart_8250_port *p)
{
return -1;
}
#endif
static inline void serial8250_rx_dma_flush(struct uart_8250_port *p) { }
static inline int serial8250_request_dma(struct uart_8250_port *p)
{
Expand Down
132 changes: 128 additions & 4 deletions drivers/tty/serial/8250/8250_dma.c
Expand Up @@ -11,6 +11,12 @@

#include "8250.h"

#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI)
#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;
Expand Down Expand Up @@ -40,6 +46,39 @@ static void __dma_tx_complete(void *param)
spin_unlock_irqrestore(&p->port.lock, flags);
}

#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI)

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;
Expand All @@ -59,6 +98,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;
Expand All @@ -76,7 +117,12 @@ int serial8250_tx_dma(struct uart_8250_port *p)
}

dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);

#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI)
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,
Expand Down Expand Up @@ -106,6 +152,64 @@ int serial8250_tx_dma(struct uart_8250_port *p)
return ret;
}

#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI)

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;
Expand All @@ -131,6 +235,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;
Expand Down Expand Up @@ -158,11 +264,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;
#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI)
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;

#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI)
dma->txconf.dst_maxburst = 16;
#endif
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);

Expand Down Expand Up @@ -206,8 +320,13 @@ int serial8250_request_dma(struct uart_8250_port *p)
dmaengine_slave_config(dma->txchan, &dma->txconf);

/* RX buffer */
#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI)
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);
Expand All @@ -229,7 +348,10 @@ int serial8250_request_dma(struct uart_8250_port *p)
}

dev_dbg_ratelimited(p->port.dev, "got both dma channels\n");

#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI)
/* start dma for rx*/
serial8250_start_rx_dma(p);
#endif
return 0;
err:
dma_release_channel(dma->txchan);
Expand All @@ -252,7 +374,9 @@ void serial8250_release_dma(struct uart_8250_port *p)
dma->rx_addr);
dma_release_channel(dma->rxchan);
dma->rxchan = NULL;

#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI)
dma->rx_running = 0;
#endif
/* Release TX resources */
dmaengine_terminate_sync(dma->txchan);
dma_unmap_single(dma->txchan->device->dev, dma->tx_addr,
Expand Down

0 comments on commit ec403a4

Please sign in to comment.