[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