EMMC boot though spi flash?

I just worked on this a little this evening. I was able to get the Arch Linux image posted in Arch Linux Image for VisionFive 2 working. I had to adjust the paths in /boot/boot/extlinux/extlinux.conf and /etc/fstab, as expected. What was unexpected was that I had to do:

setenv fdtfile starfive/jh7110-visionfive-v2.dtb

at the uBoot prompt to get past the Failed to load '/boot/dtbs/starfive/starfive_visionfive2.dtb' error.

I’m baffled at why this isn’t needed to boot from micro-SD, but is from eMMC. Did I somehow not image the eMMC card cleanly?

Note that I did not change the boot mode switches on the board. If I do that, then I don’t see the messages on the serial console port.


Aha! I figured out why the fdtfile setting wasn’t working: the SPI flash’s u-boot only reads uEnv.txt from mmc1:2 (the SD card’s partition 2) out of the box. You need to change that in the u-boot env:

setenv fatbootpart 0:2

This allows me to boot completely from eMMC. (Well, u-boot is still read from SPI flash.) And setting the fdtfile probably isn’t needed anymore, since it now reads uEnv.txt from the eMMC.

1 Like

I’m trying to follow what you did. You’re talking booting from emmc. You affected only uEnv.txt from the sdcard /dev/mmcblk1p2

Did you add that setenv fatbootpart 0:2 command within the uEnv.txt?
Where did you apply that command?
uboot tool command, if I understood correctly,
implies you have a uart-usb connected to the board
to enter the uboot cmd shell
before the board boots onto the sdcard.
You entered the u-boot prompt: “=>” then ran these commands.

Unfortunately I don’t have the uart-usb dongle to talk in the serial console with the board and apply a similar change for the booting from the nvme.

 # blkid
/dev/nvme0n1p2: LABEL="_/" UUID="d9334329-e2ad-4b72-8f5f-b61406e9d461" BLOCK_SIZE="4096" TYPE="ext4" PARTLABEL="rootfs" PARTUUID="922b24b0-dc95-441b-92cb-c24ff72c2522"
/dev/mmcblk1p3: LABEL="rootpart" UUID="e17e5f37-48b9-4648-a1de-85c504490ef5" UUID_SUB="f684fe2b-a6b1-4ce0-ba2c-3f23ca9b3f52" BLOCK_SIZE="4096" TYPE="btrfs" PARTUUID="f5d0ab68-14dd-5945-bc87-263c1dc052a9"
**/dev/mmcblk1p2**: LABEL_FATBOOT="BOOTPART" LABEL="BOOTPART" UUID="E68A-7FF7" BLOCK_SIZE="512" TYPE="vfat" PARTUUID="2400026e-23d5-4948-b4cc-e2fbde3ac380"
/dev/mmcblk1p1: PARTUUID="442e8885-bcbf-6c4f-b6a4-ffe20e5b5ee5"

I’m trying to boot from nvme in a similar manner. I haven’t modified anything yet.

Here are my current relevant mountpoints:

 # mount  

/dev/mmcblk1p2 on /boot type vfat (rw,nosuid,nodev,relatime,fmask=0000,dmask=0000,allow_utime=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,utf8,flush,errors=remount-ro)

/dev/mmcblk1p3 on / type btrfs (rw,noatime,nodiratime,compress-force=zstd:3,ssd,space_cache=v2,subvolid=5,subvol=/)

/dev/nvme0n1p2 on /mnt type ext4 (rw,relatime)

Here’s my uEnv.txt:

 # cat /boot/boot/uEnv.txt 
# Move distro to first boot to speed up booting
boot_targets=distro mmc0 dhcp 
# Fix wrong fdtfile name
# Fix missing bootcmd
bootcmd=run bootcmd_distro

Here is my extlinux.conf:

 # cat /boot/boot/extlinux/extlinux.conf

DEFAULT visionfive2
MENU TITLE starfive visionfive2 boot options

