[U-Boot] [PATCH] serial: bcm283x_mu: Detect disabled serial device

Alexander Graf agraf at suse.de
Fri Jul 29 23:49:41 CEST 2016


On the raspberry pi, you can disable the serial port to gain dynamic frequency
scaling which can get handy at times.

However, in such a configuration the serial controller gets its rx queue filled
up with zero bytes which then happily get transmitted on to whoever calls
getc() today.

This patch adds detection logic for that case and disables the mini uart if it
sends a zero byte during probe. That way we can leave the driver enabled in the
tree and can determine during runtime whether serial is usable or not.

Signed-off-by: Alexander Graf <agraf at suse.de>
---
 drivers/serial/serial_bcm283x_mu.c | 48 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/drivers/serial/serial_bcm283x_mu.c b/drivers/serial/serial_bcm283x_mu.c
index 7357bbf..ff077ec 100644
--- a/drivers/serial/serial_bcm283x_mu.c
+++ b/drivers/serial/serial_bcm283x_mu.c
@@ -48,8 +48,14 @@ struct bcm283x_mu_regs {
 
 struct bcm283x_mu_priv {
 	struct bcm283x_mu_regs *regs;
+	bool beyond_first_byte;
+	bool within_first_byte;
+	uint8_t first_byte;
+	bool broken;
 };
 
+static int bcm283x_mu_serial_getc(struct udevice *dev);
+
 static int bcm283x_mu_serial_setbrg(struct udevice *dev, int baudrate)
 {
 	struct bcm283x_mu_serial_platdata *plat = dev_get_platdata(dev);
@@ -75,6 +81,13 @@ static int bcm283x_mu_serial_probe(struct udevice *dev)
 
 	priv->regs = (struct bcm283x_mu_regs *)plat->base;
 
+	/*
+	 * We get greeted by a zero byte? That means the serial console really
+	 * is disabled and we better ignore it.
+	 */
+	if (!bcm283x_mu_serial_getc(dev))
+		priv->broken = true;
+
 	return 0;
 }
 
@@ -84,6 +97,16 @@ static int bcm283x_mu_serial_getc(struct udevice *dev)
 	struct bcm283x_mu_regs *regs = priv->regs;
 	u32 data;
 
+	if (priv->broken)
+		return -EAGAIN;
+
+	if (priv->within_first_byte) {
+		priv->within_first_byte = false;
+		priv->beyond_first_byte = true;
+
+		return (int)priv->first_byte;
+	}
+
 	/* Wait until there is data in the FIFO */
 	if (!(readl(&regs->lsr) & BCM283X_MU_LSR_RX_READY))
 		return -EAGAIN;
@@ -98,6 +121,9 @@ static int bcm283x_mu_serial_putc(struct udevice *dev, const char data)
 	struct bcm283x_mu_priv *priv = dev_get_priv(dev);
 	struct bcm283x_mu_regs *regs = priv->regs;
 
+	if (priv->broken)
+		return 0;
+
 	/* Wait until there is space in the FIFO */
 	if (!(readl(&regs->lsr) & BCM283X_MU_LSR_TX_EMPTY))
 		return -EAGAIN;
@@ -116,8 +142,30 @@ static int bcm283x_mu_serial_pending(struct udevice *dev, bool input)
 
 	if (input) {
 		WATCHDOG_RESET();
+
+		if (priv->broken)
+			return 0;
+
+		if (priv->within_first_byte)
+			return 1;
+
+		if (!priv->beyond_first_byte &&
+		    (lsr & BCM283X_MU_LSR_RX_READY)) {
+			priv->first_byte = bcm283x_mu_serial_getc(dev);
+			priv->within_first_byte = true;
+
+			if (!priv->first_byte) {
+				/* First byte was zero, serial is broken */
+				priv->broken = true;
+				return 0;
+			}
+		}
+
 		return (lsr & BCM283X_MU_LSR_RX_READY) ? 1 : 0;
 	} else {
+		if (priv->broken)
+			return 0;
+
 		return (lsr & BCM283X_MU_LSR_TX_IDLE) ? 0 : 1;
 	}
 }
-- 
1.8.5.6



More information about the U-Boot mailing list