From: Julian Braha <julianbraha@gmail.com>
To: Changhuang Liang <changhuang.liang@starfivetech.com>,
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: 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>,
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: Re: [PATCH v2 1/4] uart-routing: Add common UART routing framework
Date: Sat, 5 Sep 2026 13:30:50 +0100 [thread overview]
Message-ID: <1a21d17b-686a-4efe-9d47-fb8a9e826b39@gmail.com> (raw)
In-Reply-To: <20260905102901.126035-2-changhuang.liang@starfivetech.com>
On 9/5/26 11:28, Changhuang Liang wrote:
> Several SoCs contain a serial crossbar, usually called UART routing,
> that lets the RX line of any on-chip UART controller or physical serial
> port be fed from any other endpoint. The Aspeed AST2400/2500/2600 and
> the StarFive JHB100 both have one, and both expose it through the same
> user space interface: one sysfs file per endpoint, listing the routing
> targets with the current one in square brackets.
>
> The two drivers implementing that interface duplicate the whole sysfs
> plumbing and only really differ in the description of their register
> layout, so factor the common part out into a framework.
>
> An SoC driver now only describes each mux with a
> struct uart_routing_selector - register offset, bit position, field mask
> and the array of routing target names indexed by the raw field value -
> gathers them in an attribute group and hands the group and a regmap to
> devm_uart_routing_register(). The framework validates the description,
> creates the files and implements the show()/store() handlers.
>
> The framework keeps its state in a devres node rather than in the device
> drvdata, so drivers stay free to use dev_set_drvdata() for their own
> purposes, and the sysfs files are removed by devres, so drivers do not
> need a remove() callback for them.
>
> Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
> ---
> Documentation/driver-api/index.rst | 1 +
> Documentation/driver-api/uart-routing.rst | 145 ++++++++++++++++
> MAINTAINERS | 7 +
> drivers/Kconfig | 2 +
> drivers/Makefile | 1 +
> drivers/uart-routing/Kconfig | 16 ++
> drivers/uart-routing/Makefile | 2 +
> drivers/uart-routing/uart-routing.c | 200 ++++++++++++++++++++++
> drivers/uart-routing/uart-routing.h | 84 +++++++++
> 9 files changed, 458 insertions(+)
> create mode 100644 Documentation/driver-api/uart-routing.rst
> create mode 100644 drivers/uart-routing/Kconfig
> create mode 100644 drivers/uart-routing/Makefile
> create mode 100644 drivers/uart-routing/uart-routing.c
> create mode 100644 drivers/uart-routing/uart-routing.h
>
> diff --git a/Documentation/driver-api/index.rst b/Documentation/driver-api/index.rst
> index 6601a258690f..2a0f375cd206 100644
> --- a/Documentation/driver-api/index.rst
> +++ b/Documentation/driver-api/index.rst
> @@ -146,6 +146,7 @@ Subsystem-specific APIs
> tee
> thermal/index
> tty/index
> + uart-routing
> wbrf
> wmi
> xilinx/index
> diff --git a/Documentation/driver-api/uart-routing.rst b/Documentation/driver-api/uart-routing.rst
> new file mode 100644
> index 000000000000..67bb84958977
> --- /dev/null
> +++ b/Documentation/driver-api/uart-routing.rst
> @@ -0,0 +1,145 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +======================
> +UART routing framework
> +======================
> +
> +:Author: Changhuang Liang <changhuang.liang@starfivetech.com>
> +
> +Overview
> +========
> +
> +Several SoCs contain a serial crossbar, usually called *UART routing*, that
> +sits between the on-chip UART controllers and the physical serial ports
> +exposed on the package pins. The crossbar lets the RX line of any endpoint be
> +fed from any other endpoint, which makes it possible to, for example, snoop
> +the traffic of a host serial console, or to loop two on-chip UARTs back into
> +each other without any external wiring.
> +
> +Two endpoint families are involved:
> +
> +``uartN``
> + the RX line of the on-chip UART controller number N.
> +
> +``ioN``
> + the RX line of the physical serial port number N.
> +
> +The crossbar is programmed through bit fields, one per endpoint, spread over
> +one or more registers. The value written into a field picks the endpoint the
> +RX line is connected to; the meaning of a given value differs from field to
> +field and from SoC to SoC.
> +
> +The framework in ``drivers/uart-routing/`` takes a static description of those
> +fields and turns it into a set of sysfs files, one per endpoint, so that SoC
> +drivers only have to describe their hardware.
> +
> +User space interface
> +====================
> +
> +Every endpoint gets one read/write file in the device directory of the
> +platform driver, named after the endpoint. Reading the file lists all the
> +routing targets the endpoint can be connected to, with the current one
> +enclosed in square brackets::
> +
> + # cat /sys/bus/platform/drivers/aspeed-uart-routing/*.uart_routing/uart1
> + [io1] io2 io3 io4 uart2 uart3 uart4 io6
> +
> +Writing one of the listed names to the file changes the routing::
> +
> + # echo uart2 > /sys/bus/platform/drivers/aspeed-uart-routing/*.uart_routing/uart1
> +
> +Writing a name that is not part of the list fails with ``-EINVAL``.
> +
> +The list is not necessarily the same for every file: it is ordered by the raw
> +value programmed into the hardware, so the first entry is the target selected
> +when the field reads back as 0. Some SoCs define fields that are wider than
> +the number of documented targets. When such a field holds a value with no
> +name attached, the read appends ``[unknown(N)]`` to the list instead of
> +bracketing one of the names.
> +
> +Fields whose name is ``reserved`` are placeholders for values the hardware
> +does not implement. They are listed so that the position of the following
> +names stays correct, and writing ``reserved`` programs a value that has no
> +defined behaviour, so do not do that.
> +
> +The exact set of files of a given SoC, together with the routing targets each
> +of them accepts, is described in the corresponding
> +``Documentation/ABI/testing/sysfs-driver-*-uart-routing`` file.
> +
> +Writing a driver
> +================
> +
> +An SoC driver describes each mux with a ``struct uart_routing_selector``,
> +defined with the ``UART_ROUTING_SELECTOR()`` helper::
> +
> + static const char *const foo_uart1_options[] = {
> + "io1", "io2", "io3", "io4", "uart2", "uart3", NULL,
> + };
> + UART_ROUTING_SELECTOR(foo_uart1_sel, uart1, FOO_MUX_REG, 16, 0x7,
> + foo_uart1_options);
> +
> +The arguments are, in order, the name of the variable to define, the name of
> +the sysfs file, the offset of the register holding the field, the position of
> +the least significant bit of the field, the field mask and the array of
> +routing targets.
> +
> +The mask is given in field coordinates, that is, it is *not* shifted by the
> +bit position: a three bit field is always described as ``0x7``, whatever its
> +position in the register is.
> +
> +The array of routing targets is indexed by the raw field value, so
> +``options[n]`` is the name of the target selected when the field holds n. It
> +has to be NULL terminated, and it may be shared between several selectors
> +that happen to have the same target order.
> +
> +The selectors are then gathered in an attribute group::
> +
> + static struct attribute *foo_uart_routing_attrs[] = {
> + UART_ROUTING_SELECTOR_ATTR(foo_uart1_sel),
> + /* ... */
> + NULL,
> + };
> +
> + static const struct attribute_group foo_uart_routing_attr_group = {
> + .attrs = foo_uart_routing_attrs,
> + };
> +
> +and handed over, along with a regmap covering the selector registers, in
> +probe()::
> +
> + static int foo_uart_routing_probe(struct platform_device *pdev)
> + {
> + struct device *dev = &pdev->dev;
> + struct regmap *regmap;
> +
> + regmap = /* ... */;
> +
> + return devm_uart_routing_register(dev, regmap,
> + &foo_uart_routing_attr_group);
> + }
> +
> +The framework validates the description at registration time and rejects
> +selectors whose target list cannot fit in the field, or whose field does not
> +fit in a 32 bit register.
> +
> +The sysfs files are created and removed by devres, so a driver does not need
> +a remove() callback for them. The framework keeps its own state in a devres
> +node rather than in the device drvdata, so drivers are free to use
> +``dev_set_drvdata()`` for their own purposes.
> +
> +Locking
> +=======
> +
> +The framework does not serialise accesses itself. The read-modify-write of a
> +selector field is done with ``regmap_update_bits()``, so concurrent writes to
> +two endpoints sharing a register are made safe by the regmap lock. Reading a
> +file always reports the current hardware state, which may have been changed
> +by another writer in between.
> +
> +API reference
> +=============
> +
> +.. kernel-doc:: drivers/uart-routing/uart-routing.h
> +
> +.. kernel-doc:: drivers/uart-routing/uart-routing.c
> + :export:
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 90919c672d4d..b7fa722755c6 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -27818,6 +27818,13 @@ F: drivers/misc/uacce/
> F: include/linux/uacce.h
> F: include/uapi/misc/uacce/
>
> +UART ROUTING FRAMEWORK
> +M: Changhuang Liang <changhuang.liang@starfivetech.com>
> +L: openbmc@lists.ozlabs.org (moderated for non-subscribers)
> +S: Maintained
> +F: Documentation/driver-api/uart-routing.rst
> +F: drivers/uart-routing/
> +
> UBI FILE SYSTEM (UBIFS)
> M: Richard Weinberger <richard@nod.at>
> R: Zhihao Cheng <chengzhihao1@huawei.com>
> diff --git a/drivers/Kconfig b/drivers/Kconfig
> index f2bed2ddeb66..cb2b5c3b22b0 100644
> --- a/drivers/Kconfig
> +++ b/drivers/Kconfig
> @@ -251,6 +251,8 @@ source "drivers/hte/Kconfig"
>
> source "drivers/cdx/Kconfig"
>
> +source "drivers/uart-routing/Kconfig"
> +
> source "drivers/resctrl/Kconfig"
>
> endmenu
> diff --git a/drivers/Makefile b/drivers/Makefile
> index 0841ea851847..fe4b11419496 100644
> --- a/drivers/Makefile
> +++ b/drivers/Makefile
> @@ -195,6 +195,7 @@ obj-$(CONFIG_DRM_ACCEL) += accel/
> obj-$(CONFIG_CDX_BUS) += cdx/
> obj-$(CONFIG_DPLL) += dpll/
> obj-y += resctrl/
> +obj-$(CONFIG_UART_ROUTING) += uart-routing/
>
> obj-$(CONFIG_DIBS) += dibs/
> obj-$(CONFIG_S390) += s390/
> diff --git a/drivers/uart-routing/Kconfig b/drivers/uart-routing/Kconfig
> new file mode 100644
> index 000000000000..a0c45a7bba47
> --- /dev/null
> +++ b/drivers/uart-routing/Kconfig
> @@ -0,0 +1,16 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +
> +menu "UART routing drivers"
> +
Configuring the kernel can be an annoying process, and on platforms that
can't use these options, this menu just appears empty, further
complicating menuconfig...
Maybe it makes sense to add a dependency to the menu like this?
'depends on ARCH_ASPEED || ARCH_STARFIVE || COMPILE_TEST'
- Julian Braha
next prev parent reply other threads:[~2026-09-05 12:30 UTC|newest]
Thread overview: 7+ 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 [this message]
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 ` [PATCH v2 4/4] uart-routing: Add UART Routing driver for StarFive JHB100 SoC Changhuang Liang
2026-09-06 5:12 ` Randy Dunlap
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=1a21d17b-686a-4efe-9d47-fb8a9e826b39@gmail.com \
--to=julianbraha@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=alexander.usyskin@intel.com \
--cc=andrew@codeconstruct.com.au \
--cc=changhuang.liang@starfivetech.com \
--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=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