From 256557dd9aae376afcc3c3bc23cd739f427e9dc7 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Wed, 28 Jan 2026 17:01:25 +0100 Subject: [PATCH 1/3] sunxi: remove usage of legacy LED API We are trying to get rid of the legacy LED API and PinePhone is one of the last ones requiring it. Unlike all other users of the legacy LED API, PinePhone is controlling the GPIO LED in SPL. Unfortunately, Sunxi doesn't enable DM support in SPL because of tight space constraints, so we cannot make use of the modern LED framework as that is based on DM_GPIO. Since PinePhone is the last user of this API, I'm moving the logic to Sunxi SPL code and will let this community decide how to handle this hot potato. The logic is extremely simplified as only one GPIO LED is currently controlled in SPL by PinePhone. No need for handling multiple LEDs or inverted polarity, let's keep it simple. This however allows us to use the modern LED framework once in U-Boot proper since this logic won't collide with the new framework. Since the only misc drivers that were compiled in SPL were guarded by CONFIG_LED_STATUS and CONFIG_LED_STATUS_GPIO, we can also disable CONFIG_SPL_DRIVERS_MISC (which does nothing anymore). This also saves some space for PinePhone in SPL and proper. Tested-by: Andre Przywara Signed-off-by: Quentin Schulz Reviewed-by: Simon Glass --- arch/arm/mach-sunxi/Kconfig | 18 ++++++++++++++++++ board/sunxi/board.c | 16 ++++++++++++---- configs/pinephone_defconfig | 9 +++------ 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index e979ee4a2cc..a60ebe1d964 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -1232,6 +1232,24 @@ config CHIP_DIP_SCAN select W1_EEPROM_DS24XXX select CMD_EXTENSION +config SPL_SUNXI_LED_STATUS + bool "Control GPIO status LED within SPL" + depends on SPL_GPIO && SUNXI_GPIO + +if SPL_SUNXI_LED_STATUS + +config SPL_SUNXI_LED_STATUS_BIT + int "GPIO number for GPIO status LED" + help + GPIO number for the GPIO controlling the GPIO status LED in SPL. + +config SPL_SUNXI_LED_STATUS_STATE + bool "GPIO status LED initial state is on" + help + Whether the initial state of the status LED in SPL must be on or off. + +endif # SPL_SUNXI_LED_STATUS + source "board/sunxi/Kconfig" endif diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 954a8715075..d7722d1858a 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -50,7 +50,6 @@ #include #include #include -#include DECLARE_GLOBAL_DATA_PTR; @@ -561,14 +560,23 @@ static void sunxi_spl_store_dram_size(phys_addr_t dram_size) spl->dram_size = dram_size >> 20; } +static void status_led_init(void) +{ +#if CONFIG_IS_ENABLED(SUNXI_LED_STATUS) + unsigned int state = CONFIG_SPL_SUNXI_LED_STATUS_STATE; + unsigned int gpio = CONFIG_SPL_SUNXI_LED_STATUS_BIT; + + gpio_request(gpio, "gpio_led"); + gpio_direction_output(gpio, state); +#endif +} + void sunxi_board_init(void) { int power_failed = 0; -#ifdef CONFIG_LED_STATUS - if (IS_ENABLED(CONFIG_SPL_DRIVERS_MISC)) + if (CONFIG_IS_ENABLED(SUNXI_LED_STATUS)) status_led_init(); -#endif #ifdef CONFIG_SY8106A_POWER power_failed = sy8106a_set_vout1(CONFIG_SY8106A_VOUT1_VOLT); diff --git a/configs/pinephone_defconfig b/configs/pinephone_defconfig index 8a9916c7978..ed7dbc1852b 100644 --- a/configs/pinephone_defconfig +++ b/configs/pinephone_defconfig @@ -2,20 +2,17 @@ CONFIG_ARM=y CONFIG_ARCH_SUNXI=y CONFIG_DEFAULT_DEVICE_TREE="sun50i-a64-pinephone-1.2" CONFIG_DRAM_CLK=552 -CONFIG_SPL_DRIVERS_MISC=y CONFIG_SPL=y CONFIG_MACH_SUN50I=y CONFIG_SUNXI_DRAM_LPDDR3_STOCK=y CONFIG_DRAM_ZQ=3881949 CONFIG_MMC_SUNXI_SLOT_EXTRA=2 CONFIG_PINEPHONE_DT_SELECTION=y +CONFIG_SPL_SUNXI_LED_STATUS=y +CONFIG_SPL_SUNXI_LED_STATUS_BIT=114 +CONFIG_SPL_SUNXI_LED_STATUS_STATE=y # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set CONFIG_CMD_PSTORE=y CONFIG_CMD_PSTORE_MEM_ADDR=0x61000000 CONFIG_OF_LIST="sun50i-a64-pinephone-1.1 sun50i-a64-pinephone-1.2" CONFIG_SYS_I2C_MVTWSI=y -CONFIG_LED_STATUS=y -CONFIG_LED_STATUS_GPIO=y -CONFIG_LED_STATUS0=y -CONFIG_LED_STATUS_BIT=114 -CONFIG_LED_STATUS_STATE=2 From 3d769809474cfb9534c317d9a6a0a8ef51a47181 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Thu, 29 Jan 2026 00:57:16 +0100 Subject: [PATCH 2/3] sunxi: a133: dram: Fix PHY dx delays offsets and add dmb Some of the offsets for the DRAM PHY dx delays are wrong (as compared to the H616 code and the reference binary) since the mctl_phy_dx_delay0_inner function does not perform the correct calculation for some of them. Introduce a mctl_phy_dx_delay0_inner0 to fix the incorrect offsets and rename the existing function to mctl_phy_dx_delay0_inner1 for the offsets it correctly handles. Also add memory barriers that are also present in the H616 code while at it. This fixes detection of 4 GiB DRAM on some boards using LPDDR4. Signed-off-by: Paul Kocialkowski Sponsored-by: MEC Electronics GmbH Acked-by: Jernej Skrabec --- arch/arm/mach-sunxi/dram_sun50i_a133.c | 55 ++++++++++++++++++-------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/arch/arm/mach-sunxi/dram_sun50i_a133.c b/arch/arm/mach-sunxi/dram_sun50i_a133.c index 1496f99624d..e5c46e036cb 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_a133.c +++ b/arch/arm/mach-sunxi/dram_sun50i_a133.c @@ -871,7 +871,24 @@ static inline void mctl_phy_dx_delay1_inner(u32 *base, u32 val1, u32 val2) writel_relaxed(val2, ptr + 48); } -static inline void mctl_phy_dx_delay0_inner(u32 *base1, u32 *base2, u32 val1, +static inline void mctl_phy_dx_delay0_inner0(u32 *base1, u32 *base2, u32 val1, + u32 val2) +{ + u32 *ptr = base1; + + for (int i = 0; i < 9; i++) { + writel_relaxed(val1, ptr); + writel_relaxed(val1, ptr + 0x30); + ptr += 2; + } + + writel_relaxed(val2, base2); + writel_relaxed(val2, base2 + 48); + writel_relaxed(val2, ptr); + writel_relaxed(val2, base2 + 24); +} + +static inline void mctl_phy_dx_delay0_inner1(u32 *base1, u32 *base2, u32 val1, u32 val2) { u32 *ptr = base1; @@ -915,6 +932,8 @@ static void mctl_phy_dx_delay_compensation(const struct dram_para *para) (para->tpr11 >> 24) & 0x3f, (para->para0 >> 24) & 0x3f); + dmb(); + setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x60, 1); } @@ -922,25 +941,27 @@ static void mctl_phy_dx_delay_compensation(const struct dram_para *para) clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x54, BIT(7)); clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, BIT(2)); - mctl_phy_dx_delay0_inner((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x480), - (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x528), - para->tpr12 & 0x3f, - para->tpr14 & 0x3f); + mctl_phy_dx_delay0_inner0((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x480), + (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x528), + para->tpr12 & 0x3f, + para->tpr14 & 0x3f); - mctl_phy_dx_delay0_inner((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x4d4), - (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x52c), - (para->tpr12 >> 8) & 0x3f, - (para->tpr14 >> 8) & 0x3f); + mctl_phy_dx_delay0_inner1((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x4d4), + (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x52c), + (para->tpr12 >> 8) & 0x3f, + (para->tpr14 >> 8) & 0x3f); - mctl_phy_dx_delay0_inner((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x600), - (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x6a8), - (para->tpr12 >> 16) & 0x3f, - (para->tpr14 >> 16) & 0x3f); + mctl_phy_dx_delay0_inner0((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x600), + (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x6a8), + (para->tpr12 >> 16) & 0x3f, + (para->tpr14 >> 16) & 0x3f); - mctl_phy_dx_delay0_inner((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x6ac), - (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x528), - (para->tpr12 >> 24) & 0x3f, - (para->tpr14 >> 24) & 0x3f); + mctl_phy_dx_delay0_inner1((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x654), + (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x6ac), + (para->tpr12 >> 24) & 0x3f, + (para->tpr14 >> 24) & 0x3f); + + dmb(); setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x54, BIT(7)); } From 98429b7be6f45d393cc905b2cf9844eed7b09b8a Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Thu, 29 Jan 2026 00:57:17 +0100 Subject: [PATCH 3/3] sunxi: a133: dram: Align parameters terminology with Allwinner There is a mistmatch between Allwinner's dram_para BSP definitions and the parameters names in mainline u-boot for TPR1-3. What we call TPR1 is actually MR22 while TPR2 is TPR0 and TPR3 is TPR1. MR22 does get written to the corresponding register. This only concerns LPDDR4 support. Introduce a new Kconfig entry for MR22 and proceed with the rename. Update the only config currently using it. See the list of parameters from the Allwinner BSP at the end of: https://linux-sunxi.org/A133/DRAMC Note that the H616/H6 code is coherent with this new TPR0 definition (and does not use TPR1 and MR22). Signed-off-by: Paul Kocialkowski Sponsored-by: MEC Electronics GmbH Acked-by: Jernej Skrabec --- arch/arm/include/asm/arch-sunxi/dram_sun50i_a133.h | 2 ++ arch/arm/mach-sunxi/Kconfig | 7 +++++++ arch/arm/mach-sunxi/dram_sun50i_a133.c | 12 ++++++------ configs/liontron-h-a133l_defconfig | 6 +++--- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun50i_a133.h b/arch/arm/include/asm/arch-sunxi/dram_sun50i_a133.h index a5fc6ad3656..01f2214cd15 100644 --- a/arch/arm/include/asm/arch-sunxi/dram_sun50i_a133.h +++ b/arch/arm/include/asm/arch-sunxi/dram_sun50i_a133.h @@ -205,6 +205,8 @@ struct dram_para { uint32_t mr12; uint32_t mr13; uint32_t mr14; + uint32_t mr22; + uint32_t tpr0; uint32_t tpr1; uint32_t tpr2; uint32_t tpr3; diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index a60ebe1d964..89f0e77bcdb 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -118,6 +118,13 @@ config DRAM_SUNXI_MR14 help MR14 value from vendor DRAM settings. +config DRAM_SUNXI_MR22 + hex "DRAM MR22 parameter" + depends on DRAM_SUN50I_A133 + default 0x0 + help + MR22 value from vendor DRAM settings. + config DRAM_SUNXI_TPR0 hex "DRAM TPR0 parameter" default 0x0 diff --git a/arch/arm/mach-sunxi/dram_sun50i_a133.c b/arch/arm/mach-sunxi/dram_sun50i_a133.c index e5c46e036cb..ca3e2513c69 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_a133.c +++ b/arch/arm/mach-sunxi/dram_sun50i_a133.c @@ -426,8 +426,8 @@ static void mctl_drive_odt_config(const struct dram_para *para) writel_relaxed(val, base); if (para->type == SUNXI_DRAM_TYPE_LPDDR4) { - if (para->tpr3 & 0x1f1f1f1f) - val = (para->tpr3 >> (i * 8)) & 0x1f; + if (para->tpr1 & 0x1f1f1f1f) + val = (para->tpr1 >> (i * 8)) & 0x1f; else val = 4; } @@ -468,7 +468,7 @@ static void mctl_phy_ca_bit_delay_compensation(const struct dram_para *para) u32 *ptr; if (para->tpr10 & BIT(31)) { - val = para->tpr2; + val = para->tpr0; } else { val = ((para->tpr10 << 1) & 0x1e) | ((para->tpr10 << 5) & 0x1e00) | @@ -781,7 +781,7 @@ static void mctl_dfi_init(const struct dram_para *para) mctl_mr_write_lpddr4(12, para->mr12); mctl_mr_write_lpddr4(13, para->mr13); mctl_mr_write_lpddr4(14, para->mr14); - mctl_mr_write_lpddr4(22, para->tpr1); + mctl_mr_write_lpddr4(22, para->mr22); break; } @@ -1182,7 +1182,6 @@ static const struct dram_para para = { #elif defined(CONFIG_SUNXI_DRAM_LPDDR4) .type = SUNXI_DRAM_TYPE_LPDDR4, #endif - /* TODO: Populate from config */ .dx_odt = CONFIG_DRAM_SUNXI_DX_ODT, .dx_dri = CONFIG_DRAM_SUNXI_DX_DRI, .ca_dri = CONFIG_DRAM_SUNXI_CA_DRI, @@ -1191,9 +1190,10 @@ static const struct dram_para para = { .mr12 = CONFIG_DRAM_SUNXI_MR12, .mr13 = CONFIG_DRAM_SUNXI_MR13, .mr14 = CONFIG_DRAM_SUNXI_MR14, + .mr22 = CONFIG_DRAM_SUNXI_MR22, + .tpr0 = CONFIG_DRAM_SUNXI_TPR0, .tpr1 = CONFIG_DRAM_SUNXI_TPR1, .tpr2 = CONFIG_DRAM_SUNXI_TPR2, - .tpr3 = CONFIG_DRAM_SUNXI_TPR3, .tpr6 = CONFIG_DRAM_SUNXI_TPR6, .tpr10 = CONFIG_DRAM_SUNXI_TPR10, .tpr11 = CONFIG_DRAM_SUNXI_TPR11, diff --git a/configs/liontron-h-a133l_defconfig b/configs/liontron-h-a133l_defconfig index 56c5262f267..831d5b56e3a 100644 --- a/configs/liontron-h-a133l_defconfig +++ b/configs/liontron-h-a133l_defconfig @@ -10,9 +10,9 @@ CONFIG_DRAM_SUNXI_PARA0=0xd0a050c CONFIG_DRAM_SUNXI_MR11=0x4 CONFIG_DRAM_SUNXI_MR12=0x72 CONFIG_DRAM_SUNXI_MR14=0x7 -CONFIG_DRAM_SUNXI_TPR1=0x26 -CONFIG_DRAM_SUNXI_TPR2=0x6060606 -CONFIG_DRAM_SUNXI_TPR3=0x84040404 +CONFIG_DRAM_SUNXI_MR22=0x26 +CONFIG_DRAM_SUNXI_TPR0=0x6060606 +CONFIG_DRAM_SUNXI_TPR1=0x84040404 CONFIG_DRAM_SUNXI_TPR6=0x48000000 CONFIG_DRAM_SUNXI_TPR10=0x273333 CONFIG_DRAM_SUNXI_TPR11=0x231d151c