diff options
Diffstat (limited to 'arch/arm/cpu')
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/cpu.c | 77 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/doc/README.falcon | 140 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/soc.c | 4 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/spl.c | 26 |
5 files changed, 204 insertions, 44 deletions
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/Kconfig b/arch/arm/cpu/armv8/fsl-layerscape/Kconfig index 3518d8601d..85b7c70937 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/Kconfig +++ b/arch/arm/cpu/armv8/fsl-layerscape/Kconfig @@ -72,6 +72,7 @@ config ARCH_LS1088A select SYS_FSL_ERRATUM_A010165 select SYS_FSL_ERRATUM_A008511 select SYS_FSL_ERRATUM_A008850 + select SYS_FSL_ERRATUM_A009007 select SYS_FSL_HAS_CCI400 select SYS_FSL_HAS_DDR4 select SYS_FSL_HAS_RGMII diff --git a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c index d21a49454e..ab5d76ea3b 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c @@ -647,13 +647,14 @@ phys_size_t get_effective_memsize(void) /* * For ARMv8 SoCs, DDR memory is split into two or three regions. The - * first region is 2GB space at 0x8000_0000. If the memory extends to - * the second region (or the third region if applicable), the secure - * memory and Management Complex (MC) memory should be put into the - * highest region, i.e. the end of DDR memory. CONFIG_MAX_MEM_MAPPED - * is set to the size of first region so U-Boot doesn't relocate itself - * into higher address. Should DDR be configured to skip the first - * region, this function needs to be adjusted. + * first region is 2GB space at 0x8000_0000. Secure memory needs to + * allocated from first region. If the memory extends to the second + * region (or the third region if applicable), Management Complex (MC) + * memory should be put into the highest region, i.e. the end of DDR + * memory. CONFIG_MAX_MEM_MAPPED is set to the size of first region so + * U-Boot doesn't relocate itself into higher address. Should DDR be + * configured to skip the first region, this function needs to be + * adjusted. */ if (gd->ram_size > CONFIG_MAX_MEM_MAPPED) { ea_size = CONFIG_MAX_MEM_MAPPED; @@ -664,16 +665,10 @@ phys_size_t get_effective_memsize(void) #ifdef CONFIG_SYS_MEM_RESERVE_SECURE /* Check if we have enough space for secure memory */ - if (rem > CONFIG_SYS_MEM_RESERVE_SECURE) { - rem -= CONFIG_SYS_MEM_RESERVE_SECURE; - } else { - if (ea_size > CONFIG_SYS_MEM_RESERVE_SECURE) { - ea_size -= CONFIG_SYS_MEM_RESERVE_SECURE; - rem = 0; /* Presume MC requires more memory */ - } else { - printf("Error: No enough space for secure memory.\n"); - } - } + if (ea_size > CONFIG_SYS_MEM_RESERVE_SECURE) + ea_size -= CONFIG_SYS_MEM_RESERVE_SECURE; + else + printf("Error: No enough space for secure memory.\n"); #endif /* Check if we have enough memory for MC */ if (rem < board_reserve_ram_top(rem)) { @@ -698,8 +693,19 @@ int dram_init_banksize(void) * memory. The DDR extends from low region to high region(s) presuming * no hole is created with DDR configuration. gd->arch.secure_ram tracks * the location of secure memory. gd->arch.resv_ram tracks the location - * of reserved memory for Management Complex (MC). + * of reserved memory for Management Complex (MC). Because gd->ram_size + * is reduced by this function if secure memory is reserved, checking + * gd->arch.secure_ram should be done to avoid running it repeatedly. */ + +#ifdef CONFIG_SYS_MEM_RESERVE_SECURE + if (gd->arch.secure_ram & MEM_RESERVE_SECURE_MAINTAINED) { + debug("No need to run again, skip %s\n", __func__); + + return 0; + } +#endif + gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE; if (gd->ram_size > CONFIG_SYS_DDR_BLOCK1_SIZE) { gd->bd->bi_dram[0].size = CONFIG_SYS_DDR_BLOCK1_SIZE; @@ -718,32 +724,14 @@ int dram_init_banksize(void) gd->bd->bi_dram[0].size = gd->ram_size; } #ifdef CONFIG_SYS_MEM_RESERVE_SECURE -#ifdef CONFIG_SYS_DDR_BLOCK3_BASE - if (gd->bd->bi_dram[2].size >= CONFIG_SYS_MEM_RESERVE_SECURE) { - gd->bd->bi_dram[2].size -= CONFIG_SYS_MEM_RESERVE_SECURE; - gd->arch.secure_ram = gd->bd->bi_dram[2].start + - gd->bd->bi_dram[2].size; + if (gd->bd->bi_dram[0].size > + CONFIG_SYS_MEM_RESERVE_SECURE) { + gd->bd->bi_dram[0].size -= + CONFIG_SYS_MEM_RESERVE_SECURE; + gd->arch.secure_ram = gd->bd->bi_dram[0].start + + gd->bd->bi_dram[0].size; gd->arch.secure_ram |= MEM_RESERVE_SECURE_MAINTAINED; gd->ram_size -= CONFIG_SYS_MEM_RESERVE_SECURE; - } else -#endif - { - if (gd->bd->bi_dram[1].size >= CONFIG_SYS_MEM_RESERVE_SECURE) { - gd->bd->bi_dram[1].size -= - CONFIG_SYS_MEM_RESERVE_SECURE; - gd->arch.secure_ram = gd->bd->bi_dram[1].start + - gd->bd->bi_dram[1].size; - gd->arch.secure_ram |= MEM_RESERVE_SECURE_MAINTAINED; - gd->ram_size -= CONFIG_SYS_MEM_RESERVE_SECURE; - } else if (gd->bd->bi_dram[0].size > - CONFIG_SYS_MEM_RESERVE_SECURE) { - gd->bd->bi_dram[0].size -= - CONFIG_SYS_MEM_RESERVE_SECURE; - gd->arch.secure_ram = gd->bd->bi_dram[0].start + - gd->bd->bi_dram[0].size; - gd->arch.secure_ram |= MEM_RESERVE_SECURE_MAINTAINED; - gd->ram_size -= CONFIG_SYS_MEM_RESERVE_SECURE; - } } #endif /* CONFIG_SYS_MEM_RESERVE_SECURE */ @@ -797,6 +785,11 @@ int dram_init_banksize(void) } #endif +#ifdef CONFIG_SYS_MEM_RESERVE_SECURE + debug("%s is called. gd->ram_size is reduced to %lu\n", + __func__, (ulong)gd->ram_size); +#endif + return 0; } diff --git a/arch/arm/cpu/armv8/fsl-layerscape/doc/README.falcon b/arch/arm/cpu/armv8/fsl-layerscape/doc/README.falcon new file mode 100644 index 0000000000..2505f408ab --- /dev/null +++ b/arch/arm/cpu/armv8/fsl-layerscape/doc/README.falcon @@ -0,0 +1,140 @@ +Falcon boot option +------------------ +Falcon boot is a short cut boot method for SD/eMMC targets. It skips loading the +RAM version U-Boot. Instead, it loads FIT image and boot directly to Linux. +CONFIG_SPL_OS_BOOT enables falcon boot. CONFIG_SPL_LOAD_FIT enables the FIT +image support (also need CONFIG_SPL_OF_LIBFDT, CONFIG_SPL_FIT and optionally +CONFIG_SPL_GZIP). + +To enable falcon boot, a hook function spl_start_uboot() returns 0 to indicate +booting U-Boot is not the first choice. The kernel FIT image needs to be put +at CONFIG_SYS_MMCSD_RAW_MODE_KERNEL_SECTOR. SPL mmc driver reads the header to +determine if this is a FIT image. If true, FIT image components are parsed and +copied or decompressed (if applicable) to their destinations. If FIT image is +not found, normal U-Boot flow will follow. + +An important part of falcon boot is to prepare the device tree. A normal U-Boot +does FDT fixups when booting Linux. For falcon boot, Linux boots directly from +SPL, skipping the normal U-Boot. The device tree has to be prepared in advance. +A command "spl export" should be called under the normal RAM version U-Boot. +It is equivalent to go through "bootm" step-by-step until device tree fixup is +done. The device tree in memory is the one needed for falcon boot. Falcon boot +flow suggests to save this image to SD/eMMC at the location pointed by macro +CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR, with maximum size specified by macro +CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTORS. However, when FIT image is used for +Linux, the device tree stored in FIT image overwrites the memory loaded by spl +driver from these sectors. We could change this loading order to favor the +stored sectors. But when secure boot is enabled, these sectors are used for +signature header and needs to be loaded before the FIT image. So it is important +to understand the device tree in FIT image should be the one actually used, or +leave it absent to favor the stored sectors. It is easier to deploy the FIT +image with embedded static device tree to multiple boards. + +Macro CONFIG_SYS_SPL_ARGS_ADDR serves two purposes. One is the pointer to load +the stored sectors to. Normally this is the static device tree. The second +purpose is the memory location of signature header for secure boot. After the +FIT image is loaded into memory, it is validated against the signature header +before individual components are extracted (and optionally decompressed) into +their final memory locations, respectively. After the validation, the header +is no longer used. The static device tree is copied into this location. So +this macro is passed as the location of device tree when booting Linux. + +Steps to prepare static device tree +----------------------------------- +To prepare the static device tree for Layerscape boards, it is important to +understand the fixups in U-Boot. Memory size and location, as well as reserved +memory blocks are added/updated. Ethernet MAC addressed are updated. FMan +microcode (if used) is embedded in the device tree. Kernel command line and +initrd information are embedded. Others including CPU status, boot method, +Ethernet port status, etc. are also updated. + +Following normal booting process, all variables are set, all images are loaded +before "bootm" command would be issued to boot, run command + +spl export fdt <address> + +where the address is the location of FIT image. U-Boot goes through the booting +process as if "bootm start", "bootm loados", "bootm ramdisk"... commands but +stops before "bootm go". There we have the fixed-up device tree in memory. +We can check the device tree header by these commands + +fdt addr <fdt address> +fdt header + +Where the fdt address is the device tree in memory. It is printed by U-Boot. +It is useful to know the exact size. One way to extract this static device +tree is to save it to eMMC/SD using command in U-Boot, and extract under Linux +with these commands, repectively + +mmc write <address> <sector> <sectors> +dd if=/dev/mmcblk0 of=<filename> bs=512 skip=<sector> count=<sectors> + +Note, U-Boot takes values as hexadecimals while Linux takes them as decimals by +default. If using NAND or other storage, the commands are slightly different. +When we have the static device tree image, we can re-make the FIT image with +it. It is important to specify the load addresses in FIT image for every +components. Otherwise U-Boot cannot load them correctly. + +Generate FIT image with static device tree +------------------------------------------ +Example: + +/dts-v1/; + +/ { + description = "Image file for the LS1043A Linux Kernel"; + #address-cells = <1>; + + images { + kernel@1 { + description = "ARM64 Linux kernel"; + data = /incbin/("./arch/arm64/boot/Image.gz"); + type = "kernel"; + arch = "arm64"; + os = "linux"; + compression = "gzip"; + load = <0x80080000>; + entry = <0x80080000>; + }; + fdt@1 { + description = "Flattened Device Tree blob"; + data = /incbin/("./fsl-ls1043ardb-static.dtb"); + type = "flat_dt"; + arch = "arm64"; + compression = "none"; + load = <0x90000000>; + }; + ramdisk@1 { + description = "LS1043 Ramdisk"; + data = /incbin/("./rootfs.cpio.gz"); + type = "ramdisk"; + arch = "arm64"; + os = "linux"; + compression = "gzip"; + load = <0xa0000000>; + }; + }; + + configurations { + default = "config@1"; + config@1 { + description = "Boot Linux kernel"; + kernel = "kernel@1"; + fdt = "fdt@1"; + ramdisk = "ramdisk@1"; + loadables = "fdt", "ramdisk"; + }; + }; +}; + +The "loadables" is not optional. It tells SPL which images to load into memory. + +Other things to consider +----------------------- +Falcon boot skips a lot of initialization in U-Boot. If Linux expects the +hardware to be initialized by U-Boot, the related code should be ported to SPL +build. For example, if Linux expect Ethernet PHY to be initialized in U-Boot +(which is not a common case), the PHY initialization has to be included in +falcon boot. This increases the SPL image size and should be handled carefully. +If Linux has PHY driver enabled, it still depends on the correct MDIO bus setup +in U-Boot. Normal U-Boot sets the MDC ratio to generate a proper clock signal. diff --git a/arch/arm/cpu/armv8/fsl-layerscape/soc.c b/arch/arm/cpu/armv8/fsl-layerscape/soc.c index a90ee0afd7..497a4b541d 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/soc.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/soc.c @@ -127,7 +127,7 @@ static void erratum_a008997(void) out_be16((phy) + SCFG_USB_PHY_RX_OVRD_IN_HI, USB_PHY_RX_EQ_VAL_3); \ out_be16((phy) + SCFG_USB_PHY_RX_OVRD_IN_HI, USB_PHY_RX_EQ_VAL_4) -#elif defined(CONFIG_ARCH_LS2080A) +#elif defined(CONFIG_ARCH_LS2080A) || defined(CONFIG_ARCH_LS1088A) #define PROGRAM_USB_PHY_RX_OVRD_IN_HI(phy) \ out_le16((phy) + DCSR_USB_PHY_RX_OVRD_IN_HI, USB_PHY_RX_EQ_VAL_1); \ @@ -149,7 +149,7 @@ static void erratum_a009007(void) usb_phy = (void __iomem *)SCFG_USB_PHY3; PROGRAM_USB_PHY_RX_OVRD_IN_HI(usb_phy); -#elif defined(CONFIG_ARCH_LS2080A) +#elif defined(CONFIG_ARCH_LS2080A) || defined(CONFIG_ARCH_LS1088A) void __iomem *dcsr = (void __iomem *)DCSR_BASE; PROGRAM_USB_PHY_RX_OVRD_IN_HI(dcsr + DCSR_USB_PHY1); diff --git a/arch/arm/cpu/armv8/fsl-layerscape/spl.c b/arch/arm/cpu/armv8/fsl-layerscape/spl.c index 2776240be3..1c694e7c67 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/spl.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/spl.c @@ -80,6 +80,7 @@ void board_init_f(ulong dummy) get_clocks(); preloader_console_init(); + spl_set_bd(); #ifdef CONFIG_SPL_I2C_SUPPORT i2c_init_all(); @@ -116,4 +117,29 @@ void board_init_f(ulong dummy) gd->arch.tlb_allocated = gd->arch.tlb_addr; #endif /* CONFIG_SPL_FSL_LS_PPA */ } + +#ifdef CONFIG_SPL_OS_BOOT +/* + * Return + * 0 if booting into OS is selected + * 1 if booting into U-Boot is selected + */ +int spl_start_uboot(void) +{ + env_init(); + if (env_get_yesno("boot_os") != 0) + return 0; + + return 1; +} +#endif /* CONFIG_SPL_OS_BOOT */ +#ifdef CONFIG_SPL_LOAD_FIT +int board_fit_config_name_match(const char *name) +{ + /* Just empty function now - can't decide what to choose */ + debug("%s: %s\n", __func__, name); + + return 0; +} +#endif #endif /* CONFIG_SPL_BUILD */ |