Skip to content
Snippets Groups Projects
Commit db0a196b authored by Fabien Lahoudere's avatar Fabien Lahoudere Committed by Greg Kroah-Hartman
Browse files

serial: imx: Add DMA buffer configuration via DT


In order to optimize serial communication (performance/throughput VS
latency), we may need to tweak DMA period number and size. This adds
DT properties to configure those values before initialising DMA.
The defaults will stay the same as before.

[update documentation and commit message, rebase to current master,
switch back to DT instead of sysfs]

Signed-off-by: default avatarFabien Lahoudere <fabien.lahoudere@collabora.com>
Signed-off-by: default avatarSebastian Reichel <sebastian.reichel@collabora.com>
Link: https://lore.kernel.org/r/20210430175038.103226-2-sebastian.reichel@collabora.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 910cc953
No related branches found
No related tags found
No related merge requests found
...@@ -71,6 +71,18 @@ properties: ...@@ -71,6 +71,18 @@ properties:
received, and that the peripheral should invert its input using the received, and that the peripheral should invert its input using the
INVR registers. INVR registers.
fsl,dma-info:
$ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 2
maxItems: 2
description: |
First cell contains the size of DMA buffer chunks, second cell contains
the amount of chunks used for the device. Multiplying both numbers is
the total size of memory used for receiving data.
When not being configured the system will use default settings, which
are sensible for most use cases. If you need low latency processing on
slow connections this needs to be configured appropriately.
uart-has-rtscts: true uart-has-rtscts: true
rs485-rts-delay: true rs485-rts-delay: true
......
...@@ -225,6 +225,8 @@ struct imx_port { ...@@ -225,6 +225,8 @@ struct imx_port {
struct scatterlist rx_sgl, tx_sgl[2]; struct scatterlist rx_sgl, tx_sgl[2];
void *rx_buf; void *rx_buf;
struct circ_buf rx_ring; struct circ_buf rx_ring;
unsigned int rx_buf_size;
unsigned int rx_period_length;
unsigned int rx_periods; unsigned int rx_periods;
dma_cookie_t rx_cookie; dma_cookie_t rx_cookie;
unsigned int tx_bytes; unsigned int tx_bytes;
...@@ -1183,10 +1185,6 @@ static void imx_uart_dma_rx_callback(void *data) ...@@ -1183,10 +1185,6 @@ static void imx_uart_dma_rx_callback(void *data)
} }
} }
/* RX DMA buffer periods */
#define RX_DMA_PERIODS 16
#define RX_BUF_SIZE (RX_DMA_PERIODS * PAGE_SIZE / 4)
static int imx_uart_start_rx_dma(struct imx_port *sport) static int imx_uart_start_rx_dma(struct imx_port *sport)
{ {
struct scatterlist *sgl = &sport->rx_sgl; struct scatterlist *sgl = &sport->rx_sgl;
...@@ -1197,9 +1195,8 @@ static int imx_uart_start_rx_dma(struct imx_port *sport) ...@@ -1197,9 +1195,8 @@ static int imx_uart_start_rx_dma(struct imx_port *sport)
sport->rx_ring.head = 0; sport->rx_ring.head = 0;
sport->rx_ring.tail = 0; sport->rx_ring.tail = 0;
sport->rx_periods = RX_DMA_PERIODS;
sg_init_one(sgl, sport->rx_buf, RX_BUF_SIZE); sg_init_one(sgl, sport->rx_buf, sport->rx_buf_size);
ret = dma_map_sg(dev, sgl, 1, DMA_FROM_DEVICE); ret = dma_map_sg(dev, sgl, 1, DMA_FROM_DEVICE);
if (ret == 0) { if (ret == 0) {
dev_err(dev, "DMA mapping error for RX.\n"); dev_err(dev, "DMA mapping error for RX.\n");
...@@ -1316,7 +1313,8 @@ static int imx_uart_dma_init(struct imx_port *sport) ...@@ -1316,7 +1313,8 @@ static int imx_uart_dma_init(struct imx_port *sport)
goto err; goto err;
} }
sport->rx_buf = kzalloc(RX_BUF_SIZE, GFP_KERNEL); sport->rx_buf_size = sport->rx_period_length * sport->rx_periods;
sport->rx_buf = kzalloc(sport->rx_buf_size, GFP_KERNEL);
if (!sport->rx_buf) { if (!sport->rx_buf) {
ret = -ENOMEM; ret = -ENOMEM;
goto err; goto err;
...@@ -2179,11 +2177,16 @@ static enum hrtimer_restart imx_trigger_stop_tx(struct hrtimer *t) ...@@ -2179,11 +2177,16 @@ static enum hrtimer_restart imx_trigger_stop_tx(struct hrtimer *t)
return HRTIMER_NORESTART; return HRTIMER_NORESTART;
} }
/* Default RX DMA buffer configuration */
#define RX_DMA_PERIODS 16
#define RX_DMA_PERIOD_LEN (PAGE_SIZE / 4)
static int imx_uart_probe(struct platform_device *pdev) static int imx_uart_probe(struct platform_device *pdev)
{ {
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
struct imx_port *sport; struct imx_port *sport;
void __iomem *base; void __iomem *base;
u32 dma_buf_conf[2];
int ret = 0; int ret = 0;
u32 ucr1; u32 ucr1;
struct resource *res; struct resource *res;
...@@ -2218,6 +2221,14 @@ static int imx_uart_probe(struct platform_device *pdev) ...@@ -2218,6 +2221,14 @@ static int imx_uart_probe(struct platform_device *pdev)
if (of_get_property(np, "fsl,inverted-rx", NULL)) if (of_get_property(np, "fsl,inverted-rx", NULL))
sport->inverted_rx = 1; sport->inverted_rx = 1;
if (!of_property_read_u32_array(np, "fsl,dma-info", dma_buf_conf, 2)) {
sport->rx_period_length = dma_buf_conf[0];
sport->rx_periods = dma_buf_conf[1];
} else {
sport->rx_period_length = RX_DMA_PERIOD_LEN;
sport->rx_periods = RX_DMA_PERIODS;
}
if (sport->port.line >= ARRAY_SIZE(imx_uart_ports)) { if (sport->port.line >= ARRAY_SIZE(imx_uart_ports)) {
dev_err(&pdev->dev, "serial%d out of range\n", dev_err(&pdev->dev, "serial%d out of range\n",
sport->port.line); sport->port.line);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment