Porting U-Boot#

This module briefs on porting U-Boot on a custom board.

Overview#

When porting U-Boot on a custom board, it is recommended to start with a TI EVM that is similar to the custom hardware design. For example, the boards may have similar DDR (type and size of memory), MMC (which module is used, is the MMC an eMMC or SD card), network setup (type and number of PHYs connected), and UART setup (which UART is used as the console?).

For custom AM64x boards, many base their design off the AM64x General-Purpose EVM, or the AM64x Starter Kit.

For more information on the Linux boot flow (including how the R5 core is used during a Linux boot), reference section Linux Boot Flow.

Porting Custom Board Steps#

Porting Custom Board with Minimum Configuration#

First, create a minimal configuration that can be used for the initial board bringup attempt. Once the basics are working, the minimal configuration is a good base to incrementally build on. Add features one by one, until the configuration fully supports all the desired features of the custom board.

The Application Note Linux Board Porting on AM62x Devices (Appnote) details porting U-Boot and Linux to an AM62x custom board using TI Processor SDK. The Appnote first five sections focus on U-Boot porting. The rest focuses on kernel porting.

Though the Appnote uses AM62x as an example, the porting process is applicable to AM64x devices too.

Building out Full Support for Target Platform#

Once the U-Boot prompt has been reached, the porting focus switches to (re-)adding U-Boot features that are needed to support the custom system. It is recommended to add features one by one, while using Git to track any changes. Test and validate features on actual hardware as they are added, until all desired features have been added, tested, and integrated. Once the U-Boot features have been ported, developers can progress to porting the Linux Kernel.

Customization steps can include, but are not limited to, adding…

  • Support for additional storage media

  • Support for additional boot modes

  • Support for network interface(s)

  • Support for extra U-Boot commands (CONFIG_CMD_*) to help debug or run the system

When adding features, it is usually a good idea to analyze other boards already present in U-Boot that use the same TI SoC. Then, port features over into the new custom board files, board specific header file, and defconfig.

It can also be helpful to inspect the most current upstream U-Boot tree for additional boards that may have become available since the last TI Processor SDK release. However, care must be taken when back porting code to an earlier version of U-Boot. Consider all the required dependencies and changes that may have affected a specific feature.

Modifying RAM Size#

The Appnote section 4.3.2 “Generate Devicetree for DDR Configuration” explains the process for generating DDR config for the custom board. The memory size also should be adjusted in U-Boot device tree if the size is different from the memory size on the SK EVM.

Following U-Boot patch shows how to modify the RAM size from 2GB to 512MB as an example.

diff --git a/arch/arm/dts/k3-am62x-r5-sk-common.dtsi b/arch/arm/dts/k3-am62x-r5-sk-common.dtsi
index b4a5e3cfa1..eacc65ad59 100644
--- a/arch/arm/dts/k3-am62x-r5-sk-common.dtsi
+++ b/arch/arm/dts/k3-am62x-r5-sk-common.dtsi
@@ -20,7 +20,7 @@
                memory@80000000 {
                        device_type = "memory";
-                       /* 2G RAM */
-                       reg = <0x00000000 0x80000000 0x00000000 0x80000000>;
+                       /* 512M RAM */
+                       reg = <0x00000000 0x80000000 0x00000000 0x20000000>;
                        u-boot,dm-spl;
                };
diff --git a/arch/arm/dts/k3-am62x-sk-common.dtsi b/arch/arm/dts/k3-am62x-sk-common.dtsi
index e67ddebccf..c9b61e2a32 100644
--- a/arch/arm/dts/k3-am62x-sk-common.dtsi
+++ b/arch/arm/dts/k3-am62x-sk-common.dtsi
@@ -31,7 +31,7 @@
                memory@80000000 {
                        device_type = "memory";
-                       /* 2G RAM */
-                       reg = <0x00000000 0x80000000 0x00000000 0x80000000>;
+                       /* 512M RAM */
+                       reg = <0x00000000 0x80000000 0x00000000 0x20000000>;
                };

In the above code, 0x80000000 represents 2GB and 0x20000000 represents 512MB. After making the necessary changes, rebuild the entire U-Boot code and update our boot media with the new U-Boot binaries. To verify the changes, run the command bdinfo in U-Boot and check the DRAM size reported.

=> bdinfo
boot_params = 0x0000000000000000
DRAM bank   = 0x0000000000000000
-> start    = 0x0000000080000000
-> size     = 0x0000000020000000

U-Boot Bringup Debugging Tips#

Doing a U-Boot board port is usually an iterative process. It involves debugging and troubleshooting, especially on custom hardware platforms that differ substantially from the TI EVMs. The following list gives some ideas that could be helpful while debugging the U-Boot bringup.

  • The most efficient and powerful tool for board bringup is to have access to the SoC via JTAG debugger, and use a tool such as TI’s Code Composer Studio (CCS) or Lauterbach (T32) to inspect the device and code.

  • Performing basic printf()-style debugging:

    • Use printf()-style debugging when JTAG is not available or not practical.

    • Maximizing the usefulness of this approach usually requires the early (debug) UART to be configured and activated (which will happen as part of SPL’s board_init_f()). Most of the critical low-level code on current TI EVMs is executed while the regular console UART is not yet available. If the early UART is not activated, nothing would get printed during failures relating to boot, PMIC setup, clock setup, DDR setup, and other critical stages. This leads to “black screen” failures which provide no feedback as to what the problem may be and how to debug it.

    • Many U-Boot modules (source files) already contain various forms of debug() print statements which can be activated on a per-module basis by adding a #define DEBUG to the top of the source file.

    • Beyond that, it can be helpful to add print statements throughout the boot flow to trace program execution. For example, the printf statement shown below can be inserted into code to help debug: printf("%s: %d:\n", __func__, __LINE__);.