From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 34210C624D3 for ; Sat, 5 Sep 2026 12:31:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Transfer-Encoding: Content-Type:In-Reply-To:From:References:Cc:To:Subject:MIME-Version:Date: Message-ID:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=nF28nbshD2BPWEClB77TT3QHqkwal9Tdd0g3hy+SqKw=; b=Ri9o5wzOWbSCEXK9ytb/isHS+k X+FBiLXX90LEjDO5t0Cf4XyAPjjBRGizFEkCI6+RLpqv/3w9fMQejrtJWe2NST3mtDMjula1A/fl3 TstTtINKMjI3EkmwNHyfNTRBOOtM6Sf4QgcNwj5rt/WoNotfiFDP5m+L5qbsOvjvT+chJ1CSgUmDD CKDhPyEFJFau4M9eLdbSh8awo/RUGtIDQ9idENb8Owiyqb1n7HxytW7RG41ax1YW11QAbDCIk43Zi p5mg56Mxy3smQhDk20rlEYGYZzROLS95Ej748QA5CojFNViUHDIAQPqIeajXucqTtOIyrb94070kD ce8VBZ9w==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.99.1 #2 (Red Hat Linux)) id 1x2pXy-00000004435-10dV; Sat, 05 Sep 2026 12:31:02 +0000 Received: from mail-wr1-x430.google.com ([2a00:1450:4864:20::430]) by bombadil.infradead.org with esmtps (Exim 4.99.1 #2 (Red Hat Linux)) id 1x2pXu-0000000442f-2uNX for linux-arm-kernel@lists.infradead.org; Sat, 05 Sep 2026 12:31:00 +0000 Received: by mail-wr1-x430.google.com with SMTP id ffacd0b85a97d-482e4998d28so1447810f8f.2 for ; Sat, 05 Sep 2026 05:30:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1788611455; x=1789216255; darn=lists.infradead.org; h=content-transfer-encoding:content-type:in-reply-to:from :content-language:references:cc:to:subject:user-agent:mime-version :date:message-id:sender:from:to:cc:subject:date:message-id:reply-to :content-type; bh=nF28nbshD2BPWEClB77TT3QHqkwal9Tdd0g3hy+SqKw=; b=Hb3d2m5W4qMu3gcByGsCVq87r2A5a8sq5IRifWsa1d3SyZv/u/h8Hme01OUAf1ONmB AVU1w5yTgR1aymRLSHtHhBo1hf80Gy3dG2pP1JzhyC0J/1IlvFYk04XF8nt8AzPpgYay 5FInBEkVoTVGwmqeMtpYGdC2KElZH8VEUVV2SLJl8/gpn9lJphfMpk3rQ6X/I7aap7bQ UeUoqXw+sclx6UWHrVRY5C7TON3y146LhyvacElF9C9btlVt/u8EH3qSX6eXoknZfZik 3FtbUc/IlZZtuhhhXjr0KP3ev97DXiij87V9x6cJQJaI0k9hrhbdqpzopIrV90NODz6s sxEg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788611455; x=1789216255; h=content-transfer-encoding:content-type:in-reply-to:from :content-language:references:cc:to:subject:user-agent:mime-version :date:message-id:sender:x-gm-gg:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to:content-type; bh=nF28nbshD2BPWEClB77TT3QHqkwal9Tdd0g3hy+SqKw=; b=Nv1+g2M9VnchfxgtYv7yhwf6fiEEhYvpZaBrwRQYOtTXu05Vmo7dyjrbJV11mudhzx 46/OBWyrLeGAtGdSNn1s4k6Gs1422sMmNdCSw3sphyu0odfpVyO7KS6YR5+E+5xZMm8Z hVLQITSdrfZ4GztPC1o1c2SCt+kqftI3AyGeQs7LmQYUxfvoyYSPbFR46+H33bAPWerB sLqvA5yb4E75jn5iqyh3p8991YtlnZ+db7Y2lFEoStCENbDBYn5K8Jb65MiTPzriELyN 8tRQ3qs4Dz51SEkmIt5BHeC3mF6g7PLnaB6ng+QcllzSmb/nJJB/stY3+Y/NaRac4LxU g5FA== X-Forwarded-Encrypted: i=1; AKwUvBxjGjd6SMoWKZLPk0gGjgAsTJastGkVIygE2NnM1thz+/UfxOqXO51uKIoyY/zcW9qhdAj77PJA4ayJilbmyayo@lists.infradead.org X-Gm-Message-State: AFuF++kRNMocSV3ZW+/EFrAGnmadkTGgoDjSXxXleCdplJw3eWpAF3Yh wJUxMPumfK/D1r4FcNyaGYhqmYvhDVCF43vAY5YT5TAjQ2LQUcXSq5Ja X-Gm-Gg: AYBFou3qmJvOfxd/m6FlQ8+9YaPGbU169uLjYBulToeI7qqOkvDqvqUGDHjVVdZCdk8 7MQasyOZmibEEUu7DliSpUgG0rrxFl/qNeInOOQAs6x0J7sMq6rsbv48x3wwE3iO1ADDOYWkTbf sEKSKjkuBE+PqFgxFMNf7+FEIBaSpLkVlkZDempqvDz/PGFWJBkXCF3vgVcS5rDDI4I7bmKFIC8 wBMbHOA2peyL61bbpcB9/LU1PIMQZLuW4pxce3ivLvDEPkEpMX2NSzC5mxW9fsD3YN7/YB63NKP a6eivvq3tM3hCsY72OlvrLz9sbKJM7DeT/CjeoAYdBbWTiwCOs78ky0F1M7UlkRZzBEte6OXRks V4Kbkg7Cpphww7tKCBQCwrd28/IEo/6cHjYeEHwxmMKA53uYYzPzEdV1qNzDLezDooO8Q9TWjTs +J/suJCsilYX7+yJIBKLKAW6FRQ9DbvW8dil/jB9RATBs5xXDiUbydovDTAk8qmRORGEjsBNX7e 2ENFiP8RlV9R1avPC3egjGahwV47zDWYZ/65phGLBtka2/P2TmZYdRO X-Received: by 2002:a05:600c:1d08:b0:49b:96a0:5c00 with SMTP id 5b1f17b1804b1-49cf825168cmr134783585e9.13.1788611455009; Sat, 05 Sep 2026 05:30:55 -0700 (PDT) Received: from [10.128.10.232] (195-23-151-163.net.novis.pt. [195.23.151.163]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-485885be01bsm12862413f8f.31.2026.09.05.05.30.52 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 05 Sep 2026 05:30:54 -0700 (PDT) Message-ID: <1a21d17b-686a-4efe-9d47-fb8a9e826b39@gmail.com> Date: Sat, 5 Sep 2026 13:30:50 +0100 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [PATCH v2 1/4] uart-routing: Add common UART routing framework To: Changhuang Liang , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Corbet , Joel Stanley , Andrew Jeffery , Chia-Wei Wang , Oskar Senft , Greg Kroah-Hartman Cc: Shuah Khan , Jani Nikula , Vitaly Lubart , Hanjun Guo , Andrew Morton , Alexander Usyskin , Jason Gunthorpe , Breno Leitao , Philipp Zabel , James Morse , Paolo Abeni , Stephen Hemminger , Dave Penkler , Jakub Kicinski , Jonathan Cameron , Dan Williams , Mukesh Rathor , Vladimir Oltean , Alexandra Winter , Karthikeyan KS , Pengpeng Hou , 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 References: <20260905102901.126035-1-changhuang.liang@starfivetech.com> <20260905102901.126035-2-changhuang.liang@starfivetech.com> Content-Language: en-US From: Julian Braha In-Reply-To: <20260905102901.126035-2-changhuang.liang@starfivetech.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.9.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20260905_053058_803047_3B7E727B X-CRM114-Status: GOOD ( 47.03 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org 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 > --- > 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 > + > +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 > +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 > R: Zhihao Cheng > 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