[BPI-R3] what is SD_eMMC_SEL connected to?

Schematic diagram for BPI-R3 is incomplete. I’m trying to find out where SD_eMMC_SEL (from the dip-switch) goes to.

On the MT7986 pins SPI0 and SPI2 are both in use, so that only leaves emmc pins to be used on 1 set of pins. The other emmc aux function is used by SPI0 in this combination.

Is there a switch IC between the MT7986 and the SD and EMMC?

Will the dipswitch switch from SD to EMMC immediately, or only after reboot?

grafik

the dip switch causes first 4 datalanes from emmc (8bit bus) switched to sdslot (4bit bus)

Thanks.

This looks promising that it may work writing to EMMC running from an INITRD. So after switching when powered up, somehow need to tell the kernel that another MMC card has been insterted. Just as if a SD card has been removed and another inserted.

SGM7222 FUNCTION TABLE 
        EMMC   SD
OE   S  HSD1+  HSD2+
        HSD1-  HSD2-
0    0  ON     OFF 
0    1  OFF    ON 
1    ×  OFF    OFF

@frank-w Do you know if R315 is NC or is it 0R ?

If it is 0R, then the SD/EMMC switch can be controlled by GPIO_0, overriding the switch. When SD is selected (pull up 4k7) and GPIO_0 is set LOW, then the SD_eMMC_SEL line will go low. Then it can be controlled by software… As by design…,

PS: The 499R on the dipswitch would even protect the GPIO PIN if accidentally GPIO_0 was set HIGH and the dipswitch pulls LOW. the 499R would limit the maximum current to 7 mA (3.3V / 499Ohm)

You have to change buswidth too and i think this cannot be done at runtime

regarding r315 this is not clear from schematic “NC\0R” we have to look on board have my r3v1.0 heavily connected and v1.1 mounted in case and don’t see R315 label on top of board

I’ll check it on the board, when I receive mine, but this will take some weeks.

Don’t know if the emmc can connect 4 bits wide, otherwise, it would need to connect at 1 bit wide. Anyway, re-inserting should restart the whole negotiation again. Guess not only from initrd, but also from uboot it should be possible.

doing this from uboot makes it possible if uboot loads kernel from ram

  • read kernel+fdt+initrd into memory
  • change switch
  • boot kernel

btw. i have high-resolution pictures in my wiki, maybe you see the R315 there

https://www.fw-web.de/dokuwiki/doku.php?id=en:bpi-r3:start

for dts settings you can compare here:

Guess R315 will be NC, otherwise dipswitches nr 1 and 4 will be hard wired. Unless I’m missing something else in the schematic.

So I guess the user needs to flip the switch.

eMMC defines several bus speed modes

                                Bus Width
Legacy         Single 3.3/1.8V  1,4,8     0-26MHz   26MB/s
High Speed SDR Single 3.3/1.8V  4,8       0-52MHz   52MB/s
High Speed DDR Dual   3.3/1.8V  4,8       0-52MHz   104MB/s
HS200          Single 1.8V      4,8       0-200MHz  200MB/s
HS400          Dual   1.8V      8         0-200MHz  400MB/s

So it would need to set up HS200 only at 4 bit.

I believe the mmc driver can be reset with:

echo 11230000.mmc > /sys/bus/platform/drivers/mtk-msdc/unbind 2>/dev/null
sleep 2
echo 11230000.mmc > /sys/bus/platform/drivers/mtk-msdc/bind

This will reread the card after switching…

Edit: Or even better: unbind - switch - bind

Edit2: @frank-w For changing to 8 bit, I was thinking of CONFIG_OF_DYNAMIC applying overlays at runtime. So it would be: unbind - switch - apply overlay - bind

Just try it,have not tried apply dt overlay in running linux. You cannot delete nodes/properties,only add and change values. Mmc node has some sd/emmc specific properties (only sd care here as they maybe need to be removed),but maybe it works. I leave it up to you try it out :slight_smile: best chances i see from uboot booted from sd and preloaded emmc-kernel

It works, I’m booting from EMMC now, written from initrd that is started from SDMMC.

No need to use NOR or NAND as in between step. Can reread the MMC with unbind/bind the mtk-msdc driver.

I have not done the dynamic overlay part yet. Still can write to the emmc, but the speed it quite slow, because the correct capability is not added to the mmc controller yet. So it took a half hour… But anyway, so far so good.

Once booting from EMMC, the speed is normal.

The linux package with the mkinitcpio.conf is building and should automatically come online anytime soon…

I run this on the initrd:

#!/usr/bin/ash

# Tool for %PKGBASE% package, needs to run from initrd!
# Connect UART and when kernel starts, keep 'x' key pressed.

