From a877d4b1aef70bbae556e156e6802b7d917546ab Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Tue, 16 Oct 2018 21:56:33 -0700 Subject: [PATCH 01/12] pwm: sunxi: fix off-by-one that prevented PWM to use prescaler bypass Fix off-by-one that prevented PWM driver to use prescaler bypass. Without this change prescaler is always enabled. Signed-off-by: Vasily Khoruzhick Acked-by: Maxime Ripard Reviewed-by: Jagan Teki --- drivers/pwm/sunxi_pwm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/sunxi_pwm.c b/drivers/pwm/sunxi_pwm.c index 3c7dffdd90..baee503730 100644 --- a/drivers/pwm/sunxi_pwm.c +++ b/drivers/pwm/sunxi_pwm.c @@ -74,7 +74,7 @@ static int sunxi_pwm_set_config(struct udevice *dev, uint channel, debug("%s: period_ns=%u, duty_ns=%u\n", __func__, period_ns, duty_ns); - for (prescaler = 0; prescaler < SUNXI_PWM_CTRL_PRESCALE0_MASK; + for (prescaler = 0; prescaler <= SUNXI_PWM_CTRL_PRESCALE0_MASK; prescaler++) { if (!prescaler_table[prescaler]) continue; From ce138cb4294b85975b0c3ac8cf9e15a181462c25 Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Tue, 16 Oct 2018 21:56:34 -0700 Subject: [PATCH 02/12] pwm: sunxi: use new prescaler when configuring PWM Looks like old prescaler was used when configuring PWM, fix it. Signed-off-by: Vasily Khoruzhick Acked-by: Maxime Ripard Reviewed-by: Jagan Teki --- drivers/pwm/sunxi_pwm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/sunxi_pwm.c b/drivers/pwm/sunxi_pwm.c index baee503730..6284409b4f 100644 --- a/drivers/pwm/sunxi_pwm.c +++ b/drivers/pwm/sunxi_pwm.c @@ -97,7 +97,7 @@ static int sunxi_pwm_set_config(struct udevice *dev, uint channel, v &= ~SUNXI_PWM_CTRL_CLK_GATE; writel(v, ®s->ctrl); v &= ~SUNXI_PWM_CTRL_PRESCALE0_MASK; - v |= (priv->prescaler & SUNXI_PWM_CTRL_PRESCALE0_MASK); + v |= (prescaler & SUNXI_PWM_CTRL_PRESCALE0_MASK); writel(v, ®s->ctrl); v |= SUNXI_PWM_CTRL_CLK_GATE; writel(v, ®s->ctrl); From c33ba7ec8b9be0a6fe7a2bd47a36c991bf9189e1 Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Tue, 16 Oct 2018 21:56:35 -0700 Subject: [PATCH 03/12] pwm: sunxi: choose best prescaler to improve PWM resolution Choose best prescaler to improve PWM resolution. Without this change driver chooses first prescaler that gives us period value within range, but it could be not the best one. Signed-off-by: Vasily Khoruzhick Tested-by: Vagrant Cascadian Acked-by: Maxime Ripard Reviewed-by: Jagan Teki --- drivers/pwm/sunxi_pwm.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/drivers/pwm/sunxi_pwm.c b/drivers/pwm/sunxi_pwm.c index 6284409b4f..8a55e4f461 100644 --- a/drivers/pwm/sunxi_pwm.c +++ b/drivers/pwm/sunxi_pwm.c @@ -67,49 +67,55 @@ static int sunxi_pwm_set_config(struct udevice *dev, uint channel, { struct sunxi_pwm_priv *priv = dev_get_priv(dev); struct sunxi_pwm *regs = priv->regs; - int prescaler; - u32 v, period = 0, duty; - u64 scaled_freq = 0; + int best_prescaler = 0; + u32 v, best_period = 0, duty; + u64 best_scaled_freq = 0; const u32 nsecs_per_sec = 1000000000U; debug("%s: period_ns=%u, duty_ns=%u\n", __func__, period_ns, duty_ns); - for (prescaler = 0; prescaler <= SUNXI_PWM_CTRL_PRESCALE0_MASK; + for (int prescaler = 0; prescaler <= SUNXI_PWM_CTRL_PRESCALE0_MASK; prescaler++) { + u32 period = 0; + u64 scaled_freq = 0; if (!prescaler_table[prescaler]) continue; scaled_freq = lldiv(OSC_24MHZ, prescaler_table[prescaler]); period = lldiv(scaled_freq * period_ns, nsecs_per_sec); - if (period - 1 <= SUNXI_PWM_CH0_PERIOD_MAX) - break; + if ((period - 1 <= SUNXI_PWM_CH0_PERIOD_MAX) && + best_period < period) { + best_period = period; + best_scaled_freq = scaled_freq; + best_prescaler = prescaler; + } } - if (period - 1 > SUNXI_PWM_CH0_PERIOD_MAX) { + if (best_period - 1 > SUNXI_PWM_CH0_PERIOD_MAX) { debug("%s: failed to find prescaler value\n", __func__); return -EINVAL; } - duty = lldiv(scaled_freq * duty_ns, nsecs_per_sec); + duty = lldiv(best_scaled_freq * duty_ns, nsecs_per_sec); - if (priv->prescaler != prescaler) { + if (priv->prescaler != best_prescaler) { /* Mask clock to update prescaler */ v = readl(®s->ctrl); v &= ~SUNXI_PWM_CTRL_CLK_GATE; writel(v, ®s->ctrl); v &= ~SUNXI_PWM_CTRL_PRESCALE0_MASK; - v |= (prescaler & SUNXI_PWM_CTRL_PRESCALE0_MASK); + v |= (best_prescaler & SUNXI_PWM_CTRL_PRESCALE0_MASK); writel(v, ®s->ctrl); v |= SUNXI_PWM_CTRL_CLK_GATE; writel(v, ®s->ctrl); - priv->prescaler = prescaler; + priv->prescaler = best_prescaler; } - writel(SUNXI_PWM_CH0_PERIOD_PRD(period) | + writel(SUNXI_PWM_CH0_PERIOD_PRD(best_period) | SUNXI_PWM_CH0_PERIOD_DUTY(duty), ®s->ch0_period); debug("%s: prescaler: %d, period: %d, duty: %d\n", __func__, priv->prescaler, - period, duty); + best_period, duty); return 0; } From 297963f5b5dd510e1070e97ab3a3b6363a7d931e Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Tue, 23 Oct 2018 20:20:28 +0300 Subject: [PATCH 04/12] sunxi: Fix typos of spelling Allwinner Signed-off-by: Priit Laes Acked-by: Maxime Ripard Reviewed-by: Jagan Teki --- arch/arm/mach-sunxi/dram_sun4i.c | 2 +- arch/arm/mach-sunxi/p2wi.c | 2 +- board/sunxi/README.sunxi64 | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-sunxi/dram_sun4i.c b/arch/arm/mach-sunxi/dram_sun4i.c index 85623022f1..396c0424ea 100644 --- a/arch/arm/mach-sunxi/dram_sun4i.c +++ b/arch/arm/mach-sunxi/dram_sun4i.c @@ -5,7 +5,7 @@ * (C) Copyright 2013 Luke Kenneth Casson Leighton * * Based on sun4i Linux kernel sources mach-sunxi/pm/standby/dram*.c - * and earlier U-Boot Allwiner A10 SPL work + * and earlier U-Boot Allwinner A10 SPL work * * (C) Copyright 2007-2012 * Allwinner Technology Co., Ltd. diff --git a/arch/arm/mach-sunxi/p2wi.c b/arch/arm/mach-sunxi/p2wi.c index 82ad254133..e84e1d8d5c 100644 --- a/arch/arm/mach-sunxi/p2wi.c +++ b/arch/arm/mach-sunxi/p2wi.c @@ -5,7 +5,7 @@ * (C) Copyright 2013 Oliver Schinagl * http://linux-sunxi.org * - * Based on sun6i sources and earlier U-Boot Allwiner A10 SPL work + * Based on sun6i sources and earlier U-Boot Allwinner A10 SPL work * * (C) Copyright 2006-2013 * Allwinner Technology Co., Ltd. diff --git a/board/sunxi/README.sunxi64 b/board/sunxi/README.sunxi64 index df1dbc818f..bba2e01b60 100644 --- a/board/sunxi/README.sunxi64 +++ b/board/sunxi/README.sunxi64 @@ -130,7 +130,7 @@ U-Boot prompt on the serial console. (Legacy) boot0 method --------------------- -boot0 is Allwiner's secondary program loader and it can be used as some kind +boot0 is Allwinner's secondary program loader and it can be used as some kind of SPL replacement to get U-Boot up and running from an microSD card. For some time using boot0 was the only option to get the Pine64 booted. With working DRAM init code in U-Boot's SPL this is no longer necessary, From df4ad94d053072e71e3c131d4d47d5a84b8d1ecc Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Tue, 23 Oct 2018 20:20:30 +0300 Subject: [PATCH 05/12] sunxi: docs: Mention CONFIG_NAND requirement Signed-off-by: Priit Laes Acked-by: Maxime Ripard Reviewed-by: Jagan Teki --- board/sunxi/README.nand | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/board/sunxi/README.nand b/board/sunxi/README.nand index a5d4ff0e90..98ebe5fb7f 100644 --- a/board/sunxi/README.nand +++ b/board/sunxi/README.nand @@ -20,9 +20,9 @@ pages. In order to accomodate that, we create a tool that will generate an SPL image that is ready to be programmed directly embedding the ECCs, randomized, and with the necessary bits needed to reduce the number of -bitflips. The U-Boot build system, when configured for the NAND will -also generate the image sunxi-spl-with-ecc.bin that will have been -generated by that tool. +bitflips. The U-Boot build system, when configured for the NAND (with +CONFIG_NAND=y) will also generate the image sunxi-spl-with-ecc.bin +that will have been generated by that tool. In order to flash your U-Boot image onto a board, assuming that the board is in FEL mode, you'll need the sunxi-tools that you can find at From 3d99a0b33a16c9330a5bf5b3f8561f45d0e6ed80 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Tue, 23 Oct 2018 20:20:31 +0300 Subject: [PATCH 06/12] sunxi: display: Mark sunxi_rgb2yuv_coef array as const sunxi_rgb2yuv_coef is readonly and never modified. Signed-off-by: Priit Laes Acked-by: Anatolij Gustschin Acked-by: Maxime Ripard Reviewed-by: Jagan Teki --- drivers/video/sunxi/sunxi_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/sunxi/sunxi_display.c b/drivers/video/sunxi/sunxi_display.c index 5c8f88c42f..6dd9bec351 100644 --- a/drivers/video/sunxi/sunxi_display.c +++ b/drivers/video/sunxi/sunxi_display.c @@ -460,7 +460,7 @@ static void sunxi_composer_init(void) setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE); } -static u32 sunxi_rgb2yuv_coef[12] = { +static const u32 sunxi_rgb2yuv_coef[12] = { 0x00000107, 0x00000204, 0x00000064, 0x00000108, 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808, 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808 From c6c2c85e4b980cba54b34a55399f9b82ae2787ea Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Thu, 25 Oct 2018 17:23:02 +0800 Subject: [PATCH 07/12] sunxi: disable Pine A64 model detection code on other boards 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 Reviewed-by: Andre Przywara Acked-by: Maxime Ripard Reviewed-by: Jagan Teki --- arch/arm/mach-sunxi/Kconfig | 10 ++++++++++ board/sunxi/board.c | 3 +++ configs/pine64_plus_defconfig | 1 + 3 files changed, 14 insertions(+) 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..e075c13239 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 From 55d481d2014f79a692ac82a10a439dc71acc732c Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Thu, 25 Oct 2018 17:23:03 +0800 Subject: [PATCH 08/12] sunxi: Extend SPL header versioning 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. [1] https://semver.org Signed-off-by: Andre Przywara Signed-off-by: Icenowy Zheng Acked-by: Maxime Ripard Acked-by: Jagan Teki --- 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 e075c13239..6926504ce5 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) From cff5c138495a4d68fa6e16953517087732b76662 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Thu, 25 Oct 2018 17:23:04 +0800 Subject: [PATCH 09/12] sunxi: board.c: refactor SPL header checks 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 Signed-off-by: Icenowy Zheng Acked-by: Maxime Ripard Acked-by: Jagan Teki --- 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 6926504ce5..b117de4555 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 From 7009134c99512bd8a9a09cf14f35450f32a8602c Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Thu, 25 Oct 2018 17:23:05 +0800 Subject: [PATCH 10/12] sunxi: map DRAM part with 3G size 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 Reviewed-by: Andre Przywara Acked-by: Maxime Ripard Reviewed-by: Jagan Teki --- 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 }, { From f8aa3f8d84af6e9ae0dce9c3577d342c6a013b14 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Thu, 25 Oct 2018 17:23:06 +0800 Subject: [PATCH 11/12] sunxi: add Kconfig option for the maximum accessible DRAM 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 Reviewed-by: Andre Przywara Acked-by: Maxime Ripard Reviewed-by: Jagan Teki --- arch/arm/mach-sunxi/Kconfig | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 764337c643..6277abc3cc 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -140,6 +140,12 @@ 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 || MACH_SUN50I_H5 || MACH_SUN50I_H6 + default 0x80000000 + choice prompt "Sunxi SoC Variant" optional From 5776610e9ef022e2d8a15793d4b9955c3f8076ed Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Thu, 25 Oct 2018 17:23:07 +0800 Subject: [PATCH 12/12] sunxi: store DRAM size in SPL header 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 Signed-off-by: Icenowy Zheng Acked-by: Maxime Ripard Reviewed-by: Jagan Teki --- 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 b117de4555..b196d48674 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