[U-Boot] [PATCH v2 0/6] sunxi: extend SPL header to propagate DRAM size and H6 3GiB DRAM support

This series tries to solve three issues we currently have on Allwinner boards: - The DRAM sizing routine can only cope with power-of-two sized DRAM. - The DRAM sizing routine steps through all DRAM, possibly hitting secure memory. - The SPL header versioning is quite strict and tends to break every time we need to update it. - On some Allwinner SoCs the maximum supported DRAM size of the DRAM controller is bigger than the accessible DRAM size of the CPU.
So Andre Przywara adapted something along the lines of semantic versioning[1], where we can add backwards-compatible changes to the SPL header without breaking every tool.
The second patch and the third patches introduces the version schema and does necessary refactors, then the fourth and the fifth patches prepare for 3GiB memory support. The sixth patch finally enables the SPL header to store the the DRAM size, and let U-Boot binary check which range is accessible when picking the data.
The first patch is a prepare for the other patches, as without it newly introduced code will make H6 SPL overflow, which makes the patchset not possible to test, as the only available 3GiB DRAM device now is the 3GiB version of Pine H64 sample.
Andre Przywara (3): sunxi: Extend SPL header versioning sunxi: board.c: refactor SPL header checks sunxi: store DRAM size in SPL header
Icenowy Zheng (3): sunxi: disable Pine A64 model detection code on other boards sunxi: map DRAM part with 3G size sunxi: add Kconfig option for the maximum accessible DRAM
arch/arm/include/asm/arch-sunxi/spl.h | 22 +++++--- arch/arm/mach-sunxi/Kconfig | 18 +++++++ arch/arm/mach-sunxi/board.c | 2 +- board/sunxi/board.c | 74 ++++++++++++++++++++++----- configs/pine64_plus_defconfig | 1 + 5 files changed, 97 insertions(+), 20 deletions(-)

The Pine A64 Plus/non-Plus model detection code is now built on all 64-bit ARM SoCs, even if the code cannot be triggered when H5/H6 is in use.
Disable them when the board is Pine A64 by adding a Kconfig option that is only selected on Pine A64.
On GCC 7.3.1 this makes the size of the function reduces 184 bytes, and saves a 104 byte strstr() function, then makes SPL on H6 succeed to build.
Signed-off-by: Icenowy Zheng icenowy@aosc.io --- This used to be a independently sent patch.
Changes in v2: - Added a Kconfig option to restrict the code on only Pine A64.
arch/arm/mach-sunxi/Kconfig | 10 ++++++++++ board/sunxi/board.c | 5 ++++- configs/pine64_plus_defconfig | 1 + 3 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 686f38fec4..764337c643 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -970,4 +970,14 @@ config SPL_SPI_SUNXI sunxi SPI Flash. It uses the same method as the boot ROM, so does not need any extra configuration.
+config PINE64_DT_SELECTION + bool "Enable Pine64 device tree selection code" + depends on MACH_SUN50I + help + The original Pine A64 and Pine A64+ are similar but different + boards and can be differed by the DRAM size. Pine A64 has + 512MiB DRAM, and Pine A64+ has 1GiB or 2GiB. By selecting this + option, the device tree selection code specific to Pine64 which + utilizes the DRAM size will be enabled. + endif diff --git a/board/sunxi/board.c b/board/sunxi/board.c index d1d7f9f400..49f5695566 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -820,6 +820,7 @@ int board_fit_config_name_match(const char *name) #endif };
+#ifdef CONFIG_PINE64_DT_SELECTION /* Differentiate the two Pine64 board DTs by their DRAM size. */ if (strstr(name, "-pine64") && strstr(cmp_str, "-pine64")) { if ((gd->ram_size > 512 * 1024 * 1024)) @@ -829,5 +830,7 @@ int board_fit_config_name_match(const char *name) } else { return strcmp(name, cmp_str); } -} #endif + return strcmp(name, cmp_str); +#endif +} diff --git a/configs/pine64_plus_defconfig b/configs/pine64_plus_defconfig index 14ccc9ba05..a5b87b9063 100644 --- a/configs/pine64_plus_defconfig +++ b/configs/pine64_plus_defconfig @@ -3,6 +3,7 @@ CONFIG_ARCH_SUNXI=y CONFIG_SPL=y CONFIG_MACH_SUN50I=y CONFIG_RESERVE_ALLWINNER_BOOT0_HEADER=y +CONFIG_PINE64_DT_SELECTION=y CONFIG_NR_DRAM_BANKS=1 # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set # CONFIG_CMD_FLASH is not set