LABEL visionfive2
      MENU LABEL visionfive2
      LINUX ../../vmlinuz-5.15.0-vf2-260+
      INITRD ../../initrd.img-5.15.0-vf2-260+
      FDTDIR ../../dtb-5.15.0-vf2-260+
      APPEND root=LABEL=rootpart rw console=tty0 console=ttyS0,115200 earlycon rootwait stmmaceth=chain_mode:1 selinux=0 apparmor=0
1 Like

Ah! Sorry; I should have been more clear.

Yes, I’m talking to the UART on pins 6, 8, and 10 of the GPIO header. (I highly recommend you pick up a USB-serial interface. They’re handy for talking to all sorts of devices. They’re dirt cheap on AliExpress, or in a hurry, Amazon carries AdaFruit’s version that the Chinese ones copy.)

You need to set in the U-Boot environment variables the location of the partition that contains the uEnv.txt file. The U-Boot variables are stored in the SPI flash (if I’m not mistaken).

There may be a way to write the U-Boot environment variables using some fancy flashcp incantations, but that seems pretty risky. (If you mess up, you’ll have to boot over UART, and that’ll definitely require a USB UART dongle.) I’m not sure how else to set these variables.

Here’s what I did:

  1. Set up a bootable SD card. I used cwt’s Arch Linux image.
  2. Set up the GPT partition table on the eMMC device using fdisk.
  3. Copy the SD card’s partition 2 (/dev/mmcblk1p2) and 3 (/dev/mmcblk1p3) to the eMMC device (/dev/mmcblk0p2 and /dev/mmcblk0p2).
    a. On the Arch image, there are multiple BTRFS subvolumes in partition 3, so there aren’t any more partitions. Nice and easy. Copy the rest if you have more.
    b. I used dd to copy the EFI partition (partition 2) because I set them to identical sizes, and I used btrfs send / btrfs receive to copy partition 3 to save time and not to have to worry about the slightly smaller partition size on my eMMC device.
  4. Edit the boot/extlinux/extlinux.conf in the eMMC /boot partition. (This will likely be mounted on /mnt/boot/boot, if you do it similarly to how I did.)
  5. You do not need to edit uEnv.txt. You just need to arrange for it to be read from the eMMC device. That’s what step 8 does.
  6. Reboot.
  7. Remove the SD card after it’s synced but before it starts up. (You could just shut down, remove the SD card, and power up again.)
  8. Using the UART port, interrupt the boot process by pressing any key early on. Then issue these commands to U-Boot:
    a. setenv fatbootpart 0:2
    b. saveenv
  9. Continue booting. (Type boot; hit the reset button; whatever.)

Now, all that said, I haven’t tried getting it to work with the EFI partition on NVMe. This may or may not work with the U-Boot currently in SPI flash. It’s easy enough to have your root filesystem on NVMe though; just use the appropriate root path in extlinux.conf. I’m doing that now.

Your uEnv.txt looks identical to mine. It probably doesn’t need to change.

However, your extlinux.conf file is a little different. Mine comes from the Arch build, as I noted. It looks like this:

default Arch-cwt6-server
menu title U-Boot menu
prompt 0
timeout 50

label Arch-cwt6-server
	menu label Arch Linux 5.15.0-cwt6-server
	linux /boot/vmlinuz-5.15.0-cwt6-server
	initrd /boot/initrd.img-5.15.0-cwt6-server
	fdtdir /boot/dtbs/
	append root=/dev/nvme0n1p3 rw console=tty0 console=ttyS0,115200 earlycon rootwait stmmaceth=chain_mode:1 rootflags=defaults,discard=async,compress=lzo,user_subvol_rm_allowed,subvol=arch-minimal

label Arch-cwt6-server-single
	menu label Arch Linux 5.15.0-cwt6-server (Single User Mode)
	linux /boot/vmlinuz-5.15.0-cwt6-server
	initrd /boot/initrd.img-5.15.0-cwt6-server
	fdtdir /boot/dtbs/
	append root=/dev/nvme0n1p3 rw console=tty0 console=ttyS0,115200 earlycon rootwait stmmaceth=chain_mode:1 rootflags=defaults,discard=async,compress=lzo,user_subvol_rm_allowed,subvol=arch-minimal single

