serial: amba-pl011: Fix DMA transmission in RS485 mode
commit3b69e32e15upstream. When DMA is used in RS485 mode make sure that the UARTs tx section is enabled before the DMA buffers are queued for transmission. Cc: stable@vger.kernel.org Fixes:8d47923772("serial: amba-pl011: add RS485 support") Signed-off-by: Lino Sanfilippo <l.sanfilippo@kunbus.com> Link: https://lore.kernel.org/r/20240216224709.9928-2-l.sanfilippo@kunbus.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
d9d2426253
commit
d4c7e4b1b0
@@ -1345,11 +1345,41 @@ static void pl011_start_tx_pio(struct uart_amba_port *uap)
|
||||
}
|
||||
}
|
||||
|
||||
static void pl011_rs485_tx_start(struct uart_amba_port *uap)
|
||||
{
|
||||
struct uart_port *port = &uap->port;
|
||||
u32 cr;
|
||||
|
||||
/* Enable transmitter */
|
||||
cr = pl011_read(uap, REG_CR);
|
||||
cr |= UART011_CR_TXE;
|
||||
|
||||
/* Disable receiver if half-duplex */
|
||||
if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
|
||||
cr &= ~UART011_CR_RXE;
|
||||
|
||||
if (port->rs485.flags & SER_RS485_RTS_ON_SEND)
|
||||
cr &= ~UART011_CR_RTS;
|
||||
else
|
||||
cr |= UART011_CR_RTS;
|
||||
|
||||
pl011_write(cr, uap, REG_CR);
|
||||
|
||||
if (port->rs485.delay_rts_before_send)
|
||||
mdelay(port->rs485.delay_rts_before_send);
|
||||
|
||||
uap->rs485_tx_started = true;
|
||||
}
|
||||
|
||||
static void pl011_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct uart_amba_port *uap =
|
||||
container_of(port, struct uart_amba_port, port);
|
||||
|
||||
if ((uap->port.rs485.flags & SER_RS485_ENABLED) &&
|
||||
!uap->rs485_tx_started)
|
||||
pl011_rs485_tx_start(uap);
|
||||
|
||||
if (!pl011_dma_tx_start(uap))
|
||||
pl011_start_tx_pio(uap);
|
||||
}
|
||||
@@ -1431,42 +1461,12 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c,
|
||||
return true;
|
||||
}
|
||||
|
||||
static void pl011_rs485_tx_start(struct uart_amba_port *uap)
|
||||
{
|
||||
struct uart_port *port = &uap->port;
|
||||
u32 cr;
|
||||
|
||||
/* Enable transmitter */
|
||||
cr = pl011_read(uap, REG_CR);
|
||||
cr |= UART011_CR_TXE;
|
||||
|
||||
/* Disable receiver if half-duplex */
|
||||
if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
|
||||
cr &= ~UART011_CR_RXE;
|
||||
|
||||
if (port->rs485.flags & SER_RS485_RTS_ON_SEND)
|
||||
cr &= ~UART011_CR_RTS;
|
||||
else
|
||||
cr |= UART011_CR_RTS;
|
||||
|
||||
pl011_write(cr, uap, REG_CR);
|
||||
|
||||
if (port->rs485.delay_rts_before_send)
|
||||
mdelay(port->rs485.delay_rts_before_send);
|
||||
|
||||
uap->rs485_tx_started = true;
|
||||
}
|
||||
|
||||
/* Returns true if tx interrupts have to be (kept) enabled */
|
||||
static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq)
|
||||
{
|
||||
struct circ_buf *xmit = &uap->port.state->xmit;
|
||||
int count = uap->fifosize >> 1;
|
||||
|
||||
if ((uap->port.rs485.flags & SER_RS485_ENABLED) &&
|
||||
!uap->rs485_tx_started)
|
||||
pl011_rs485_tx_start(uap);
|
||||
|
||||
if (uap->port.x_char) {
|
||||
if (!pl011_tx_char(uap, uap->port.x_char, from_irq))
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user