On 10/25/18 10:23 AM, Icenowy Zheng wrote:
The Pine A64 Plus/non-Plus model detection code is now built on all 64-bit ARM SoCs, even if the code cannot be triggered when H5/H6 is in use.
Disable them when the board is Pine A64 by adding a Kconfig option that is only selected on Pine A64.
On GCC 7.3.1 this makes the size of the function reduces 184 bytes, and saves a 104 byte strstr() function, then makes SPL on H6 succeed to build.
Signed-off-by: Icenowy Zheng icenowy@aosc.io
Reviewed-by: Andre Przywara andre.przywara@arm.com
Thanks! Andre.
This used to be a independently sent patch.
Changes in v2:
- Added a Kconfig option to restrict the code on only Pine A64.
arch/arm/mach-sunxi/Kconfig | 10 ++++++++++ board/sunxi/board.c | 5 ++++- configs/pine64_plus_defconfig | 1 + 3 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 686f38fec4..764337c643 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -970,4 +970,14 @@ config SPL_SPI_SUNXI sunxi SPI Flash. It uses the same method as the boot ROM, so does not need any extra configuration.
+config PINE64_DT_SELECTION
- bool "Enable Pine64 device tree selection code"
- depends on MACH_SUN50I
- help
The original Pine A64 and Pine A64+ are similar but different
boards and can be differed by the DRAM size. Pine A64 has
512MiB DRAM, and Pine A64+ has 1GiB or 2GiB. By selecting this
option, the device tree selection code specific to Pine64 which
utilizes the DRAM size will be enabled.
endif diff --git a/board/sunxi/board.c b/board/sunxi/board.c index d1d7f9f400..49f5695566 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -820,6 +820,7 @@ int board_fit_config_name_match(const char *name) #endif };
+#ifdef CONFIG_PINE64_DT_SELECTION /* Differentiate the two Pine64 board DTs by their DRAM size. */ if (strstr(name, "-pine64") && strstr(cmp_str, "-pine64")) { if ((gd->ram_size > 512 * 1024 * 1024)) @@ -829,5 +830,7 @@ int board_fit_config_name_match(const char *name) } else { return strcmp(name, cmp_str); } -} #endif
- return strcmp(name, cmp_str);
+#endif +} diff --git a/configs/pine64_plus_defconfig b/configs/pine64_plus_defconfig index 14ccc9ba05..a5b87b9063 100644 --- a/configs/pine64_plus_defconfig +++ b/configs/pine64_plus_defconfig @@ -3,6 +3,7 @@ CONFIG_ARCH_SUNXI=y CONFIG_SPL=y CONFIG_MACH_SUN50I=y CONFIG_RESERVE_ALLWINNER_BOOT0_HEADER=y +CONFIG_PINE64_DT_SELECTION=y CONFIG_NR_DRAM_BANKS=1 # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set # CONFIG_CMD_FLASH is not set

On Thu, Oct 25, 2018 at 2:53 PM Icenowy Zheng icenowy@aosc.io wrote:
The Pine A64 Plus/non-Plus model detection code is now built on all 64-bit ARM SoCs, even if the code cannot be triggered when H5/H6 is in use.
Disable them when the board is Pine A64 by adding a Kconfig option that is only selected on Pine A64.
On GCC 7.3.1 this makes the size of the function reduces 184 bytes, and saves a 104 byte strstr() function, then makes SPL on H6 succeed to build.
Signed-off-by: Icenowy Zheng icenowy@aosc.io
Reviewed-by: Jagan Teki jagan@openedev.com
Applied to u-boot-sunxi/master

From: Andre Przywara andre.przywara@arm.com
On Allwinner SoCs we use some free bytes at the beginning of the SPL image to store various information. We have a version byte to allow updates, but changing this always requires all tools to be updated as well.
Introduce the concept of semantic versioning [1] to the SPL header: The major part of the version number only changes on incompatible updates, a minor number bump indicates backward compatibility. This patch just documents the major/minor split, adds some comments to the header file and uses the versioning information for the existing users.
Signed-off-by: Andre Przywara andre.przywara@arm.com Signed-off-by: Icenowy Zheng icenowy@aosc.io --- No changes in v2.
arch/arm/include/asm/arch-sunxi/spl.h | 19 ++++++++++++++----- board/sunxi/board.c | 4 ++-- 2 files changed, 16 insertions(+), 7 deletions(-)
diff --git a/arch/arm/include/asm/arch-sunxi/spl.h b/arch/arm/include/asm/arch-sunxi/spl.h index 55f2deb18d..014184b638 100644 --- a/arch/arm/include/asm/arch-sunxi/spl.h +++ b/arch/arm/include/asm/arch-sunxi/spl.h @@ -9,7 +9,16 @@
#define BOOT0_MAGIC "eGON.BT0" #define SPL_SIGNATURE "SPL" /* marks "sunxi" SPL header */ -#define SPL_HEADER_VERSION 2 +#define SPL_MAJOR_BITS 3 +#define SPL_MINOR_BITS 5 +#define SPL_VERSION(maj, min) \ + ((((maj) & ((1U << SPL_MAJOR_BITS) - 1)) << SPL_MINOR_BITS) | \ + ((min) & ((1U << SPL_MINOR_BITS) - 1))) + +#define SPL_HEADER_VERSION SPL_VERSION(0, 2) + +#define SPL_ENV_HEADER_VERSION SPL_VERSION(0, 1) +#define SPL_DT_HEADER_VERSION SPL_VERSION(0, 2)
#define SPL_ADDR CONFIG_SUNXI_SRAM_ADDRESS
@@ -45,14 +54,14 @@ struct boot_file_head { uint32_t pub_head_size; uint8_t spl_signature[4]; }; - uint32_t fel_script_address; + uint32_t fel_script_address; /* since v0.1, set by sunxi-fel */ /* * If the fel_uEnv_length member below is set to a non-zero value, * it specifies the size (byte count) of data at fel_script_address. * At the same time this indicates that the data is in uEnv.txt * compatible format, ready to be imported via "env import -t". */ - uint32_t fel_uEnv_length; + uint32_t fel_uEnv_length; /* since v0.1, set by sunxi-fel */ /* * Offset of an ASCIIZ string (relative to the SPL header), which * contains the default device tree name (CONFIG_DEFAULT_DEVICE_TREE). @@ -60,11 +69,11 @@ struct boot_file_head { * by flash programming tools for providing nice informative messages * to the users. */ - uint32_t dt_name_offset; + uint32_t dt_name_offset; /* since v0.2, set by mksunxiboot */ uint32_t reserved1; uint32_t boot_media; /* written here by the boot ROM */ /* A padding area (may be used for storing text strings) */ - uint32_t string_pool[13]; + uint32_t string_pool[13]; /* since v0.2, filled by mksunxiboot */ /* The header must be a multiple of 32 bytes (for VBAR alignment) */ };
diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 49f5695566..94555ef468 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -667,9 +667,9 @@ static void parse_spl_header(const uint32_t spl_addr) return; /* signature mismatch, no usable header */
uint8_t spl_header_version = spl->spl_signature[3]; - if (spl_header_version != SPL_HEADER_VERSION) { + if (spl_header_version < SPL_ENV_HEADER_VERSION) { printf("sunxi SPL version mismatch: expected %u, got %u\n", - SPL_HEADER_VERSION, spl_header_version); + SPL_ENV_HEADER_VERSION, spl_header_version); return; } if (!spl->fel_script_address)