mkdir -p /tmp/mnt
mount --source /dev/disk/by-partlabel/*-sdmmc-root --target /tmp/mnt
[ $? -ne 0 ] && exit
[ ! -e "/tmp/mnt$1" ] && exit
echo "Reading file $1 now..."
cp -f "/tmp/mnt$1" "/tmp/tempfile"
umount /tmp/mnt
[ $? -ne 0 ] && exit

while [ ! -e /sys/block/mmcblk0boot0 ]; do
  echo 11230000.mmc >/sys/bus/platform/drivers/mtk-msdc/unbind
  sleep 0.1
  echo 11230000.mmc >/sys/bus/platform/drivers/mtk-msdc/bind
  echo "Flip SD/EMMC switch now (most near to power plug)!"
  sleep 1.9
done

echo "Setting up EMMC so that mmcblk0boot0 is the bootdevice."
mmc bootpart enable 1 1 /dev/mmcblk0
echo "Writing $1 to EMMC now..."
xz -dcv "/tmp/tempfile" | dd of=/dev/mmcblk0 conv=fsync,notrunc

echo "Copying atf partition to mmcblk0boot0"
echo 0 >/sys/block/mmcblk0boot0/force_ro
dd if=/dev/mmcblk0 of=/dev/mmcblk0boot0 bs=512 skip=34 count=1024 conv=fsync,notrunc
echo 1 >/sys/block/mmcblk0boot0/force_ro

echo "Flip other switch now (most far away from power plug)!"
echo "Reboot and enjoy booting from EMMC."

So it turned out the EMMC image can be build with: BOOT_DEVICE=emmc and BROM_HEADER_TYPE=sdmmc, after a small change to atf source. Then boot with only switch D down.

Anyway, now that I figured out how to boot from EMMC from mmcblk0 only, the script is also simpler:

#!/usr/bin/ash

# Tool for %PKGBASE% package, needs to run from initrd!
# Connect UART and when kernel starts, keep 'x' key pressed.

mkdir -p /tmp/mnt
mount --source /dev/disk/by-partlabel/*-sdmmc-root --target /tmp/mnt
[ $? -ne 0 ] && exit
[ ! -e "/tmp/mnt$1" ] && exit
echo "Reading file $1 now..."
cp -f "/tmp/mnt$1" "/tmp/tempfile"
umount /tmp/mnt
[ $? -ne 0 ] && exit

while [ ! -e /sys/block/mmcblk0boot0 ]; do
  echo 11230000.mmc >/sys/bus/platform/drivers/mtk-msdc/unbind
  sleep 0.1
  echo 11230000.mmc >/sys/bus/platform/drivers/mtk-msdc/bind
  echo "Flip SD/EMMC switch down (most near to power plug), the rest stay up!"
  sleep 1.9
done

echo "Setting up EMMC so that mmcblk0 is the bootdevice."
mmc bootpart enable 7 1 /dev/mmcblk0
echo "Writing $1 to EMMC now..."
xz -dcv "/tmp/tempfile" | dd of=/dev/mmcblk0 conv=fsync,notrunc

echo "Reboot and enjoy booting from EMMC."

This makes the SD image and EMMC image practically the same. No need to write anything to mmcblk0boot0

Where do you get data you write to emmc (/tmp/mnt)? Is this an usb storage you mount there?

Have you solved the dtb load?

I have this now in the readme:

… Then copy the bpir.img.xz to the SD card /tmp/ folder. It is accessible without root.

Boot the R3 with the SD card with UART connected. When kernel starts keep ‘x’ key pressed. Clear the commandline with enter. Execute:

bpir3-flash2emmc /tmp/bpir.img.zx

So it mounts the root partition on the SDMMC, copies the file to ram and unmounts it, then switches over.

I still have to try the dynamic overlay… Just need to add the emmc specific capability and change the bus width. I think nothing needs to be deleted.

Appearently configfs for dynamic overlays is not a mainline kernel thing…

Anyway, I borrowed from xilinx:

https://github.com/Xilinx/linux-xlnx/blob/master/drivers/of/configfs.c

And made it part of my kernel. I now can run me script from initrd busybox, that looks like this:

#!/usr/bin/ash
 
# Tool for %PKGBASE% package, needs to run from initrd!
# Connect UART and when kernel starts, keep 'x' key pressed.
 
driver="mtk-msdc"
addr="11230000"
 
function get_sysmmc {
  str=$(echo /sys/bus/platform/devices/${addr}.mmc/mmc_host/mmc*/mmc* | head -1)
  [ -e "$str" ] && echo ${str} || echo ""
}
function get_mmcblk {
  str=$(get_sysmmc)
  [ ! -z "$str" ] &&  echo "$(basename $(ls ${str}/block | head -1))" || echo "/dev/null"
}
function get_mmctype {
  str=$(get_sysmmc)
  [ ! -z "$str" ] && cat ${str}/type || echo "NONE"
}

function set_sdmmc {
rmdir ${mmcdtbo}
} 

function set_emmc {
cat <<EOT | tee /tmp/mmc0.dts
/dts-v1/;
/plugin/;
&mmc0 {
  bus-width = <8>;
  max-frequency = <200000000>;
  cap-mmc-highspeed;
  mmc-hs200-1_8v;
//  mmc-hs400-1_8v;
//  hs400-ds-delay = <0x14014>;
  no-sd;
  no-sdio;
  status = "okay";
};
EOT
mkdir -p ${mmcdtbo}
dtc -@ -I dts -O dtb -o ${mmcdtbo}/dtbo /tmp/mmc0.dts
}
 
function restart_driver {
  [[ "$1" == "SD" ]] && pos="UP"
  [[ "$1" == "MMC" ]] && pos="DOWN"
  until [[ "$(get_mmctype)" == "$1" ]]; do
    echo ${addr}.mmc >/sys/bus/platform/drivers/${driver}/unbind
    sleep 0.1
    echo ${addr}.mmc >/sys/bus/platform/drivers/${driver}/bind
    echo "Flip SD/EMMC switch ${pos} (=$1) (most near to power plug), the rest stay up!"
    sleep 1.9
  done
}
 
mount -t configfs none /sys/kernel/config
 
mmcblk=$(get_mmcblk)
mmcdtbo="/sys/kernel/config/device-tree/overlays/mmc0"
 
echo "Device = /dev/${mmcblk}"
 
if [[ "$(get_mmctype)" == "SD" ]]; then
  mkdir -p /tmp/mnt
  mount --source /dev/disk/by-partlabel/*-sdmmc-root --target /tmp/mnt
  [ $? -ne 0 ] && exit
  echo "Reading file $1 now..."
  cp -f "/tmp/mnt$1" "/tmp/tempfile"
  umount /tmp/mnt
  [ $? -ne 0 ] && exit
  echo "Switching to EMMC..."
  set_emmc
  restart_driver "MMC"
  mmcblk=$(get_mmcblk)
  if [ -e "/tmp/tempfile" ]; then
    echo "Setting up EMMC so that ${mmcblk} is the bootdevice."
    mmc bootpart enable 7 1 /dev/${mmcblk}
    echo "Writing $1 to EMMC now..."
    xz -dcv "/tmp/tempfile" | dd of=/dev/${mmcblk} conv=fsync,notrunc
    echo "Reboot and enjoy booting from EMMC."
  fi
elif [[ "$(get_mmctype)" == "MMC" ]]; then
  echo "Switching back to SDMMC..."
  set_sdmmc
  restart_driver "SD"
  mmcblk=$(get_mmcblk)
fi

Now I can write the image with HS200 speed…

Run the script again and it it possible to change back to SD.

But I cannot get HS400 to work, also without dynamic overlays, only loading 1 dtb with HS400 set, I get errors. Maybe I’m missing something in kernel 6.2.7.

[  133.416314] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  133.426428] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  133.436566] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  133.540762] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  133.551996] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  133.562159] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  133.567923] I/O error, dev mmcblk0, sector 10038120 op 0x1:(WRITE) flags 0x104000 phys_seg 123 prio class 2
[  133.568168] I/O error, dev mmcblk0, sector 10039144 op 0x1:(WRITE) flags 0x100000 phys_seg 73 prio class 2

[  148.533725] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
/ # [  148.544168] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  148.554497] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  148.564559] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  148.570331] I/O error, dev mmcblk0, sector 1115648 op 0x1:(WRITE) flags 0x800 phys_seg 87 prio class 2
[  148.584183] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  148.594287] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  148.604389] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  148.608827] F2FS-fs (mmcblk0p3): do_checkpoint failed err:-5, stop checkpoint
[  148.614491] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  148.627342] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  148.637446] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  148.647547] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  148.657648] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  148.667613] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  148.677575] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  148.687536] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  148.697445] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  148.707408] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  148.717369] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  148.727337] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  148.737299] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  148.747260] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  148.753031] I/O error, dev mmcblk0, sector 248464 op 0x1:(WRITE) flags 0x3800 phys_seg 1 prio class 2
[  148.766411] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  148.772179] I/O error, dev mmcblk0, sector 160432 op 0x1:(WRITE) flags 0x3800 phys_seg 1 prio class 2
[  148.785497] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  148.791272] I/O error, dev mmcblk0, sector 159904 op 0x1:(WRITE) flags 0x3800 phys_seg 1 prio class 2
[  148.804649] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  148.810419] I/O error, dev mmcblk0, sector 155800 op 0x1:(WRITE) flags 0x3800 phys_seg 1 prio class 2
[  148.823791] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  148.829561] I/O error, dev mmcblk0, sector 155648 op 0x1:(WRITE) flags 0x3800 phys_seg 1 prio class 2
[  148.842942] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  148.848699] I/O error, dev mmcblk0, sector 151552 op 0x1:(WRITE) flags 0x3800 phys_seg 1 prio class 2
[  148.862073] mtk-msdc 11230000.mmc: Final PAD_DS_TUNE: 0x15414
[  148.867831] I/O error, dev mmcblk0, sector 147784 op 0x1:(WRITE) flags 0x3800 phys_seg 2 prio class 2
[  148.877190] I/O error, dev mmcblk0, sector 143360 op 0x1:(WRITE) flags 0x3800 phys_seg 3 prio class 2

Or do I need to change 14014 to 15414?