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"; }; diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c index 94a1b40b164550..e054557a441f7d 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,46 @@ 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; + } + + 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"); } } } @@ -897,6 +926,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 +940,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 +952,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 +968,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 +982,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 +1301,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; diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 388935ea128b93..fed16f84a94397 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -277,6 +277,9 @@ 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) @@ -403,18 +406,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 +563,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, @@ -588,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. @@ -627,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; @@ -638,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; @@ -673,6 +707,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; @@ -789,6 +827,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; @@ -1357,8 +1399,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) @@ -1432,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++; @@ -1897,6 +1943,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 +2846,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; diff --git a/localversion-rt b/localversion-rt index 7d028f4a9e567f..54e7da6f49fb2b 100644 --- a/localversion-rt +++ b/localversion-rt @@ -1 +1 @@ --rt74 +-rt75