Colibri VF50/VF61 on the current BSP: mainline U-Boot v2026.07 and Linux 6.18 LTS

Toradex no longer supports the Vybrid Colibris. BSP 7.7.0 ships no VF machine and no VF kernel or bootloader recipe. Because of CRA obligations the software has to stay maintained rather than frozen.

We put them back on current sources with a small layer that drops into the latest Toradex BSP:

It adds colibri-vf50 and colibri-vf61 with mainline U-Boot v2026.07 and Linux 6.18.44 LTS. It also carries Iris carrier device trees, since mainline never had any for Vybrid, SODIMM gpio-line-names, and an SD card update package, because the Easy Installer never covered these modules. Every image ships an SPDX bill of materials, so you can scan it for current CVEs.

Build:


repo init -u https://git.toradex.com/toradex-manifest.git -b refs/tags/7.7.0 -m tdxref/default.xml

repo sync -j8 -c

git clone https://github.com/mfide/meta-toradex-colibri-vf.git layers/meta-toradex-colibri-vf

. export

Add the layer to conf/bblayers.conf, then:


DISTRO=tdx-xwayland-upstream MACHINE=colibri-vf50 bitbake tdx-reference-minimal-image

Unpack the resulting sdcard-*.tar.xz onto a FAT card, then in U-Boot: run setupdate, run update, reset. There’s a prebuilt package attached to the release if you’d rather not build one yourself.

Tested on a VF50 on an Iris carrier: Ethernet, USB host, wifi (AR9271 on ath9k_htc), microSD, all three UARTs, I2C with the carrier RTC, SPI, the RS232 transceiver hogs, NAND and UBIFS. The full boot log is here:

The work turned up six small fixes, three in U-Boot and three in the kernel. GPIO output and console input were both broken upstream on vf610, which was a surprise. All of them went to the respective lists.

VF61 builds but has never run on hardware. If anyone has one on an Iris, I’d be glad to hear how it goes.

Sharing in case it’s useful to anyone else in the same position.

Best regards

Hi, I’m the Toradex AI Assistant.

I might make mistakes or occasionally get you wrong. Our support team will step in if needed.


Thank you for sharing this community contribution for bringing Colibri VF50/VF61 modules to mainline U-Boot and Linux 6.18 LTS on BSP 7.7.0!

This is a valuable resource for users who need to maintain Vybrid-based modules beyond official support, particularly given CRA compliance requirements.

Official Toradex Position on Vybrid Support

As confirmed in the available documentation, Toradex does not plan to support Colibri VF50/VF61 on BSP 7(1). The latest BSP that officially supported Vybrid-based modules was BSP 2(1).

For users requiring ongoing support, the recommended approaches are(1):

  1. Upgrade to newer modules in the Colibri family or migrate to the Verdin family for better long-term support
  2. Engage Toradex partners who can provide custom BSP porting services

Community Layer Acknowledgment

Your meta-toradex-colibri-vf layer appears to address a real need for:

  • Maintaining software rather than freezing it (CRA compliance)
  • Providing mainline U-Boot v2026.07 and Linux 6.18.44 LTS
  • Including SPDX bill of materials for CVE scanning
  • Supporting both VF50 and VF61 variants

The comprehensive testing you’ve documented (Ethernet, USB, WiFi, SD, UARTs, I2C, SPI, NAND/UBIFS) and upstream fixes contributed are commendable.

Important Notes for Users

  • This is a community-maintained layer, not officially supported by Toradex
  • Users should evaluate compatibility with their specific requirements
  • Standard Toradex support channels may not cover issues arising from this layer

Your contribution provides a path forward for existing VF50/VF61 deployments that require maintained software. Thank you for sharing this with the community.

Best regards,
Toradex AI Assistant.


Did you like my answer? :+1: :-1:

If I answered your question, please tick the “Solution” checkbox.

For follow-up questions to me, please use @ToradexAI in your post.

Hello @Fide

thank you very much for the contribution!
also the AI has sumarized very well Toradex’s position regarding to this topic
let us know if you have questions or further information you would like to share.

Thank you once again.
we wish you a great day
best,

Thanks for missing cache geometry. I wonder, will it improve VF performance minimally on not? Looks like imx7 and imx6ull as well have it missing. I guess older kernels would use this information as well, but no one provided?

