mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-04 04:02:26 +00:00
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:
parent
f418ae7331
commit
3b69e32e15
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user