Skip to content

Commit 85b5c1d

Browse files
Long Chenggregkh
authored andcommitted
serial: 8250-mtk: add uart DMA support
Modify uart register to support DMA function. Signed-off-by: Long Cheng <long.cheng@mediatek.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 8921246 commit 85b5c1d

File tree

1 file changed

+209
-1
lines changed

1 file changed

+209
-1
lines changed

drivers/tty/serial/8250/8250_mtk.c

Lines changed: 209 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
#include <linux/pm_runtime.h>
1515
#include <linux/serial_8250.h>
1616
#include <linux/serial_reg.h>
17+
#include <linux/console.h>
18+
#include <linux/dma-mapping.h>
19+
#include <linux/tty.h>
20+
#include <linux/tty_flip.h>
1721

1822
#include "8250.h"
1923

@@ -22,12 +26,172 @@
2226
#define UART_MTK_SAMPLE_POINT 0x0b /* Sample point register */
2327
#define MTK_UART_RATE_FIX 0x0d /* UART Rate Fix Register */
2428

29+
#define MTK_UART_DMA_EN 0x13 /* DMA Enable register */
30+
#define MTK_UART_DMA_EN_TX 0x2
31+
#define MTK_UART_DMA_EN_RX 0x5
32+
33+
#define MTK_UART_TX_SIZE UART_XMIT_SIZE
34+
#define MTK_UART_RX_SIZE 0x8000
35+
#define MTK_UART_TX_TRIGGER 1
36+
#define MTK_UART_RX_TRIGGER MTK_UART_RX_SIZE
37+
38+
#ifdef CONFIG_SERIAL_8250_DMA
39+
enum dma_rx_status {
40+
DMA_RX_START = 0,
41+
DMA_RX_RUNNING = 1,
42+
DMA_RX_SHUTDOWN = 2,
43+
};
44+
#endif
45+
2546
struct mtk8250_data {
2647
int line;
48+
unsigned int rx_pos;
2749
struct clk *uart_clk;
2850
struct clk *bus_clk;
51+
struct uart_8250_dma *dma;
52+
#ifdef CONFIG_SERIAL_8250_DMA
53+
enum dma_rx_status rx_status;
54+
#endif
2955
};
3056

57+
#ifdef CONFIG_SERIAL_8250_DMA
58+
static void mtk8250_rx_dma(struct uart_8250_port *up);
59+
60+
static void mtk8250_dma_rx_complete(void *param)
61+
{
62+
struct uart_8250_port *up = param;
63+
struct uart_8250_dma *dma = up->dma;
64+
struct mtk8250_data *data = up->port.private_data;
65+
struct tty_port *tty_port = &up->port.state->port;
66+
struct dma_tx_state state;
67+
unsigned char *ptr;
68+
int copied;
69+
70+
dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
71+
dma->rx_size, DMA_FROM_DEVICE);
72+
73+
dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
74+
75+
if (data->rx_status == DMA_RX_SHUTDOWN)
76+
return;
77+
78+
if ((data->rx_pos + state.residue) <= dma->rx_size) {
79+
ptr = (unsigned char *)(data->rx_pos + dma->rx_buf);
80+
copied = tty_insert_flip_string(tty_port, ptr, state.residue);
81+
} else {
82+
ptr = (unsigned char *)(data->rx_pos + dma->rx_buf);
83+
copied = tty_insert_flip_string(tty_port, ptr,
84+
dma->rx_size - data->rx_pos);
85+
ptr = (unsigned char *)(dma->rx_buf);
86+
copied += tty_insert_flip_string(tty_port, ptr,
87+
data->rx_pos + state.residue - dma->rx_size);
88+
}
89+
up->port.icount.rx += copied;
90+
91+
tty_flip_buffer_push(tty_port);
92+
93+
mtk8250_rx_dma(up);
94+
}
95+
96+
static void mtk8250_rx_dma(struct uart_8250_port *up)
97+
{
98+
struct uart_8250_dma *dma = up->dma;
99+
struct mtk8250_data *data = up->port.private_data;
100+
struct dma_async_tx_descriptor *desc;
101+
struct dma_tx_state state;
102+
103+
desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr,
104+
dma->rx_size, DMA_DEV_TO_MEM,
105+
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
106+
if (!desc) {
107+
pr_err("failed to prepare rx slave single\n");
108+
return;
109+
}
110+
111+
desc->callback = mtk8250_dma_rx_complete;
112+
desc->callback_param = up;
113+
114+
dma->rx_cookie = dmaengine_submit(desc);
115+
116+
dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
117+
data->rx_pos = state.residue;
118+
119+
dma_sync_single_for_device(dma->rxchan->device->dev, dma->rx_addr,
120+
dma->rx_size, DMA_FROM_DEVICE);
121+
122+
dma_async_issue_pending(dma->rxchan);
123+
}
124+
125+
static void mtk8250_dma_enable(struct uart_8250_port *up)
126+
{
127+
struct uart_8250_dma *dma = up->dma;
128+
struct mtk8250_data *data = up->port.private_data;
129+
int lcr = serial_in(up, UART_LCR);
130+
131+
if (data->rx_status != DMA_RX_START)
132+
return;
133+
134+
dma->rxconf.direction = DMA_DEV_TO_MEM;
135+
dma->rxconf.src_addr_width = dma->rx_size / 1024;
136+
dma->rxconf.src_addr = dma->rx_addr;
137+
138+
dma->txconf.direction = DMA_MEM_TO_DEV;
139+
dma->txconf.dst_addr_width = MTK_UART_TX_SIZE / 1024;
140+
dma->txconf.dst_addr = dma->tx_addr;
141+
142+
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
143+
UART_FCR_CLEAR_XMIT);
144+
serial_out(up, MTK_UART_DMA_EN,
145+
MTK_UART_DMA_EN_RX | MTK_UART_DMA_EN_TX);
146+
147+
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
148+
serial_out(up, UART_EFR, UART_EFR_ECB);
149+
serial_out(up, UART_LCR, lcr);
150+
151+
if (dmaengine_slave_config(dma->rxchan, &dma->rxconf) != 0)
152+
pr_err("failed to configure rx dma channel\n");
153+
if (dmaengine_slave_config(dma->txchan, &dma->txconf) != 0)
154+
pr_err("failed to configure tx dma channel\n");
155+
156+
data->rx_status = DMA_RX_RUNNING;
157+
data->rx_pos = 0;
158+
mtk8250_rx_dma(up);
159+
}
160+
#endif
161+
162+
static int mtk8250_startup(struct uart_port *port)
163+
{
164+
#ifdef CONFIG_SERIAL_8250_DMA
165+
struct uart_8250_port *up = up_to_u8250p(port);
166+
struct mtk8250_data *data = port->private_data;
167+
168+
/* disable DMA for console */
169+
if (uart_console(port))
170+
up->dma = NULL;
171+
172+
if (up->dma) {
173+
data->rx_status = DMA_RX_START;
174+
uart_circ_clear(&port->state->xmit);
175+
}
176+
#endif
177+
memset(&port->icount, 0, sizeof(port->icount));
178+
179+
return serial8250_do_startup(port);
180+
}
181+
182+
static void mtk8250_shutdown(struct uart_port *port)
183+
{
184+
#ifdef CONFIG_SERIAL_8250_DMA
185+
struct uart_8250_port *up = up_to_u8250p(port);
186+
struct mtk8250_data *data = port->private_data;
187+
188+
if (up->dma)
189+
data->rx_status = DMA_RX_SHUTDOWN;
190+
#endif
191+
192+
return serial8250_do_shutdown(port);
193+
}
194+
31195
static void
32196
mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
33197
struct ktermios *old)
@@ -36,6 +200,17 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
36200
unsigned long flags;
37201
unsigned int baud, quot;
38202