Do you mean it doesn’t boot? What doesn’t boot, u-boot, kernel? Perhaps it is related to VF unsupported NAND oob size. VF50 comes with 128MiB NAND with 64 byte oob. VF61 comes with 96? bytes oob. Older kernel driver hardcoded oob<=64 worked differently. Now this <=64 limit attempt in probe() doesn’t work, since actual oob is communicated to MTD driver after flash chip is detected.

Hi Edward,

On the cache geometry: no measurable performance change is expected. Those properties do not configure the hardware, the caches were already enabled and set up before Linux. what they fix is what cacheinfo reports under /sys/devices/system/cpu/*/cache and the missing-property warnings. And since it is device tree data, any kernel version that parses it benefits the same way. You are right that imx7/imx6ull have the same gap. the same kind of one-line dts additions would cover them.

On the VF61: “never run on hardware” just means I have not tested on a VF61 myself yet, nothing is known to be broken. I could probably dig one out of some deep box at the office if I searched, and Francesco has kindly offered off-list to provide one. As soon as a module lands here I will run the same test round on it. I fully expect it to just work, but until then it stays listed as untested.

Your OOB point was worth checking though. In current U-Boot and Linux the vf610_nfc (NAND Flash Controller) driver applies its OOB handling after chip detection (attach_chip in Linux), so a larger spare area is not rejected: the controller limit is writesize + oobsize <= 2296 bytes, and anything above 64 bytes of OOB simply gets clamped to 64 (“only 64 byte ECC layouts known”). So a 2K+128 or 2K+224 chip should probe fine. Whether that clamped layout lines up end to end on a real VF61 (U-Boot writing, Linux reading, UBI, bad block table) is exactly what the hardware test will confirm.

As I understand it, cache geometry has benefits in some cases, like flushing just single row instead of flushing whole cache, etc. It should give some performance improvements, though perhaps hardly noticeable. Without improvements id doesn’t make a lot of sense bothering providing this info in DT.

At least older u-boot and kernel ignored anything above 64 bytes OOB. Perhaps new kernel will work, but I guess it won’t read old kernel/u-boot formatted partition. At least is was something like that when I tried newer kernel quite long ago, I had to patch it to be compatible and working on VF61.

I guess it won’t read old kernel/u-boot formatted partition.

We hit that class in production, in the opposite direction: the new kernel writing what the old one cannot read. Our devices must up/downgrade between 4.4 and 6.12 on the same NAND, and two small changes made that work:

  1. 6.12 auto-formats fresh UBIFS volumes as on-flash v5, which 4.4 refuses. We default ubifs_default_version to 4 (one-line patch).
  2. We keep zstd out of the UBIFS config so 6.12 never writes nodes 4.4 cannot decompress.

Both directions are tested. The raw NAND/ECC layout itself never changed on the 64-byte-OOB VF50, so that layer was never the problem for us.

Regards,
Fide.

Had moment to try unpatched kernel botting from NFS:

[    0.601805] Bad block table found at page 262080, version 0x01
[    0.608337] Bad block table found at page 262016, version 0x01
[    0.614464] nand_bbt: ECC error in BBT at 0x00001ffe0005
[    0.620033] nand_bbt: ECC error in BBT at 0x00001ffc0005

^^^ kernel was unable to read former bad block table, kernel's trying to recreate it:

[    0.625418] Scanning device for bad blocks
[    0.645584] Bad eraseblock 158 at 0x0000013c0000
[    0.941525] Bad eraseblock 3040 at 0x000017c00000
[    1.010477] Bad eraseblock 3676 at 0x00001cb80000
[    1.030436] Bad eraseblock 3827 at 0x00001de60000
[    1.039603] Bad eraseblock 3871 at 0x00001e3e0000
[    1.045144] Bad eraseblock 3879 at 0x00001e4e0000
[    1.057730] Bad eraseblock 3957 at 0x00001eea0000
[    1.077674] Bad block table written to 0x00001ffe0000, version 0x01
[    1.085144] Bad block table written to 0x00001ffc0000, version 0x01

as well zilion of UBI read errors past UBI MTD attach, like this

[    1.620384] ubi0: attaching mtd3
[    1.624624] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 64 bytes from PEB 0:0, read only 64 bytes, retry
[    1.636719] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 64 bytes from PEB 0:0, read only 64 bytes, retry
[    1.648187] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 64 bytes from PEB 0:0, read only 64 bytes, retry
[    1.659643] ubi0 error: ubi_io_read: error -74 (ECC error) while reading 64 bytes from PEB 0:0, read 64 bytes
[    1.669676] CPU: 0 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.18.20 #17 VOLUNTARY
[    1.677403] Hardware name: Freescale Vybrid VF5xx/VF6xx (Device Tree)
[    1.683885] Call trace:
[    1.683916]  unwind_backtrace from show_stack+0xb/0xc
[    1.691594]  show_stack from dump_stack_lvl+0x23/0x2a
[    1.696711]  dump_stack_lvl from ubi_io_read+0x105/0x280
[    1.702086]  ubi_io_read from ubi_io_read_ec_hdr+0x45/0x218
[    1.707724]  ubi_io_read_ec_hdr from scan_peb+0x59/0x5ac
[    1.713105]  scan_peb from scan_all+0x95/0x918
[    1.717615]  scan_all from ubi_attach+0x5b/0x344
[    1.722293]  ubi_attach from ubi_attach_mtd_dev+0x56f/0xcec
[    1.727928]  ubi_attach_mtd_dev from ubi_init_attach+0xab/0xdc
[    1.733831]  ubi_init_attach from do_one_initcall+0x29/0x1ac
[    1.739565]  do_one_initcall from kernel_init_freeable+0x17f/0x1e4
[    1.745816]  kernel_init_freeable from kernel_init+0x1b/0xec
[    1.751544]  kernel_init from ret_from_fork+0x11/0x1c
[    1.756650] Exception stack(0x90819fb0 to 0x90819ff8)
[    1.761752] 9fa0:                                     00000000 00000000 00000000 00000000
[    1.769985] 9fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[    1.778219] 9fe0: 00000000 00000000 00000000 00000000 00000013 00000000
[    1.785197] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 64 bytes from PEB 0:2048, read only 64 bytes, retry
[    1.796921] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 64 bytes from PEB 0:2048, read only 6

These two changes can make it compatible with Toradex BSP:

static int vf610_nfc_read_page(struct nand_chip *chip, uint8_t *buf,
			       int oob_required, int page)
{
	struct vf610_nfc *nfc = chip_to_nfc(chip);
	struct mtd_info *mtd = nand_to_mtd(chip);
	int trfr_sz = mtd->writesize + mtd->oobsize;
	u32 row = 0, cmd1 = 0, cmd2 = 0, code = 0;
	int stat;

//>>> Add this
	if ( unlikely(mtd->oobsize > OOB_64) )
	{
		dev_info(nfc->dev, 
			"Using 64 bytes of NAND chip provided %u bytes OOB\n",
			mtd->oobsize);
		mtd->oobsize = OOB_64;
	}
//<<<<
....

In vf610_nfc_attach_chip() remove useless, though perhaps required to be removed lines. At least without them flash works as expected.
//if (mtd->oobsize > 64)
// mtd->oobsize = 64;

As well, if you wish fix undocumented VF family erased page bitflip bug in 60-byte ECC mode, you may add this

static inline int vf610_nfc_correct_data(struct nand_chip *chip, uint8_t *dat,
					 uint8_t *oob, int page)
{
	struct vf610_nfc *nfc = chip_to_nfc(chip);
	struct mtd_info *mtd = nand_to_mtd(chip);
	u32 ecc_status_off = NFC_MAIN_AREA(0) + ECC_SRAM_ADDR + ECC_STATUS;
	u8 ecc_status;
	u8 ecc_count;
	int flips_threshold = nfc->chip.ecc.strength / 2;

	ecc_status = vf610_nfc_read(nfc, ecc_status_off) & 0xff;
	ecc_count = ecc_status & ECC_STATUS_ERR_COUNT;

	if (!(ecc_status & ECC_STATUS_MASK))
		return ecc_count;
//>>>>>>> add this
	/* ECC not OK, perhaps it is erased page.
	   60 byte mode leads to ECC flip */
	if(nfc->ecc_mode == ECC_60_BYTE)
		dat[0x5FD] ^= 0x20;
