From c83594e844931ac2db1da19597119c2309b88f2c Mon Sep 17 00:00:00 2001 From: Omar Ivan Fardjoume Date: Tue, 26 May 2026 18:28:59 -0300 Subject: [PATCH 01/11] mmc: sunxi: fix MACH_SUN9I typo in get_mclk_offset() The get_mclk_offset() function used the non-existent Kconfig symbol CONFIG_MACH_SUN9I_A80 instead of CONFIG_MACH_SUN9I, causing the MMC2 clock register to be written at 0x06000090 instead of 0x06000418. This corrupted the CMD2 response and made eMMC completely unresponsive. Also the legacy (SPL) sunxi_mmc_init() did not include CONFIG_MACH_SUN9I in the 8-bit bus width condition, so MMC2 (eMMC) would only use 4-bit mode in the SPL, which is insufficient for reliable boot. Tested on a Cubieboard4 A80: with both fixes, SPL loads U-Boot proper and boots Debian 12 from eMMC with no SD card present. Signed-off-by: Omar Ivan Fardjoume [Andre: fix mangled patch, trim commit message] Signed-off-by: Andre Przywara --- drivers/mmc/sunxi_mmc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index e28c81afffe..84f4e4c2198 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -576,8 +576,8 @@ struct mmc *sunxi_mmc_init(int sdc_no) cfg->host_caps = MMC_MODE_4BIT; if ((IS_ENABLED(CONFIG_MACH_SUN50I) || IS_ENABLED(CONFIG_MACH_SUN8I) || - IS_ENABLED(CONFIG_SUN50I_GEN_H6) || IS_ENABLED(CONFIG_MACH_SUN55I_A523)) && - (sdc_no == 2)) + IS_ENABLED(CONFIG_MACH_SUN9I) || IS_ENABLED(CONFIG_SUN50I_GEN_H6) || + IS_ENABLED(CONFIG_MACH_SUN55I_A523)) && (sdc_no == 2)) cfg->host_caps = MMC_MODE_8BIT; cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; @@ -663,7 +663,7 @@ static const struct dm_mmc_ops sunxi_mmc_ops = { static unsigned get_mclk_offset(void) { - if (IS_ENABLED(CONFIG_MACH_SUN9I_A80)) + if (IS_ENABLED(CONFIG_MACH_SUN9I)) return 0x410; if (IS_ENABLED(CONFIG_SUN50I_GEN_H6) || IS_ENABLED(CONFIG_SUNXI_GEN_NCAT2)) From 4b5a1e0283aec9048d9e12cf137d969a203b5f62 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Fri, 8 May 2026 12:31:22 +0200 Subject: [PATCH 02/11] spi: sunxi: add support for A523 SPI controller The SPI controllers in the Allwinner A523/A527/T527 SoCs is very close to the one used in the R329 and D1 generation, definitely as far as our driver is concerned. Add the new compatible string, but use the existing config section from the previous SoC generation. Signed-off-by: Andre Przywara Acked-by: Jernej Skrabec --- drivers/spi/spi-sunxi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/spi/spi-sunxi.c b/drivers/spi/spi-sunxi.c index 08b603f04a2..4e91cf6b7fd 100644 --- a/drivers/spi/spi-sunxi.c +++ b/drivers/spi/spi-sunxi.c @@ -587,6 +587,10 @@ static const struct udevice_id sun4i_spi_ids[] = { .compatible = "allwinner,sun50i-r329-spi", .data = (ulong)&sun50i_r329_spi_variant, }, + { + .compatible = "allwinner,sun55i-a523-spi", + .data = (ulong)&sun50i_r329_spi_variant, + }, { /* sentinel */ } }; From 6882f72fa3562ab927072a231f1f5a54ed60f90b Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Fri, 8 May 2026 10:52:50 +0200 Subject: [PATCH 03/11] sunxi: spl: spi: Clean up SPI0 pinmux setting The function to set the pinmux for the Port C SPI0 pins was looking more like a logic puzzle from a magazine than something that readers could understand and extend. Replace the convoluted pinmux setup, grouped by pin, with a simple array of the four pins involved, and just initialise this array at build time, based on the selected SoC. This makes it easy to see which pins are needed, and even easier to extend. Signed-off-by: Andre Przywara --- arch/arm/mach-sunxi/spl_spi_sunxi.c | 43 ++++++++++++----------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/arch/arm/mach-sunxi/spl_spi_sunxi.c b/arch/arm/mach-sunxi/spl_spi_sunxi.c index 5f72e809952..5cdf155d76a 100644 --- a/arch/arm/mach-sunxi/spl_spi_sunxi.c +++ b/arch/arm/mach-sunxi/spl_spi_sunxi.c @@ -105,35 +105,28 @@ /* * Allwinner A10/A20 SoCs were using pins PC0,PC1,PC2,PC23 for booting - * from SPI Flash, everything else is using pins PC0,PC1,PC2,PC3. - * The H6 uses PC0, PC2, PC3, PC5, the H616 PC0, PC2, PC3, PC4. + * from SPI Flash, later SoCs are using pins PC0,PC1,PC2,PC3. + * Newer SoCs are all over the place. */ static void spi0_pinmux_setup(unsigned int pin_function) { - /* All chips use PC2. And all chips use PC0, except R528/T113 */ - if (!IS_ENABLED(CONFIG_MACH_SUN8I_R528)) - sunxi_gpio_set_cfgpin(SUNXI_GPC(0), pin_function); + const u16 spi0_pc_pins[4] = { +#if IS_ENABLED(CONFIG_MACH_SUN8I_R528) + SUNXI_GPC(2), SUNXI_GPC(3), SUNXI_GPC(4), SUNXI_GPC(5) +#elif IS_ENABLED(CONFIG_MACH_SUN50I_H616) + SUNXI_GPC(0), SUNXI_GPC(2), SUNXI_GPC(3), SUNXI_GPC(4) +#elif IS_ENABLED(CONFIG_MACH_SUN50I_H6) + SUNXI_GPC(0), SUNXI_GPC(2), SUNXI_GPC(3), SUNXI_GPC(5) +#elif IS_ENABLED(CONFIG_MACH_SUN4I) || IS_ENABLED(CONFIG_MACH_SUN7I) || \ + IS_ENABLED(CONFIG_MACH_SUN8I_R40) + SUNXI_GPC(0), SUNXI_GPC(1), SUNXI_GPC(2), SUNXI_GPC(23) +#else + SUNXI_GPC(0), SUNXI_GPC(1), SUNXI_GPC(2), SUNXI_GPC(3) +#endif + }; - sunxi_gpio_set_cfgpin(SUNXI_GPC(2), pin_function); - - /* All chips except H6/H616/R528/T113 use PC1. */ - if (!IS_ENABLED(CONFIG_SUN50I_GEN_H6) && - !IS_ENABLED(CONFIG_MACH_SUN8I_R528)) - sunxi_gpio_set_cfgpin(SUNXI_GPC(1), pin_function); - - if (IS_ENABLED(CONFIG_MACH_SUN50I_H6) || - IS_ENABLED(CONFIG_MACH_SUN8I_R528)) - sunxi_gpio_set_cfgpin(SUNXI_GPC(5), pin_function); - if (IS_ENABLED(CONFIG_MACH_SUN50I_H616) || - IS_ENABLED(CONFIG_MACH_SUN8I_R528)) - sunxi_gpio_set_cfgpin(SUNXI_GPC(4), pin_function); - - /* Older generations use PC23 for CS, newer ones use PC3. */ - if (IS_ENABLED(CONFIG_MACH_SUN4I) || IS_ENABLED(CONFIG_MACH_SUN7I) || - IS_ENABLED(CONFIG_MACH_SUN8I_R40)) - sunxi_gpio_set_cfgpin(SUNXI_GPC(23), pin_function); - else - sunxi_gpio_set_cfgpin(SUNXI_GPC(3), pin_function); + for (int i = 0; i < 4; i++) + sunxi_gpio_set_cfgpin(spi0_pc_pins[i], pin_function); } static bool is_sun6i_gen_spi(void) From 9ceb0a3e0cde6bbac2c4cee7ae18e9e1d7d33858 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Fri, 8 May 2026 10:01:40 +0200 Subject: [PATCH 04/11] sunxi: spl: spi: Add support for Allwinner A523 The SPI IP in the Allwinner A523 is mostly compatible to the later generation used in other Allwinner SoCs, at least as far as the SPL driver is concerned. Just add the pinmux configuration for SPI0 on PortC, as used by the BROM. This enables SPI (NOR) boot on A523/A527/T527 boards. Signed-off-by: Andre Przywara Reviewed-by: Jernej Skrabec --- arch/arm/mach-sunxi/spl_spi_sunxi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-sunxi/spl_spi_sunxi.c b/arch/arm/mach-sunxi/spl_spi_sunxi.c index 5cdf155d76a..6c9937128b9 100644 --- a/arch/arm/mach-sunxi/spl_spi_sunxi.c +++ b/arch/arm/mach-sunxi/spl_spi_sunxi.c @@ -113,6 +113,8 @@ static void spi0_pinmux_setup(unsigned int pin_function) const u16 spi0_pc_pins[4] = { #if IS_ENABLED(CONFIG_MACH_SUN8I_R528) SUNXI_GPC(2), SUNXI_GPC(3), SUNXI_GPC(4), SUNXI_GPC(5) +#elif IS_ENABLED(CONFIG_MACH_SUN55I_A523) + SUNXI_GPC(2), SUNXI_GPC(3), SUNXI_GPC(4), SUNXI_GPC(12) #elif IS_ENABLED(CONFIG_MACH_SUN50I_H616) SUNXI_GPC(0), SUNXI_GPC(2), SUNXI_GPC(3), SUNXI_GPC(4) #elif IS_ENABLED(CONFIG_MACH_SUN50I_H6) @@ -250,7 +252,8 @@ static void spi0_init(void) unsigned int pin_function = SUNXI_GPC_SPI0; if (IS_ENABLED(CONFIG_MACH_SUN50I) || - IS_ENABLED(CONFIG_SUN50I_GEN_H6)) + IS_ENABLED(CONFIG_SUN50I_GEN_H6) || + IS_ENABLED(CONFIG_MACH_SUN55I_A523)) pin_function = SUN50I_GPC_SPI0; else if (IS_ENABLED(CONFIG_MACH_SUNIV) || IS_ENABLED(CONFIG_MACH_SUN8I_R528)) From 1721809d29d06a7ac4a5d68956eaa6344fb7cbdd Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Fri, 8 May 2026 12:34:10 +0200 Subject: [PATCH 05/11] sunxi: configs: Radxa Cubie A5E: enable SPI The Radxa Cubie A5E ships with SPI NOR flash, so enable the SPI and flash drivers, also the SPL version, for SPI booting. Sync the defconfig file with the version from savedefconfig on the way. Signed-off-by: Andre Przywara Acked-by: Jernej Skrabec --- configs/radxa-cubie-a5e_defconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/configs/radxa-cubie-a5e_defconfig b/configs/radxa-cubie-a5e_defconfig index 52a23615e60..2a66d0e0866 100644 --- a/configs/radxa-cubie-a5e_defconfig +++ b/configs/radxa-cubie-a5e_defconfig @@ -15,6 +15,7 @@ CONFIG_DRAM_SUNXI_TPR12=0x3533302f CONFIG_MACH_SUN55I_A523=y CONFIG_MMC_SUNXI_SLOT_EXTRA=2 CONFIG_R_I2C_ENABLE=y +CONFIG_SPL_SPI_SUNXI=y CONFIG_SPL_SUNXI_LED_STATUS=y CONFIG_SPL_SUNXI_LED_STATUS_GPIO=356 # CONFIG_SPL_SUNXI_LED_STATUS_ACTIVE_HIGH is not set @@ -25,11 +26,14 @@ CONFIG_SYS_I2C_MVTWSI=y CONFIG_SYS_I2C_SLAVE=0x7f CONFIG_SYS_I2C_SPEED=400000 CONFIG_SUPPORT_EMMC_BOOT=y +CONFIG_MTD=y +CONFIG_SPI_FLASH_WINBOND=y CONFIG_SUN8I_EMAC=y CONFIG_PHY_REALTEK=y CONFIG_REGULATOR_AXP=y CONFIG_AXP717_POWER=y CONFIG_AXP_DCDC2_VOLT=920 CONFIG_AXP_DCDC3_VOLT=1100 +CONFIG_SPI=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_OHCI_HCD=y From 1519d3a3840aa87c97698bcb02d089cebf7618b8 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Mon, 11 May 2026 22:57:58 +0200 Subject: [PATCH 06/11] sunxi: configs: OrangePi 4A: enable SPI The OrangePi 4A board ships with SPI NOR flash, so enable the SPI and flash drivers, also the SPL version, for SPI booting. Signed-off-by: Andre Przywara Acked-by: Jernej Skrabec --- configs/orangepi_4a_defconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/configs/orangepi_4a_defconfig b/configs/orangepi_4a_defconfig index 6a44dd97959..2d36757ba11 100644 --- a/configs/orangepi_4a_defconfig +++ b/configs/orangepi_4a_defconfig @@ -16,6 +16,7 @@ CONFIG_DRAM_SUNXI_TPR12=0x3a373233 CONFIG_MACH_SUN55I_A523=y CONFIG_MMC_SUNXI_SLOT_EXTRA=2 CONFIG_R_I2C_ENABLE=y +CONFIG_SPL_SPI_SUNXI=y # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set CONFIG_SPL_I2C=y CONFIG_SPL_SYS_I2C_LEGACY=y @@ -23,10 +24,13 @@ CONFIG_SYS_I2C_MVTWSI=y CONFIG_SYS_I2C_SLAVE=0x7f CONFIG_SYS_I2C_SPEED=400000 CONFIG_SUPPORT_EMMC_BOOT=y +CONFIG_MTD=y +CONFIG_SPI_FLASH_XMC=y CONFIG_REGULATOR_AXP=y CONFIG_AXP717_POWER=y CONFIG_AXP_I2C_ADDRESS=0x35 CONFIG_AXP_DCDC2_VOLT=920 CONFIG_AXP_DCDC3_VOLT=1160 +CONFIG_SPI=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_OHCI_HCD=y From f8fd33a3647a13683f652d65f48f42478082418b Mon Sep 17 00:00:00 2001 From: Junhui Liu Date: Tue, 19 May 2026 20:58:30 +0800 Subject: [PATCH 07/11] pinctrl: sunxi: a523: add gmac1 support The Allwinner sun55i (A523/A527/T527) platform provide a Synopsys DesignWare Ethernet QOS IP block as the gmac1 controller, which uses pins PJ0 to PJ16. Add the gmac1 function to the pinctrl driver to support it. Signed-off-by: Junhui Liu Reviewed-by: Andre Przywara --- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index a8632aeaf8f..ab4e88c9918 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -761,7 +761,8 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h616_pinctrl_desc = }; static const struct sunxi_pinctrl_function sun55i_a523_pinctrl_functions[] = { - { "gmac0", 5 }, /* PI0-PI16 */ + { "gmac0", 5 }, /* PH0-PH7, PH9-PH10, PH14-PH18 */ + { "gmac1", 5 }, /* PJ0-PJ9, PJ11-PJ15 */ { "gpio_in", 0 }, { "gpio_out", 1 }, { "mmc0", 2 }, /* PF0-PF5 */ From 0874f96a2e42dd3e729f4f1432f51fc170b4773f Mon Sep 17 00:00:00 2001 From: Junhui Liu Date: Tue, 19 May 2026 20:58:31 +0800 Subject: [PATCH 08/11] clk: sunxi: a523: add MBUS_EMAC1 clock gate The Allwinner sun55i (A523/A527/T527) platform requires the MBUS clock gate enabled for the gmac1 controller to function. Add the clock gate definition for CLK_MBUS_EMAC1. Signed-off-by: Junhui Liu Reviewed-by: Andre Przywara --- drivers/clk/sunxi/clk_a523.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/sunxi/clk_a523.c b/drivers/clk/sunxi/clk_a523.c index 1de95fbaf2f..494ee195599 100644 --- a/drivers/clk/sunxi/clk_a523.c +++ b/drivers/clk/sunxi/clk_a523.c @@ -16,6 +16,7 @@ static struct ccu_clk_gate a523_gates[] = { [CLK_PLL_PERIPH0_200M] = GATE_DUMMY, [CLK_APB1] = GATE_DUMMY, + [CLK_MBUS_EMAC1] = GATE(0x804, BIT(12)), [CLK_BUS_MMC0] = GATE(0x84c, BIT(0)), [CLK_BUS_MMC1] = GATE(0x84c, BIT(1)), [CLK_BUS_MMC2] = GATE(0x84c, BIT(2)), From d2a46d3eb2c337b81084300e8931a9c42b76c0fc Mon Sep 17 00:00:00 2001 From: Junhui Liu Date: Tue, 19 May 2026 20:58:29 +0800 Subject: [PATCH 09/11] arm: mach-sunxi: add syscon driver for system-control nodes The upstream Linux kernel relies on the sunxi_sram driver to bind the system-control nodes as syscon devices. Since U-Boot lacks this SRAM driver, peripheral drivers may fail to resolve the syscon node unless an explicit "syscon" compatible is added into the device tree. To address this, add a bare UCLASS_SYSCON driver that matches all Allwinner system-control and SRAM controller compatibles listed in the Linux kernel to provide the necessary regmap access to the system controller. Signed-off-by: Junhui Liu --- arch/arm/mach-sunxi/Kconfig | 7 +++++++ arch/arm/mach-sunxi/Makefile | 1 + arch/arm/mach-sunxi/syscon.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 arch/arm/mach-sunxi/syscon.c diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 5ace74567dd..b0c5d3cd903 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -209,6 +209,13 @@ config SUN6I_PRCM Support for the PRCM (Power/Reset/Clock Management) unit available in A31 SoC. +config SUNXI_SYSCON + bool + select SYSCON + help + Enable syscon driver for Allwinner system controllers, which provides + access to the SRAM/system-control node for drivers. + config AXP_PMIC_BUS bool select DM_PMIC if DM_I2C diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile index 9c79b55abf3..ff475d8fff5 100644 --- a/arch/arm/mach-sunxi/Makefile +++ b/arch/arm/mach-sunxi/Makefile @@ -10,6 +10,7 @@ obj-y += board.o obj-y += cpu_info.o obj-y += dram_helpers.o obj-$(CONFIG_SUN6I_PRCM) += prcm.o +obj-$(CONFIG_SUNXI_SYSCON) += syscon.o obj-$(CONFIG_AXP_PMIC_BUS) += pmic_bus.o obj-$(CONFIG_MACH_SUNIV) += clock_sun6i.o obj-$(CONFIG_MACH_SUN4I) += clock_sun4i.o diff --git a/arch/arm/mach-sunxi/syscon.c b/arch/arm/mach-sunxi/syscon.c new file mode 100644 index 00000000000..e27110dfb0d --- /dev/null +++ b/arch/arm/mach-sunxi/syscon.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2026 Junhui Liu + */ + +#include +#include + +static const struct udevice_id sunxi_syscon_ids[] = { + { .compatible = "allwinner,sun4i-a10-sram-controller" }, + { .compatible = "allwinner,sun4i-a10-system-control" }, + { .compatible = "allwinner,sun5i-a13-system-control" }, + { .compatible = "allwinner,sun8i-a23-system-control" }, + { .compatible = "allwinner,sun8i-h3-system-control" }, + { .compatible = "allwinner,sun20i-d1-system-control" }, + { .compatible = "allwinner,sun50i-a64-sram-controller" }, + { .compatible = "allwinner,sun50i-a64-system-control" }, + { .compatible = "allwinner,sun50i-h5-system-control" }, + { .compatible = "allwinner,sun50i-h616-system-control" }, + { .compatible = "allwinner,sun55i-a523-system-control" }, + { /* sentinel */ }, +}; + +U_BOOT_DRIVER(sunxi_syscon) = { + .name = "sunxi_syscon", + .id = UCLASS_SYSCON, + .of_match = sunxi_syscon_ids, +}; From c5d3fac4becf7ca5db58a6937ddaf69df0070834 Mon Sep 17 00:00:00 2001 From: Junhui Liu Date: Tue, 19 May 2026 20:58:28 +0800 Subject: [PATCH 10/11] net: dwc_eth_qos: add support for sun55i platform The Allwinner sun55i (A523/A527/T527) platform features the Synopsys DesignWare Ethernet QOS IP. To enable this GMAC controller in U-Boot, this introduces the glue layer responsible for configuring the corresponding clocks, resets, and syscon registers. This implementation is directly ported from upstream Linux kernel commit f603808a98af ("net: stmmac: Add support for Allwinner A523 GMAC200"). Link: https://patch.msgid.link/20250925191600.3306595-3-wens@kernel.org Signed-off-by: Junhui Liu --- drivers/net/Kconfig | 9 ++ drivers/net/Makefile | 1 + drivers/net/dwc_eth_qos.c | 6 + drivers/net/dwc_eth_qos.h | 1 + drivers/net/dwc_eth_qos_sunxi.c | 254 ++++++++++++++++++++++++++++++++ 5 files changed, 271 insertions(+) create mode 100644 drivers/net/dwc_eth_qos_sunxi.c diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 4399c6c7a99..faa08e9ebba 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -284,6 +284,15 @@ config DWC_ETH_QOS_STM32 The Synopsys Designware Ethernet QOS IP block with the specific configuration used in STM32MP soc. +config DWC_ETH_QOS_SUNXI + bool "Synopsys DWC Ethernet QOS device support for Allwinner SoCs" + depends on DWC_ETH_QOS && ARCH_SUNXI + select REGMAP + select SUNXI_SYSCON + help + The Synopsys Designware Ethernet QOS IP block with specific + configuration used in Allwinner SoCs. + config DWC_ETH_QOS_TEGRA186 bool "Synopsys DWC Ethernet QOS device support for TEGRA186" depends on DWC_ETH_QOS diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 761f7f0f451..4c1f4094ab2 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_DWC_ETH_QOS_QCOM) += dwc_eth_qos_qcom.o obj-$(CONFIG_DWC_ETH_QOS_ROCKCHIP) += dwc_eth_qos_rockchip.o obj-$(CONFIG_DWC_ETH_QOS_STARFIVE) += dwc_eth_qos_starfive.o obj-$(CONFIG_DWC_ETH_QOS_STM32) += dwc_eth_qos_stm32.o +obj-$(CONFIG_DWC_ETH_QOS_SUNXI) += dwc_eth_qos_sunxi.o obj-$(CONFIG_DWC_ETH_XGMAC) += dwc_eth_xgmac.o obj-$(CONFIG_DWC_ETH_XGMAC_SOCFPGA) += dwc_eth_xgmac_socfpga.o obj-$(CONFIG_E1000) += e1000.o diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index b7e6299c307..e7cf68d011c 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -1664,6 +1664,12 @@ static const struct udevice_id eqos_ids[] = { .compatible = "mediatek,mt8189-gmac", .data = (ulong)&eqos_mtk_config }, +#endif +#if IS_ENABLED(CONFIG_DWC_ETH_QOS_SUNXI) + { + .compatible = "allwinner,sun55i-a523-gmac200", + .data = (ulong)&eqos_sunxi_config + }, #endif { } }; diff --git a/drivers/net/dwc_eth_qos.h b/drivers/net/dwc_eth_qos.h index 978b848b46e..ccb3c3a1453 100644 --- a/drivers/net/dwc_eth_qos.h +++ b/drivers/net/dwc_eth_qos.h @@ -318,3 +318,4 @@ extern struct eqos_config eqos_stm32mp25_config; extern struct eqos_config eqos_jh7110_config; extern struct eqos_config eqos_adi_config; extern struct eqos_config eqos_mtk_config; +extern struct eqos_config eqos_sunxi_config; diff --git a/drivers/net/dwc_eth_qos_sunxi.c b/drivers/net/dwc_eth_qos_sunxi.c new file mode 100644 index 00000000000..91d871dd271 --- /dev/null +++ b/drivers/net/dwc_eth_qos_sunxi.c @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2017 Corentin Labbe + * Copyright (C) 2025 Chen-Yu Tsai + * Copyright (C) 2026 Junhui Liu + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dwc_eth_qos.h" + +#define SYSCON_REG 0x34 + +#define SYSCON_PHY_SELECT BIT(15) /* 1: internal, 0: external */ +/* RMII specific bits */ +#define SYSCON_RMII_EN BIT(13) /* 1: enable RMII (overrides EPIT) */ +/* Generic system control EMAC_CLK bits */ +#define SYSCON_ETXDC_MASK GENMASK(12, 10) +#define SYSCON_ERXDC_MASK GENMASK(9, 5) +/* EMAC PHY Interface Type */ +#define SYSCON_EPIT BIT(2) /* 1: RGMII, 0: MII */ +#define SYSCON_ETCS_MASK GENMASK(1, 0) +#define SYSCON_ETCS_MII 0x0 +#define SYSCON_ETCS_EXT_GMII 0x1 +#define SYSCON_ETCS_INT_GMII 0x2 + +struct sunxi_platform_data { + struct clk_bulk clks; + struct reset_ctl_bulk resets; +}; + +static int sunxi_gmac_set_syscon(struct udevice *dev, + phy_interface_t interface_type) +{ + struct regmap *regmap; + u32 val, reg = 0; + int ret; + + regmap = syscon_regmap_lookup_by_phandle(dev, "syscon"); + if (IS_ERR(regmap)) { + dev_err(dev, "Unable to map syscon\n"); + return PTR_ERR(regmap); + } + + if (!dev_read_u32(dev, "tx-internal-delay-ps", &val)) { + if (val % 100) { + dev_err(dev, "tx-delay must be a multiple of 100\n"); + return -EINVAL; + } + val /= 100; + dev_dbg(dev, "set tx-delay to %x\n", val); + + if (!FIELD_FIT(SYSCON_ETXDC_MASK, val)) { + dev_err(dev, "TX clock delay exceeds maximum\n"); + return -EINVAL; + } + + reg |= FIELD_PREP(SYSCON_ETXDC_MASK, val); + } + + if (!dev_read_u32(dev, "rx-internal-delay-ps", &val)) { + if (val % 100) { + dev_err(dev, "rx-delay must be a multiple of 100\n"); + return -EINVAL; + } + val /= 100; + dev_dbg(dev, "set rx-delay to %x\n", val); + if (!FIELD_FIT(SYSCON_ERXDC_MASK, val)) { + dev_err(dev, "Invalid RX clock delay: %d\n", val); + return -EINVAL; + } + + reg |= FIELD_PREP(SYSCON_ERXDC_MASK, val); + } + + switch (interface_type) { + case PHY_INTERFACE_MODE_MII: + /* default */ + break; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + reg |= SYSCON_EPIT | SYSCON_ETCS_INT_GMII; + break; + case PHY_INTERFACE_MODE_RMII: + reg |= SYSCON_RMII_EN; + break; + default: + dev_err(dev, "Unsupported interface mode: %s\n", + phy_interface_strings[interface_type]); + return -EINVAL; + } + + ret = regmap_write(regmap, SYSCON_REG, reg); + if (ret < 0) { + dev_err(dev, "Failed to write to syscon\n"); + return ret; + } + + return 0; +} + +static int eqos_start_clks_sunxi(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct sunxi_platform_data *data = pdata->priv_pdata; + + return clk_enable_bulk(&data->clks); +} + +static int eqos_stop_clks_sunxi(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct sunxi_platform_data *data = pdata->priv_pdata; + + return clk_disable_bulk(&data->clks); +} + +static int eqos_start_resets_sunxi(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct sunxi_platform_data *data = pdata->priv_pdata; + int ret; + + ret = reset_deassert_bulk(&data->resets); + if (ret) + return ret; + + return sunxi_gmac_set_syscon(dev, pdata->phy_interface); +} + +static int eqos_stop_resets_sunxi(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct sunxi_platform_data *data = pdata->priv_pdata; + + return reset_assert_bulk(&data->resets); +} + +static int eqos_probe_resources_sunxi(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_plat(dev); + struct sunxi_platform_data *data; + struct udevice *phy_supply = NULL; + int ret; + + ret = eqos_get_base_addr_dt(dev); + if (ret) { + dev_err(dev, "Failed to get base address: %d\n", ret); + return ret; + } + + data = calloc(1, sizeof(struct sunxi_platform_data)); + if (!data) + return -ENOMEM; + + pdata->priv_pdata = data; + + pdata->phy_interface = eqos->config->interface(dev); + if (pdata->phy_interface == PHY_INTERFACE_MODE_NA) { + dev_err(dev, "Failed to get PHY interface mode\n"); + return -EINVAL; + } + + ret = clk_get_by_name(dev, "stmmaceth", &eqos->clk_master_bus); + if (ret) { + dev_err(dev, "Failed to get stmmaceth clock: %d\n", ret); + return ret; + } + + ret = reset_get_bulk(dev, &data->resets); + if (ret) { + dev_err(dev, "Failed to get resets: %d\n", ret); + return ret; + } + + ret = clk_get_bulk(dev, &data->clks); + if (ret) { + dev_err(dev, "Failed to get clocks: %d\n", ret); + return ret; + } + + if (IS_ENABLED(CONFIG_DM_REGULATOR)) { + ret = device_get_supply_regulator(dev, "phy-supply", &phy_supply); + if (ret && ret != -ENOENT) { + dev_err(dev, "Failed to get PHY supply: %d\n", ret); + return ret; + } + + if (phy_supply) { + ret = regulator_set_enable_if_allowed(phy_supply, true); + if (ret) { + dev_err(dev, "Failed to enable phy supply: %d\n", ret); + return ret; + } + } + } + + return 0; +} + +static int eqos_remove_resources_sunxi(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct sunxi_platform_data *data = pdata->priv_pdata; + + reset_assert_bulk(&data->resets); + clk_disable_bulk(&data->clks); + + return 0; +} + +static struct eqos_ops eqos_sunxi_ops = { + .eqos_inval_desc = eqos_inval_desc_generic, + .eqos_flush_desc = eqos_flush_desc_generic, + .eqos_inval_buffer = eqos_inval_buffer_generic, + .eqos_flush_buffer = eqos_flush_buffer_generic, + .eqos_probe_resources = eqos_probe_resources_sunxi, + .eqos_remove_resources = eqos_remove_resources_sunxi, + .eqos_stop_resets = eqos_stop_resets_sunxi, + .eqos_start_resets = eqos_start_resets_sunxi, + .eqos_stop_clks = eqos_stop_clks_sunxi, + .eqos_start_clks = eqos_start_clks_sunxi, + .eqos_calibrate_pads = eqos_null_ops, + .eqos_disable_calibration = eqos_null_ops, + .eqos_set_tx_clk_speed = eqos_null_ops, + .eqos_get_enetaddr = eqos_null_ops, +}; + +struct eqos_config __maybe_unused eqos_sunxi_config = { + .reg_access_always_ok = false, + .mdio_wait = 10, + .swr_wait = 50, + .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB, + .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_150_250, + .axi_bus_width = EQOS_AXI_WIDTH_64, + .interface = dev_read_phy_mode, + .ops = &eqos_sunxi_ops +}; From 59edf9a3427c13f05d450fe84f42ef00dc7096c9 Mon Sep 17 00:00:00 2001 From: Junhui Liu Date: Tue, 19 May 2026 20:58:32 +0800 Subject: [PATCH 11/11] configs: radxa-cubie-a5e: enable the gmac1 controller The Allwinner A527 SoC features two Ethernet controllers utilizing different IP blocks. While gmac0 uses the older sun8i-emac IP, gmac1 is based on the Synopsys DesignWare Ethernet QOS IP. This enables the DWC_ETH_QOS_SUNXI driver and the required PHY interface configurations in the defconfig for the Radxa Cubie A5E board, activating the gmac1 port. Signed-off-by: Junhui Liu [Andre: drop unneeded options] Reviewed-by: Andre Przywara Tested-by: Andre Przywara --- configs/radxa-cubie-a5e_defconfig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/configs/radxa-cubie-a5e_defconfig b/configs/radxa-cubie-a5e_defconfig index 2a66d0e0866..6ea99dc46b6 100644 --- a/configs/radxa-cubie-a5e_defconfig +++ b/configs/radxa-cubie-a5e_defconfig @@ -28,6 +28,11 @@ CONFIG_SYS_I2C_SPEED=400000 CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_MTD=y CONFIG_SPI_FLASH_WINBOND=y +CONFIG_DM_MDIO=y +CONFIG_DM_ETH_PHY=y +CONFIG_DWC_ETH_QOS=y +CONFIG_DWC_ETH_QOS_SUNXI=y +CONFIG_RGMII=y CONFIG_SUN8I_EMAC=y CONFIG_PHY_REALTEK=y CONFIG_REGULATOR_AXP=y