serial: amba-pl011: Fix DMA transmission in RS485 mode
commit 3b69e32e151bc4a4e3c785cbdb1f918d5ee337ed upstream.
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:
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;
|
||||
|
|
Loading…
Reference in New Issue