Chapter 24J: SPI LCD and I2C OLED displays in U-Boot

An SPI transfer succeeds, yet the screen does not change. That is possible: SPI reports whether the controller moved bits, not whether those bits were the panel’s commands, used the right D/C level, or reached initialized pixel memory. An I2C ACK is similarly narrower than a visible OLED image.

This chapter follows those bytes to a small status display. We use upstream U-Boot v2026.04, distinguish its drivers from Linux’s, and provide a bounded SSD1306 command for one documented module profile. The supplied MINI V2.2 has no fitted SPI LCD or I2C OLED. Its RGBLCD socket belongs to Chapter 24I; a small serial display is an added module. We use the actual P4 expansion routes below, with a shared P1/I2C2 alternative for an OLED. The guide’s ALPHA I2C/SPI sensor labs are not evidence that their devices exist on MINI.

Begin with Chapter 19’s MINI vendor baseline and UART1 console. The bus mapping below comes from the supplied MINI/core schematics; the code targets the separate v2026.04 mx6ull_pa_mini migration, not a drop-in vendor patch. Keep UART1 for diagnostics while bringing up the added module.

24J.1 First decision: what kind of display is it?

Display

Bus/memory

Path in this chapter

Parallel RGB panel

eLCDIF scans a RAM framebuffer

Chapter 24I’s DM video path

ST7735/ST7789/ILI9341-type color module

SPI commands and controller pixel RAM

Board-specific transport/init unless a verified driver implements the required path

SSD1306 monochrome module

I2C commands and page-organized display RAM

Bounded board-local status command

SH1106 module

Similar-looking but different addressing/geometry

Its own driver/profile, not the SSD1306 command below

Smart UART display

Module-specific serial protocol

Separate product integration

The v2026.04 drivers/video/ tree has no matching ST7735, ST7789, ILI9341, SSD1306, or SH1106 driver for these examples. A Linux-compatible string does not create a U-Boot driver. In particular, a panel-initialization driver is not necessarily a DM video driver that allocates a framebuffer and flushes pixels over SPI.

Use a full framebuffer only when you need it and have the complete transport integration. A rectangle indicating service mode needs far less code, but still needs correct initialization and errors. Calling the routine “tiny” does not exempt it from those requirements.

For a first MINI extension, a documented 128 x 64 I2C SSD1306 module with 3.3 V-compatible supply/logic and the specified charge-pump profile needs fewer control wires than a color SPI LCD. Use I2C1 on P4 as described in Section 24J.8. A color module additionally needs a reviewed D/C, reset, backlight and initialization path; the transport helper alone will not display an image. Neither module is part of the stock-board acceptance test.

24J.2 What belongs in U-Boot?

Useful early states include boot attempt, recovery service, refusal reason, and a defined factory result. Show update progress only after verified work actually advances; transferring bytes into a buffer is not a committed flash update. Do not display PASS before the check succeeds.

Keep the serial console as the authoritative diagnostic path. A display may itself be the failed optional peripheral. Rendering it must not enable an unsafe rail, bypass a power veto, or block watchdog service indefinitely. Linux takes over the display after its own driver initializes it; U-Boot’s status routine is not the product UI.

24J.3 SPI LCD hardware checklist

Signal/condition

Evidence needed

SCLK/MOSI/CS

Actual ECSPI controller, pad routing, chip select, SPI mode and allowed frequency

MISO

Whether connected and whether reads are supported; write-only panels cannot prove identity by readback

D/C

Command/data polarity and setup time relative to CS/clock

RESET

Assertion polarity, pulse width, delay after release

Backlight

Separate driver/enable/PWM polarity and safe startup order

VCC/IOVCC

Correct voltage levels, power sequence, no powered GPIO back-feed

Geometry

Controller RAM size, visible window offsets, rotation and RGB/BGR order

MINI sheet 3’s P4 exposes a useful ECSPI3 route, verified against the v2026.04 i.MX6UL pin-function definitions:

P4 pin

Schematic net / SoC pad

ECSPI3 function

17

UART2_TXD / UART2_TX_DATA

SS0 (native chip select)

18

UART2_RXD / UART2_RX_DATA

SCLK

19

UART2_RTS / UART2_RTS_B

MISO

20

UART2_CTS / UART2_CTS_B

MOSI

