From c0c122bfa1621a1fe18631145f08039cb9a19341 Mon Sep 17 00:00:00 2001 From: Liya Huang <1425075683@qq.com> Date: Fri, 31 Jan 2025 09:12:43 +0800 Subject: [PATCH 01/15] sunxi: kconfig : Make CHIP_DIP_SCAN depend on ARCH_SUNXI The CHIP_DIP_SCAN configuration option is relevant only to ARCH_SUNXI. Make CHIP_DIP_SCAN dependent on ARCH_SUNXI so that it does not show up on other goals. Signed-off-by: Liya Huang <1425075683@qq.com> Reviewed-by: Andre Przywara --- arch/arm/mach-sunxi/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index ba1b1541437..cc28f403fae 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -1131,10 +1131,6 @@ config BLUETOOTH_DT_DEVICE_FIXUP The used address is "bdaddr" if set, and "ethaddr" with the LSB flipped elsewise. -source "board/sunxi/Kconfig" - -endif - config CHIP_DIP_SCAN bool "Enable DIPs detection for CHIP board" select SUPPORT_EXTENSION_SCAN @@ -1143,3 +1139,7 @@ config CHIP_DIP_SCAN select W1_EEPROM select W1_EEPROM_DS24XXX select CMD_EXTENSION + +source "board/sunxi/Kconfig" + +endif From 46c291e14779d83cb216c9177cf7bb327005382b Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Wed, 26 Feb 2025 11:37:11 +0000 Subject: [PATCH 02/15] sunxi: mmc: Fix T113-s3 MMC clock divider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On the Allwinner D1/R528/T113-s3 SoCs the MMC clock source selected by mux value 1 is PLL_PERIPH0(1x), not (2x), as in the other SoCs. But we have still the hidden divisor of 2 in the MMC mod clock, so need to explicitly compensate for that on those SoCs. This leads to the actually programmed clock rate to be double compared to before, which increases the MMC performance on those SoCs. Signed-off-by: Andre Przywara Reported-by: Kuba SzczodrzyƄski Reviewed-by: Jernej Skrabec Reviewed-by: Peng Fan --- drivers/mmc/sunxi_mmc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index 0b56d1405be..8f72d758e46 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -92,6 +92,13 @@ static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz) pll = CCM_MMC_CTRL_PLL6; pll_hz = clock_get_pll6(); #endif + /* + * On the D1/R528/T113 mux source 1 refers to PLL_PERIPH0(1x), + * like for the older SoCs. However we still have the hidden + * divider of 2x, so compensate for that here. + */ + if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) + pll_hz /= 2; } div = pll_hz / hz; From 720023c85f0c5e78893536e137994bcca1b70282 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Wed, 26 Feb 2025 11:37:12 +0000 Subject: [PATCH 03/15] sunxi: sun50i_h6: clock: fix PLL_PERIPH0 rate calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On the Allwinner D1/R528/T113-s3 SoCs (NCAT2) the factors encoded in the PLL register describe the doubled clock rate, as in the other SoCs. Correct for that by always dividing the calculated rate by 2, except on the H6, where we need a divisor of 4 (no change here). This corrects the PERIPH0 clock rate as read by the MMC driver, and actually doubles the MMC performance on those NCAT2 chips. Signed-off-by: Andre Przywara Reported-by: Kuba SzczodrzyƄski Reviewed-by: Jernej Skrabec Reviewed-by: Peng Fan --- arch/arm/mach-sunxi/clock_sun50i_h6.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-sunxi/clock_sun50i_h6.c b/arch/arm/mach-sunxi/clock_sun50i_h6.c index b424a7893ea..359513d1669 100644 --- a/arch/arm/mach-sunxi/clock_sun50i_h6.c +++ b/arch/arm/mach-sunxi/clock_sun50i_h6.c @@ -147,15 +147,20 @@ unsigned int clock_get_pll6(void) if (IS_ENABLED(CONFIG_SUNXI_GEN_NCAT2)) { div1 = ((rval & CCM_PLL6_CTRL_P0_MASK) >> CCM_PLL6_CTRL_P0_SHIFT) + 1; - m = 1; } else { div1 = ((rval & CCM_PLL6_CTRL_DIV1_MASK) >> CCM_PLL6_CTRL_DIV1_SHIFT) + 1; - if (IS_ENABLED(CONFIG_MACH_SUN50I_H6)) - m = 4; - else - m = 2; } + /* + * The factors encoded in the register describe the doubled clock + * frequency, expect for the H6, where it's the quadrupled frequency. + * Compensate for that here. + */ + if (IS_ENABLED(CONFIG_MACH_SUN50I_H6)) + m = 4; + else + m = 2; + return 24000000U * n / m / div1 / div2; } From 6ba4d46ef6efd7d1878e35fd1d1e27569c3c23b0 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Sun, 20 Oct 2024 17:36:19 +0100 Subject: [PATCH 04/15] power: pmic: sunxi: add SPL support for the AXP803 The AXP803 has been around for about a decade now, but so far we didn't need SPL support, since the DRAM rail was wired up correctly at reset. Now some boards using the A133 SoC use the (compatible) AXP707 with DDR4 memory, which requires the SPL to set the required 1.1V voltage manually. Add the descriptions for the DC/DC regulators of the AXP803, and enable that when CONFIG_AXP803_POWER is enabled. Signed-off-by: Andre Przywara Acked-by: Jernej Skrabec --- board/sunxi/board.c | 5 ++++- drivers/power/Kconfig | 15 +++++++++++---- drivers/power/Makefile | 1 + drivers/power/axp_spl.c | 17 +++++++++++++++++ 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/board/sunxi/board.c b/board/sunxi/board.c index c7a2205ed61..ac9cefc6eac 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -563,7 +563,8 @@ void sunxi_board_init(void) #if defined CONFIG_AXP152_POWER || defined CONFIG_AXP209_POWER || \ defined CONFIG_AXP221_POWER || defined CONFIG_AXP305_POWER || \ defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER || \ - defined CONFIG_AXP313_POWER || defined CONFIG_AXP717_POWER + defined CONFIG_AXP313_POWER || defined CONFIG_AXP717_POWER || \ + defined CONFIG_AXP803_POWER power_failed = axp_init(); if (IS_ENABLED(CONFIG_AXP_DISABLE_BOOT_ON_POWERON) && !power_failed) { @@ -581,6 +582,8 @@ void sunxi_board_init(void) #endif #ifdef CONFIG_AXP_DCDC2_VOLT power_failed |= axp_set_dcdc2(CONFIG_AXP_DCDC2_VOLT); +#endif +#ifdef CONFIG_AXP_DCDC3_VOLT power_failed |= axp_set_dcdc3(CONFIG_AXP_DCDC3_VOLT); #endif #ifdef CONFIG_AXP_DCDC4_VOLT diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 4b81aeb7497..5c73bc75a15 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -116,6 +116,12 @@ config AXP717_POWER ---help--- Select this to enable support for the AXP717 PMIC found on some boards. +config AXP803_POWER + bool "AXP803 PMIC support" + select AXP_PMIC_BUS + ---help--- + Select this to enable support for the AXP803 PMIC found on some boards. + config AXP809_POWER bool "axp809 pmic support" depends on MACH_SUN9I @@ -144,8 +150,8 @@ endchoice config AXP_DCDC1_VOLT int "axp pmic dcdc1 voltage" - depends on AXP221_POWER || AXP809_POWER || AXP818_POWER - default 3300 if AXP818_POWER || MACH_SUN8I_R40 + depends on AXP221_POWER || AXP809_POWER || AXP818_POWER || AXP803_POWER + default 3300 if AXP818_POWER || MACH_SUN8I_R40 || AXP803_POWER default 3000 if MACH_SUN6I || MACH_SUN8I || MACH_SUN9I ---help--- Set the voltage (mV) to program the axp pmic dcdc1 at, set to 0 to @@ -158,11 +164,12 @@ config AXP_DCDC1_VOLT config AXP_DCDC2_VOLT int "axp pmic dcdc2 voltage" - depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER || AXP313_POWER || AXP717_POWER + depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER || AXP313_POWER || AXP717_POWER || AXP803_POWER default 900 if AXP818_POWER default 1400 if AXP152_POWER || AXP209_POWER default 1000 if AXP313_POWER default 1000 if AXP717_POWER + default 1000 if AXP803_POWER default 1200 if MACH_SUN6I default 1100 if MACH_SUN8I default 0 if MACH_SUN9I @@ -219,7 +226,7 @@ config AXP_DCDC4_VOLT config AXP_DCDC5_VOLT int "axp pmic dcdc5 voltage" - depends on AXP221_POWER || AXP809_POWER || AXP818_POWER + depends on AXP221_POWER || AXP809_POWER || AXP818_POWER || AXP803_POWER default 1500 if MACH_SUN6I || MACH_SUN8I || MACH_SUN9I ---help--- Set the voltage (mV) to program the axp pmic dcdc5 at, set to 0 to diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 3f4d56f5139..3363191fdc8 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_AXP313_POWER) += axp_spl.o obj-$(CONFIG_AXP717_POWER) += axp_spl.o obj-$(CONFIG_AXP809_POWER) += axp809.o obj-$(CONFIG_AXP818_POWER) += axp818.o +obj-$(CONFIG_AXP803_POWER) += axp_spl.o endif obj-$(CONFIG_EXYNOS_TMU) += exynos-tmu.o obj-$(CONFIG_SY8106A_POWER) += sy8106a.o diff --git a/drivers/power/axp_spl.c b/drivers/power/axp_spl.c index 3c86eb20ab4..7c51a9b3dfb 100644 --- a/drivers/power/axp_spl.c +++ b/drivers/power/axp_spl.c @@ -36,6 +36,23 @@ static const struct axp_reg_desc_spl axp_spl_dcdc_regulators[] = { #define AXP_SHUTDOWN_REG 0x27 #define AXP_SHUTDOWN_MASK BIT(0) +#elif defined(CONFIG_AXP803_POWER) /* AXP803 */ + +static const struct axp_reg_desc_spl axp_spl_dcdc_regulators[] = { + { 0x10, BIT(0), 0x20, 0x1f, 1600, 3400, 100, NA }, + { 0x10, BIT(1), 0x21, 0x7f, 500, 1300, 10, 70 }, + { 0x10, BIT(2), 0x22, 0x7f, 500, 1300, 10, 70 }, + { 0x10, BIT(3), 0x23, 0x7f, 500, 1300, 10, 70 }, + { 0x10, BIT(4), 0x24, 0x7f, 800, 1840, 10, 32 }, + { 0x10, BIT(5), 0x25, 0x7f, 600, 1520, 10, 50 }, +}; + +#define AXP_CHIP_VERSION 0x3 +#define AXP_CHIP_VERSION_MASK 0xcf +#define AXP_CHIP_ID 0x41 +#define AXP_SHUTDOWN_REG 0x32 +#define AXP_SHUTDOWN_MASK BIT(7) + #elif defined(CONFIG_AXP313_POWER) /* AXP313 */ static const struct axp_reg_desc_spl axp_spl_dcdc_regulators[] = { From 549c497a4639f7f969f2e56e0fa9ef2fa3b8ce1a Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Tue, 18 Mar 2025 00:39:43 +0000 Subject: [PATCH 05/15] sunxi: pmic_bus: Move SPL I2C addresses into Kconfig Some of the X-Power AXP PMICs can be ordered with an alternative I2C address, for instance an AXP717 could be shipped with address 0x34 or with address 0x35. Similarly the AXP803 lists two possible addresses. For DM (DT) based drivers this is no problem, but the Allwinner SPL code relies on exactly one hardcoded address per PMIC so far. Add a Kconfig variable that holds the I2C address used by the PMIC accessed in the SPL, and provide the (mostly only one) supported address as its default, for the PMICs we use. Boards using the other address can easily set this in their defconfig. This effectively moves the hardcoding from C code to Kconfig. That enables to use the AXP717 on some boards with the new Allwinner A523 chip, which use the other I2C address there. Signed-off-by: Andre Przywara Reviewed-by: Heiko Schocher --- arch/arm/mach-sunxi/pmic_bus.c | 27 ++------------------------- drivers/power/Kconfig | 10 ++++++++++ 2 files changed, 12 insertions(+), 25 deletions(-) diff --git a/arch/arm/mach-sunxi/pmic_bus.c b/arch/arm/mach-sunxi/pmic_bus.c index 8e19324c8ac..c77dc538456 100644 --- a/arch/arm/mach-sunxi/pmic_bus.c +++ b/arch/arm/mach-sunxi/pmic_bus.c @@ -16,33 +16,10 @@ #include #include -#define AXP152_I2C_ADDR 0x30 - -#define AXP209_I2C_ADDR 0x34 -#define AXP717_I2C_ADDR 0x34 - -#define AXP305_I2C_ADDR 0x36 -#define AXP313_I2C_ADDR 0x36 - #define AXP221_CHIP_ADDR 0x68 #if CONFIG_IS_ENABLED(PMIC_AXP) static struct udevice *pmic; -#else -static int pmic_i2c_address(void) -{ - if (IS_ENABLED(CONFIG_AXP152_POWER)) - return AXP152_I2C_ADDR; - if (IS_ENABLED(CONFIG_AXP305_POWER)) - return AXP305_I2C_ADDR; - if (IS_ENABLED(CONFIG_AXP313_POWER)) - return AXP313_I2C_ADDR; - if (IS_ENABLED(CONFIG_AXP717_POWER)) - return AXP717_I2C_ADDR; - - /* Other AXP2xx and AXP8xx variants */ - return AXP209_I2C_ADDR; -} #endif int pmic_bus_init(void) @@ -88,7 +65,7 @@ int pmic_bus_read(u8 reg, u8 *data) if (IS_ENABLED(CONFIG_SYS_I2C_SUN8I_RSB)) return rsb_read(AXP_PMIC_PRI_RUNTIME_ADDR, reg, data); - return i2c_read(pmic_i2c_address(), reg, 1, data, 1); + return i2c_read(CONFIG_AXP_I2C_ADDRESS, reg, 1, data, 1); #endif } @@ -102,7 +79,7 @@ int pmic_bus_write(u8 reg, u8 data) if (IS_ENABLED(CONFIG_SYS_I2C_SUN8I_RSB)) return rsb_write(AXP_PMIC_PRI_RUNTIME_ADDR, reg, data); - return i2c_write(pmic_i2c_address(), reg, 1, &data, 1); + return i2c_write(CONFIG_AXP_I2C_ADDRESS, reg, 1, &data, 1); #endif } diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 5c73bc75a15..eed65058e66 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -148,6 +148,16 @@ config SY8106A_POWER endchoice +config AXP_I2C_ADDRESS + hex "AXP PMIC I2C address" + depends on ARCH_SUNXI && !SUNXI_NO_PMIC + default 0x36 if AXP305_POWER + default 0x36 if AXP313_POWER + default 0x30 if AXP152_POWER + default 0x34 + ---help--- + I2C address of the AXP PMIC, used for the SPL only. + config AXP_DCDC1_VOLT int "axp pmic dcdc1 voltage" depends on AXP221_POWER || AXP809_POWER || AXP818_POWER || AXP803_POWER From d1d5e1af2415838ca08425370653601e21a4a265 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Fri, 14 Mar 2025 01:01:48 +0000 Subject: [PATCH 06/15] sunxi: Kconfig: consolidate SYS_CLK_FREQ selection Most Allwinner SoCs (used on 107 out of 172 boards) use a default CPU frequency of 1008 MHz during the initial setup in the SPL. Make this the fallback default, in case nothing else is selected, to simplify the Kconfig stanza and make future additions easier. Signed-off-by: Andre Przywara Acked-by: Jernej Skrabec --- arch/arm/mach-sunxi/Kconfig | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index cc28f403fae..b21f364edf2 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -713,16 +713,10 @@ endif config SYS_CLK_FREQ default 408000000 if MACH_SUNIV - default 1008000000 if MACH_SUN4I - default 1008000000 if MACH_SUN5I - default 1008000000 if MACH_SUN6I - default 912000000 if MACH_SUN7I default 816000000 if MACH_SUN50I || MACH_SUN50I_H5 - default 1008000000 if MACH_SUN8I - default 1008000000 if MACH_SUN9I default 888000000 if MACH_SUN50I_H6 - default 1008000000 if MACH_SUN50I_H616 - default 1008000000 if MACH_SUN8I_R528 + default 912000000 if MACH_SUN7I + default 1008000000 config SYS_CONFIG_NAME default "suniv" if MACH_SUNIV From 1f8374ebefece7ccb242aa1c59e149a32f566fc8 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Thu, 2 Jan 2025 11:06:22 +0000 Subject: [PATCH 07/15] spl: reorder SPL_MAX_SIZE defaults for sunxi Reorder the Kconfig defaults for the maximum SPL size, to make the Allwinner specific values more readable and extensible: many older SoCs need to be limited to 32KB, so make this the last ARCH_SUNXI entry, used as a fallback unless explicitly overridden before. Signed-off-by: Andre Przywara Acked-by: Jernej Skrabec --- common/spl/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 97f542fcc8a..36dd064c25a 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -80,11 +80,10 @@ config SPL_MAX_SIZE default 0x1b000 if AM33XX && !TI_SECURE_DEVICE default 0xec00 if OMAP34XX default 0x10000 if ARCH_MX6 && !MX6_OCRAM_256KB - default 0x7fa0 if SUNXI_SRAM_ADDRESS = 0x10000 - default 0x7fa0 if SUNXI_SRAM_ADDRESS = 0x20000 && !MACH_SUN50I_H616 default 0xbfa0 if MACH_SUN50I_H616 default 0x7000 if RCAR_GEN3 default 0x5fa0 if SUNXI_SRAM_ADDRESS = 0x0 + default 0x7fa0 if ARCH_SUNXI default 0x10000 if ASPEED_AST2600 default 0x27000 if IMX8MM && SPL_TEXT_BASE = 0x7E1000 default 0x30000 if ARCH_SC5XX && (SC59X_64 || SC59X) From 7d1936aef7c4046a89660b8f5763bde592946840 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Thu, 26 Oct 2023 00:28:44 +0100 Subject: [PATCH 08/15] clk: sunxi: Add support for the A100/A133 CCU The Allwinner A100 SoC has been around for a while, and has now seemingly been replaced with its close sibling A133. Add support for the CCU, as far as used by U-Boot proper. Linux has some basic (clock and pinctrl) support for a while, so we can already use the existing binding headers. Signed-off-by: Andre Przywara Acked-by: Jernej Skrabec --- arch/arm/mach-sunxi/Kconfig | 3 + drivers/clk/sunxi/Kconfig | 7 +++ drivers/clk/sunxi/Makefile | 1 + drivers/clk/sunxi/clk_a100.c | 102 ++++++++++++++++++++++++++++++++++ drivers/clk/sunxi/clk_sunxi.c | 5 ++ 5 files changed, 118 insertions(+) create mode 100644 drivers/clk/sunxi/clk_a100.c diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index b21f364edf2..ab432390d3c 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -457,6 +457,9 @@ config MACH_SUN50I_H616 select SUN50I_GEN_H6 imply OF_UPSTREAM +config MACH_SUN50I_A133 + bool "sun50i (Allwinner A133)" + endchoice # The sun8i SoCs share a lot, this helps to avoid a lot of "if A23 || A33" diff --git a/drivers/clk/sunxi/Kconfig b/drivers/clk/sunxi/Kconfig index 8bdc0944896..f44db76c182 100644 --- a/drivers/clk/sunxi/Kconfig +++ b/drivers/clk/sunxi/Kconfig @@ -122,4 +122,11 @@ config CLK_SUN50I_A64 This enables common clock driver support for platforms based on Allwinner A64 SoC. +config CLK_SUN50I_A100 + bool "Clock driver for Allwinner A100/A133" + default MACH_SUN50I_A133 + help + This enables common clock driver support for platforms based + on Allwinner A100/A133 SoCs. + endif # CLK_SUNXI diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile index 90a277489dc..7ff71c756e0 100644 --- a/drivers/clk/sunxi/Makefile +++ b/drivers/clk/sunxi/Makefile @@ -24,3 +24,4 @@ obj-$(CONFIG_CLK_SUN50I_H6) += clk_h6.o obj-$(CONFIG_CLK_SUN50I_H6_R) += clk_h6_r.o obj-$(CONFIG_CLK_SUN50I_H616) += clk_h616.o obj-$(CONFIG_CLK_SUN50I_A64) += clk_a64.o +obj-$(CONFIG_CLK_SUN50I_A100) += clk_a100.o diff --git a/drivers/clk/sunxi/clk_a100.c b/drivers/clk/sunxi/clk_a100.c new file mode 100644 index 00000000000..b641feb8612 --- /dev/null +++ b/drivers/clk/sunxi/clk_a100.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2023-2024 Arm Ltd. + */ + +#include +#include +#include +#include + +static struct ccu_clk_gate a100_gates[] = { + [CLK_PLL_PERIPH0] = GATE(0x020, BIT(31) | BIT(27)), + + [CLK_APB1] = GATE_DUMMY, + + [CLK_DE] = GATE(0x600, BIT(31)), + [CLK_BUS_DE] = GATE(0x60c, BIT(0)), + + [CLK_BUS_MMC0] = GATE(0x84c, BIT(0)), + [CLK_BUS_MMC1] = GATE(0x84c, BIT(1)), + [CLK_BUS_MMC2] = GATE(0x84c, BIT(2)), + + [CLK_BUS_UART0] = GATE(0x90c, BIT(0)), + [CLK_BUS_UART1] = GATE(0x90c, BIT(1)), + [CLK_BUS_UART2] = GATE(0x90c, BIT(2)), + [CLK_BUS_UART3] = GATE(0x90c, BIT(3)), + [CLK_BUS_UART4] = GATE(0x90c, BIT(4)), + + [CLK_BUS_I2C0] = GATE(0x91c, BIT(0)), + [CLK_BUS_I2C1] = GATE(0x91c, BIT(1)), + [CLK_BUS_I2C2] = GATE(0x91c, BIT(2)), + [CLK_BUS_I2C3] = GATE(0x91c, BIT(3)), + + [CLK_SPI0] = GATE(0x940, BIT(31)), + [CLK_SPI1] = GATE(0x944, BIT(31)), + [CLK_SPI2] = GATE(0x948, BIT(31)), + + [CLK_BUS_SPI0] = GATE(0x96c, BIT(0)), + [CLK_BUS_SPI1] = GATE(0x96c, BIT(1)), + [CLK_BUS_SPI2] = GATE(0x96c, BIT(2)), + + [CLK_BUS_EMAC] = GATE(0x97c, BIT(0)), + + [CLK_USB_PHY0] = GATE(0xa70, BIT(29)), + [CLK_USB_OHCI0] = GATE(0xa70, BIT(31)), + + [CLK_USB_PHY1] = GATE(0xa74, BIT(29)), + [CLK_USB_OHCI1] = GATE(0xa74, BIT(31)), + + [CLK_BUS_OHCI0] = GATE(0xa8c, BIT(0)), + [CLK_BUS_OHCI1] = GATE(0xa8c, BIT(1)), + [CLK_BUS_EHCI0] = GATE(0xa8c, BIT(4)), + [CLK_BUS_EHCI1] = GATE(0xa8c, BIT(5)), + [CLK_BUS_OTG] = GATE(0xa8c, BIT(8)), + + [CLK_TCON_LCD] = GATE(0xb60, BIT(31)), + [CLK_BUS_TCON_LCD] = GATE(0xb7c, BIT(0)), +}; + +static struct ccu_reset a100_resets[] = { + [RST_BUS_DE] = RESET(0x60c, BIT(16)), + + [RST_BUS_MMC0] = RESET(0x84c, BIT(16)), + [RST_BUS_MMC1] = RESET(0x84c, BIT(17)), + [RST_BUS_MMC2] = RESET(0x84c, BIT(18)), + + [RST_BUS_UART0] = RESET(0x90c, BIT(16)), + [RST_BUS_UART1] = RESET(0x90c, BIT(17)), + [RST_BUS_UART2] = RESET(0x90c, BIT(18)), + [RST_BUS_UART3] = RESET(0x90c, BIT(19)), + [RST_BUS_UART4] = RESET(0x90c, BIT(20)), + + [RST_BUS_I2C0] = RESET(0x91c, BIT(16)), + [RST_BUS_I2C1] = RESET(0x91c, BIT(17)), + [RST_BUS_I2C2] = RESET(0x91c, BIT(18)), + [RST_BUS_I2C3] = RESET(0x91c, BIT(19)), + + [RST_BUS_SPI0] = RESET(0x96c, BIT(16)), + [RST_BUS_SPI1] = RESET(0x96c, BIT(17)), + [RST_BUS_SPI2] = RESET(0x96c, BIT(18)), + + [RST_BUS_EMAC] = RESET(0x97c, BIT(16)), + + [RST_USB_PHY0] = RESET(0xa70, BIT(30)), + + [RST_USB_PHY1] = RESET(0xa74, BIT(30)), + + [RST_BUS_OHCI0] = RESET(0xa8c, BIT(16)), + [RST_BUS_OHCI1] = RESET(0xa8c, BIT(17)), + [RST_BUS_EHCI0] = RESET(0xa8c, BIT(20)), + [RST_BUS_EHCI1] = RESET(0xa8c, BIT(21)), + [RST_BUS_OTG] = RESET(0xa8c, BIT(24)), + + [RST_BUS_TCON_LCD] = RESET(0xb7c, BIT(16)), +}; + +const struct ccu_desc a100_ccu_desc = { + .gates = a100_gates, + .resets = a100_resets, + .num_gates = ARRAY_SIZE(a100_gates), + .num_resets = ARRAY_SIZE(a100_resets), +}; diff --git a/drivers/clk/sunxi/clk_sunxi.c b/drivers/clk/sunxi/clk_sunxi.c index 2ef4f45dacf..e0765cbc6dc 100644 --- a/drivers/clk/sunxi/clk_sunxi.c +++ b/drivers/clk/sunxi/clk_sunxi.c @@ -122,6 +122,7 @@ extern const struct ccu_desc f1c100s_ccu_desc; extern const struct ccu_desc h3_ccu_desc; extern const struct ccu_desc h6_ccu_desc; extern const struct ccu_desc h616_ccu_desc; +extern const struct ccu_desc a100_ccu_desc; extern const struct ccu_desc h6_r_ccu_desc; extern const struct ccu_desc r40_ccu_desc; extern const struct ccu_desc v3s_ccu_desc; @@ -215,6 +216,10 @@ static const struct udevice_id sunxi_clk_ids[] = { { .compatible = "allwinner,sun50i-h616-r-ccu", .data = (ulong)&h6_r_ccu_desc }, #endif +#ifdef CONFIG_CLK_SUN50I_A100 + { .compatible = "allwinner,sun50i-a100-ccu", + .data = (ulong)&a100_ccu_desc }, +#endif #ifdef CONFIG_CLK_SUNIV_F1C100S { .compatible = "allwinner,suniv-f1c100s-ccu", .data = (ulong)&f1c100s_ccu_desc }, From 17c1add327713cb7df80cf52cac0beaf9986542a Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Thu, 26 Oct 2023 00:38:59 +0100 Subject: [PATCH 09/15] pinctrl: sunxi: add Allwinner A100/A133 pinctrl description The Allwinner A100 SoC has been around for a while, and has now seemingly been replaced with its close sibling A133. Add the required mapping between the pinmux group strings and their respective mux value, as far as used by U-Boot proper. Linux has some basic (clock and pinctrl) support for a while, so we can build on the names already used there. Signed-off-by: Andre Przywara Acked-by: Jernej Skrabec --- drivers/pinctrl/sunxi/Kconfig | 10 ++++++ drivers/pinctrl/sunxi/pinctrl-sunxi.c | 47 +++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig index cbd61795986..65e8192a99a 100644 --- a/drivers/pinctrl/sunxi/Kconfig +++ b/drivers/pinctrl/sunxi/Kconfig @@ -124,6 +124,16 @@ config PINCTRL_SUN50I_H616_R default MACH_SUN50I_H616 select PINCTRL_SUNXI +config PINCTRL_SUN50I_A100 + bool "Support for the Allwinner A100/A133 PIO" + default MACH_SUN50I_A133 + select PINCTRL_SUNXI + +config PINCTRL_SUN50I_A100_R + bool "Support for the Allwinner A100/A133 R-PIO" + default MACH_SUN50I_A133 + select PINCTRL_SUNXI + config PINCTRL_SUN20I_D1 bool "Support for the Allwinner D1/R528 PIO" default MACH_SUN8I_R528 diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 37ea93715d1..c38edf7d4f5 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -774,6 +774,41 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h616_r_pinctrl_desc .num_banks = 1, }; +static const struct sunxi_pinctrl_function sun50i_a100_pinctrl_functions[] = { + { "emac0", 5 }, /* PH0-PH16 */ + { "gpio_in", 0 }, + { "gpio_out", 1 }, + { "mmc0", 2 }, /* PF0-PF5 */ + { "mmc1", 2 }, /* PG0-PG5 */ + { "mmc2", 3 }, /* PC0-PC16 */ + { "spi0", 4 }, /* PC2-PC4, PC7, PC12, PC15-PC16 */ +#if IS_ENABLED(CONFIG_UART0_PORT_F) + { "uart0", 3 }, /* PF2-PF4 */ +#else + { "uart0", 2 }, /* PB9-PB10 */ +#endif +}; + +static const struct sunxi_pinctrl_desc __maybe_unused sun50i_a100_pinctrl_desc = { + .functions = sun50i_a100_pinctrl_functions, + .num_functions = ARRAY_SIZE(sun50i_a100_pinctrl_functions), + .first_bank = SUNXI_GPIO_A, + .num_banks = 8, +}; + +static const struct sunxi_pinctrl_function sun50i_a100_r_pinctrl_functions[] = { + { "gpio_in", 0 }, + { "gpio_out", 1 }, + { "s_i2c0", 2 }, +}; + +static const struct sunxi_pinctrl_desc __maybe_unused sun50i_a100_r_pinctrl_desc = { + .functions = sun50i_a100_r_pinctrl_functions, + .num_functions = ARRAY_SIZE(sun50i_a100_r_pinctrl_functions), + .first_bank = SUNXI_GPIO_L, + .num_banks = 1, +}; + static const struct udevice_id sunxi_pinctrl_ids[] = { #ifdef CONFIG_PINCTRL_SUNIV_F1C100S { @@ -936,6 +971,18 @@ static const struct udevice_id sunxi_pinctrl_ids[] = { .compatible = "allwinner,sun50i-h616-r-pinctrl", .data = (ulong)&sun50i_h616_r_pinctrl_desc, }, +#endif +#ifdef CONFIG_PINCTRL_SUN50I_A100 + { + .compatible = "allwinner,sun50i-a100-pinctrl", + .data = (ulong)&sun50i_a100_pinctrl_desc, + }, +#endif +#ifdef CONFIG_PINCTRL_SUN50I_A100_R + { + .compatible = "allwinner,sun50i-a100-r-pinctrl", + .data = (ulong)&sun50i_a100_r_pinctrl_desc, + }, #endif {} }; From 40c687aef01fd0ccdf24285f577db1bc0d64db16 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Sun, 9 Mar 2025 07:31:42 +0100 Subject: [PATCH 10/15] sunxi: h616: dram: Rework size detection Since there is quite a few possible DRAM configurations in terms of bus width, rank and rows and columns count, size detection algorithm must be very careful not to test combination which would be bigger than H616 is actually capable of handling. Ideally, we should always detect memory aliasing, even for 4 GB memory size, which is the maximum amount of memory that H616 is capable of handling. For this reason, we have to configure minimum amount of supported rows when testing for columns and vice versa. This way test code will never step out of 4 GB boundary. While at it, check for 17 rows maximum. This aligns code with BSP DRAM driver. There is probably no such configuration which would make sense with 4 GB memory. Signed-off-by: Jernej Skrabec Reviewed-by: Icenowy Zheng Reviewed-by: Andre Przywara --- arch/arm/mach-sunxi/dram_sun50i_h616.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c index b3554cc64bf..6f84e59e39c 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h616.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c @@ -1363,7 +1363,7 @@ static void mctl_auto_detect_rank_width(const struct dram_para *para, static void mctl_auto_detect_dram_size(const struct dram_para *para, struct dram_config *config) { - unsigned int shift; + unsigned int shift, cols, rows; /* max. config for columns, but not rows */ config->cols = 11; @@ -1373,23 +1373,27 @@ static void mctl_auto_detect_dram_size(const struct dram_para *para, shift = config->bus_full_width + 1; /* detect column address bits */ - for (config->cols = 8; config->cols < 11; config->cols++) { - if (mctl_mem_matches(1ULL << (config->cols + shift))) + for (cols = 8; cols < 11; cols++) { + if (mctl_mem_matches(1ULL << (cols + shift))) break; } - debug("detected %u columns\n", config->cols); + debug("detected %u columns\n", cols); /* reconfigure to make sure that all active rows are accessible */ - config->rows = 18; + config->cols = 8; + config->rows = 17; mctl_core_init(para, config); /* detect row address bits */ shift = config->bus_full_width + 4 + config->cols; - for (config->rows = 13; config->rows < 18; config->rows++) { - if (mctl_mem_matches(1ULL << (config->rows + shift))) + for (rows = 13; rows < 17; rows++) { + if (mctl_mem_matches(1ULL << (rows + shift))) break; } - debug("detected %u rows\n", config->rows); + debug("detected %u rows\n", rows); + + config->cols = cols; + config->rows = rows; } static unsigned long mctl_calc_size(const struct dram_config *config) From 380802938673c6c82b776a33eda6d57eba7ca914 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Sun, 9 Mar 2025 07:31:43 +0100 Subject: [PATCH 11/15] sunxi: H616: dram: Improve address wrapping detection It turns out that checking just one write is not enough. Due to unexplained reasons scan procedure detected double the size. By making 16 dword writes and comparisons that never happens. New procedure is also inverted. Instead of writing two different values to base address and some offset and then reading both and comparing values, simplify this by writing pattern at the base address and then search for this pattern at some offset. Signed-off-by: Jernej Skrabec Tested-by: Ryan Walklin Reviewed-by: Andre Przywara --- arch/arm/mach-sunxi/dram_sun50i_h616.c | 58 +++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c index 6f84e59e39c..cd9d321a018 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h616.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c @@ -1360,38 +1360,92 @@ static void mctl_auto_detect_rank_width(const struct dram_para *para, panic("This DRAM setup is currently not supported.\n"); } +static void mctl_write_pattern(void) +{ + unsigned int i; + u32 *ptr, val; + + ptr = (u32 *)CFG_SYS_SDRAM_BASE; + for (i = 0; i < 16; ptr++, i++) { + if (i & 1) + val = ~(ulong)ptr; + else + val = (ulong)ptr; + writel(val, ptr); + } +} + +static bool mctl_check_pattern(ulong offset) +{ + unsigned int i; + u32 *ptr, val; + + ptr = (u32 *)CFG_SYS_SDRAM_BASE; + for (i = 0; i < 16; ptr++, i++) { + if (i & 1) + val = ~(ulong)ptr; + else + val = (ulong)ptr; + if (val != *(ptr + offset / 4)) + return false; + } + + return true; +} + static void mctl_auto_detect_dram_size(const struct dram_para *para, struct dram_config *config) { unsigned int shift, cols, rows; + u32 buffer[16]; /* max. config for columns, but not rows */ config->cols = 11; config->rows = 13; mctl_core_init(para, config); + /* + * Store content so it can be restored later. This is important + * if controller was already initialized and holds any data + * which is important for restoring system. + */ + memcpy(buffer, (u32 *)CFG_SYS_SDRAM_BASE, sizeof(buffer)); + + mctl_write_pattern(); + shift = config->bus_full_width + 1; /* detect column address bits */ for (cols = 8; cols < 11; cols++) { - if (mctl_mem_matches(1ULL << (cols + shift))) + if (mctl_check_pattern(1ULL << (cols + shift))) break; } debug("detected %u columns\n", cols); + /* restore data */ + memcpy((u32 *)CFG_SYS_SDRAM_BASE, buffer, sizeof(buffer)); + /* reconfigure to make sure that all active rows are accessible */ config->cols = 8; config->rows = 17; mctl_core_init(para, config); + /* store data again as it might be moved */ + memcpy(buffer, (u32 *)CFG_SYS_SDRAM_BASE, sizeof(buffer)); + + mctl_write_pattern(); + /* detect row address bits */ shift = config->bus_full_width + 4 + config->cols; for (rows = 13; rows < 17; rows++) { - if (mctl_mem_matches(1ULL << (rows + shift))) + if (mctl_check_pattern(1ULL << (rows + shift))) break; } debug("detected %u rows\n", rows); + /* restore data again */ + memcpy((u32 *)CFG_SYS_SDRAM_BASE, buffer, sizeof(buffer)); + config->cols = cols; config->rows = rows; } From 3e78f8f407a0a0e7b50aa7eaa6f2f579f35e9837 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Sun, 9 Mar 2025 07:12:41 +0100 Subject: [PATCH 12/15] sunxi: mmc: Improve reset procedure Cards should always be reset and threshold set. This fixes eMMC on H616. Signed-off-by: Jernej Skrabec [Andre: use macro-defined offsets to fix build on older SoCs] Signed-off-by: Andre Przywara --- drivers/mmc/sunxi_mmc.c | 28 ++++++++++++++++++++++------ drivers/mmc/sunxi_mmc.h | 18 ++++++++++++++++-- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index 8f72d758e46..951e6acd34d 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -449,6 +449,26 @@ out: return error; } +static void sunxi_mmc_reset(void *regs) +{ + /* Reset controller */ + writel(SUNXI_MMC_GCTRL_RESET, regs + SUNXI_MMC_GCTRL); + udelay(1000); + + if (IS_ENABLED(CONFIG_SUN50I_GEN_H6) || IS_ENABLED(CONFIG_SUNXI_GEN_NCAT2)) { + /* Reset card */ + writel(SUNXI_MMC_HWRST_ASSERT, regs + SUNXI_MMC_HWRST); + udelay(10); + writel(SUNXI_MMC_HWRST_DEASSERT, regs + SUNXI_MMC_HWRST); + udelay(300); + + /* Setup FIFO R/W threshold. Needed on H616. */ + writel(SUNXI_MMC_THLDC_READ_THLD(512) | + SUNXI_MMC_THLDC_WRITE_EN | + SUNXI_MMC_THLDC_READ_EN, regs + SUNXI_MMC_THLDC); + } +} + /* non-DM code here is used by the (ARM) SPL only */ #if !CONFIG_IS_ENABLED(DM_MMC) @@ -496,9 +516,7 @@ static int sunxi_mmc_core_init(struct mmc *mmc) { struct sunxi_mmc_priv *priv = mmc->priv; - /* Reset controller */ - writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl); - udelay(1000); + sunxi_mmc_reset(priv->reg); return 0; } @@ -691,9 +709,7 @@ static int sunxi_mmc_probe(struct udevice *dev) upriv->mmc = &plat->mmc; - /* Reset controller */ - writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl); - udelay(1000); + sunxi_mmc_reset(priv->reg); return 0; } diff --git a/drivers/mmc/sunxi_mmc.h b/drivers/mmc/sunxi_mmc.h index f4ae5a790c8..71865160319 100644 --- a/drivers/mmc/sunxi_mmc.h +++ b/drivers/mmc/sunxi_mmc.h @@ -37,7 +37,9 @@ struct sunxi_mmc { u32 res0; /* 0x54 reserved */ u32 a12a; /* 0x58 Auto command 12 argument */ u32 ntsr; /* 0x5c New timing set register */ - u32 res1[8]; + u32 res1[6]; + u32 hwrst; /* 0x78 Hardware Reset */ + u32 res5; u32 dmac; /* 0x80 internal DMA control */ u32 dlba; /* 0x84 internal DMA descr list base address */ u32 idst; /* 0x88 internal DMA status */ @@ -46,7 +48,8 @@ struct sunxi_mmc { u32 cbda; /* 0x94 */ u32 res2[26]; #if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6) || defined(CONFIG_SUNXI_GEN_NCAT2) - u32 res3[17]; + u32 thldc; /* 0x100 Threshold control */ + u32 res3[16]; u32 samp_dl; u32 res4[46]; #endif @@ -57,6 +60,7 @@ struct sunxi_mmc { #define SUNXI_MMC_CLK_ENABLE (0x1 << 16) #define SUNXI_MMC_CLK_DIVIDER_MASK (0xff) +#define SUNXI_MMC_GCTRL 0x000 #define SUNXI_MMC_GCTRL_SOFT_RESET (0x1 << 0) #define SUNXI_MMC_GCTRL_FIFO_RESET (0x1 << 1) #define SUNXI_MMC_GCTRL_DMA_RESET (0x1 << 2) @@ -123,6 +127,10 @@ struct sunxi_mmc { #define SUNXI_MMC_NTSR_MODE_SEL_NEW (0x1 << 31) +#define SUNXI_MMC_HWRST 0x078 +#define SUNXI_MMC_HWRST_ASSERT (0x0 << 0) +#define SUNXI_MMC_HWRST_DEASSERT (0x1 << 0) + #define SUNXI_MMC_IDMAC_RESET (0x1 << 0) #define SUNXI_MMC_IDMAC_FIXBURST (0x1 << 1) #define SUNXI_MMC_IDMAC_ENABLE (0x1 << 7) @@ -133,6 +141,12 @@ struct sunxi_mmc { #define SUNXI_MMC_COMMON_CLK_GATE (1 << 16) #define SUNXI_MMC_COMMON_RESET (1 << 18) +#define SUNXI_MMC_THLDC 0x100 +#define SUNXI_MMC_THLDC_READ_EN (0x1 << 0) +#define SUNXI_MMC_THLDC_BSY_CLR_INT_EN (0x1 << 1) +#define SUNXI_MMC_THLDC_WRITE_EN (0x1 << 2) +#define SUNXI_MMC_THLDC_READ_THLD(x) (((x) & 0xfff) << 16) + #define SUNXI_MMC_CAL_DL_SW_EN (0x1 << 7) #endif /* _SUNXI_MMC_H */ From abb086efd5d08fcb2759d325d39630a576c3dfbc Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Sun, 23 Mar 2025 11:35:34 +0000 Subject: [PATCH 13/15] sunxi: armv8: fel: move fel_stash variable to the front To return a 64-bit Allwinner chip back to the 32-bit BootROM code, we have some embedded AArch32 code that restores the CPU state, before branching back to the BootROM. At the moment the pointer to the buffer with that state is located *after* the code, which makes the PC relative code fragile: adding or removing instructions will change the distance to that pointer variable. The "new" Allwinner A523 SoC requires more state to be restored (GICv3 system registers), but we must do that *only* on that SoC. Conditional compilation sounds like the easiest solution, but would mean that the distance to that pointer would change. Solve this rather easily by moving the pointer to the *front* of the code: we load that pointer in the first instruction, so the distance would always stay the same. Later in the code we won't need PC relative addressing anymore, so this code can grow or shrink easily, for instance due to conditional compilation. Signed-off-by: Andre Przywara Reviewed-by: Jernej Skrabec --- arch/arm/cpu/armv8/fel_utils.S | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/arm/cpu/armv8/fel_utils.S b/arch/arm/cpu/armv8/fel_utils.S index 939869b9ffa..f7707acdf1a 100644 --- a/arch/arm/cpu/armv8/fel_utils.S +++ b/arch/arm/cpu/armv8/fel_utils.S @@ -63,9 +63,12 @@ ENTRY(return_to_fel) 1: wfi b 1b +fel_stash_addr: // must immediately precede back_in_32: + .word 0x00000000 // receives fel_stash addr, by AA64 code above + /* AArch32 code to restore the state from fel_stash and return back to FEL. */ back_in_32: - .word 0xe59f0028 // ldr r0, [pc, #40] ; load fel_stash address + .word 0xe51f000c // ldr r0, [pc, #-12] ; load fel_stash address .word 0xe5901008 // ldr r1, [r0, #8] .word 0xe129f001 // msr CPSR_fc, r1 .word 0xf57ff06f // isb @@ -77,6 +80,4 @@ back_in_32: .word 0xee011f10 // mcr 15, 0, r1, cr1, cr0, {0} ; SCTLR .word 0xf57ff06f // isb .word 0xe12fff1e // bx lr ; return to FEL -fel_stash_addr: - .word 0x00000000 // receives fel_stash addr, by AA64 code above ENDPROC(return_to_fel) From f8f6c867d934948acdcd83bc3b13c02763b5c9df Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Sun, 23 Mar 2025 11:35:35 +0000 Subject: [PATCH 14/15] sunxi: arm64: boot0.h: move fel_stash_addr variable to the front To be able to return to the BootROM when booting via the FEL USB protocol, we need to save the CPU state very early, which we need to do in the embedded AArch32 code. At the moment the pointer to the buffer for that state is located *after* the code, which makes the PC relative code fragile: adding or removing instructions will change the distance to that pointer variable. The "new" Allwinner A523 SoC requires more state to be saved (GICv3 system registers), but we must do that *only* on that SoC. Conditional compilation sounds like the easiest solution, but would mean that the distance to that pointer would change. Solve this rather easily by moving the pointer to the *front* of the code: we load that pointer in the first instructions, so the distance would always stay the same. Later in the code we won't need PC relative addressing anymore, so this code can grow or shrink easily, for instance due to conditional compilation. Signed-off-by: Andre Przywara Reviewed-by: Jernej Skrabec --- arch/arm/include/asm/arch-sunxi/boot0.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/boot0.h b/arch/arm/include/asm/arch-sunxi/boot0.h index 6b2bb5a4586..24c81391d58 100644 --- a/arch/arm/include/asm/arch-sunxi/boot0.h +++ b/arch/arm/include/asm/arch-sunxi/boot0.h @@ -16,10 +16,11 @@ */ tst x0, x0 // this is "b #0x84" in ARM b reset - .space 0x7c + .space 0x78 + .word fel_stash - . - .word 0xe28f0070 // add r0, pc, #112 // @(fel_stash - .) - .word 0xe59f106c // ldr r1, [pc, #108] // fel_stash - . + .word 0xe24f000c // sub r0, pc, #12 // @(fel_stash - .) + .word 0xe51f1010 // ldr r1, [pc, #-16] // fel_stash - . .word 0xe0800001 // add r0, r0, r1 .word 0xe580d000 // str sp, [r0] .word 0xe580e004 // str lr, [r0, #4] @@ -54,7 +55,6 @@ #else .word CONFIG_TEXT_BASE #endif - .word fel_stash - . #else /* normal execution */ b reset From 6d6d58be25dd0b8e1955b15cf197f418be58bfd9 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Sun, 23 Mar 2025 11:35:36 +0000 Subject: [PATCH 15/15] sunxi: update rmr_switch.S source code Because the Allwinner BootROM always runs in AArch32, even on ARMv8 SoCs, we need to switch to AArch64 first, but also need to save the CPU state, when we later may need to return to the BootROM, for continuing with the FEL USB protocol. This is done in 32-bit code, which we include into the AArch64 boot assembly file as a series of .word directives, containing the encoded AArch32 instructions. To be able to change and verify that code, we also kept an assembly file with the respective 32-bit code, but just for reference. As this code is never compiled or assembled - it's just for documentation - it became stale over time: we didn't really update this along with the changes we made to the boot code. In particular the FEL save code was completely missing. Update that 32-bit assembly file, to match the current version used in boot0.h, including the FEL save routine. Also update the build instructions in the comments, to give people an actual chance to assemble this code. Signed-off-by: Andre Przywara Acked-by: Jernej Skrabec --- arch/arm/mach-sunxi/rmr_switch.S | 40 +++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-sunxi/rmr_switch.S b/arch/arm/mach-sunxi/rmr_switch.S index 33e55d49686..422007c985b 100644 --- a/arch/arm/mach-sunxi/rmr_switch.S +++ b/arch/arm/mach-sunxi/rmr_switch.S @@ -16,7 +16,9 @@ @ the machine code must be inserted as verbatim .word statements into the @ beginning of the AArch64 U-Boot code. @ To get the encoded bytes, use: -@ ${CROSS_COMPILE}gcc -c -o rmr_switch.o rmr_switch.S +@ ${CROSS_COMPILE}gcc -c -Iinclude -Iarch/arm/include \ +@ -D__ASSEMBLY__ -DCONFIG_ARM64 \ +@ -o rmr_switch.o arch/arm/mach-sunxi/rmr_switch.S @ ${CROSS_COMPILE}objdump -d rmr_switch.o @ @ The resulting words should be inserted into the U-Boot file at @@ -29,14 +31,40 @@ #include .text + b start32 // this is "tst x0, x0" in AArch64 + .word 0x14000047 // this is "b reset" in AArch64 -#ifndef CONFIG_SUN50I_GEN_H6 - ldr r1, =0x017000a0 @ MMIO mapped RVBAR[0] register + .space 0x78 // gap distance set by the common + // encoding of the first instruction +fel_stash_addr: + .word fel_stash - . // distance to fel_stash buffer + +start32: + adr r0, fel_stash_addr // absolute location of fel_stash_addr + ldr r1, fel_stash_addr // distance to actual fel_stash + add r0, r0, r1 // real address of fel_stash + + /* save the current state as needed by the BROM for a later return */ + str sp, [r0] + str lr, [r0, #4] + mrs lr, CPSR + str lr, [r0, #8] + mrc p15, 0, lr, cr1, cr0, 0 // SCTLR + str lr, [r0, #12] + mrc p15, 0, lr, cr12, cr0, 0 // VBAR + str lr, [r0, #16] + + ldr r1, =CONFIG_SUNXI_RVBAR_ADDRESS + ldr r0, =SUNXI_SRAMC_BASE + ldr r0, [r0, #36] // SRAM_VER_REG + ands r0, r0, #0xff + ldrne r1, =CONFIG_SUNXI_RVBAR_ALTERNATIVE +#ifdef CONFIG_XPL_BUILD + ldr r0, =CONFIG_SPL_TEXT_BASE #else - ldr r1, =0x09010040 @ MMIO mapped RVBAR[0] register + ldr r0, =CONFIG_TEXT_BASE #endif - ldr r0, =0x57aA7add @ start address, to be replaced - str r0, [r1] + str r0, [r1] // store start address in RVBAR dsb sy isb sy mrc 15, 0, r0, cr12, cr0, 2 @ read RMR register