Cover Image
Shanghai is hosting the White Magnolia Ice and Snow Festival, featuring a rare outdoor ice skating rink.[Previous Highlights]: Comprehensive Guide: Practical Guide to Tuning GPU on RK Platform with Ubuntu
Welcome to follow “Embedded Sharing“, updated weekly!☞
Main Content
Friends who have debugged both RK and Allwinner platforms know that on the Allwinner platform, display adjustments often require changes to both U-Boot and kernel DTS; however, on the RK platform, only the kernel DTS needs to be modified.Why is this? This is mainly due to the Kernel-DTB mechanism.
Background of Kernel-DTB Design
The native architecture of U-Boot has a clear requirement: one board must correspond to one U-Boot DTS, and the DTB generated from this DTS will be directly packaged into the U-Boot image itself. This leads to a problem: on various SoC platforms, if there are N different boards, N corresponding U-Boot images need to be generated.
We can easily see that the core differences among different boards on the same SoC platform lie mainly in peripheral configurations, while the core part of the SoC remains consistent. To achieve the goal of having only one U-Boot image for a single SoC platform, the RK platform specifically introduced the Kernel-DTB mechanism — which essentially switches to the Kernel DTB early in the boot process, directly reusing its configuration information to complete peripheral initialization.
Thus, the RK platform, by supporting the Kernel-DTB mechanism, can accommodate peripheral differences across different boards, such as display, PMIC/regulator, pinctrl, clk, etc.The division of labor is clear:
- U-Boot DTB: only responsible for initializing core basic devices such as storage and serial printing;
- Kernel DTB: responsible for initializing all other peripherals except for storage and serial printing.
The U-Boot initialization process is as follows: first, the U-Boot DTB completes the basic initialization of storage and serial printing, then loads the Kernel DTB from storage, and continues to use this DTB to complete the initialization of other peripherals.Developers usually do not need to modify the U-Boot DTB (only adjustments are needed when changing the serial printing), and the defconfig in the SDK released for each platform has already enabled the Kernel-DTB mechanism by default. Therefore, for peripheral DTS modifications, users can directly modify the Kernel DTB.
Enabling the kernel DTB relies on OF_LIVE (live device tree, abbreviated as: live-dt).
config USING_KERNEL_DTBbool "Using dtb from Kernel/resource for U-Boot"depends on RKIMG_BOOTLOADER && OF_LIVEdefault yhelpThis enable support to read dtb from resource and use it for U-Boot,the uart and emmc will still using U-Boot dtb, but other devices likeregulator/pmic, display, usb will use dts node from kernel.
Implementation of the Kernel DTB Mechanism
Specifically, the switch to the Kernel DTB is implemented in the init_kernel_dtb() function in the ./arch/arm/mach-rockchip/board.c file.
This switch occurs at a critical point: the DTB of U-Boot has already completed scanning and initialization, which means that drivers for storage media such as MMC, NAND, and NOR are functioning normally.In the init_kernel_dtb() function, U-Boot performs the following operations:
- Loads the Kernel DTB from the specified storage medium (such as eMMC) into memory.
- Executes the Live DT table creation process on the newly loaded Kernel DTB and binds all device nodes to their corresponding device drivers.
- Finally, updates the global gd->fdt_blob pointer to point to this new Kernel DTB.
Background and Principles of Live Device Tree
With the introduction of the Kernel-DTB mechanism, there will be two independent DTBs (Device Tree Blobs) during the U-Boot phase: one is the U-Boot DTB itself (used for initializing storage, serial ports, encryption, and other early core devices), and the other is the Kernel DTB that will be passed to the kernel (used to describe the complete hardware information of the system).This brings a core challenge: during the execution flow of U-Boot, it may need to access device modules belonging to these two DTBs at different times. For example, U-Boot may first initialize the serial port (console) using its own DTB, and then during certain operations (such as downloading the kernel via a network card), it needs to access the network device described by the Kernel DTB.The problem is that these device modules rely on a global DTB pointer (usually gd->fdt_blob) when accessing their configuration information. This pointer can only point to one DTB at any given time, and frequent switching can lead to significant complexity and potential risks.Moreover, directly merging (overlaying) the contents of the U-Boot DTB into the Kernel DTB is also not feasible, as the Kernel DTB must maintain its purity and independence to ensure it can be correctly parsed and used by the kernel.So, how does the RK platform elegantly solve this problem?The Live DT mechanism perfectly addresses this issue. Its core principle is as follows: during the U-Boot initialization phase, all DTBs (including U-Boot DTB and Kernel DTB) are scanned, and all DTB nodes are uniformly converted into a linked list of struct device_node types, which are then bound to their corresponding device drivers. When subsequent device drivers need to access hardware configuration information, they can directly call their bound device_node without needing to directly manipulate the original DTB files.This effectively binds the U-Boot DTB and Kernel DTB to their respective groups of device drivers, eliminating the need to directly access the original DTB files throughout the process. This fundamentally resolves the pointer conflict issue caused by accessing two DTBs during the U-Boot phase.In summary: During the U-Boot phase, the Kernel’s DTB is loaded and read, and the Live DT mechanism activates its device drivers, thus achieving the shared use of a single DTS configuration.At this point, we fully understand why on the RK platform, display adjustments do not require modifications to both U-Boot and Kernel DTS as is the case with the Allwinner platform.
(End)