From: Changhuang Liang <changhuang.liang@starfivetech.com>
To: Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
Jonathan Corbet <corbet@lwn.net>, Joel Stanley <joel@jms.id.au>,
Andrew Jeffery <andrew@codeconstruct.com.au>,
Chia-Wei Wang <chiawei_wang@aspeedtech.com>,
Oskar Senft <osk@google.com>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Changhuang Liang <changhuang.liang@starfivetech.com>,
Shuah Khan <skhan@linuxfoundation.org>,
Jani Nikula <jani.nikula@intel.com>,
Vitaly Lubart <lubvital@gmail.com>,
Hanjun Guo <guohanjun@huawei.com>,
Andrew Morton <akpm@linux-foundation.org>,
Alexander Usyskin <alexander.usyskin@intel.com>,
Jason Gunthorpe <jgg@ziepe.ca>, Breno Leitao <leitao@debian.org>,
Philipp Zabel <p.zabel@pengutronix.de>,
James Morse <james.morse@arm.com>,
Paolo Abeni <pabeni@redhat.com>,
Stephen Hemminger <stephen@networkplumber.org>,
Dave Penkler <dpenkler@gmail.com>,
Jakub Kicinski <kuba@kernel.org>,
Jonathan Cameron <jic23@kernel.org>,
Dan Williams <djbw@kernel.org>,
Mukesh Rathor <mrathor@linux.microsoft.com>,
Vladimir Oltean <vladimir.oltean@nxp.com>,
Alexandra Winter <wintera@linux.ibm.com>,
Julian Braha <julianbraha@gmail.com>,
Karthikeyan KS <karthiproffesional@gmail.com>,
Pengpeng Hou <pengpeng@iscas.ac.cn>,
openbmc@lists.ozlabs.org, linux-kernel@vger.kernel.org,
devicetree@vger.kernel.org, linux-doc@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-aspeed@lists.ozlabs.org
Subject: [PATCH v2 4/4] uart-routing: Add UART Routing driver for StarFive JHB100 SoC
Date: Sat, 5 Sep 2026 03:29:01 -0700 [thread overview]
Message-ID: <20260905102901.126035-5-changhuang.liang@starfivetech.com> (raw)
In-Reply-To: <20260905102901.126035-1-changhuang.liang@starfivetech.com>
Add driver support for JHB100 UART Routing control, allowing runtime
configuration of RX muxes between UART controllers and I/O pins.
A sysfs interface is provided for easy checking and updating of routing
paths.
Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
---
.../sysfs-driver-starfive-uart-routing | 45 ++++
MAINTAINERS | 8 +
drivers/uart-routing/Kconfig | 13 ++
drivers/uart-routing/Makefile | 1 +
drivers/uart-routing/starfive-uart-routing.c | 192 ++++++++++++++++++
5 files changed, 259 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-driver-starfive-uart-routing
create mode 100644 drivers/uart-routing/starfive-uart-routing.c
diff --git a/Documentation/ABI/testing/sysfs-driver-starfive-uart-routing b/Documentation/ABI/testing/sysfs-driver-starfive-uart-routing
new file mode 100644
index 000000000000..737afdf428bc
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-starfive-uart-routing
@@ -0,0 +1,45 @@
+What: /sys/bus/platform/drivers/starfive-uart-routing/\*/uart\*
+Date: August 2026
+Contact: Changhuang Liang <changhuang.liang@starfivetech.com>
+Description: Selects the RX source of the UARTx device.
+
+ When read, each file shows the list of available options with currently
+ selected option marked by brackets "[]". The list of available options
+ depends on the selected file.
+
+ e.g.
+ cat /sys/bus/platform/drivers/starfive-uart-routing/\*.uart-routing/uart1
+ io0 [io1] io2 io3 io4 io5 io6 io7 io8 io9 io10 io11 io12 io13 io14 uart0 uart1
+ uart2 uart3 uart4 uart5 uart6 uart7 uart8 uart9 uart10 uart11 uart12 uart13 uart14
+
+ In this case, UART1 gets its input from IO1 (physical serial port 1).
+
+ To switch the RX source of UART1 to UART2, write the desired source to the file:
+ echo uart2 > /sys/bus/platform/drivers/starfive-uart-routing/*.uart-routing/uart1
+
+ This indicates that UART1 now receives its input from UART2.
+
+Users: OpenBMC. Proposed changes should be mailed to
+ openbmc@lists.ozlabs.org
+
+What: /sys/bus/platform/drivers/starfive-uart-routing/\*/io\*
+Date: August 2026
+Contact: Changhuang Liang <changhuang.liang@starfivetech.com>
+Description: Selects the RX source of IOx serial port. The current selection
+ will be marked by brackets "[]". The list of available options
+ depends on the selected file.
+
+ e.g.
+ cat /sys/bus/platform/drivers/starfive-uart-routing/\*.uart-routing/io9
+ uart0 uart1 uart2 uart3 uart4 uart5 uart6 uart7 uart8 [uart9] uart10 uart11 uart12
+ uart13 uart14 io0 io1 io2 io3 io4 io5 io6 io7 io8 io9 io10 io11 io12 io13 io14
+
+ In this case, IO9 (physical serial port 9) gets its input from UART9.
+
+ To switch the RX source of IO9 to UART10, write the desired source to the file:
+ echo uart10 > /sys/bus/platform/drivers/starfive-uart-routing/*.uart-routing/io9
+
+ This indicates that IO9 now receives its input from UART10.
+
+Users: OpenBMC. Proposed changes should be mailed to
+ openbmc@lists.ozlabs.org
diff --git a/MAINTAINERS b/MAINTAINERS
index ad6706c18f37..16c2fa9aff57 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -26115,6 +26115,14 @@ M: Changhuang Liang <changhuang.liang@starfivetech.com>
S: Maintained
F: Documentation/devicetree/bindings/soc/starfive/starfive,jhb100-syscon.yaml
+STARFIVE UART ROUTING DRIVER
+M: Changhuang Liang <changhuang.liang@starfivetech.com>
+L: openbmc@lists.ozlabs.org (moderated for non-subscribers)
+S: Maintained
+F: Documentation/ABI/testing/sysfs-driver-starfive-uart-routing
+F: Documentation/devicetree/bindings/uart-routing/starfive,uart-routing.yaml
+F: drivers/uart-routing/starfive-uart-routing.c
+
STATIC BRANCH/CALL
M: Peter Zijlstra <peterz@infradead.org>
M: Josh Poimboeuf <jpoimboe@kernel.org>
diff --git a/drivers/uart-routing/Kconfig b/drivers/uart-routing/Kconfig
index b67c2a6de74c..13b2424d47c7 100644
--- a/drivers/uart-routing/Kconfig
+++ b/drivers/uart-routing/Kconfig
@@ -28,4 +28,17 @@ config ASPEED_UART_ROUTING
If M is selected, the module will be called
aspeed-uart-routing.
+config STARFIVE_UART_ROUTING
+ tristate "StarFive uart routing control"
+ depends on ARCH_STARFIVE || COMPILE_TEST
+ select UART_ROUTING
+ select REGMAP_MMIO
+ help
+ Provides a driver to control the UART routing paths, allowing
+ users to perform runtime configuration of the RX muxes among
+ the UART controllers and I/O pins.
+
+ If M is selected, the module will be called
+ starfive-uart-routing.
+
endmenu
diff --git a/drivers/uart-routing/Makefile b/drivers/uart-routing/Makefile
index 226980c639a4..59d9b65c2273 100644
--- a/drivers/uart-routing/Makefile
+++ b/drivers/uart-routing/Makefile
@@ -2,3 +2,4 @@
obj-$(CONFIG_UART_ROUTING) += uart-routing.o
obj-$(CONFIG_ASPEED_UART_ROUTING) += aspeed-uart-routing.o
+obj-$(CONFIG_STARFIVE_UART_ROUTING) += starfive-uart-routing.o
diff --git a/drivers/uart-routing/starfive-uart-routing.c b/drivers/uart-routing/starfive-uart-routing.c
new file mode 100644
index 000000000000..3bd83ca5a258
--- /dev/null
+++ b/drivers/uart-routing/starfive-uart-routing.c
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * StarFive JHB100 UART Routing driver
+ *
+ * Copyright (C) 2026 StarFive Technology Co., Ltd
+ */
+
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/sysfs.h>
+
+#include "uart-routing.h"
+
+/* One selector register per channel, holding the IO and UART RX mux. */
+#define JHB100_ROUTING_SEL(ch) ((ch) * 0x04)
+#define JHB100_ROUTING_IO_SHIFT 0
+#define JHB100_ROUTING_UART_SHIFT 8
+#define JHB100_ROUTING_MASK GENMASK(4, 0)
+
+#define JHB100_UART_PORTS 15 /* UART0-UART14 */
+
+#define JHB100_IO_TARGETS \
+ "io0", "io1", "io2", "io3", "io4", \
+ "io5", "io6", "io7", "io8", "io9", \
+ "io10", "io11", "io12", "io13", "io14"
+
+#define JHB100_UART_TARGETS \
+ "uart0", "uart1", "uart2", "uart3", "uart4", \
+ "uart5", "uart6", "uart7", "uart8", "uart9", \
+ "uart10", "uart11", "uart12", "uart13", "uart14"
+
+/*
+ * The two mux fields of a channel index the same target list, but starting
+ * from a different end of it: field value 0 selects IO0 for the RX mux of a
+ * UART, and UART0 for the RX mux of an IO pin.
+ */
+static const char *const jhb100_uart_rx_options[] = {
+ JHB100_IO_TARGETS,
+ JHB100_UART_TARGETS,
+ NULL,
+};
+
+static const char *const jhb100_io_rx_options[] = {
+ JHB100_UART_TARGETS,
+ JHB100_IO_TARGETS,
+ NULL,
+};
+
+#define JHB100_UART_SELECTOR(_ch) \
+ UART_ROUTING_SELECTOR(jhb100_uart##_ch##_sel, uart##_ch, \
+ JHB100_ROUTING_SEL(_ch), \
+ JHB100_ROUTING_UART_SHIFT, \
+ JHB100_ROUTING_MASK, \
+ jhb100_uart_rx_options)
+
+#define JHB100_IO_SELECTOR(_ch) \
+ UART_ROUTING_SELECTOR(jhb100_io##_ch##_sel, io##_ch, \
+ JHB100_ROUTING_SEL(_ch), \
+ JHB100_ROUTING_IO_SHIFT, \
+ JHB100_ROUTING_MASK, \
+ jhb100_io_rx_options)
+
+/* RX source of UART0-UART14 */
+JHB100_UART_SELECTOR(0);
+JHB100_UART_SELECTOR(1);
+JHB100_UART_SELECTOR(2);
+JHB100_UART_SELECTOR(3);
+JHB100_UART_SELECTOR(4);
+JHB100_UART_SELECTOR(5);
+JHB100_UART_SELECTOR(6);
+JHB100_UART_SELECTOR(7);
+JHB100_UART_SELECTOR(8);
+JHB100_UART_SELECTOR(9);
+JHB100_UART_SELECTOR(10);
+JHB100_UART_SELECTOR(11);
+JHB100_UART_SELECTOR(12);
+JHB100_UART_SELECTOR(13);
+JHB100_UART_SELECTOR(14);
+
+/* RX source of IO0-IO14 */
+JHB100_IO_SELECTOR(0);
+JHB100_IO_SELECTOR(1);
+JHB100_IO_SELECTOR(2);
+JHB100_IO_SELECTOR(3);
+JHB100_IO_SELECTOR(4);
+JHB100_IO_SELECTOR(5);
+JHB100_IO_SELECTOR(6);
+JHB100_IO_SELECTOR(7);
+JHB100_IO_SELECTOR(8);
+JHB100_IO_SELECTOR(9);
+JHB100_IO_SELECTOR(10);
+JHB100_IO_SELECTOR(11);
+JHB100_IO_SELECTOR(12);
+JHB100_IO_SELECTOR(13);
+JHB100_IO_SELECTOR(14);
+
+static struct attribute *jhb100_uart_routing_attrs[] = {
+ UART_ROUTING_SELECTOR_ATTR(jhb100_uart0_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_uart1_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_uart2_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_uart3_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_uart4_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_uart5_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_uart6_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_uart7_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_uart8_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_uart9_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_uart10_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_uart11_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_uart12_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_uart13_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_uart14_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_io0_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_io1_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_io2_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_io3_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_io4_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_io5_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_io6_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_io7_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_io8_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_io9_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_io10_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_io11_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_io12_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_io13_sel),
+ UART_ROUTING_SELECTOR_ATTR(jhb100_io14_sel),
+ NULL,
+};
+
+static const struct attribute_group jhb100_uart_routing_attr_group = {
+ .attrs = jhb100_uart_routing_attrs,
+};
+
+static const struct regmap_config jhb100_uart_routing_regmap_cfg = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = JHB100_ROUTING_SEL(JHB100_UART_PORTS - 1),
+};
+
+static int starfive_uart_routing_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct reset_control *rst;
+ void __iomem *reg_base;
+ struct regmap *regmap;
+
+ reg_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(reg_base))
+ return dev_err_probe(dev, PTR_ERR(reg_base),
+ "Unable to map IO resources\n");
+
+ rst = devm_reset_control_get_exclusive_deasserted(dev, NULL);
+ if (IS_ERR(rst))
+ return dev_err_probe(dev, PTR_ERR(rst),
+ "Unable to get and deassert reset control\n");
+
+ regmap = devm_regmap_init_mmio(dev, reg_base,
+ &jhb100_uart_routing_regmap_cfg);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap),
+ "Unable to init regmap\n");
+
+ return devm_uart_routing_register(dev, regmap,
+ &jhb100_uart_routing_attr_group);
+}
+
+static const struct of_device_id starfive_uart_routing_match[] = {
+ { .compatible = "starfive,jhb100-uart-routing" },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, starfive_uart_routing_match);
+
+static struct platform_driver starfive_uart_routing_driver = {
+ .probe = starfive_uart_routing_probe,
+ .driver = {
+ .name = "starfive-uart-routing",
+ .of_match_table = starfive_uart_routing_match,
+ },
+};
+
+module_platform_driver(starfive_uart_routing_driver);
+
+MODULE_AUTHOR("Changhuang Liang <changhuang.liang@starfivetech.com>");
+MODULE_DESCRIPTION("StarFive JHB100 UART Routing driver");
+MODULE_LICENSE("GPL");
--
2.25.1
next prev parent reply other threads:[~2026-09-05 10:44 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-05 10:28 [PATCH v2 0/4] Add support for StarFive JHB100 UART Routing Changhuang Liang
2026-09-05 10:28 ` [PATCH v2 1/4] uart-routing: Add common UART routing framework Changhuang Liang
2026-09-05 12:30 ` Julian Braha
2026-09-07 1:19 ` Changhuang Liang
2026-09-05 10:28 ` [PATCH v2 2/4] soc: aspeed: Move UART routing driver to drivers/uart-routing Changhuang Liang
2026-09-05 10:29 ` [PATCH v2 3/4] dt-bindings: uart-routing: Add binding for StarFive JHB100 UART routing Changhuang Liang
2026-09-17 22:26 ` Rob Herring
2026-09-17 22:27 ` Rob Herring
2026-09-05 10:29 ` Changhuang Liang [this message]
2026-09-06 5:12 ` [PATCH v2 4/4] uart-routing: Add UART Routing driver for StarFive JHB100 SoC Randy Dunlap
2026-09-07 1:24 ` Changhuang Liang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260905102901.126035-5-changhuang.liang@starfivetech.com \
--to=changhuang.liang@starfivetech.com \
--cc=akpm@linux-foundation.org \
--cc=alexander.usyskin@intel.com \
--cc=andrew@codeconstruct.com.au \
--cc=chiawei_wang@aspeedtech.com \
--cc=conor+dt@kernel.org \
--cc=corbet@lwn.net \
--cc=devicetree@vger.kernel.org \
--cc=djbw@kernel.org \
--cc=dpenkler@gmail.com \
--cc=gregkh@linuxfoundation.org \
--cc=guohanjun@huawei.com \
--cc=james.morse@arm.com \
--cc=jani.nikula@intel.com \
--cc=jgg@ziepe.ca \
--cc=jic23@kernel.org \
--cc=joel@jms.id.au \
--cc=julianbraha@gmail.com \
--cc=karthiproffesional@gmail.com \
--cc=krzk+dt@kernel.org \
--cc=kuba@kernel.org \
--cc=leitao@debian.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-aspeed@lists.ozlabs.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=lubvital@gmail.com \
--cc=mrathor@linux.microsoft.com \
--cc=openbmc@lists.ozlabs.org \
--cc=osk@google.com \
--cc=p.zabel@pengutronix.de \
--cc=pabeni@redhat.com \
--cc=pengpeng@iscas.ac.cn \
--cc=robh@kernel.org \
--cc=skhan@linuxfoundation.org \
--cc=stephen@networkplumber.org \
--cc=vladimir.oltean@nxp.com \
--cc=wintera@linux.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.