Re: [PATCH v2] serial: 8250: 8250_omap: Support native RS485

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sun, 2022-10-16 at 10:02 +0200, Lukas Wunner wrote:
> Recent TI Sitara SoCs such as AM64/AM65 have gained the ability to
> automatically assert RTS when data is transmitted, obviating the need
> to emulate this functionality in software.
> 
> The feature is controlled through new DIR_EN and DIR_POL bits in the
> Mode Definition Register 3.  For details see page 8783 and 8890 of the
> AM65 TRM:  
> https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.ti.com%2Flit%2Fug%2Fspruid7e%2Fspruid7e.pdf&data=05%7C01%7Cbaocheng.su%40ad011.siemens.com%7Ce23a8a66efb546fac6c608daaf4cb3dd%7C38ae3bcd95794fd4addab42e1495d55a%7C1%7C0%7C638015041558171363%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=YHG2%2F82aqVxQMqAgSjVlonkPdy%2FTtt34LC97U1%2F%2F1%2BQ%3D&reserved=0
> 
> Signed-off-by: Lukas Wunner <lukas@xxxxxxxxx>
> Cc: Ilpo Järvinen <ilpo.jarvinen@xxxxxxxxxxxxxxx>
> Cc: Su Bao Cheng <baocheng.su@xxxxxxxxxxx>

My colleague has tested this patch on Siemens IOT2050, it works.

Tested-by: Zeng Chao <chao.zeng@xxxxxxxxxxx>

- Baocheng Su

