Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] serial: imx: keep the CPU out of deep idle while an RS485 port is open
@ 2026-10-15 14:46 Otavio Salvador
  2026-10-15 15:24 ` Frank Li
  0 siblings, 1 reply; 2+ messages in thread
From: Otavio Salvador @ 2026-10-15 14:46 UTC (permalink / raw)
  To: gregkh, jirislaby
  Cc: Frank.Li, s.hauer, kernel, festevam, linux-serial, imx,
	linux-arm-kernel, linux-kernel, Otavio Salvador,
	Rodrigo M. Duarte

In RS485 mode the driver releases the transmitter (RTS/DE) from the TX
complete interrupt. On i.MX6UL/ULL the imx6sx cpuidle driver offers an
"ARM power off" state with a declared exit latency of 300us, measured at
up to 2ms. When the CPU enters it while the last character is shifted
out, DE is released that much later. Modbus RTU slaves may answer after
3.5 character times (1.75ms at >=19200 baud), so the head of their reply
collides with our still-driven transmitter and is lost.

Add a CPU latency QoS request of 100us while an RS485 port is open. It
excludes the power-off state but keeps WFI and WAIT (50us) available, so
cpuidle can stay enabled and the constraint only applies while the port
is in use.

The request is added on startup and removed on shutdown, and its value
follows the RS485 state in imx_uart_rs485_config(), so RS485 enabled
through TIOCSRS485 after the port is opened, as libmodbus does, is
covered as well.

Tested-by: Rodrigo M. Duarte <rodrigo.duarte@ossystems.com.br>
Signed-off-by: Otavio Salvador <otavio@ossystems.com.br>
---
 drivers/tty/serial/imx.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 986fefb45c632..be05ed94bf0c4 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -24,6 +24,7 @@
 #include <linux/ktime.h>
 #include <linux/mutex.h>
 #include <linux/pinctrl/consumer.h>
+#include <linux/pm_qos.h>
 #include <linux/rational.h>
 #include <linux/slab.h>
 #include <linux/of.h>
@@ -237,6 +238,7 @@ struct imx_port {
 	struct hrtimer		trigger_start_tx;
 	struct hrtimer		trigger_stop_tx;
 	unsigned int		rxtl;
+	struct pm_qos_request	rs485_pm_qos;
 };
 
 struct imx_port_ucrs {
@@ -339,6 +341,22 @@ static void start_hrtimer_ms(struct hrtimer *hrt, unsigned long msec)
        hrtimer_start(hrt, ms_to_ktime(msec), HRTIMER_MODE_REL);
 }
 
+/*
+ * In RS485 mode the transmitter is only released from the TX complete
+ * interrupt. If the CPU sits in a deep idle state at that point, the wakeup
+ * delays the release long enough to collide with fast responders on the
+ * bus. The i.MX6UL/SX "ARM power off" state has a 300us exit latency and was
+ * measured at up to 2ms, so keep the CPU out of states slower than this while
+ * an RS485 port is open.
+ */
+#define IMX_UART_RS485_CPU_LATENCY_US	100
+
+static s32 imx_uart_rs485_cpu_latency(u32 rs485_flags)
+{
+	return rs485_flags & SER_RS485_ENABLED ?
+		IMX_UART_RS485_CPU_LATENCY_US : PM_QOS_DEFAULT_VALUE;
+}
+
 /* called with port.lock taken and irqs off */
 static void imx_uart_soft_reset(struct imx_port *sport)
 {
@@ -1585,6 +1603,9 @@ static int imx_uart_startup(struct uart_port *port)
 
 	uart_port_unlock_irqrestore(&sport->port, flags);
 
+	cpu_latency_qos_add_request(&sport->rs485_pm_qos,
+				    imx_uart_rs485_cpu_latency(port->rs485.flags));
+
 	return 0;
 }
 
@@ -1710,6 +1731,8 @@ static void imx_uart_shutdown(struct uart_port *port)
 
 	clk_disable_unprepare(sport->clk_per);
 	clk_disable_unprepare(sport->clk_ipg);
+
+	cpu_latency_qos_remove_request(&sport->rs485_pm_qos);
 }
 
 /* called with port.lock taken and irqs off */
@@ -2053,6 +2076,11 @@ static int imx_uart_rs485_config(struct uart_port *port, struct ktermios *termio
 		imx_uart_start_rx(port);
 	}
 
+	/* The request only exists while the port is open */
+	if (cpu_latency_qos_request_active(&sport->rs485_pm_qos))
+		cpu_latency_qos_update_request(&sport->rs485_pm_qos,
+					       imx_uart_rs485_cpu_latency(rs485conf->flags));
+
 	return 0;
 }
 
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-10-15 15:25 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-15 14:46 [PATCH] serial: imx: keep the CPU out of deep idle while an RS485 port is open Otavio Salvador
2026-10-15 15:24 ` Frank Li

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox