[PATCH v3 1/3] serial: Allow a serial port to be silent disabled
Simon Glass
sjg at chromium.org
Wed Nov 20 16:35:52 CET 2024
Provide a way to disable a serial port at runtime if it is known that it
will not work.
This is useful when booting from coreboot, if it does not provide info
about the serial port in its sysinfo tables. U-Boot then hangs since if
does not have the UART harware-address needed to write to the UART.
The feature is optional, since it increases code-size slightly.
Signed-off-by: Simon Glass <sjg at chromium.org>
---
(no changes since v1)
drivers/serial/Kconfig | 9 +++++++++
drivers/serial/serial-uclass.c | 19 ++++++++++++++++++-
include/serial.h | 25 +++++++++++++++++++++++++
3 files changed, 52 insertions(+), 1 deletion(-)
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 8b27ad9a77e..d6541b289a0 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -99,6 +99,15 @@ config VPL_SERIAL_PRESENT
This option enables the full UART in TPL, so if is it disabled,
the full UART driver will be omitted, thus saving space.
+config SERIAL_CAN_DISABLE
+ bool "Serial ports can be silently disabled"
+ help
+ Enable this to allow serial ports to be disabled at runtime. This is
+ used when there is a UART driver available, but it cannot operate,
+ perhaps because it does not have the required hardware information.
+ An example is when coreboot boots into U-Boot but does not provide the
+ serial information in its sysinfo tables
+
config CONS_INDEX
int "UART used for console"
depends on SPECIFY_CONSOLE_INDEX
diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c
index a08678dde4e..7f1914e21ed 100644
--- a/drivers/serial/serial-uclass.c
+++ b/drivers/serial/serial-uclass.c
@@ -242,11 +242,20 @@ static void _serial_flush(struct udevice *dev)
;
}
+bool serial_is_disabled_(struct udevice *dev)
+{
+ struct serial_dev_plat *uplat = dev_get_uclass_plat(dev);
+
+ return uplat->disable;
+}
+
static void _serial_putc(struct udevice *dev, char ch)
{
struct dm_serial_ops *ops = serial_get_ops(dev);
int err;
+ if (serial_is_disabled(dev))
+ return;
if (ch == '\n')
_serial_putc(dev, '\r');
@@ -262,6 +271,8 @@ static int __serial_puts(struct udevice *dev, const char *str, size_t len)
{
struct dm_serial_ops *ops = serial_get_ops(dev);
+ if (serial_is_disabled(dev))
+ return 0;
do {
ssize_t written = ops->puts(dev, str, len);
@@ -306,6 +317,8 @@ static int __serial_getc(struct udevice *dev)
struct dm_serial_ops *ops = serial_get_ops(dev);
int err;
+ if (serial_is_disabled(dev))
+ return 0;
do {
err = ops->getc(dev);
if (err == -EAGAIN)
@@ -319,6 +332,9 @@ static int __serial_tstc(struct udevice *dev)
{
struct dm_serial_ops *ops = serial_get_ops(dev);
+ if (serial_is_disabled(dev))
+ return 0;
+
if (ops->pending)
return ops->pending(dev, true);
@@ -568,7 +584,7 @@ static int serial_post_probe(struct udevice *dev)
int ret;
/* Set the baud rate */
- if (ops->setbrg) {
+ if (!serial_is_disabled(dev) && ops->setbrg) {
ret = ops->setbrg(dev, gd->baudrate);
if (ret)
return ret;
@@ -611,6 +627,7 @@ UCLASS_DRIVER(serial) = {
.flags = DM_UC_FLAG_SEQ_ALIAS,
.post_probe = serial_post_probe,
.pre_remove = serial_pre_remove,
+ .per_device_plat_auto = sizeof(struct serial_dev_plat),
.per_device_auto = sizeof(struct serial_dev_priv),
};
#endif
diff --git a/include/serial.h b/include/serial.h
index e5f6d984d28..f62dc6e9ba4 100644
--- a/include/serial.h
+++ b/include/serial.h
@@ -287,6 +287,19 @@ struct dm_serial_ops {
int (*getinfo)(struct udevice *dev, struct serial_device_info *info);
};
+/**
+ * struct serial_dev_plat - plat data used by the uclass
+ *
+ * @disable: true to disable probing and using this device. This is used when
+ * there is a UART driver available, but it cannot operate, perhaps because it
+ * does not have the required hardware information. An example is when coreboot
+ * boots into U-Boot but does not provide the serial information in its sysinfo
+ * tables
+ */
+struct serial_dev_plat {
+ bool disable;
+};
+
/**
* struct serial_dev_priv - information about a device used by the uclass
*
@@ -309,6 +322,18 @@ struct serial_dev_priv {
/* Access the serial operations for a device */
#define serial_get_ops(dev) ((struct dm_serial_ops *)(dev)->driver->ops)
+bool serial_is_disabled_(struct udevice *dev);
+
+/* Provide a way to silently disable the port */
+static inline bool serial_is_disabled(struct udevice *dev)
+{
+#ifdef CONFIG_SERIAL_CAN_DISABLE
+ return serial_is_disabled_(dev);
+#else
+ return false;
+#endif
+}
+
/**
* serial_getconfig() - Get the uart configuration
* (parity, 5/6/7/8 bits word length, stop bits)
--
2.34.1
More information about the U-Boot
mailing list