> Cc: Vignesh Raghavendra <vigneshr@xxxxxx>
> Cc: Jan Kiszka <jan.kiszka@xxxxxxxxxxx>
> Cc: Bin Liu <b-liu@xxxxxx>
> ---
>  Changes v1 -> v2:
> 
>  * Fall back to RS485 software emulation if RTS GPIO is used or
>    user-requested delays exceed fixed hardware delays (Bin Liu,
>    Vignesh Raghavendra)
> 
>  * Set fixed hardware delay upon RTS assertion to 1 clock cycle
>    instead of 0 previously
> 
>  * Add code comment to clarify that rs485_supported is the same
>    for software emulation and native RS485 (Ilpo Järvinen)
> 
>  drivers/tty/serial/8250/8250_omap.c | 85
> ++++++++++++++++++++++++++++-
>  1 file changed, 82 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/tty/serial/8250/8250_omap.c
> b/drivers/tty/serial/8250/8250_omap.c
> index 68f5a167377f..0648e858a7cd 100644
> --- a/drivers/tty/serial/8250/8250_omap.c
> +++ b/drivers/tty/serial/8250/8250_omap.c
> @@ -44,6 +44,7 @@
>  #define        UART_HAS_EFR2                   BIT(4)
>  #define UART_HAS_RHR_IT_DIS            BIT(5)
>  #define UART_RX_TIMEOUT_QUIRK          BIT(6)
> +#define UART_HAS_NATIVE_RS485          BIT(7)
>  
>  #define OMAP_UART_FCR_RX_TRIG          6
>  #define OMAP_UART_FCR_TX_TRIG          4
> @@ -101,6 +102,11 @@
>  #define UART_OMAP_IER2                 0x1B
>  #define UART_OMAP_IER2_RHR_IT_DIS      BIT(2)
>  
> +/* Mode Definition Register 3 */
> +#define UART_OMAP_MDR3                 0x20
> +#define UART_OMAP_MDR3_DIR_POL         BIT(3)
> +#define UART_OMAP_MDR3_DIR_EN          BIT(4)
> +
>  /* Enhanced features register 2 */
>  #define UART_OMAP_EFR2                 0x23
>  #define UART_OMAP_EFR2_TIMEOUT_BEHAVE  BIT(6)
> @@ -112,6 +118,7 @@ struct omap8250_priv {
>         int line;
>         u8 habit;
>         u8 mdr1;
> +       u8 mdr3;
>         u8 efr;
>         u8 scr;
>         u8 wer;
> @@ -345,7 +352,10 @@ static void omap8250_restore_regs(struct
> uart_8250_port *up)
>  
>         up->port.ops->set_mctrl(&up->port, up->port.mctrl);
>  
> -       if (up->port.rs485.flags & SER_RS485_ENABLED)
> +       serial_out(up, UART_OMAP_MDR3, priv->mdr3);
> +
> +       if (up->port.rs485.flags & SER_RS485_ENABLED &&
> +           up->port.rs485_config == serial8250_em485_config)
>                 serial8250_em485_stop_tx(up);
>  }
>  
> @@ -793,6 +803,74 @@ static void omap_8250_unthrottle(struct uart_port
> *port)
>         pm_runtime_put_autosuspend(port->dev);
>  }
>  
> +static int omap8250_rs485_config(struct uart_port *port,
> +                                struct ktermios *termios,
> +                                struct serial_rs485 *rs485)
> +{
> +       struct omap8250_priv *priv = port->private_data;
> +       struct uart_8250_port *up = up_to_u8250p(port);
> +       u32 fixed_delay_rts_before_send = 0;
> +       u32 fixed_delay_rts_after_send = 0;
> +       unsigned int baud;
> +
> +       /*
> +        * There is a fixed delay of 3 bit clock cycles after the TX
> shift
> +        * register is going empty to allow time for the stop bit to
> transition
> +        * through the transceiver before direction is changed to
> receive.
> +        *
> +        * Additionally there appears to be a 1 bit clock delay
> between writing
> +        * to the THR register and transmission of the start bit, per
> page 8783
> +        * of the AM65 TRM:  
> https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.ti.com%2Flit%2Fug%2Fspruid7e%2Fspruid7e.pdf&amp;data=05%7C01%7Cbaocheng.su%40ad011.siemens.com%7Ce23a8a66efb546fac6c608daaf4cb3dd%7C38ae3bcd95794fd4addab42e1495d55a%7C1%7C0%7C638015041558171363%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&amp;sdata=YHG2%2F82aqVxQMqAgSjVlonkPdy%2FTtt34LC97U1%2F%2F1%2BQ%3D&amp;reserved=0
> +        */
> +       if (priv->quot) {
> +               if (priv->mdr1 & UART_OMAP_MDR1_16X_MODE)
> +                       baud = port->uartclk / (16 * priv->quot);
> +               else
> +                       baud = port->uartclk / (13 * priv->quot);
> +
> +               fixed_delay_rts_after_send  = 3 * MSEC_PER_SEC / baud;
> +               fixed_delay_rts_before_send = 1 * MSEC_PER_SEC / baud;
> +       }
> +
> +       /*
> +        * Fall back to RS485 software emulation if the UART is
> missing
> +        * hardware support, if the device tree specifies an
> mctrl_gpio
> +        * (indicates that RTS is unavailable due to a pinmux
> conflict)
> +        * or if the requested delays exceed the fixed hardware
> delays.
> +        */
> +       if (!(priv->habit & UART_HAS_NATIVE_RS485) ||
> +           mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_RTS) ||
> +           rs485->delay_rts_after_send  > fixed_delay_rts_after_send
> ||
> +           rs485->delay_rts_before_send >
> fixed_delay_rts_before_send) {
> +               priv->mdr3 &= ~UART_OMAP_MDR3_DIR_EN;
> +               serial_out(up, UART_OMAP_MDR3, priv->mdr3);
> +
> +               port->rs485_config = serial8250_em485_config;
> +               return serial8250_em485_config(port, termios, rs485);
> +       }
> +
> +       rs485->delay_rts_after_send  = fixed_delay_rts_after_send;
> +       rs485->delay_rts_before_send = fixed_delay_rts_before_send;
> +
> +       if (rs485->flags & SER_RS485_ENABLED)
> +               priv->mdr3 |= UART_OMAP_MDR3_DIR_EN;
> +       else
> +               priv->mdr3 &= ~UART_OMAP_MDR3_DIR_EN;
> +
> +       /*
> +        * Retain same polarity semantics as RS485 software emulation,
> +        * i.e. SER_RS485_RTS_ON_SEND means driving RTS low on send.
> +        */
> +       if (rs485->flags & SER_RS485_RTS_ON_SEND)
> +               priv->mdr3 &= ~UART_OMAP_MDR3_DIR_POL;
> +       else
> +               priv->mdr3 |= UART_OMAP_MDR3_DIR_POL;
> +
> +       serial_out(up, UART_OMAP_MDR3, priv->mdr3);
> +
> +       return 0;
> +}
> +
>  #ifdef CONFIG_SERIAL_8250_DMA
>  static int omap_8250_rx_dma(struct uart_8250_port *p);
>  
> @@ -1242,7 +1320,7 @@ static struct omap8250_dma_params am33xx_dma = {
>  static struct omap8250_platdata am654_platdata = {
>         .dma_params     = &am654_dma,
>         .habit          = UART_HAS_EFR2 | UART_HAS_RHR_IT_DIS |
> -                         UART_RX_TIMEOUT_QUIRK,
> +                         UART_RX_TIMEOUT_QUIRK |
> UART_HAS_NATIVE_RS485,
>  };
>  
>  static struct omap8250_platdata am33xx_platdata = {
> @@ -1335,7 +1413,8 @@ static int omap8250_probe(struct platform_device
> *pdev)
>         up.port.shutdown = omap_8250_shutdown;
>         up.port.throttle = omap_8250_throttle;
>         up.port.unthrottle = omap_8250_unthrottle;
> -       up.port.rs485_config = serial8250_em485_config;
> +       up.port.rs485_config = omap8250_rs485_config;
> +       /* same rs485_supported for software emulation and native
> RS485 */
>         up.port.rs485_supported = serial8250_em485_supported;
>         up.rs485_start_tx = serial8250_em485_start_tx;
>         up.rs485_stop_tx = serial8250_em485_stop_tx;





[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux PPP]     [Linux FS]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Linmodem]     [Device Mapper]     [Linux Kernel for ARM]

  Powered by Linux