serial: amba-pl011: Fix DMA transmission in RS485 mode

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:
Lino Sanfilippo 2024-02-16 23:47:08 +01:00 committed by Greg Kroah-Hartman
parent f418ae7331
commit 3b69e32e15

View File

@ -1339,11 +1339,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);
}
@ -1424,42 +1454,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;