summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2026-07-27 13:56:03 -0600
committerTom Rini <[email protected]>2026-07-27 13:56:03 -0600
commitd7e7c9b063bc6e7d753064a13a7662fee7f74a56 (patch)
treeb4e09cd495a098c0cace88c5106743fd7e92abcb
parent6fd5e4b7e7a800d1d6b7be6d764477a0ec9582aa (diff)
parent59edf9a3427c13f05d450fe84f42ef00dc7096c9 (diff)
Merge branch 'main' of https://git.u-boot-project.org/u-boot/custodians/u-boot-sunxi
Beside a fix for a long standing bug in the A80 eMMC code, this adds SPI booting support for the Allwinner A523/A527/T527 class of boards. The second major feature is support for the secondary Ethernet controller on that same SoC. This might not be as important as for the kernel (I doubt that U-Boot acts as a router), but for once some boards only connect the secondary EMAC, and on others people might have the boot server only reachable via this port. There are some smaller fixes and improvements still queued up, but they need some more testing and are minor, so can land a bit later. The world build timed out, but the rest passed, and I booted that briefly on an A523 board with two Ethernet ports.
-rw-r--r--arch/arm/mach-sunxi/Kconfig7
-rw-r--r--arch/arm/mach-sunxi/Makefile1
-rw-r--r--arch/arm/mach-sunxi/spl_spi_sunxi.c48
-rw-r--r--arch/arm/mach-sunxi/syscon.c28
-rw-r--r--configs/orangepi_4a_defconfig4
-rw-r--r--configs/radxa-cubie-a5e_defconfig9
-rw-r--r--drivers/clk/sunxi/clk_a523.c1
-rw-r--r--drivers/mmc/sunxi_mmc.c6
-rw-r--r--drivers/net/Kconfig9
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/dwc_eth_qos.c6
-rw-r--r--drivers/net/dwc_eth_qos.h1
-rw-r--r--drivers/net/dwc_eth_qos_sunxi.c254
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sunxi.c3
-rw-r--r--drivers/spi/spi-sunxi.c4
15 files changed, 352 insertions, 30 deletions
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/spl_spi_sunxi.c b/arch/arm/mach-sunxi/spl_spi_sunxi.c
index 5f72e809952..6c9937128b9 100644
--- a/arch/arm/mach-sunxi/spl_spi_sunxi.c
+++ b/arch/arm/mach-sunxi/spl_spi_sunxi.c
@@ -105,35 +105,30 @@
/*
* 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);
-
- 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);
+ 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)
+ 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
+ };
- /* 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)
@@ -257,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))
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 <[email protected]>
+ */
+
+#include <dm.h>
+#include <syscon.h>
+
+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,
+};
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
diff --git a/configs/radxa-cubie-a5e_defconfig b/configs/radxa-cubie-a5e_defconfig
index 52a23615e60..6ea99dc46b6 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,19 @@ 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_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
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
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)),
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))
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
@@ -1665,6 +1665,12 @@ static const struct udevice_id eqos_ids[] = {
.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 <[email protected]>
+ * Copyright (C) 2025 Chen-Yu Tsai <[email protected]>
+ * Copyright (C) 2026 Junhui Liu <[email protected]>
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <dm/device.h>
+#include <dm/device_compat.h>
+#include <linux/bitfield.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <net.h>
+#include <phy.h>
+#include <power/regulator.h>
+#include <regmap.h>
+#include <reset.h>
+#include <malloc.h>
+#include <syscon.h>
+
+#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
+};
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 */
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 */ }
};