From 7adc29f59ede5112b94b3df4688b47a88f84f544 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 12 Jun 2020 11:06:38 +0100 Subject: [PATCH] mediatek: add SD card image creation for Banana Pi R2 Based on work by Alexey Loukianov and others. Signed-off-by: David Woodhouse --- .../patches/005-update-bpir2-defconfig.patch | 3 +- target/linux/mediatek/image/Config.in | 4 + .../linux/mediatek/image/gen_banana_pi_img.sh | 145 ++++++++++++++++++ target/linux/mediatek/image/mt7623.mk | 30 ++++ .../mediatek/image/mt7623n_bpir2-uEnv.txt | 78 ++++++++++ 5 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 target/linux/mediatek/image/Config.in create mode 100755 target/linux/mediatek/image/gen_banana_pi_img.sh create mode 100644 target/linux/mediatek/image/mt7623n_bpir2-uEnv.txt diff --git a/package/boot/uboot-mediatek/patches/005-update-bpir2-defconfig.patch b/package/boot/uboot-mediatek/patches/005-update-bpir2-defconfig.patch index 104994bf63..a45665eff6 100644 --- a/package/boot/uboot-mediatek/patches/005-update-bpir2-defconfig.patch +++ b/package/boot/uboot-mediatek/patches/005-update-bpir2-defconfig.patch @@ -2,7 +2,7 @@ diff --git a/configs/mt7623n_bpir2_defconfig b/configs/mt7623n_bpir2_defconfig index 6b9fbd7e22..fb2a004803 100644 --- a/configs/mt7623n_bpir2_defconfig +++ b/configs/mt7623n_bpir2_defconfig -@@ -52,3 +52,12 @@ CONFIG_TIMER=y +@@ -52,3 +52,13 @@ CONFIG_TIMER=y CONFIG_WDT_MTK=y CONFIG_LZMA=y # CONFIG_EFI_LOADER is not set @@ -15,3 +15,4 @@ index 6b9fbd7e22..fb2a004803 100644 +CONFIG_ENV_FAT_FILE="uboot.env" +CONFIG_CMD_ASKENV=y +CONFIG_ENV_SIZE=0x2000 ++CONFIG_CMD_SETEXPR=y diff --git a/target/linux/mediatek/image/Config.in b/target/linux/mediatek/image/Config.in new file mode 100644 index 0000000000..f32f83c321 --- /dev/null +++ b/target/linux/mediatek/image/Config.in @@ -0,0 +1,4 @@ +config BANANA_PI_BOOT_PARTSIZE + int "Boot (SD Card) filesystem partition size (in MiB)" + depends on TARGET_mediatek_mt7623_DEVICE_bpi_bananapi-r2 + default 32 diff --git a/target/linux/mediatek/image/gen_banana_pi_img.sh b/target/linux/mediatek/image/gen_banana_pi_img.sh new file mode 100755 index 0000000000..26fbca1388 --- /dev/null +++ b/target/linux/mediatek/image/gen_banana_pi_img.sh @@ -0,0 +1,145 @@ +#!/bin/sh +# +# Copyright © 2019 Alexey Loukianov +# Copyright © 2020 David Woodhouse +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +# Generates a bootable SD card image for Banana Pi R2 (and probably +# other similar boards) as documented at +# http://www.fw-web.de/dokuwiki/doku.php?id=en:bpi-r2:storage +# +# The first sector must contain the SDMMC_BOOT header shown +# below, and also contains the MBR partition table in the end +# of the sector. The partition table must contain no active +# partitions. +# +# The second sector must contain the BRLYT header, and the +# special preloader image goes in sector 4; 2KiB into the image. +# +# The preloader loads U-Boot from sector 640; 320KiB into the image. +# The location and the size (512KiB) are fixed and not read from +# the partition table. We set up a partition for it merely for +# our own convenience for upgrades, etc. +# +# The second partition is a FAT file system containing the kernel +# image and a uboot.env file, which is provided to this script as +# $4 (bootfs image). Its size is configurable with the +# CONFIG_BANANA_PI_BOOT_PARTSIZE option; by default 32MiB. +# +# The root filesystem comes next in the third partition. +# +# +# ------------------------ Sector Offset +# | MBR + SDMMC_BOOT | 0 0x0 +# |----------------------| +# | BRLYT header | 1 0x200 +# |----------------------| +# . . +# . . +# |----------------------| +# | | 4 0x800 +# | | +# | Preloader | +# . . +# . . +# | | 639 +# |----------------------| +# | MBR partition #1 | 640 0x50000 +# | | +# | U-Boot | +# . . +# . . +# | | 1663 +# |----------------------| +# | MBR partition #2 | +# | | +# | FAT partition | ( BANANA_PI_BOOT_PARTSIZE +# . . default 32MiB ) +# . (kernel, uEnv) . +# | | +# |----------------------| +# | MBR partition #3 | +# | | +# | Root partition | +# | | ( TARGET_ROOTFS_PARTSIZE +# | (squashfs+overlay | default 104MiB ) +# . or ext4, etc.) . +# . . +# | | +# ------------------------ +# +# For eMMC boot, everything up to and including the preloader must be +# written to /dev/mmcblk0boot0, with the SDMMC_BOOT header changed to +# read EMMC_BOOT\0 instead. +# +# The contents of the main eMMC are identical to the SD card layout, +# with the preloader loading 512KiB of U-Boot starting at 0x50000. + +function usage() { + echo "SYNTAX: $0 sd " + echo " OR: $0 emmc " + exit 1 +} + +set -e + +PRELOADER_OFFSET=2 # 2KiB + +SDMMC_BOOT="SDMMC_BOOT\x00\x00\x01\x00\x00\x00\x00\x02\x00\x00" +EMMC_BOOT="EMMC_BOOT\x00\x00\x00\x01\x00\x00\x00\x00\x02\x00\x00" +BRLYT="BRLYT\x00\x00\x00\x01\x00\x00\x00\x00\x08\x00\x00\ +\x00\x08\x00\x00\x42\x42\x42\x42\x08\x00\x01\x00\x00\x08\x00\x00\ +\x00\x08\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + +case $1 in + sd) + [ $# -eq 8 ] || usage + OUTPUT="$2" + PRELOADER="$3" + UBOOT="$4" + BOOTFS="$5" + ROOTFS="$6" + BOOTFSSIZE="$7" + ROOTFSSIZE="$8" + + head=4 + sect=63 + + set $(ptgen -o $OUTPUT -h $head -s $sect -a 0 -l 1024 \ + -t 41 -p 512k@320k \ + -t c -p ${BOOTFSSIZE}M \ + -t 83 -p ${ROOTFSSIZE}M ) + + UBOOT_OFFSET="$(($1 / 512))" + UBOOT_SIZE="$(($2 / 512))" + BOOTFS_OFFSET="$(($3 / 512))" + BOOTFS_SIZE="$(($4 / 512))" + ROOTFS_OFFSET="$(($5 / 512))" + ROOTFS_SIZE="$(($6 / 512))" + + echo -en "${SDMMC_BOOT}" | dd bs=1 of="${OUTPUT}" seek=0 conv=notrunc + echo -en "${BRLYT}" | dd bs=1 of="${OUTPUT}" seek=512 conv=notrunc + + dd bs=1024 if="${PRELOADER}" of="${OUTPUT}" seek="${PRELOADER_OFFSET}" conv=notrunc + dd bs=512 if="${UBOOT}" of="${OUTPUT}" seek="${UBOOT_OFFSET}" conv=notrunc + dd bs=512 if="${BOOTFS}" of="${OUTPUT}" seek="${BOOTFS_OFFSET}" conv=notrunc + dd bs=512 if="${ROOTFS}" of="${OUTPUT}" seek="${ROOTFS_OFFSET}" conv=notrunc + dd bs=128k if=/dev/zero of="${OUTPUT}" count=1 oflag=append conv=notrunc + ;; + emmc) + [ $# -eq 3 ] || usage + OUTPUT="$2" + PRELOADER="$3" + + echo -en "${EMMC_BOOT}" | dd bs=1 of="${OUTPUT}" seek=0 + echo -en "${BRLYT}" | dd bs=1 of="${OUTPUT}" seek=512 conv=notrunc + + dd bs=1024 if="${PRELOADER}" of="${OUTPUT}" seek="${PRELOADER_OFFSET}" conv=notrunc + ;; + *) + usage + ;; +esac diff --git a/target/linux/mediatek/image/mt7623.mk b/target/linux/mediatek/image/mt7623.mk index a38c03deb9..1c2dcf7624 100644 --- a/target/linux/mediatek/image/mt7623.mk +++ b/target/linux/mediatek/image/mt7623.mk @@ -1,5 +1,30 @@ KERNEL_LOADADDR := 0x80008000 +ifneq ($(CONFIG_BANANA_PI_BOOT_PARTSIZE),) +BOOTFS_BLOCK_SIZE := 1024 +BOOTFS_BLOCKS := $(shell echo $$(($(CONFIG_BANANA_PI_BOOT_PARTSIZE)*1024*1024/$(BOOTFS_BLOCK_SIZE)))) +endif + +define Build/banana-pi-sdcard + rm -f $@.boot + mkfs.fat -C $@.boot $(BOOTFS_BLOCKS) + + ./gen_banana_pi_img.sh emmc $@.emmc \ + $(STAGING_DIR_IMAGE)/$(UBOOT_TARGET)-preloader.bin + + mkenvimage -s 0x2000 -o $(STAGING_DIR_IMAGE)/$(UBOOT_TARGET)-uboot.env $(UBOOT_TARGET)-uEnv.txt + mcopy -i $@.boot $(STAGING_DIR_IMAGE)/$(UBOOT_TARGET)-uboot.env ::uboot.env + mcopy -i $@.boot $(IMAGE_KERNEL) ::uImage + mcopy -i $@.boot $@.emmc ::eMMCboot.bin + ./gen_banana_pi_img.sh sd $@ \ + $(STAGING_DIR_IMAGE)/$(UBOOT_TARGET)-preloader.bin \ + $(STAGING_DIR_IMAGE)/$(UBOOT_TARGET)-u-boot.bin \ + $@.boot \ + $(IMAGE_ROOTFS) \ + $(CONFIG_BANANA_PI_BOOT_PARTSIZE) \ + $(CONFIG_TARGET_ROOTFS_PARTSIZE) +endef + define Device/bpi_bananapi-r2 DEVICE_VENDOR := Bpi DEVICE_MODEL := Banana Pi R2 @@ -7,6 +32,11 @@ define Device/bpi_bananapi-r2 SUPPORTED_DEVICES := bananapi,bpi-r2 DEVICE_PACKAGES := kmod-fs-vfat kmod-nls-cp437 kmod-nls-iso8859-1 kmod-mmc \ mkf2fs e2fsprogs kmod-usb-ohci kmod-usb2 kmod-usb3 kmod-ata-ahci-mtk + UBOOT_TARGET := mt7623n_bpir2 + IMAGES := img.gz + IMAGE/img.gz := banana-pi-sdcard | gzip | append-metadata + KERNEL := kernel-bin | fit none $$(DTS_DIR)/$$(DEVICE_DTS).dtb + KERNEL_INITRAMFS := endef TARGET_DEVICES += bpi_bananapi-r2 diff --git a/target/linux/mediatek/image/mt7623n_bpir2-uEnv.txt b/target/linux/mediatek/image/mt7623n_bpir2-uEnv.txt new file mode 100644 index 0000000000..f260ed9176 --- /dev/null +++ b/target/linux/mediatek/image/mt7623n_bpir2-uEnv.txt @@ -0,0 +1,78 @@ +# Boot menu for Banana Pi R2 +# Copyright © 2020 David Woodhouse + +kernel=uImage +loadaddr=0x88000000 +dtaddr=0x83f00000 +fdt_high=0xffffffff + +console=ttyS2,115200 +bootopts=rootfstype=squashfs,ext4 rootwait + +# Create the command line (with appropriate root=) and boot the Linux FIT image. +boot1=setenv bootargs "console=${console} root=${rootdev} ${bootopts}";printenv bootargs;\ + fatload mmc ${partition} ${loadaddr} ${kernel}; bootm + +# The preloader leaves a breadcrumb behind to say what it booted from. +checkbootedfrom=if itest.l *81dffff0 == 434d4d65 ; then setenv bootedfrom eMMC; else setenv bootedfrom SD; fi; + +# Build the boot menu one item at a time +bm_count=0 +checkkernel=test -e mmc ${bm_part} ${kernel} +addbm=if run checkkernel; then setenv bootmenu_${bm_count} "Boot from ${bm_dev}.=setenv partition ${bm_part};setenv rootdev ${bm_root};run boot1";if test "${bootedfrom}" = "${bm_dev}"; then setenv bootmenu_default ${bm_count};fi;setexpr bm_count ${bm_count} + 1; fi +# Here we assume that SD card id mmcblk1 and eMMC is mmcblk0 in linux. Swap them if your DTS define them in reverse order. +addeMMCbm=setenv bm_part 0:2;setenv bm_root /dev/mmcblk0p3;setenv bm_dev eMMC;run addbm +addSDbm=setenv bm_part 1:2;setenv bm_root /dev/mmcblk1p3;setenv bm_dev SD;run addbm +addinstallbm=if test "${bootedfrom}" = "SD";then run checkinstall; if run validparts; then setenv bootmenu_${bm_count} "Install OpenWrt from SD to internal eMMC.=run doinstall";setexpr bm_count ${bm_count} + 1;fi;fi + +runbootmenu=if test "${bootedfrom}" = "";then run checkbootedfrom;fi;\ + setenv bm_count 0;run addeMMCbm;run addSDbm;run addinstallbm;setenv bootmenu_${bm_count};\ + bootmenu + +bootdelay=0 +bootcmd=run checkbootedfrom;run runbootmenu + +# XX: Can we read this from the device, or must we trust they're all the same as mine? +# Probably not that important as we're unlikely ever to hit the limit anyway. +maxsect=0xe8ffff +validparts=false + +# We could use 'part size' here but I'd like to check the types too. +checkinstall=mmc dev 1;\ + mmc read 0x88000002 0 1;\ + setenv validparts true;\ + test -e mmc 1:2 eMMCboot.bin || setenv validparts false && echo "eMMCboot.bin not present on SD partition 2";\ + if run validparts && itest.b *0x880001c4 != 0x41; then echo "SD partition 1 is not a PReP Boot partition"; setenv validparts false; fi;\ + if run validparts && itest.l *0x880001c8 != 0x280; then echo "SD partition 1 does not start at 320KiB for U-Boot"; mmc part; exit; fi;\ + if run validparts && itest.l *0x880001cc != 0x400; then echo "SD partition 1 is not 512KiB in size for U-Boot"; mmc part; exit; fi;\ + if run validparts && itest.b *0x880001d4 != 0x0c; then echo "SD partition 2 is not a FAT32 partition"; setenv validparts false; fi;\ + if run validparts && itest.b *0x880001e4 != 0x83; then echo "SD partition 3 is not a Linux partition"; setenv validparts false; fi;\ + setexpr.l part2_start *0x880001d8;setexpr.l part2_len *0x880001dc;setexpr.l part3_start *0x880001e8;setexpr.l part3_len *0x880001ec;\ + if run validparts && test 0x${part2_start} -gt ${maxsect}; then echo "SD partition 2 start too high"; setenv validparts false; fi;\ + if run validparts && test 0x${part2_len} -gt ${maxsect}; then echo "SD partition 2 is too large"; setenv validparts false; fi;\ + if run validparts && test 0x${part3_start} -gt ${maxsect}; then echo "SD partition 3 start too high"; setenv validparts false; fi;\ + if run validparts && test 0x${part3_len} -gt ${maxsect}; then echo "SD partition 2 is too large"; setenv validparts false; fi;\ + setexpr.l part2_end 0x$(part2_start} + 0x${part2_len};setexpr.l part3_end 0x${part3_start} + 0x${part3_len};\ + if run validparts && test 0x${part2_end} -ge ${maxsect}; then echo "SD partition 2 end too high"; setenv validparts false; fi;\ + if run validparts && test 0x${part3_end} -ge ${maxsect}; then echo "SD partition 3 end too high"; setenv validparts false; fi; + +# Copy a single chunk, up to 0x8000 sectors / 16MiB, from SD to eMMC at the specified offset. +writechunk=setenv thislen 8000; if test 0x${partlen} -lt 0x${thislen}; then setenv thislen ${partlen};fi;\ + mmc dev 1;mmc read ${loadaddr} 0x${partofs} 0x${thislen};\ + mmc dev 0; mmc write ${loadaddr} 0x${partofs} 0x${thislen};\ + setexpr partofs 0x${partofs} + 0x${thislen};setexpr partlen 0x${partlen} - 0x${thislen} + +# Copy a partition defined by ${partofs} / ${partlen} from SD to eMMC +writepart=while test 0x${partlen} -ne 0; do run writechunk; done + +# Configure the eMMC boot partition and write eMMCboot.bin to it +writeboot=mmc partconf 0 1 1 0;fatload mmc 1:2 ${loadaddr} eMMCboot.bin;\ + setexpr filesize ${filesize} + 0x1ff;setexpr blocks ${filesize} / 0x200;\ + mmc dev 0 1;mmc write ${loadaddr} 0 ${blocks} + +# Install OpenWrt from the SD card to internal eMMC. +doinstall=run checkinstall;if run validparts;then run writeboot;\ + echo "Copying preloader and U-Boot";setenv partofs 0;setenv partlen 680;run writepart;\ + echo "Copying FAT boot partition";setenv partofs ${part2_start};setenv partlen ${part2_len};run writepart;\ + echo "Copying root partition";setenv partofs ${part3_start};setenv partlen ${part3_len};run writepart;\ + echo "Installed OpenWrt to eMMC";setenv bootedfrom eMMC;run runbootmenu;fi