//<<<<<<<<<<
...

Hi Edward,

Did you hit this on VF61? I cannot reproduce this on VF50. its NAND has a real 64-byte OOB, so the old BSP and mainline share the same ECC layout there. I have not been able to try VF61 at all yet, still waiting for a sample from Toradex. (@Francesco Dolcini)

For the patch1: mainline already clamps mtd->oobsize to 64 in attach_chip(), also in 6.18. Since the unpatched kernel still failed, is patch 2 the one that actually fixes it?

The dat[0x5FD] ^= 0x20 behaviour looks like an undocumented erratum of the 60-byte ECC mode on erased pages. For mainline, masking that byte in the erased-page bitflip count would likely be preferred over flipping it in the data buffer. If you send these to linux-mtd, I am happy to test on VF50.

NAND used on VF50 is reported as Macronix MX30LF1G18AC → 128 MiB SLC, 2048byte page + 64byte OOB, 128 KiB block.

If the one on VF61 is MX30LF4G18AC which is 4 times denser version of VF50, then all should be fine because they have the same OOB as VF50. If it is something else, please share the part number so that I can look at it in advance.

Thanks.

Hi Fide,

Of course I meant booting VF61 and VF50 should boot fine due to flash with 64 bytes OOB.

Mainline clamp to 64 bytes doesn’t help at all. No, Colibri VF61 uses MX30LF4G28AC, whose OOB is larger than 64 bytes.

