* [PATCH V2 0/2] Add rs485 support to uartps driver
@ 2023-10-11 14:56 ` Manikanta Guntupalli
0 siblings, 0 replies; 19+ messages in thread
From: Manikanta Guntupalli @ 2023-10-11 14:56 UTC (permalink / raw)
To: git, michal.simek, gregkh, robh+dt, krzysztof.kozlowski+dt,
conor+dt, linux-serial, devicetree, linux-kernel, jirislaby,
linux-arm-kernel
Cc: radhey.shyam.pandey, srinivas.goud, shubhrajyoti.datta,
manion05gk, Manikanta Guntupalli
Add optional gpio property to uartps node to support rs485.
Add rs485 support to uartps driver.
---
Changes for V2:
Modify optional gpio name to xlnx,phy-ctrl-gpios.
Update commit description.
Add support for RTS, delay_rts_before_send and delay_rts_after_send in RS485 mode.
Manikanta Guntupalli (2):
dt-bindings: Add optional gpio property to uartps node to support
rs485
tty: serial: uartps: Add rs485 support to uartps driver
.../devicetree/bindings/serial/cdns,uart.yaml | 6 +
drivers/tty/serial/xilinx_uartps.c | 116 +++++++++++++++++-
2 files changed, 121 insertions(+), 1 deletion(-)
--
2.25.1
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH V2 0/2] Add rs485 support to uartps driver
@ 2023-10-11 14:56 ` Manikanta Guntupalli
0 siblings, 0 replies; 19+ messages in thread
From: Manikanta Guntupalli @ 2023-10-11 14:56 UTC (permalink / raw)
To: git, michal.simek, gregkh, robh+dt, krzysztof.kozlowski+dt,
conor+dt, linux-serial, devicetree, linux-kernel, jirislaby,
linux-arm-kernel
Cc: radhey.shyam.pandey, srinivas.goud, shubhrajyoti.datta,
manion05gk, Manikanta Guntupalli
Add optional gpio property to uartps node to support rs485.
Add rs485 support to uartps driver.
---
Changes for V2:
Modify optional gpio name to xlnx,phy-ctrl-gpios.
Update commit description.
Add support for RTS, delay_rts_before_send and delay_rts_after_send in RS485 mode.
Manikanta Guntupalli (2):
dt-bindings: Add optional gpio property to uartps node to support
rs485
tty: serial: uartps: Add rs485 support to uartps driver
.../devicetree/bindings/serial/cdns,uart.yaml | 6 +
drivers/tty/serial/xilinx_uartps.c | 116 +++++++++++++++++-
2 files changed, 121 insertions(+), 1 deletion(-)
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH V2 1/2] dt-bindings: Add optional gpio property to uartps node to support rs485
2023-10-11 14:56 ` Manikanta Guntupalli
@ 2023-10-11 14:56 ` Manikanta Guntupalli
-1 siblings, 0 replies; 19+ messages in thread
From: Manikanta Guntupalli @ 2023-10-11 14:56 UTC (permalink / raw)
To: git, michal.simek, gregkh, robh+dt, krzysztof.kozlowski+dt,
conor+dt, linux-serial, devicetree, linux-kernel, jirislaby,
linux-arm-kernel
Cc: radhey.shyam.pandey, srinivas.goud, shubhrajyoti.datta,
manion05gk, Manikanta Guntupalli
Add optional gpio property to uartps node and reference to rs485.yaml
On Xilinx/AMD Kria SOM KD240 board rs485 connects via TI ISOW1432
Transceiver device, where one GPIO is used for driving DE/RE signals.
With rs485 half duplex configuration, DE and RE shorts to each other,
and at a time, any node acts as either a driver or a receiver.
Here,
DE - Driver enable. If pin is floating, driver is disabled.
RE - Receiver enable. If pin is floating, receiver buffer is disabled.
For more deatils, please find below link which contains Transceiver
device(ISOW1432) datasheet
https://www.ti.com/lit/ds/symlink/isow1432.pdf?ts=1682607122706&ref_url=https%253A%252F%252Fwww.ti.com%252Fproduct%252FISOW1432%252Fpart-details%252FISOW1432DFMR%253FkeyMatch%253DISOW1432DFMR%2526tisearch%253Dsearch-everything%2526usecase%253DOPN
xlnx,phy-ctrl-gpios is optional property, because it is not required
for uart console node.
Signed-off-by: Manikanta Guntupalli <manikanta.guntupalli@amd.com>
---
Changes for V2:
Modify optional gpio name to xlnx,phy-ctrl-gpios.
Update commit description.
---
Documentation/devicetree/bindings/serial/cdns,uart.yaml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/Documentation/devicetree/bindings/serial/cdns,uart.yaml b/Documentation/devicetree/bindings/serial/cdns,uart.yaml
index a8b323d7bf94..cf8ef55ba210 100644
--- a/Documentation/devicetree/bindings/serial/cdns,uart.yaml
+++ b/Documentation/devicetree/bindings/serial/cdns,uart.yaml
@@ -46,6 +46,11 @@ properties:
power-domains:
maxItems: 1
+ xlnx,phy-ctrl-gpios:
+ description: Optional GPIO to control transmit/receive on RS485 phy
+ in halfduplex mode.
+ maxItems: 1
+
required:
- compatible
- reg
@@ -55,6 +60,7 @@ required:
allOf:
- $ref: serial.yaml#
+ - $ref: rs485.yaml#
- if:
properties:
compatible:
--
2.25.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH V2 1/2] dt-bindings: Add optional gpio property to uartps node to support rs485
@ 2023-10-11 14:56 ` Manikanta Guntupalli
0 siblings, 0 replies; 19+ messages in thread
From: Manikanta Guntupalli @ 2023-10-11 14:56 UTC (permalink / raw)
To: git, michal.simek, gregkh, robh+dt, krzysztof.kozlowski+dt,
conor+dt, linux-serial, devicetree, linux-kernel, jirislaby,
linux-arm-kernel
Cc: radhey.shyam.pandey, srinivas.goud, shubhrajyoti.datta,
manion05gk, Manikanta Guntupalli
Add optional gpio property to uartps node and reference to rs485.yaml
On Xilinx/AMD Kria SOM KD240 board rs485 connects via TI ISOW1432
Transceiver device, where one GPIO is used for driving DE/RE signals.
With rs485 half duplex configuration, DE and RE shorts to each other,
and at a time, any node acts as either a driver or a receiver.
Here,
DE - Driver enable. If pin is floating, driver is disabled.
RE - Receiver enable. If pin is floating, receiver buffer is disabled.
For more deatils, please find below link which contains Transceiver
device(ISOW1432) datasheet
https://www.ti.com/lit/ds/symlink/isow1432.pdf?ts=1682607122706&ref_url=https%253A%252F%252Fwww.ti.com%252Fproduct%252FISOW1432%252Fpart-details%252FISOW1432DFMR%253FkeyMatch%253DISOW1432DFMR%2526tisearch%253Dsearch-everything%2526usecase%253DOPN
xlnx,phy-ctrl-gpios is optional property, because it is not required
for uart console node.
Signed-off-by: Manikanta Guntupalli <manikanta.guntupalli@amd.com>
---
Changes for V2:
Modify optional gpio name to xlnx,phy-ctrl-gpios.
Update commit description.
---
Documentation/devicetree/bindings/serial/cdns,uart.yaml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/Documentation/devicetree/bindings/serial/cdns,uart.yaml b/Documentation/devicetree/bindings/serial/cdns,uart.yaml
index a8b323d7bf94..cf8ef55ba210 100644
--- a/Documentation/devicetree/bindings/serial/cdns,uart.yaml
+++ b/Documentation/devicetree/bindings/serial/cdns,uart.yaml
@@ -46,6 +46,11 @@ properties:
power-domains:
maxItems: 1
+ xlnx,phy-ctrl-gpios:
+ description: Optional GPIO to control transmit/receive on RS485 phy
+ in halfduplex mode.
+ maxItems: 1
+
required:
- compatible
- reg
@@ -55,6 +60,7 @@ required:
allOf:
- $ref: serial.yaml#
+ - $ref: rs485.yaml#
- if:
properties:
compatible:
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH V2 2/2] tty: serial: uartps: Add rs485 support to uartps driver
2023-10-11 14:56 ` Manikanta Guntupalli
@ 2023-10-11 14:56 ` Manikanta Guntupalli
-1 siblings, 0 replies; 19+ messages in thread
From: Manikanta Guntupalli @ 2023-10-11 14:56 UTC (permalink / raw)
To: git, michal.simek, gregkh, robh+dt, krzysztof.kozlowski+dt,
conor+dt, linux-serial, devicetree, linux-kernel, jirislaby,
linux-arm-kernel
Cc: radhey.shyam.pandey, srinivas.goud, shubhrajyoti.datta,
manion05gk, Manikanta Guntupalli
In RS485 half duplex configuration, DriverEnable and ReceiverEnable
shorted to each other, and at a time, any node acts as either a driver
or a receiver. Use either xlnx,phy-ctrl-gpios or RTS to control
RS485 phy as driver or a receiver.
Signed-off-by: Manikanta Guntupalli <manikanta.guntupalli@amd.com>
---
Changes for V2:
Modify optional gpio name to xlnx,phy-ctrl-gpios.
Update commit description.
Add support for RTS, delay_rts_before_send and delay_rts_after_send in RS485 mode.
---
drivers/tty/serial/xilinx_uartps.c | 116 ++++++++++++++++++++++++++++-
1 file changed, 115 insertions(+), 1 deletion(-)
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 8e521c69a959..abddcf1a8bf4 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -23,6 +23,7 @@
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/iopoll.h>
+#include <linux/gpio.h>
#define CDNS_UART_TTY_NAME "ttyPS"
#define CDNS_UART_NAME "xuartps"
@@ -193,6 +194,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
* @clk_rate_change_nb: Notifier block for clock changes
* @quirks: Flags for RXBS support.
* @cts_override: Modem control state override
+ * @gpiod: Pointer to the gpio descriptor
*/
struct cdns_uart {
struct uart_port *port;
@@ -203,10 +205,19 @@ struct cdns_uart {
struct notifier_block clk_rate_change_nb;
u32 quirks;
bool cts_override;
+ struct gpio_desc *gpiod;
};
struct cdns_platform_data {
u32 quirks;
};
+
+struct serial_rs485 cdns_rs485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
+ SER_RS485_RTS_AFTER_SEND,
+ .delay_rts_before_send = 1,
+ .delay_rts_after_send = 1,
+};
+
#define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \
clk_rate_change_nb)
@@ -305,6 +316,42 @@ static void cdns_uart_handle_rx(void *dev_id, unsigned int isrstatus)
tty_flip_buffer_push(&port->state->port);
}
+/**
+ * cdns_rs485_tx_setup - Tx setup specific to rs485
+ * @cdns_uart: Handle to the cdns_uart
+ */
+static void cdns_rs485_tx_setup(struct cdns_uart *cdns_uart)
+{
+ u32 val;
+
+ if (cdns_uart->gpiod) {
+ gpiod_set_value(cdns_uart->gpiod, 1);
+ } else {
+ val = readl(cdns_uart->port->membase + CDNS_UART_MODEMCR);
+ val &= ~CDNS_UART_MODEMCR_RTS;
+ writel(val, cdns_uart->port->membase + CDNS_UART_MODEMCR);
+ }
+}
+
+/**
+ * cdns_rs485_rx_setup - Rx setup specific to rs485
+ * @cdns_uart: Handle to the cdns_uart
+ */
+static void cdns_rs485_rx_setup(struct cdns_uart *cdns_uart)
+{
+ u32 val;
+
+ if (cdns_uart->gpiod) {
+ gpiod_set_value(cdns_uart->gpiod, 0);
+ } else {
+ val = readl(cdns_uart->port->membase + CDNS_UART_MODEMCR);
+ val |= CDNS_UART_MODEMCR_RTS;
+ writel(val, cdns_uart->port->membase + CDNS_UART_MODEMCR);
+ }
+}
+
+static unsigned int cdns_uart_tx_empty(struct uart_port *port);
+
/**
* cdns_uart_handle_tx - Handle the bytes to be Txed.
* @dev_id: Id of the UART port
@@ -313,12 +360,20 @@ static void cdns_uart_handle_rx(void *dev_id, unsigned int isrstatus)
static void cdns_uart_handle_tx(void *dev_id)
{
struct uart_port *port = (struct uart_port *)dev_id;
+ struct cdns_uart *cdns_uart = port->private_data;
struct circ_buf *xmit = &port->state->xmit;
+ unsigned long time_out;
unsigned int numbytes;
+ if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) {
+ cdns_rs485_tx_setup(cdns_uart);
+ if (cdns_uart->port->rs485.delay_rts_before_send)
+ mdelay(cdns_uart->port->rs485.delay_rts_before_send);
+ }
+
if (uart_circ_empty(xmit)) {
writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR);
- return;
+ goto rs485_rx_setup;
}
numbytes = port->fifosize;
@@ -332,6 +387,23 @@ static void cdns_uart_handle_tx(void *dev_id)
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
+
+rs485_rx_setup:
+ if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) {
+ time_out = jiffies + usecs_to_jiffies(TX_TIMEOUT);
+ /* Wait for tx completion */
+ while ((cdns_uart_tx_empty(cdns_uart->port) != TIOCSER_TEMT) &&
+ time_before(jiffies, time_out))
+ cpu_relax();
+
+ /*
+ * Default Rx should be setup, because RX signaling path
+ * need to enable to receive data.
+ */
+ cdns_rs485_rx_setup(cdns_uart);
+ if (cdns_uart->port->rs485.delay_rts_after_send)
+ mdelay(cdns_uart->port->rs485.delay_rts_after_send);
+ }
}
/**
@@ -829,6 +901,9 @@ static int cdns_uart_startup(struct uart_port *port)
(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
cpu_relax();
+ if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED)
+ cdns_rs485_rx_setup(cdns_uart);
+
/*
* Clear the RX disable bit and then set the RX enable bit to enable
* the receiver.
@@ -1455,6 +1530,25 @@ MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
/* Temporary variable for storing number of instances */
static int instances;
+/**
+ * cdns_rs485_config - Called when an application calls TIOCSRS485 ioctl.
+ * @port: Pointer to the uart_port structure
+ * @termios: Pointer to the ktermios structure
+ * @rs485: Pointer to the serial_rs485 structure
+ *
+ * Return: 0
+ */
+static int cdns_rs485_config(struct uart_port *port, struct ktermios *termios,
+ struct serial_rs485 *rs485)
+{
+ port->rs485 = *rs485;
+
+ if (rs485->flags & SER_RS485_ENABLED)
+ dev_dbg(port->dev, "Setting UART to RS485\n");
+
+ return 0;
+}
+
/**
* cdns_uart_probe - Platform driver probe
* @pdev: Pointer to the platform device structure
@@ -1597,9 +1691,28 @@ static int cdns_uart_probe(struct platform_device *pdev)
port->private_data = cdns_uart_data;
port->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG |
CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT;
+ port->rs485_config = cdns_rs485_config;
+ port->rs485_supported = cdns_rs485_supported;
cdns_uart_data->port = port;
platform_set_drvdata(pdev, port);
+ rc = uart_get_rs485_mode(port);
+ if (rc)
+ goto err_out_clk_notifier;
+
+ cdns_uart_data->gpiod = devm_gpiod_get_optional(&pdev->dev, "xlnx,phy-ctrl",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(cdns_uart_data->gpiod)) {
+ rc = PTR_ERR(cdns_uart_data->gpiod);
+ dev_err(port->dev, "xuartps: devm_gpiod_get_optional failed\n");
+ goto err_out_clk_notifier;
+ }
+
+ if (cdns_uart_data->gpiod) {
+ gpiod_direction_output(cdns_uart_data->gpiod, GPIOD_OUT_LOW);
+ gpiod_set_value(cdns_uart_data->gpiod, 0);
+ }
+
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
pm_runtime_set_active(&pdev->dev);
@@ -1646,6 +1759,7 @@ static int cdns_uart_probe(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
+err_out_clk_notifier:
#ifdef CONFIG_COMMON_CLK
clk_notifier_unregister(cdns_uart_data->uartclk,
&cdns_uart_data->clk_rate_change_nb);
--
2.25.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH V2 2/2] tty: serial: uartps: Add rs485 support to uartps driver
@ 2023-10-11 14:56 ` Manikanta Guntupalli
0 siblings, 0 replies; 19+ messages in thread
From: Manikanta Guntupalli @ 2023-10-11 14:56 UTC (permalink / raw)
To: git, michal.simek, gregkh, robh+dt, krzysztof.kozlowski+dt,
conor+dt, linux-serial, devicetree, linux-kernel, jirislaby,
linux-arm-kernel
Cc: radhey.shyam.pandey, srinivas.goud, shubhrajyoti.datta,
manion05gk, Manikanta Guntupalli
In RS485 half duplex configuration, DriverEnable and ReceiverEnable
shorted to each other, and at a time, any node acts as either a driver
or a receiver. Use either xlnx,phy-ctrl-gpios or RTS to control
RS485 phy as driver or a receiver.
Signed-off-by: Manikanta Guntupalli <manikanta.guntupalli@amd.com>
---
Changes for V2:
Modify optional gpio name to xlnx,phy-ctrl-gpios.
Update commit description.
Add support for RTS, delay_rts_before_send and delay_rts_after_send in RS485 mode.
---
drivers/tty/serial/xilinx_uartps.c | 116 ++++++++++++++++++++++++++++-
1 file changed, 115 insertions(+), 1 deletion(-)
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 8e521c69a959..abddcf1a8bf4 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -23,6 +23,7 @@
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/iopoll.h>
+#include <linux/gpio.h>
#define CDNS_UART_TTY_NAME "ttyPS"
#define CDNS_UART_NAME "xuartps"
@@ -193,6 +194,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
* @clk_rate_change_nb: Notifier block for clock changes
* @quirks: Flags for RXBS support.
* @cts_override: Modem control state override
+ * @gpiod: Pointer to the gpio descriptor
*/
struct cdns_uart {
struct uart_port *port;
@@ -203,10 +205,19 @@ struct cdns_uart {
struct notifier_block clk_rate_change_nb;
u32 quirks;
bool cts_override;
+ struct gpio_desc *gpiod;
};
struct cdns_platform_data {
u32 quirks;
};
+
+struct serial_rs485 cdns_rs485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
+ SER_RS485_RTS_AFTER_SEND,
+ .delay_rts_before_send = 1,
+ .delay_rts_after_send = 1,
+};
+
#define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \
clk_rate_change_nb)
@@ -305,6 +316,42 @@ static void cdns_uart_handle_rx(void *dev_id, unsigned int isrstatus)
tty_flip_buffer_push(&port->state->port);
}
+/**
+ * cdns_rs485_tx_setup - Tx setup specific to rs485
+ * @cdns_uart: Handle to the cdns_uart
+ */
+static void cdns_rs485_tx_setup(struct cdns_uart *cdns_uart)
+{
+ u32 val;
+
+ if (cdns_uart->gpiod) {
+ gpiod_set_value(cdns_uart->gpiod, 1);
+ } else {
+ val = readl(cdns_uart->port->membase + CDNS_UART_MODEMCR);
+ val &= ~CDNS_UART_MODEMCR_RTS;
+ writel(val, cdns_uart->port->membase + CDNS_UART_MODEMCR);
+ }
+}
+
+/**
+ * cdns_rs485_rx_setup - Rx setup specific to rs485
+ * @cdns_uart: Handle to the cdns_uart
+ */
+static void cdns_rs485_rx_setup(struct cdns_uart *cdns_uart)
+{
+ u32 val;
+
+ if (cdns_uart->gpiod) {
+ gpiod_set_value(cdns_uart->gpiod, 0);
+ } else {
+ val = readl(cdns_uart->port->membase + CDNS_UART_MODEMCR);
+ val |= CDNS_UART_MODEMCR_RTS;
+ writel(val, cdns_uart->port->membase + CDNS_UART_MODEMCR);
+ }
+}
+
+static unsigned int cdns_uart_tx_empty(struct uart_port *port);
+
/**
* cdns_uart_handle_tx - Handle the bytes to be Txed.
* @dev_id: Id of the UART port
@@ -313,12 +360,20 @@ static void cdns_uart_handle_rx(void *dev_id, unsigned int isrstatus)
static void cdns_uart_handle_tx(void *dev_id)
{
struct uart_port *port = (struct uart_port *)dev_id;
+ struct cdns_uart *cdns_uart = port->private_data;
struct circ_buf *xmit = &port->state->xmit;
+ unsigned long time_out;
unsigned int numbytes;
+ if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) {
+ cdns_rs485_tx_setup(cdns_uart);
+ if (cdns_uart->port->rs485.delay_rts_before_send)
+ mdelay(cdns_uart->port->rs485.delay_rts_before_send);
+ }
+
if (uart_circ_empty(xmit)) {
writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR);
- return;
+ goto rs485_rx_setup;
}
numbytes = port->fifosize;
@@ -332,6 +387,23 @@ static void cdns_uart_handle_tx(void *dev_id)
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
+
+rs485_rx_setup:
+ if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) {
+ time_out = jiffies + usecs_to_jiffies(TX_TIMEOUT);
+ /* Wait for tx completion */
+ while ((cdns_uart_tx_empty(cdns_uart->port) != TIOCSER_TEMT) &&
+ time_before(jiffies, time_out))
+ cpu_relax();
+
+ /*
+ * Default Rx should be setup, because RX signaling path
+ * need to enable to receive data.
+ */
+ cdns_rs485_rx_setup(cdns_uart);
+ if (cdns_uart->port->rs485.delay_rts_after_send)
+ mdelay(cdns_uart->port->rs485.delay_rts_after_send);
+ }
}
/**
@@ -829,6 +901,9 @@ static int cdns_uart_startup(struct uart_port *port)
(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
cpu_relax();
+ if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED)
+ cdns_rs485_rx_setup(cdns_uart);
+
/*
* Clear the RX disable bit and then set the RX enable bit to enable
* the receiver.
@@ -1455,6 +1530,25 @@ MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
/* Temporary variable for storing number of instances */
static int instances;
+/**
+ * cdns_rs485_config - Called when an application calls TIOCSRS485 ioctl.
+ * @port: Pointer to the uart_port structure
+ * @termios: Pointer to the ktermios structure
+ * @rs485: Pointer to the serial_rs485 structure
+ *
+ * Return: 0
+ */
+static int cdns_rs485_config(struct uart_port *port, struct ktermios *termios,
+ struct serial_rs485 *rs485)
+{
+ port->rs485 = *rs485;
+
+ if (rs485->flags & SER_RS485_ENABLED)
+ dev_dbg(port->dev, "Setting UART to RS485\n");
+
+ return 0;
+}
+
/**
* cdns_uart_probe - Platform driver probe
* @pdev: Pointer to the platform device structure
@@ -1597,9 +1691,28 @@ static int cdns_uart_probe(struct platform_device *pdev)
port->private_data = cdns_uart_data;
port->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG |
CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT;
+ port->rs485_config = cdns_rs485_config;
+ port->rs485_supported = cdns_rs485_supported;
cdns_uart_data->port = port;
platform_set_drvdata(pdev, port);
+ rc = uart_get_rs485_mode(port);
+ if (rc)
+ goto err_out_clk_notifier;
+
+ cdns_uart_data->gpiod = devm_gpiod_get_optional(&pdev->dev, "xlnx,phy-ctrl",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(cdns_uart_data->gpiod)) {
+ rc = PTR_ERR(cdns_uart_data->gpiod);
+ dev_err(port->dev, "xuartps: devm_gpiod_get_optional failed\n");
+ goto err_out_clk_notifier;
+ }
+
+ if (cdns_uart_data->gpiod) {
+ gpiod_direction_output(cdns_uart_data->gpiod, GPIOD_OUT_LOW);
+ gpiod_set_value(cdns_uart_data->gpiod, 0);
+ }
+
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
pm_runtime_set_active(&pdev->dev);
@@ -1646,6 +1759,7 @@ static int cdns_uart_probe(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
+err_out_clk_notifier:
#ifdef CONFIG_COMMON_CLK
clk_notifier_unregister(cdns_uart_data->uartclk,
&cdns_uart_data->clk_rate_change_nb);
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH V2 2/2] tty: serial: uartps: Add rs485 support to uartps driver
2023-10-11 14:56 ` Manikanta Guntupalli
(?)
@ 2023-10-12 11:19 ` kernel test robot
-1 siblings, 0 replies; 19+ messages in thread
From: kernel test robot @ 2023-10-12 11:19 UTC (permalink / raw)
To: Manikanta Guntupalli; +Cc: oe-kbuild-all
Hi Manikanta,
kernel test robot noticed the following build errors:
[auto build test ERROR on tty/tty-testing]
[also build test ERROR on tty/tty-next tty/tty-linus linus/master v6.6-rc5 next-20231012]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Manikanta-Guntupalli/dt-bindings-Add-optional-gpio-property-to-uartps-node-to-support-rs485/20231011-225836
base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing
patch link: https://lore.kernel.org/r/20231011145602.3619616-3-manikanta.guntupalli%40amd.com
patch subject: [PATCH V2 2/2] tty: serial: uartps: Add rs485 support to uartps driver
config: xtensa-cadence_csp_defconfig (https://download.01.org/0day-ci/archive/20231012/202310121912.HkIj952o-lkp@intel.com/config)
compiler: xtensa-csp-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231012/202310121912.HkIj952o-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202310121912.HkIj952o-lkp@intel.com/
All errors (new ones prefixed by >>):
drivers/tty/serial/xilinx_uartps.c: In function 'cdns_rs485_tx_setup':
>> drivers/tty/serial/xilinx_uartps.c:328:17: error: implicit declaration of function 'gpiod_set_value'; did you mean 'gpio_set_value'? [-Werror=implicit-function-declaration]
328 | gpiod_set_value(cdns_uart->gpiod, 1);
| ^~~~~~~~~~~~~~~
| gpio_set_value
drivers/tty/serial/xilinx_uartps.c: In function 'cdns_uart_probe':
>> drivers/tty/serial/xilinx_uartps.c:1703:33: error: implicit declaration of function 'devm_gpiod_get_optional'; did you mean 'devm_clk_get_optional'? [-Werror=implicit-function-declaration]
1703 | cdns_uart_data->gpiod = devm_gpiod_get_optional(&pdev->dev, "xlnx,phy-ctrl",
| ^~~~~~~~~~~~~~~~~~~~~~~
| devm_clk_get_optional
>> drivers/tty/serial/xilinx_uartps.c:1704:57: error: 'GPIOD_OUT_LOW' undeclared (first use in this function); did you mean 'GPIOF_INIT_LOW'?
1704 | GPIOD_OUT_LOW);
| ^~~~~~~~~~~~~
| GPIOF_INIT_LOW
drivers/tty/serial/xilinx_uartps.c:1704:57: note: each undeclared identifier is reported only once for each function it appears in
>> drivers/tty/serial/xilinx_uartps.c:1712:17: error: implicit declaration of function 'gpiod_direction_output'; did you mean 'gpio_direction_output'? [-Werror=implicit-function-declaration]
1712 | gpiod_direction_output(cdns_uart_data->gpiod, GPIOD_OUT_LOW);
| ^~~~~~~~~~~~~~~~~~~~~~
| gpio_direction_output
cc1: some warnings being treated as errors
vim +328 drivers/tty/serial/xilinx_uartps.c
318
319 /**
320 * cdns_rs485_tx_setup - Tx setup specific to rs485
321 * @cdns_uart: Handle to the cdns_uart
322 */
323 static void cdns_rs485_tx_setup(struct cdns_uart *cdns_uart)
324 {
325 u32 val;
326
327 if (cdns_uart->gpiod) {
> 328 gpiod_set_value(cdns_uart->gpiod, 1);
329 } else {
330 val = readl(cdns_uart->port->membase + CDNS_UART_MODEMCR);
331 val &= ~CDNS_UART_MODEMCR_RTS;
332 writel(val, cdns_uart->port->membase + CDNS_UART_MODEMCR);
333 }
334 }
335
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH V2 1/2] dt-bindings: Add optional gpio property to uartps node to support rs485
2023-10-11 14:56 ` Manikanta Guntupalli
@ 2023-10-12 18:35 ` m.brock
-1 siblings, 0 replies; 19+ messages in thread
From: m.brock @ 2023-10-12 18:35 UTC (permalink / raw)
To: Manikanta Guntupalli
Cc: git, michal.simek, gregkh, robh+dt, krzysztof.kozlowski+dt,
conor+dt, linux-serial, devicetree, linux-kernel, jirislaby,
linux-arm-kernel, radhey.shyam.pandey, srinivas.goud,
shubhrajyoti.datta, manion05gk
Manikanta Guntupalli wrote on 2023-10-11 16:56:
> Add optional gpio property to uartps node and reference to rs485.yaml
>
> On Xilinx/AMD Kria SOM KD240 board rs485 connects via TI ISOW1432
> Transceiver device, where one GPIO is used for driving DE/RE signals.
> With rs485 half duplex configuration, DE and RE shorts to each other,
s/shorts/are connected
> and at a time, any node acts as either a driver or a receiver.
>
> Here,
> DE - Driver enable. If pin is floating, driver is disabled.
> RE - Receiver enable. If pin is floating, receiver buffer is disabled.
Please use DE and /RE to indicate DE is active high and /RE is active
low.
> xlnx,phy-ctrl-gpios is optional property, because it is not required
> for uart console node.
How about introducing an rs485 generic gpios property instead of xlnx
private one? See also rs485-term-gpios and rs485-rx-during-tx-gpios.
Also note that every kernel driver expects to use RTS for this purpose.
So why not give this driver the option to choose a gpio instead of its
native RTS? And from there on use the rts route?
What if someone wants to use normal (non-rs485) RTS on a GPIO instead
of the native pin?
@Rob Herring
I am curious to know how the rs485 maintainers look at this.
Maarten
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH V2 1/2] dt-bindings: Add optional gpio property to uartps node to support rs485
@ 2023-10-12 18:35 ` m.brock
0 siblings, 0 replies; 19+ messages in thread
From: m.brock @ 2023-10-12 18:35 UTC (permalink / raw)
To: Manikanta Guntupalli
Cc: git, michal.simek, gregkh, robh+dt, krzysztof.kozlowski+dt,
conor+dt, linux-serial, devicetree, linux-kernel, jirislaby,
linux-arm-kernel, radhey.shyam.pandey, srinivas.goud,
shubhrajyoti.datta, manion05gk
Manikanta Guntupalli wrote on 2023-10-11 16:56:
> Add optional gpio property to uartps node and reference to rs485.yaml
>
> On Xilinx/AMD Kria SOM KD240 board rs485 connects via TI ISOW1432
> Transceiver device, where one GPIO is used for driving DE/RE signals.
> With rs485 half duplex configuration, DE and RE shorts to each other,
s/shorts/are connected
> and at a time, any node acts as either a driver or a receiver.
>
> Here,
> DE - Driver enable. If pin is floating, driver is disabled.
> RE - Receiver enable. If pin is floating, receiver buffer is disabled.
Please use DE and /RE to indicate DE is active high and /RE is active
low.
> xlnx,phy-ctrl-gpios is optional property, because it is not required
> for uart console node.
How about introducing an rs485 generic gpios property instead of xlnx
private one? See also rs485-term-gpios and rs485-rx-during-tx-gpios.
Also note that every kernel driver expects to use RTS for this purpose.
So why not give this driver the option to choose a gpio instead of its
native RTS? And from there on use the rts route?
What if someone wants to use normal (non-rs485) RTS on a GPIO instead
of the native pin?
@Rob Herring
I am curious to know how the rs485 maintainers look at this.
Maarten
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH V2 2/2] tty: serial: uartps: Add rs485 support to uartps driver
2023-10-11 14:56 ` Manikanta Guntupalli
@ 2023-10-12 19:05 ` m.brock
-1 siblings, 0 replies; 19+ messages in thread
From: m.brock @ 2023-10-12 19:05 UTC (permalink / raw)
To: Manikanta Guntupalli
Cc: git, michal.simek, gregkh, robh+dt, krzysztof.kozlowski+dt,
conor+dt, linux-serial, devicetree, linux-kernel, jirislaby,
linux-arm-kernel, radhey.shyam.pandey, srinivas.goud,
shubhrajyoti.datta, manion05gk
Manikanta Guntupalli wrote on 2023-10-11 16:56:
> In RS485 half duplex configuration, DriverEnable and ReceiverEnable
> shorted to each other, and at a time, any node acts as either a driver
> or a receiver. Use either xlnx,phy-ctrl-gpios or RTS to control
> RS485 phy as driver or a receiver.
>
> Signed-off-by: Manikanta Guntupalli <manikanta.guntupalli@amd.com>
> ---
> Changes for V2:
> Modify optional gpio name to xlnx,phy-ctrl-gpios.
> Update commit description.
> Add support for RTS, delay_rts_before_send and delay_rts_after_send in
> RS485 mode.
> ---
> drivers/tty/serial/xilinx_uartps.c | 116 ++++++++++++++++++++++++++++-
> 1 file changed, 115 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/tty/serial/xilinx_uartps.c
> b/drivers/tty/serial/xilinx_uartps.c
> index 8e521c69a959..abddcf1a8bf4 100644
> --- a/drivers/tty/serial/xilinx_uartps.c
> +++ b/drivers/tty/serial/xilinx_uartps.c
> @@ -23,6 +23,7 @@
> #include <linux/module.h>
> #include <linux/pm_runtime.h>
> #include <linux/iopoll.h>
> +#include <linux/gpio.h>
>
> #define CDNS_UART_TTY_NAME "ttyPS"
> #define CDNS_UART_NAME "xuartps"
> @@ -193,6 +194,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
> * @clk_rate_change_nb: Notifier block for clock changes
> * @quirks: Flags for RXBS support.
> * @cts_override: Modem control state override
> + * @gpiod: Pointer to the gpio descriptor
> */
> struct cdns_uart {
> struct uart_port *port;
> @@ -203,10 +205,19 @@ struct cdns_uart {
> struct notifier_block clk_rate_change_nb;
> u32 quirks;
> bool cts_override;
> + struct gpio_desc *gpiod;
> };
> struct cdns_platform_data {
> u32 quirks;
> };
> +
> +struct serial_rs485 cdns_rs485_supported = {
> + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
> + SER_RS485_RTS_AFTER_SEND,
You promise here to support both RTS-on-send and RTS-after-send, but...
> + .delay_rts_before_send = 1,
> + .delay_rts_after_send = 1,
> +};
> +
> #define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \
> clk_rate_change_nb)
>
> @@ -305,6 +316,42 @@ static void cdns_uart_handle_rx(void *dev_id,
> unsigned int isrstatus)
> tty_flip_buffer_push(&port->state->port);
> }
>
> +/**
> + * cdns_rs485_tx_setup - Tx setup specific to rs485
> + * @cdns_uart: Handle to the cdns_uart
> + */
> +static void cdns_rs485_tx_setup(struct cdns_uart *cdns_uart)
> +{
> + u32 val;
> +
> + if (cdns_uart->gpiod) {
> + gpiod_set_value(cdns_uart->gpiod, 1);
> + } else {
> + val = readl(cdns_uart->port->membase + CDNS_UART_MODEMCR);
> + val &= ~CDNS_UART_MODEMCR_RTS;
> + writel(val, cdns_uart->port->membase + CDNS_UART_MODEMCR);
Here you don't care about RTS-on-send or RTS-after-send anymore.
And neither do you btw. in the if clause.
> + }
> +}
> +
> +/**
> + * cdns_rs485_rx_setup - Rx setup specific to rs485
> + * @cdns_uart: Handle to the cdns_uart
> + */
> +static void cdns_rs485_rx_setup(struct cdns_uart *cdns_uart)
> +{
> + u32 val;
> +
> + if (cdns_uart->gpiod) {
> + gpiod_set_value(cdns_uart->gpiod, 0);
> + } else {
> + val = readl(cdns_uart->port->membase + CDNS_UART_MODEMCR);
> + val |= CDNS_UART_MODEMCR_RTS;
> + writel(val, cdns_uart->port->membase + CDNS_UART_MODEMCR);
> + }
Same here.
> +}
> +
> +static unsigned int cdns_uart_tx_empty(struct uart_port *port);
> +
I think it's better to move up the implementation than to use a forward
declaration.
> /**
> * cdns_uart_handle_tx - Handle the bytes to be Txed.
> * @dev_id: Id of the UART port
> @@ -313,12 +360,20 @@ static void cdns_uart_handle_rx(void *dev_id,
> unsigned int isrstatus)
> static void cdns_uart_handle_tx(void *dev_id)
> {
> struct uart_port *port = (struct uart_port *)dev_id;
> + struct cdns_uart *cdns_uart = port->private_data;
> struct circ_buf *xmit = &port->state->xmit;
> + unsigned long time_out;
> unsigned int numbytes;
>
> + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) {
> + cdns_rs485_tx_setup(cdns_uart);
> + if (cdns_uart->port->rs485.delay_rts_before_send)
> + mdelay(cdns_uart->port->rs485.delay_rts_before_send);
mdelay?
https://www.kernel.org/doc/html/latest/timers/timers-howto.html
"In general, use of mdelay is discouraged and code should be refactored
to
allow for the use of msleep."
Furthermore, you're delaying before every burst of bytes here!
Every TXEMPTY interrupt!
> + }
> +
> if (uart_circ_empty(xmit)) {
> writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR);
> - return;
> + goto rs485_rx_setup;
And when there was nothing more to send you waited for nothing.
> }
>
> numbytes = port->fifosize;
> @@ -332,6 +387,23 @@ static void cdns_uart_handle_tx(void *dev_id)
>
> if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
> uart_write_wakeup(port);
> +
> +rs485_rx_setup:
> + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) {
> + time_out = jiffies + usecs_to_jiffies(TX_TIMEOUT);
> + /* Wait for tx completion */
> + while ((cdns_uart_tx_empty(cdns_uart->port) != TIOCSER_TEMT) &&
> + time_before(jiffies, time_out))
> + cpu_relax();
> +
> + /*
> + * Default Rx should be setup, because RX signaling path
> + * need to enable to receive data.
> + */
> + cdns_rs485_rx_setup(cdns_uart);
> + if (cdns_uart->port->rs485.delay_rts_after_send)
> + mdelay(cdns_uart->port->rs485.delay_rts_after_send);
This is not delaying rts after send. You must keep RTS aka DE active for
a little
longer so even the last stop bit(s) are transmitted correctly. So this
delay must
happen before cdns_rs485_rx_setup().
> + }
> }
>
> /**
> @@ -829,6 +901,9 @@ static int cdns_uart_startup(struct uart_port
> *port)
> (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
> cpu_relax();
>
> + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED)
> + cdns_rs485_rx_setup(cdns_uart);
> +
> /*
> * Clear the RX disable bit and then set the RX enable bit to enable
> * the receiver.
> @@ -1455,6 +1530,25 @@ MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
> /* Temporary variable for storing number of instances */
> static int instances;
>
> +/**
> + * cdns_rs485_config - Called when an application calls TIOCSRS485
> ioctl.
> + * @port: Pointer to the uart_port structure
> + * @termios: Pointer to the ktermios structure
> + * @rs485: Pointer to the serial_rs485 structure
> + *
> + * Return: 0
> + */
> +static int cdns_rs485_config(struct uart_port *port, struct ktermios
> *termios,
> + struct serial_rs485 *rs485)
> +{
> + port->rs485 = *rs485;
> +
> + if (rs485->flags & SER_RS485_ENABLED)
> + dev_dbg(port->dev, "Setting UART to RS485\n");
> +
> + return 0;
> +}
> +
> /**
> * cdns_uart_probe - Platform driver probe
> * @pdev: Pointer to the platform device structure
> @@ -1597,9 +1691,28 @@ static int cdns_uart_probe(struct
> platform_device *pdev)
> port->private_data = cdns_uart_data;
> port->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG
> |
> CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT;
> + port->rs485_config = cdns_rs485_config;
> + port->rs485_supported = cdns_rs485_supported;
> cdns_uart_data->port = port;
> platform_set_drvdata(pdev, port);
>
> + rc = uart_get_rs485_mode(port);
> + if (rc)
> + goto err_out_clk_notifier;
> +
> + cdns_uart_data->gpiod = devm_gpiod_get_optional(&pdev->dev,
> "xlnx,phy-ctrl",
> + GPIOD_OUT_LOW);
> + if (IS_ERR(cdns_uart_data->gpiod)) {
> + rc = PTR_ERR(cdns_uart_data->gpiod);
> + dev_err(port->dev, "xuartps: devm_gpiod_get_optional failed\n");
> + goto err_out_clk_notifier;
> + }
> +
> + if (cdns_uart_data->gpiod) {
> + gpiod_direction_output(cdns_uart_data->gpiod, GPIOD_OUT_LOW);
> + gpiod_set_value(cdns_uart_data->gpiod, 0);
> + }
> +
> pm_runtime_use_autosuspend(&pdev->dev);
> pm_runtime_set_autosuspend_delay(&pdev->dev,
> UART_AUTOSUSPEND_TIMEOUT);
> pm_runtime_set_active(&pdev->dev);
> @@ -1646,6 +1759,7 @@ static int cdns_uart_probe(struct platform_device
> *pdev)
> pm_runtime_disable(&pdev->dev);
> pm_runtime_set_suspended(&pdev->dev);
> pm_runtime_dont_use_autosuspend(&pdev->dev);
> +err_out_clk_notifier:
> #ifdef CONFIG_COMMON_CLK
> clk_notifier_unregister(cdns_uart_data->uartclk,
> &cdns_uart_data->clk_rate_change_nb);
Maarten
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH V2 2/2] tty: serial: uartps: Add rs485 support to uartps driver
@ 2023-10-12 19:05 ` m.brock
0 siblings, 0 replies; 19+ messages in thread
From: m.brock @ 2023-10-12 19:05 UTC (permalink / raw)
To: Manikanta Guntupalli
Cc: git, michal.simek, gregkh, robh+dt, krzysztof.kozlowski+dt,
conor+dt, linux-serial, devicetree, linux-kernel, jirislaby,
linux-arm-kernel, radhey.shyam.pandey, srinivas.goud,
shubhrajyoti.datta, manion05gk
Manikanta Guntupalli wrote on 2023-10-11 16:56:
> In RS485 half duplex configuration, DriverEnable and ReceiverEnable
> shorted to each other, and at a time, any node acts as either a driver
> or a receiver. Use either xlnx,phy-ctrl-gpios or RTS to control
> RS485 phy as driver or a receiver.
>
> Signed-off-by: Manikanta Guntupalli <manikanta.guntupalli@amd.com>
> ---
> Changes for V2:
> Modify optional gpio name to xlnx,phy-ctrl-gpios.
> Update commit description.
> Add support for RTS, delay_rts_before_send and delay_rts_after_send in
> RS485 mode.
> ---
> drivers/tty/serial/xilinx_uartps.c | 116 ++++++++++++++++++++++++++++-
> 1 file changed, 115 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/tty/serial/xilinx_uartps.c
> b/drivers/tty/serial/xilinx_uartps.c
> index 8e521c69a959..abddcf1a8bf4 100644
> --- a/drivers/tty/serial/xilinx_uartps.c
> +++ b/drivers/tty/serial/xilinx_uartps.c
> @@ -23,6 +23,7 @@
> #include <linux/module.h>
> #include <linux/pm_runtime.h>
> #include <linux/iopoll.h>
> +#include <linux/gpio.h>
>
> #define CDNS_UART_TTY_NAME "ttyPS"
> #define CDNS_UART_NAME "xuartps"
> @@ -193,6 +194,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
> * @clk_rate_change_nb: Notifier block for clock changes
> * @quirks: Flags for RXBS support.
> * @cts_override: Modem control state override
> + * @gpiod: Pointer to the gpio descriptor
> */
> struct cdns_uart {
> struct uart_port *port;
> @@ -203,10 +205,19 @@ struct cdns_uart {
> struct notifier_block clk_rate_change_nb;
> u32 quirks;
> bool cts_override;
> + struct gpio_desc *gpiod;
> };
> struct cdns_platform_data {
> u32 quirks;
> };
> +
> +struct serial_rs485 cdns_rs485_supported = {
> + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
> + SER_RS485_RTS_AFTER_SEND,
You promise here to support both RTS-on-send and RTS-after-send, but...
> + .delay_rts_before_send = 1,
> + .delay_rts_after_send = 1,
> +};
> +
> #define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \
> clk_rate_change_nb)
>
> @@ -305,6 +316,42 @@ static void cdns_uart_handle_rx(void *dev_id,
> unsigned int isrstatus)
> tty_flip_buffer_push(&port->state->port);
> }
>
> +/**
> + * cdns_rs485_tx_setup - Tx setup specific to rs485
> + * @cdns_uart: Handle to the cdns_uart
> + */
> +static void cdns_rs485_tx_setup(struct cdns_uart *cdns_uart)
> +{
> + u32 val;
> +
> + if (cdns_uart->gpiod) {
> + gpiod_set_value(cdns_uart->gpiod, 1);
> + } else {
> + val = readl(cdns_uart->port->membase + CDNS_UART_MODEMCR);
> + val &= ~CDNS_UART_MODEMCR_RTS;
> + writel(val, cdns_uart->port->membase + CDNS_UART_MODEMCR);
Here you don't care about RTS-on-send or RTS-after-send anymore.
And neither do you btw. in the if clause.
> + }
> +}
> +
> +/**
> + * cdns_rs485_rx_setup - Rx setup specific to rs485
> + * @cdns_uart: Handle to the cdns_uart
> + */
> +static void cdns_rs485_rx_setup(struct cdns_uart *cdns_uart)
> +{
> + u32 val;
> +
> + if (cdns_uart->gpiod) {
> + gpiod_set_value(cdns_uart->gpiod, 0);
> + } else {
> + val = readl(cdns_uart->port->membase + CDNS_UART_MODEMCR);
> + val |= CDNS_UART_MODEMCR_RTS;
> + writel(val, cdns_uart->port->membase + CDNS_UART_MODEMCR);
> + }
Same here.
> +}
> +
> +static unsigned int cdns_uart_tx_empty(struct uart_port *port);
> +
I think it's better to move up the implementation than to use a forward
declaration.
> /**
> * cdns_uart_handle_tx - Handle the bytes to be Txed.
> * @dev_id: Id of the UART port
> @@ -313,12 +360,20 @@ static void cdns_uart_handle_rx(void *dev_id,
> unsigned int isrstatus)
> static void cdns_uart_handle_tx(void *dev_id)
> {
> struct uart_port *port = (struct uart_port *)dev_id;
> + struct cdns_uart *cdns_uart = port->private_data;
> struct circ_buf *xmit = &port->state->xmit;
> + unsigned long time_out;
> unsigned int numbytes;
>
> + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) {
> + cdns_rs485_tx_setup(cdns_uart);
> + if (cdns_uart->port->rs485.delay_rts_before_send)
> + mdelay(cdns_uart->port->rs485.delay_rts_before_send);
mdelay?
https://www.kernel.org/doc/html/latest/timers/timers-howto.html
"In general, use of mdelay is discouraged and code should be refactored
to
allow for the use of msleep."
Furthermore, you're delaying before every burst of bytes here!
Every TXEMPTY interrupt!
> + }
> +
> if (uart_circ_empty(xmit)) {
> writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR);
> - return;
> + goto rs485_rx_setup;
And when there was nothing more to send you waited for nothing.
> }
>
> numbytes = port->fifosize;
> @@ -332,6 +387,23 @@ static void cdns_uart_handle_tx(void *dev_id)
>
> if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
> uart_write_wakeup(port);
> +
> +rs485_rx_setup:
> + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) {
> + time_out = jiffies + usecs_to_jiffies(TX_TIMEOUT);
> + /* Wait for tx completion */
> + while ((cdns_uart_tx_empty(cdns_uart->port) != TIOCSER_TEMT) &&
> + time_before(jiffies, time_out))
> + cpu_relax();
> +
> + /*
> + * Default Rx should be setup, because RX signaling path
> + * need to enable to receive data.
> + */
> + cdns_rs485_rx_setup(cdns_uart);
> + if (cdns_uart->port->rs485.delay_rts_after_send)
> + mdelay(cdns_uart->port->rs485.delay_rts_after_send);
This is not delaying rts after send. You must keep RTS aka DE active for
a little
longer so even the last stop bit(s) are transmitted correctly. So this
delay must
happen before cdns_rs485_rx_setup().
> + }
> }
>
> /**
> @@ -829,6 +901,9 @@ static int cdns_uart_startup(struct uart_port
> *port)
> (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
> cpu_relax();
>
> + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED)
> + cdns_rs485_rx_setup(cdns_uart);
> +
> /*
> * Clear the RX disable bit and then set the RX enable bit to enable
> * the receiver.
> @@ -1455,6 +1530,25 @@ MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
> /* Temporary variable for storing number of instances */
> static int instances;
>
> +/**
> + * cdns_rs485_config - Called when an application calls TIOCSRS485
> ioctl.
> + * @port: Pointer to the uart_port structure
> + * @termios: Pointer to the ktermios structure
> + * @rs485: Pointer to the serial_rs485 structure
> + *
> + * Return: 0
> + */
> +static int cdns_rs485_config(struct uart_port *port, struct ktermios
> *termios,
> + struct serial_rs485 *rs485)
> +{
> + port->rs485 = *rs485;
> +
> + if (rs485->flags & SER_RS485_ENABLED)
> + dev_dbg(port->dev, "Setting UART to RS485\n");
> +
> + return 0;
> +}
> +
> /**
> * cdns_uart_probe - Platform driver probe
> * @pdev: Pointer to the platform device structure
> @@ -1597,9 +1691,28 @@ static int cdns_uart_probe(struct
> platform_device *pdev)
> port->private_data = cdns_uart_data;
> port->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG
> |
> CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT;
> + port->rs485_config = cdns_rs485_config;
> + port->rs485_supported = cdns_rs485_supported;
> cdns_uart_data->port = port;
> platform_set_drvdata(pdev, port);
>
> + rc = uart_get_rs485_mode(port);
> + if (rc)
> + goto err_out_clk_notifier;
> +
> + cdns_uart_data->gpiod = devm_gpiod_get_optional(&pdev->dev,
> "xlnx,phy-ctrl",
> + GPIOD_OUT_LOW);
> + if (IS_ERR(cdns_uart_data->gpiod)) {
> + rc = PTR_ERR(cdns_uart_data->gpiod);
> + dev_err(port->dev, "xuartps: devm_gpiod_get_optional failed\n");
> + goto err_out_clk_notifier;
> + }
> +
> + if (cdns_uart_data->gpiod) {
> + gpiod_direction_output(cdns_uart_data->gpiod, GPIOD_OUT_LOW);
> + gpiod_set_value(cdns_uart_data->gpiod, 0);
> + }
> +
> pm_runtime_use_autosuspend(&pdev->dev);
> pm_runtime_set_autosuspend_delay(&pdev->dev,
> UART_AUTOSUSPEND_TIMEOUT);
> pm_runtime_set_active(&pdev->dev);
> @@ -1646,6 +1759,7 @@ static int cdns_uart_probe(struct platform_device
> *pdev)
> pm_runtime_disable(&pdev->dev);
> pm_runtime_set_suspended(&pdev->dev);
> pm_runtime_dont_use_autosuspend(&pdev->dev);
> +err_out_clk_notifier:
> #ifdef CONFIG_COMMON_CLK
> clk_notifier_unregister(cdns_uart_data->uartclk,
> &cdns_uart_data->clk_rate_change_nb);
Maarten
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH V2 1/2] dt-bindings: Add optional gpio property to uartps node to support rs485
2023-10-12 18:35 ` m.brock
(?)
@ 2023-10-12 20:51 ` Rob Herring
2023-10-13 11:17 ` m.brock
-1 siblings, 1 reply; 19+ messages in thread
From: Rob Herring @ 2023-10-12 20:51 UTC (permalink / raw)
To: m.brock
Cc: Manikanta Guntupalli, git, michal.simek, gregkh,
krzysztof.kozlowski+dt, conor+dt, linux-serial, devicetree,
linux-kernel, jirislaby, linux-arm-kernel, radhey.shyam.pandey,
srinivas.goud, shubhrajyoti.datta, manion05gk
On Thu, Oct 12, 2023 at 08:35:59PM +0200, m.brock@vanmierlo.com wrote:
> Manikanta Guntupalli wrote on 2023-10-11 16:56:
> > Add optional gpio property to uartps node and reference to rs485.yaml
> >
> > On Xilinx/AMD Kria SOM KD240 board rs485 connects via TI ISOW1432
> > Transceiver device, where one GPIO is used for driving DE/RE signals.
> > With rs485 half duplex configuration, DE and RE shorts to each other,
>
> s/shorts/are connected
>
> > and at a time, any node acts as either a driver or a receiver.
> >
> > Here,
> > DE - Driver enable. If pin is floating, driver is disabled.
> > RE - Receiver enable. If pin is floating, receiver buffer is disabled.
>
> Please use DE and /RE to indicate DE is active high and /RE is active low.
>
> > xlnx,phy-ctrl-gpios is optional property, because it is not required
> > for uart console node.
>
> How about introducing an rs485 generic gpios property instead of xlnx
> private one? See also rs485-term-gpios and rs485-rx-during-tx-gpios.
>
> Also note that every kernel driver expects to use RTS for this purpose.
> So why not give this driver the option to choose a gpio instead of its
> native RTS? And from there on use the rts route?
> What if someone wants to use normal (non-rs485) RTS on a GPIO instead
> of the native pin?
>
> @Rob Herring
> I am curious to know how the rs485 maintainers look at this.
Ask them.
We already have 'rts-gpios'. If that's what's always used, then perhaps
we should use that in the RS485 case too?
Rob
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH V2 1/2] dt-bindings: Add optional gpio property to uartps node to support rs485
2023-10-12 20:51 ` Rob Herring
@ 2023-10-13 11:17 ` m.brock
0 siblings, 0 replies; 19+ messages in thread
From: m.brock @ 2023-10-13 11:17 UTC (permalink / raw)
To: Rob Herring
Cc: Manikanta Guntupalli, git, michal.simek, gregkh,
krzysztof.kozlowski+dt, conor+dt, linux-serial, devicetree,
linux-kernel, jirislaby, linux-arm-kernel, radhey.shyam.pandey,
srinivas.goud, shubhrajyoti.datta, manion05gk
Rob Herring wrote on 2023-10-12 22:51:
>> How about introducing an rs485 generic gpios property instead of xlnx
>> private one? See also rs485-term-gpios and rs485-rx-during-tx-gpios.
>>
>> Also note that every kernel driver expects to use RTS for this
>> purpose.
>> So why not give this driver the option to choose a gpio instead of its
>> native RTS? And from there on use the rts route?
>> What if someone wants to use normal (non-rs485) RTS on a GPIO instead
>> of the native pin?
>>
>> @Rob Herring
>> I am curious to know how the rs485 maintainers look at this.
>
> Ask them.
Funny, your name is the only one listed under the maintainers in
Documentation/devicetree/bindings/serial/rs485.yaml
And there is no mention of (RS-)485 in MAINTAINERS.
> We already have 'rts-gpios'. If that's what's always used, then perhaps
> we should use that in the RS485 case too?
>
> Rob
Sounds like a good idea.
Maarten
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH V2 1/2] dt-bindings: Add optional gpio property to uartps node to support rs485
@ 2023-10-13 11:17 ` m.brock
0 siblings, 0 replies; 19+ messages in thread
From: m.brock @ 2023-10-13 11:17 UTC (permalink / raw)
To: Rob Herring
Cc: Manikanta Guntupalli, git, michal.simek, gregkh,
krzysztof.kozlowski+dt, conor+dt, linux-serial, devicetree,
linux-kernel, jirislaby, linux-arm-kernel, radhey.shyam.pandey,
srinivas.goud, shubhrajyoti.datta, manion05gk
Rob Herring wrote on 2023-10-12 22:51:
>> How about introducing an rs485 generic gpios property instead of xlnx
>> private one? See also rs485-term-gpios and rs485-rx-during-tx-gpios.
>>
>> Also note that every kernel driver expects to use RTS for this
>> purpose.
>> So why not give this driver the option to choose a gpio instead of its
>> native RTS? And from there on use the rts route?
>> What if someone wants to use normal (non-rs485) RTS on a GPIO instead
>> of the native pin?
>>
>> @Rob Herring
>> I am curious to know how the rs485 maintainers look at this.
>
> Ask them.
Funny, your name is the only one listed under the maintainers in
Documentation/devicetree/bindings/serial/rs485.yaml
And there is no mention of (RS-)485 in MAINTAINERS.
> We already have 'rts-gpios'. If that's what's always used, then perhaps
> we should use that in the RS485 case too?
>
> Rob
Sounds like a good idea.
Maarten
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 19+ messages in thread
* RE: [PATCH V2 2/2] tty: serial: uartps: Add rs485 support to uartps driver
2023-10-12 19:05 ` m.brock
@ 2023-10-17 11:59 ` Guntupalli, Manikanta
-1 siblings, 0 replies; 19+ messages in thread
From: Guntupalli, Manikanta @ 2023-10-17 11:59 UTC (permalink / raw)
To: m.brock@vanmierlo.com
Cc: git (AMD-Xilinx), Simek, Michal, gregkh@linuxfoundation.org,
robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org,
conor+dt@kernel.org, linux-serial@vger.kernel.org,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
jirislaby@kernel.org, linux-arm-kernel@lists.infradead.org,
Pandey, Radhey Shyam, Goud, Srinivas, Datta, Shubhrajyoti,
manion05gk@gmail.com
Hi,
> -----Original Message-----
> From: m.brock@vanmierlo.com <m.brock@vanmierlo.com>
> Sent: Friday, October 13, 2023 12:35 AM
> To: Guntupalli, Manikanta <manikanta.guntupalli@amd.com>
> Cc: git (AMD-Xilinx) <git@amd.com>; Simek, Michal
> <michal.simek@amd.com>; gregkh@linuxfoundation.org;
> robh+dt@kernel.org; krzysztof.kozlowski+dt@linaro.org;
> conor+dt@kernel.org; linux-serial@vger.kernel.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org;
> jirislaby@kernel.org; linux-arm-kernel@lists.infradead.org; Pandey, Radhey
> Shyam <radhey.shyam.pandey@amd.com>; Goud, Srinivas
> <srinivas.goud@amd.com>; Datta, Shubhrajyoti
> <shubhrajyoti.datta@amd.com>; manion05gk@gmail.com
> Subject: Re: [PATCH V2 2/2] tty: serial: uartps: Add rs485 support to uartps
> driver
>
> Manikanta Guntupalli wrote on 2023-10-11 16:56:
> > In RS485 half duplex configuration, DriverEnable and ReceiverEnable
> > shorted to each other, and at a time, any node acts as either a driver
> > or a receiver. Use either xlnx,phy-ctrl-gpios or RTS to control
> > RS485 phy as driver or a receiver.
> >
> > Signed-off-by: Manikanta Guntupalli <manikanta.guntupalli@amd.com>
> > ---
> > Changes for V2:
> > Modify optional gpio name to xlnx,phy-ctrl-gpios.
> > Update commit description.
> > Add support for RTS, delay_rts_before_send and delay_rts_after_send in
> > RS485 mode.
> > ---
> > drivers/tty/serial/xilinx_uartps.c | 116
> > ++++++++++++++++++++++++++++-
> > 1 file changed, 115 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/tty/serial/xilinx_uartps.c
> > b/drivers/tty/serial/xilinx_uartps.c
> > index 8e521c69a959..abddcf1a8bf4 100644
> > --- a/drivers/tty/serial/xilinx_uartps.c
> > +++ b/drivers/tty/serial/xilinx_uartps.c
> > @@ -23,6 +23,7 @@
> > #include <linux/module.h>
> > #include <linux/pm_runtime.h>
> > #include <linux/iopoll.h>
> > +#include <linux/gpio.h>
> >
> > #define CDNS_UART_TTY_NAME "ttyPS"
> > #define CDNS_UART_NAME "xuartps"
> > @@ -193,6 +194,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-
> 255");
> > * @clk_rate_change_nb: Notifier block for clock changes
> > * @quirks: Flags for RXBS support.
> > * @cts_override: Modem control state override
> > + * @gpiod: Pointer to the gpio descriptor
> > */
> > struct cdns_uart {
> > struct uart_port *port;
> > @@ -203,10 +205,19 @@ struct cdns_uart {
> > struct notifier_block clk_rate_change_nb;
> > u32 quirks;
> > bool cts_override;
> > + struct gpio_desc *gpiod;
> > };
> > struct cdns_platform_data {
> > u32 quirks;
> > };
> > +
> > +struct serial_rs485 cdns_rs485_supported = {
> > + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
> > + SER_RS485_RTS_AFTER_SEND,
>
> You promise here to support both RTS-on-send and RTS-after-send, but...
>
> > + .delay_rts_before_send = 1,
> > + .delay_rts_after_send = 1,
> > +};
> > +
> > #define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \
> > clk_rate_change_nb)
> >
> > @@ -305,6 +316,42 @@ static void cdns_uart_handle_rx(void *dev_id,
> > unsigned int isrstatus)
> > tty_flip_buffer_push(&port->state->port);
> > }
> >
> > +/**
> > + * cdns_rs485_tx_setup - Tx setup specific to rs485
> > + * @cdns_uart: Handle to the cdns_uart */ static void
> > +cdns_rs485_tx_setup(struct cdns_uart *cdns_uart) {
> > + u32 val;
> > +
> > + if (cdns_uart->gpiod) {
> > + gpiod_set_value(cdns_uart->gpiod, 1);
> > + } else {
> > + val = readl(cdns_uart->port->membase +
> CDNS_UART_MODEMCR);
> > + val &= ~CDNS_UART_MODEMCR_RTS;
> > + writel(val, cdns_uart->port->membase +
> CDNS_UART_MODEMCR);
>
> Here you don't care about RTS-on-send or RTS-after-send anymore.
> And neither do you btw. in the if clause.
On Xilinx/AMD Kria SOM KD240 board rs485 connects via TI ISOW1432
Transceiver device, where one GPIO is used for driving DE/RE signals.
With rs485 half duplex configuration, DE and RE shorted to each other,
and at a time, any node acts as either a driver or a receiver.
We recommend using either GPIO or RTS to control RS485 phy as driver or a
receiver. So, we fall back to RTS, if rts-gpios not passed.
>
> > + }
> > +}
> > +
> > +/**
> > + * cdns_rs485_rx_setup - Rx setup specific to rs485
> > + * @cdns_uart: Handle to the cdns_uart */ static void
> > +cdns_rs485_rx_setup(struct cdns_uart *cdns_uart) {
> > + u32 val;
> > +
> > + if (cdns_uart->gpiod) {
> > + gpiod_set_value(cdns_uart->gpiod, 0);
> > + } else {
> > + val = readl(cdns_uart->port->membase +
> CDNS_UART_MODEMCR);
> > + val |= CDNS_UART_MODEMCR_RTS;
> > + writel(val, cdns_uart->port->membase +
> CDNS_UART_MODEMCR);
> > + }
>
> Same here.
>
> > +}
> > +
> > +static unsigned int cdns_uart_tx_empty(struct uart_port *port);
> > +
>
> I think it's better to move up the implementation than to use a forward
> declaration.
We will fix.
>
> > /**
> > * cdns_uart_handle_tx - Handle the bytes to be Txed.
> > * @dev_id: Id of the UART port
> > @@ -313,12 +360,20 @@ static void cdns_uart_handle_rx(void *dev_id,
> > unsigned int isrstatus) static void cdns_uart_handle_tx(void *dev_id)
> > {
> > struct uart_port *port = (struct uart_port *)dev_id;
> > + struct cdns_uart *cdns_uart = port->private_data;
> > struct circ_buf *xmit = &port->state->xmit;
> > + unsigned long time_out;
> > unsigned int numbytes;
> >
> > + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) {
> > + cdns_rs485_tx_setup(cdns_uart);
> > + if (cdns_uart->port->rs485.delay_rts_before_send)
> > + mdelay(cdns_uart->port-
> >rs485.delay_rts_before_send);
>
> mdelay?
> https://www.kernel.org/doc/html/latest/timers/timers-howto.html
> "In general, use of mdelay is discouraged and code should be refactored to
> allow for the use of msleep."
For refactoring the code will move this code snippet to start_tx, even there,
interrupts are disabled, so can't use msleep.
https://docs.kernel.org/driver-api/serial/driver.html
Documentation recommends,
start_tx
void ()(struct uart_port *port)
Start transmitting characters.
Locking: port->lock taken. Interrupts: locally disabled. This call must not sleep.
>
> Furthermore, you're delaying before every burst of bytes here!
> Every TXEMPTY interrupt!
We will move code to start_tx.
>
> > + }
> > +
> > if (uart_circ_empty(xmit)) {
> > writel(CDNS_UART_IXR_TXEMPTY, port->membase +
> CDNS_UART_IDR);
> > - return;
> > + goto rs485_rx_setup;
>
> And when there was nothing more to send you waited for nothing.
We will fix.
>
> > }
> >
> > numbytes = port->fifosize;
> > @@ -332,6 +387,23 @@ static void cdns_uart_handle_tx(void *dev_id)
> >
> > if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
> > uart_write_wakeup(port);
> > +
> > +rs485_rx_setup:
> > + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) {
> > + time_out = jiffies + usecs_to_jiffies(TX_TIMEOUT);
> > + /* Wait for tx completion */
> > + while ((cdns_uart_tx_empty(cdns_uart->port) !=
> TIOCSER_TEMT) &&
> > + time_before(jiffies, time_out))
> > + cpu_relax();
> > +
> > + /*
> > + * Default Rx should be setup, because RX signaling path
> > + * need to enable to receive data.
> > + */
> > + cdns_rs485_rx_setup(cdns_uart);
> > + if (cdns_uart->port->rs485.delay_rts_after_send)
> > + mdelay(cdns_uart->port-
> >rs485.delay_rts_after_send);
>
> This is not delaying rts after send. You must keep RTS aka DE active for a little
> longer so even the last stop bit(s) are transmitted correctly. So this delay must
> happen before cdns_rs485_rx_setup().
We will fix.
>
> > + }
> > }
> >
> > /**
> > @@ -829,6 +901,9 @@ static int cdns_uart_startup(struct uart_port
> > *port)
> > (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
> > cpu_relax();
> >
> > + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED)
> > + cdns_rs485_rx_setup(cdns_uart);
> > +
> > /*
> > * Clear the RX disable bit and then set the RX enable bit to enable
> > * the receiver.
> > @@ -1455,6 +1530,25 @@ MODULE_DEVICE_TABLE(of,
> cdns_uart_of_match);
> > /* Temporary variable for storing number of instances */ static int
> > instances;
> >
> > +/**
> > + * cdns_rs485_config - Called when an application calls TIOCSRS485
> > ioctl.
> > + * @port: Pointer to the uart_port structure
> > + * @termios: Pointer to the ktermios structure
> > + * @rs485: Pointer to the serial_rs485 structure
> > + *
> > + * Return: 0
> > + */
> > +static int cdns_rs485_config(struct uart_port *port, struct ktermios
> > *termios,
> > + struct serial_rs485 *rs485)
> > +{
> > + port->rs485 = *rs485;
> > +
> > + if (rs485->flags & SER_RS485_ENABLED)
> > + dev_dbg(port->dev, "Setting UART to RS485\n");
> > +
> > + return 0;
> > +}
> > +
> > /**
> > * cdns_uart_probe - Platform driver probe
> > * @pdev: Pointer to the platform device structure @@ -1597,9
> > +1691,28 @@ static int cdns_uart_probe(struct platform_device *pdev)
> > port->private_data = cdns_uart_data;
> > port->read_status_mask = CDNS_UART_IXR_TXEMPTY |
> > CDNS_UART_IXR_RXTRIG
> > |
> > CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT;
> > + port->rs485_config = cdns_rs485_config;
> > + port->rs485_supported = cdns_rs485_supported;
> > cdns_uart_data->port = port;
> > platform_set_drvdata(pdev, port);
> >
> > + rc = uart_get_rs485_mode(port);
> > + if (rc)
> > + goto err_out_clk_notifier;
> > +
> > + cdns_uart_data->gpiod = devm_gpiod_get_optional(&pdev->dev,
> > "xlnx,phy-ctrl",
> > + GPIOD_OUT_LOW);
> > + if (IS_ERR(cdns_uart_data->gpiod)) {
> > + rc = PTR_ERR(cdns_uart_data->gpiod);
> > + dev_err(port->dev, "xuartps: devm_gpiod_get_optional
> failed\n");
> > + goto err_out_clk_notifier;
> > + }
> > +
> > + if (cdns_uart_data->gpiod) {
> > + gpiod_direction_output(cdns_uart_data->gpiod,
> GPIOD_OUT_LOW);
> > + gpiod_set_value(cdns_uart_data->gpiod, 0);
> > + }
> > +
> > pm_runtime_use_autosuspend(&pdev->dev);
> > pm_runtime_set_autosuspend_delay(&pdev->dev,
> > UART_AUTOSUSPEND_TIMEOUT);
> > pm_runtime_set_active(&pdev->dev);
> > @@ -1646,6 +1759,7 @@ static int cdns_uart_probe(struct
> > platform_device
> > *pdev)
> > pm_runtime_disable(&pdev->dev);
> > pm_runtime_set_suspended(&pdev->dev);
> > pm_runtime_dont_use_autosuspend(&pdev->dev);
> > +err_out_clk_notifier:
> > #ifdef CONFIG_COMMON_CLK
> > clk_notifier_unregister(cdns_uart_data->uartclk,
> > &cdns_uart_data->clk_rate_change_nb);
>
> Maarten
Thanks,
Manikanta.
^ permalink raw reply [flat|nested] 19+ messages in thread
* RE: [PATCH V2 2/2] tty: serial: uartps: Add rs485 support to uartps driver
@ 2023-10-17 11:59 ` Guntupalli, Manikanta
0 siblings, 0 replies; 19+ messages in thread
From: Guntupalli, Manikanta @ 2023-10-17 11:59 UTC (permalink / raw)
To: m.brock@vanmierlo.com
Cc: git (AMD-Xilinx), Simek, Michal, gregkh@linuxfoundation.org,
robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org,
conor+dt@kernel.org, linux-serial@vger.kernel.org,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
jirislaby@kernel.org, linux-arm-kernel@lists.infradead.org,
Pandey, Radhey Shyam, Goud, Srinivas, Datta, Shubhrajyoti,
manion05gk@gmail.com
Hi,
> -----Original Message-----
> From: m.brock@vanmierlo.com <m.brock@vanmierlo.com>
> Sent: Friday, October 13, 2023 12:35 AM
> To: Guntupalli, Manikanta <manikanta.guntupalli@amd.com>
> Cc: git (AMD-Xilinx) <git@amd.com>; Simek, Michal
> <michal.simek@amd.com>; gregkh@linuxfoundation.org;
> robh+dt@kernel.org; krzysztof.kozlowski+dt@linaro.org;
> conor+dt@kernel.org; linux-serial@vger.kernel.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org;
> jirislaby@kernel.org; linux-arm-kernel@lists.infradead.org; Pandey, Radhey
> Shyam <radhey.shyam.pandey@amd.com>; Goud, Srinivas
> <srinivas.goud@amd.com>; Datta, Shubhrajyoti
> <shubhrajyoti.datta@amd.com>; manion05gk@gmail.com
> Subject: Re: [PATCH V2 2/2] tty: serial: uartps: Add rs485 support to uartps
> driver
>
> Manikanta Guntupalli wrote on 2023-10-11 16:56:
> > In RS485 half duplex configuration, DriverEnable and ReceiverEnable
> > shorted to each other, and at a time, any node acts as either a driver
> > or a receiver. Use either xlnx,phy-ctrl-gpios or RTS to control
> > RS485 phy as driver or a receiver.
> >
> > Signed-off-by: Manikanta Guntupalli <manikanta.guntupalli@amd.com>
> > ---
> > Changes for V2:
> > Modify optional gpio name to xlnx,phy-ctrl-gpios.
> > Update commit description.
> > Add support for RTS, delay_rts_before_send and delay_rts_after_send in
> > RS485 mode.
> > ---
> > drivers/tty/serial/xilinx_uartps.c | 116
> > ++++++++++++++++++++++++++++-
> > 1 file changed, 115 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/tty/serial/xilinx_uartps.c
> > b/drivers/tty/serial/xilinx_uartps.c
> > index 8e521c69a959..abddcf1a8bf4 100644
> > --- a/drivers/tty/serial/xilinx_uartps.c
> > +++ b/drivers/tty/serial/xilinx_uartps.c
> > @@ -23,6 +23,7 @@
> > #include <linux/module.h>
> > #include <linux/pm_runtime.h>
> > #include <linux/iopoll.h>
> > +#include <linux/gpio.h>
> >
> > #define CDNS_UART_TTY_NAME "ttyPS"
> > #define CDNS_UART_NAME "xuartps"
> > @@ -193,6 +194,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-
> 255");
> > * @clk_rate_change_nb: Notifier block for clock changes
> > * @quirks: Flags for RXBS support.
> > * @cts_override: Modem control state override
> > + * @gpiod: Pointer to the gpio descriptor
> > */
> > struct cdns_uart {
> > struct uart_port *port;
> > @@ -203,10 +205,19 @@ struct cdns_uart {
> > struct notifier_block clk_rate_change_nb;
> > u32 quirks;
> > bool cts_override;
> > + struct gpio_desc *gpiod;
> > };
> > struct cdns_platform_data {
> > u32 quirks;
> > };
> > +
> > +struct serial_rs485 cdns_rs485_supported = {
> > + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
> > + SER_RS485_RTS_AFTER_SEND,
>
> You promise here to support both RTS-on-send and RTS-after-send, but...
>
> > + .delay_rts_before_send = 1,
> > + .delay_rts_after_send = 1,
> > +};
> > +
> > #define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \
> > clk_rate_change_nb)
> >
> > @@ -305,6 +316,42 @@ static void cdns_uart_handle_rx(void *dev_id,
> > unsigned int isrstatus)
> > tty_flip_buffer_push(&port->state->port);
> > }
> >
> > +/**
> > + * cdns_rs485_tx_setup - Tx setup specific to rs485
> > + * @cdns_uart: Handle to the cdns_uart */ static void
> > +cdns_rs485_tx_setup(struct cdns_uart *cdns_uart) {
> > + u32 val;
> > +
> > + if (cdns_uart->gpiod) {
> > + gpiod_set_value(cdns_uart->gpiod, 1);
> > + } else {
> > + val = readl(cdns_uart->port->membase +
> CDNS_UART_MODEMCR);
> > + val &= ~CDNS_UART_MODEMCR_RTS;
> > + writel(val, cdns_uart->port->membase +
> CDNS_UART_MODEMCR);
>
> Here you don't care about RTS-on-send or RTS-after-send anymore.
> And neither do you btw. in the if clause.
On Xilinx/AMD Kria SOM KD240 board rs485 connects via TI ISOW1432
Transceiver device, where one GPIO is used for driving DE/RE signals.
With rs485 half duplex configuration, DE and RE shorted to each other,
and at a time, any node acts as either a driver or a receiver.
We recommend using either GPIO or RTS to control RS485 phy as driver or a
receiver. So, we fall back to RTS, if rts-gpios not passed.
>
> > + }
> > +}
> > +
> > +/**
> > + * cdns_rs485_rx_setup - Rx setup specific to rs485
> > + * @cdns_uart: Handle to the cdns_uart */ static void
> > +cdns_rs485_rx_setup(struct cdns_uart *cdns_uart) {
> > + u32 val;
> > +
> > + if (cdns_uart->gpiod) {
> > + gpiod_set_value(cdns_uart->gpiod, 0);
> > + } else {
> > + val = readl(cdns_uart->port->membase +
> CDNS_UART_MODEMCR);
> > + val |= CDNS_UART_MODEMCR_RTS;
> > + writel(val, cdns_uart->port->membase +
> CDNS_UART_MODEMCR);
> > + }
>
> Same here.
>
> > +}
> > +
> > +static unsigned int cdns_uart_tx_empty(struct uart_port *port);
> > +
>
> I think it's better to move up the implementation than to use a forward
> declaration.
We will fix.
>
> > /**
> > * cdns_uart_handle_tx - Handle the bytes to be Txed.
> > * @dev_id: Id of the UART port
> > @@ -313,12 +360,20 @@ static void cdns_uart_handle_rx(void *dev_id,
> > unsigned int isrstatus) static void cdns_uart_handle_tx(void *dev_id)
> > {
> > struct uart_port *port = (struct uart_port *)dev_id;
> > + struct cdns_uart *cdns_uart = port->private_data;
> > struct circ_buf *xmit = &port->state->xmit;
> > + unsigned long time_out;
> > unsigned int numbytes;
> >
> > + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) {
> > + cdns_rs485_tx_setup(cdns_uart);
> > + if (cdns_uart->port->rs485.delay_rts_before_send)
> > + mdelay(cdns_uart->port-
> >rs485.delay_rts_before_send);
>
> mdelay?
> https://www.kernel.org/doc/html/latest/timers/timers-howto.html
> "In general, use of mdelay is discouraged and code should be refactored to
> allow for the use of msleep."
For refactoring the code will move this code snippet to start_tx, even there,
interrupts are disabled, so can't use msleep.
https://docs.kernel.org/driver-api/serial/driver.html
Documentation recommends,
start_tx
void ()(struct uart_port *port)
Start transmitting characters.
Locking: port->lock taken. Interrupts: locally disabled. This call must not sleep.
>
> Furthermore, you're delaying before every burst of bytes here!
> Every TXEMPTY interrupt!
We will move code to start_tx.
>
> > + }
> > +
> > if (uart_circ_empty(xmit)) {
> > writel(CDNS_UART_IXR_TXEMPTY, port->membase +
> CDNS_UART_IDR);
> > - return;
> > + goto rs485_rx_setup;
>
> And when there was nothing more to send you waited for nothing.
We will fix.
>
> > }
> >
> > numbytes = port->fifosize;
> > @@ -332,6 +387,23 @@ static void cdns_uart_handle_tx(void *dev_id)
> >
> > if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
> > uart_write_wakeup(port);
> > +
> > +rs485_rx_setup:
> > + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) {
> > + time_out = jiffies + usecs_to_jiffies(TX_TIMEOUT);
> > + /* Wait for tx completion */
> > + while ((cdns_uart_tx_empty(cdns_uart->port) !=
> TIOCSER_TEMT) &&
> > + time_before(jiffies, time_out))
> > + cpu_relax();
> > +
> > + /*
> > + * Default Rx should be setup, because RX signaling path
> > + * need to enable to receive data.
> > + */
> > + cdns_rs485_rx_setup(cdns_uart);
> > + if (cdns_uart->port->rs485.delay_rts_after_send)
> > + mdelay(cdns_uart->port-
> >rs485.delay_rts_after_send);
>
> This is not delaying rts after send. You must keep RTS aka DE active for a little
> longer so even the last stop bit(s) are transmitted correctly. So this delay must
> happen before cdns_rs485_rx_setup().
We will fix.
>
> > + }
> > }
> >
> > /**
> > @@ -829,6 +901,9 @@ static int cdns_uart_startup(struct uart_port
> > *port)
> > (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
> > cpu_relax();
> >
> > + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED)
> > + cdns_rs485_rx_setup(cdns_uart);
> > +
> > /*
> > * Clear the RX disable bit and then set the RX enable bit to enable
> > * the receiver.
> > @@ -1455,6 +1530,25 @@ MODULE_DEVICE_TABLE(of,
> cdns_uart_of_match);
> > /* Temporary variable for storing number of instances */ static int
> > instances;
> >
> > +/**
> > + * cdns_rs485_config - Called when an application calls TIOCSRS485
> > ioctl.
> > + * @port: Pointer to the uart_port structure
> > + * @termios: Pointer to the ktermios structure
> > + * @rs485: Pointer to the serial_rs485 structure
> > + *
> > + * Return: 0
> > + */
> > +static int cdns_rs485_config(struct uart_port *port, struct ktermios
> > *termios,
> > + struct serial_rs485 *rs485)
> > +{
> > + port->rs485 = *rs485;
> > +
> > + if (rs485->flags & SER_RS485_ENABLED)
> > + dev_dbg(port->dev, "Setting UART to RS485\n");
> > +
> > + return 0;
> > +}
> > +
> > /**
> > * cdns_uart_probe - Platform driver probe
> > * @pdev: Pointer to the platform device structure @@ -1597,9
> > +1691,28 @@ static int cdns_uart_probe(struct platform_device *pdev)
> > port->private_data = cdns_uart_data;
> > port->read_status_mask = CDNS_UART_IXR_TXEMPTY |
> > CDNS_UART_IXR_RXTRIG
> > |
> > CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT;
> > + port->rs485_config = cdns_rs485_config;
> > + port->rs485_supported = cdns_rs485_supported;
> > cdns_uart_data->port = port;
> > platform_set_drvdata(pdev, port);
> >
> > + rc = uart_get_rs485_mode(port);
> > + if (rc)
> > + goto err_out_clk_notifier;
> > +
> > + cdns_uart_data->gpiod = devm_gpiod_get_optional(&pdev->dev,
> > "xlnx,phy-ctrl",
> > + GPIOD_OUT_LOW);
> > + if (IS_ERR(cdns_uart_data->gpiod)) {
> > + rc = PTR_ERR(cdns_uart_data->gpiod);
> > + dev_err(port->dev, "xuartps: devm_gpiod_get_optional
> failed\n");
> > + goto err_out_clk_notifier;
> > + }
> > +
> > + if (cdns_uart_data->gpiod) {
> > + gpiod_direction_output(cdns_uart_data->gpiod,
> GPIOD_OUT_LOW);
> > + gpiod_set_value(cdns_uart_data->gpiod, 0);
> > + }
> > +
> > pm_runtime_use_autosuspend(&pdev->dev);
> > pm_runtime_set_autosuspend_delay(&pdev->dev,
> > UART_AUTOSUSPEND_TIMEOUT);
> > pm_runtime_set_active(&pdev->dev);
> > @@ -1646,6 +1759,7 @@ static int cdns_uart_probe(struct
> > platform_device
> > *pdev)
> > pm_runtime_disable(&pdev->dev);
> > pm_runtime_set_suspended(&pdev->dev);
> > pm_runtime_dont_use_autosuspend(&pdev->dev);
> > +err_out_clk_notifier:
> > #ifdef CONFIG_COMMON_CLK
> > clk_notifier_unregister(cdns_uart_data->uartclk,
> > &cdns_uart_data->clk_rate_change_nb);
>
> Maarten
Thanks,
Manikanta.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH V2 2/2] tty: serial: uartps: Add rs485 support to uartps driver
2023-10-11 14:56 ` Manikanta Guntupalli
@ 2023-10-18 0:28 ` Lino Sanfilippo
-1 siblings, 0 replies; 19+ messages in thread
From: Lino Sanfilippo @ 2023-10-18 0:28 UTC (permalink / raw)
To: Manikanta Guntupalli, git, michal.simek, gregkh, robh+dt,
krzysztof.kozlowski+dt, conor+dt, linux-serial, devicetree,
linux-kernel, jirislaby, linux-arm-kernel
Cc: radhey.shyam.pandey, srinivas.goud, shubhrajyoti.datta,
manion05gk
On 11.10.23 at 16:56, Manikanta Guntupalli wrote:
> In RS485 half duplex configuration, DriverEnable and ReceiverEnable
> shorted to each other, and at a time, any node acts as either a driver
> or a receiver. Use either xlnx,phy-ctrl-gpios or RTS to control
> RS485 phy as driver or a receiver.
This is a very specific hardware setup. RS485 is supposed to work with various
hardware configurations though. So the above assumptions must not be hardcoded
in the RS485 implementation (as it is in cdns_rs485_rx_setup() and cdns_rs485_tx_setup()
IIUC)
>
> Signed-off-by: Manikanta Guntupalli <manikanta.guntupalli@amd.com>
> ---
> Changes for V2:
> Modify optional gpio name to xlnx,phy-ctrl-gpios.
> Update commit description.
> Add support for RTS, delay_rts_before_send and delay_rts_after_send in RS485 mode.
> ---
> drivers/tty/serial/xilinx_uartps.c | 116 ++++++++++++++++++++++++++++-
> 1 file changed, 115 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
> index 8e521c69a959..abddcf1a8bf4 100644
> --- a/drivers/tty/serial/xilinx_uartps.c
> +++ b/drivers/tty/serial/xilinx_uartps.c
> @@ -23,6 +23,7 @@
> #include <linux/module.h>
> #include <linux/pm_runtime.h>
> #include <linux/iopoll.h>
> +#include <linux/gpio.h>
>
> #define CDNS_UART_TTY_NAME "ttyPS"
> #define CDNS_UART_NAME "xuartps"
> @@ -193,6 +194,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
> * @clk_rate_change_nb: Notifier block for clock changes
> * @quirks: Flags for RXBS support.
> * @cts_override: Modem control state override
> + * @gpiod: Pointer to the gpio descriptor
> */
> struct cdns_uart {
> struct uart_port *port;
> @@ -203,10 +205,19 @@ struct cdns_uart {
> struct notifier_block clk_rate_change_nb;
> u32 quirks;
> bool cts_override;
> + struct gpio_desc *gpiod;
> };
> struct cdns_platform_data {
> u32 quirks;
> };
> +
> +struct serial_rs485 cdns_rs485_supported = {
> + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
> + SER_RS485_RTS_AFTER_SEND,
> + .delay_rts_before_send = 1,
> + .delay_rts_after_send = 1,
> +};
> +
> #define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \
> clk_rate_change_nb)
>
> @@ -305,6 +316,42 @@ static void cdns_uart_handle_rx(void *dev_id, unsigned int isrstatus)
> tty_flip_buffer_push(&port->state->port);
> }
>
> +/**
> + * cdns_rs485_tx_setup - Tx setup specific to rs485
> + * @cdns_uart: Handle to the cdns_uart
> + */
> +static void cdns_rs485_tx_setup(struct cdns_uart *cdns_uart)
> +{
> + u32 val;
> +
> + if (cdns_uart->gpiod) {
If both RTS_ON_SEND and RTS_AFTER_SEND are supported than you have to set the
GPIO value here depending on which one is currently configured. Note that
userspace may change RTS mode via TIOCSRS485 ioctl.
> + gpiod_set_value(cdns_uart->gpiod, 1);
> + } else {
> + val = readl(cdns_uart->port->membase + CDNS_UART_MODEMCR);
> + val &= ~CDNS_UART_MODEMCR_RTS;
> + writel(val, cdns_uart->port->membase + CDNS_UART_MODEMCR);
Same for the native RTS case.
> + }
> +}
> +
> +/**
> + * cdns_rs485_rx_setup - Rx setup specific to rs485
> + * @cdns_uart: Handle to the cdns_uart
> + */
> +static void cdns_rs485_rx_setup(struct cdns_uart *cdns_uart)
> +{
> + u32 val;
> +
> + if (cdns_uart->gpiod) {
> + gpiod_set_value(cdns_uart->gpiod, 0);
> + } else {
> + val = readl(cdns_uart->port->membase + CDNS_UART_MODEMCR);
> + val |= CDNS_UART_MODEMCR_RTS;
> + writel(val, cdns_uart->port->membase + CDNS_UART_MODEMCR);
> + }
See above.
> +}
> +
> +static unsigned int cdns_uart_tx_empty(struct uart_port *port);
> +
> /**
> * cdns_uart_handle_tx - Handle the bytes to be Txed.
> * @dev_id: Id of the UART port
> @@ -313,12 +360,20 @@ static void cdns_uart_handle_rx(void *dev_id, unsigned int isrstatus)
> static void cdns_uart_handle_tx(void *dev_id)
> {
> struct uart_port *port = (struct uart_port *)dev_id;
> + struct cdns_uart *cdns_uart = port->private_data;
> struct circ_buf *xmit = &port->state->xmit;
> + unsigned long time_out;
> unsigned int numbytes;
>
> + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) {
> + cdns_rs485_tx_setup(cdns_uart);
> + if (cdns_uart->port->rs485.delay_rts_before_send)
> + mdelay(cdns_uart->port->rs485.delay_rts_before_send);
> + }
> +
> if (uart_circ_empty(xmit)) {
> writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR);
> - return;
> + goto rs485_rx_setup;
> }
>
> numbytes = port->fifosize;
> @@ -332,6 +387,23 @@ static void cdns_uart_handle_tx(void *dev_id)
>
> if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
> uart_write_wakeup(port);
> +
> +rs485_rx_setup:
> + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) {
> + time_out = jiffies + usecs_to_jiffies(TX_TIMEOUT);
> + /* Wait for tx completion */
> + while ((cdns_uart_tx_empty(cdns_uart->port) != TIOCSER_TEMT) &&
> + time_before(jiffies, time_out))
> + cpu_relax();
> +
> + /*
> + * Default Rx should be setup, because RX signaling path
> + * need to enable to receive data.
> + */
> + cdns_rs485_rx_setup(cdns_uart);
> + if (cdns_uart->port->rs485.delay_rts_after_send)
> + mdelay(cdns_uart->port->rs485.delay_rts_after_send);
> + }
> }
>
> /**
> @@ -829,6 +901,9 @@ static int cdns_uart_startup(struct uart_port *port)
> (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
> cpu_relax();
>
> + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED)
> + cdns_rs485_rx_setup(cdns_uart);
> +
> /*
> * Clear the RX disable bit and then set the RX enable bit to enable
> * the receiver.
> @@ -1455,6 +1530,25 @@ MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
> /* Temporary variable for storing number of instances */
> static int instances;
>
> +/**
> + * cdns_rs485_config - Called when an application calls TIOCSRS485 ioctl.
> + * @port: Pointer to the uart_port structure
> + * @termios: Pointer to the ktermios structure
> + * @rs485: Pointer to the serial_rs485 structure
> + *
> + * Return: 0
> + */
> +static int cdns_rs485_config(struct uart_port *port, struct ktermios *termios,
> + struct serial_rs485 *rs485)
> +{
> + port->rs485 = *rs485;
> +
This assignment is not needed, the serial core will do that.
> + if (rs485->flags & SER_RS485_ENABLED)
> + dev_dbg(port->dev, "Setting UART to RS485\n");
> +
> + return 0;
> +}
> +
> /**
> * cdns_uart_probe - Platform driver probe
> * @pdev: Pointer to the platform device structure
> @@ -1597,9 +1691,28 @@ static int cdns_uart_probe(struct platform_device *pdev)
> port->private_data = cdns_uart_data;
> port->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG |
> CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT;
> + port->rs485_config = cdns_rs485_config;
> + port->rs485_supported = cdns_rs485_supported;
> cdns_uart_data->port = port;
> platform_set_drvdata(pdev, port);
>
> + rc = uart_get_rs485_mode(port);
> + if (rc)
> + goto err_out_clk_notifier;
> +
> + cdns_uart_data->gpiod = devm_gpiod_get_optional(&pdev->dev, "xlnx,phy-ctrl",
> + GPIOD_OUT_LOW);
> + if (IS_ERR(cdns_uart_data->gpiod)) {
> + rc = PTR_ERR(cdns_uart_data->gpiod);
> + dev_err(port->dev, "xuartps: devm_gpiod_get_optional failed\n");
> + goto err_out_clk_notifier;
> + }
> +
If using the GPIO is optional, why not fall back to the use of the native RTS?
> + if (cdns_uart_data->gpiod) {
> + gpiod_direction_output(cdns_uart_data->gpiod, GPIOD_OUT_LOW);
> + gpiod_set_value(cdns_uart_data->gpiod, 0);
You already set both of these attributes when you requested the GPIO.
> + }
> +
> pm_runtime_use_autosuspend(&pdev->dev);
> pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
> pm_runtime_set_active(&pdev->dev);
> @@ -1646,6 +1759,7 @@ static int cdns_uart_probe(struct platform_device *pdev)
> pm_runtime_disable(&pdev->dev);
> pm_runtime_set_suspended(&pdev->dev);
> pm_runtime_dont_use_autosuspend(&pdev->dev);
> +err_out_clk_notifier:
> #ifdef CONFIG_COMMON_CLK
> clk_notifier_unregister(cdns_uart_data->uartclk,
> &cdns_uart_data->clk_rate_change_nb);
>
Regards,
Lino
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH V2 2/2] tty: serial: uartps: Add rs485 support to uartps driver
@ 2023-10-18 0:28 ` Lino Sanfilippo
0 siblings, 0 replies; 19+ messages in thread
From: Lino Sanfilippo @ 2023-10-18 0:28 UTC (permalink / raw)
To: Manikanta Guntupalli, git, michal.simek, gregkh, robh+dt,
krzysztof.kozlowski+dt, conor+dt, linux-serial, devicetree,
linux-kernel, jirislaby, linux-arm-kernel
Cc: radhey.shyam.pandey, srinivas.goud, shubhrajyoti.datta,
manion05gk
On 11.10.23 at 16:56, Manikanta Guntupalli wrote:
> In RS485 half duplex configuration, DriverEnable and ReceiverEnable
> shorted to each other, and at a time, any node acts as either a driver
> or a receiver. Use either xlnx,phy-ctrl-gpios or RTS to control
> RS485 phy as driver or a receiver.
This is a very specific hardware setup. RS485 is supposed to work with various
hardware configurations though. So the above assumptions must not be hardcoded
in the RS485 implementation (as it is in cdns_rs485_rx_setup() and cdns_rs485_tx_setup()
IIUC)
>
> Signed-off-by: Manikanta Guntupalli <manikanta.guntupalli@amd.com>
> ---
> Changes for V2:
> Modify optional gpio name to xlnx,phy-ctrl-gpios.
> Update commit description.
> Add support for RTS, delay_rts_before_send and delay_rts_after_send in RS485 mode.
> ---
> drivers/tty/serial/xilinx_uartps.c | 116 ++++++++++++++++++++++++++++-
> 1 file changed, 115 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
> index 8e521c69a959..abddcf1a8bf4 100644
> --- a/drivers/tty/serial/xilinx_uartps.c
> +++ b/drivers/tty/serial/xilinx_uartps.c
> @@ -23,6 +23,7 @@
> #include <linux/module.h>
> #include <linux/pm_runtime.h>
> #include <linux/iopoll.h>
> +#include <linux/gpio.h>
>
> #define CDNS_UART_TTY_NAME "ttyPS"
> #define CDNS_UART_NAME "xuartps"
> @@ -193,6 +194,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
> * @clk_rate_change_nb: Notifier block for clock changes
> * @quirks: Flags for RXBS support.
> * @cts_override: Modem control state override
> + * @gpiod: Pointer to the gpio descriptor
> */
> struct cdns_uart {
> struct uart_port *port;
> @@ -203,10 +205,19 @@ struct cdns_uart {
> struct notifier_block clk_rate_change_nb;
> u32 quirks;
> bool cts_override;
> + struct gpio_desc *gpiod;
> };
> struct cdns_platform_data {
> u32 quirks;
> };
> +
> +struct serial_rs485 cdns_rs485_supported = {
> + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
> + SER_RS485_RTS_AFTER_SEND,
> + .delay_rts_before_send = 1,
> + .delay_rts_after_send = 1,
> +};
> +
> #define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \
> clk_rate_change_nb)
>
> @@ -305,6 +316,42 @@ static void cdns_uart_handle_rx(void *dev_id, unsigned int isrstatus)
> tty_flip_buffer_push(&port->state->port);
> }
>
> +/**
> + * cdns_rs485_tx_setup - Tx setup specific to rs485
> + * @cdns_uart: Handle to the cdns_uart
> + */
> +static void cdns_rs485_tx_setup(struct cdns_uart *cdns_uart)
> +{
> + u32 val;
> +
> + if (cdns_uart->gpiod) {
If both RTS_ON_SEND and RTS_AFTER_SEND are supported than you have to set the
GPIO value here depending on which one is currently configured. Note that
userspace may change RTS mode via TIOCSRS485 ioctl.
> + gpiod_set_value(cdns_uart->gpiod, 1);
> + } else {
> + val = readl(cdns_uart->port->membase + CDNS_UART_MODEMCR);
> + val &= ~CDNS_UART_MODEMCR_RTS;
> + writel(val, cdns_uart->port->membase + CDNS_UART_MODEMCR);
Same for the native RTS case.
> + }
> +}
> +
> +/**
> + * cdns_rs485_rx_setup - Rx setup specific to rs485
> + * @cdns_uart: Handle to the cdns_uart
> + */
> +static void cdns_rs485_rx_setup(struct cdns_uart *cdns_uart)
> +{
> + u32 val;
> +
> + if (cdns_uart->gpiod) {
> + gpiod_set_value(cdns_uart->gpiod, 0);
> + } else {
> + val = readl(cdns_uart->port->membase + CDNS_UART_MODEMCR);
> + val |= CDNS_UART_MODEMCR_RTS;
> + writel(val, cdns_uart->port->membase + CDNS_UART_MODEMCR);
> + }
See above.
> +}
> +
> +static unsigned int cdns_uart_tx_empty(struct uart_port *port);
> +
> /**
> * cdns_uart_handle_tx - Handle the bytes to be Txed.
> * @dev_id: Id of the UART port
> @@ -313,12 +360,20 @@ static void cdns_uart_handle_rx(void *dev_id, unsigned int isrstatus)
> static void cdns_uart_handle_tx(void *dev_id)
> {
> struct uart_port *port = (struct uart_port *)dev_id;
> + struct cdns_uart *cdns_uart = port->private_data;
> struct circ_buf *xmit = &port->state->xmit;
> + unsigned long time_out;
> unsigned int numbytes;
>
> + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) {
> + cdns_rs485_tx_setup(cdns_uart);
> + if (cdns_uart->port->rs485.delay_rts_before_send)
> + mdelay(cdns_uart->port->rs485.delay_rts_before_send);
> + }
> +
> if (uart_circ_empty(xmit)) {
> writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR);
> - return;
> + goto rs485_rx_setup;
> }
>
> numbytes = port->fifosize;
> @@ -332,6 +387,23 @@ static void cdns_uart_handle_tx(void *dev_id)
>
> if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
> uart_write_wakeup(port);
> +
> +rs485_rx_setup:
> + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) {
> + time_out = jiffies + usecs_to_jiffies(TX_TIMEOUT);
> + /* Wait for tx completion */
> + while ((cdns_uart_tx_empty(cdns_uart->port) != TIOCSER_TEMT) &&
> + time_before(jiffies, time_out))
> + cpu_relax();
> +
> + /*
> + * Default Rx should be setup, because RX signaling path
> + * need to enable to receive data.
> + */
> + cdns_rs485_rx_setup(cdns_uart);
> + if (cdns_uart->port->rs485.delay_rts_after_send)
> + mdelay(cdns_uart->port->rs485.delay_rts_after_send);
> + }
> }
>
> /**
> @@ -829,6 +901,9 @@ static int cdns_uart_startup(struct uart_port *port)
> (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
> cpu_relax();
>
> + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED)
> + cdns_rs485_rx_setup(cdns_uart);
> +
> /*
> * Clear the RX disable bit and then set the RX enable bit to enable
> * the receiver.
> @@ -1455,6 +1530,25 @@ MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
> /* Temporary variable for storing number of instances */
> static int instances;
>
> +/**
> + * cdns_rs485_config - Called when an application calls TIOCSRS485 ioctl.
> + * @port: Pointer to the uart_port structure
> + * @termios: Pointer to the ktermios structure
> + * @rs485: Pointer to the serial_rs485 structure
> + *
> + * Return: 0
> + */
> +static int cdns_rs485_config(struct uart_port *port, struct ktermios *termios,
> + struct serial_rs485 *rs485)
> +{
> + port->rs485 = *rs485;
> +
This assignment is not needed, the serial core will do that.
> + if (rs485->flags & SER_RS485_ENABLED)
> + dev_dbg(port->dev, "Setting UART to RS485\n");
> +
> + return 0;
> +}
> +
> /**
> * cdns_uart_probe - Platform driver probe
> * @pdev: Pointer to the platform device structure
> @@ -1597,9 +1691,28 @@ static int cdns_uart_probe(struct platform_device *pdev)
> port->private_data = cdns_uart_data;
> port->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG |
> CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT;
> + port->rs485_config = cdns_rs485_config;
> + port->rs485_supported = cdns_rs485_supported;
> cdns_uart_data->port = port;
> platform_set_drvdata(pdev, port);
>
> + rc = uart_get_rs485_mode(port);
> + if (rc)
> + goto err_out_clk_notifier;
> +
> + cdns_uart_data->gpiod = devm_gpiod_get_optional(&pdev->dev, "xlnx,phy-ctrl",
> + GPIOD_OUT_LOW);
> + if (IS_ERR(cdns_uart_data->gpiod)) {
> + rc = PTR_ERR(cdns_uart_data->gpiod);
> + dev_err(port->dev, "xuartps: devm_gpiod_get_optional failed\n");
> + goto err_out_clk_notifier;
> + }
> +
If using the GPIO is optional, why not fall back to the use of the native RTS?
> + if (cdns_uart_data->gpiod) {
> + gpiod_direction_output(cdns_uart_data->gpiod, GPIOD_OUT_LOW);
> + gpiod_set_value(cdns_uart_data->gpiod, 0);
You already set both of these attributes when you requested the GPIO.
> + }
> +
> pm_runtime_use_autosuspend(&pdev->dev);
> pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
> pm_runtime_set_active(&pdev->dev);
> @@ -1646,6 +1759,7 @@ static int cdns_uart_probe(struct platform_device *pdev)
> pm_runtime_disable(&pdev->dev);
> pm_runtime_set_suspended(&pdev->dev);
> pm_runtime_dont_use_autosuspend(&pdev->dev);
> +err_out_clk_notifier:
> #ifdef CONFIG_COMMON_CLK
> clk_notifier_unregister(cdns_uart_data->uartclk,
> &cdns_uart_data->clk_rate_change_nb);
>
Regards,
Lino
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH V2 2/2] tty: serial: uartps: Add rs485 support to uartps driver
2023-10-11 14:56 ` Manikanta Guntupalli
` (3 preceding siblings ...)
(?)
@ 2023-10-19 0:53 ` kernel test robot
-1 siblings, 0 replies; 19+ messages in thread
From: kernel test robot @ 2023-10-19 0:53 UTC (permalink / raw)
To: Manikanta Guntupalli; +Cc: oe-kbuild-all
Hi Manikanta,
kernel test robot noticed the following build warnings:
[auto build test WARNING on tty/tty-testing]
[also build test WARNING on tty/tty-next tty/tty-linus linus/master v6.6-rc6 next-20231018]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Manikanta-Guntupalli/dt-bindings-Add-optional-gpio-property-to-uartps-node-to-support-rs485/20231011-225836
base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing
patch link: https://lore.kernel.org/r/20231011145602.3619616-3-manikanta.guntupalli%40amd.com
patch subject: [PATCH V2 2/2] tty: serial: uartps: Add rs485 support to uartps driver
config: i386-randconfig-062-20231018 (https://download.01.org/0day-ci/archive/20231019/202310190816.kxgkr4cZ-lkp@intel.com/config)
compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231019/202310190816.kxgkr4cZ-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202310190816.kxgkr4cZ-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
>> drivers/tty/serial/xilinx_uartps.c:214:21: sparse: sparse: symbol 'cdns_rs485_supported' was not declared. Should it be static?
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2023-10-19 0:53 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-10-11 14:56 [PATCH V2 0/2] Add rs485 support to uartps driver Manikanta Guntupalli
2023-10-11 14:56 ` Manikanta Guntupalli
2023-10-11 14:56 ` [PATCH V2 1/2] dt-bindings: Add optional gpio property to uartps node to support rs485 Manikanta Guntupalli
2023-10-11 14:56 ` Manikanta Guntupalli
2023-10-12 18:35 ` m.brock
2023-10-12 18:35 ` m.brock
2023-10-12 20:51 ` Rob Herring
2023-10-13 11:17 ` m.brock
2023-10-13 11:17 ` m.brock
2023-10-11 14:56 ` [PATCH V2 2/2] tty: serial: uartps: Add rs485 support to uartps driver Manikanta Guntupalli
2023-10-11 14:56 ` Manikanta Guntupalli
2023-10-12 11:19 ` kernel test robot
2023-10-12 19:05 ` m.brock
2023-10-12 19:05 ` m.brock
2023-10-17 11:59 ` Guntupalli, Manikanta
2023-10-17 11:59 ` Guntupalli, Manikanta
2023-10-18 0:28 ` Lino Sanfilippo
2023-10-18 0:28 ` Lino Sanfilippo
2023-10-19 0:53 ` kernel test robot
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.