203+
#ifdef CONFIG_SERIAL_8250_DMA
204+
if (up->dma) {
205+
if (uart_console(port)) {
206+
devm_kfree(up->port.dev, up->dma);
207+
up->dma = NULL;
208+
} else {
209+
mtk8250_dma_enable(up);
210+
}
211+
}
212+
#endif
213+
39214
serial8250_do_set_termios(port, termios, old);
40215

41216
/*
@@ -143,9 +318,20 @@ mtk8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
143318
pm_runtime_put_sync_suspend(port->dev);
144319
}
145320

321+
#ifdef CONFIG_SERIAL_8250_DMA
322+
static bool mtk8250_dma_filter(struct dma_chan *chan, void *param)
323+
{
324+
return false;
325+
}
326+
#endif
327+
146328
static int mtk8250_probe_of(struct platform_device *pdev, struct uart_port *p,
147329
struct mtk8250_data *data)
148330
{
331+
#ifdef CONFIG_SERIAL_8250_DMA
332+
int dmacnt;
333+
#endif
334+
149335
data->uart_clk = devm_clk_get(&pdev->dev, "baud");
150336
if (IS_ERR(data->uart_clk)) {
151337
/*
@@ -162,7 +348,23 @@ static int mtk8250_probe_of(struct platform_device *pdev, struct uart_port *p,
162348
}
163349

164350
data->bus_clk = devm_clk_get(&pdev->dev, "bus");
165-
return PTR_ERR_OR_ZERO(data->bus_clk);
351+
if (IS_ERR(data->bus_clk))
352+
return PTR_ERR(data->bus_clk);
353+
354+
data->dma = NULL;
355+
#ifdef CONFIG_SERIAL_8250_DMA
356+
dmacnt = of_property_count_strings(pdev->dev.of_node, "dma-names");
357+
if (dmacnt == 2) {
358+
data->dma = devm_kzalloc(&pdev->dev, sizeof(*data->dma),
359+
GFP_KERNEL);
360+
data->dma->fn = mtk8250_dma_filter;
361+
data->dma->rx_size = MTK_UART_RX_SIZE;
362+
data->dma->rxconf.src_maxburst = MTK_UART_RX_TRIGGER;
363+
data->dma->txconf.dst_maxburst = MTK_UART_TX_TRIGGER;
364+
}
365+
#endif
366+
367+
return 0;
166368
}
167369

168370
static int mtk8250_probe(struct platform_device *pdev)
@@ -204,8 +406,14 @@ static int mtk8250_probe(struct platform_device *pdev)
204406
uart.port.iotype = UPIO_MEM32;
205407
uart.port.regshift = 2;
206408
uart.port.private_data = data;
409+
uart.port.shutdown = mtk8250_shutdown;
410+
uart.port.startup = mtk8250_startup;
207411
uart.port.set_termios = mtk8250_set_termios;
208412
uart.port.uartclk = clk_get_rate(data->uart_clk);
413+
#ifdef CONFIG_SERIAL_8250_DMA
414+
if (data->dma)
415+
uart.dma = data->dma;
416+
#endif
209417

210418
/* Disable Rate Fix function */
211419
writel(0x0, uart.port.membase +

0 commit comments

Comments
 (0)