Re: [PATCH 2/2] serial: 8250_of: drop RS-485 RTS on Microchip Core16550

From: Conor Dooley

Date: Wed Nov 04 2026 - 11:31:00 EST


On Tue, Nov 03, 2026 at 11:11:32AM +1100, Kohei Otsuka wrote:
> Core16550, a 16550-compatible UART for Microchip FPGAs, interrupts on
> THRE but not on TEMT. When the last character moves from the FIFO into
> the shift register, the THRE interrupt calls __stop_tx(), which finds
> TEMT clear and, without UART_CAP_NOTEMT, returns to wait for a TEMT
> interrupt that never comes. RTS, and with it the RS-485 driver enable,
> then stays asserted after the frame, and receive interrupts, disabled
> for the half-duplex transmission, stay off.
>
> Set UART_CAP_NOTEMT for nodes compatible with "microchip,core16550",
> so em485 drops RTS from its stop timer one frame time (plus 1/7) after
> THRE, as it does for DesignWare UARTs.
>
> Set UART_CAP_FIFO as well: with the capabilities already non-zero,
> serial8250_do_startup() no longer fills in the PORT_16550A default,
> and without UART_CAP_FIFO serial8250_clear_fifos() does nothing, so
> the RX FIFO is not flushed at the end of a half-duplex transmission.
>
> Link: https://github.com/linux4microchip/meta-mchp/issues/5

It's worth noting that in that GitHub link I pointed out that the time I
recall this core being used they required changes to the baud rate logic
in the driver and that there were differences between how the baud rate
is actually determined from the input clock:
| The docs for core16550 say:
|
| This block takes the input PCLK and divides it by a programmed value (from 1 to 216 – 1). The result
| is divided by 16 to create the transmission clock (BAUDOUT)
|
| whereas ns16550a docs say:
|
| The UART includes a programmable baud rate generator
| that is capable of dividing the timing reference clock input
| by divisors of 1 to (216-1 ), and producing a 16 x clock for
| driving the internal transmitter logic. Provisions are also included to use this 16 x clock to drive the receiver logic.

Kohei reported not being affected by this, but I figured it was worth
mentioning.

Cheers,
Conor.

> Signed-off-by: Kohei Otsuka <kohei@xxxxxxxxxxxxxxxxx>
> ---
> drivers/tty/serial/8250/8250_of.c | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
> index b41ca604083f..2f1f505501a2 100644
> --- a/drivers/tty/serial/8250/8250_of.c
> +++ b/drivers/tty/serial/8250/8250_of.c
> @@ -278,6 +278,15 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
> if (port8250.port.fifosize)
> port8250.capabilities = UART_CAP_FIFO;
>
> + /*
> + * Core16550 has no TEMT interrupt: without UART_CAP_NOTEMT the em485
> + * code waits for one after the last THRE interrupt and never drops RTS.
> + * Set UART_CAP_FIFO too, because a non-zero value stops
> + * serial8250_do_startup() filling in the PORT_16550A default.
> + */
> + if (of_device_is_compatible(ofdev->dev.of_node, "microchip,core16550"))
> + port8250.capabilities |= UART_CAP_FIFO | UART_CAP_NOTEMT;
> +
> /* Check for TX FIFO threshold & set tx_loadsz */
> if ((of_property_read_u32(ofdev->dev.of_node, "tx-threshold",
> &tx_threshold) == 0) &&
>
> --
> 2.53.0
>

Attachment: signature.asc
Description: PGP signature