The UART labels name physical routes, not the selected function. Disable UART2 ownership and configure the corresponding __ECSPI3_* pinmux plus the ECSPI3 controller in U-Boot’s control DT. Do not use ALPHA’s sensor connector wiring or switch ENET2 pads away from the MINI’s onboard PHY. Confirm P4 pin 1/orientation on the actual assembly before attaching wires.

P4 pin 47 is ground, 48 DCDC_3V3, and 46 DCDC_5V. These are board supply nets, not interchangeable module voltages; check the module’s supply and IO levels, pull-ups, current budget and power-off behavior. D/C/reset and backlight still need separately assigned GPIOs/module circuits. UART1_CTS/GPIO1_IO18 is MINI KEY0; GPIO1_IO01 carries GBC_KEY/AP_INT, not that switch. GPIO1_IO03 is LED0, GPIO1_IO08 RGB backlight, and SNVS_TAMPER1/GPIO5 bit 1 BEEP through an active-low PNP switch. GPIO1_IO04 also reaches camera PWDN, and GPIO1_IO02 camera RESET. A header pin is not automatically unowned: review accessories and the control DT before selecting the additional outputs.

A typical controller sequence includes reset, sleep exit and its delay, power/gamma configuration, pixel format, memory orientation, a visible column/row window, pixel data, display-on, and backlight. The exact command bytes and delays come from the controller and module specification. ST7789, ST7735, and ILI9341 sequences are not interchangeable.

24J.4 SPI LCD: Device Tree shape

Describe the real ECSPI bus, pinmux, and chip select. A display child needs its actual reg chip-select index and spi-max-frequency; mode properties, D/C/reset GPIOs, and any power/backlight links must match the driver you are actually writing. Do not add sitronix,st7789v and expect v2026.04 to bind a missing driver.

Property/group

What it establishes

Bus pinctrl

SCLK/MOSI and any MISO route; separate D/C/reset/CS GPIO pad groups where needed

cs-gpios or native CS

The verified selected device, not an assumed GPIO4 bit 26

Child reg

SPI chip select, not a memory address

spi-max-frequency and mode

A reviewed bus limit, not a calibrated transfer rate

Driver-consumed GPIO properties

Ownership/polarity only if the implementation requests them

Width/height/rotation

Useful only if the chosen driver parses them

For an initial command-driven prototype, bind a reviewed generic SPI child or the new board-local driver and request GPIO descriptors explicitly. Generic SPI binding does not reset the LCD or render pixels. A future video driver must provide geometry/storage, draw/flush behavior, and error handling; a panel node alone is not that implementation.

24J.5 SPI LCD: useful configs

The i.MX bus foundation is:

CONFIG_SPI=y
CONFIG_DM_SPI=y
CONFIG_MXC_SPI=y
CONFIG_CMD_SPI=y
CONFIG_DM_GPIO=y

CMD_SPI adds sspi, not a command named spi. Check help sspi on the actual build. Its arguments include a bit count, not a byte count. Its small command buffer is not a frame uploader; do not paste unbounded pixel hex strings. A transfer also needs the right D/C state, which sspi does not configure for you.

If implementing a real DM video driver, use CONFIG_VIDEO and the required BMP formats as in Chapter 24I; CONFIG_DM_VIDEO is not a v2026.04 symbol. Do not enable generic video and claim it supplies the absent panel driver. Build the same MINI port with Chapter 3’s sourced environment and a separate O= directory. Bus compilation does not validate the added module wiring.

24J.6 SPI LCD manual bring-up order

First keep the backlight disabled and review the electrical/reset sequence. Verify the bus/pad route, then use an approved analyzer connection to inspect a small, documented command transaction. A write-only transfer returning zero cannot distinguish an absent panel from a correctly connected one.

This transport helper, not a complete panel driver, sends one command and up to 512 data bytes with CS held across the D/C change. It assumes a probed SPI child device and an already requested D/C descriptor whose logical 0 is command and 1 is data:

#include <dm.h>
#include <spi.h>
#include <asm/gpio.h>
#include <linux/errno.h>
#include <linux/types.h>

