From a7f1c150082270d672751b9f842cdca6b7f3b6d1 Mon Sep 17 00:00:00 2001 From: "Luis Claudio R. Goncalves" Date: Sun, 30 Oct 2022 10:59:11 -0300 Subject: [PATCH 1/7] Linux 5.10.152-rt75 Signed-off-by: Luis Claudio R. Goncalves --- localversion-rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/localversion-rt b/localversion-rt index 7d028f4a9e567f..54e7da6f49fb2b 100644 --- a/localversion-rt +++ b/localversion-rt @@ -1 +1 @@ --rt74 +-rt75 From a1afd9ffb8da3250ac9202f973a1e0083df28109 Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Tue, 7 Feb 2023 17:57:30 +0100 Subject: [PATCH 2/7] Patch DMA Treiber --- drivers/dma/bcm2835-dma.c | 47 +++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c index 94a1b40b164550..aa2d979c9b2306 100644 --- a/drivers/dma/bcm2835-dma.c +++ b/drivers/dma/bcm2835-dma.c @@ -592,7 +592,8 @@ static void bcm2835_dma_fill_cb_chain_with_sg( enum dma_transfer_direction direction, struct bcm2835_cb_entry *cb, struct scatterlist *sgl, - unsigned int sg_len) + unsigned int sg_len, + enum dma_slave_buswidth buswidth) { size_t len, max_len; unsigned int i; @@ -607,7 +608,7 @@ static void bcm2835_dma_fill_cb_chain_with_sg( for (addr = sg_dma_address(sgent), len = sg_dma_len(sgent); len > 0; - addr += scb->len, len -= scb->len, cb++) { + cb++) { scb = (struct bcm2711_dma40_scb *)cb->cb; if (direction == DMA_DEV_TO_MEM) { scb->dst = lower_32_bits(addr); @@ -617,18 +618,37 @@ static void bcm2835_dma_fill_cb_chain_with_sg( scb->srci = upper_32_bits(addr) | BCM2711_DMA40_INC; } scb->len = min(len, max_len); + + addr += scb->len; + len -= scb->len; + + /* Setup 2D X-Y len*/ + scb->len /= buswidth; + scb->len--; + scb->len = BCM2711_DMA40_STRIDE(scb->len); + scb->len |= buswidth; } } else { for (addr = sg_dma_address(sgent), len = sg_dma_len(sgent); len > 0; - addr += cb->cb->length, len -= cb->cb->length, cb++) { if (direction == DMA_DEV_TO_MEM) cb->cb->dst = addr; else cb->cb->src = addr; cb->cb->length = min(len, max_len); + + addr += cb->cb->length; + len -= cb->cb->length; + + if (!c->is_lite_channel) { + /* Setup 2D X-Y len*/ + cb->cb->length /= buswidth; + cb->cb->length--; + cb->cb->length <<= 16; + cb->cb->length |= buswidth; + } } } } @@ -897,6 +917,7 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_slave_sg( WIDE_SOURCE(c->dreq) | WIDE_DEST(c->dreq); u32 extra = BCM2835_DMA_INT_EN; size_t frames; + enum dma_slave_buswidth buswidth; if (!is_slave_direction(direction)) { dev_err(chan->device->dev, @@ -910,6 +931,7 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_slave_sg( if (direction == DMA_DEV_TO_MEM) { if (c->cfg.src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) return NULL; + buswidth = c->cfg.src_addr_width; src = c->cfg.src_addr; /* * One would think it ought to be possible to get the physical @@ -921,8 +943,13 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_slave_sg( src |= 0x400000000ull; info |= BCM2835_DMA_S_DREQ | BCM2835_DMA_D_INC; } else { - if (c->cfg.dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) - return NULL; + if (c->cfg.dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) { + if (c->is_lite_channel) + return NULL; + if (c->cfg.dst_addr_width != DMA_SLAVE_BUSWIDTH_1_BYTE) + return NULL; + } + buswidth = c->cfg.dst_addr_width; dst = c->cfg.dst_addr; if (c->is_40bit_channel) dst |= 0x400000000ull; @@ -932,6 +959,10 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_slave_sg( /* count frames in sg list */ frames = bcm2835_dma_count_frames_for_sg(c, sgl, sg_len); + /* Set 2D mode for all but lite channels */ + if (!c->is_lite_channel) + info |= BCM2835_DMA_TDMODE; + /* allocate the CB chain */ d = bcm2835_dma_create_cb_chain(c, direction, false, info, extra, @@ -942,7 +973,7 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_slave_sg( /* fill in frames with scatterlist pointers */ bcm2835_dma_fill_cb_chain_with_sg(c, direction, d->cb_list, - sgl, sg_len); + sgl, sg_len, buswidth); return vchan_tx_prep(&c->vc, &d->vd, flags); } @@ -1261,7 +1292,9 @@ static int bcm2835_dma_probe(struct platform_device *pdev) od->ddev.device_terminate_all = bcm2835_dma_terminate_all; od->ddev.device_synchronize = bcm2835_dma_synchronize; od->ddev.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); - od->ddev.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); + /* TODO: support further byte widths */ + od->ddev.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); od->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV) | BIT(DMA_MEM_TO_MEM); od->ddev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; From e6d77a149d931bd37687b19e7d1b5a6dbc90f368 Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Thu, 9 Feb 2023 18:24:05 +0100 Subject: [PATCH 3/7] Modify device tree for UART tx DMA --- arch/arm/boot/dts/overlays/revpi-flat-s-2022-overlay.dts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/overlays/revpi-flat-s-2022-overlay.dts b/arch/arm/boot/dts/overlays/revpi-flat-s-2022-overlay.dts index 574d09fcbca414..52df36099b6278 100644 --- a/arch/arm/boot/dts/overlays/revpi-flat-s-2022-overlay.dts +++ b/arch/arm/boot/dts/overlays/revpi-flat-s-2022-overlay.dts @@ -369,10 +369,12 @@ fragment@8 { target = <&uart3>; __overlay__ { - linux,rs485-enabled-at-boot-time; - rs485-rts-active-low; + dmas = <&dma 19>; + dma-names = "tx"; pinctrl-names = "default"; pinctrl-0 = <&rs485_0_pins>; + linux,rs485-enabled-at-boot-time; + rs485-rts-active-low; rs485-term-gpios = <&expander 14 GPIO_ACTIVE_LOW>; status = "okay"; }; From de9daa8c88c5adcfd2a4b6619b344914b6325060 Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Thu, 9 Feb 2023 19:02:28 +0100 Subject: [PATCH 4/7] aenderungen amba treiber --- drivers/tty/serial/amba-pl011.c | 35 ++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 388935ea128b93..45fce15958ff8c 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -403,18 +403,25 @@ static void pl011_dma_probe(struct uart_amba_port *uap) /* DMA is the sole user of the platform data right now */ struct amba_pl011_data *plat = dev_get_platdata(uap->port.dev); struct device *dev = uap->port.dev; - struct dma_slave_config tx_conf = { - .dst_addr = uap->port.mapbase + - pl011_reg_to_offset(uap, REG_DR), - .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, - .direction = DMA_MEM_TO_DEV, - .dst_maxburst = uap->fifosize >> 1, - .device_fc = false, - }; + struct dma_slave_config tx_conf; struct dma_chan *chan; dma_cap_mask_t mask; + tx_conf.dst_addr = uap->port.mapbase + + pl011_reg_to_offset(uap, REG_DR); + // XXX: translate from phys to bus address. Use dma-ranges property + // for this? + tx_conf.dst_addr -= 0x80000000; + + printk(KERN_INFO "DST ADDR IS 0x%08x\n", (u32) tx_conf.dst_addr); + + tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + tx_conf.direction = DMA_MEM_TO_DEV; + tx_conf.dst_maxburst = uap->fifosize >> 1; + tx_conf.device_fc = false; + uap->dma_probed = true; + chan = dma_request_chan(dev, "tx"); if (IS_ERR(chan)) { if (PTR_ERR(chan) == -EPROBE_DEFER) { @@ -553,6 +560,8 @@ static void pl011_dma_tx_callback(void *data) unsigned long flags; u16 dmacr; + trace_printk("DMA TX CALLBACK\n"); + spin_lock_irqsave(&uap->port.lock, flags); if (uap->dmatx.queued) dma_unmap_sg(dmatx->chan->device->dev, &dmatx->sg, 1, @@ -1357,8 +1366,11 @@ static void pl011_start_tx(struct uart_port *port) struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); - if (!pl011_dma_tx_start(uap)) + if (!pl011_dma_tx_start(uap)) { + trace_printk("Using PIO instead of DMA\n"); pl011_start_tx_pio(uap); + } else + trace_printk("Using DMA !!!\n"); } static void pl011_stop_rx(struct uart_port *port) @@ -1897,6 +1909,9 @@ static int pl011_startup(struct uart_port *port) /* Startup DMA */ pl011_dma_startup(uap); + trace_printk("%s TX DMA\n", uap->using_tx_dma ? "USING " : "NOT USING "); + trace_printk("%s RX DMA\n", uap->using_rx_dma ? "USING " : "NOT USING "); + pl011_enable_interrupts(uap); return 0; @@ -2797,7 +2812,9 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap, uap->port.dev = dev; uap->port.mapbase = mmiobase->start; + trace_printk("MAPBASE IS 0x%08x\n", (u32) mmiobase->start); uap->port.membase = base; + trace_printk("MEMBASE IS 0x%08x\n", (u32) base); uap->port.fifosize = uap->fifosize; uap->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_AMBA_PL011_CONSOLE); uap->port.flags = UPF_BOOT_AUTOCONF; From ef2b58856f58ab7618ca1cfa82afc44b7dc2ec6e Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Thu, 9 Feb 2023 19:06:59 +0100 Subject: [PATCH 5/7] serial: amba-pl011: Fix data transmission for RS485 when using DMA When using DMA with RS485 do not forget to first switch to RS485 transmit mode. Signed-off-by: Lino Sanfilippo --- drivers/tty/serial/amba-pl011.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 45fce15958ff8c..a90c8ee4139441 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -277,6 +277,7 @@ struct uart_amba_port { }; static unsigned int pl011_tx_empty(struct uart_port *port); +static void pl011_rs485_tx_start(struct uart_amba_port *uap); static unsigned int pl011_reg_to_offset(const struct uart_amba_port *uap, unsigned int reg) @@ -682,6 +683,10 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap) /* Fire the DMA transaction */ dma_dev->device_issue_pending(chan); + if ((uap->port.rs485.flags & SER_RS485_ENABLED) && + !uap->rs485_tx_started) + pl011_rs485_tx_start(uap); + uap->dmacr |= UART011_TXDMAE; pl011_write(uap->dmacr, uap, REG_DMACR); uap->dmatx.queued = true; @@ -798,6 +803,10 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) return false; } + if ((uap->port.rs485.flags & SER_RS485_ENABLED) && + !uap->rs485_tx_started) + pl011_rs485_tx_start(uap); + pl011_write(uap->port.x_char, uap, REG_DR); uap->port.icount.tx++; uap->port.x_char = 0; From 378cf9a7a1046364a51f7c9acd8a0ceacbf71882 Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Fri, 10 Feb 2023 11:48:12 +0100 Subject: [PATCH 6/7] Add tracing --- drivers/dma/bcm2835-dma.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c index aa2d979c9b2306..e054557a441f7d 100644 --- a/drivers/dma/bcm2835-dma.c +++ b/drivers/dma/bcm2835-dma.c @@ -649,6 +649,15 @@ static void bcm2835_dma_fill_cb_chain_with_sg( cb->cb->length <<= 16; cb->cb->length |= buswidth; } + + trace_printk("DMA: DUMP CB\n"); + trace_printk("DMA: CB INFO: 0x%08x\n", cb->cb->info); + trace_printk("DMA: CB src: 0x%08x\n", cb->cb->src); + trace_printk("DMA: CB dst: 0x%08x\n", cb->cb->dst); + trace_printk("DMA: CB length: 0x%08x\n", cb->cb->length); + trace_printk("DMA: CB stride: 0x%08x\n", cb->cb->stride); + trace_printk("DMA: CB next: 0x%08x\n", cb->cb->next); + trace_printk("DMA: DUMP CB END\n"); } } } From bccb4aaa3a7e8503b8cad7eec6e21d1350a930cd Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Fri, 10 Feb 2023 11:49:36 +0100 Subject: [PATCH 7/7] Add tracing --- drivers/tty/serial/amba-pl011.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index a90c8ee4139441..fed16f84a94397 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -277,8 +277,10 @@ struct uart_amba_port { }; static unsigned int pl011_tx_empty(struct uart_port *port); +static void dump_buffer(unsigned char *buff, unsigned int len); static void pl011_rs485_tx_start(struct uart_amba_port *uap); + static unsigned int pl011_reg_to_offset(const struct uart_amba_port *uap, unsigned int reg) { @@ -598,6 +600,16 @@ static void pl011_dma_tx_callback(void *data) spin_unlock_irqrestore(&uap->port.lock, flags); } +static void dump_buffer(unsigned char *buff, unsigned int len) +{ + int i; + + for (i = 0; i < len; i++) + trace_printk("0x%02x (%c) ", buff[i], buff[i]); + + trace_printk("\n"); +} + /* * Try to refill the TX DMA buffer. * Locking: called with port lock held and IRQs disabled. @@ -637,9 +649,12 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap) if (count > PL011_DMA_BUFFER_SIZE) count = PL011_DMA_BUFFER_SIZE; - if (xmit->tail < xmit->head) + if (xmit->tail < xmit->head) { memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], count); - else { + trace_printk("Dumping DMA buffer (1)\n"); + dump_buffer(dmatx->buf, count); + trace_printk("Dumping DMA buffer (1) END\n"); + } else { size_t first = UART_XMIT_SIZE - xmit->tail; size_t second; @@ -648,8 +663,17 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap) second = count - first; memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], first); - if (second) + + trace_printk("Dumping DMA buffer (2a)\n"); + dump_buffer(dmatx->buf, first); + trace_printk("Dumping DMA buffer (2a) END\n"); + + if (second) { memcpy(&dmatx->buf[first], &xmit->buf[0], second); + trace_printk("Dumping DMA buffer (2b)\n"); + dump_buffer(&dmatx->buf[first], second); + trace_printk("Dumping DMA buffer (2b) END\n"); + } } dmatx->sg.length = count; @@ -1453,6 +1477,7 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c, pl011_read(uap, REG_FR) & UART01x_FR_TXFF) return false; /* unable to transmit character */ + trace_printk("PIO - 0x%02x (%c) ", c, c); pl011_write(c, uap, REG_DR); uap->port.icount.tx++;