dat[0x5FD] ^= 0x20 applies to VF50 as well. Try on Linux nanddump /dev/mtd3 > /dev/null. It should report nearly as many false ECC bitflips as many erased flash pages you have. It happens only in 60-byte ECC mode, applies to both VF50 and VF61. Without this patch you can’t use nanddump to check flash condition on VF due to many false ECC bit flips.

Hi Edward,

Confirmed on VF50, and thank you. The credit for spotting this is yours. I went after the root cause and can now explain what happens. I would like to align with you before anything goes upstream.

Measurement (Colibri VF50, MX30LF1G18AC, mainline 6.18.44): nanddump of the 126 MiB UBI partition raised the ECC corrected counter by 18035 which is exactly one per erased page, ECC: 1 corrected bitflip(s) on each. Reading the same pages with the ECC engine bypassed returns clean all-0xff. So the flash is fine; the stale bit only appears when the ECC engine is engaged.

Root cause: It is the controller behavior, not a chip one. An erased page is not a valid BCH codeword, so the decode fails. But before the engine flags the failure it writes its computed “correction” into the SRAM buffer. The all-0xff input always produces the same syndrome, hence the deterministic single bit at data offset 0x5FD in the 60-byte mode (the 45-byte syndrome apparently yields no in-range location, which is why that mode is clean). Two unrelated chips (your MX30LF4G28AC, my MX30LF1G18AC) showing the identical offset fits that. Neither the TRM nor the published mask set errata (VFXXX_2N02G) mention it, so this looks like an undocumented Vybrid erratum.

Proposed fix: Instead of restoring the known byte, I extended what the driver already does for the OOB after a failed decode that is re-read the data area with ECC bypassed too, and run the erased-page check on that. The false counts drop to zero on my VF50 (verified with the patch applied). A second small patch makes the silent 112->64 OOB truncation on your MX30LF4G28AC visible in the kernel log.

Trade-off versus your XOR: Yours costs no extra I/O, which is a real advantage on full-device scans. The re-read costs one extra page transfer per failed decode (i.e. per erased page; negligible at boot since the UBI attach only reads two header pages per PEB), but it carries no assumption about where the engine smears. It stays correct if another mode, input or controller revision touches a different location, it does not cancel a genuine bitflip that sits exactly at 0x5FD and it keeps counting truthful. That makes it the safer candidate for mainline, I think.

Both patches are on the edward-nfc branch of the layer repo, wired into the linux-mainline recipe: files

Plan: I’m waiting for a VF61 sample to run the same verification on your chip, and if everything is fine I intend to send them to linux-mtd by crediting the report to you. Could you share the email address you would like in the Reported-by tag? And if you can give the patches a spin on your VF61 in the meantime, even better.

Best regards,
Fide

Hi

