York Sun | ffea3e6 | 2017-09-28 08:42:14 -0700 | [diff] [blame^] | 1 | Falcon boot option |
| 2 | ------------------ |
| 3 | Falcon boot is a short cut boot method for SD/eMMC targets. It skips loading the |
| 4 | RAM version U-Boot. Instead, it loads FIT image and boot directly to Linux. |
| 5 | CONFIG_SPL_OS_BOOT enables falcon boot. CONFIG_SPL_LOAD_FIT enables the FIT |
| 6 | image support (also need CONFIG_SPL_OF_LIBFDT, CONFIG_SPL_FIT and optionally |
| 7 | CONFIG_SPL_GZIP). |
| 8 | |
| 9 | To enable falcon boot, a hook function spl_start_uboot() returns 0 to indicate |
| 10 | booting U-Boot is not the first choice. The kernel FIT image needs to be put |
| 11 | at CONFIG_SYS_MMCSD_RAW_MODE_KERNEL_SECTOR. SPL mmc driver reads the header to |
| 12 | determine if this is a FIT image. If true, FIT image components are parsed and |
| 13 | copied or decompressed (if applicable) to their destinations. If FIT image is |
| 14 | not found, normal U-Boot flow will follow. |
| 15 | |
| 16 | An important part of falcon boot is to prepare the device tree. A normal U-Boot |
| 17 | does FDT fixups when booting Linux. For falcon boot, Linux boots directly from |
| 18 | SPL, skipping the normal U-Boot. The device tree has to be prepared in advance. |
| 19 | A command "spl export" should be called under the normal RAM version U-Boot. |
| 20 | It is equivalent to go through "bootm" step-by-step until device tree fixup is |
| 21 | done. The device tree in memory is the one needed for falcon boot. Falcon boot |
| 22 | flow suggests to save this image to SD/eMMC at the location pointed by macro |
| 23 | CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR, with maximum size specified by macro |
| 24 | CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTORS. However, when FIT image is used for |
| 25 | Linux, the device tree stored in FIT image overwrites the memory loaded by spl |
| 26 | driver from these sectors. We could change this loading order to favor the |
| 27 | stored sectors. But when secure boot is enabled, these sectors are used for |
| 28 | signature header and needs to be loaded before the FIT image. So it is important |
| 29 | to understand the device tree in FIT image should be the one actually used, or |
| 30 | leave it absent to favor the stored sectors. It is easier to deploy the FIT |
| 31 | image with embedded static device tree to multiple boards. |
| 32 | |
| 33 | Macro CONFIG_SYS_SPL_ARGS_ADDR serves two purposes. One is the pointer to load |
| 34 | the stored sectors to. Normally this is the static device tree. The second |
| 35 | purpose is the memory location of signature header for secure boot. After the |
| 36 | FIT image is loaded into memory, it is validated against the signature header |
| 37 | before individual components are extracted (and optionally decompressed) into |
| 38 | their final memory locations, respectively. After the validation, the header |
| 39 | is no longer used. The static device tree is copied into this location. So |
| 40 | this macro is passed as the location of device tree when booting Linux. |
| 41 | |
| 42 | Steps to prepare static device tree |
| 43 | ----------------------------------- |
| 44 | To prepare the static device tree for Layerscape boards, it is important to |
| 45 | understand the fixups in U-Boot. Memory size and location, as well as reserved |
| 46 | memory blocks are added/updated. Ethernet MAC addressed are updated. FMan |
| 47 | microcode (if used) is embedded in the device tree. Kernel command line and |
| 48 | initrd information are embedded. Others including CPU status, boot method, |
| 49 | Ethernet port status, etc. are also updated. |
| 50 | |
| 51 | Following normal booting process, all variables are set, all images are loaded |
| 52 | before "bootm" command would be issued to boot, run command |
| 53 | |
| 54 | spl export fdt <address> |
| 55 | |
| 56 | where the address is the location of FIT image. U-Boot goes through the booting |
| 57 | process as if "bootm start", "bootm loados", "bootm ramdisk"... commands but |
| 58 | stops before "bootm go". There we have the fixed-up device tree in memory. |
| 59 | We can check the device tree header by these commands |
| 60 | |
| 61 | fdt addr <fdt address> |
| 62 | fdt header |
| 63 | |
| 64 | Where the fdt address is the device tree in memory. It is printed by U-Boot. |
| 65 | It is useful to know the exact size. One way to extract this static device |
| 66 | tree is to save it to eMMC/SD using command in U-Boot, and extract under Linux |
| 67 | with these commands, repectively |
| 68 | |
| 69 | mmc write <address> <sector> <sectors> |
| 70 | dd if=/dev/mmcblk0 of=<filename> bs=512 skip=<sector> count=<sectors> |
| 71 | |
| 72 | Note, U-Boot takes values as hexadecimals while Linux takes them as decimals by |
| 73 | default. If using NAND or other storage, the commands are slightly different. |
| 74 | When we have the static device tree image, we can re-make the FIT image with |
| 75 | it. It is important to specify the load addresses in FIT image for every |
| 76 | components. Otherwise U-Boot cannot load them correctly. |
| 77 | |
| 78 | Generate FIT image with static device tree |
| 79 | ------------------------------------------ |
| 80 | Example: |
| 81 | |
| 82 | /dts-v1/; |
| 83 | |
| 84 | / { |
| 85 | description = "Image file for the LS1043A Linux Kernel"; |
| 86 | #address-cells = <1>; |
| 87 | |
| 88 | images { |
| 89 | kernel@1 { |
| 90 | description = "ARM64 Linux kernel"; |
| 91 | data = /incbin/("./arch/arm64/boot/Image.gz"); |
| 92 | type = "kernel"; |
| 93 | arch = "arm64"; |
| 94 | os = "linux"; |
| 95 | compression = "gzip"; |
| 96 | load = <0x80080000>; |
| 97 | entry = <0x80080000>; |
| 98 | }; |
| 99 | fdt@1 { |
| 100 | description = "Flattened Device Tree blob"; |
| 101 | data = /incbin/("./fsl-ls1043ardb-static.dtb"); |
| 102 | type = "flat_dt"; |
| 103 | arch = "arm64"; |
| 104 | compression = "none"; |
| 105 | load = <0x90000000>; |
| 106 | }; |
| 107 | ramdisk@1 { |
| 108 | description = "LS1043 Ramdisk"; |
| 109 | data = /incbin/("./rootfs.cpio.gz"); |
| 110 | type = "ramdisk"; |
| 111 | arch = "arm64"; |
| 112 | os = "linux"; |
| 113 | compression = "gzip"; |
| 114 | load = <0xa0000000>; |
| 115 | }; |
| 116 | }; |
| 117 | |
| 118 | configurations { |
| 119 | default = "config@1"; |
| 120 | config@1 { |
| 121 | description = "Boot Linux kernel"; |
| 122 | kernel = "kernel@1"; |
| 123 | fdt = "fdt@1"; |
| 124 | ramdisk = "ramdisk@1"; |
| 125 | loadables = "fdt", "ramdisk"; |
| 126 | }; |
| 127 | }; |
| 128 | }; |
| 129 | |
| 130 | The "loadables" is not optional. It tells SPL which images to load into memory. |
| 131 | |
| 132 | Other things to consider |
| 133 | ----------------------- |
| 134 | Falcon boot skips a lot of initialization in U-Boot. If Linux expects the |
| 135 | hardware to be initialized by U-Boot, the related code should be ported to SPL |
| 136 | build. For example, if Linux expect Ethernet PHY to be initialized in U-Boot |
| 137 | (which is not a common case), the PHY initialization has to be included in |
| 138 | falcon boot. This increases the SPL image size and should be handled carefully. |
| 139 | If Linux has PHY driver enabled, it still depends on the correct MDIO bus setup |
| 140 | in U-Boot. Normal U-Boot sets the MDC ratio to generate a proper clock signal. |