p-boot - pico sized bootloader for PinePhone -------------------------------------------- Official website: https://xnux.eu/p-boot/ This is a no nonsense bootloader for extremely fast and flexible booting of PinePhone. p-boot is partly based on some borrowed U-Boot and Linux code. Some benefits over U-Boot: - It's very fast (30-60ms boot times + load times for images) - Uses MMC DMA, eMMC DDR, and CPU data cache - Only minimal necessary boot steps are performed in the most straightforward manner - It's fail safe and easily debuggable - It will power down the device in case of bootloader stage boot failure, instead of silently draining the battery - Boot status is indicated via LED - green = in bootloader - red = just before passing control to ATF/Linux - no led = powered off - Bootloader failure is indicated by a 5-bit binary blinking pattern (serial port not needed for quick debugging) - Bootloader log is stored to DTB, and is visible from Linux via `/sys/firmware/devicetree/base/p-boot/log` file - Boot log can be printed to the serial port (this will slow down boot) - It has flexible boot source options - Supports multiple boot configurations on SD and eMMC - Ability to load bootloader from SD card, but read boot data from eMMC (which allows 85MiB/s image load speeds and avoids 1s LED flash activation and 1s boot delay waiting for BROM to load bootlader from eMMC) - List of available boot configurations is passed to Linux via `/sys/firmware/devicetree/base/p-boot/configs` file, so it's easy to make a Linux based boot menu. - Boot configuration selection via volume keys pressed during boot (up to 3 different boot configurations) - Allow for default boot config override via a RTC data register (you can reboot from one OS to another without user intervention) - Support for one time reboot to other OS, or "persistent" change to other boot configuration - It has access to PMIC over RSB (p-boot can access and configure the PMIC) - Easy to select alternate boot configuration in case of low battery charge level - p-boot configures the PMIC and can react to various boot reasons indicated by PMIC - Single DT blob used by p-boot, ATF and Linux (no U-Boot specific DT blob needed) - Configure a stable WiFi MAC address in FDT based on SoC ID - A lot of free space for extensions (p-boot size limit is 32KiB, current p-boot size is 31KiB with display support enabled and 25KiB with display support disabled) - Easy to understand and customize Enjoy! Ondřej Jirman (aka "megi") Future possibilities -------------------- See TODO for some possible/planned features. Building -------- 1) Get aarch64-linux-musl cross-compiler and set path to it in config.ini (you can use config.ini.sample as a starting point). 2) Then run: php configure.php ninja 3) As a result you'll get a bunch of p-boot*.bin variants in .build/ dir, named p-boot*.bin. See "Variants" section bellow for description of each variant. You may have trouble building p-boot with some toolchains. p-boot is a bit space constrained and some toolchains don't build it small enough. Known working toolchains are aarch64 toolchain (gcc 10.2) from community repo of Arch Linux, and aarch64 toolchain in the latest Ubuntu release. Building (without PHP) ---------------------- 1) Get aarch64-linux-musl cross-compiler and set path to it in build/ninja.build by modifying aarch64_prefix. 2) Go to build and run: ninja 3) Same as above. Installation summary / key points --------------------------------- - PinePhone looks for bootloader 8KiB from the start of SD or eMMC block devices, in that order. p-boot.bin needs to be flashed there. - p-boot doesn't understand traditional filesystems, it uses its own very simple boot filesystem format, and comes with a filesystem formating utility called p-boot-conf, that is used to create it. - Once flashed to the boot sector, p-boot will look for the boot filesystem in the DOS MBR style partition table (it doesn't understand any other partition format). - So all you need to have is: - DOS MBR partition table - A boot partition for p-boot. You can re-use a boot partition that most distributions create for files in /boot, just copy files from /boot to your root partition, unmount /boot, and re-format the boot partition using p-boot-conf. You can copy the the original files from boot partition back to /boot directory on the root partition, so that your distro will not break and keep updating them. Just make sure your distro will not overwrite a boot sector during updates with U-Boot. (perhaps by uninstalling a u-boot package) Installing p-boot to the "boot sector" -------------------------------------- You must install p-boot by copying the contents of p-boot.bin to the SD card and/or eMMC starting from 8KiB offset from the start of the block device: dd if=p-boot.bin of=/dev/mmcblk2 bs=1024 seek=8 dd if=p-boot.bin of=/dev/mmcblk0 bs=1024 seek=8 ATF / SCP --------- You'll need a patched ATF that works with p-boot and a SCP firmware build. You can build these using instructions in the fw/README or use a pre-built binary from dist/fw.bin (contains combined ATF and SCP binaries). Boot partition -------------- p-boot needs to find a specialized boot filesystem on one of the primary MBR partitions on eMMC or SD card (in that order). p-boot will only search partitions of type 0x83 (Linux) and it will give priority to partitions with a boot flag set. Boot partition contains a table of up to 33 boot configurations. Boot configuration is a specific set of ATF/SCP firmware, DTB, Linux, and initramfs images + Linux command line arguments (bootargs). You can use p-boot-conf tool to create a boot filesystem. You can find this tool pre-built in the dist/ folder. This tool reads a 'boot.conf' file from a specified configuration directory and creates a specialized filesystem on the boot partition based on the content of these files. You'll need to run this tool each time you'll update the configuration, or one of the kernel images, to regenerate the boot filesystem. Each configuration file has the following format: key1=value key2=value ... For example: no=1 dtb=board.dtb atf=fw.bin linux=Image initramfs=initramfs.img bootargs=console=ttyS0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=f2fs rw rootwait panic=3 Meanings of configuration options: - no: Configuration index (0-32) - dtb: path to the pinephone's DTB file - atf: path to the ATF binary or to the combined ATF+SCP binary (see dist/fw.bin) - linux: path to the Linux 'Image' file - initramfs: path to initramfs archive - bootargs: Linux kernel boot arguments to be passed to the kernel All options are required except for initramfs. All paths are relative to the configuration directory. After preparing the configuration files, and collecting the required binary files in the configuration directory, run: p-boot-conf $conf_dir $boot_partition_block_device Once done, you can reboot the PinePhone to check that p-boot works. Pre-built dist/p-boot-conf is meant for running on PinePhone itself. If you need a build of this tool for another architecture, just run `gcc -o p-boot-conf-native conf.c` in the `src/` directory. GUI variant of p-boot --------------------- GUI variant of p-boot looks for certain hardcoded files in the boot filesystem: - off.argb - power off splashscreen - pboot2.argb - default p-boot splashscreen These files can be found in the `example/` configuration, or generated from source files in the `theme/` directory. Runtime behavior ---------------- (this is slightly outdated, check main.c for actual behavior) During powerup or reboot, p-boot will check several places in its decision making process for selecting the desired boot configuration: - boot filesystem superblock (32bit BE value at 12 byte offset from the start of boot partition) - RTC data register (address 0x01f00100) - PMIC data register (address 0x04) - Status of the volume keys: - VOLUME_UP - no=1 - VOLUME_DOWN - no=0 Default value is stored in the boot filesystem's superblock. (at offset 12, 4-byte BE value). The value is unchanged by p-boot-conf. Values in volatile registers are reset to 0 during boot if bit 7 of the value is set. If the register contains value 0, the value is ignored and doesn't affect boot configuration selection process. Values other than 0 are decremented by 1 and the result is used to select the boot configuration. For example register value 0x03 will select boot configuration 2. Register value 0x82 will select boot configuration 1 and the register will be reset to 0 during boot. Boot process of p-boot is as follows: (also see src/main.c) - sample the time of the start of the boot - turn on a green LED - init various A64 clocks - enable lradc (to get a sample from volume keys ADC, later on) - (optional) init debug UART - init RSB connection to PMIC - configure PMIC - (optional) print PMIC status - shorten POK reaction time - increase VBUS current limit to 2A and enable charger detection - increase CPU voltage to accommodate switch to 1.152GHz later on - init DRAM - setup p-boot heap space for malloc() at 256MiB from end of DRAM - enable instruction cache - enable MMU/setup CPU data cache - setup SoC buses - enable LCD power early so that controller initializes before kernel runs, and kernel LCD probe can avoid delays - disable battery temperature sensor - program the battery OCV curve for better capacity reporting - increase CPU clock speed to 1152MHz - initialize eMMC - search for boot partition and load bootfs superblock/conf table - if not found repeat the same process on the SD card - select configuration from the boot table - read default boot config selection index from the table - apply value from the RTC register - apply value from the PMIC register - if VOLUME_UP is pressed, force bootsel index = 1 - if VOLUME_DOWN is pressed, force bootsel index = 0 - go through the table and load images from the table to: - Linux image to 0x40080000 - initramfs to 0x4fe00000 - DTB (FDT blob) to 0x4a000000 - ATF+SCP to 0x44000 - check validity of FDT blob, and in FDT: - set /chosen/bootargs to kernel command line - append bootdev=emmc or bootdev=sd based on the source of the bootfs - calculate MAC address for WiFi from SoC ID and patch it to FDT - add DRAM address/size info - add initramfs info - turn off green and turn on red LED - jump to ATF - ATF jumps to Linux image while switching to EL2 - (alternatively) after return from ATF, jump to Linux image while switching to EL2 Debugging --------- p-boot will try to fail gracefully in the event of boot failure. This means that it will try its best to power down the SoC. p-boot also enables the red LED as early as possible so that the user is informed in case the boot process hangs that the device is on and drawing power from the battery. In case of a bootloader panic, p-boot will first blink the red led quickly for a second and then you'll see 5 flashes of the green LED followed by device poweroff. The 5 green flashes represent a 5-bit binary number in MSB first bit order. Long flash represents 1 and short flash represents 0. You can use this to get the reason for boot failure without the need to pull out the serial cable. Simply translate the binary number to decimal and search p-boot code for the panic call with this number. For example, if you get a flash pattern ". - . - ." -> 0b01010 -> 10: grep -R 'panic(10' src src/main.c: panic(10, "BOOTFS not found"); That is bootfs was not found. :) Variants -------- p-boot can be compiled with several options that improve boot speed, or reduce size or both. p-boot.bin - GUI variant of p-boot p-boot-serial.bin - non-GUI variant, logs to serial console and FDT p-boot-tiny.bin - non-GUI variant, doesn't log anyhting at all, and doesn't store log messages in the binary, so it saves about 5 KiB of space for more code This is a typical boot log from the p-boot-serial.bin: % cat /sys/firmware/devicetree/base/p-boot/log p-boot (version 547db8d-dirty built 2020-05-20 22:55) 384 us: PMIC ready 3492 us: DRAM: 2048 MiB SoC ID: 92c059ba:14104620:78968308:101a0950 Board rev: 1.2 Boot Source: ff 34065 us: eMMC ready Trying boot partition located at 0x100000(255 MiB) (part 0) Bootsel override via RTC data[0] to 5 35500 us: Booting configuration 5 (xnux:Tablet UI test (eMMC)) 41228 us: IMG[A]: 0x476e400(61368 B) -> 0x44000 (10466 KiB/s) 41856 us: IMG[D]: 0x477d400(37399 B) -> 0x4a000000 (58342 KiB/s) 196896 us: IMG[L]: 0x4786800(14002184 B) -> 0x40080000 (88197 KiB/s) Model: Pine64 PinePhone (1.2) WiFi MAC: 02:ba:7c:9c:cc:78 Bugs and support ---------------- Please report bugs via email: p-boot@xnux.eu Development ----------- Project status: p-boot is maintained and actively developed by the original author. You can join development of p-boot by sending questions, ideas, bugreports and patches to the above mailing address. GIT repository is available at: https://megous.com/git/p-boot. Support the project ------------------- p-boot is free and opesource software released under GPLv3. It is an independent personal project not backed by any comapny or commercial interests. You can contribute by writing code, helping improve documentation, spreading the word, and/or by donating at: https://xnux.eu/contribute.html