U-Boot porting: Difference between revisions
Dsankouski (talk | contribs) No edit summary |
Dsankouski (talk | contribs) No edit summary |
||
Line 30: | Line 30: | ||
* CONFIG_SYS_INIT_SP_ADDR - address of early C runtime environment stack (should in RAM address space, but NOT at the bottom, because stack is growing DOWN. see u-boot readme memory management section) | * CONFIG_SYS_INIT_SP_ADDR - address of early C runtime environment stack (should in RAM address space, but NOT at the bottom, because stack is growing DOWN. see u-boot readme memory management section) | ||
* CONFIG_SYS_TEXT_BASE - u-boot base address. See instructions below, how to find it. | * CONFIG_SYS_TEXT_BASE - u-boot base address. See instructions below, how to find it. | ||
* CONFIG_DEBUG_UART=y | |||
* CONFIG_DEBUG_UART_SKIP_INIT=y - make sure to comment <code>_debug_uart_init</code> function code in you serial driver with that option | |||
* CONFIG_DEBUG_UART_BASE=0x13820000 // your uart address from downstream device tree | |||
* CONFIG_LOGLEVEL=8 // log all | |||
=== Building === | === Building === | ||
==== Make u-boot ==== | |||
Install arm cross compiler | Install arm cross compiler | ||
Build: | Build: | ||
Line 39: | Line 43: | ||
make <$board_name>_defconfig | make <$board_name>_defconfig | ||
make | make | ||
{ | ==== Create android boot image ==== | ||
mkbootimg --base 0x40000000 --kernel_offset 0x00008000 --ramdisk_offset 0x01000000 --tags_offset 0x00000100 --pagesize 2048 --second_offset 0x00f00000 --kernel {path to u-boot.bin} -o {output file} | |||
Replace offsets to your offsets, found from downstream boot.img. | |||
== Getting uart debug output == | == Getting uart debug output == | ||
Line 53: | Line 59: | ||
=== Using debug() function === | === Using debug() function === | ||
You can get debug output from particular *.c file by adding <code>#define DEBUG</code> at the top of file, and calling <code>debug("debug output");</code> where you need. | You can get debug output from particular *.c file by adding <code>#define DEBUG</code> at the top of file, and calling <code>debug("debug output");</code> where you need. | ||
Line 98: | Line 98: | ||
== Creating basic device tree == | == Creating basic device tree == | ||
{{ | Will contain node for uart driver, fixed clock and chosen. | ||
=== a5y17lte device tree example === | |||
exynos7880.dtsi: | |||
// SPDX-License-Identifier: GPL-2.0+ | |||
/dts-v1/; | |||
#include "skeleton.dtsi" | |||
/ { | |||
compatible = "samsung,exynos7880"; | |||
fin_pll: xxti { | |||
compatible = "fixed-clock"; | |||
clock-output-names = "fin_pll"; | |||
u-boot,dm-pre-reloc; | |||
#clock-cells = <0>; | |||
}; | |||
uart2: serial@13820000 { | |||
compatible = "samsung,exynos4210-uart"; | |||
reg = <0x13820000 0x100>; | |||
u-boot,dm-pre-reloc; | |||
}; | |||
}; | |||
a5y17lte.dts: | |||
// SPDX-License-Identifier: GPL-2.0+ | |||
/dts-v1/; | |||
#include "exynos7880.dtsi" | |||
/ { | |||
compatible = "samsung,exynos7880"; | |||
aliases { | |||
console = &uart2; | |||
}; | |||
chosen { | |||
stdout-path = &uart2; | |||
}; | |||
}; | |||
&fin_pll { | |||
clock-frequency = <26000000>; | |||
}; | |||
=== Final changes === | |||
You may need to comment some serial driver initialization code, as it may not work properly without clock and pinctrl drivers. | |||
== Congrats! You should now get a u-boot console prompt! == | == Congrats! You should now get a u-boot console prompt! == |
Revision as of 13:49, 10 October 2020
It is possible to port u-boot on your phone, even if there is no SOC support in uboot tree (because stock bootloader initialized hardware for us). First thing to focus on should be getting u-boot shell prompt.
Preparation
- Find uboot code
- Before starting uboot porting, you should get access to the stock bootloader uart port. Make sure you can see stock bootloader logs.
- Search uboot code for a uart driver, compatible with your SOC. It is good, if it support debug(i.e. include debug_uart.h)
- Get familiar with you phone RAM map
- Some useful links:
- bring up process
- configuration process
Create basic configuration and build
Add board files
Use guide from Free Electrons pdf or video version
Examples
Configure
U-boot configuration system comes from linux kernel. Put config options not supposed to be changed by user in /include/configs/.*.h
files, in *_defconfig
otherwise
Options, you DO NOT need
- All SPL related options. SPL(Secondary Program Loader) splits u-boot in two parts. You don't need this, since stock bootloader will load whole u-boot image into RAM.
- CONFIG_BOARD_EARLY_INIT_F
Options, you need
- CONFIG_SYS_MALLOC_LEN - size of early C runtime environment heap
- CONFIG_SYS_INIT_SP_ADDR - address of early C runtime environment stack (should in RAM address space, but NOT at the bottom, because stack is growing DOWN. see u-boot readme memory management section)
- CONFIG_SYS_TEXT_BASE - u-boot base address. See instructions below, how to find it.
- CONFIG_DEBUG_UART=y
- CONFIG_DEBUG_UART_SKIP_INIT=y - make sure to comment
_debug_uart_init
function code in you serial driver with that option - CONFIG_DEBUG_UART_BASE=0x13820000 // your uart address from downstream device tree
- CONFIG_LOGLEVEL=8 // log all
Building
Make u-boot
Install arm cross compiler Build:
export CROSS_COMPILE=aarch64-linux-gnu- make <$board_name>_defconfig make
Create android boot image
mkbootimg --base 0x40000000 --kernel_offset 0x00008000 --ramdisk_offset 0x01000000 --tags_offset 0x00000100 --pagesize 2048 --second_offset 0x00f00000 --kernel {path to u-boot.bin} -o {output file}
Replace offsets to your offsets, found from downstream boot.img.
Getting uart debug output
Raw
This may be useful, when no C runtime environment set up yet. You should find uart address to write
C
*(volatile unsigned char *)(0x13820020/*uart register to write characters*/) = 0x48; // print H letter
Assembly
mov x26, #0x20 // move 0x13820020 low 16 bit to x26 register movk x26, #0x1382, lsl #16 // move 0x13820020 high 16 bit to x26 register mov x27, #0x48 // H letter ascii code str x27, [x26] // move H to uart register
Using debug() function
You can get debug output from particular *.c file by adding #define DEBUG
at the top of file, and calling debug("debug output");
where you need.
Finding base address
You should tell u-boot base address, i.e. address in RAM, where stock bootloader load u-boot. Keep in mind, that stock bootloader may ignore offsets, set in boot.img. This section describes, how to find it.
Without the knowledge of base address u-boot will fail on /common/board_f.c
file when calling functions from init_sequence_f
. This is a list of initcall addresses, and if CONFIG_SYS_TEXT_BASE does not match with address u-boot resides, you CPU will jump in wrong address and execute irrelevant code, leaving you with unpredictable uart output and results.
To find u-boot base address, you should dump RAM, where u-boot presumably resides, and find(hex search), at what address uboot image starts.
Enable debug
- put #define DEBUG
at the top of /common/board_f.c
file
Narrow down RAM range u-boot resides in
- read PC(program counter) or LR(link register) at board_init_f function
uint64_t pc; asm volatile ("ADR %0, ." : "=r"(pc) ::); debug("pc reg at board_init_f is: %p", pc);
Here we are reading pc reg from C
Once you have PC register value, u-boot base address 100% in range PC-uboot_size - PC+uboot_size.
How to dump ram
- put ram dump code at the beginning of board_init_f
function.
Ram dump code example:
char *val; val = 0x40001000; // dump start address debug("0x40001000 - 0x40101000 \n"); for(int i=0 ; i < 0x100000 /* dump size*/; i++) { if ((i & 0xf) == 0) {// new line every 16 symbols debug("\n%.8x: ", val + i); // current address stamp } debug("%.2x ", *(val + i)); } debug("\n");
Find uboot start address in dump
Find first few bytes of compiled u-boot image in RAM dump. Result will be u-boot base address.
Creating basic device tree
Will contain node for uart driver, fixed clock and chosen.
a5y17lte device tree example
exynos7880.dtsi:
// SPDX-License-Identifier: GPL-2.0+ /dts-v1/; #include "skeleton.dtsi" / { compatible = "samsung,exynos7880"; fin_pll: xxti { compatible = "fixed-clock"; clock-output-names = "fin_pll"; u-boot,dm-pre-reloc; #clock-cells = <0>; }; uart2: serial@13820000 { compatible = "samsung,exynos4210-uart"; reg = <0x13820000 0x100>; u-boot,dm-pre-reloc; }; };
a5y17lte.dts:
// SPDX-License-Identifier: GPL-2.0+ /dts-v1/; #include "exynos7880.dtsi" / { compatible = "samsung,exynos7880"; aliases { console = &uart2; }; chosen { stdout-path = &uart2; }; }; &fin_pll { clock-frequency = <26000000>; };
Final changes
You may need to comment some serial driver initialization code, as it may not work properly without clock and pinctrl drivers.