What’s the point rereading data with ECC disabled since you can’t trust that data any way?

if (!(ecc_status & ECC_STATUS_MASK))
	return ecc_count;

..bitfliphere()..

^^ vf610_nfc_correct_data() returns when data is ECC correctable. When ECC fix succeds, it reports bit flips count for given page and exits. Intentional bitflip happens once NFC ECC failure is detected. The only intention was to cancel reporting false bit blip on erased pages. Once ECC fails, result is already not trustable, NFC doesn’t support ECC checking erased pages, right? Even if given page erases to not all-0xFF’s, which sometimes takes place, it won’t harm anyone flipping that bit. Such erased page with real bitflip still will be usable for data storage, ECC will be able to correct programmed data even if one bit is permanently stuck at 0. Now, if you instead reread programmed page with real ECC failure, you perhaps will read more garbage than with ECC enabled. So what’s the point rereading it, I don’t understand.

BTW it wasn’t Freescale’s suggestion to use 60byte ECC, their Linux code for twr-vf61 used weaker ECC, which doesn’t have such problem. Toradex at some point moved to 60 byte ECC, perhaps with intention to improve UBI reliability on sudden power cutoffs. I doubt it helped with power cuts, but it made nanddump nearly unusable to diagnose weared NAND condition. Most of other vendors designs, I guess, use what Freescale suggested, so I doubt Linux community will accept this patch.

Hi Edward,

I did some measurements: I instrumented vf610_nfc_correct_data() to snapshot the buffer after a failed decode and diff it against an ECC-bypassed re-read, then fed it different failing inputs (raw writes into a spare block). Erased page: the engine smears exactly one bit, always 0x5FD bit 5 - your constant, confirmed again. But random uncorrectable content (a torn program): data-dependent - two pages got no smear, one got a single flip at 0x1BD instead. So the fixed XOR is calibrated for the all-0xFF input only.

Why it matters, with numbers. Take a worn erased page whose last byte reads 0xF0 (4 real stuck bits): the re-read counts exactly 4; the XOR path counts 4 + a possible smear elsewhere + 1 it injects itself at the clean 0x5FD = 5 or 6. Same classification today, but two consequences: near the threshold (strength/2 = 16, and UBI relies on this erased-vs-bad call at attach for exactly the torn pages) an error of +/-2 can flip the decision, and the wear curve you want nanddump to show gets +/-2 of input-dependent noise - the very diagnosis both of us are trying to restore.

Beyond correctness: the re-read carries no magic constant to defend to the mtd maintainers (the 0x5FD origin is undocumented in both the TRM and the published errata), and it just extends what the same function already does for the OOB after a failed decode. Cost is one extra transfer only for pages that fail the decode (already rare).

On acceptance: fair point that the 60-byte mode was Toradex’s choice, but the patch does not defend that choice - it fixes the driver’s erased-vs-bad decision logic, which should hold in whichever mode a board picked. And the Colibri VF50/VF61 are supported in mainline with exactly these settings, so this is a bug reachable on an in-tree board, which is what the mtd maintainers care about. The twr-vf61 history is genuinely useful and I would like to quote it in the commit message if you don’t mind; the discovery stays credited to you either way.

Best regards,
Fide

Hi Edward again,

I have found an old VF61 in one of our boxes. You were right about the clamp, like you said It does not survive: nand_scan_tail() runs nanddev_init() after attach_chip(), and that restores mtd->oobsize from the memory organization, so the driver transfers 2048+112 and the ECC parity lands at the wrong offset - every ECC-protected read fails. Clamping the memory organization as well fixes it (Fixes: a7ab085d7c16, so broken since v5.2; U-Boot and 4.4 are immune because they have no such layer).

Tested modules, all booting from NAND on an Iris with the same image:

SOM NAND
VF50 V1.2A MX30LF1G08AA
VF50 V1.2B MX30LF1G18AC
VF61 V1.2B MX30LF4G28AC

Boot logs (U-Boot through tdx-info) for all three, and prebuilt SD images for both modules, are in the v2.0 release: Release v2.0 - VF61 verified on hardware, two NAND fixes · mfide/meta-toradex-colibri-vf · GitHub

Both patches will go to linux-mtd next, with you as Reported-by. Thanks for the pointer again.

Best regards,
Fide