I wonder how those ../../ paths work in yours to locate the boot image files. In any event, I think you’ll need to change the root boot parameter to root=/dev/nvme0n1p3 to have, say, the EFI boot partition on eMMC and root on NVMe.

Oh, and I’m using the latest build of U-Boot (2021.10) in SPI flash. That may or may not matter.

1 Like

This post suggests that there may be another way to write the U-Boot environment variables, but it seems like there might be issues with it. I haven’t looked into this at all; proceed with caution!

1 Like

The problem I noticed is that the partition table on the QSPI NOR FLASH from Linux is seen as:

|device name|Device offset|Env. size |Flash sector size|Label|
|/dev/mtd1  |0x0000000    |0x00020000|0x00020000       |SPL  |
|/dev/mtd2  |0x0100000    |0x00300000|0x00300000       |UBOOT|
|/dev/mtd3  |0x0F00000    |0x01000000|0x01000000       |DATA |

But the way that it is actually used by U-Boot according to the “JH7110Boot User Guide (page 8)” is:

|device name|Device offset|Env. size |Flash sector size|Contents                         |
|           |0x0000000    |0x00080000|0x00080000       |SPL                              |
|           |0x00F0000    |0x00010000|0x00010000       |U-Boot environment variables     |
|           |0x0100000    |0x00400000|0x00400000       |fw_payload.img (OpenSBI + U-Boot)|
|           |0x0600000    |0x01000000|0x01000000       |Reseved                          |

So from Linux there is currently no raw partition to access the U-Boot environment variables using “libubootenv”. You could create a new partition that points to the U-Boot environment variables and create a /etc/fw_env.config file that point to that, but probably far safer to wait on the next image to arrive which will probably align the partitions with the documentation, although I just spotted a typo, but it is nothing important.

Hmm, but linux reports yet other sizes:

# cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00020000 00001000 "spl"
mtd1: 00300000 00001000 "uboot"
mtd2: 00100000 00001000 "data"

Note mtd2 is smaller than mtd1 here. While your figures would allow to store a trimmed down kernel into the nor flash, it would not be possible, if /proc/mtd info above were right.

@msz, I would also love to get / set the environment via fw_printenv, but i’m not certain about the geometry, yet. Unfortunately, digging into the u-boot or kernel source does not help much, if the figures there are not right w.r.t. the last partition. One could look at the chips specs, though. Where did you get the sector sizes from, btw?

The RVspace Doc Center is a good place to look for information.
There you will also find the following, for example: Software SDK Developer Guide for U- Boot


I dug a into the issue and fortunately it can be handled without recompiling the kernel.

The partition table for mtd is defined in the device tree, originally in the linux kernel source in



