[PATCH v1 1/2] serial: msm_geni: Skip UART TX when no cable is connected

Aswin Murugan <[email protected]>
Newsgroups org.u-boot-project.lists.u-boot
Message-ID <[email protected]>
Add MSM_GENI_SERIAL_CABLE_DETECT Kconfig option and detect a
persistent RX-line BREAK condition (no S_GP_IRQ_3 after
S_GP_IRQ_2) to identify a disconnected debug UART cable, and
suppress TX output in that case to avoid driving an
unterminated line.

Signed-off-by: Aswin Murugan <[email protected]>
---
 drivers/serial/Kconfig           |  9 +++++++
 drivers/serial/serial_msm_geni.c | 41 ++++++++++++++++++++++++++++++++
 2 files changed, 50 insertions(+)

diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index ffc58d663ff..326088c7027 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1020,6 +1020,15 @@ config MSM_GENI_SERIAL
 	  Driver works in FIFO mode.
 	  Multiple baudrates supported.
 
+config MSM_GENI_SERIAL_CABLE_DETECT
+	bool "Disable GENI UART TX when no cable/console is connected"
+	depends on MSM_GENI_SERIAL
+	default n
+	help
+	  Detect a UART RX-line BREAK condition, which indicates that no
+	  cable is connected to the debug UART port, and suppress UART TX
+	  output.
+
 config MXS_AUART_SERIAL
 	bool "MXS AUART"
 	depends on DM_SERIAL
diff --git a/drivers/serial/serial_msm_geni.c b/drivers/serial/serial_msm_geni.c
index ff91e0018fa..8bf5f6eea26 100644
--- a/drivers/serial/serial_msm_geni.c
+++ b/drivers/serial/serial_msm_geni.c
@@ -98,6 +98,7 @@ struct msm_serial_data {
 	u32 baud;
 	u32 oversampling;
 	struct clk *se;
+	bool cable_connected;
 };
 
 unsigned long root_freq[] = {7372800,  14745600, 19200000, 29491200,
@@ -298,6 +299,28 @@ static u32 qcom_geni_serial_tx_empty(u64 base)
 	return !readl(base + SE_GENI_TX_FIFO_STATUS);
 }
 
+/**
+ * qcom_geni_serial_is_cable_connected() - Check UART RX-line BREAK condition.
+ * @base:	Pointer to the concerned serial engine.
+ *
+ * A serial cable that is not connected leaves the RX line in a state that
+ * the UART hardware reports as a BREAK condition that never ends, i.e.
+ * S_GP_IRQ_2 (RX_BREAK_START) gets set without a following S_GP_IRQ_3
+ * (RX_BREAK_END). This function checks the secondary sequencer IRQ status
+ * for that pattern.
+ *
+ * Return: false, if no cable is connected, true otherwise.
+ */
+static bool qcom_geni_serial_is_cable_connected(u64 base)
+{
+	u32 s_irq_status = readl(base + SE_GENI_S_IRQ_STATUS);
+
+	if ((s_irq_status & S_GP_IRQ_2_EN) && !(s_irq_status & S_GP_IRQ_3_EN))
+		return false;
+
+	return true;
+}
+
 /**
  * geni_se_setup_s_cmd() - Setup the secondary sequencer
  * @se:		Pointer to the concerned serial engine.
@@ -384,6 +407,10 @@ static int msm_serial_putc(struct udevice *dev, const char ch)
 {
 	struct msm_serial_data *priv = dev_get_priv(dev);
 
+	if (CONFIG_IS_ENABLED(MSM_GENI_SERIAL_CABLE_DETECT) &&
+	    !priv->cable_connected)
+		return 0;
+
 	writel(DEF_TX_WM, priv->base + SE_GENI_TX_WATERMARK_REG);
 	qcom_geni_serial_setup_tx(priv->base, 1);
 
@@ -565,6 +592,11 @@ static int msm_serial_probe(struct udevice *dev)
 	qcom_geni_serial_start_rx(dev);
 	qcom_geni_serial_start_tx(priv->base);
 
+	if (CONFIG_IS_ENABLED(MSM_GENI_SERIAL_CABLE_DETECT))
+		priv->cable_connected = qcom_geni_serial_is_cable_connected(priv->base);
+	else
+		priv->cable_connected = true;
+
 	return 0;
 }
 
@@ -615,6 +647,8 @@ static struct udevice init_dev = {
 #error Clocks cannot be set at early debug. Change CONFIG_BAUDRATE
 #endif
 
+static bool debug_uart_cable_connected = true;
+
 static inline void _debug_uart_init(void)
 {
 	phys_addr_t base = CONFIG_VAL(DEBUG_UART_BASE);
@@ -623,12 +657,19 @@ static inline void _debug_uart_init(void)
 	writel(DEF_RX_WM, base + SE_GENI_RX_WATERMARK_REG);
 	geni_serial_baud(base, CLK_DIV, CONFIG_BAUDRATE);
 	qcom_geni_serial_start_tx(base);
+
+	if (CONFIG_IS_ENABLED(MSM_GENI_SERIAL_CABLE_DETECT))
+		debug_uart_cable_connected = qcom_geni_serial_is_cable_connected(base);
 }
 
 static inline void _debug_uart_putc(int ch)
 {
 	phys_addr_t base = CONFIG_VAL(DEBUG_UART_BASE);
 
+	if (CONFIG_IS_ENABLED(MSM_GENI_SERIAL_CABLE_DETECT) &&
+	    !debug_uart_cable_connected)
+		return;
+
 	writel(DEF_TX_WM, base + SE_GENI_TX_WATERMARK_REG);
 	qcom_geni_serial_setup_tx(base, 1);
 	qcom_geni_serial_poll_bit(&init_dev, SE_GENI_M_IRQ_STATUS,
-- 
2.34.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.