On Thu, Oct 25, 2018 at 2:53 PM Icenowy Zheng icenowy@aosc.io wrote:
From: Andre Przywara andre.przywara@arm.com
On Allwinner SoCs we use some free bytes at the beginning of the SPL image to store various information. We have a version byte to allow updates, but changing this always requires all tools to be updated as well.
Introduce the concept of semantic versioning [1] to the SPL header: The major part of the version number only changes on incompatible updates, a minor number bump indicates backward compatibility. This patch just documents the major/minor split, adds some comments to the header file and uses the versioning information for the existing users.
Signed-off-by: Andre Przywara andre.przywara@arm.com Signed-off-by: Icenowy Zheng icenowy@aosc.io
Acked-by: Jagan Teki jagan@openedev.com
Applied to u-boot-sunxi/master

From: Andre Przywara andre.przywara@arm.com
So far we have two users which want to look at the SPL header. We will get more in the future. Refactor the existing SPL header checks into a common function, to simplify reusing the code. Now that this is easy, add proper version checks to the DT name parsing.
Signed-off-by: Andre Przywara andre.przywara@arm.com Signed-off-by: Icenowy Zheng icenowy@aosc.io --- No changes in v2.
board/sunxi/board.c | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-)
diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 94555ef468..bdec82b065 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -255,6 +255,30 @@ int board_init(void) return soft_i2c_board_init(); }
+/* + * On older SoCs the SPL is actually at address zero, so using NULL as + * an error value does not work. + */ +#define INVALID_SPL_HEADER ((void *)~0UL) + +static struct boot_file_head * get_spl_header(uint8_t req_version) +{ + struct boot_file_head *spl = (void *)(ulong)SPL_ADDR; + uint8_t spl_header_version = spl->spl_signature[3]; + + /* Is there really the SPL header (still) there? */ + if (memcmp(spl->spl_signature, SPL_SIGNATURE, 3) != 0) + return INVALID_SPL_HEADER; + + if (spl_header_version < req_version) { + printf("sunxi SPL version mismatch: expected %u, got %u\n", + req_version, spl_header_version); + return INVALID_SPL_HEADER; + } + + return spl; +} + int dram_init(void) { gd->ram_size = get_ram_size((long *)PHYS_SDRAM_0, PHYS_SDRAM_0_SIZE); @@ -662,16 +686,11 @@ void get_board_serial(struct tag_serialnr *serialnr) */ static void parse_spl_header(const uint32_t spl_addr) { - struct boot_file_head *spl = (void *)(ulong)spl_addr; - if (memcmp(spl->spl_signature, SPL_SIGNATURE, 3) != 0) - return; /* signature mismatch, no usable header */ + struct boot_file_head *spl = get_spl_header(SPL_ENV_HEADER_VERSION);
- uint8_t spl_header_version = spl->spl_signature[3]; - if (spl_header_version < SPL_ENV_HEADER_VERSION) { - printf("sunxi SPL version mismatch: expected %u, got %u\n", - SPL_ENV_HEADER_VERSION, spl_header_version); + if (spl == INVALID_SPL_HEADER) return; - } + if (!spl->fel_script_address) return;
@@ -806,11 +825,11 @@ int ft_board_setup(void *blob, bd_t *bd) #ifdef CONFIG_SPL_LOAD_FIT int board_fit_config_name_match(const char *name) { - struct boot_file_head *spl = (void *)(ulong)SPL_ADDR; - const char *cmp_str = (void *)(ulong)SPL_ADDR; + struct boot_file_head *spl = get_spl_header(SPL_DT_HEADER_VERSION); + const char *cmp_str = (const char *)spl;
/* Check if there is a DT name stored in the SPL header and use that. */ - if (spl->dt_name_offset) { + if (spl != INVALID_SPL_HEADER && spl->dt_name_offset) { cmp_str += spl->dt_name_offset; } else { #ifdef CONFIG_DEFAULT_DEVICE_TREE

On Thu, Oct 25, 2018 at 2:53 PM Icenowy Zheng icenowy@aosc.io wrote:
From: Andre Przywara andre.przywara@arm.com
So far we have two users which want to look at the SPL header. We will get more in the future. Refactor the existing SPL header checks into a common function, to simplify reusing the code. Now that this is easy, add proper version checks to the DT name parsing.
Signed-off-by: Andre Przywara andre.przywara@arm.com Signed-off-by: Icenowy Zheng icenowy@aosc.io
Acked-by: Jagan Teki jagan@openedev.com
Applied to u-boot-sunxi/master

All Allwinner 64-bit SoCs now are known to be able to access 3GiB of external DRAM, however the size of DRAM part in the MMU translation table is still 2GiB.
Change the size of DRAM part in MMU table to 3GiB.
Signed-off-by: Icenowy Zheng icenowy@aosc.io --- This used to be in another patchset targeting 3GiB support.
No changes in v2.
arch/arm/mach-sunxi/board.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c index d22a84ea6b..b74eaf2a0e 100644 --- a/arch/arm/mach-sunxi/board.c +++ b/arch/arm/mach-sunxi/board.c @@ -52,7 +52,7 @@ static struct mm_region sunxi_mem_map[] = { /* RAM */ .virt = 0x40000000UL, .phys = 0x40000000UL, - .size = 0x80000000UL, + .size = 0xC0000000UL, .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_INNER_SHARE }, {

On 10/25/18 10:23 AM, Icenowy Zheng wrote:
All Allwinner 64-bit SoCs now are known to be able to access 3GiB of external DRAM, however the size of DRAM part in the MMU translation table is still 2GiB.
Change the size of DRAM part in MMU table to 3GiB.
Signed-off-by: Icenowy Zheng icenowy@aosc.io
Reviewed-by: Andre Przywara andre.przywara@arm.com
Cheers, Andre.
This used to be in another patchset targeting 3GiB support.
No changes in v2.
arch/arm/mach-sunxi/board.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c index d22a84ea6b..b74eaf2a0e 100644 --- a/arch/arm/mach-sunxi/board.c +++ b/arch/arm/mach-sunxi/board.c @@ -52,7 +52,7 @@ static struct mm_region sunxi_mem_map[] = { /* RAM */ .virt = 0x40000000UL, .phys = 0x40000000UL,
.size = 0x80000000UL,
.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_INNER_SHARE }, {.size = 0xC0000000UL,

On Thu, Oct 25, 2018 at 2:53 PM Icenowy Zheng icenowy@aosc.io wrote:
All Allwinner 64-bit SoCs now are known to be able to access 3GiB of external DRAM, however the size of DRAM part in the MMU translation table is still 2GiB.
Change the size of DRAM part in MMU table to 3GiB.
Signed-off-by: Icenowy Zheng icenowy@aosc.io
Reviewed-by: Jagan Teki jagan@openedev.com
Applied to u-boot-sunxi/master

Allwinner 64-bit SoCs can use 4GiB DRAM chip, however their memory map has only allocated 3GiB for DRAM, so only 3GiB of the DRAM is accessible.
Add a Kconfig option for the maximum accessible DRAM.
For A80 it should be a much higher value (8GiB), but as I have no A80 device to test and originally U-Boot only supports 2GiB DRAM on A80, it currently still falls under the 2GiB situation.
Signed-off-by: Icenowy Zheng icenowy@aosc.io --- This used to be in another patchset targeting 3GiB support.
Changes in v2: - Add H6 to SoCs that support 3GiB DRAM.
arch/arm/mach-sunxi/Kconfig | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 764337c643..e9e1b4bc0e 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -140,6 +140,14 @@ config MACH_SUNXI_H3_H5 select SUNXI_GEN_SUN6I select SUPPORT_SPL
+# TODO: try out A80's 8GiB DRAM space +config SUNXI_DRAM_MAX_SIZE + hex + default 0xC0000000 if MACH_SUN50I + default 0xC0000000 if MACH_SUN50I_H5 + default 0xC0000000 if MACH_SUN50I_H6 + default 0x80000000 + choice prompt "Sunxi SoC Variant" optional

On 10/25/18 10:23 AM, Icenowy Zheng wrote:
Allwinner 64-bit SoCs can use 4GiB DRAM chip, however their memory map has only allocated 3GiB for DRAM, so only 3GiB of the DRAM is accessible.
Add a Kconfig option for the maximum accessible DRAM.
For A80 it should be a much higher value (8GiB), but as I have no A80 device to test and originally U-Boot only supports 2GiB DRAM on A80, it currently still falls under the 2GiB situation.
Signed-off-by: Icenowy Zheng icenowy@aosc.io
Reviewed-by: Andre Przywara andre.przywara@arm.com
Cheers, Andre.
This used to be in another patchset targeting 3GiB support.
Changes in v2:
- Add H6 to SoCs that support 3GiB DRAM.
arch/arm/mach-sunxi/Kconfig | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 764337c643..e9e1b4bc0e 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -140,6 +140,14 @@ config MACH_SUNXI_H3_H5 select SUNXI_GEN_SUN6I select SUPPORT_SPL
+# TODO: try out A80's 8GiB DRAM space +config SUNXI_DRAM_MAX_SIZE
- hex
- default 0xC0000000 if MACH_SUN50I
- default 0xC0000000 if MACH_SUN50I_H5
- default 0xC0000000 if MACH_SUN50I_H6
- default 0x80000000
choice prompt "Sunxi SoC Variant" optional

On Thu, Oct 25, 2018 at 2:53 PM Icenowy Zheng icenowy@aosc.io wrote:
Allwinner 64-bit SoCs can use 4GiB DRAM chip, however their memory map has only allocated 3GiB for DRAM, so only 3GiB of the DRAM is accessible.
Add a Kconfig option for the maximum accessible DRAM.
For A80 it should be a much higher value (8GiB), but as I have no A80 device to test and originally U-Boot only supports 2GiB DRAM on A80, it currently still falls under the 2GiB situation.
Signed-off-by: Icenowy Zheng icenowy@aosc.io
This used to be in another patchset targeting 3GiB support.
Changes in v2:
- Add H6 to SoCs that support 3GiB DRAM.
arch/arm/mach-sunxi/Kconfig | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 764337c643..e9e1b4bc0e 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -140,6 +140,14 @@ config MACH_SUNXI_H3_H5 select SUNXI_GEN_SUN6I select SUPPORT_SPL
+# TODO: try out A80's 8GiB DRAM space +config SUNXI_DRAM_MAX_SIZE
hex
default 0xC0000000 if MACH_SUN50I
default 0xC0000000 if MACH_SUN50I_H5
default 0xC0000000 if MACH_SUN50I_H6
Moved in to single line and
Applied to u-boot-sunxi/master

From: Andre Przywara andre.przywara@arm.com
At the moment we rely on the infamous get_ram_size() function to learn the actual DRAM size in U-Boot proper. This function has two issues: 1) It only works if the DRAM size is a power of two. We start to see boards which have 3GB of (usable) DRAM, so this does not fit anymore. 2) As U-Boot has no notion of reserved memory so far, it will happily ride through the DRAM, possibly stepping on secure-only memory. This could be a region of DRAM reserved for OP-TEE or some other secure payload, for instance. It will most likely crash in that case.
As the SPL DRAM init routine has very accurate knowledge of the actual DRAM size, lets propagate this wisdom to U-Boot proper. We re-purpose a currently reserved word in our SPL header for that. The SPL itself stores the detected DRAM size there, and bumps the SPL header version number in that case. U-Boot proper checks for a valid SPL header and a high enough version number, then uses the DRAM size from there. If the SPL header field is not sufficient, we fall back to the old DRAM scanning routine.
Part of the DRAM might be present and probed by SPL, but not accessible by the CPU. They're restricted in the main U-Boot binary, when accessing the DRAM size from SPL header.
Signed-off-by: Andre Przywara andre.przywara@arm.com Signed-off-by: Icenowy Zheng icenowy@aosc.io --- Changes in v2: - Restrict the DRAM size to the accessible range.
arch/arm/include/asm/arch-sunxi/spl.h | 3 ++- board/sunxi/board.c | 28 ++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/arch/arm/include/asm/arch-sunxi/spl.h b/arch/arm/include/asm/arch-sunxi/spl.h index 014184b638..4baba38b00 100644 --- a/arch/arm/include/asm/arch-sunxi/spl.h +++ b/arch/arm/include/asm/arch-sunxi/spl.h @@ -19,6 +19,7 @@
#define SPL_ENV_HEADER_VERSION SPL_VERSION(0, 1) #define SPL_DT_HEADER_VERSION SPL_VERSION(0, 2) +#define SPL_DRAM_HEADER_VERSION SPL_VERSION(0, 3)
#define SPL_ADDR CONFIG_SUNXI_SRAM_ADDRESS
@@ -70,7 +71,7 @@ struct boot_file_head { * to the users. */ uint32_t dt_name_offset; /* since v0.2, set by mksunxiboot */ - uint32_t reserved1; + uint32_t dram_size; /* in MiB, since v0.3, set by SPL */ uint32_t boot_media; /* written here by the boot ROM */ /* A padding area (may be used for storing text strings) */ uint32_t string_pool[13]; /* since v0.2, filled by mksunxiboot */ diff --git a/board/sunxi/board.c b/board/sunxi/board.c index bdec82b065..65ae0c4219 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -281,7 +281,16 @@ static struct boot_file_head * get_spl_header(uint8_t req_version)
int dram_init(void) { - gd->ram_size = get_ram_size((long *)PHYS_SDRAM_0, PHYS_SDRAM_0_SIZE); + struct boot_file_head *spl = get_spl_header(SPL_DRAM_HEADER_VERSION); + + if (spl == INVALID_SPL_HEADER) + gd->ram_size = get_ram_size((long *)PHYS_SDRAM_0, + PHYS_SDRAM_0_SIZE); + else + gd->ram_size = (phys_addr_t)spl->dram_size << 20; + + if (gd->ram_size > CONFIG_SUNXI_DRAM_MAX_SIZE) + gd->ram_size = CONFIG_SUNXI_DRAM_MAX_SIZE;
return 0; } @@ -545,6 +554,21 @@ int board_mmc_init(bd_t *bis) #endif
#ifdef CONFIG_SPL_BUILD + +static void sunxi_spl_store_dram_size(phys_addr_t dram_size) +{ + struct boot_file_head *spl = get_spl_header(SPL_DT_HEADER_VERSION); + + if (spl == INVALID_SPL_HEADER) + return; + + /* Promote the header version for U-Boot proper, if needed. */ + if (spl->spl_signature[3] < SPL_DRAM_HEADER_VERSION) + spl->spl_signature[3] = SPL_DRAM_HEADER_VERSION; + + spl->dram_size = dram_size >> 20; +} + void sunxi_board_init(void) { int power_failed = 0; @@ -613,6 +637,8 @@ void sunxi_board_init(void) if (!gd->ram_size) hang();
+ sunxi_spl_store_dram_size(gd->ram_size); + /* * Only clock up the CPU to full speed if we are reasonably * assured it's being powered with suitable core voltage

On Thu, Oct 25, 2018 at 2:53 PM Icenowy Zheng icenowy@aosc.io wrote:
From: Andre Przywara andre.przywara@arm.com
At the moment we rely on the infamous get_ram_size() function to learn the actual DRAM size in U-Boot proper. This function has two issues:
- It only works if the DRAM size is a power of two. We start to see
boards which have 3GB of (usable) DRAM, so this does not fit anymore. 2) As U-Boot has no notion of reserved memory so far, it will happily ride through the DRAM, possibly stepping on secure-only memory. This could be a region of DRAM reserved for OP-TEE or some other secure payload, for instance. It will most likely crash in that case.
As the SPL DRAM init routine has very accurate knowledge of the actual DRAM size, lets propagate this wisdom to U-Boot proper. We re-purpose a currently reserved word in our SPL header for that. The SPL itself stores the detected DRAM size there, and bumps the SPL header version number in that case. U-Boot proper checks for a valid SPL header and a high enough version number, then uses the DRAM size from there. If the SPL header field is not sufficient, we fall back to the old DRAM scanning routine.
Part of the DRAM might be present and probed by SPL, but not accessible by the CPU. They're restricted in the main U-Boot binary, when accessing the DRAM size from SPL header.
Signed-off-by: Andre Przywara andre.przywara@arm.com Signed-off-by: Icenowy Zheng icenowy@aosc.io
Changes in v2:
- Restrict the DRAM size to the accessible range.
arch/arm/include/asm/arch-sunxi/spl.h | 3 ++- board/sunxi/board.c | 28 ++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/arch/arm/include/asm/arch-sunxi/spl.h b/arch/arm/include/asm/arch-sunxi/spl.h index 014184b638..4baba38b00 100644 --- a/arch/arm/include/asm/arch-sunxi/spl.h +++ b/arch/arm/include/asm/arch-sunxi/spl.h @@ -19,6 +19,7 @@
#define SPL_ENV_HEADER_VERSION SPL_VERSION(0, 1) #define SPL_DT_HEADER_VERSION SPL_VERSION(0, 2) +#define SPL_DRAM_HEADER_VERSION SPL_VERSION(0, 3)
#define SPL_ADDR CONFIG_SUNXI_SRAM_ADDRESS
@@ -70,7 +71,7 @@ struct boot_file_head { * to the users. */ uint32_t dt_name_offset; /* since v0.2, set by mksunxiboot */
uint32_t reserved1;
uint32_t dram_size; /* in MiB, since v0.3, set by SPL */ uint32_t boot_media; /* written here by the boot ROM */ /* A padding area (may be used for storing text strings) */ uint32_t string_pool[13]; /* since v0.2, filled by mksunxiboot */
diff --git a/board/sunxi/board.c b/board/sunxi/board.c index bdec82b065..65ae0c4219 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -281,7 +281,16 @@ static struct boot_file_head * get_spl_header(uint8_t req_version)
int dram_init(void) {
gd->ram_size = get_ram_size((long *)PHYS_SDRAM_0, PHYS_SDRAM_0_SIZE);
struct boot_file_head *spl = get_spl_header(SPL_DRAM_HEADER_VERSION);
if (spl == INVALID_SPL_HEADER)
gd->ram_size = get_ram_size((long *)PHYS_SDRAM_0,
PHYS_SDRAM_0_SIZE);
else
gd->ram_size = (phys_addr_t)spl->dram_size << 20;
How about checking SPL_DRAM_HEADER_VERSION in valid header case?

于 2018年10月26日 GMT+08:00 下午1:54:44, Jagan Teki jagan@amarulasolutions.com 写到:
On Thu, Oct 25, 2018 at 2:53 PM Icenowy Zheng icenowy@aosc.io wrote:
From: Andre Przywara andre.przywara@arm.com
At the moment we rely on the infamous get_ram_size() function to
learn
the actual DRAM size in U-Boot proper. This function has two issues:
- It only works if the DRAM size is a power of two. We start to see
boards which have 3GB of (usable) DRAM, so this does not fit anymore. 2) As U-Boot has no notion of reserved memory so far, it will happily ride through the DRAM, possibly stepping on secure-only memory. This could be a region of DRAM reserved for OP-TEE or some other secure payload, for instance. It will most likely crash in that case.
As the SPL DRAM init routine has very accurate knowledge of the
actual
DRAM size, lets propagate this wisdom to U-Boot proper. We re-purpose a currently reserved word in our SPL header for that. The SPL itself stores the detected DRAM size there, and bumps the SPL header version number in that case. U-Boot proper checks for a valid SPL header and a high enough version number, then uses the DRAM size from there. If the SPL header field is not sufficient, we fall back
to
the old DRAM scanning routine.
Part of the DRAM might be present and probed by SPL, but not
accessible
by the CPU. They're restricted in the main U-Boot binary, when
accessing
the DRAM size from SPL header.
Signed-off-by: Andre Przywara andre.przywara@arm.com Signed-off-by: Icenowy Zheng icenowy@aosc.io
Changes in v2:
- Restrict the DRAM size to the accessible range.
arch/arm/include/asm/arch-sunxi/spl.h | 3 ++- board/sunxi/board.c | 28
++++++++++++++++++++++++++-
2 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/arch/arm/include/asm/arch-sunxi/spl.h
b/arch/arm/include/asm/arch-sunxi/spl.h
index 014184b638..4baba38b00 100644 --- a/arch/arm/include/asm/arch-sunxi/spl.h +++ b/arch/arm/include/asm/arch-sunxi/spl.h @@ -19,6 +19,7 @@
#define SPL_ENV_HEADER_VERSION SPL_VERSION(0, 1) #define SPL_DT_HEADER_VERSION SPL_VERSION(0, 2) +#define SPL_DRAM_HEADER_VERSION SPL_VERSION(0, 3)
#define SPL_ADDR CONFIG_SUNXI_SRAM_ADDRESS
@@ -70,7 +71,7 @@ struct boot_file_head { * to the users. */ uint32_t dt_name_offset; /* since v0.2, set by
mksunxiboot */
uint32_t reserved1;
uint32_t dram_size; /* in MiB, since v0.3, set by
SPL */
uint32_t boot_media; /* written here by the boot
ROM */
/* A padding area (may be used for storing text strings) */ uint32_t string_pool[13]; /* since v0.2, filled by
mksunxiboot */
diff --git a/board/sunxi/board.c b/board/sunxi/board.c index bdec82b065..65ae0c4219 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -281,7 +281,16 @@ static struct boot_file_head *
get_spl_header(uint8_t req_version)
int dram_init(void) {
gd->ram_size = get_ram_size((long *)PHYS_SDRAM_0,
PHYS_SDRAM_0_SIZE);
struct boot_file_head *spl =
get_spl_header(SPL_DRAM_HEADER_VERSION);
if (spl == INVALID_SPL_HEADER)
gd->ram_size = get_ram_size((long *)PHYS_SDRAM_0,
PHYS_SDRAM_0_SIZE);
else
gd->ram_size = (phys_addr_t)spl->dram_size << 20;
How about checking SPL_DRAM_HEADER_VERSION in valid header case?
get_spl_header() does the version check.

On Fri, Oct 26, 2018 at 11:27 AM Icenowy Zheng icenowy@aosc.io wrote:
于 2018年10月26日 GMT+08:00 下午1:54:44, Jagan Teki jagan@amarulasolutions.com 写到:
On Thu, Oct 25, 2018 at 2:53 PM Icenowy Zheng icenowy@aosc.io wrote:
From: Andre Przywara andre.przywara@arm.com
At the moment we rely on the infamous get_ram_size() function to
learn
the actual DRAM size in U-Boot proper. This function has two issues:
- It only works if the DRAM size is a power of two. We start to see
boards which have 3GB of (usable) DRAM, so this does not fit anymore. 2) As U-Boot has no notion of reserved memory so far, it will happily ride through the DRAM, possibly stepping on secure-only memory. This could be a region of DRAM reserved for OP-TEE or some other secure payload, for instance. It will most likely crash in that case.
As the SPL DRAM init routine has very accurate knowledge of the
actual
DRAM size, lets propagate this wisdom to U-Boot proper. We re-purpose a currently reserved word in our SPL header for that. The SPL itself stores the detected DRAM size there, and bumps the SPL header version number in that case. U-Boot proper checks for a valid SPL header and a high enough version number, then uses the DRAM size from there. If the SPL header field is not sufficient, we fall back
to
the old DRAM scanning routine.
Part of the DRAM might be present and probed by SPL, but not
accessible
by the CPU. They're restricted in the main U-Boot binary, when
accessing
the DRAM size from SPL header.
Signed-off-by: Andre Przywara andre.przywara@arm.com Signed-off-by: Icenowy Zheng icenowy@aosc.io
Changes in v2:
- Restrict the DRAM size to the accessible range.
arch/arm/include/asm/arch-sunxi/spl.h | 3 ++- board/sunxi/board.c | 28
++++++++++++++++++++++++++-
2 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/arch/arm/include/asm/arch-sunxi/spl.h
b/arch/arm/include/asm/arch-sunxi/spl.h
index 014184b638..4baba38b00 100644 --- a/arch/arm/include/asm/arch-sunxi/spl.h +++ b/arch/arm/include/asm/arch-sunxi/spl.h @@ -19,6 +19,7 @@
#define SPL_ENV_HEADER_VERSION SPL_VERSION(0, 1) #define SPL_DT_HEADER_VERSION SPL_VERSION(0, 2) +#define SPL_DRAM_HEADER_VERSION SPL_VERSION(0, 3)
#define SPL_ADDR CONFIG_SUNXI_SRAM_ADDRESS
@@ -70,7 +71,7 @@ struct boot_file_head { * to the users. */ uint32_t dt_name_offset; /* since v0.2, set by
mksunxiboot */
uint32_t reserved1;
uint32_t dram_size; /* in MiB, since v0.3, set by
SPL */
uint32_t boot_media; /* written here by the boot
ROM */
/* A padding area (may be used for storing text strings) */ uint32_t string_pool[13]; /* since v0.2, filled by
mksunxiboot */
diff --git a/board/sunxi/board.c b/board/sunxi/board.c index bdec82b065..65ae0c4219 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -281,7 +281,16 @@ static struct boot_file_head *
get_spl_header(uint8_t req_version)
int dram_init(void) {
gd->ram_size = get_ram_size((long *)PHYS_SDRAM_0,
PHYS_SDRAM_0_SIZE);
struct boot_file_head *spl =
get_spl_header(SPL_DRAM_HEADER_VERSION);
if (spl == INVALID_SPL_HEADER)
gd->ram_size = get_ram_size((long *)PHYS_SDRAM_0,
PHYS_SDRAM_0_SIZE);
else
gd->ram_size = (phys_addr_t)spl->dram_size << 20;
How about checking SPL_DRAM_HEADER_VERSION in valid header case?
get_spl_header() does the version check.
Applied to u-boot-sunxi/master

On 10/25/18 10:23 AM, Icenowy Zheng wrote:
Hi Icenowy,
thanks for picking this up, resending and adapting this!
This series tries to solve three issues we currently have on Allwinner boards:
- The DRAM sizing routine can only cope with power-of-two sized DRAM.
- The DRAM sizing routine steps through all DRAM, possibly hitting secure memory.
- The SPL header versioning is quite strict and tends to break every time we need to update it.
- On some Allwinner SoCs the maximum supported DRAM size of the DRAM controller is bigger than the accessible DRAM size of the CPU.
So Andre Przywara adapted something along the lines of semantic versioning[1], where we can add backwards-compatible changes to the SPL header without breaking every tool.
The second patch and the third patches introduces the version schema and does necessary refactors, then the fourth and the fifth patches prepare for 3GiB memory support. The sixth patch finally enables the SPL header to store the the DRAM size, and let U-Boot binary check which range is accessible when picking the data.
Out of curiosity: Do you know whether one can play around with the DRAM controller's mapping registers to make the upper GB of a 4GB DRAM accessible (so map 3-4GB to 0xc0000000 instead of 2-3GB)? To use something like bank switching, maybe? This is not really aimed at any upstream OS, I am just curious from a hacker's perspective.
The first patch is a prepare for the other patches, as without it newly introduced code will make H6 SPL overflow, which makes the patchset not possible to test, as the only available 3GiB DRAM device now is the 3GiB version of Pine H64 sample.
I guess this tight memory situation is also the reason that you disabled PSCI_RESET in the defconfig? Do you know what causes the bigger memory consumption for H6 boards? Is that the DRAM driver? For A64 I end up at a rather comfortable 30KB SPL with my GCC 7.3.0 these days.
And just in case: If you run into size issues while testing and developing, you can always disable ARMV8_SPL_EXCEPTION_VECTORS to gain some additional KBs. I don't really want to make this permanent in a defconfig, though.
Cheers, Andre.
Andre Przywara (3): sunxi: Extend SPL header versioning sunxi: board.c: refactor SPL header checks sunxi: store DRAM size in SPL header
Icenowy Zheng (3): sunxi: disable Pine A64 model detection code on other boards sunxi: map DRAM part with 3G size sunxi: add Kconfig option for the maximum accessible DRAM
arch/arm/include/asm/arch-sunxi/spl.h | 22 +++++--- arch/arm/mach-sunxi/Kconfig | 18 +++++++ arch/arm/mach-sunxi/board.c | 2 +- board/sunxi/board.c | 74 ++++++++++++++++++++++----- configs/pine64_plus_defconfig | 1 + 5 files changed, 97 insertions(+), 20 deletions(-)

于 2018年10月25日 GMT+08:00 下午6:15:11, "André Przywara" andre.przywara@arm.com 写到:
On 10/25/18 10:23 AM, Icenowy Zheng wrote:
Hi Icenowy,
thanks for picking this up, resending and adapting this!
This series tries to solve three issues we currently have on Allwinner boards:
- The DRAM sizing routine can only cope with power-of-two sized DRAM.
- The DRAM sizing routine steps through all DRAM, possibly hitting
secure
memory.
- The SPL header versioning is quite strict and tends to break every
time
we need to update it.
- On some Allwinner SoCs the maximum supported DRAM size of the DRAM controller is bigger than the accessible DRAM size of the CPU.
So Andre Przywara adapted something along the lines of semantic versioning[1], where we can add backwards-compatible changes to the
SPL
header without breaking every tool.
The second patch and the third patches introduces the version schema
and
does necessary refactors, then the fourth and the fifth patches
prepare
for 3GiB memory support. The sixth patch finally enables the SPL
header
to store the the DRAM size, and let U-Boot binary check which range
is
accessible when picking the data.
Out of curiosity: Do you know whether one can play around with the DRAM controller's mapping registers to make the upper GB of a 4GB DRAM accessible (so map 3-4GB to 0xc0000000 instead of 2-3GB)? To use something like bank switching, maybe? This is not really aimed at any upstream OS, I am just curious from a hacker's perspective.
The first patch is a prepare for the other patches, as without it
newly
introduced code will make H6 SPL overflow, which makes the patchset
not
possible to test, as the only available 3GiB DRAM device now is the 3GiB version of Pine H64 sample.
I guess this tight memory situation is also the reason that you disabled PSCI_RESET in the defconfig? Do you know what causes the bigger memory consumption for H6 boards? Is that the DRAM driver? For A64 I end up at a rather comfortable 30KB SPL with my GCC 7.3.0 these days.
Yes, the DRAM driver is ~2.5KiB larger.
And just in case: If you run into size issues while testing and developing, you can always disable ARMV8_SPL_EXCEPTION_VECTORS to gain some additional KBs. I don't really want to make this permanent in a defconfig, though.
Cheers, Andre.
Andre Przywara (3): sunxi: Extend SPL header versioning sunxi: board.c: refactor SPL header checks sunxi: store DRAM size in SPL header
Icenowy Zheng (3): sunxi: disable Pine A64 model detection code on other boards sunxi: map DRAM part with 3G size sunxi: add Kconfig option for the maximum accessible DRAM
arch/arm/include/asm/arch-sunxi/spl.h | 22 +++++--- arch/arm/mach-sunxi/Kconfig | 18 +++++++ arch/arm/mach-sunxi/board.c | 2 +- board/sunxi/board.c | 74
++++++++++++++++++++++-----
configs/pine64_plus_defconfig | 1 + 5 files changed, 97 insertions(+), 20 deletions(-)

On Thu, Oct 25, 2018 at 05:23:01PM +0800, Icenowy Zheng wrote:
This series tries to solve three issues we currently have on Allwinner boards:
- The DRAM sizing routine can only cope with power-of-two sized DRAM.
- The DRAM sizing routine steps through all DRAM, possibly hitting secure memory.
- The SPL header versioning is quite strict and tends to break every time we need to update it.
- On some Allwinner SoCs the maximum supported DRAM size of the DRAM controller is bigger than the accessible DRAM size of the CPU.
So Andre Przywara adapted something along the lines of semantic versioning[1], where we can add backwards-compatible changes to the SPL header without breaking every tool.
The second patch and the third patches introduces the version schema and does necessary refactors, then the fourth and the fifth patches prepare for 3GiB memory support. The sixth patch finally enables the SPL header to store the the DRAM size, and let U-Boot binary check which range is accessible when picking the data.
The first patch is a prepare for the other patches, as without it newly introduced code will make H6 SPL overflow, which makes the patchset not possible to test, as the only available 3GiB DRAM device now is the 3GiB version of Pine H64 sample.
For the whole series, Acked-by: Maxime Ripard maxime.ripard@bootlin.com
Thanks! Maxime

于 2018年10月25日 GMT+08:00 下午5:23:01, Icenowy Zheng icenowy@aosc.io 写到:
This series tries to solve three issues we currently have on Allwinner boards:
- The DRAM sizing routine can only cope with power-of-two sized DRAM.
- The DRAM sizing routine steps through all DRAM, possibly hitting
secure memory.
- The SPL header versioning is quite strict and tends to break every
time we need to update it.
- On some Allwinner SoCs the maximum supported DRAM size of the DRAM
controller is bigger than the accessible DRAM size of the CPU.
So Andre Przywara adapted something along the lines of semantic versioning[1], where we can add backwards-compatible changes to the SPL header without breaking every tool.
The second patch and the third patches introduces the version schema and does necessary refactors, then the fourth and the fifth patches prepare for 3GiB memory support. The sixth patch finally enables the SPL header to store the the DRAM size, and let U-Boot binary check which range is accessible when picking the data.
The first patch is a prepare for the other patches, as without it newly introduced code will make H6 SPL overflow, which makes the patchset not possible to test, as the only available 3GiB DRAM device now is the 3GiB version of Pine H64 sample.
Jagan, could you have a check on this patchset and apply it?
Thanks!
Andre Przywara (3): sunxi: Extend SPL header versioning sunxi: board.c: refactor SPL header checks sunxi: store DRAM size in SPL header
Icenowy Zheng (3): sunxi: disable Pine A64 model detection code on other boards sunxi: map DRAM part with 3G size sunxi: add Kconfig option for the maximum accessible DRAM
arch/arm/include/asm/arch-sunxi/spl.h | 22 +++++--- arch/arm/mach-sunxi/Kconfig | 18 +++++++ arch/arm/mach-sunxi/board.c | 2 +- board/sunxi/board.c | 74 ++++++++++++++++++++++----- configs/pine64_plus_defconfig | 1 + 5 files changed, 97 insertions(+), 20 deletions(-)
participants (4)
-
André Przywara
-
Icenowy Zheng
-
Jagan Teki
-
Maxime Ripard