4.1. Porting U-Boot on Custom Board

4.1.1. Overview

When porting custom board to U-Boot it is recommended to start with a TI EVM that resembles the custom hardware design in some capacity, for example in the areas of DDR (type and size of memory), MMC (which module is used, is there an eMMC connected or is an SD card being used), network setup (type and number of PHYs connected), and UART setup (which UART is intended to be used for console purposes?).

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

4.1.2. Porting Custom Board Steps

4.1.2.1. Starting with U-Boot on TI EVM

U-Boot uses the driver model, and driver binding is accomplished with Device Tree Source (DTS) Files. There is a DTS that is unique to the R5 and a unique one to the A53. The DTS File is the board portion of the abstraction and binds the Kernel and now U-Boot to a board.

  • Build defconfigs:
    • am64x_evm_r5_defconfig: defconfig which includes the configuration flags for building R5 SPL
    • am64x_evm_a53_defconfig: defconfig which includes the configuration flags for building A53 SPL and U-Boot
  • DTS files:
    • k3-am642-r5-evm.dts: main R5 DTS file which includs the nodes for R5 boot, Pinmux, DDR, etc.
    • k3-am642-evm.dts: main A53 DTS file which includes the nodes for A53 boot, Pinmux, etc.
  • Summary:
    • Use the U-Boot source in the Processor SDK from TI.
    • Start with the TI examples of the R5 and A53 DTS files.
    • The Board DTS is the final step that defines what SOC components are necessary to run the custom board.
    • The Pinmux and DDR Config tool will be used to fill out DTS nodes.

4.1.2.2. Porting Custom Board with Minimum Configuration

As a first step we want to create a minimal configuration that can be used for an initial attempt at bringing up the board. Once the basics are working, it will become a good base to incrementally build, step by step, to fully support all the desired features of a custom board. Note that the chances of getting everything right in the first attempts are rather low. Typically an iterative approach is taken: start simple, make small changes, build, check them into the Git source tree (so changes can be traced, understood, and reverted if needed more easily), and testing them on hardware, until the fully working and functional board port is achieved.

  • Port DDR configuration if your DDR setup (devices, clock speeds, etc.) differs from the originating platform (EVM)

    • Follow the steps outlined in the DDR Board Design and Layout Guidelines in detail. This application report also includes information useful for DDR bringup.

    • To facilitate software configuration of the DDRSS, use the DDR Subsystem Configuration Tool in SysConfig to generate DDR configuration device tree files. For example,

      • u-boot/arch/arm/dts/k3-am64-evm-ddr4-1600MTs.dtsi: AM64x GP EVM DDR4 configuration
      • u-boot/arch/arm/dts/k3-am64-sk-lp4-1333MTs.dtsi: AM64x SK LPDDR4 configuration
    • When the DDR timings and parameters are setup correctly, U-Boot will automatically detect, verify, and configure the size of DDR during runtime in the architectural files by using get_ram_size().

  • Establish an initial minimal pinmux setup for the custom board

    • A minimal pinmux setup is needed to avoid any potential signal conflicts that may occur when running a configuration that was intended for a TI EVM that is simply run on a custom board.
    • Pinmux performed in U-Boot is usually limited to the peripherals that are directly involved in the boot process (such as GPMC, DDR, MMC, SPI, etc.), an I2C module used for PMIC connectivity, as well as the console UART.
    • The recommended way to quickly derive the pinmux settings needed is to use the TI-provided Pin MUX Utility in SysConfig.
  • Update PMIC configuration

    • TI AMxxx SoCs are typically supplied by an external Power Management IC (PMIC) connected via the I2C interface. One of the jobs of the PMIC is to supply and provide the voltages meeting datasheet requirements.
    • The actual PMIC configuration is made dependent on the clock frequency configured for a given board. It may also need to be made dependent on silicon revision, so review the originating TI EVM’s code carefully, which is mostly directed based on board_is_*() invocations
  • Customize console UART settings

    • Configure desired console index using the Kconfig tool
  • Deactivate all peripheral initializations except for basic boot support like UART, MMC, etc. from the <device>-<myboard>.dts device tree file using one of the following methods:

    1. Remove all device tree nodes that are not applicable, including their references such as clocks, power regulator, and pinmux settings
    2. De-activate peripherals that are not needed by adding a status = "disabled"; property to their respective nodes

With the customizations now made, an attempt should be made at an initial boot of the custom hardware platform in the context of the hardware bringup of the new board. The goal should be to get to the U-Boot prompt.

4.1.2.3. Building out Full Support for Target Platform

Once the U-Boot prompt has been reached, the porting focus now switches to (re-)adding any features to U-Boot that may be needed to more fully support the custom system, and then move to booting the Linux Kernel. 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.

Customization steps can involve, 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 debugging or running 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, and 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 since have become available. However, care must be taken when back porting code to the U-Boot part of the TI Processor SDK to consider all required dependencies and changes that may have since affected a specific feature.

4.1.3. U-Boot Bringup Debugging Tips

Doing an U-Boot board port is usually an iterative process, involving some amount of debugging and troubleshooting, especially on a custom hardware platform that differs substantially from one of the TI EVMs. The following list gives some ideas that could be helpful during debugging and 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 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()). As discussed earlier, most of the critical low-level code on current TI EVMs is executed while the regular console UART is not yet available. In this case nothing would get printed during any failures relating to boot, PMIC setup, clock setup, DDR setup, and other critical stages, leading to “black screen” type of failures which provide no feedback as to what the problem may be and how to debug.
    • 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 simple statement shown below can easily be replicated through copy and paste yet gives usually enough information to pinpoint a specific line of code: printf("%s: %d:\n", __func__, __LINE__);.