static int lcd_command(struct udevice *child, struct gpio_desc *dc,
                       u8 command, const u8 *data, unsigned int len)
{
    int ret;

    if (len > 512 || (len && !data))
        return -EINVAL;
    ret = dm_spi_claim_bus(child);
    if (ret)
        return ret;
    ret = dm_gpio_set_value(dc, 0);
    if (ret)
        goto release;
    ret = dm_spi_xfer(child, 8, &command, NULL,
                     SPI_XFER_BEGIN | (len ? 0 : SPI_XFER_END));
    if (ret)
        goto end;
    if (len) {
        ret = dm_gpio_set_value(dc, 1);
        if (ret)
            goto end;
        ret = dm_spi_xfer(child, len * 8, data, NULL, SPI_XFER_END);
        if (ret)
            goto end;
    }
    goto release;
end:
    /* Best effort to release CS; preserve the original error. */
    dm_spi_xfer(child, 0, NULL, NULL, SPI_XFER_END);
release:
    dm_spi_release_bus(child);
    return ret;
}

The byte bound makes len * 8 safe and keeps the buffer contract explicit. The supplied buffer must really contain len bytes. A cleanup error cannot prove CS returned idle: report the original error and stop that display path, then use the board’s approved reset/recovery procedure. The helper does not supply reset, delays, bus speed/mode, or rail initialization. Add required D/C setup/hold delays if the selected controller’s specification needs them.

After a documented initialization, set a small column/row window using the controller’s required high-byte/low-byte order, then write a known pixel pattern. For an RGB565 mode, red is the byte pair f8 00, green 07 e0, and blue 00 1f if the selected mode is high-byte-first RGB. Sending a native little-endian u16 array reverses those bytes. RGB/BGR settings can change the visible colors too.

The bounded helper is not a whole-screen fill engine. A 16 x 16 RGB565 window needs 512 pixel bytes; a larger frame needs a reviewed streaming/chunking routine that preserves controller address state and watchdog scheduling. Do not restart RAM-write at the origin for every chunk and call that a fill. Prove color/window mapping before adding text. Without module-specific init, this SPI path remains an implementation example, not a ready-to-use driver.

24J.7 I2C OLED: why it feels different

An SSD1306 has display RAM too. In its page organization, one byte controls eight vertical pixels at one column. A 128 x 64 image needs 128 * (64 / 8) = 1024 data bytes. There is no separate backlight: OLED pixels emit light.

In I2C mode, a control byte precedes the payload. 0x00 selects a command stream; 0x40 selects display data. These are not register addresses. The first payload byte must not be preceded by an extra register-offset byte inserted by a generic I2C helper.

SSD1306 modules may use 7-bit address 0x3c or 0x3d, but verify the fitted strap/module. Some modules are SPI, 128 x 32, externally supplied, or contain SH1106 instead. A matching outline or an ACK does not establish this profile.

After the I2C slave address, control byte 0x00 introduces SSD1306 commands and 0x40 introduces display data. One data byte represents eight vertical pixels in page organization.

The control byte selects how the SSD1306 interprets the following bytes. It is not a register address, and no extra offset byte belongs before it. The pixel column illustrates page organization without claiming a fitted MINI display.

24J.8 I2C OLED Device Tree shape

Linux’s solomon,ssd1306fb-i2c binding does not imply a matching U-Boot driver. Keep the two control trees and ownership stages distinct. The board command below directly obtains a generic I2C chip on a verified bus/address.

On MINI, use I2C1 via P4 pin 43 UART4_TXD (SCL), pin 42 UART4_RXD (SDA), and the reviewed supply/ground connections. Pin 41 is ENET1_RXER, not SCL; pin 44 is UART5_RXD/I2C2 SDA, not I2C1 SDA. Do not infer UART or bus pairs from adjacent header rows. MINI sheet 1 shows R42/R57 4.7 kOhm pull-ups to DCDC_3V3. Core sheet 6 and the upstream pin definitions map these pads to MX6UL_PAD_UART4_TX_DATA__I2C1_SCL and MX6UL_PAD_UART4_RX_DATA__I2C1_SDA. Disable UART4 on these pads, enable &i2c1, and supply its IOMUXC pinctrl group with the board’s reviewed pad settings. Account for the module’s own pull-ups rather than adding another pair automatically. Keep UART1/USB_TTL as the console.

Use i2c bus to map this hardware I2C1 to its U-Boot sequence, then set the command’s OLED_BUS accordingly. The 0 below is an example sequence, not an assertion that every migrated DT assigns I2C1 sequence zero. I2C2 is also routed to the RGB touch/camera connectors, so it is not an isolated spare bus on an accessorized MINI. Prefer the explicitly reviewed P4 route for this first module instead of probing an unknown shared bus.

The layout also labels P1 OLED/CAMERA. Sheet 2 routes P1 pin 1 to DCDC_3V3, pin 2 to ground, pin 4 to I2C2 SCL and pin 6 to I2C2 SDA. A documented OLED adapter can use those wires after checking the shared camera/touch bus and module address. This is an alternative to P4/I2C1, not a promise that a generic four-pin OLED plugs into P1 directly; the connector’s other pins carry camera signals. Select the corresponding I2C2 pinmux and actual U-Boot bus sequence if taking this route.

For a dedicated U-Boot generic child, explicitly describing u-boot,i2c-offset-len = <0> prevents register-offset insertion. Its chosen compatible/driver must be reviewed; do not attach this property to an unrelated chip or override a PMIC driver’s protocol. The command also sets and checks zero offset length because the chip may already be bound. Linux should receive its own supported display node and reset/power wiring.

24J.9 I2C OLED configs

Enable the actual bus and command support:

CONFIG_DM_I2C=y
CONFIG_SYS_I2C_MXC=y
CONFIG_CMD_I2C=y
CONFIG_DM_GPIO=y

BOARD_LATE_INIT is needed only if the integration uses that callback, not for the command itself. First inspect i2c bus, bus aliases/pinmux, supply, pull-ups, and reset wiring. Do not indiscriminately scan a shared PMIC bus. A reviewed known-address check may establish an ACK, not chip identity or successful display initialization.

24J.10 A tiny SSD1306 U-Boot command

This example covers only a verified 128 x 64 SSD1306 I2C module with the internal charge-pump profile described below. Before running it, the module must be powered and reset with its documented timing. Its segment/COM orientation, electrical settings, contrast, and power sequence must match its specification. Do not substitute a 128 x 32 or SH1106 module. The P4/I2C1 route above is documented MINI hardware; the particular module, address strap, reset and supply profile still need matching.

Create board/myorg/mx6ull_pa_mini/oled_ssd1306.c in your port. Change the bus/address constants only after mapping the actual controller and strap:

// SPDX-License-Identifier: GPL-2.0+
#include <command.h>
#include <dm.h>
#include <i2c.h>
#include <stdio.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/string.h>

#define OLED_BUS       0       /* Must match the verified U-Boot bus sequence. */
#define OLED_ADDR      0x3c    /* Must match the module's 7-bit address. */
#define OLED_WIDTH     128
#define OLED_PAGES     8
#define OLED_CHUNK     16

static int oled_packet(struct udevice *dev, u8 control,
                       const u8 *data, unsigned int len)
{
    u8 buf[OLED_CHUNK + 1];

    if (!len || len > OLED_CHUNK || !data)
        return -EINVAL;
    buf[0] = control;
    memcpy(buf + 1, data, len);
    return dm_i2c_write(dev, 0, buf, len + 1);
}

static int oled_commands(struct udevice *dev, const u8 *data, unsigned int len)
{
    return oled_packet(dev, 0x00, data, len);
}

static int oled_init(struct udevice *dev)
{
    static const struct {
        u8 bytes[2];
        u8 len;
    } init[] = {
        { { 0xae, 0 }, 1 },       /* Display off until RAM is cleared. */
        { { 0xd5, 0x80 }, 2 },    /* Module profile: clock. */
        { { 0xa8, 0x3f }, 2 },    /* 64-row multiplex. */
        { { 0xd3, 0x00 }, 2 },    /* Display offset. */
        { { 0x40, 0 }, 1 },       /* Start line. */
        { { 0x8d, 0x14 }, 2 },    /* Internal charge pump profile. */
        { { 0x20, 0x02 }, 2 },    /* Page addressing, matching drawing below. */
        { { 0xa1, 0 }, 1 },       /* Segment remap. */
        { { 0xc8, 0 }, 1 },       /* COM scan direction. */
        { { 0xda, 0x12 }, 2 },    /* 128x64 COM pin profile. */
        { { 0x81, 0x7f }, 2 },    /* Profile contrast, not a measured optimum. */
        { { 0xd9, 0xf1 }, 2 },    /* Charge-pump precharge profile. */
        { { 0xdb, 0x20 }, 2 },    /* Documented VCOMH encoding. */
        { { 0xa4, 0 }, 1 },       /* Display RAM, not all-pixels-on. */
        { { 0xa6, 0 }, 1 },       /* Normal polarity. */
        { { 0x2e, 0 }, 1 },       /* Scrolling disabled. */
    };
    unsigned int i;
    int ret;

    for (i = 0; i < ARRAY_SIZE(init); ++i) {
        ret = oled_commands(dev, init[i].bytes, init[i].len);
        if (ret)
            return ret;
    }
    return 0;
}

static int oled_draw(struct udevice *dev, int bar)
{
    u8 pixels[OLED_CHUNK];
    unsigned int page, col;
    int ret;

    for (page = 0; page < OLED_PAGES; ++page) {
        u8 position[] = { 0xb0 + page, 0x00, 0x10 };

        ret = oled_commands(dev, position, sizeof(position));
        if (ret)
            return ret;
        memset(pixels, bar && page < 2 ? 0xff : 0, sizeof(pixels));
        for (col = 0; col < OLED_WIDTH; col += OLED_CHUNK) {
            ret = oled_packet(dev, 0x40, pixels, sizeof(pixels));
            if (ret)
                return ret;
        }
    }
    return 0;
}

static int do_oled(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
    struct udevice *dev;
    const u8 on = 0xaf;
    int bar, ret;

    if (argc != 2)
        return CMD_RET_USAGE;
    if (!strcmp(argv[1], "clear"))
        bar = 0;
    else if (!strcmp(argv[1], "bar"))
        bar = 1;
    else
        return CMD_RET_USAGE;

    ret = i2c_get_chip_for_busnum(OLED_BUS, OLED_ADDR, 0, &dev);
    if (ret)
        goto fail;
    ret = i2c_set_chip_offset_len(dev, 0);
    if (ret)
        goto fail;
    ret = oled_init(dev);
    if (ret)
        goto fail;
    ret = oled_draw(dev, bar);
    if (ret)
        goto fail;
    ret = oled_commands(dev, &on, 1);
    if (ret)
        goto fail;
    return CMD_RET_SUCCESS;
fail:
    printf("OLED transfer failed on bus %d address 0x%02x: %d\n",
           OLED_BUS, OLED_ADDR, ret);
    return CMD_RET_FAILURE;
}

U_BOOT_CMD(oled, 2, 0, do_oled,
           "draw a checked SSD1306 module status pattern",
           "clear - initialize, clear RAM, then enable display\n"
           "oled bar - draw a 16-pixel-high band (not update progress)");

Each command and its argument stay in one bounded packet. Drawing uses page addressing (0x20,0x02) followed by the matching page/column commands. Each page contains eight 16-byte data packets. The first two pages form a 16-pixel band; this is a recognizable marker, not a percentage gauge. The entire RAM is written before display-on, avoiding stale pixels at startup. If any transfer fails, stop and return failure; partially changed pixels must not be interpreted as a valid result.

The command encodings were checked against Solomon Systech’s SSD1306 Rev 1.1 command tables and its charge-pump application note, available in this manufacturer document hosted by Focus LCDs. The document specifies page mode, control bytes, and the VCOMH 0x20 encoding; it does not qualify the supply/reset design of an unknown module.

Add the object to the existing board Makefile only for the selected optional feature, or for a dedicated example build:

obj-y += oled_ssd1306.o

Then build with the selected Linux Arm compiler as in Chapter 24F. On an approved matching module, oled clear and oled bar are the manual checks. oled typo or missing arguments must return usage before any bus access. There is no successful hardware log promised here. A host transfer fixture can verify bytes and failures; it cannot qualify OLED voltages or reset timing.

24J.11 Showing status automatically

Only after manual qualification, add a RAM-only optional wrapper to the existing normal A/B path. Use it only from an approved normal-boot console, not one stopped by a recovery or power veto:

pa-mini=> setenv show_oled 'oled bar'
pa-mini=> setenv normal_with_oled 'run show_oled; run boot_selected'
pa-mini=> setenv bootcmd 'run normal_with_oled'
pa-mini=> run normal_with_oled

If the RGB splash is also used, integrate both optional commands into one normal wrapper. Do not replace the port with an assumed distro_bootcmd, and do not blindly saveenv an experimental display hook. Retain the alternate rollback command and the recovery/power overrides. Optional display failure may be reported without blocking normal boot if the hardware is safe.

The last command tries Linux in this session. Resetting without saving reloads the earlier stored policy. A compiled board hook runs at a different time: review its interaction with the whole-environment bootcount save, as in 24G/H.

For a power fault, serial-only reporting is the default: initializing an optional display can draw exactly the current the policy is refusing. A rollback/recovery-specific symbol needs a defined renderer and qualified hook; oled bar alone does not distinguish those states. Do not call a static helper from another board source file without providing a proper interface and linking it deliberately.

24J.12 Which path should you choose?

Requirement

Implementation boundary

Full RGB logo

Chapter 24I’s verified video driver and trusted BMP path

SPI LCD with no upstream driver

Module-specific reset/init plus bounded transactions, then a real draw/flush implementation

SSD1306 marker on the exact profile

The board command above, after hardware qualification

Text, fonts, percentage progress

Additional renderer, clipping/bounds, real state source and transfer/error tests

Shared Linux display

Separate Linux driver/DT initialization and intentional handoff

Safety-critical indication

Defined indication semantics and independent failure behavior; not merely a colored shape

The first useful result is a small, explainable pattern with known bytes. Do not call it a working graphics stack or production status display before its missing layers have been built and tested.

24J.13 Pitfalls

  • Linux driver names used as U-Boot support evidence. Check this release’s tree.

  • SPI success treated as panel ACK. SPI has no automatic device ACK.

  • Byte count passed as bit count. dm_spi_xfer takes bits.

  • Native u16 pixels on a high-byte-first wire. Construct the actual bytes.

  • D/C or CS broken across a command/data pair. Inspect the whole transaction.

  • Extra I2C offset byte. SSD1306 requires its control byte first.

  • Horizontal mode mixed with page commands. Initialization and drawing must agree.

  • SH1106 or 128x32 treated as this module. Geometry and commands differ.

  • A display hook bypassing A/B or safety. Optional feedback must retain policy.

24J.14 Key Notes

  • The stock MINI has neither serial display, and v2026.04 lacks the named panel drivers used in these examples. A compatible string or working bus driver does not supply reset, initialization or rendering.

  • SPI command/data transfers depend on D/C and CS across the entire transaction. The bounded helper owns bus claim/release and length checks, but not panel timing or a whole-screen streaming engine.

  • dm_spi_xfer counts bits, while RGB565 wire order is a byte-level contract. Native little-endian pixel arrays do not automatically match high-byte-first panel modes.

  • SSD1306 I2C packets start with command/data control bytes, not register offsets. Zero offset length, page-mode initialization and page/column writes must agree for all 1024 pixel bytes.

  • The supplied OLED command covers only its documented 128 x 64 charge-pump profile. An ACK, similar module shape or SH1106 name does not establish that profile.

  • P4 bus routes share pads with UART functions, and P1/I2C2 shares accessories. Module voltage, pull-ups and separate GPIO ownership remain hardware contracts beyond byte-transaction correctness.

  • Optional indication retains serial diagnostics and boot/recovery/power precedence. Partial pixels after a transfer failure and a decorative bar are not verified status or committed update progress.

24J.15 Going deeper

  • Supplied MINI V2.2 schematic, sheets 1-3, and core sheets 5-6/8: P4 bus routes, existing GPIO owners and I2C pull-ups. The guide’s applicability table (pp. 7-8) excludes the stock MINI from its ALPHA I2C/SPI sensor labs.

  • v2026.04 i.MX6UL pin-function definitions: UART2-to-ECSPI3 and UART4-to-I2C1 alternate functions.

  • v2026.04 video drivers and SPI API.

  • I2C API and I2C uclass: offset insertion and errors.

  • Solomon Systech SSD1306 product documentation, plus the fitted module’s documented initialization/power specification.

  • The actual ST7735/ST7789/ILI9341 or SH1106 manufacturer’s controller manual, matched to the module rather than a generic internet initialization list.


End of Part III.

We can now separate image choice from acceptance, service entry from ROM recovery, and a display indication from the operation it describes. The next part follows the kernel after U-Boot hands it the selected image and DTB.

Previous: Chapter 24I: U-Boot display and boot screen

Next: Chapter 25: Building mainline Linux for i.MX6ULL