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
prev parent reply other threads:[~2026-09-05 10:44 UTC|newest]
Thread overview: 6+ 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-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-05 10:29 ` Changhuang Liang [this message]
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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox