summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2026-08-14 16:29:07 -0600
committerTom Rini <trini@konsulko.com>2026-08-14 16:29:07 -0600
commit7581a12eb96c8b8825b65a9c597696cb28cb6155 (patch)
treeb96337791fe5dca9acd265ff565f067afe50746f
parent8841b7b292c74864acf4ed0bd8ce05839252c1f2 (diff)
parent817664148ebd584a55a4f482d198fe6ae595d079 (diff)
downloadu-boot-7581a12eb96c8b8825b65a9c597696cb28cb6155.tar.gz
u-boot-7581a12eb96c8b8825b65a9c597696cb28cb6155.zip
Merge tag 'u-boot-imx-next-20260814' of https://git.u-boot-project.org/u-boot/custodians/u-boot-imx into next
CI: https://git.u-boot-project.org/u-boot/custodians/u-boot-imx/-/pipelines/990 - Several fixes for long-standing Vybrid issues. - Improvements for imx6dl-sielaff. - ADD SPL Quick Boot support for several Toradex boards.
-rw-r--r--arch/arm/include/asm/mach-imx/sys_proto.h1
-rw-r--r--arch/arm/mach-imx/hab.c12
-rw-r--r--arch/arm/mach-imx/init.c75
-rw-r--r--arch/arm/mach-imx/spl.c7
-rw-r--r--board/sielaff/imx6dl-sielaff/imx6dl-sielaff.c30
-rw-r--r--board/sielaff/imx6dl-sielaff/spl.c22
-rw-r--r--board/toradex/apalis-imx8/apalis-imx8.c34
-rw-r--r--board/toradex/aquila-imx95/spl.c4
-rw-r--r--board/toradex/common/Kconfig1
-rw-r--r--board/toradex/smarc-imx95/spl.c4
-rw-r--r--board/toradex/verdin-imx95/spl.c4
-rw-r--r--configs/aquila-imx95_defconfig2
-rw-r--r--configs/colibri_vf_defconfig4
-rw-r--r--configs/imx6dl_sielaff_defconfig2
-rw-r--r--configs/toradex-smarc-imx8mp_defconfig2
-rw-r--r--configs/toradex-smarc-imx95_defconfig2
-rw-r--r--configs/verdin-imx95_defconfig2
-rw-r--r--doc/board/toradex/colibri_vf.rst66
-rw-r--r--doc/board/toradex/index.rst1
-rw-r--r--drivers/gpio/vybrid_gpio.c8
-rw-r--r--drivers/serial/serial_lpuart.c9
21 files changed, 245 insertions, 47 deletions
diff --git a/arch/arm/include/asm/mach-imx/sys_proto.h b/arch/arm/include/asm/mach-imx/sys_proto.h
index d25c08f8fe7..06b5636c7a0 100644
--- a/arch/arm/include/asm/mach-imx/sys_proto.h
+++ b/arch/arm/include/asm/mach-imx/sys_proto.h
@@ -159,6 +159,7 @@ enum imx6_bmode {
};
u32 imx6_src_get_boot_mode(void);
+bool imx6_is_ecspi_recovery_boot(void);
void gpr_init(void);
#endif /* CONFIG_MX6 */
diff --git a/arch/arm/mach-imx/hab.c b/arch/arm/mach-imx/hab.c
index ab5861578e5..f92f77670a8 100644
--- a/arch/arm/mach-imx/hab.c
+++ b/arch/arm/mach-imx/hab.c
@@ -541,7 +541,19 @@ static int get_hab_status_m4(void)
record_len = get_record_len(rec);
+ if (!record_len ||
+ offset + record_len > HAB_M4_PERSISTENT_BYTES) {
+ puts("\nERROR: Invalid HAB record length\n");
+ return 1;
+ }
+
if (rec->tag == HAB_TAG_EVT) {
+ if (record_len > sizeof(event_data)) {
+ printf("\nERROR: HAB event %d too large (%zu bytes)\n",
+ index + 1, record_len);
+ return 1;
+ }
+
memcpy(&event_data, rec, record_len);
puts("\n");
printf("--------- HAB Event %d -----------------\n",
diff --git a/arch/arm/mach-imx/init.c b/arch/arm/mach-imx/init.c
index ce3eb4b0b8a..4193b350e03 100644
--- a/arch/arm/mach-imx/init.c
+++ b/arch/arm/mach-imx/init.c
@@ -137,4 +137,79 @@ u32 imx6_src_get_boot_mode(void)
else
return readl(&src_base->sbmr1);
}
+
+/*
+ * The boot ROM records what it did in an event log buffer in OCRAM. The
+ * address of that buffer is stored at a fixed, SoC specific location inside
+ * the ROM, see AN12853 "i.MX ROMs Log Events". i.MX6 uses the version 0 log
+ * format, where an entry consists of a 32-bit word holding a 24-bit event
+ * ID, optionally followed by up to three parameter words.
+ */
+#define IMX6_ROM_LOG_ID_MASK GENMASK(23, 0)
+#define IMX6_ROM_LOG_MAX_ENTRIES 128
+
+static const u32 *imx6_get_rom_log(void)
+{
+ uintptr_t log;
+ ulong addr;
+
+ if (is_mx6dq() || is_mx6dqp() || is_mx6sl())
+ addr = 0xd4;
+ else if (is_mx6sdl())
+ addr = 0xd8;
+ else if (is_mx6sx() || is_mx6sll() || is_mx6ul() || is_mx6ull())
+ addr = 0x1e0;
+ else
+ return NULL;
+
+ log = readl(addr);
+
+ /* The log buffer lives in OCRAM, ignore an invalid pointer */
+ if (log < IRAM_BASE_ADDR || log >= IRAM_BASE_ADDR + IRAM_SIZE ||
+ log & 0x3)
+ return NULL;
+
+ return (const u32 *)log;
+}
+
+/*
+ * If BOOT_CFG4[6] is fused, the boot ROM does not fall back to the serial
+ * downloader right away when the primary boot device fails, but first tries
+ * a recovery boot from the serial ROM selected by BOOT_CFG4[2:0]. Neither
+ * SRC_SBMR1 nor SRC_SBMR2 reflect that this happened, so ask the ROM event
+ * log instead.
+ */
+bool imx6_is_ecspi_recovery_boot(void)
+{
+ const u32 *log = imx6_get_rom_log();
+ u32 event_id;
+ int i;
+
+ if (!log)
+ return false;
+
+ for (i = 0; i < IMX6_ROM_LOG_MAX_ENTRIES; i++) {
+ event_id = log[i] & IMX6_ROM_LOG_ID_MASK;
+
+ switch (event_id) {
+ case 0x000000: /* End of list */
+ return false;
+ /* Recovery boot from ECSPI NOR device */
+ case 0x061004:
+ return true;
+ /* Log entries with 1 parameter, skip 1 */
+ case 0x080000: /* Start to read data from boot device */
+ case 0x090000: /* Image authentication result */
+ case 0x0a0000: /* Start to execute the plugin program */
+ case 0x0b0000: /* Jump to the boot image soon */
+ case 0x0d0000: /* Jump to the SDP boot image soon */
+ i += 1;
+ continue;
+ default:
+ continue;
+ }
+ }
+
+ return false;
+}
#endif
diff --git a/arch/arm/mach-imx/spl.c b/arch/arm/mach-imx/spl.c
index 1029c1e4e85..fbe5172d385 100644
--- a/arch/arm/mach-imx/spl.c
+++ b/arch/arm/mach-imx/spl.c
@@ -93,6 +93,13 @@ u32 spl_boot_device(void)
if (is_usbotg_phy_active())
return BOOT_DEVICE_BOARD;
+ /*
+ * Likewise the boot ROM may have done a recovery boot from a serial
+ * ROM on ECSPI after the primary boot device failed.
+ */
+ if (imx6_is_ecspi_recovery_boot())
+ return BOOT_DEVICE_SPI;
+
/* BOOT_CFG1[7:4] - see IMX6DQRM Table 8-8 */
switch ((reg & IMX6_BMODE_MASK) >> IMX6_BMODE_SHIFT) {
/* EIM: See 8.5.1, Table 8-9 */
diff --git a/board/sielaff/imx6dl-sielaff/imx6dl-sielaff.c b/board/sielaff/imx6dl-sielaff/imx6dl-sielaff.c
index 4da084ed91c..f2c206cfeb0 100644
--- a/board/sielaff/imx6dl-sielaff/imx6dl-sielaff.c
+++ b/board/sielaff/imx6dl-sielaff/imx6dl-sielaff.c
@@ -9,6 +9,7 @@
#include <asm/arch/crm_regs.h>
#include <asm/arch/mx6-pins.h>
#include <asm/io.h>
+#include <env_internal.h>
#include <init.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -109,3 +110,32 @@ int board_init(void)
return 0;
}
+
+/*
+ * Keep the environment on the device we were booted from. The boot fuses
+ * use the SD card as primary boot device and the SPI NOR as the ECSPI
+ * recovery device, so both are valid places for the environment to live.
+ */
+enum env_location env_get_location(enum env_operation op, int prio)
+{
+ u32 bmode;
+
+ if (prio > 0)
+ return ENVL_UNKNOWN;
+
+ if (imx6_is_ecspi_recovery_boot())
+ return ENVL_SPI_FLASH;
+
+ bmode = (imx6_src_get_boot_mode() & IMX6_BMODE_MASK) >>
+ IMX6_BMODE_SHIFT;
+
+ switch (bmode) {
+ case IMX6_BMODE_SD:
+ case IMX6_BMODE_ESD:
+ case IMX6_BMODE_MMC:
+ case IMX6_BMODE_EMMC:
+ return ENVL_MMC;
+ default:
+ return ENVL_SPI_FLASH;
+ }
+}
diff --git a/board/sielaff/imx6dl-sielaff/spl.c b/board/sielaff/imx6dl-sielaff/spl.c
index 6815952c0fb..ae36ff5712c 100644
--- a/board/sielaff/imx6dl-sielaff/spl.c
+++ b/board/sielaff/imx6dl-sielaff/spl.c
@@ -249,25 +249,3 @@ void board_init_f(ulong dummy)
/* load/boot image from boot device */
board_init_r(NULL, 0);
}
-
-void board_boot_order(u32 *spl_boot_list)
-{
- u32 bootdev = spl_boot_device();
-
- /*
- * The default boot fuse settings use the SD card (MMC1) as primary
- * boot device, but allow SPI NOR as a fallback boot device.
- * We can't detect the fallback case and spl_boot_device() will return
- * BOOT_DEVICE_MMC1 despite the actual boot device being SPI NOR.
- * Therefore we try to load U-Boot proper vom SPI NOR after loading
- * from MMC has failed.
- */
- spl_boot_list[0] = bootdev;
-
- switch (bootdev) {
- case BOOT_DEVICE_MMC1:
- case BOOT_DEVICE_MMC2:
- spl_boot_list[1] = BOOT_DEVICE_SPI;
- break;
- }
-}
diff --git a/board/toradex/apalis-imx8/apalis-imx8.c b/board/toradex/apalis-imx8/apalis-imx8.c
index b915673d9e3..ec30ceb3a68 100644
--- a/board/toradex/apalis-imx8/apalis-imx8.c
+++ b/board/toradex/apalis-imx8/apalis-imx8.c
@@ -120,20 +120,26 @@ static void get_tdx_user_fuse(struct tdx_user_fuses *tdxuserfuse)
tdxuserfuse->ramid = fuse_block & GENMASK(3, 0);
}
-void board_mem_get_layout(u64 *phys_sdram_1_start,
- u64 *phys_sdram_1_size,
- u64 *phys_sdram_2_start,
- u64 *phys_sdram_2_size)
+static bool is_imx8qp(void)
{
- u32 is_quadplus = 0, val = 0;
- struct tdx_user_fuses tdxramfuses;
+ u32 val = 0;
int scierr = sc_misc_otp_fuse_read(-1, 6, &val);
if (!scierr) {
/* QP has one A72 core disabled */
- is_quadplus = ((val >> 4) & 0x3) != 0x0;
+ return ((val >> 4) & 0x3) != 0x0;
}
+ return false;
+}
+
+void board_mem_get_layout(u64 *phys_sdram_1_start,
+ u64 *phys_sdram_1_size,
+ u64 *phys_sdram_2_start,
+ u64 *phys_sdram_2_size)
+{
+ struct tdx_user_fuses tdxramfuses;
+
get_tdx_user_fuse(&tdxramfuses);
*phys_sdram_1_start = PHYS_SDRAM_1;
@@ -154,7 +160,7 @@ void board_mem_get_layout(u64 *phys_sdram_1_start,
*phys_sdram_2_size = SZ_4G + SZ_2G;
break;
default:
- if (is_quadplus)
+ if (is_imx8qp())
/* Our QP based SKUs only have 2 GB RAM (PHYS_SDRAM_1_SIZE) */
*phys_sdram_2_size = 0x0UL;
else
@@ -245,18 +251,10 @@ static void select_dt_from_module_version(void)
else
env_set("variant", "-v1.1");
- switch (tdx_hw_tag.prodid) {
- /* Select Apalis iMX8QP device trees */
- case APALIS_IMX8QP_WIFI_BT:
- case APALIS_IMX8QP:
- case APALIS_IMX8QP_WIFI_BT_1300MHZ:
- case APALIS_IMX8QP_1300MHZ:
+ if (is_imx8qp())
env_set("soc", "imx8qp");
- break;
- default:
+ else
env_set("soc", "imx8qm");
- break;
- }
}
static int do_select_dt_from_module_version(struct cmd_tbl *cmdtp, int flag,
diff --git a/board/toradex/aquila-imx95/spl.c b/board/toradex/aquila-imx95/spl.c
index 9f501c11c1d..93e76be6145 100644
--- a/board/toradex/aquila-imx95/spl.c
+++ b/board/toradex/aquila-imx95/spl.c
@@ -6,6 +6,7 @@
#include <asm/arch/sys_proto.h>
#include <asm/mach-imx/boot_mode.h>
#include <asm/mach-imx/ele_api.h>
+#include <asm/mach-imx/qb.h>
#include <asm/sections.h>
#include <asm/global_data.h>
#include <clk.h>
@@ -40,6 +41,9 @@ void spl_board_init(void)
ret = ele_start_rng();
if (ret)
printf("Fail to start RNG: %d\n", ret);
+
+ if (IS_ENABLED(CONFIG_SPL_IMX_QB))
+ spl_imx_qb_save();
}
void board_init_f(ulong dummy)
diff --git a/board/toradex/common/Kconfig b/board/toradex/common/Kconfig
index b85893ab44e..05f8341e4c3 100644
--- a/board/toradex/common/Kconfig
+++ b/board/toradex/common/Kconfig
@@ -3,6 +3,7 @@
menuconfig TDX_CFG_BLOCK
bool "Enable Toradex config block support"
+ select EVENT
select OF_BOARD_SETUP
select SYSINFO
help
diff --git a/board/toradex/smarc-imx95/spl.c b/board/toradex/smarc-imx95/spl.c
index ce8da89410b..aebb4a2f0b6 100644
--- a/board/toradex/smarc-imx95/spl.c
+++ b/board/toradex/smarc-imx95/spl.c
@@ -6,6 +6,7 @@
#include <asm/arch/sys_proto.h>
#include <asm/mach-imx/boot_mode.h>
#include <asm/mach-imx/ele_api.h>
+#include <asm/mach-imx/qb.h>
#include <asm/sections.h>
#include <asm/global_data.h>
#include <clk.h>
@@ -81,6 +82,9 @@ void spl_board_init(void)
ret = ele_start_rng();
if (ret)
printf("Fail to start RNG: %d\n", ret);
+
+ if (IS_ENABLED(CONFIG_SPL_IMX_QB))
+ spl_imx_qb_save();
}
void board_init_f(ulong dummy)
diff --git a/board/toradex/verdin-imx95/spl.c b/board/toradex/verdin-imx95/spl.c
index 9f501c11c1d..93e76be6145 100644
--- a/board/toradex/verdin-imx95/spl.c
+++ b/board/toradex/verdin-imx95/spl.c
@@ -6,6 +6,7 @@
#include <asm/arch/sys_proto.h>
#include <asm/mach-imx/boot_mode.h>
#include <asm/mach-imx/ele_api.h>
+#include <asm/mach-imx/qb.h>
#include <asm/sections.h>
#include <asm/global_data.h>
#include <clk.h>
@@ -40,6 +41,9 @@ void spl_board_init(void)
ret = ele_start_rng();
if (ret)
printf("Fail to start RNG: %d\n", ret);
+
+ if (IS_ENABLED(CONFIG_SPL_IMX_QB))
+ spl_imx_qb_save();
}
void board_init_f(ulong dummy)
diff --git a/configs/aquila-imx95_defconfig b/configs/aquila-imx95_defconfig
index bb3d475ef4d..ee66cebfa4f 100644
--- a/configs/aquila-imx95_defconfig
+++ b/configs/aquila-imx95_defconfig
@@ -26,6 +26,7 @@ CONFIG_SYS_LOAD_ADDR=0x90400000
CONFIG_WATCHDOG_TIMEOUT_MSECS=30000
CONFIG_SPL=y
CONFIG_SPL_RECOVER_DATA_SECTION=y
+CONFIG_SPL_IMX_QB=y
CONFIG_PCI=y
CONFIG_SYS_MEMTEST_START=0x90000000
CONFIG_SYS_MEMTEST_END=0xA0000000
@@ -59,6 +60,7 @@ CONFIG_SPL_SYS_MMCSD_RAW_MODE=y
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x1040
CONFIG_SPL_I2C=y
CONFIG_SPL_DM_MAILBOX=y
+CONFIG_SPL_MMC_WRITE=y
CONFIG_SPL_POWER_DOMAIN=y
CONFIG_SPL_THERMAL=y
CONFIG_SPL_WATCHDOG=y
diff --git a/configs/colibri_vf_defconfig b/configs/colibri_vf_defconfig
index 5145e947e88..beb64189d5c 100644
--- a/configs/colibri_vf_defconfig
+++ b/configs/colibri_vf_defconfig
@@ -2,7 +2,7 @@ CONFIG_ARM=y
CONFIG_SKIP_LOWLEVEL_INIT=y
CONFIG_SYS_THUMB_BUILD=y
CONFIG_ARCH_VF610=y
-CONFIG_TEXT_BASE=0x3f401000
+CONFIG_TEXT_BASE=0x3f408000
CONFIG_SYS_MALLOC_LEN=0x0220000
CONFIG_NR_DRAM_BANKS=1
CONFIG_ENV_SIZE=0x20000
@@ -16,7 +16,7 @@ CONFIG_SYS_MEMTEST_START=0x80010000
CONFIG_SYS_MEMTEST_END=0x87c00000
CONFIG_ENV_VARS_UBOOT_CONFIG=y
CONFIG_HAS_BOARD_SIZE_LIMIT=y
-CONFIG_BOARD_SIZE_LIMIT=520192
+CONFIG_BOARD_SIZE_LIMIT=491520
# CONFIG_EFI_LOADER is not set
CONFIG_BOOTDELAY=1
CONFIG_FDT_FIXUP_PARTITIONS=y
diff --git a/configs/imx6dl_sielaff_defconfig b/configs/imx6dl_sielaff_defconfig
index bfa4c4aa1d8..615c2935844 100644
--- a/configs/imx6dl_sielaff_defconfig
+++ b/configs/imx6dl_sielaff_defconfig
@@ -61,8 +61,10 @@ CONFIG_EFI_PARTITION=y
# CONFIG_SPL_EFI_PARTITION is not set
CONFIG_OF_CONTROL=y
CONFIG_OF_UPSTREAM=y
+CONFIG_ENV_IS_IN_MMC=y
CONFIG_ENV_IS_IN_SPI_FLASH=y
CONFIG_ENV_RELOC_GD_ENV_ADDR=y
+CONFIG_ENV_MMC_DEVICE_INDEX=2
CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
CONFIG_BOUNCE_BUFFER=y
CONFIG_USB_FUNCTION_FASTBOOT=y
diff --git a/configs/toradex-smarc-imx8mp_defconfig b/configs/toradex-smarc-imx8mp_defconfig
index 7301d7a4ace..83647284ae8 100644
--- a/configs/toradex-smarc-imx8mp_defconfig
+++ b/configs/toradex-smarc-imx8mp_defconfig
@@ -56,6 +56,8 @@ CONFIG_SPL_SYS_MALLOC=y
CONFIG_SPL_HAS_CUSTOM_MALLOC_START=y
CONFIG_SPL_CUSTOM_SYS_MALLOC_ADDR=0x42200000
CONFIG_SPL_SYS_MALLOC_SIZE=0x80000
+CONFIG_SPL_SYS_MMCSD_RAW_MODE=y
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x300
CONFIG_SPL_I2C=y
CONFIG_SPL_POWER=y
CONFIG_SPL_WATCHDOG=y
diff --git a/configs/toradex-smarc-imx95_defconfig b/configs/toradex-smarc-imx95_defconfig
index 9abadb0ed1a..b76d1fb3cd7 100644
--- a/configs/toradex-smarc-imx95_defconfig
+++ b/configs/toradex-smarc-imx95_defconfig
@@ -26,6 +26,7 @@ CONFIG_SYS_LOAD_ADDR=0x90400000
CONFIG_WATCHDOG_TIMEOUT_MSECS=30000
CONFIG_SPL=y
CONFIG_SPL_RECOVER_DATA_SECTION=y
+CONFIG_SPL_IMX_QB=y
CONFIG_PCI=y
CONFIG_SYS_MEMTEST_START=0x90000000
CONFIG_SYS_MEMTEST_END=0xA0000000
@@ -59,6 +60,7 @@ CONFIG_SPL_SYS_MMCSD_RAW_MODE=y
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x1040
CONFIG_SPL_I2C=y
CONFIG_SPL_DM_MAILBOX=y
+CONFIG_SPL_MMC_WRITE=y
CONFIG_SPL_POWER_DOMAIN=y
CONFIG_SPL_THERMAL=y
CONFIG_SPL_WATCHDOG=y
diff --git a/configs/verdin-imx95_defconfig b/configs/verdin-imx95_defconfig
index daf41a8b830..d7076231bbe 100644
--- a/configs/verdin-imx95_defconfig
+++ b/configs/verdin-imx95_defconfig
@@ -26,6 +26,7 @@ CONFIG_SYS_LOAD_ADDR=0x90400000
CONFIG_WATCHDOG_TIMEOUT_MSECS=30000
CONFIG_SPL=y
CONFIG_SPL_RECOVER_DATA_SECTION=y
+CONFIG_SPL_IMX_QB=y
CONFIG_PCI=y
CONFIG_SYS_MEMTEST_START=0x90000000
CONFIG_SYS_MEMTEST_END=0xA0000000
@@ -60,6 +61,7 @@ CONFIG_SPL_SYS_MMCSD_RAW_MODE=y
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x1040
CONFIG_SPL_I2C=y
CONFIG_SPL_DM_MAILBOX=y
+CONFIG_SPL_MMC_WRITE=y
CONFIG_SPL_POWER_DOMAIN=y
CONFIG_SPL_THERMAL=y
CONFIG_SPL_WATCHDOG=y
diff --git a/doc/board/toradex/colibri_vf.rst b/doc/board/toradex/colibri_vf.rst
new file mode 100644
index 00000000000..f9c81d70214
--- /dev/null
+++ b/doc/board/toradex/colibri_vf.rst
@@ -0,0 +1,66 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+.. sectionauthor:: Mehmet Fide <mehmet.fide@screeningeagle.com>
+
+Colibri VF50/VF61 Modules
+=========================
+
+- SoM: https://www.toradex.com/computer-on-modules/colibri-arm-family/nxp-vybrid-vf5xx-vf6xx
+- Carrier boards: https://www.toradex.com/products/carrier-board/colibri-evaluation-board
+ and https://www.toradex.com/products/carrier-board/iris-carrier-board
+
+Quick Start
+-----------
+
+- Build U-Boot
+- Flash to NAND from a running U-Boot
+- Flash to NAND over recovery mode
+- Modules still carrying the WinCE bootloader
+
+Build U-Boot
+------------
+
+.. code-block:: console
+
+ $ export CROSS_COMPILE=arm-linux-gnueabi-
+ $ make colibri_vf_defconfig
+ $ make
+
+This produces ``u-boot.imx``, the image with the IVT for the Vybrid
+BootROM, ready to be written to the ``u-boot`` NAND partition.
+
+Flash to NAND from a running U-Boot
+-----------------------------------
+
+Load the image over TFTP or from a FAT formatted SD card and use the
+``update_uboot`` script from the default environment:
+
+.. code-block:: none
+
+ Colibri VFxx # fatload mmc 0:1 ${loadaddr} u-boot.imx
+ Colibri VFxx # run update_uboot
+ Colibri VFxx # reset
+
+Flash to NAND over recovery mode
+--------------------------------
+
+With nothing bootable in NAND, the Vybrid BootROM falls back to the
+serial downloader on the USB client port. The `imx_usb_loader
+<https://github.com/boundarydevices/imx_usb_loader>`_ tool can push
+``u-boot.imx`` straight into OCRAM and run it:
+
+.. code-block:: console
+
+ $ imx_usb u-boot.imx
+
+From the running U-Boot, flash NAND as in the previous section.
+
+Modules still carrying the WinCE bootloader
+-------------------------------------------
+
+Modules that were shipped with the WinCE-era Toradex bootloader (eBoot)
+offer a ``flashloader`` command that writes a U-Boot image to NAND:
+
+.. code-block:: none
+
+ > flashloader u-boot.imx
+ > reboot
diff --git a/doc/board/toradex/index.rst b/doc/board/toradex/index.rst
index c5955ea1ad8..10af3a5b758 100644
--- a/doc/board/toradex/index.rst
+++ b/doc/board/toradex/index.rst
@@ -11,6 +11,7 @@ Toradex
aquila-imx95
colibri_imx7
colibri-imx8x
+ colibri_vf
smarc-imx8mp
smarc-imx95
verdin-am62
diff --git a/drivers/gpio/vybrid_gpio.c b/drivers/gpio/vybrid_gpio.c
index 5b4bba96da7..3d2e16e8ef3 100644
--- a/drivers/gpio/vybrid_gpio.c
+++ b/drivers/gpio/vybrid_gpio.c
@@ -109,7 +109,13 @@ static int vybrid_gpio_odata_to_plat(struct udevice *dev)
struct vybrid_gpio_plat *plat = dev_get_plat(dev);
fdt_addr_t base_addr;
- base_addr = dev_read_addr(dev);
+ /*
+ * The first reg range is the PORT block (pin control), the second one
+ * the GPIO block this driver reads and writes.
+ */
+ base_addr = dev_read_addr_index(dev, 1);
+ if (base_addr == FDT_ADDR_T_NONE)
+ base_addr = dev_read_addr(dev);
if (base_addr == FDT_ADDR_T_NONE)
return -EINVAL;
diff --git a/drivers/serial/serial_lpuart.c b/drivers/serial/serial_lpuart.c
index 917445e1ee2..dccd0974150 100644
--- a/drivers/serial/serial_lpuart.c
+++ b/drivers/serial/serial_lpuart.c
@@ -194,10 +194,11 @@ static int _lpuart_serial_tstc(struct lpuart_serial_plat *plat)
{
struct lpuart_fsl *base = plat->reg;
- if (__raw_readb(&base->urcfifo) == 0)
- return 0;
-
- return 1;
+ /*
+ * The receive FIFO counter stays at zero because _lpuart_serial_init()
+ * disables the FIFO, so ask the status register, the way getc() does.
+ */
+ return __raw_readb(&base->us1) & (US1_RDRF | US1_OR) ? 1 : 0;
}
/*