* [PATCH v7 3/3] pinctrl: aspeed: Add AST2700 SoC0 support
From: Billy Tsai @ 2026-04-16 7:29 UTC (permalink / raw)
To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Joel Stanley, Andrew Jeffery, Linus Walleij, Billy Tsai,
Bartosz Golaszewski, Ryan Chen
Cc: Andrew Jeffery, devicetree, linux-arm-kernel, linux-aspeed,
linux-kernel, openbmc, linux-gpio, linux-clk
In-Reply-To: <20260416-upstream_pinctrl-v7-0-d72762253163@aspeedtech.com>
Add pinctrl support for the SoC0 instance of the ASPEED AST2700.
AST2700 consists of two interconnected SoC instances, each with its own
pinctrl register block.
The SoC0 pinctrl hardware closely follows the design found in previous
ASPEED BMC generations, allowing the driver to build upon the common
ASPEED pinctrl infrastructure.
Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
---
drivers/pinctrl/aspeed/Kconfig | 9 +
drivers/pinctrl/aspeed/Makefile | 1 +
drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc0.c | 749 ++++++++++++++++++++++++
3 files changed, 759 insertions(+)
diff --git a/drivers/pinctrl/aspeed/Kconfig b/drivers/pinctrl/aspeed/Kconfig
index 1a4e5b9ed471..f9672cca891e 100644
--- a/drivers/pinctrl/aspeed/Kconfig
+++ b/drivers/pinctrl/aspeed/Kconfig
@@ -31,3 +31,12 @@ config PINCTRL_ASPEED_G6
help
Say Y here to enable pin controller support for Aspeed's 6th
generation SoCs. GPIO is provided by a separate GPIO driver.
+
+config PINCTRL_ASPEED_G7_SOC0
+ bool "Aspeed G7 SoC pin control"
+ depends on (ARCH_ASPEED || COMPILE_TEST) && OF
+ select PINCTRL_ASPEED
+ help
+ Say Y here to enable pin controller support for the SoC0 instance
+ of Aspeed's 7th generation SoCs. GPIO is provided by a separate
+ GPIO driver.
diff --git a/drivers/pinctrl/aspeed/Makefile b/drivers/pinctrl/aspeed/Makefile
index db2a7600ae2b..0de524ca2c72 100644
--- a/drivers/pinctrl/aspeed/Makefile
+++ b/drivers/pinctrl/aspeed/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_PINCTRL_ASPEED) += pinctrl-aspeed.o pinmux-aspeed.o
obj-$(CONFIG_PINCTRL_ASPEED_G4) += pinctrl-aspeed-g4.o
obj-$(CONFIG_PINCTRL_ASPEED_G5) += pinctrl-aspeed-g5.o
obj-$(CONFIG_PINCTRL_ASPEED_G6) += pinctrl-aspeed-g6.o
+obj-$(CONFIG_PINCTRL_ASPEED_G7_SOC0) += pinctrl-aspeed-g7-soc0.o
diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc0.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc0.c
new file mode 100644
index 000000000000..35a28b677318
--- /dev/null
+++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc0.c
@@ -0,0 +1,749 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/bitops.h>
+#include <linux/bits.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include "pinctrl-aspeed.h"
+#include "pinmux-aspeed.h"
+#include "../pinctrl-utils.h"
+
+#define SCU200 0x200 /* System Reset Control #1 */
+
+#define SCU010 0x010 /* Hardware Strap Register */
+#define SCU400 0x400 /* Multi-function Pin Control #1 */
+#define SCU404 0x404 /* Multi-function Pin Control #2 */
+#define SCU408 0x408 /* Multi-function Pin Control #3 */
+#define SCU40C 0x40C /* Multi-function Pin Control #3 */
+#define SCU410 0x410 /* USB Multi-function Control Register */
+#define SCU414 0x414 /* VGA Function Control Register */
+
+#define SCU480 0x480 /* GPIO18A0 IO Control Register */
+#define SCU484 0x484 /* GPIO18A1 IO Control Register */
+#define SCU488 0x488 /* GPIO18A2 IO Control Register */
+#define SCU48C 0x48c /* GPIO18A3 IO Control Register */
+#define SCU490 0x490 /* GPIO18A4 IO Control Register */
+#define SCU494 0x494 /* GPIO18A5 IO Control Register */
+#define SCU498 0x498 /* GPIO18A6 IO Control Register */
+#define SCU49C 0x49c /* GPIO18A7 IO Control Register */
+#define SCU4A0 0x4A0 /* GPIO18B0 IO Control Register */
+#define SCU4A4 0x4A4 /* GPIO18B1 IO Control Register */
+#define SCU4A8 0x4A8 /* GPIO18B2 IO Control Register */
+#define SCU4AC 0x4AC /* GPIO18B3 IO Control Register */
+
+enum {
+ AC14,
+ AE15,
+ AD14,
+ AE14,
+ AF14,
+ AB13,
+ AB14,
+ AF15,
+ AF13,
+ AC13,
+ AD13,
+ AE13,
+ JTAG_PORT,
+ PCIERC0_PERST,
+ PCIERC1_PERST,
+ PORTA_MODE,
+ PORTA_U2,
+ PORTB_MODE,
+ PORTB_U2,
+ PORTA_U2_PHY,
+ PORTB_U2_PHY,
+ PORTA_U3,
+ PORTB_U3,
+ PORTA_U3_PHY,
+ PORTB_U3_PHY,
+};
+
+SIG_EXPR_LIST_DECL_SEMG(AC14, EMMCCLK, EMMCG1, EMMC, SIG_DESC_SET(SCU400, 0));
+SIG_EXPR_LIST_DECL_SESG(AC14, VB1CS, VB1, SIG_DESC_SET(SCU404, 0));
+PIN_DECL_2(AC14, GPIO18A0, EMMCCLK, VB1CS);
+
+SIG_EXPR_LIST_DECL_SEMG(AE15, EMMCCMD, EMMCG1, EMMC, SIG_DESC_SET(SCU400, 1));
+SIG_EXPR_LIST_DECL_SESG(AE15, VB1CK, VB1, SIG_DESC_SET(SCU404, 1));
+PIN_DECL_2(AE15, GPIO18A1, EMMCCMD, VB1CK);
+
+SIG_EXPR_LIST_DECL_SEMG(AD14, EMMCDAT0, EMMCG1, EMMC, SIG_DESC_SET(SCU400, 2));
+SIG_EXPR_LIST_DECL_SESG(AD14, VB1MOSI, VB1, SIG_DESC_SET(SCU404, 2));
+PIN_DECL_2(AD14, GPIO18A2, EMMCDAT0, VB1MOSI);
+
+SIG_EXPR_LIST_DECL_SEMG(AE14, EMMCDAT1, EMMCG4, EMMC, SIG_DESC_SET(SCU400, 3));
+SIG_EXPR_LIST_DECL_SESG(AE14, VB1MISO, VB1, SIG_DESC_SET(SCU404, 3));
+PIN_DECL_2(AE14, GPIO18A3, EMMCDAT1, VB1MISO);
+
+SIG_EXPR_LIST_DECL_SEMG(AF14, EMMCDAT2, EMMCG4, EMMC, SIG_DESC_SET(SCU400, 4));
+PIN_DECL_1(AF14, GPIO18A4, EMMCDAT2);
+
+SIG_EXPR_LIST_DECL_SEMG(AB13, EMMCDAT3, EMMCG4, EMMC, SIG_DESC_SET(SCU400, 5));
+PIN_DECL_1(AB13, GPIO18A5, EMMCDAT3);
+
+SIG_EXPR_LIST_DECL_SEMG(AB14, EMMCCDN, EMMCG1, EMMC, SIG_DESC_SET(SCU400, 6));
+SIG_EXPR_LIST_DECL_SESG(AB14, VB0CS, VB0, SIG_DESC_SET(SCU010, 17));
+PIN_DECL_2(AB14, GPIO18A6, EMMCCDN, VB0CS);
+
+SIG_EXPR_LIST_DECL_SEMG(AF15, EMMCWPN, EMMCG1, EMMC, SIG_DESC_SET(SCU400, 7));
+SIG_EXPR_LIST_DECL_SESG(AF15, VB0CK, VB0, SIG_DESC_SET(SCU010, 17));
+PIN_DECL_2(AF15, GPIO18A7, EMMCWPN, VB0CK);
+
+SIG_EXPR_LIST_DECL_SESG(AF13, TSPRSTN, TSPRSTN, SIG_DESC_SET(SCU010, 9));
+SIG_EXPR_LIST_DECL_SEMG(AF13, EMMCDAT4, EMMCG8, EMMC, SIG_DESC_SET(SCU400, 8));
+SIG_EXPR_LIST_DECL_SESG(AF13, VB0MOSI, VB0, SIG_DESC_SET(SCU010, 17));
+PIN_DECL_3(AF13, GPIO18B0, TSPRSTN, EMMCDAT4, VB0MOSI);
+
+SIG_EXPR_LIST_DECL_SESG(AC13, UFSCLKI, UFSCLKI, SIG_DESC_SET(SCU010, 19));
+SIG_EXPR_LIST_DECL_SEMG(AC13, EMMCDAT5, EMMCG8, EMMC, SIG_DESC_SET(SCU400, 9));
+SIG_EXPR_LIST_DECL_SESG(AC13, VB0MISO, VB0, SIG_DESC_SET(SCU010, 17));
+PIN_DECL_3(AC13, GPIO18B1, UFSCLKI, EMMCDAT5, VB0MISO);
+
+SIG_EXPR_LIST_DECL_SEMG(AD13, EMMCDAT6, EMMCG8, EMMC, SIG_DESC_SET(SCU400, 10));
+SIG_EXPR_LIST_DECL_SESG(AD13, DDCCLK, VGADDC, SIG_DESC_SET(SCU404, 10));
+PIN_DECL_2(AD13, GPIO18B2, EMMCDAT6, DDCCLK);
+
+SIG_EXPR_LIST_DECL_SEMG(AE13, EMMCDAT7, EMMCG8, EMMC, SIG_DESC_SET(SCU400, 11));
+SIG_EXPR_LIST_DECL_SESG(AE13, DDCDAT, VGADDC, SIG_DESC_SET(SCU404, 11));
+PIN_DECL_2(AE13, GPIO18B3, EMMCDAT7, DDCDAT);
+
+GROUP_DECL(EMMCG1, AC14, AE15, AD14);
+GROUP_DECL(EMMCG4, AC14, AE15, AD14, AE14, AF14, AB13);
+GROUP_DECL(EMMCG8, AC14, AE15, AD14, AE14, AF14, AB13, AF13, AC13, AD13, AE13);
+GROUP_DECL(EMMCWPN, AF15);
+GROUP_DECL(EMMCCDN, AB14);
+FUNC_DECL_(EMMC, "EMMCG1", "EMMCG4", "EMMCG8", "EMMCWPN", "EMMCCDN");
+
+GROUP_DECL(VB1, AC14, AE15, AD14, AE14);
+GROUP_DECL(VB0, AF15, AB14, AF13, AC13);
+FUNC_DECL_2(VB, VB1, VB0);
+
+FUNC_GROUP_DECL(TSPRSTN, AF13);
+
+FUNC_GROUP_DECL(UFSCLKI, AC13);
+
+FUNC_GROUP_DECL(VGADDC, AD13, AE13);
+
+/* JTAG Port Selection */
+#define JTAG_PORT_PSP_DESC { ASPEED_IP_SCU, SCU408, GENMASK(12, 5), 0x0, 0 }
+#define JTAG_PORT_SSP_DESC { ASPEED_IP_SCU, SCU408, GENMASK(12, 5), 0x41, 0 }
+#define JTAG_PORT_TSP_DESC { ASPEED_IP_SCU, SCU408, GENMASK(12, 5), 0x42, 0 }
+#define JTAG_PORT_DDR_DESC { ASPEED_IP_SCU, SCU408, GENMASK(12, 5), 0x43, 0 }
+#define JTAG_PORT_USB3A_DESC { ASPEED_IP_SCU, SCU408, GENMASK(12, 5), 0x44, 0 }
+#define JTAG_PORT_USB3B_DESC { ASPEED_IP_SCU, SCU408, GENMASK(12, 5), 0x45, 0 }
+#define JTAG_PORT_PCIEA_DESC { ASPEED_IP_SCU, SCU408, GENMASK(12, 5), 0x46, 0 }
+#define JTAG_PORT_PCIEB_DESC { ASPEED_IP_SCU, SCU408, GENMASK(12, 5), 0x47, 0 }
+#define JTAG_PORT_JTAGM0_DESC { ASPEED_IP_SCU, SCU408, GENMASK(12, 5), 0x8, 0 }
+
+SIG_EXPR_LIST_DECL_SEMG(JTAG_PORT, JTAGPSP, JTAG0, JTAGPSP, JTAG_PORT_PSP_DESC);
+SIG_EXPR_LIST_DECL_SEMG(JTAG_PORT, JTAGSSP, JTAG0, JTAGSSP, JTAG_PORT_SSP_DESC);
+SIG_EXPR_LIST_DECL_SEMG(JTAG_PORT, JTAGTSP, JTAG0, JTAGTSP, JTAG_PORT_TSP_DESC);
+SIG_EXPR_LIST_DECL_SEMG(JTAG_PORT, JTAGDDR, JTAG0, JTAGDDR, JTAG_PORT_DDR_DESC);
+SIG_EXPR_LIST_DECL_SEMG(JTAG_PORT, JTAGUSB3A, JTAG0, JTAGUSB3A, JTAG_PORT_USB3A_DESC);
+SIG_EXPR_LIST_DECL_SEMG(JTAG_PORT, JTAGUSB3B, JTAG0, JTAGUSB3B, JTAG_PORT_USB3B_DESC);
+SIG_EXPR_LIST_DECL_SEMG(JTAG_PORT, JTAGPCIEA, JTAG0, JTAGPCIEA, JTAG_PORT_PCIEA_DESC);
+SIG_EXPR_LIST_DECL_SEMG(JTAG_PORT, JTAGPCIEB, JTAG0, JTAGPCIEB, JTAG_PORT_PCIEB_DESC);
+SIG_EXPR_LIST_DECL_SEMG(JTAG_PORT, JTAGM0, JTAG0, JTAGM0, JTAG_PORT_JTAGM0_DESC);
+PIN_DECL_(JTAG_PORT, SIG_EXPR_LIST_PTR(JTAG_PORT, JTAGPSP), SIG_EXPR_LIST_PTR(JTAG_PORT, JTAGSSP),
+ SIG_EXPR_LIST_PTR(JTAG_PORT, JTAGTSP), SIG_EXPR_LIST_PTR(JTAG_PORT, JTAGDDR),
+ SIG_EXPR_LIST_PTR(JTAG_PORT, JTAGUSB3A), SIG_EXPR_LIST_PTR(JTAG_PORT, JTAGUSB3B),
+ SIG_EXPR_LIST_PTR(JTAG_PORT, JTAGPCIEA), SIG_EXPR_LIST_PTR(JTAG_PORT, JTAGPCIEB),
+ SIG_EXPR_LIST_PTR(JTAG_PORT, JTAGM0));
+
+GROUP_DECL(JTAG0, JTAG_PORT);
+
+FUNC_DECL_1(JTAGPSP, JTAG0);
+FUNC_DECL_1(JTAGSSP, JTAG0);
+FUNC_DECL_1(JTAGTSP, JTAG0);
+FUNC_DECL_1(JTAGDDR, JTAG0);
+FUNC_DECL_1(JTAGUSB3A, JTAG0);
+FUNC_DECL_1(JTAGUSB3B, JTAG0);
+FUNC_DECL_1(JTAGPCIEA, JTAG0);
+FUNC_DECL_1(JTAGPCIEB, JTAG0);
+FUNC_DECL_1(JTAGM0, JTAG0);
+
+/* PCIe Reset Control */
+SIG_EXPR_LIST_DECL_SESG(PCIERC0_PERST, PCIERC0PERST, PCIERC0PERST, SIG_DESC_SET(SCU200, 21));
+PIN_DECL_(PCIERC0_PERST, SIG_EXPR_LIST_PTR(PCIERC0_PERST, PCIERC0PERST));
+FUNC_GROUP_DECL(PCIERC0PERST, PCIERC0_PERST);
+
+SIG_EXPR_LIST_DECL_SESG(PCIERC1_PERST, PCIERC1PERST, PCIERC1PERST, SIG_DESC_SET(SCU200, 19));
+PIN_DECL_(PCIERC1_PERST, SIG_EXPR_LIST_PTR(PCIERC1_PERST, PCIERC1PERST));
+FUNC_GROUP_DECL(PCIERC1PERST, PCIERC1_PERST);
+
+#define PORTA_MODE_HPD0_DESC { ASPEED_IP_SCU, SCU410, GENMASK(25, 24), 0, 0 }
+#define PORTA_MODE_D0_DESC { ASPEED_IP_SCU, SCU410, GENMASK(25, 24), 1, 0 }
+#define PORTA_MODE_H_DESC { ASPEED_IP_SCU, SCU410, GENMASK(25, 24), 2, 0 }
+#define PORTA_MODE_HP_DESC { ASPEED_IP_SCU, SCU410, GENMASK(25, 24), 3, 0 }
+
+SIG_EXPR_LIST_DECL_SEMG(PORTA_MODE, USB2AHPD0, USB2AH, USB2AHPD0, PORTA_MODE_HPD0_DESC);
+SIG_EXPR_LIST_DECL_SEMG(PORTA_MODE, USB2AH, USB2AHAP, USB2AH, PORTA_MODE_H_DESC);
+SIG_EXPR_LIST_DECL_SEMG(PORTA_MODE, USB2AHP, USB2AHAP, USB2AHP, PORTA_MODE_HP_DESC);
+SIG_EXPR_LIST_DECL_SEMG(PORTA_MODE, USB2AD0, USB2AHAP, USB2AD0, PORTA_MODE_D0_DESC);
+PIN_DECL_(PORTA_MODE, SIG_EXPR_LIST_PTR(PORTA_MODE, USB2AHPD0),
+ SIG_EXPR_LIST_PTR(PORTA_MODE, USB2AH), SIG_EXPR_LIST_PTR(PORTA_MODE, USB2AHP),
+ SIG_EXPR_LIST_PTR(PORTA_MODE, USB2AD0));
+
+#define PORTA_U2_XHD_DESC { ASPEED_IP_SCU, SCU410, GENMASK(3, 2), 0, 0 }
+#define PORTA_U2_D1_DESC { ASPEED_IP_SCU, SCU410, GENMASK(3, 2), 1, 0 }
+#define PORTA_U2_XH_DESC { ASPEED_IP_SCU, SCU410, GENMASK(3, 2), 2, 0 }
+#define PORTA_U2_XH2E_DESC { ASPEED_IP_SCU, SCU410, GENMASK(3, 2), 3, 0 }
+
+SIG_EXPR_LIST_DECL_SEMG(PORTA_U2, USB2AXHD1, USB2A, USB2AXHD1, PORTA_U2_XHD_DESC,
+ SIG_DESC_SET(SCU410, 9));
+SIG_EXPR_LIST_DECL_SEMG(PORTA_U2, USB2AXHPD1, USB2A, USB2AXHPD1, PORTA_U2_XHD_DESC,
+ SIG_DESC_CLEAR(SCU410, 9));
+SIG_EXPR_LIST_DECL_SEMG(PORTA_U2, USB2AXH, USB2AAP, USB2AXH, PORTA_U2_XH_DESC,
+ SIG_DESC_SET(SCU410, 9));
+SIG_EXPR_LIST_DECL_SEMG(PORTA_U2, USB2AXHP, USB2AAP, USB2AXHP, PORTA_U2_XH_DESC,
+ SIG_DESC_CLEAR(SCU410, 9));
+SIG_EXPR_LIST_DECL_SEMG(PORTA_U2, USB2AXH2B, USB2ABP, USB2AXH2B, PORTA_U2_XH2E_DESC,
+ SIG_DESC_SET(SCU410, 9));
+SIG_EXPR_LIST_DECL_SEMG(PORTA_U2, USB2AXHP2B, USB2ABP, USB2AXHP2B, PORTA_U2_XH2E_DESC,
+ SIG_DESC_CLEAR(SCU410, 9));
+SIG_EXPR_LIST_DECL_SEMG(PORTA_U2, USB2AD1, USB2ADAP, USB2AD1, PORTA_U2_D1_DESC);
+PIN_DECL_(PORTA_U2, SIG_EXPR_LIST_PTR(PORTA_U2, USB2AXHD1), SIG_EXPR_LIST_PTR(PORTA_U2, USB2AXHPD1),
+ SIG_EXPR_LIST_PTR(PORTA_U2, USB2AXH), SIG_EXPR_LIST_PTR(PORTA_U2, USB2AXHP),
+ SIG_EXPR_LIST_PTR(PORTA_U2, USB2AXH2B), SIG_EXPR_LIST_PTR(PORTA_U2, USB2AXHP2B),
+ SIG_EXPR_LIST_PTR(PORTA_U2, USB2AD1));
+
+#define PORTB_MODE_HPD0_DESC { ASPEED_IP_SCU, SCU410, GENMASK(29, 28), 0, 0 }
+#define PORTB_MODE_D0_DESC { ASPEED_IP_SCU, SCU410, GENMASK(29, 28), 1, 0 }
+#define PORTB_MODE_H_DESC { ASPEED_IP_SCU, SCU410, GENMASK(29, 28), 2, 0 }
+#define PORTB_MODE_HP_DESC { ASPEED_IP_SCU, SCU410, GENMASK(29, 28), 3, 0 }
+
+SIG_EXPR_LIST_DECL_SEMG(PORTB_MODE, USB2BHPD0, USB2BH, USB2BHPD0, PORTB_MODE_HPD0_DESC);
+SIG_EXPR_LIST_DECL_SEMG(PORTB_MODE, USB2BH, USB2BHBP, USB2BH, PORTB_MODE_H_DESC);
+SIG_EXPR_LIST_DECL_SEMG(PORTB_MODE, USB2BHP, USB2BHBP, USB2BHP, PORTB_MODE_HP_DESC);
+SIG_EXPR_LIST_DECL_SEMG(PORTB_MODE, USB2BD0, USB2BHBP, USB2BD0, PORTB_MODE_D0_DESC);
+PIN_DECL_(PORTB_MODE, SIG_EXPR_LIST_PTR(PORTB_MODE, USB2BHPD0),
+ SIG_EXPR_LIST_PTR(PORTB_MODE, USB2BH), SIG_EXPR_LIST_PTR(PORTB_MODE, USB2BHP),
+ SIG_EXPR_LIST_PTR(PORTB_MODE, USB2BD0));
+
+#define PORTB_U2_XHD_DESC { ASPEED_IP_SCU, SCU410, GENMASK(7, 6), 0, 0 }
+#define PORTB_U2_D1_DESC { ASPEED_IP_SCU, SCU410, GENMASK(7, 6), 1, 0 }
+#define PORTB_U2_XH_DESC { ASPEED_IP_SCU, SCU410, GENMASK(7, 6), 2, 0 }
+#define PORTB_U2_XH2E_DESC { ASPEED_IP_SCU, SCU410, GENMASK(7, 6), 3, 0 }
+
+SIG_EXPR_LIST_DECL_SEMG(PORTB_U2, USB2BXHD1, USB2B, USB2BXHD1, PORTB_U2_XHD_DESC,
+ SIG_DESC_SET(SCU410, 10));
+SIG_EXPR_LIST_DECL_SEMG(PORTB_U2, USB2BXHPD1, USB2B, USB2BXHPD1, PORTB_U2_XHD_DESC,
+ SIG_DESC_CLEAR(SCU410, 10));
+SIG_EXPR_LIST_DECL_SEMG(PORTB_U2, USB2BXH, USB2BBP, USB2BXH, PORTB_U2_XH_DESC,
+ SIG_DESC_SET(SCU410, 10));
+SIG_EXPR_LIST_DECL_SEMG(PORTB_U2, USB2BXHP, USB2BBP, USB2BXHP, PORTB_U2_XH_DESC,
+ SIG_DESC_CLEAR(SCU410, 10));
+SIG_EXPR_LIST_DECL_SEMG(PORTB_U2, USB2BXH2A, USB2BAP, USB2BXH2A, PORTB_U2_XH2E_DESC,
+ SIG_DESC_SET(SCU410, 10));
+SIG_EXPR_LIST_DECL_SEMG(PORTB_U2, USB2BXHP2A, USB2BAP, USB2BXHP2A, PORTB_U2_XH2E_DESC,
+ SIG_DESC_CLEAR(SCU410, 10));
+SIG_EXPR_LIST_DECL_SEMG(PORTB_U2, USB2BD1, USB2BDBP, USB2BD1, PORTB_U2_D1_DESC);
+PIN_DECL_(PORTB_U2, SIG_EXPR_LIST_PTR(PORTB_U2, USB2BXHD1), SIG_EXPR_LIST_PTR(PORTB_U2, USB2BXHPD1),
+ SIG_EXPR_LIST_PTR(PORTB_U2, USB2BXH), SIG_EXPR_LIST_PTR(PORTB_U2, USB2BXHP),
+ SIG_EXPR_LIST_PTR(PORTB_U2, USB2BXH2A), SIG_EXPR_LIST_PTR(PORTB_U2, USB2BXHP2A),
+ SIG_EXPR_LIST_PTR(PORTB_U2, USB2BD1));
+/*
+ * USB2 virtual PHY pins.
+ *
+ * PORTA_U2_PHY and PORTB_U2_PHY are logical endpoints, not package pins.
+ * They alias existing USB2 expressions so pin groups can model direct and
+ * cross-coupled routing for host and mode paths.
+ *
+ * - USB2AAP/USB2ADAP/USB2AHAP: use PORTA_U2_PHY
+ * - USB2ABP : use PORTB_U2_PHY
+ * - USB2BBP/USB2BDBP/USB2BHBP: use PORTB_U2_PHY
+ * - USB2BAP : use PORTA_U2_PHY
+ *
+ * They do not have any registers to configure this behaviour; the goal is
+ * simply for the driver to prevent conflicting selections. For example,
+ * selecting group USB2ABP and USB2BBP at the same time should not be
+ * allowed.
+ */
+SIG_EXPR_LIST_ALIAS(PORTA_U2_PHY, USB2AXH, USB2AAP);
+SIG_EXPR_LIST_ALIAS(PORTA_U2_PHY, USB2AXHP, USB2AAP);
+SIG_EXPR_LIST_ALIAS(PORTA_U2_PHY, USB2BXH2A, USB2BAP);
+SIG_EXPR_LIST_ALIAS(PORTA_U2_PHY, USB2BXHP2A, USB2BAP);
+SIG_EXPR_LIST_ALIAS(PORTA_U2_PHY, USB2AD1, USB2ADAP);
+SIG_EXPR_LIST_ALIAS(PORTA_U2_PHY, USB2AH, USB2AHAP);
+SIG_EXPR_LIST_ALIAS(PORTA_U2_PHY, USB2AHP, USB2AHAP);
+SIG_EXPR_LIST_ALIAS(PORTA_U2_PHY, USB2AD0, USB2AHAP);
+PIN_DECL_(PORTA_U2_PHY, SIG_EXPR_LIST_PTR(PORTA_U2_PHY, USB2AXH),
+ SIG_EXPR_LIST_PTR(PORTA_U2_PHY, USB2AXHP), SIG_EXPR_LIST_PTR(PORTA_U2_PHY, USB2BXH2A),
+ SIG_EXPR_LIST_PTR(PORTA_U2_PHY, USB2BXHP2A), SIG_EXPR_LIST_PTR(PORTA_U2_PHY, USB2AD1),
+ SIG_EXPR_LIST_PTR(PORTA_U2_PHY, USB2AH), SIG_EXPR_LIST_PTR(PORTA_U2_PHY, USB2AHP),
+ SIG_EXPR_LIST_PTR(PORTA_U2_PHY, USB2AD0));
+
+SIG_EXPR_LIST_ALIAS(PORTB_U2_PHY, USB2AXH2B, USB2ABP);
+SIG_EXPR_LIST_ALIAS(PORTB_U2_PHY, USB2AXHP2B, USB2ABP);
+SIG_EXPR_LIST_ALIAS(PORTB_U2_PHY, USB2BXH, USB2BBP);
+SIG_EXPR_LIST_ALIAS(PORTB_U2_PHY, USB2BXHP, USB2BBP);
+SIG_EXPR_LIST_ALIAS(PORTB_U2_PHY, USB2BD1, USB2BDBP);
+SIG_EXPR_LIST_ALIAS(PORTB_U2_PHY, USB2BH, USB2BHBP);
+SIG_EXPR_LIST_ALIAS(PORTB_U2_PHY, USB2BHP, USB2BHBP);
+SIG_EXPR_LIST_ALIAS(PORTB_U2_PHY, USB2BD0, USB2BHBP);
+PIN_DECL_(PORTB_U2_PHY, SIG_EXPR_LIST_PTR(PORTB_U2_PHY, USB2AXH2B),
+ SIG_EXPR_LIST_PTR(PORTB_U2_PHY, USB2AXHP2B), SIG_EXPR_LIST_PTR(PORTB_U2_PHY, USB2BXH),
+ SIG_EXPR_LIST_PTR(PORTB_U2_PHY, USB2BXHP), SIG_EXPR_LIST_PTR(PORTB_U2_PHY, USB2BD1),
+ SIG_EXPR_LIST_PTR(PORTB_U2_PHY, USB2BH), SIG_EXPR_LIST_PTR(PORTB_U2_PHY, USB2BHP),
+ SIG_EXPR_LIST_PTR(PORTB_U2_PHY, USB2BD0));
+
+GROUP_DECL(USB2A, PORTA_U2);
+GROUP_DECL(USB2AAP, PORTA_U2, PORTA_U2_PHY);
+GROUP_DECL(USB2ABP, PORTA_U2, PORTB_U2_PHY);
+GROUP_DECL(USB2ADAP, PORTA_U2, PORTA_U2_PHY);
+GROUP_DECL(USB2AH, PORTA_MODE);
+GROUP_DECL(USB2AHAP, PORTA_MODE, PORTA_U2_PHY);
+
+FUNC_DECL_1(USB2AXHD1, USB2A);
+FUNC_DECL_1(USB2AXHPD1, USB2A);
+FUNC_DECL_1(USB2AXH, USB2AAP);
+FUNC_DECL_1(USB2AXHP, USB2AAP);
+FUNC_DECL_1(USB2AXH2B, USB2ABP);
+FUNC_DECL_1(USB2AXHP2B, USB2ABP);
+FUNC_DECL_1(USB2AD1, USB2ADAP);
+FUNC_DECL_1(USB2AHPD0, USB2AH);
+FUNC_DECL_1(USB2AH, USB2AHAP);
+FUNC_DECL_1(USB2AHP, USB2AHAP);
+FUNC_DECL_1(USB2AD0, USB2AHAP);
+
+GROUP_DECL(USB2B, PORTB_U2);
+GROUP_DECL(USB2BBP, PORTB_U2, PORTB_U2_PHY);
+GROUP_DECL(USB2BAP, PORTB_U2, PORTA_U2_PHY);
+GROUP_DECL(USB2BDBP, PORTB_U2, PORTB_U2_PHY);
+GROUP_DECL(USB2BH, PORTB_MODE);
+GROUP_DECL(USB2BHBP, PORTB_MODE, PORTB_U2_PHY);
+
+FUNC_DECL_1(USB2BXHD1, USB2B);
+FUNC_DECL_1(USB2BXHPD1, USB2B);
+FUNC_DECL_1(USB2BXH, USB2BBP);
+FUNC_DECL_1(USB2BXHP, USB2BBP);
+FUNC_DECL_1(USB2BXH2A, USB2BAP);
+FUNC_DECL_1(USB2BXHP2A, USB2BAP);
+FUNC_DECL_1(USB2BD1, USB2BDBP);
+FUNC_DECL_1(USB2BHPD0, USB2BH);
+FUNC_DECL_1(USB2BH, USB2BHBP);
+FUNC_DECL_1(USB2BHP, USB2BHBP);
+FUNC_DECL_1(USB2BD0, USB2BHBP);
+
+#define PORTA_U3_XHD_DESC { ASPEED_IP_SCU, SCU410, GENMASK(1, 0), 0, 0 }
+#define PORTA_U3_XH_DESC { ASPEED_IP_SCU, SCU410, GENMASK(1, 0), 2, 0 }
+#define PORTA_U3_XH2E_DESC { ASPEED_IP_SCU, SCU410, GENMASK(1, 0), 3, 0 }
+
+SIG_EXPR_LIST_DECL_SEMG(PORTA_U3, USB3AXHD, USB3A, USB3AXHD, PORTA_U3_XHD_DESC,
+ SIG_DESC_SET(SCU410, 9));
+SIG_EXPR_LIST_DECL_SEMG(PORTA_U3, USB3AXHPD, USB3A, USB3AXHPD, PORTA_U3_XHD_DESC,
+ SIG_DESC_CLEAR(SCU410, 9));
+SIG_EXPR_LIST_DECL_SEMG(PORTA_U3, USB3AXH, USB3AAP, USB3AXH, PORTA_U3_XH_DESC,
+ SIG_DESC_SET(SCU410, 9));
+SIG_EXPR_LIST_DECL_SEMG(PORTA_U3, USB3AXHP, USB3AAP, USB3AXHP, PORTA_U3_XH_DESC,
+ SIG_DESC_CLEAR(SCU410, 9));
+SIG_EXPR_LIST_DECL_SEMG(PORTA_U3, USB3AXH2B, USB3ABP, USB3AXH2B, PORTA_U3_XH2E_DESC,
+ SIG_DESC_SET(SCU410, 9));
+SIG_EXPR_LIST_DECL_SEMG(PORTA_U3, USB3AXHP2B, USB3ABP, USB3AXHP2B, PORTA_U3_XH2E_DESC,
+ SIG_DESC_CLEAR(SCU410, 9));
+PIN_DECL_(PORTA_U3, SIG_EXPR_LIST_PTR(PORTA_U3, USB3AXHD), SIG_EXPR_LIST_PTR(PORTA_U3, USB3AXHPD),
+ SIG_EXPR_LIST_PTR(PORTA_U3, USB3AXH), SIG_EXPR_LIST_PTR(PORTA_U3, USB3AXHP),
+ SIG_EXPR_LIST_PTR(PORTA_U3, USB3AXH2B), SIG_EXPR_LIST_PTR(PORTA_U3, USB3AXHP2B));
+
+#define PORTB_U3_XHD_DESC { ASPEED_IP_SCU, SCU410, GENMASK(5, 4), 0, 0 }
+#define PORTB_U3_XH_DESC { ASPEED_IP_SCU, SCU410, GENMASK(5, 4), 2, 0 }
+#define PORTB_U3_XH2E_DESC { ASPEED_IP_SCU, SCU410, GENMASK(5, 4), 3, 0 }
+
+SIG_EXPR_LIST_DECL_SEMG(PORTB_U3, USB3BXHD, USB3B, USB3BXHD, PORTB_U3_XHD_DESC,
+ SIG_DESC_SET(SCU410, 10));
+SIG_EXPR_LIST_DECL_SEMG(PORTB_U3, USB3BXHPD, USB3B, USB3BXHPD, PORTB_U3_XHD_DESC,
+ SIG_DESC_CLEAR(SCU410, 10));
+SIG_EXPR_LIST_DECL_SEMG(PORTB_U3, USB3BXH, USB3BBP, USB3BXH, PORTB_U3_XH_DESC,
+ SIG_DESC_SET(SCU410, 10));
+SIG_EXPR_LIST_DECL_SEMG(PORTB_U3, USB3BXHP, USB3BBP, USB3BXHP, PORTB_U3_XH_DESC,
+ SIG_DESC_CLEAR(SCU410, 10));
+SIG_EXPR_LIST_DECL_SEMG(PORTB_U3, USB3BXH2A, USB3BAP, USB3BXH2A, PORTB_U3_XH2E_DESC,
+ SIG_DESC_SET(SCU410, 10));
+SIG_EXPR_LIST_DECL_SEMG(PORTB_U3, USB3BXHP2A, USB3BAP, USB3BXHP2A, PORTB_U3_XH2E_DESC,
+ SIG_DESC_CLEAR(SCU410, 10));
+PIN_DECL_(PORTB_U3, SIG_EXPR_LIST_PTR(PORTB_U3, USB3BXHD), SIG_EXPR_LIST_PTR(PORTB_U3, USB3BXHPD),
+ SIG_EXPR_LIST_PTR(PORTB_U3, USB3BXH), SIG_EXPR_LIST_PTR(PORTB_U3, USB3BXHP),
+ SIG_EXPR_LIST_PTR(PORTB_U3, USB3BXH2A), SIG_EXPR_LIST_PTR(PORTB_U3, USB3BXHP2A));
+
+/*
+ * USB3 virtual PHY pins.
+ *
+ * PORTA_U3_PHY and PORTB_U3_PHY are logical endpoints, not package pins.
+ * They alias existing USB3 expressions so pin groups can model both direct and
+ * cross-coupled routing to PHY A/B.
+ *
+ * - USB3AAP: PORTA_U3 + PORTA_U3_PHY (A -> PHY A)
+ * - USB3ABP: PORTA_U3 + PORTB_U3_PHY (A -> PHY B)
+ * - USB3BBP: PORTB_U3 + PORTB_U3_PHY (B -> PHY B)
+ * - USB3BAP: PORTB_U3 + PORTA_U3_PHY (B -> PHY A)
+ *
+ * They do not have any registers to configure this behavior; the goal is
+ * simply for the driver to prevent conflicting selections. For example,
+ * selecting group USB3ABP and USB3BBP at the same time should not be
+ * allowed.
+ */
+SIG_EXPR_LIST_ALIAS(PORTA_U3_PHY, USB3AXH, USB3AAP);
+SIG_EXPR_LIST_ALIAS(PORTA_U3_PHY, USB3AXHP, USB3AAP);
+SIG_EXPR_LIST_ALIAS(PORTA_U3_PHY, USB3BXH2A, USB3BAP);
+SIG_EXPR_LIST_ALIAS(PORTA_U3_PHY, USB3BXHP2A, USB3BAP);
+PIN_DECL_(PORTA_U3_PHY, SIG_EXPR_LIST_PTR(PORTA_U3_PHY, USB3AXH),
+ SIG_EXPR_LIST_PTR(PORTA_U3_PHY, USB3AXHP), SIG_EXPR_LIST_PTR(PORTA_U3_PHY, USB3BXH2A),
+ SIG_EXPR_LIST_PTR(PORTA_U3_PHY, USB3BXHP2A));
+
+SIG_EXPR_LIST_ALIAS(PORTB_U3_PHY, USB3AXH2B, USB3ABP);
+SIG_EXPR_LIST_ALIAS(PORTB_U3_PHY, USB3AXHP2B, USB3ABP);
+SIG_EXPR_LIST_ALIAS(PORTB_U3_PHY, USB3BXH, USB3BBP);
+SIG_EXPR_LIST_ALIAS(PORTB_U3_PHY, USB3BXHP, USB3BBP);
+PIN_DECL_(PORTB_U3_PHY, SIG_EXPR_LIST_PTR(PORTB_U3_PHY, USB3AXH2B),
+ SIG_EXPR_LIST_PTR(PORTB_U3_PHY, USB3AXHP2B), SIG_EXPR_LIST_PTR(PORTB_U3_PHY, USB3BXH),
+ SIG_EXPR_LIST_PTR(PORTB_U3_PHY, USB3BXHP));
+
+/* USB3A xHCI to vHUB */
+GROUP_DECL(USB3A, PORTA_U3);
+/* USB3A xHCI to USB3A PHY */
+GROUP_DECL(USB3AAP, PORTA_U3, PORTA_U3_PHY);
+/* USB3A xHCI to USB3B PHY */
+GROUP_DECL(USB3ABP, PORTA_U3, PORTB_U3_PHY);
+
+FUNC_DECL_1(USB3AXHD, USB3A);
+FUNC_DECL_1(USB3AXHPD, USB3A);
+FUNC_DECL_1(USB3AXH, USB3AAP);
+FUNC_DECL_1(USB3AXHP, USB3AAP);
+FUNC_DECL_1(USB3AXH2B, USB3ABP);
+FUNC_DECL_1(USB3AXHP2B, USB3ABP);
+
+/* USB3B xHCI to vHUB */
+GROUP_DECL(USB3B, PORTB_U3);
+/* USB3B xHCI to USB3A PHY */
+GROUP_DECL(USB3BAP, PORTB_U3, PORTA_U3_PHY);
+/* USB3B xHCI to USB3B PHY */
+GROUP_DECL(USB3BBP, PORTB_U3, PORTB_U3_PHY);
+
+FUNC_DECL_1(USB3BXHD, USB3B);
+FUNC_DECL_1(USB3BXHPD, USB3B);
+FUNC_DECL_1(USB3BXH, USB3BBP);
+FUNC_DECL_1(USB3BXHP, USB3BBP);
+FUNC_DECL_1(USB3BXH2A, USB3BAP);
+FUNC_DECL_1(USB3BXHP2A, USB3BAP);
+
+static const struct pinctrl_pin_desc aspeed_g7_soc0_pins[] = {
+ ASPEED_PINCTRL_PIN(AC14),
+ ASPEED_PINCTRL_PIN(AE15),
+ ASPEED_PINCTRL_PIN(AD14),
+ ASPEED_PINCTRL_PIN(AE14),
+ ASPEED_PINCTRL_PIN(AF14),
+ ASPEED_PINCTRL_PIN(AB13),
+ ASPEED_PINCTRL_PIN(AB14),
+ ASPEED_PINCTRL_PIN(AF15),
+ ASPEED_PINCTRL_PIN(AF13),
+ ASPEED_PINCTRL_PIN(AC13),
+ ASPEED_PINCTRL_PIN(AD13),
+ ASPEED_PINCTRL_PIN(AE13),
+ ASPEED_PINCTRL_PIN(JTAG_PORT),
+ ASPEED_PINCTRL_PIN(PCIERC0_PERST),
+ ASPEED_PINCTRL_PIN(PCIERC1_PERST),
+ ASPEED_PINCTRL_PIN(PORTA_MODE),
+ ASPEED_PINCTRL_PIN(PORTA_U2),
+ ASPEED_PINCTRL_PIN(PORTA_U3),
+ ASPEED_PINCTRL_PIN(PORTA_U2_PHY),
+ ASPEED_PINCTRL_PIN(PORTA_U3_PHY),
+ ASPEED_PINCTRL_PIN(PORTB_MODE),
+ ASPEED_PINCTRL_PIN(PORTB_U2),
+ ASPEED_PINCTRL_PIN(PORTB_U3),
+ ASPEED_PINCTRL_PIN(PORTB_U2_PHY),
+ ASPEED_PINCTRL_PIN(PORTB_U3_PHY),
+};
+
+static const struct aspeed_pin_group aspeed_g7_soc0_groups[] = {
+ ASPEED_PINCTRL_GROUP(EMMCCDN),
+ ASPEED_PINCTRL_GROUP(EMMCG1),
+ ASPEED_PINCTRL_GROUP(EMMCG4),
+ ASPEED_PINCTRL_GROUP(EMMCG8),
+ ASPEED_PINCTRL_GROUP(EMMCWPN),
+ ASPEED_PINCTRL_GROUP(TSPRSTN),
+ ASPEED_PINCTRL_GROUP(UFSCLKI),
+ ASPEED_PINCTRL_GROUP(VB0),
+ ASPEED_PINCTRL_GROUP(VB1),
+ ASPEED_PINCTRL_GROUP(VGADDC),
+ /* JTAG groups */
+ ASPEED_PINCTRL_GROUP(JTAG0),
+ /* PCIE RC groups */
+ ASPEED_PINCTRL_GROUP(PCIERC0PERST),
+ ASPEED_PINCTRL_GROUP(PCIERC1PERST),
+ /* USB3A groups */
+ ASPEED_PINCTRL_GROUP(USB3A),
+ ASPEED_PINCTRL_GROUP(USB3AAP),
+ ASPEED_PINCTRL_GROUP(USB3ABP),
+ /* USB3B groups */
+ ASPEED_PINCTRL_GROUP(USB3B),
+ ASPEED_PINCTRL_GROUP(USB3BAP),
+ ASPEED_PINCTRL_GROUP(USB3BBP),
+ /* USB2A groups */
+ ASPEED_PINCTRL_GROUP(USB2A),
+ ASPEED_PINCTRL_GROUP(USB2AAP),
+ ASPEED_PINCTRL_GROUP(USB2ABP),
+ ASPEED_PINCTRL_GROUP(USB2ADAP),
+ ASPEED_PINCTRL_GROUP(USB2AH),
+ ASPEED_PINCTRL_GROUP(USB2AHAP),
+ /* USB2B groups */
+ ASPEED_PINCTRL_GROUP(USB2B),
+ ASPEED_PINCTRL_GROUP(USB2BAP),
+ ASPEED_PINCTRL_GROUP(USB2BBP),
+ ASPEED_PINCTRL_GROUP(USB2BDBP),
+ ASPEED_PINCTRL_GROUP(USB2BH),
+ ASPEED_PINCTRL_GROUP(USB2BHBP),
+};
+
+static const struct aspeed_pin_function aspeed_g7_soc0_functions[] = {
+ ASPEED_PINCTRL_FUNC(EMMC),
+ ASPEED_PINCTRL_FUNC(TSPRSTN),
+ ASPEED_PINCTRL_FUNC(UFSCLKI),
+ ASPEED_PINCTRL_FUNC(VB),
+ ASPEED_PINCTRL_FUNC(VGADDC),
+ /* JTAG functions */
+ ASPEED_PINCTRL_FUNC(JTAGDDR),
+ ASPEED_PINCTRL_FUNC(JTAGM0),
+ ASPEED_PINCTRL_FUNC(JTAGPCIEA),
+ ASPEED_PINCTRL_FUNC(JTAGPCIEB),
+ ASPEED_PINCTRL_FUNC(JTAGPSP),
+ ASPEED_PINCTRL_FUNC(JTAGSSP),
+ ASPEED_PINCTRL_FUNC(JTAGTSP),
+ ASPEED_PINCTRL_FUNC(JTAGUSB3A),
+ ASPEED_PINCTRL_FUNC(JTAGUSB3B),
+ /* PCIE RC functions */
+ ASPEED_PINCTRL_FUNC(PCIERC0PERST),
+ ASPEED_PINCTRL_FUNC(PCIERC1PERST),
+ /* USB3A functions */
+ ASPEED_PINCTRL_FUNC(USB3AXH),
+ ASPEED_PINCTRL_FUNC(USB3AXH2B),
+ ASPEED_PINCTRL_FUNC(USB3AXHD),
+ ASPEED_PINCTRL_FUNC(USB3AXHP),
+ ASPEED_PINCTRL_FUNC(USB3AXHP2B),
+ ASPEED_PINCTRL_FUNC(USB3AXHPD),
+ /* USB3B functions */
+ ASPEED_PINCTRL_FUNC(USB3BXH),
+ ASPEED_PINCTRL_FUNC(USB3BXH2A),
+ ASPEED_PINCTRL_FUNC(USB3BXHD),
+ ASPEED_PINCTRL_FUNC(USB3BXHP),
+ ASPEED_PINCTRL_FUNC(USB3BXHP2A),
+ ASPEED_PINCTRL_FUNC(USB3BXHPD),
+ /* USB2A functions */
+ ASPEED_PINCTRL_FUNC(USB2AD0),
+ ASPEED_PINCTRL_FUNC(USB2AD1),
+ ASPEED_PINCTRL_FUNC(USB2AH),
+ ASPEED_PINCTRL_FUNC(USB2AHP),
+ ASPEED_PINCTRL_FUNC(USB2AHPD0),
+ ASPEED_PINCTRL_FUNC(USB2AXH),
+ ASPEED_PINCTRL_FUNC(USB2AXH2B),
+ ASPEED_PINCTRL_FUNC(USB2AXHD1),
+ ASPEED_PINCTRL_FUNC(USB2AXHP),
+ ASPEED_PINCTRL_FUNC(USB2AXHP2B),
+ ASPEED_PINCTRL_FUNC(USB2AXHPD1),
+ /* USB2B functions */
+ ASPEED_PINCTRL_FUNC(USB2BD0),
+ ASPEED_PINCTRL_FUNC(USB2BD1),
+ ASPEED_PINCTRL_FUNC(USB2BH),
+ ASPEED_PINCTRL_FUNC(USB2BHP),
+ ASPEED_PINCTRL_FUNC(USB2BHPD0),
+ ASPEED_PINCTRL_FUNC(USB2BXH),
+ ASPEED_PINCTRL_FUNC(USB2BXH2A),
+ ASPEED_PINCTRL_FUNC(USB2BXHD1),
+ ASPEED_PINCTRL_FUNC(USB2BXHP),
+ ASPEED_PINCTRL_FUNC(USB2BXHP2A),
+ ASPEED_PINCTRL_FUNC(USB2BXHPD1),
+};
+
+static const struct pinmux_ops aspeed_g7_soc0_pinmux_ops = {
+ .get_functions_count = aspeed_pinmux_get_fn_count,
+ .get_function_name = aspeed_pinmux_get_fn_name,
+ .get_function_groups = aspeed_pinmux_get_fn_groups,
+ .set_mux = aspeed_pinmux_set_mux,
+ .gpio_request_enable = aspeed_gpio_request_enable,
+ .strict = true,
+};
+
+static const struct pinctrl_ops aspeed_g7_soc0_pinctrl_ops = {
+ .get_groups_count = aspeed_pinctrl_get_groups_count,
+ .get_group_name = aspeed_pinctrl_get_group_name,
+ .get_group_pins = aspeed_pinctrl_get_group_pins,
+ .pin_dbg_show = aspeed_pinctrl_pin_dbg_show,
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_all,
+ .dt_free_map = pinctrl_utils_free_map,
+};
+
+static const struct pinconf_ops aspeed_g7_soc0_pinconf_ops = {
+ .is_generic = true,
+ .pin_config_get = aspeed_pin_config_get,
+ .pin_config_set = aspeed_pin_config_set,
+ .pin_config_group_get = aspeed_pin_config_group_get,
+ .pin_config_group_set = aspeed_pin_config_group_set,
+};
+
+/* pinctrl_desc */
+static const struct pinctrl_desc aspeed_g7_soc0_pinctrl_desc = {
+ .name = "aspeed-g7-soc0-pinctrl",
+ .pins = aspeed_g7_soc0_pins,
+ .npins = ARRAY_SIZE(aspeed_g7_soc0_pins),
+ .pctlops = &aspeed_g7_soc0_pinctrl_ops,
+ .pmxops = &aspeed_g7_soc0_pinmux_ops,
+ .confops = &aspeed_g7_soc0_pinconf_ops,
+};
+
+static const struct aspeed_pin_config aspeed_g7_soc0_configs[] = {
+ /* GPIO18A */
+ { PIN_CONFIG_DRIVE_STRENGTH, { AC14, AC14 }, SCU480, GENMASK(3, 0) },
+ { PIN_CONFIG_BIAS_PULL_DOWN, { AC14, AC14 }, SCU480, GENMASK(5, 4) },
+ { PIN_CONFIG_BIAS_PULL_UP, { AC14, AC14 }, SCU480, GENMASK(5, 4) },
+ { PIN_CONFIG_BIAS_DISABLE, { AC14, AC14 }, SCU480, BIT(5) },
+ { PIN_CONFIG_DRIVE_STRENGTH, { AE15, AE15 }, SCU484, GENMASK(3, 0) },
+ { PIN_CONFIG_BIAS_PULL_DOWN, { AE15, AE15 }, SCU484, GENMASK(5, 4) },
+ { PIN_CONFIG_BIAS_PULL_UP, { AE15, AE15 }, SCU484, GENMASK(5, 4) },
+ { PIN_CONFIG_BIAS_DISABLE, { AE15, AE15 }, SCU484, BIT(5) },
+ { PIN_CONFIG_DRIVE_STRENGTH, { AD14, AD14 }, SCU488, GENMASK(3, 0) },
+ { PIN_CONFIG_BIAS_PULL_DOWN, { AD14, AD14 }, SCU488, GENMASK(5, 4) },
+ { PIN_CONFIG_BIAS_PULL_UP, { AD14, AD14 }, SCU488, GENMASK(5, 4) },
+ { PIN_CONFIG_BIAS_DISABLE, { AD14, AD14 }, SCU488, BIT(5) },
+ { PIN_CONFIG_DRIVE_STRENGTH, { AE14, AE14 }, SCU48C, GENMASK(3, 0) },
+ { PIN_CONFIG_BIAS_PULL_DOWN, { AE14, AE14 }, SCU48C, GENMASK(5, 4) },
+ { PIN_CONFIG_BIAS_PULL_UP, { AE14, AE14 }, SCU48C, GENMASK(5, 4) },
+ { PIN_CONFIG_BIAS_DISABLE, { AE14, AE14 }, SCU48C, BIT(5) },
+ { PIN_CONFIG_DRIVE_STRENGTH, { AF14, AF14 }, SCU490, GENMASK(3, 0) },
+ { PIN_CONFIG_BIAS_PULL_DOWN, { AF14, AF14 }, SCU490, GENMASK(5, 4) },
+ { PIN_CONFIG_BIAS_PULL_UP, { AF14, AF14 }, SCU490, GENMASK(5, 4) },
+ { PIN_CONFIG_BIAS_DISABLE, { AF14, AF14 }, SCU490, BIT(5) },
+ { PIN_CONFIG_DRIVE_STRENGTH, { AB13, AB13 }, SCU494, GENMASK(3, 0) },
+ { PIN_CONFIG_BIAS_PULL_DOWN, { AB13, AB13 }, SCU494, GENMASK(5, 4) },
+ { PIN_CONFIG_BIAS_PULL_UP, { AB13, AB13 }, SCU494, GENMASK(5, 4) },
+ { PIN_CONFIG_BIAS_DISABLE, { AB13, AB13 }, SCU494, BIT(5) },
+ { PIN_CONFIG_DRIVE_STRENGTH, { AB14, AB14 }, SCU498, GENMASK(3, 0) },
+ { PIN_CONFIG_BIAS_PULL_DOWN, { AB14, AB14 }, SCU498, GENMASK(5, 4) },
+ { PIN_CONFIG_BIAS_PULL_UP, { AB14, AB14 }, SCU498, GENMASK(5, 4) },
+ { PIN_CONFIG_BIAS_DISABLE, { AB14, AB14 }, SCU498, BIT(5) },
+ { PIN_CONFIG_DRIVE_STRENGTH, { AF15, AF15 }, SCU49C, GENMASK(3, 0) },
+ { PIN_CONFIG_BIAS_PULL_DOWN, { AF15, AF15 }, SCU49C, GENMASK(5, 4) },
+ { PIN_CONFIG_BIAS_PULL_UP, { AF15, AF15 }, SCU49C, GENMASK(5, 4) },
+ { PIN_CONFIG_BIAS_DISABLE, { AF15, AF15 }, SCU49C, BIT(5) },
+ /* GPIO18B */
+ { PIN_CONFIG_DRIVE_STRENGTH, { AF13, AF13 }, SCU4A0, GENMASK(3, 0) },
+ { PIN_CONFIG_BIAS_PULL_DOWN, { AF13, AF13 }, SCU4A0, GENMASK(5, 4) },
+ { PIN_CONFIG_BIAS_PULL_UP, { AF13, AF13 }, SCU4A0, GENMASK(5, 4) },
+ { PIN_CONFIG_BIAS_DISABLE, { AF13, AF13 }, SCU4A0, BIT(5) },
+ { PIN_CONFIG_DRIVE_STRENGTH, { AC13, AC13 }, SCU4A4, GENMASK(3, 0) },
+ { PIN_CONFIG_BIAS_PULL_DOWN, { AC13, AC13 }, SCU4A4, GENMASK(5, 4) },
+ { PIN_CONFIG_BIAS_PULL_UP, { AC13, AC13 }, SCU4A4, GENMASK(5, 4) },
+ { PIN_CONFIG_BIAS_DISABLE, { AC13, AC13 }, SCU4A4, BIT(5) },
+ { PIN_CONFIG_DRIVE_STRENGTH, { AD13, AD13 }, SCU4A8, GENMASK(3, 0) },
+ { PIN_CONFIG_BIAS_PULL_DOWN, { AD13, AD13 }, SCU4A8, GENMASK(5, 4) },
+ { PIN_CONFIG_BIAS_PULL_UP, { AD13, AD13 }, SCU4A8, GENMASK(5, 4) },
+ { PIN_CONFIG_BIAS_DISABLE, { AD13, AD13 }, SCU4A8, BIT(5) },
+ { PIN_CONFIG_DRIVE_STRENGTH, { AE13, AE13 }, SCU4AC, GENMASK(3, 0) },
+ { PIN_CONFIG_BIAS_PULL_DOWN, { AE13, AE13 }, SCU4AC, GENMASK(5, 4) },
+ { PIN_CONFIG_BIAS_PULL_UP, { AE13, AE13 }, SCU4AC, GENMASK(5, 4) },
+ { PIN_CONFIG_BIAS_DISABLE, { AE13, AE13 }, SCU4AC, BIT(5) },
+};
+
+static const struct aspeed_pin_config_map aspeed_g7_soc0_pin_config_map[] = {
+ { PIN_CONFIG_BIAS_PULL_DOWN, -1, 2, GENMASK(1, 0) },
+ { PIN_CONFIG_BIAS_PULL_UP, -1, 3, GENMASK(1, 0) },
+ { PIN_CONFIG_BIAS_DISABLE, -1, 0, BIT_MASK(0) },
+ { PIN_CONFIG_DRIVE_STRENGTH, 3, 0, GENMASK(3, 0) },
+ { PIN_CONFIG_DRIVE_STRENGTH, 6, 1, GENMASK(3, 0) },
+ { PIN_CONFIG_DRIVE_STRENGTH, 8, 2, GENMASK(3, 0) },
+ { PIN_CONFIG_DRIVE_STRENGTH, 11, 3, GENMASK(3, 0) },
+ { PIN_CONFIG_DRIVE_STRENGTH, 16, 4, GENMASK(3, 0) },
+ { PIN_CONFIG_DRIVE_STRENGTH, 18, 5, GENMASK(3, 0) },
+ { PIN_CONFIG_DRIVE_STRENGTH, 20, 6, GENMASK(3, 0) },
+ { PIN_CONFIG_DRIVE_STRENGTH, 23, 7, GENMASK(3, 0) },
+ { PIN_CONFIG_DRIVE_STRENGTH, 30, 8, GENMASK(3, 0) },
+ { PIN_CONFIG_DRIVE_STRENGTH, 32, 9, GENMASK(3, 0) },
+ { PIN_CONFIG_DRIVE_STRENGTH, 33, 10, GENMASK(3, 0) },
+ { PIN_CONFIG_DRIVE_STRENGTH, 35, 11, GENMASK(3, 0) },
+ { PIN_CONFIG_DRIVE_STRENGTH, 37, 12, GENMASK(3, 0) },
+ { PIN_CONFIG_DRIVE_STRENGTH, 38, 13, GENMASK(3, 0) },
+ { PIN_CONFIG_DRIVE_STRENGTH, 39, 14, GENMASK(3, 0) },
+ { PIN_CONFIG_DRIVE_STRENGTH, 41, 15, GENMASK(3, 0) },
+
+};
+
+static int aspeed_g7_soc0_sig_expr_set(struct aspeed_pinmux_data *ctx,
+ const struct aspeed_sig_expr *expr, bool enable)
+{
+ int ret;
+ int i;
+
+ for (i = 0; i < expr->ndescs; i++) {
+ const struct aspeed_sig_desc *desc = &expr->descs[i];
+ u32 pattern = enable ? desc->enable : desc->disable;
+ u32 val = (pattern << __ffs(desc->mask));
+
+ if (!ctx->maps[desc->ip])
+ return -ENODEV;
+
+ WARN_ON_ONCE(desc->ip != ASPEED_IP_SCU);
+
+ ret = regmap_update_bits(ctx->maps[desc->ip], desc->reg,
+ desc->mask, val);
+ if (ret)
+ return ret;
+ }
+
+ ret = aspeed_sig_expr_eval(ctx, expr, enable);
+ if (ret < 0)
+ return ret;
+
+ return ret ? 0 : -EPERM;
+}
+
+static const struct aspeed_pinmux_ops aspeed_g7_soc0_ops = {
+ .set = aspeed_g7_soc0_sig_expr_set,
+};
+
+static struct aspeed_pinctrl_data aspeed_g7_soc0_pinctrl_data = {
+ .pins = aspeed_g7_soc0_pins,
+ .npins = ARRAY_SIZE(aspeed_g7_soc0_pins),
+ .pinmux = {
+ .ops = &aspeed_g7_soc0_ops,
+ .groups = aspeed_g7_soc0_groups,
+ .ngroups = ARRAY_SIZE(aspeed_g7_soc0_groups),
+ .functions = aspeed_g7_soc0_functions,
+ .nfunctions = ARRAY_SIZE(aspeed_g7_soc0_functions),
+ },
+ .configs = aspeed_g7_soc0_configs,
+ .nconfigs = ARRAY_SIZE(aspeed_g7_soc0_configs),
+ .confmaps = aspeed_g7_soc0_pin_config_map,
+ .nconfmaps = ARRAY_SIZE(aspeed_g7_soc0_pin_config_map),
+};
+
+static int aspeed_g7_soc0_pinctrl_probe(struct platform_device *pdev)
+{
+ return aspeed_pinctrl_probe(pdev, &aspeed_g7_soc0_pinctrl_desc,
+ &aspeed_g7_soc0_pinctrl_data);
+}
+
+static const struct of_device_id aspeed_g7_soc0_pinctrl_match[] = {
+ { .compatible = "aspeed,ast2700-soc0-pinctrl" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, aspeed_g7_soc0_pinctrl_match);
+
+static struct platform_driver aspeed_g7_soc0_pinctrl_driver = {
+ .probe = aspeed_g7_soc0_pinctrl_probe,
+ .driver = {
+ .name = "aspeed-g7-soc0-pinctrl",
+ .of_match_table = aspeed_g7_soc0_pinctrl_match,
+ .suppress_bind_attrs = true,
+ },
+};
+
+static int __init aspeed_g7_soc0_pinctrl_init(void)
+{
+ return platform_driver_register(&aspeed_g7_soc0_pinctrl_driver);
+}
+arch_initcall(aspeed_g7_soc0_pinctrl_init);
--
2.34.1
^ permalink raw reply related
* Re: [PATCH v4 2/4] pwm: sun50i: Add H616 PWM support
From: Richard GENOUD @ 2026-04-16 7:53 UTC (permalink / raw)
To: Paul Kocialkowski
Cc: Uwe Kleine-König, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Chen-Yu Tsai, Jernej Skrabec, Samuel Holland,
Philipp Zabel, Thomas Petazzoni, John Stultz, Joao Schim,
linux-pwm, devicetree, linux-arm-kernel, linux-sunxi,
linux-kernel
In-Reply-To: <adfiPo4Jq1IRMM0h@shepard>
Hi Paul,
Le 09/04/2026 à 19:30, Paul Kocialkowski a écrit :
> Hi Richard,
>
> On Thu 05 Mar 26, 10:19, Richard Genoud wrote:
>> +/* PWM IRQ Enable Register */
>> +#define H616_PWM_IER 0x0
>
> I think it would make more sense to keep the full register names from the
> manual after the suffix and stick to them. It makes things easier when
> comparing the code with documentation or the reference implementation.
>
> So something like SUN8I_PWM_PIER here.
Ok, that make sense.
>
>> +
>> +/* PWM IRQ Status Register */
>> +#define H616_PWM_ISR 0x4
>> +
>> +/* PWM Capture IRQ Enable Register */
>> +#define H616_PWM_CIER 0x10
>> +
>> +/* PWM Capture IRQ Status Register */
>> +#define H616_PWM_CISR 0x14
>> +
>> +/* PWMCC Pairs Clock Configuration Registers */
>> +#define H616_PWM_XY_CLK_CR(pair) (0x20 + ((pair) * 0x4))
>> +#define H616_PWM_XY_CLK_CR_SRC_SHIFT 7
>> +#define H616_PWM_XY_CLK_CR_SRC_MASK 1
>> +#define H616_PWM_XY_CLK_CR_GATE_BIT 4
>> +#define H616_PWM_XY_CLK_CR_BYPASS_BIT(chan) ((chan) % 2 + 5)
>> +#define H616_PWM_XY_CLK_CR_DIV_M_SHIFT 0
>> +
>> +/* PWMCC Pairs Dead Zone Control Registers */
>> +#define H616_PWM_XY_DZ(pair) (0x30 + ((pair) * 0x4))
>> +
>> +/* PWM Enable Register */
>> +#define H616_PWM_ENR 0x40
>> +#define H616_PWM_ENABLE(x) BIT(x)
>> +
>> +/* PWM Capture Enable Register */
>> +#define H616_PWM_CER 0x44
>> +
>> +/* PWM Control Register */
>> +#define H616_PWM_CTRL_REG(chan) (0x60 + (chan) * 0x20)
>
> You're sometimes calling the register offset _REG and sometimes not.
> Both options are fine but you need to keep it consistent across the whole
> definitions. I would be enclined to not use it after using the register names
> coming from the manual as suggested above.
I see what you mean, so H616_PWM_CTRL_REG() would become SUN8I_PWM_PCR()
>
> Also you're sometimes using "chan", sometimes "ch" for the argument to the
> register macros. This is inconsistent and you might as well just use "c"
> everywhere so it doesn't take too much space.
Indeed.
>
>> +#define H616_PWM_CTRL_PRESCAL_K_SHIFT 0
>> +#define H616_PWM_CTRL_PRESCAL_K_WIDTH 8
>> +#define H616_PWM_CTRL_ACTIVE_STATE BIT(8)
>> +
>> +/* PWM Period Register */
>> +#define H616_PWM_PERIOD_REG(ch) (0x64 + (ch) * 0x20)
>> +#define H616_PWM_PERIOD_MASK GENMASK(31, 16)
>> +#define H616_PWM_DUTY_MASK GENMASK(15, 0)
>> +#define H616_PWM_REG_PERIOD(reg) (FIELD_GET(H616_PWM_PERIOD_MASK, reg) + 1)
>> +#define H616_PWM_REG_DUTY(reg) FIELD_GET(H616_PWM_DUTY_MASK, reg)
>> +#define H616_PWM_PERIOD(prd) FIELD_PREP(H616_PWM_PERIOD_MASK, (prd) - 1)
>> +#define H616_PWM_DUTY(dty) FIELD_PREP(H616_PWM_DUTY_MASK, dty)
>> +#define H616_PWM_PERIOD_MAX (FIELD_MAX(H616_PWM_PERIOD_MASK) + 1)
>
> Using REG as a prefix feels a bit confusing here. I would rather see:
> #define SUN8I_PWM_PPR(c) (0x64 + (c) * 0x20)
> #define SUN8I_PWM_PPR_PERIOD(p) FIELD_PREP(...)
> #define SUN8I_PWM_PPR_PERIOD_VALUE(r) FIELD_GET(...)
> #define SUN8I_PWN_PPR_PERIOD_MAX FIELD_MAX(...)
> #define SUN8I_PWM_PPR_DUTY(d) FIELD_PREP(...)
> #define SUN8I_PWM_PPR_DUTY_VALUE(r) FIELD_GET(...)
That's right, that would be less confusing.
>
>> +
>> +/* PWM Count Register */
>> +#define H616_PWM_CNT_REG(x) (0x68 + (x) * 0x20)
>> +
>> +/* PWM Capture Control Register */
>> +#define H616_PWM_CCR(x) (0x6c + (x) * 0x20)
>> +
>> +/* PWM Capture Rise Lock Register */
>> +#define H616_PWM_CRLR(x) (0x70 + (x) * 0x20)
>> +
>> +/* PWM Capture Fall Lock Register */
>> +#define H616_PWM_CFLR(x) (0x74 + (x) * 0x20)
>> +
>> +#define H616_PWM_PAIR_IDX(chan) ((chan) >> 2)
>> +
>> +/*
>> + * Block diagram of the PWM clock controller:
>> + *
>> + * _____ ______ ________
>> + * OSC24M --->| | | | | |
>> + * APB1 ----->| Mux |--->| Gate |--->| /div_m |-----> H616_PWM_clock_src_xy
>> + * |_____| |______| |________|
>> + * ________
>> + * | |
>> + * +->| /div_k |---> H616_PWM_clock_x
>> + * | |________|
>> + * | ______
>> + * | | |
>> + * +-->| Gate |----> H616_PWM_bypass_clock_x
>> + * | |______|
>> + * H616_PWM_clock_src_xy ----+ ________
>> + * | | |
>> + * +->| /div_k |---> H616_PWM_clock_y
>> + * | |________|
>> + * | ______
>> + * | | |
>> + * +-->| Gate |----> H616_PWM_bypass_clock_y
>> + * |______|
>> + *
>> + * NB: when the bypass is set, all the PWM logic is bypassed.
>> + * So, the duty cycle and polarity can't be modified (we just have a clock).
>> + * The bypass in PWM mode is used to achieve a 1/2 relative duty cycle with the
>> + * fastest clock.
>> + *
>> + * H616_PWM_clock_x/y serve for the PWM purpose.
>> + * H616_PWM_bypass_clock_x/y serve for the clock-provider purpose.
>> + *
>> + */
>> +
>> +/*
>> + * Table used for /div_m (diviser before obtaining H616_PWM_clock_src_xy)
>> + * It's actually CLK_DIVIDER_POWER_OF_TWO, but limited to /256
>> + */
>> +#define CLK_TABLE_DIV_M_ENTRY(i) { \
>> + .val = (i), .div = 1 << (i) \
>> +}
>> +
>> +static const struct clk_div_table clk_table_div_m[] = {
>> + CLK_TABLE_DIV_M_ENTRY(0),
>> + CLK_TABLE_DIV_M_ENTRY(1),
>> + CLK_TABLE_DIV_M_ENTRY(2),
>> + CLK_TABLE_DIV_M_ENTRY(3),
>> + CLK_TABLE_DIV_M_ENTRY(4),
>> + CLK_TABLE_DIV_M_ENTRY(5),
>> + CLK_TABLE_DIV_M_ENTRY(6),
>> + CLK_TABLE_DIV_M_ENTRY(7),
>> + CLK_TABLE_DIV_M_ENTRY(8),
>> + { /* sentinel */ }
>> +};
>> +
>> +#define H616_PWM_XY_SRC_GATE(_pair, _reg) \
>> +struct clk_gate gate_xy_##_pair = { \
>> + .reg = (void *)(_reg), \
>> + .bit_idx = H616_PWM_XY_CLK_CR_GATE_BIT, \
>> + .hw.init = &(struct clk_init_data){ \
>> + .ops = &clk_gate_ops, \
>> + } \
>> +}
>> +
>> +#define H616_PWM_XY_SRC_MUX(_pair, _reg) \
>> +struct clk_mux mux_xy_##_pair = { \
>> + .reg = (void *)(_reg), \
>> + .shift = H616_PWM_XY_CLK_CR_SRC_SHIFT, \
>> + .mask = H616_PWM_XY_CLK_CR_SRC_MASK, \
>> + .flags = CLK_MUX_ROUND_CLOSEST, \
>> + .hw.init = &(struct clk_init_data){ \
>> + .ops = &clk_mux_ops, \
>> + } \
>> +}
>> +
>> +#define H616_PWM_XY_SRC_DIV(_pair, _reg) \
>> +struct clk_divider rate_xy_##_pair = { \
>> + .reg = (void *)(_reg), \
>> + .shift = H616_PWM_XY_CLK_CR_DIV_M_SHIFT, \
>> + .table = clk_table_div_m, \
>> + .hw.init = &(struct clk_init_data){ \
>> + .ops = &clk_divider_ops, \
>> + } \
>> +}
>> +
>> +#define H616_PWM_X_DIV(_idx, _reg) \
>> +struct clk_divider rate_x_##_idx = { \
>> + .reg = (void *)(_reg), \
>> + .shift = H616_PWM_CTRL_PRESCAL_K_SHIFT, \
>> + .width = H616_PWM_CTRL_PRESCAL_K_WIDTH, \
>> + .hw.init = &(struct clk_init_data){ \
>> + .ops = &clk_divider_ops, \
>> + } \
>> +}
>> +
>> +#define H616_PWM_X_BYPASS_GATE(_idx) \
>> +struct clk_gate gate_x_bypass_##_idx = { \
>> + .reg = (void *)H616_PWM_ENR, \
>> + .bit_idx = _idx, \
>> + .hw.init = &(struct clk_init_data){ \
>> + .ops = &clk_gate_ops, \
>> + } \
>> +}
>> +
>> +#define H616_PWM_XY_CLK_SRC(_pair, _reg) \
>> + static H616_PWM_XY_SRC_MUX(_pair, _reg); \
>> + static H616_PWM_XY_SRC_GATE(_pair, _reg); \
>> + static H616_PWM_XY_SRC_DIV(_pair, _reg)
>> +
>> +#define H616_PWM_X_CLK(_idx) \
>> + static H616_PWM_X_DIV(_idx, H616_PWM_CTRL_REG(_idx))
>> +
>> +#define H616_PWM_X_BYPASS_CLK(_idx) \
>> + H616_PWM_X_BYPASS_GATE(_idx)
>> +
>> +#define REF_CLK_XY_SRC(_pair) \
>> + { \
>> + .name = "pwm-clk-src" #_pair, \
>> + .mux_hw = &mux_xy_##_pair.hw, \
>> + .gate_hw = &gate_xy_##_pair.hw, \
>> + .rate_hw = &rate_xy_##_pair.hw, \
>> + }
>> +
>> +#define REF_CLK_X(_idx, _pair) \
>> + { \
>> + .name = "pwm-clk" #_idx, \
>> + .parent_names = (const char *[]){ "pwm-clk-src" #_pair }, \
>> + .num_parents = 1, \
>> + .rate_hw = &rate_x_##_idx.hw, \
>> + .flags = CLK_SET_RATE_PARENT, \
>> + }
>> +
>> +#define REF_CLK_BYPASS(_idx, _pair) \
>> + { \
>> + .name = "pwm-clk-bypass" #_idx, \
>> + .parent_names = (const char *[]){ "pwm-clk-src" #_pair }, \
>> + .num_parents = 1, \
>> + .gate_hw = &gate_x_bypass_##_idx.hw, \
>> + .flags = CLK_SET_RATE_PARENT, \
>> + }
>> +
>> +/*
>> + * H616_PWM_clock_src_xy generation:
>> + * _____ ______ ________
>> + * OSC24M --->| | | | | |
>> + * APB1 ----->| Mux |--->| Gate |--->| /div_m |-----> H616_PWM_clock_src_xy
>> + * |_____| |______| |________|
>> + */
>> +H616_PWM_XY_CLK_SRC(01, H616_PWM_XY_CLK_CR(0));
>> +H616_PWM_XY_CLK_SRC(23, H616_PWM_XY_CLK_CR(1));
>> +H616_PWM_XY_CLK_SRC(45, H616_PWM_XY_CLK_CR(2));
>> +
>> +/*
>> + * H616_PWM_clock_x_div generation:
>> + * ________
>> + * | | H616_PWM_clock_x/y
>> + * H616_PWM_clock_src_xy --->| /div_k |--------------->
>> + * |________|
>> + */
>> +H616_PWM_X_CLK(0);
>> +H616_PWM_X_CLK(1);
>> +H616_PWM_X_CLK(2);
>> +H616_PWM_X_CLK(3);
>> +H616_PWM_X_CLK(4);
>> +H616_PWM_X_CLK(5);
>> +
>> +/*
>> + * H616_PWM_bypass_clock_xy generation:
>> + * ______
>> + * | |
>> + * H616_PWM_clock_src_xy ---->| Gate |-------> H616_PWM_bypass_clock_x
>> + * |______|
>> + *
>> + * The gate is actually H616_PWM_ENR register.
>> + */
>> +H616_PWM_X_BYPASS_CLK(0);
>> +H616_PWM_X_BYPASS_CLK(1);
>> +H616_PWM_X_BYPASS_CLK(2);
>> +H616_PWM_X_BYPASS_CLK(3);
>> +H616_PWM_X_BYPASS_CLK(4);
>> +H616_PWM_X_BYPASS_CLK(5);
>> +
>> +struct clk_pwm_data {
>> + const char *name;
>> + const char **parent_names;
>> + unsigned int num_parents;
>> + struct clk_hw *mux_hw;
>> + struct clk_hw *rate_hw;
>> + struct clk_hw *gate_hw;
>> + unsigned long flags;
>> +};
>> +
>> +#define CLK_BYPASS(h616chip, ch) ((h616chip)->data->npwm + (ch))
>> +#define CLK_XY_SRC_IDX(h616chip, ch) ((h616chip)->data->npwm * 2 + ((ch) >> 1))
>> +static struct clk_pwm_data pwmcc_data[] = {
>> + REF_CLK_X(0, 01),
>> + REF_CLK_X(1, 01),
>> + REF_CLK_X(2, 23),
>> + REF_CLK_X(3, 23),
>> + REF_CLK_X(4, 45),
>> + REF_CLK_X(5, 45),
>> + REF_CLK_BYPASS(0, 01),
>> + REF_CLK_BYPASS(1, 01),
>> + REF_CLK_BYPASS(2, 23),
>> + REF_CLK_BYPASS(3, 23),
>> + REF_CLK_BYPASS(4, 45),
>> + REF_CLK_BYPASS(5, 45),
>> + REF_CLK_XY_SRC(01),
>> + REF_CLK_XY_SRC(23),
>> + REF_CLK_XY_SRC(45),
>> + { /* sentinel */ }
>> +};
>
> We'll probably need a way to tie these static definitions to a particular
> instance of the unit for a given chip. But I guess that can be done later
> when adding more chips to the driver.
>
> I'm not too versed in the clk and pwm APIs but the rest generally looks good
> to me.
Thanks!
>
> All the best,
>
> Paul
>
^ permalink raw reply
* Re: [PATCH v4 2/4] pwm: sun50i: Add H616 PWM support
From: Richard GENOUD @ 2026-04-16 7:57 UTC (permalink / raw)
To: bigunclemax
Cc: conor+dt, devicetree, jernej.skrabec, joao, jstultz, krzk+dt,
linux-arm-kernel, linux-kernel, linux-pwm, linux-sunxi, p.zabel,
paulk, robh, samuel, thomas.petazzoni, u.kleine-koenig, wens
In-Reply-To: <20260413123920.2459916-1-bigunclemax@gmail.com>
Le 13/04/2026 à 14:39, bigunclemax@gmail.com a écrit :
> Hi Richard,
>
>> +
>> +/* PWM Capture Fall Lock Register */
>> +#define H616_PWM_CFLR(x) (0x74 + (x) * 0x20)
>> +
>> +#define H616_PWM_PAIR_IDX(chan) ((chan) >> 2)
>> +
>
> It looks like there's a typo or a mistake in the PAIR_IDX calculation.
> It should be like ((chan) >> 1).
> For example, for the 5th channel the result will be 1, but it should be 2.
Good catch!
I mainly tested with PWM1 as it's the only one easily accessible with a
scope.
I'll change that in the next iteration.
Thanks!
>
> Best regards
> Maksim
>
^ permalink raw reply
* Re: [PATCH 1/6] drm/connector: report IRQ_HPD events to drm_connector_oob_hotplug_event()
From: Tomi Valkeinen @ 2026-04-16 8:10 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: dri-devel, linux-kernel, linux-usb, intel-gfx, intel-xe,
linux-amlogic, linux-arm-kernel, linux-arm-msm, freedreno,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Heikki Krogerus, Greg Kroah-Hartman, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Adrien Grassein, Jani Nikula, Rodrigo Vivi,
Joonas Lahtinen, Tvrtko Ursulin, Kevin Hilman, Jerome Brunet,
Martin Blumenstingl, Rob Clark, Dmitry Baryshkov, Abhinav Kumar,
Jessica Zhang, Sean Paul, Marijn Suijten, Bjorn Andersson,
Konrad Dybcio, Pengyu Luo, Nikita Travkin, Yongxing Mou
In-Reply-To: <20260416-hpd-irq-events-v1-1-1ab1f1cfb2b2@oss.qualcomm.com>
Hi,
On 16/04/2026 02:22, Dmitry Baryshkov wrote:
> The DisplayPort standard defines a special kind of events called IRQ.
> These events are used to notify DP Source about the events on the Sink
> side. It is extremely important for DP MST handling, where the MST
> events are reported through this IRQ.
>
> In case of the USB-C DP AltMode there is no actual HPD pulse, but the
> events are ported through the bits in the AltMode VDOs.
>
> Extend the drm_connector_oob_hotplug_event() interface and report IRQ
> events to the DisplayPort Sink drivers.
>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> ---
> drivers/gpu/drm/drm_connector.c | 4 +++-
> drivers/usb/typec/altmodes/displayport.c | 12 ++++++++----
> include/drm/drm_connector.h | 3 ++-
> 3 files changed, 13 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> index 47dc53c4a738..5fdacbd84bd7 100644
> --- a/drivers/gpu/drm/drm_connector.c
> +++ b/drivers/gpu/drm/drm_connector.c
> @@ -3510,6 +3510,7 @@ struct drm_connector *drm_connector_find_by_fwnode(struct fwnode_handle *fwnode)
> * drm_connector_oob_hotplug_event - Report out-of-band hotplug event to connector
> * @connector_fwnode: fwnode_handle to report the event on
> * @status: hot plug detect logical state
> + * @irq_hpd: HPD pulse detected
> *
> * On some hardware a hotplug event notification may come from outside the display
> * driver / device. An example of this is some USB Type-C setups where the hardware
> @@ -3520,7 +3521,8 @@ struct drm_connector *drm_connector_find_by_fwnode(struct fwnode_handle *fwnode)
> * a drm_connector reference through calling drm_connector_find_by_fwnode().
> */
> void drm_connector_oob_hotplug_event(struct fwnode_handle *connector_fwnode,
> - enum drm_connector_status status)
> + enum drm_connector_status status,
> + bool irq_hpd)
I find the "IRQ HPD" naming always confusing, even if I'm somewhat
familiar with DP, but if someone has mainly worked on HDMI, I'm sure
it's even worse.
Can we define this a bit more precisely? Is 'irq_hpd' only for
displayport? If so, perhaps 'dp_irq_hpd' or 'displayport_irq_hpd'. I
might even call it 'dp_hpd_pulse', but maybe that's not good as the spec
talks about HPD pulse for both short and long ones (although in the
kernel doc you just write "HPD pulse")... The kernel doc could be
expanded a bit to make it clear what this flag indicates.
Tomi
^ permalink raw reply
* Re: [PATCH net,v2 1/1] net: stmmac: Update default_an_inband before passing value to phylink_config
From: Paolo Abeni @ 2026-04-16 8:12 UTC (permalink / raw)
To: KhaiWenTan, andrew+netdev, davem, edumazet, kuba, mcoquelin.stm32,
alexandre.torgue, rmk+kernel, maxime.chevallier, ovidiu.panait.rb,
vladimir.oltean
Cc: netdev, linux-stm32, linux-arm-kernel, linux-kernel,
yoong.siang.song, hong.aun.looi, khai.wen.tan
In-Reply-To: <20260413020339.68426-1-khai.wen.tan@linux.intel.com>
On 4/13/26 4:03 AM, KhaiWenTan wrote:
> get_interfaces() will update both the plat->phy_interfaces and
> mdio_bus_data->default_an_inband based on reading a SERDES register. As
> get_interfaces() will be called after default_an_inband had already been
> read, dwmac-intel regressed as a result with incorrect default_an_inband
> value in phylink_config.
>
> Therefore, we moved the priv->plat->get_interfaces() to be executed first
> before assigning mdio_bus_data->default_an_inband to
> config->default_an_inband to ensure default_an_inband is in correct value.
>
> Fixes: d3836052fe09 ("net: stmmac: intel: convert speed_mode_2500() to get_interfaces()")
> Signed-off-by: KhaiWenTan <khai.wen.tan@linux.intel.com>
Since Jakub sent the net-next PR and forwarded the trees, this patch
does not apply anymore. Please rebase and repost. You can retain
Russell's reviewed-by tag.
Thanks,
Paolo
^ permalink raw reply
* Re: [PATCH net,v2 1/1] net: stmmac: Update default_an_inband before passing value to phylink_config
From: KhaiWenTan @ 2026-04-16 8:22 UTC (permalink / raw)
To: Paolo Abeni, andrew+netdev, davem, edumazet, kuba,
mcoquelin.stm32, alexandre.torgue, rmk+kernel, maxime.chevallier,
ovidiu.panait.rb, vladimir.oltean
Cc: netdev, linux-stm32, linux-arm-kernel, linux-kernel,
yoong.siang.song, hong.aun.looi, khai.wen.tan
In-Reply-To: <72d1b0b7-c8df-463e-a2d9-bf5ff04ba33c@redhat.com>
On 4/16/2026 4:12 PM, Paolo Abeni wrote:
> On 4/13/26 4:03 AM, KhaiWenTan wrote:
>> get_interfaces() will update both the plat->phy_interfaces and
>> mdio_bus_data->default_an_inband based on reading a SERDES register. As
>> get_interfaces() will be called after default_an_inband had already been
>> read, dwmac-intel regressed as a result with incorrect default_an_inband
>> value in phylink_config.
>>
>> Therefore, we moved the priv->plat->get_interfaces() to be executed first
>> before assigning mdio_bus_data->default_an_inband to
>> config->default_an_inband to ensure default_an_inband is in correct value.
>>
>> Fixes: d3836052fe09 ("net: stmmac: intel: convert speed_mode_2500() to get_interfaces()")
>> Signed-off-by: KhaiWenTan <khai.wen.tan@linux.intel.com>
> Since Jakub sent the net-next PR and forwarded the trees, this patch
> does not apply anymore. Please rebase and repost. You can retain
> Russell's reviewed-by tag.
>
> Thanks,
>
> Paolo
Thank you Paolo, will be rebasing the patch and update a v3.
^ permalink raw reply
* Re: [PATCH v4 0/4] Introduce Allwinner H616 PWM controller
From: Richard GENOUD @ 2026-04-16 8:22 UTC (permalink / raw)
To: Paul Kocialkowski
Cc: Uwe Kleine-König, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Chen-Yu Tsai, Jernej Skrabec, Samuel Holland,
Philipp Zabel, Thomas Petazzoni, John Stultz, Joao Schim,
linux-pwm, devicetree, linux-arm-kernel, linux-sunxi,
linux-kernel
In-Reply-To: <adfe2z2YeBxm_6oR@shepard>
Le 09/04/2026 à 19:16, Paul Kocialkowski a écrit :
> Hi Richard,
>
> On Thu 05 Mar 26, 10:19, Richard Genoud wrote:
>> Allwinner H616 PWM controller is quite different from the A10 one.
>
> As I've mentionned before, this PWM controller is not specific to the H616
> but also appears in other chips, so the name of the driver and registers
> should not mention H616.
>
> After further investigation, I can see multiple versions of this new PWM IP
> being used in different chips, starting with the R40/V40 (sun8iw11) in 2016.
>
> The latest downstream BSP driver has a list of the different generations:
> https://github.com/radxa/allwinner-bsp/blob/cubie-aiot-v1.4.6/drivers/pwm/pwm-sunxi.c#L1901
>
> We have a first generation called v100/v101 for the following chips:
> H616, R328 and R40. A second generation is called v200 and brings slight
> register layout differences for A133, D1/T113-S3 and V851. Subsequent
> iterations (v201-5) are used in more recent chips like A527 and A733 and
> seem register-compatible with v200 (from a quick look).
>
> So what I suggest here is to rename the driver "sun8i-pwm" and eventually add
> a list of generations to the driver and different registers when needed, with
> an appropriate suffix in their name.
>
> But since you're currently only dealing with H616, this work can be done later
> when introducing support for more chips.
ok, I'm fine with that :)
>
>> It can drive 6 PWM channels, and like for the A10, each channel has a
>> bypass that permits to output a clock, bypassing the PWM logic, when
>> enabled.
>>
>> But, the channels are paired 2 by 2, sharing a first set of
>> MUX/prescaler/gate.
>> Then, for each channel, there's another prescaler (that will be bypassed
>> if the bypass is enabled for this channel).
>>
>> It looks like that:
>> _____ ______ ________
>> OSC24M --->| | | | | |
>> APB1 ----->| Mux |--->| Gate |--->| /div_m |-----> PWM_clock_src_xy
>> |_____| |______| |________|
>> ________
>> | |
>> +->| /div_k |---> PWM_clock_x
>> | |________|
>> | ______
>> | | |
>> +-->| Gate |----> PWM_bypass_clock_x
>> | |______|
>> PWM_clock_src_xy -----+ ________
>> | | |
>> +->| /div_k |---> PWM_clock_y
>> | |________|
>> | ______
>> | | |
>> +-->| Gate |----> PWM_bypass_clock_y
>> |______|
>>
>> Where xy can be 0/1, 2/3, 4/5
>>
>> PWM_clock_x/y serve for the PWM purpose.
>> PWM_bypass_clock_x/y serve for the clock-provider purpose.
>> The common clock framework has been used to manage those clocks.
>>
>> This PWM driver serves as a clock-provider for PWM_bypass_clocks.
>> This is needed for example by the embedded AC300 PHY which clock comes
>> from PMW5 pin (PB12).
>>
>> Usually, to get a clock from a PWM driver, we use the pwm-clock driver
>> so that the PWM driver doesn't need to be a clk-provider itself.
>> While this works in most cases, here it just doesn't.
>> That's because the pwm-clock request a period from the PWM driver,
>> without any clue that it actually wants a clock at a specific frequency,
>> and not a PWM signal with duty cycle capability.
>
> From what I understand the pwm-clock driver will either assume a fixed rate
> set in device-tree or deduce the rate from the pwm period. In any case it will
> check that the pwm period (which it cannot change) is the same as the requested
> clock period.
>
> So I agree that pwm-clock is unable to change the clock rate at runtime and will
> just use whatever frequency the pwm is running at (which is typically set
> in the device-tree consumer property).
>
>> So, the PWM driver doesn't know if it can use the bypass or not, it
>> doesn't even have the real accurate frequency information (23809524 Hz
>> instead of 24MHz) because PWM drivers only deal with periods.
>
> I agree that the driver needs to register as a proper clock provider in
> addition to pwm. But what happens if the same PWM clock is requested both from
> the clk side and the pwm side?
The first to request it is the winner :)
The other ones will receive a -EBUSY
In h616_pwm_request() and h616_pwm_of_clk_get(), the channel mode is
checked, and if it's free to use, it's set as either PWM or CLK mode so
that it can't be requested a second time.
>
>> With pwm-clock, we loose a precious information along the way (that we
>> actually want a clock and not a PWM signal).
>> That's ok with simple PWM drivers that don't have multiple input clocks,
>> but in this case, without this information, we can't know for sure which
>> clock to use.
>> And here, for instance, if we ask for a 24MHz clock, pwm-clock will
>> requests 42ns (assigned-clocks doesn't help for that matter). The logic
>> is to select the highest clock (100MHz) with no prescaler and a duty
>> cycle value of 2/4 => we have 25MHz instead of 24MHz.
>> And that's a perfectly fine choice for a PMW, because we still can
>> change the duty cycle in the range [0-4]/4.
>> But obviously for a clock, we don't care about the duty cycle, but more
>> about the clock accuracy.
>>
>> And actually, this PWM is really a PWM AND a real clock when the bypass
>> is set.
>
> Make sense to me.
>
>> This series is based onto v6.19-rc4
>>
>> NB: checkpatch is not happy with patch 2, but it's a false positive.
>> It doesn't detect that PWM_XY_SRC_MUX/GATE/DIV are structures, but as
>> it's more readable like that, I prefer keeping it that way.
>>
>> NB2: for geopolitical reasons, I didn't re-use the old series that Paul
>> was referring to.
>>
>> Changes since v3:
>> - gather Acked-by/Tested-by
>> - fix cast from pointer to integer of different size (kernel test robot
>> with arc platform)
>> - add devm_action for clk_hw_unregister_composite as suggested by Philipp
>> - remove now unused pwm_remove as suggested by Philipp
>>
>> Changes since v2:
>> - use U32_MAX instead of defining UINT32_MAX
>> - add a comment on U32_MAX usage in clk_round_rate()
>> - change clk_table_div_m (use macros)
>> - fix formatting (double space, superfluous comma, extra line feed)
>> - fix the parent clock order
>> - simplify code by using scoped_guard()
>> - add missing const in to_h616_pwm_chip() and rename to
>> h616_pwm_from_chip()
>> - add/remove missing/superflous error messages
>> - rename cnt->period_ticks, duty_cnt->duty_ticks
>> - fix PWM_PERIOD_MAX
>> - add .remove() callback
>> - fix DIV_ROUND_CLOSEST_ULL->DIV_ROUND_UP_ULL
>> - add H616_ prefix
>> - protect _reg in macros
>> - switch to waveforms instead of apply/get_state
>> - shrink struct h616_pwm_channel
>> - rebase on v6.19-rc4
>>
>> Changes since v1:
>> - rebase onto v6.19-rc1
>> - add missing headers
>> - remove MODULE_ALIAS (suggested by Krzysztof)
>> - use sun4i-pwm binding instead of creating a new one (suggested by Krzysztof)
>> - retrieve the parent clocks from the devicetree
>> - switch num_parents to unsigned int
>>
>> Richard Genoud (4):
>> dt-bindings: pwm: allwinner: add h616 pwm compatible
>> pwm: sun50i: Add H616 PWM support
>> arm64: dts: allwinner: h616: add PWM controller
>> MAINTAINERS: Add entry on Allwinner H616 PWM driver
>>
>> .../bindings/pwm/allwinner,sun4i-a10-pwm.yaml | 19 +-
>> MAINTAINERS | 5 +
>> .../arm64/boot/dts/allwinner/sun50i-h616.dtsi | 47 +
>> drivers/pwm/Kconfig | 12 +
>> drivers/pwm/Makefile | 1 +
>> drivers/pwm/pwm-sun50i-h616.c | 936 ++++++++++++++++++
>> 6 files changed, 1019 insertions(+), 1 deletion(-)
>> create mode 100644 drivers/pwm/pwm-sun50i-h616.c
>>
>>
>> base-commit: 11439c4635edd669ae435eec308f4ab8a0804808
>
Regards,
Richard
^ permalink raw reply
* Re: [PATCH v2 1/8] dt-bindings: mfd: khadas: Add new compatible for Khadas VIM4 MCU
From: Ronald Claveau @ 2026-04-16 8:25 UTC (permalink / raw)
To: Rob Herring
Cc: Neil Armstrong, Lee Jones, Krzysztof Kozlowski, Conor Dooley,
Andi Shyti, Kevin Hilman, Jerome Brunet, Martin Blumenstingl,
Beniamino Galvani, Rafael J. Wysocki, Daniel Lezcano, Zhang Rui,
Lukasz Luba, Liam Girdwood, Mark Brown, linux-amlogic, devicetree,
linux-kernel, linux-i2c, linux-arm-kernel, linux-pm
In-Reply-To: <20260415214815.GA602572-robh@kernel.org>
On 4/15/26 11:48 PM, Rob Herring wrote:
> On Fri, Apr 03, 2026 at 06:08:34PM +0200, Ronald Claveau wrote:
>> The Khadas VIM4 MCU register is slightly different
>> from previous boards' MCU.
>> This board also features a switchable power source for its fan.
>>
>> Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
>> ---
>> Documentation/devicetree/bindings/mfd/khadas,mcu.yaml | 5 +++++
>> 1 file changed, 5 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml b/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml
>> index 084960fd5a1fd..67769ef5d58b1 100644
>> --- a/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml
>> +++ b/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml
>> @@ -18,6 +18,7 @@ properties:
>> compatible:
>> enum:
>> - khadas,mcu # MCU revision is discoverable
>
> The revision is no longer discoverable as was claimed?
>
The firmware revision is still discoverable, and via the same register,
but the VIM4 MCU has a different register layout (eg: no DEVICE_NO
register). The new compatible is needed to describe a different MCU
variant, not a different revision of the same MCU.
I will remove the comment as it is confusing with new boards.
>> + - khadas,vim4-mcu
>>
>> "#cooling-cells": # Only needed for boards having FAN control feature
>> const: 2
>> @@ -25,6 +26,10 @@ properties:
>> reg:
>> maxItems: 1
>>
>> + fan-supply:
>> + description: Phandle to the regulator that powers the fan.
>> + $ref: /schemas/types.yaml#/definitions/phandle
>> +
>> required:
>> - compatible
>> - reg
>>
>> --
>> 2.49.0
>>
--
Best regards,
Ronald
^ permalink raw reply
* [PATCH] serial: mxs-auart: Compare the return value of gpiod_get_direction against GPIO_LINE_DIRECTION_IN
From: Nikola Z. Ivanov @ 2026-04-16 8:32 UTC (permalink / raw)
To: gregkh, jirislaby, Frank.Li, s.hauer, kernel, festevam
Cc: linux-kernel, linux-serial, imx, linux-arm-kernel,
Nikola Z. Ivanov
The GPIO_LINE_DIRECTION_* definitions have just recently been exposed to
gpio consumers.h by breaking them out in a separate defs.h file.
Use this to validate the gpio direction instead of the hard-coded literal.
Signed-off-by: Nikola Z. Ivanov <zlatistiv@gmail.com>
---
drivers/tty/serial/mxs-auart.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index cc65c9fb6446..6c6df4d5c21f 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -1519,7 +1519,7 @@ static int mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev)
for (i = 0; i < UART_GPIO_MAX; i++) {
gpiod = mctrl_gpio_to_gpiod(s->gpios, i);
- if (gpiod && (gpiod_get_direction(gpiod) == 1))
+ if (gpiod && (gpiod_get_direction(gpiod) == GPIO_LINE_DIRECTION_IN))
s->gpio_irq[i] = gpiod_to_irq(gpiod);
else
s->gpio_irq[i] = -EINVAL;
--
2.53.0
^ permalink raw reply related
* Re: [PATCH net] net: airoha: Fix possible TX queue stall in airoha_qdma_tx_napi_poll()
From: Paolo Abeni @ 2026-04-16 8:44 UTC (permalink / raw)
To: Lorenzo Bianconi, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski
Cc: linux-arm-kernel, linux-mediatek, netdev
In-Reply-To: <20260413-airoha-txq-potential-stall-v1-1-7830363b1543@kernel.org>
On 4/13/26 10:29 AM, Lorenzo Bianconi wrote:
> Since multiple net_device TX queues can share the same hw QDMA TX queue,
> there is no guarantee we have inflight packets queued in hw belonging to a
> net_device TX queue stopped in the xmit path because hw QDMA TX queue
> can be full. In this corner case the net_device TX queue will never be
> re-activated. In order to avoid any potential net_device TX queue stall,
> we need to wake all the net_device TX queues feeding the same hw QDMA TX
> queue in airoha_qdma_tx_napi_poll routine.
>
> Fixes: 23020f0493270 ("net: airoha: Introduce ethernet support for EN7581 SoC")
> Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
> ---
> drivers/net/ethernet/airoha/airoha_eth.c | 30 ++++++++++++++++++++++++++----
> 1 file changed, 26 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
> index 9e995094c32a..e7610f36b8e4 100644
> --- a/drivers/net/ethernet/airoha/airoha_eth.c
> +++ b/drivers/net/ethernet/airoha/airoha_eth.c
> @@ -855,6 +855,19 @@ static int airoha_qdma_init_rx(struct airoha_qdma *qdma)
> return 0;
> }
>
> +static void airoha_qdma_wake_tx_queues(struct airoha_qdma *qdma)
> +{
> + struct airoha_eth *eth = qdma->eth;
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
> + struct airoha_gdm_port *port = eth->ports[i];
> +
> + if (port && port->qdma == qdma)
> + netif_tx_wake_all_queues(port->dev);
> + }
> +}
> +
> static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget)
> {
> struct airoha_tx_irq_queue *irq_q;
> @@ -931,12 +944,21 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget)
>
> txq = netdev_get_tx_queue(skb->dev, queue);
> netdev_tx_completed_queue(txq, 1, skb->len);
> - if (netif_tx_queue_stopped(txq) &&
> - q->ndesc - q->queued >= q->free_thr)
> - netif_tx_wake_queue(txq);
> -
> dev_kfree_skb_any(skb);
> }
> +
> + if (q->ndesc - q->queued == q->free_thr) {
Sashiko says:
---
Can this exact equality check cause a permanent TX queue stall?
The previous logic checked if the free space was greater than or equal
to q->free_thr. If the xmit path stops the queue because the free space
drops to exactly q->free_thr, the hardware queue will have exactly
q->free_thr free slots.
When the NAPI poll routine subsequently reaps a completed descriptor,
q->queued is decremented, increasing the free space to q->free_thr + 1.
Since the free space is no longer exactly equal to the threshold, this
condition evaluates to false.
As NAPI continues to reap more descriptors, the free space strictly
increases, meaning the exact equality check will never evaluate to true
and the netdev TX queue will remain permanently stalled.
---
Please, try to triage sashiko comments proactively. Especially on NIC
drivers, validating the AI statements is extremely cumbersome for the
maintainers.
Thanks,
Paolo
^ permalink raw reply
* [PATCH v2 1/3] arm64: dts: amlogic: t7: Add uart_c pinctrl pins group
From: Ronald Claveau @ 2026-04-16 8:54 UTC (permalink / raw)
To: Neil Armstrong, Kevin Hilman, Jerome Brunet, Martin Blumenstingl,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-arm-kernel, linux-amlogic, devicetree, linux-kernel,
Ronald Claveau
In-Reply-To: <20260416-add-bluetooth-t7-vim4-v2-0-9a57098fd055@aliel.fr>
Add the pin multiplexing configuration for UART C (TX, RX, CTS, RTS)
in the T7 SoC pinctrl node, required to route the UART C signals
through the correct pads before enabling the controller.
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
index 7fe72c94ed623..4a55d9641bc9b 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
+++ b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
@@ -553,6 +553,18 @@ mux {
bias-pull-up;
};
};
+
+ uart_c_pins: uart-c {
+ mux {
+ groups = "uart_c_tx",
+ "uart_c_rx",
+ "uart_c_cts",
+ "uart_c_rts";
+ bias-pull-up;
+ output-high;
+ function = "uart_c";
+ };
+ };
};
gpio_intc: interrupt-controller@4080 {
--
2.49.0
^ permalink raw reply related
* [PATCH v2 3/3] arm64: dts: amlogic: t7: khadas-vim4: Enable Bluetooth
From: Ronald Claveau @ 2026-04-16 8:54 UTC (permalink / raw)
To: Neil Armstrong, Kevin Hilman, Jerome Brunet, Martin Blumenstingl,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-arm-kernel, linux-amlogic, devicetree, linux-kernel,
Ronald Claveau
In-Reply-To: <20260416-add-bluetooth-t7-vim4-v2-0-9a57098fd055@aliel.fr>
Enable UART C on the Khadas VIM4 board and attach the BCM43438
compatible Bluetooth controller to it. The node configures the RTS/CTS
hardware flow control, the associated pinmux, the power supplies (vddao_3v3
and vddao_1v8), the 32 kHz LPO clock shared with the wifi32k fixed
clock, and the GPIO lines used for host wakeup, device wakeup and
shutdown.
Remove clocks and clock-names for UART A, as they are defined in DTSI.
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
.../dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts | 21 +++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts b/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts
index 69d6118ba57e7..8ea7ae609fbd5 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts
+++ b/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts
@@ -250,6 +250,23 @@ &sd_emmc_c {
&uart_a {
status = "okay";
- clocks = <&xtal>, <&xtal>, <&xtal>;
- clock-names = "xtal", "pclk", "baud";
+};
+
+&uart_c {
+ status = "okay";
+ pinctrl-0 = <&uart_c_pins>;
+ pinctrl-names = "default";
+ uart-has-rtscts;
+
+ bluetooth {
+ compatible = "brcm,bcm43438-bt";
+ shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>;
+ host-wakeup-gpios = <&gpio GPIOX_18 GPIO_ACTIVE_HIGH>;
+ device-wakeup-gpios = <&gpio GPIOX_19 GPIO_ACTIVE_HIGH>;
+ max-speed = <3000000>;
+ clocks = <&wifi32k>;
+ clock-names = "lpo";
+ vbat-supply = <&vddao_3v3>;
+ vddio-supply = <&vddao_1v8>;
+ };
};
--
2.49.0
^ permalink raw reply related
* [PATCH v2 2/3] arm64: dts: amlogic: t7: Add UART controllers nodes
From: Ronald Claveau @ 2026-04-16 8:54 UTC (permalink / raw)
To: Neil Armstrong, Kevin Hilman, Jerome Brunet, Martin Blumenstingl,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-arm-kernel, linux-amlogic, devicetree, linux-kernel,
Ronald Claveau
In-Reply-To: <20260416-add-bluetooth-t7-vim4-v2-0-9a57098fd055@aliel.fr>
Add device tree nodes for UART B through F (serial@7a000 to
serial@82000), completing the UART controller description for the T7
SoC. Each node includes the peripheral clock.
While at it, move the uart_a node to its correct position in the
bus address order (0x78000) to comply with the DT requirement that
nodes be sorted by their reg address. Complete the
uart_a node with its peripheral clock (CLKID_SYS_UART_A) and the
associated clock-names, matching the vendor default clock assignment,
consistent with the other UART nodes.
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi | 61 +++++++++++++++++++++++++----
1 file changed, 54 insertions(+), 7 deletions(-)
diff --git a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
index 4a55d9641bc9b..81c26b1e3e7a4 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
+++ b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
@@ -577,13 +577,6 @@ gpio_intc: interrupt-controller@4080 {
<10 11 12 13 14 15 16 17 18 19 20 21>;
};
- uart_a: serial@78000 {
- compatible = "amlogic,t7-uart", "amlogic,meson-s4-uart";
- reg = <0x0 0x78000 0x0 0x18>;
- interrupts = <GIC_SPI 168 IRQ_TYPE_EDGE_RISING>;
- status = "disabled";
- };
-
gp0: clock-controller@8080 {
compatible = "amlogic,t7-gp0-pll";
reg = <0x0 0x8080 0x0 0x20>;
@@ -713,6 +706,60 @@ pwm_ao_cd: pwm@60000 {
status = "disabled";
};
+ uart_a: serial@78000 {
+ compatible = "amlogic,t7-uart", "amlogic,meson-s4-uart";
+ reg = <0x0 0x78000 0x0 0x18>;
+ interrupts = <GIC_SPI 168 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&xtal>, <&clkc_periphs CLKID_SYS_UART_A>, <&xtal>;
+ clock-names = "xtal", "pclk", "baud";
+ status = "disabled";
+ };
+
+ uart_b: serial@7a000 {
+ compatible = "amlogic,t7-uart", "amlogic,meson-s4-uart";
+ reg = <0x0 0x7a000 0x0 0x18>;
+ interrupts = <GIC_SPI 169 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&xtal>, <&clkc_periphs CLKID_SYS_UART_B>, <&xtal>;
+ clock-names = "xtal", "pclk", "baud";
+ status = "disabled";
+ };
+
+ uart_c: serial@7c000 {
+ compatible = "amlogic,t7-uart", "amlogic,meson-s4-uart";
+ reg = <0x0 0x7c000 0x0 0x18>;
+ interrupts = <GIC_SPI 170 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&xtal>, <&clkc_periphs CLKID_SYS_UART_C>, <&xtal>;
+ clock-names = "xtal", "pclk", "baud";
+ status = "disabled";
+ };
+
+ uart_d: serial@7e000 {
+ compatible = "amlogic,t7-uart", "amlogic,meson-s4-uart";
+ reg = <0x0 0x7e000 0x0 0x18>;
+ interrupts = <GIC_SPI 171 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&xtal>, <&clkc_periphs CLKID_SYS_UART_D>, <&xtal>;
+ clock-names = "xtal", "pclk", "baud";
+ status = "disabled";
+ };
+
+ uart_e: serial@80000 {
+ compatible = "amlogic,t7-uart", "amlogic,meson-s4-uart";
+ reg = <0x0 0x80000 0x0 0x18>;
+ interrupts = <GIC_SPI 172 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&xtal>, <&clkc_periphs CLKID_SYS_UART_E>, <&xtal>;
+ clock-names = "xtal", "pclk", "baud";
+ status = "disabled";
+ };
+
+ uart_f: serial@82000 {
+ compatible = "amlogic,t7-uart", "amlogic,meson-s4-uart";
+ reg = <0x0 0x82000 0x0 0x18>;
+ interrupts = <GIC_SPI 173 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&xtal>, <&clkc_periphs CLKID_SYS_UART_F>, <&xtal>;
+ clock-names = "xtal", "pclk", "baud";
+ status = "disabled";
+ };
+
sd_emmc_a: mmc@88000 {
compatible = "amlogic,t7-mmc", "amlogic,meson-axg-mmc";
reg = <0x0 0x88000 0x0 0x800>;
--
2.49.0
^ permalink raw reply related
* [PATCH v2 0/3] arm64: dts: amlogic: t7: Add UART support and enable Bluetooth on VIM4
From: Ronald Claveau @ 2026-04-16 8:54 UTC (permalink / raw)
To: Neil Armstrong, Kevin Hilman, Jerome Brunet, Martin Blumenstingl,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-arm-kernel, linux-amlogic, devicetree, linux-kernel,
Ronald Claveau
This series adds all UART controllers for the Amlogic T7 SoC and enables
the Bluetooth controller on the Khadas VIM4 board.
The T7 SoC ships with six UART controllers (A through F), but only
uart_a was previously described in the device tree.
- Patch 1 adds the pinctrl group for UART C, which is needed to route
its four signals (TX, RX, CTS, RTS) through the correct pads.
- Patch 2 completes the uart_a node (peripheral clock) and
repositions it to respect the ascending reg address order required
by the DT specification. It then adds nodes for UART B through F,
each with their respective peripheral clock.
- Patch 3 enables UART C on the Khadas VIM4 board and attaches the
on-board BCM43438 Bluetooth controller to it, with hardware flow
control, wakeup GPIOs, LPO clock and power supplies.
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
Changes in v2:
- PATCH 1: change underscore to dash in pin node name,
according to Xianwei's feedback.
- PATCH 3: remove clocks and clock-names as already defined in DTSI,
according to Xianwei's feedback.
- Link to v1: https://lore.kernel.org/r/20260415-add-bluetooth-t7-vim4-v1-0-0ba0746cc1d6@aliel.fr
---
Ronald Claveau (3):
arm64: dts: amlogic: t7: Add uart_c pinctrl pins group
arm64: dts: amlogic: t7: Add UART controllers nodes
arm64: dts: amlogic: t7: khadas-vim4: Enable Bluetooth
.../dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts | 21 ++++++-
arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi | 73 +++++++++++++++++++---
2 files changed, 85 insertions(+), 9 deletions(-)
---
base-commit: 6aa9edb4f8266cfb913ee74f5e55116550b5574d
change-id: 20260414-add-bluetooth-t7-vim4-f01e03c4ec2a
Best regards,
--
Ronald Claveau <linux-kernel-dev@aliel.fr>
^ permalink raw reply
* Re: [PATCH v3 4/6] dt-bindings: soc: mediatek: devapc: Add bindings for MT8189
From: Krzysztof Kozlowski @ 2026-04-16 8:56 UTC (permalink / raw)
To: Xiaoshun Xu
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, devicetree, linux-kernel,
linux-arm-kernel, linux-mediatek, Sirius Wang, Vince-wl Liu,
Project_Global_Chrome_Upstream_Group
In-Reply-To: <20260416031231.2932493-5-xiaoshun.xu@mediatek.com>
On Thu, Apr 16, 2026 at 11:12:07AM +0800, Xiaoshun Xu wrote:
> Extend the devapc device tree bindings to support the MediaTek MT8189
> SoC. This includes:
>
> - Adding "mediatek,mt8189-devapc" to the list of compatible strings.
> - Introducing the "vio-idx-num" property to specify the number of bus
> slaves managed by devapc.
>
> These changes enable proper configuration and integration of devapc on
> MT8189 platforms, ensuring accurate device matching and resource
> allocation in the device tree.
Pointless paragraph. Would you write a commit which does not enable
proper configuration?
>
> Signed-off-by: Xiaoshun Xu <xiaoshun.xu@mediatek.com>
> ---
> .../devicetree/bindings/soc/mediatek/devapc.yaml | 10 +++++++---
> 1 file changed, 7 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/soc/mediatek/devapc.yaml b/Documentation/devicetree/bindings/soc/mediatek/devapc.yaml
> index 99e2caafeadf..06a096440331 100644
> --- a/Documentation/devicetree/bindings/soc/mediatek/devapc.yaml
> +++ b/Documentation/devicetree/bindings/soc/mediatek/devapc.yaml
> @@ -14,13 +14,14 @@ description: |
> analysis and countermeasures.
>
> maintainers:
> - - Neal Liu <neal.liu@mediatek.com>
Your commit said what the change is doing. It's pointless because we see
it in the diff. Except that we don't...
> + - Xiaoshun Xu <xiaoshun.xu@mediatek.com>
>
> properties:
> compatible:
> enum:
> - mediatek,mt6779-devapc
> - mediatek,mt8186-devapc
> + - mediatek,mt8189-devapc
>
> reg:
> description: The base address of devapc register bank
> @@ -30,6 +31,10 @@ properties:
> description: A single interrupt specifier
> maxItems: 1
>
> + vio-idx-num:
Nah, compatible defines it. Please follow standard rules for bindings,
see writing-bindings doc.
> + description: Describe the number of bus slaves controlled by devapc
> + $ref: /schemas/types.yaml#/definitions/uint32
> +
> clocks:
> description: Contains module clock source and clock names
> maxItems: 1
> @@ -42,8 +47,6 @@ required:
> - compatible
> - reg
> - interrupts
> - - clocks
> - - clock-names
Why?
This commit explains nothing and makes some random-looking code changes.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v3 6/6] dt-bindings: soc: mediatek: devapc: Add bindings for MT8196
From: Krzysztof Kozlowski @ 2026-04-16 8:58 UTC (permalink / raw)
To: Xiaoshun Xu
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, devicetree, linux-kernel,
linux-arm-kernel, linux-mediatek, Sirius Wang, Vince-wl Liu,
Project_Global_Chrome_Upstream_Group
In-Reply-To: <20260416031231.2932493-7-xiaoshun.xu@mediatek.com>
On Thu, Apr 16, 2026 at 11:12:09AM +0800, Xiaoshun Xu wrote:
> Extend the devapc device tree bindings to support the MediaTek MT8196
> SoC. This includes:
>
> - Adding "mediatek,mt8196-devapc" to the list of compatible strings.
>
> These changes enable proper configuration and integration of devapc on
> MT8196 platforms, ensuring accurate device matching and resource
> allocation in the device tree.
Same comments. It's really poor commit msg.
Also, subject wrong. Drop second/last, redundant "bindings". The
"dt-bindings" prefix is already stating that these are bindings.
See also:
https://elixir.bootlin.com/linux/v6.17-rc3/source/Documentation/devicetree/bindings/submitting-patches.rst#L18
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH] arm_pmu: acpi: fix reference leak on failed device registration
From: Guangshuo Li @ 2026-04-16 8:59 UTC (permalink / raw)
To: Johan Hovold
Cc: Greg Kroah-Hartman, Mark Rutland, Will Deacon, Anshuman Khandual,
linux-arm-kernel, linux-perf-users, linux-kernel, stable
In-Reply-To: <aeCOdWLaVpH-5w8s@hovoldconsulting.com>
Hi Greg, Mark, Johan,
Thanks for the further comments.
On Thu, 16 Apr 2026 at 15:23, Johan Hovold <johan@kernel.org> wrote:
>
> On Thu, Apr 16, 2026 at 06:40:55AM +0200, Greg Kroah-Hartman wrote:
> > On Wed, Apr 15, 2026 at 07:19:06PM +0100, Mark Rutland wrote:
>
> > > AFAICT you're saying that the reference was taken *within*
> > > platform_device_register(), and then platform_device_register() itself
> > > has failed. I think it's surprising that platform_device_register()
> > > doesn't clean that up itself in the case of an error.
> > >
> > > There are *tonnes* of calls to platform_device_register() throughout the
> > > kernel that don't even bother to check the return value, and many that
> > > just pass the return onto a caller that can't possibly know to call
> > > platform_device_put().
> > >
> > > Code in the same file as platform_device_register() expects it to clean up
> > > after itself, e.g.
> > >
> > > | int platform_add_devices(struct platform_device **devs, int num)
> > > | {
> > > | int i, ret = 0;
> > > |
> > > | for (i = 0; i < num; i++) {
> > > | ret = platform_device_register(devs[i]);
> > > | if (ret) {
> > > | while (--i >= 0)
> > > | platform_device_unregister(devs[i]);
> > > | break;
> > > | }
> > > | }
> > > |
> > > | return ret;
> > > | }
> > >
> > > That's been there since the initial git commit, and back then,
> > > platform_device_register() didn't mention that callers needed to perform
> > > any cleanup.
> > >
> > > I see a comment was added to platform_device_register() in commit:
> > >
> > > 67e532a42cf4 ("driver core: platform: document registration-failure requirement")
> > >
> > > ... and that copied the commend added for device_register() in commit:
> > >
> > > 5739411acbaa ("Driver core: Clarify device cleanup.")
> > >
> > > ... but the potential brokenness is so widespread, and the behaviour is
> > > so surprising, that I'd argue the real but is that device_register()
> > > doesn't clean up in case of error. I don't think it's worth changing
> > > this single instance given the prevalance and churn fixing all of that
> > > would involve.
> > >
> > > I think it would be far better to fix the core driver API such that when
> > > those functions return an error, they've already cleaned up for
> > > themselves.
> > >
> > > Greg, am I missing some functional reason why we can't rework
> > > device_register() and friends to handle cleanup themselves? I appreciate
> > > that'll involve churn for some callers, but AFAICT the majority of
> > > callers don't have the required cleanup.
> >
> > Yes, we should fix the platform core code here, this should not be
> > required to do everywhere as obviously we all got it wrong.
>
> It's not just the platform code as this directly reflects the behaviour
> of device_register() as Mark pointed out.
>
> It is indeed an unfortunate quirk of the driver model, but one can argue
> that having a registration function that frees its argument on errors
> would be even worse. And even more so when many (or most) users get this
> right.
>
> So if we want to change this, I think we would need to deprecate
> device_register() in favour of explicit device_initialize() and
> device_add().
>
> That said, most users of platform_device_register() appear to operate
> on static platform devices which don't even have a release function and
> would trigger a WARN() if we ever drop the reference (which is arguably
> worse than leaking a tiny bit of memory).
>
> So leaving things as-is is also an option.
>
> Johan
I did some more investigation, and it looks like directly changing the
semantics of the existing API would break code that is already correct
today.
In particular, there seem to be at least two different kinds of callers:
Callers that already handle the failure path explicitly after
platform_device_register() fails. For these users, changing
platform_device_register() itself to drop the reference internally
would lead to double put / use-after-free issues.
Callers that operate on static struct platform_device objects. Many of
these do not have a release callback, so blindly dropping the
reference on failure would trigger a WARN.
Because of this, changing platform_device_register() itself to always
clean up on failure does not look safe.
One possible direction may be to leave platform_device_register()
unchanged, and instead add new helper APIs for the different cases.
For case (1), I was thinking of a helper like:
platform_device_register_and_put()
The implementation would simply call platform_device_register(), and if
that fails, call platform_device_put(). Callers converted to this helper
would then no longer perform their own put on the failure path.
For case (2), I was thinking of a helper like:
platform_device_register_static()
The implementation would first install a no-op release callback when
pdev->dev.release is not set, and then call
platform_device_register_and_put(). This would make the failure path
well-defined for static platform_device users, avoiding the reference
leak without triggering a WARN.
If this direction sounds reasonable, I would be happy to work on it and
send a patch, and I would also be very willing to help with the related
API conversion work for existing callers.
Thanks,
Guangshuo
^ permalink raw reply
* Re: [PATCH v2 2/3] dt-bindings: gpio: Add EIO GPIO compatible to gpio-zynq
From: Krzysztof Kozlowski @ 2026-04-16 9:06 UTC (permalink / raw)
To: Michal Simek
Cc: Conor Dooley, Shubhrajyoti Datta, linux-kernel, git,
shubhrajyoti.datta, Srinivas Neeli, Linus Walleij,
Bartosz Golaszewski, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-gpio, devicetree, linux-arm-kernel
In-Reply-To: <c973f9d4-9bb5-40f4-8f09-72e23f92cd2d@amd.com>
On Thu, Apr 16, 2026 at 07:58:27AM +0200, Michal Simek wrote:
>
>
> On 4/15/26 17:01, Conor Dooley wrote:
> > On Wed, Apr 15, 2026 at 04:26:27PM +0530, Shubhrajyoti Datta wrote:
> > > EIO (Extended IO) is a GPIO block found on xa2ve3288 silicon..
> >
> >
> > Why does the compatible have a "1.0" when it is in silicon?
>
> Sorry not following what the problem is. Yes this is hard block in silicon
> and it is silicon v1.
Writing bindings: compatibles should be specific to device, not some
arbitrary versioning.
OR explain in commit msg. That commit msg clealy suggests code is wrong.
>
> > Why doesn't the compatible contain "xa2ve3288"?
>
> This unit can be used on different silicons too.
That's not what the commit said.
>
> > Why is this device not compatible with existing ones, since
> > gpio-lines-names appears to be the sole difference?
>
> There is no way how to detect gpio width.
Where in the commit msg are the differences explained?
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH] crypto: tstmgr - guard xxhash tests
From: Herbert Xu @ 2026-04-16 9:06 UTC (permalink / raw)
To: Hamza Mahfooz
Cc: linux-crypto, David S. Miller, Maxime Coquelin, Alexandre Torgue,
linux-stm32, linux-arm-kernel, linux-kernel, Jeff Barnes,
Paul Monson
In-Reply-To: <adffSYxKIuaDLZit@linuxonhyperv3.guj3yctzbm1etfxqx2vob5hsef.xx.internal.cloudapp.net>
On Thu, Apr 09, 2026 at 10:18:01AM -0700, Hamza Mahfooz wrote:
>
> alg: hash: failed to allocate transform for xxhash64: -2
> Kernel panic - not syncing: alg: self-tests for xxhash64 (xxhash64) failed in fips mode!
> CPU: 0 PID: 425 Comm: modprobe Not tainted 6.6.130.2-2.azl3 #1
> Hardware name: Microsoft Corporation Virtual Machine/Virtual Machine, BIOS Hyper-V UEFI Release v4.1 01/08/2026
> Call Trace:
> <TASK>
> dump_stack_lvl+0x4c/0x70
> dump_stack+0x14/0x20
> panic+0x179/0x330
> alg_test+0x678/0x680
> ? __alloc_pages+0x1e2/0x340
> do_test+0x26f8/0x7670 [tcrypt]
So the error is coming from tcrypt. I think that's where the ifdef
should be added.
Thanks,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [PATCH] crypto: tstmgr - guard xxhash tests
From: Herbert Xu @ 2026-04-16 9:09 UTC (permalink / raw)
To: Hamza Mahfooz
Cc: linux-crypto, David S. Miller, Maxime Coquelin, Alexandre Torgue,
linux-stm32, linux-arm-kernel, linux-kernel, Jeff Barnes,
Paul Monson
In-Reply-To: <aeCmk6LbLFT4Keo2@gondor.apana.org.au>
On Thu, Apr 16, 2026 at 05:06:27PM +0800, Herbert Xu wrote:
>
> So the error is coming from tcrypt. I think that's where the ifdef
> should be added.
On second thought, fips_allowed should not mean that an algorithm
must be present.
So we should change it such that an -ENOENT is not fatal, or at least
when it's called from tcrypt.
Thanks,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [PATCH v2 0/9] driver core / pmdomain: Add support for fined grained sync_state
From: Geert Uytterhoeven @ 2026-04-16 9:15 UTC (permalink / raw)
To: Ulf Hansson
Cc: Saravana Kannan, Rafael J . Wysocki, Greg Kroah-Hartman, linux-pm,
Sudeep Holla, Cristian Marussi, Kevin Hilman, Stephen Boyd,
Marek Szyprowski, Bjorn Andersson, Abel Vesa, Peng Fan,
Tomi Valkeinen, Maulik Shah, Konrad Dybcio, Thierry Reding,
Jonathan Hunter, Dmitry Baryshkov, linux-arm-kernel, linux-kernel
In-Reply-To: <20260410104058.83748-1-ulf.hansson@linaro.org>
Hi Ulf,
On Fri, 10 Apr 2026 at 12:41, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> Since the introduction [1] of the common sync_state support for pmdomains
> (genpd), we have encountered a lot of various interesting problems. In most
> cases the new behaviour of genpd triggered some weird platform specific bugs.
>
> That said, in LPC in Tokyo me and Saravana hosted a session to walk through the
> remaining limitations that we have found for genpd's sync state support. In
> particular, we discussed the problems we have for the so-called onecell power
> domain providers, where a single provider typically provides multiple
> independent power domains, all with their own set of consumers.
>
> Note that, onecell power domain providers are very common. It's being used by
> many SoCs/platforms/technologies. To name a few:
> SCMI, Qualcomm, NXP, Mediatek, Renesas, TI, etc.
>
> Anyway, in these cases, the generic sync_state mechanism with fw_devlink isn't
> fine grained enough, as we end up waiting for all consumers for all power
> domains before the ->sync_callback gets called for the supplier/provider. In
> other words, we may end up keeping unused power domains powered-on, for no good
> reasons.
>
> The series intends to fix this problem. Please have a look at the commit
> messages for more details and help review/test!
Thanks for the update!
At first glance, the only real change compared to v1 seems to be
the removal of printing
pr_info("%s:%s con=%s\n", __func__, dev_name(dev),
dev_name(consumer));
Right?
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH] arm_pmu: acpi: fix reference leak on failed device registration
From: Mark Rutland @ 2026-04-16 9:30 UTC (permalink / raw)
To: Johan Hovold
Cc: Greg Kroah-Hartman, Guangshuo Li, Will Deacon, Anshuman Khandual,
linux-arm-kernel, linux-perf-users, linux-kernel, stable
In-Reply-To: <aeCOdWLaVpH-5w8s@hovoldconsulting.com>
On Thu, Apr 16, 2026 at 09:23:33AM +0200, Johan Hovold wrote:
> On Thu, Apr 16, 2026 at 06:40:55AM +0200, Greg Kroah-Hartman wrote:
> > On Wed, Apr 15, 2026 at 07:19:06PM +0100, Mark Rutland wrote:
>
> > > AFAICT you're saying that the reference was taken *within*
> > > platform_device_register(), and then platform_device_register() itself
> > > has failed. I think it's surprising that platform_device_register()
> > > doesn't clean that up itself in the case of an error.
> > >
> > > There are *tonnes* of calls to platform_device_register() throughout the
> > > kernel that don't even bother to check the return value, and many that
> > > just pass the return onto a caller that can't possibly know to call
> > > platform_device_put().
> > >
> > > Code in the same file as platform_device_register() expects it to clean up
> > > after itself, e.g.
> > >
> > > | int platform_add_devices(struct platform_device **devs, int num)
> > > | {
> > > | int i, ret = 0;
> > > |
> > > | for (i = 0; i < num; i++) {
> > > | ret = platform_device_register(devs[i]);
> > > | if (ret) {
> > > | while (--i >= 0)
> > > | platform_device_unregister(devs[i]);
> > > | break;
> > > | }
> > > | }
> > > |
> > > | return ret;
> > > | }
> > >
> > > That's been there since the initial git commit, and back then,
> > > platform_device_register() didn't mention that callers needed to perform
> > > any cleanup.
> > >
> > > I see a comment was added to platform_device_register() in commit:
> > >
> > > 67e532a42cf4 ("driver core: platform: document registration-failure requirement")
> > >
> > > ... and that copied the commend added for device_register() in commit:
> > >
> > > 5739411acbaa ("Driver core: Clarify device cleanup.")
> > >
> > > ... but the potential brokenness is so widespread, and the behaviour is
> > > so surprising, that I'd argue the real but is that device_register()
> > > doesn't clean up in case of error. I don't think it's worth changing
> > > this single instance given the prevalance and churn fixing all of that
> > > would involve.
> > >
> > > I think it would be far better to fix the core driver API such that when
> > > those functions return an error, they've already cleaned up for
> > > themselves.
> > >
> > > Greg, am I missing some functional reason why we can't rework
> > > device_register() and friends to handle cleanup themselves? I appreciate
> > > that'll involve churn for some callers, but AFAICT the majority of
> > > callers don't have the required cleanup.
> >
> > Yes, we should fix the platform core code here, this should not be
> > required to do everywhere as obviously we all got it wrong.
>
> It's not just the platform code as this directly reflects the behaviour
> of device_register() as Mark pointed out.
>
> It is indeed an unfortunate quirk of the driver model, but one can argue
> that having a registration function that frees its argument on errors
> would be even worse. And even more so when many (or most) users get this
> right.
Ah, sorry; I had missed that the _put() step would actually free the
object (and as you explain below, how that won't work for many callers).
> So if we want to change this, I think we would need to deprecate
> device_register() in favour of explicit device_initialize() and
> device_add().
Is is possible to have {platfom_,}device_uninitialize() functions that
does everything except the ->release() call? If we had that, then we'd
be able to have a flow along the lines of:
int some_init_function(void)
{
int err;
platform_device_init(&static_pdev);
err = platform_device_add(&static_pdev))
if (err)
goto out_uninit;
return 0;
out_uninit:
platform_device_uninit(&static_pdev);
return err;
}
... which I think would align with what people generally expect to have
to do.
Those would have to check that only a single reference was held (from
the corresponding _initialize()), and could WARN/fail if more were held.
> That said, most users of platform_device_register() appear to operate
> on static platform devices which don't even have a release function and
> would trigger a WARN() if we ever drop the reference (which is arguably
> worse than leaking a tiny bit of memory).
>
> So leaving things as-is is also an option.
I suspect that might be the best option for now.
Mark.
^ permalink raw reply
* Re: [PATCH 1/9] dt-bindings: sound: mt2701-afe-pcm: add HDMI audio path clocks
From: Krzysztof Kozlowski @ 2026-04-16 9:38 UTC (permalink / raw)
To: Daniel Golle
Cc: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Jaroslav Kysela, Takashi Iwai, Cyril Chao, Arnd Bergmann,
Kuninori Morimoto, Nícolas F. R. A. Prado, Eugen Hristev,
linux-sound, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek
In-Reply-To: <50afd83a314cd20c715fb9b0d3bc85fb00f9a6eb.1776265610.git.daniel@makrotopia.org>
On Wed, Apr 15, 2026 at 04:23:27PM +0100, Daniel Golle wrote:
> Document four additional optional clocks feeding the HDMI audio
> output path on MT2701 and MT7623N: the HADDS2 PLL (root of the
There is no MT7623N compatible in this file, so that's confusing. Does
mt7622 have it? If not, then it should be restricted per variant. If
yet, the model name is confusing.
Best regards,
Krzysztof
^ permalink raw reply
* ACPI dump of HP OmniBook 5 14-he0xxx
From: gaming stream @ 2026-04-16 9:42 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
I’ve extracted a full ACPI dump from an HP OmniBook 5 14-he0xxx
running Snapdragon X (X126100, Oryon CPU).
This includes DSDT, all SSDTs, and full raw ACPI tables.
Repository: https://github.com/TheXterminator/hp-omnibook-5-snapdragon-x-acpi.git
Sharing in case it helps with Linux bring-up or device tree work
for Snapdragon X platforms.
^ permalink raw reply
* Re: [PATCH v2 0/9] driver core / pmdomain: Add support for fined grained sync_state
From: Ulf Hansson @ 2026-04-16 9:42 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Saravana Kannan, Rafael J . Wysocki, Greg Kroah-Hartman, linux-pm,
Sudeep Holla, Cristian Marussi, Kevin Hilman, Stephen Boyd,
Marek Szyprowski, Bjorn Andersson, Abel Vesa, Peng Fan,
Tomi Valkeinen, Maulik Shah, Konrad Dybcio, Thierry Reding,
Jonathan Hunter, Dmitry Baryshkov, linux-arm-kernel, linux-kernel
In-Reply-To: <CAMuHMdWHnANr4R+AW5-xHrm=D4SJLuKVF5mq3PFkbevcTz5qWw@mail.gmail.com>
On Thu, 16 Apr 2026 at 11:15, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
>
> Hi Ulf,
>
> On Fri, 10 Apr 2026 at 12:41, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> > Since the introduction [1] of the common sync_state support for pmdomains
> > (genpd), we have encountered a lot of various interesting problems. In most
> > cases the new behaviour of genpd triggered some weird platform specific bugs.
> >
> > That said, in LPC in Tokyo me and Saravana hosted a session to walk through the
> > remaining limitations that we have found for genpd's sync state support. In
> > particular, we discussed the problems we have for the so-called onecell power
> > domain providers, where a single provider typically provides multiple
> > independent power domains, all with their own set of consumers.
> >
> > Note that, onecell power domain providers are very common. It's being used by
> > many SoCs/platforms/technologies. To name a few:
> > SCMI, Qualcomm, NXP, Mediatek, Renesas, TI, etc.
> >
> > Anyway, in these cases, the generic sync_state mechanism with fw_devlink isn't
> > fine grained enough, as we end up waiting for all consumers for all power
> > domains before the ->sync_callback gets called for the supplier/provider. In
> > other words, we may end up keeping unused power domains powered-on, for no good
> > reasons.
> >
> > The series intends to fix this problem. Please have a look at the commit
> > messages for more details and help review/test!
>
> Thanks for the update!
>
> At first glance, the only real change compared to v1 seems to be
> the removal of printing
>
> pr_info("%s:%s con=%s\n", __func__, dev_name(dev),
> dev_name(consumer));
>
> Right?
Correct! I forgot to include a version history, sorry.
Besides the removed print, I have just added your tags and updated the
commit message in patch9.
FYI, my plan is to queue this as soon as v7.1-rc1 is available.
Kind regards
Uffe
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox