Look mom no UART!

Having C.H.I.P hooked up via UART and being able to interactively type commands in U-BOOT and is great for debugging. It becomes kind of a burden though when you need to do it to boot up your C.H.I.P. In this chapter we are adding scripts to flash your U-Boot and the Buildroot image automatically and setup everything such that C.H.I.P can boot straight into Linux without manual intervention via UART.

Enable UBIFS generation in Buildroot

First, we enable the generation of an UBIFS rootfs image in our Buildroot config:

UBOOT_NAND_CFG="buildroot-external/board/nextthingco/CHIP/uboot/nand.cfg"
NAND_BLOCK_SIZE=$(sed -n -e 's/CONFIG_SYS_NAND_BLOCK_SIZE=\(.*\)/\1/p' "${UBOOT_NAND_CFG}")
NAND_PAGE_SIZE=$(sed -n -e 's/CONFIG_SYS_NAND_PAGE_SIZE=\(.*\)/\1/p' "${UBOOT_NAND_CFG}")

MINIOSIZE="${NAND_PAGE_SIZE}"
LEB_SIZE="$(printf "0x%x" $((NAND_BLOCK_SIZE/2 - 2*NAND_PAGE_SIZE)))" 

cat <<EOF >>"${BR2_EXTERNAL}"/configs/nextthingco_chip_defconfig
BR2_TARGET_ROOTFS_UBIFS=y
BR2_TARGET_ROOTFS_UBIFS_LEBSIZE=${LEB_SIZE}
BR2_TARGET_ROOTFS_UBIFS_MINIOSIZE=${MINIOSIZE}
BR2_TARGET_ROOTFS_UBIFS_MAXLEBCNT=4096
BR2_TARGET_ROOTFS_UBIFS_RT_LZO=y
BR2_TARGET_ROOTFS_UBIFS_NONE=y
BR2_TARGET_ROOTFS_UBIFS_OPTS=""
EOF

cd ${BR_DIR}
make nextthingco_chip_defconfig

Configure U-Boot to automatically boot from NAND

We are adding a nand_boot.cfg U-Boot configuration fragment in order to change the BOOT_COMMAND such that it mounts the UBI rootfs partition on the NAND and loads the Linux kernel and the device tree binary from there. We also define the bootargs and finally boot into the Linux kernel:

cat <<EOF >${BR2_EXTERNAL}/board/nextthingco/CHIP/uboot/nand_boot.cfg
CONFIG_AUTOBOOT=y
CONFIG_USE_BOOTCOMMAND=y
CONFIG_BOOTCOMMAND="\
if test -n \${fel_booted} && test -n \${fel_scriptaddr}; then \
    source \${fel_scriptaddr}; \
fi; \
ubi part rootfs; ubifsmount ubi0:rootfs; ubifsload 0x42000000 /boot/zImage; ubifsload 0x43000000 /boot/sun5i-r8-chip.dtb; setenv bootargs root=ubi0_0 rootfstype=ubifs ubi.mtd=4 rw earlyprintk waitroot; bootz 0x42000000 - 0x43000000"
EOF

Now also activate the new configuration fragment:

sed -i -e '
s%\(BR2_TARGET_UBOOT_CONFIG_FRAGMENT_FILES=\).*%\1\"\${BR2_EXTERNAL}/board/nextthingco/CHIP/uboot/nand.cfg \${BR2_EXTERNAL}/board/nextthingco/CHIP/uboot/nand_boot.cfg\"%g
' ${BR2_EXTERNAL}/configs/nextthingco_chip_defconfig

make nextthingco_chip_defconfig

Then re-compile u-boot and run the post-image scripts:

make uboot-reconfigure
make

Bash script to write U-Boot onto the NAND

We are going to use the U-Boot we have built above not only to boot Linux, but also to write the NAND images. For that to work we need to overwrite the auto boot command we defined above by downloading a U-boot environment file to address 0x43100000 with the sunxi-fel tool. The first line in the uenv.txt file needs to be #=uEnv:

cat <<END >${BR_DIR}/output/images/flash.sh
#!/bin/bash

if [ -z "\${BR_DIR}" ]; then
    D="\${PWD}"
else
    D="\${BR_DIR}/output/images"
fi

U_BOOT_SUNXI_WITH_SPL="\${D}/u-boot-sunxi-with-spl.bin"
UENV_TXT="\${D}/uenv.txt"
SUNXI_SPL_BIN_HYNIX_NAND="\${D}/sunxi-spl.bin.hynix.nand"
SUNXI_SPL_BIN_TOSHIBA_NAND="\${D}/sunxi-spl.bin.toshiba.nand"
U_BOOT_BIN_NAND="\${D}/u-boot.bin.nand"
ROOTFS_UBIFS="\${D}/rootfs.ubifs"

ROOTFS_UBIFS_SIZE=\$(stat -c%s "\${ROOTFS_UBIFS}")
ROOTFS_UBIFS_SIZE=\$(printf "0x%x" \${ROOTFS_UBIFS_SIZE}) 

cat <<EOF >"\${UENV_TXT}"
#=uEnv
bootdelay=0
bootcmd=\
nand erase.chip; \
if itest.b *0x1c03035 == 40; then \
  echo "Toshiba NAND Detected"; \
  env set spl_img 0x44000000; \
fi; \
if itest.b *0x1c03035 == 60; then \
  echo "Hynix NAND Detected"; \
  env set spl_img 0x43000000; \
fi; \
nand write.raw.noverify \\\${spl_img} SPL 0x100; \
nand write.raw.noverify \\\${spl_img} SPL.backup 0x100; \
nand write 0x45000000 U-Boot 0x400000; \
nand write 0x45000000 U-Boot.backup 0x400000; \
ubi part rootfs; \
ubi createvol rootfs; \
ubi writevol 0x50000000 rootfs \${ROOTFS_UBIFS_SIZE}; \
reset
EOF

echo "# please connect CHIP with FEL-pin pulled low"
while ! sunxi-fel ver >/dev/null 2>&1; do sleep 0.5; done

sunxi-fel -v -p \
    uboot "\${U_BOOT_SUNXI_WITH_SPL}" \
    write 0x42000000 "\${UENV_TXT}" \
    write 0x43000000 "\${SUNXI_SPL_BIN_HYNIX_NAND}" \
    write 0x44000000 "\${SUNXI_SPL_BIN_TOSHIBA_NAND}" \
    write 0x45000000 "\${U_BOOT_BIN_NAND}" \
    write 0x50000000 "\${ROOTFS_UBIFS}"

echo "# flashing..."
while ! sunxi-fel ver >/dev/null 2>&1; do sleep 0.5; done
echo "# done!"
echo 
echo "# please pull FEL pin high (remove cable connected to GND) and power-cycle CHIP"

END
chmod a+x ${BR_DIR}/output/images/flash.sh

Note: in the U-Boot bootcmd defined above we do a trick to find out the NAND type. We first erase the NAND. After doing that we can read from memory address 0x1c03035 which returns 40 for the Toshiba and 60 for the Hynix NAND. It does not work without erasing the NAND first. (Learned this from Chris Morgan's flashing scripts).