partitions {
     compatible = "fixed-partitions";
     #address-cells = <1>;
     #size-cells = <1>;

     spl@0 {
             reg = <0x0 0x20000>;
     uboot@100000 {
             reg = <0x100000 0x300000>;
     data@f00000 {
             reg = <0xf00000 0x100000>;

Unfortunately, this is outdated or was never right.

@mzs posted hopefully better table based on information in JH7110 Boot User Guide and found a glitch there, too.

Now since the device table is separate (binary) file in the /boot directory, the table can be fixed there as a workaround. The procedure is as follows:

# apt-get install device-tree-compiler # get dtc
# cd /boot/boot/dtbs/starfive
# cp jh7110-visionfive-v2.dtb jh7110-visionfive-v2.dtb.orig
# dtc -I dtb -O dts jh7110-visionfive-v2.dtc > jh7110-visionfive-v2.dts # convert to source
# vi jh7110-visionfive-v2.dts # replacing the section as below
# dtc -I dts -O dtb jh7110-visionfive-v2.dts > jh7110-visionfive-v2.dtb # convert to binary
# reboot

The section in question need to be replaced by

partitions {
  compatible = "fixed-partitions";
  #address-cells = <0x01>;
  #size-cells = <0x01>;

  spl@0 {
    reg = <0x00 0x80000>;

  ubootenv@0 {
    reg = <0xF0000 0x10000>;

  payload@100000 {
    reg = <0x100000 0x400000>;

  reserved@600000 {
    reg = <0x600000 0xa00000>;

which is hopefully a bit better.

After the reboot, try

# cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00080000 00001000 "spl"
mtd1: 00010000 00001000 "ubootenv"
mtd2: 00400000 00001000 "payload"
mtd3: 00a00000 00001000 "reserved"

(Note that the erase sizes shown differ from @mzs 's table.)

Now the u-boot environment should be accessible by fw_printenv. Install the utility using apt-get install libubootenv-tool. The utility must be configured. Create a file /etc/fw_env.config containing:

# MTD device name       Device offset   Env. size       Flash sector size       Number of sectors
/dev/mtd1               0x00000         0x10000         0x10000

Now as good as i understand, the u-boot environment is not persistent by default. Thus fw_printenv would show you an empty environment.

Being connected to the UART, reboot and enter the u-boot dialog:

StarFive # env save

Now /dev/mtd1 is populated and will be used by u-boot. Boot into linux and try:

# fw_printenv
boot_a_script=load ${devtype} ${devnum}:${distro_bootpart} ${scriptaddr} ${prefix}${script}; source ${scriptaddr}
ver=U-Boot 2021.10 (Jan 08 2023 - 18:04:54 +0800)
visionfive2_mem_set=fdt memory ${memory_addr} ${memory_size};

Parts of the configuration is also /etc/u-boot-initial-env, which can best be produced now:

# fw_printenv > /etc/u-boot-initial-env

If anything fails, the original configuration can be restored in u-boot using

StarFive # env default -a

Note that the utility contains a fw_setenv command, too.

Hope it helps, good luck!


Since important information like MAC address are storaged inside external eeprom, I think we could completely re-arrange spi partition layout. I think this also might help solve problems happened on current opensuse image:https://en.opensuse.org/HCL:VisionFive2#Manual_Installation
Also, we could separate OpenSBI image and U-Boot to update them independently.

Hmm, while paging through the u-boot env and the related processes, i came over
I wonder how common u-boot related kernel installations and upgrades currently are. I’ve seen a u-boot-update script in Debian that hooks into the regular kernel installion. Does SuSE have a likely infrastructure or is this all new ground for everyone?

Perhaps this and the next entry in the blog below might be of interest for this topic,
since many distributions struggled to cope commonly with SPI and U-BOOT installations.

1 Like

With new image of debian I just was able to boot without sd card :sunny:
(but just once :anger: )

please make sure you press&hold more than 3 second

1 Like

this is just hard reset - correct?
I just reinstalled image on eMMC and after all it’s booting again, I’ll play now with that to see if it’s everything ok. Eventually I would like to start from m.2 slot only, for now sdcard-less booting is just better than earlier. :slight_smile:

yes, just for hardware reset.

Have you also managed to load SPL and u-Boot from the eMMC, as well? I’m still stuck on that part.

My current setup is:

SPL and U-Boot: SPI flash
FAT boot partition: eMMC
Linux partition: NVMe

I’ve set up partitions 1 and 2 (starting at sectors 4096 and 8192, as described in the JH7110 Boot User Guide), set them with the correct type UUIDs, and copied the u-boot-spl.bin.normal/out and visionfive2_fw_payload.img contents to them, as described in the new section 4.3.2 in the VisionFive2 Quick Start Guide.

But it doesn’t work: When I switch the dip switches to eMMC boot, there is no output.

I see some people have managed to get SD card images that do have working u-Boot installations on them. If I write one of those to an SD card and set the dip switches for SDIO3.0 boot, then u-Boot is read from the SD card.

Has anyone gotten U-Boot to be read from the eMMC device? If so, what’s the magic incantation?

I downloaded starfive-jh7110-202302-eMMC-minimal-desktop.img.bz2 as described and linked here:

Unfortunately, it seems that my new eMMC died and my eMMC to Micro-SD adapter got lost before I could test the current image. But over the course of today, two eMMC should arrive, as well as an eMMC to Micro-SD adapter and a USB 3.1 to eMMC adapter. I have to work a night shift tonight and will probably not be able to report until tomorrow morning.


UPS was here 40 minutes ago and unfortunately I don’t have good results to show.
starfive-jh7110-202302-eMMC-minimal-desktop.img.bz2 was quickly written using USB to eMMC adapter. eMMC inserted into VF2 v1.3B, boot mode set to eMMC, my headless terminal (Raspberry Zero W with USB to UART adapter) started, logged in and Minicom started, then VF2 switched on. Red LED comes on, green LED doesn’t even blink and not a single character arrives in Minicom!

VF2 switched off, boot mode set to SDIO and VF2 switched on again. System starts normally, so I start tightvncserver so that I can comfortably start gparted on the headless VF2. eMMC is recognised and expanding the / partition happens without problems. VF2 switched off, boot mode set to eMMC, green LED does not flash again, but at least something arrives in the Minicom, five lines are written with each new power on.

ÿdwmci_d: DATA ERROR!
dwmci_s: Timeout.
BOOT fail,Error is 0xffffffff
dwmci_s: Response Timeout.
BOOT fail,Error is 0xffffffff

Tomorrow, after the night shift, I will first do a firmware upgrade of the QSPI flash to v2.10.4 to try to boot the eMMC in QSPI flash boot mode and then put the VF2 v1.3B aside and try my VF2 v1.2A with an eMMC instead.


Let me just introduce a little bit about how I do it.

  1. Switch boot mode to SDIO, then power up and boot it from TF card;
  2. Transfer eMMC image into system (either over ethernet or USB etc.) ;
  3. Use dd command to flash eMMC image into eMMC(mmcblk0), such as dd if=starfive-jh7110-202302-eMMC-minimal-desktop.img of=/dev/mmcblk0 bs=4M status=progress
  4. Input sync command and power down;
  5. Switch boot mode to eMMC mode and power up;

Please make sure you press&hold the reset button for more than 3 seconds if you need reset the system.


I have repeated all the steps again using your method. Unfortunately, I can only very rarely boot an eMMC on my Kickstarter Early Bird - 4GB VF2 v1.3B after many resets.

I just remembered, at first the boot from eMMC worked, I was able to install openssh-server with keyboard and screen, change the passwords of root and user and after a reboot I was able to install headless my favourite editor, setup using apt-cacher-ng as proxy, as well as set up my bash environment for my liking. later I take a break shut down the system and hours later could only boot it with difficulty sometimes.

On my 8GB VF2 v1.2A from Waveshare I then carried out all the steps with a second 64GB eMMC and so far everything works here.

I will test the two “non-functioning” eMMC 32GB and 64GB with the VF2 v1.2A later.

I get these bus speed messages on the debug terminal very rarely with the VF2 v1.2A and very often with the VF2 v1.3B.

[   12.935725] mmc_host mmc0: Bus speed (slot 0) = 198000000Hz (slot req 400000Hz, actual 399193HZ )
[   13.192614] mmc_host mmc0: Bus speed (slot 0) = 198000000Hz (slot req 100000000Hz, actual 990000)
[   13.768426] starfive-eth-plat 16030000.ethernet end0: Link is Up - 1Gbps/Full - flow control rx/x

Debian GNU/Linux
Debian GNU/Linux bookworm/sid vfive2-8 hvc0

vfive2-8 login:  bookworm/sid vfive2-8 ttyS0

vfive2-8 login: [   34.486172] mipi_0p9: disabling
[   39.445859] mmc_host mmc0: Bus speed (slot 0) = 198000000Hz (slot req 400000Hz, actual 399193HZ )
[   39.712463] mmc_host mmc0: Bus speed (slot 0) = 198000000Hz (slot req 100000000Hz, actual 990000)

I use the same PD power supply on both boards and have also installed the same cooler/fan combination.