mvebu: uDPU: add sysupgrade support
authorVladimir Vid <vladimir.vid@sartura.hr>
Mon, 22 Jul 2019 11:08:18 +0000 (13:08 +0200)
committerLuka Perkov <luka.perkov@sartura.hr>
Sat, 24 Aug 2019 21:11:15 +0000 (23:11 +0200)
This patch adds sysupgrade, uboot-env and networking support
for Methode uDPU device.

Device features 4 partitions:

-----------------------------------------
|  boot   | recovery  | rootfs |  misc  |
| (ext4)  |  (ext4)   | (fsf2) | (f2fs) |
_________________________________________

Idea was to use f2fs only but the u-boot currently lacks support
so first 2 partition are ext4 to be u-boot readable, and this was
a reason why custom build and sysupgrade sections were required.

On the sysupgrade, boot and rootfs partitions are updated, firmare
image and user configuration is saved on the misc partition and if
the upgrade was successfull, recovery partition will be updated on
after the reboot from preinit script. If the sysupgrade fails for any
reason, device will fallback to recovery initramfs image.

Signed-off-by: Vladimir Vid <vladimir.vid@sartura.hr>
package/boot/uboot-envtools/files/mvebu
target/linux/mvebu/base-files/etc/board.d/02_network
target/linux/mvebu/base-files/lib/preinit/82_uDPU [new file with mode: 0644]
target/linux/mvebu/base-files/lib/upgrade/platform.sh
target/linux/mvebu/base-files/lib/upgrade/uDPU.sh [new file with mode: 0644]
target/linux/mvebu/image/Makefile
target/linux/mvebu/image/cortex-a53.mk
target/linux/mvebu/image/udpu.bootscript [new file with mode: 0644]

index c2e746d959c9c219962dd6a5dd1d00a0c0d89829..7902384a37a4dd792124084c7620ffba4548511b 100644 (file)
@@ -36,6 +36,9 @@ linksys,rango|\
 linksys,venom)
        ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x20000" "0x20000"
        ;;
+methode,udpu)
+       ubootenv_add_uci_config "/dev/mtd0" "0x180000" "0x10000" "0x10000"
+       ;;
 esac
 
 config_load ubootenv
index 7acbe4bf629c851ab12c6b267ddbee3e45fca2d6..69c63e3791688c4f40f7efb2d88f68153e615353 100755 (executable)
@@ -49,7 +49,7 @@ marvell,armada-3720-db)
 marvell,axp-gp)
        ucidef_set_interface_lan "eth0 eth1 eth2 eth3"
        ;;
-methode,uDPU)
+methode,udpu)
        ucidef_set_interfaces_lan_wan "eth1" "eth0"
        ;;
 solidrun,clearfog*a1)
diff --git a/target/linux/mvebu/base-files/lib/preinit/82_uDPU b/target/linux/mvebu/base-files/lib/preinit/82_uDPU
new file mode 100644 (file)
index 0000000..937a0a5
--- /dev/null
@@ -0,0 +1,48 @@
+#
+# Copyright (C) 2014-2019 OpenWrt.org
+# Copyright (C) 2016 LEDE-Project.org
+#
+
+preinit_mount_udpu() {
+
+       . /lib/functions.sh
+
+       case $(board_name) in
+       methode,udpu)
+               # Check which device is detected
+               [ -b "/dev/mmcblk0" ] && mmcdev="/dev/mmcblk0" || mmcdev="/dev/mmcblk1"
+
+               if [ -b "${mmcdev}p4" ]; then
+                       mkdir /misc
+                       mount -t f2fs ${mmcdev}p4 /misc
+                       [ -f "/misc/sysupgrade.tgz" ] && {
+                               echo "- Restoring configuration files -"
+                               tar xzf /misc/sysupgrade.tgz -C /
+                               rm -f /misc/sysupgrade.tgz
+                               sync
+                       }
+                       [ -f "/misc/firmware/recovery.itb" ] && {
+                                       echo "- Updating /recovery partition -"
+                                       mkfs.ext4 -q ${mmcdev}p2 | echo y &> /dev/null
+                                       mkdir -p /tmp/recovery
+                                       mount ${mmcdev}p2 /tmp/recovery
+                                       cp /misc/firmware/recovery.itb /tmp/recovery
+                                       [ -f "/misc/firmware/boot.scr" ] && \
+                                               cp /misc/firmware/boot.scr /tmp/recovery
+                                       sync
+                                       umount /tmp/recovery
+                                       rm -rf /tmp/recovery
+
+                                       # Replace previous backup with the new one
+                                       [ -d "/misc/firmware_old" ] && rm -rf /misc/firmware_old
+                                       [ -d "/misc/firmware" ] && mv /misc/firmware /misc/firmware_old
+                               }
+               fi
+
+               # Legacy support - if rootfs was booted, instruct u-boot to keep the current root dev
+               [ "$(df | grep /dev/root)" ] && fw_setenv root_ok '2'
+       ;;
+       esac
+}
+
+boot_hook_add preinit_main preinit_mount_udpu
index 58e7d83e4e7f507592f516a3e1b466f2b82a7bc4..0223b72d718aa15f30ac04f68431fded19d13400 100755 (executable)
@@ -28,6 +28,9 @@ platform_do_upgrade() {
        marvell,armada8040-mcbin|solidrun,clearfog-base-a1|solidrun,clearfog-pro-a1)
                platform_do_upgrade_sdcard "$1"
                ;;
+       methode,udpu)
+               platform_do_upgrade_uDPU "$1"
+               ;;
        *)
                default_do_upgrade "$1"
                ;;
@@ -42,5 +45,8 @@ platform_copy_config() {
        marvell,armada8040-mcbin|solidrun,clearfog-base-a1|solidrun,clearfog-pro-a1)
                platform_copy_config_sdcard
                ;;
+       methode,udpu)
+               platform_copy_config_uDPU
+               ;;
        esac
 }
diff --git a/target/linux/mvebu/base-files/lib/upgrade/uDPU.sh b/target/linux/mvebu/base-files/lib/upgrade/uDPU.sh
new file mode 100644 (file)
index 0000000..1e98f67
--- /dev/null
@@ -0,0 +1,152 @@
+# uDPU uses combined ext4 and f2fs partitions.
+# partition layout:
+#      1. boot (ext4)
+#      2. recovery  (ext4)
+#      3. rootfs (f2fs)
+#      4. misc (f2fs)
+
+# Check which device is available, depending on the board revision
+if [ -b "/dev/mmcblk1" ]; then
+       emmc_dev=/dev/mmcblk1
+elif [ -b "/dev/mmcblk0" ]; then
+       emmc_dev=/dev/mmcblk0
+else
+       echo "Cannot detect eMMC flash, aborting.."
+       exit 1
+fi
+
+part_prep() {
+        if [ "$(grep $1 /proc/mounts)" ]; then
+               mounted_part="$(grep $1 /proc/mounts | awk '{print $2}' | head -1)"
+               umount $mounted_part
+               [ "$(grep -wo $mounted_part /proc/mounts)" ] && umount -l $mounted_part
+       fi
+}
+
+do_part_check() {
+       local emmc_parts="1 2 3 4"
+       local part_valid="1"
+
+       # Check if the block devices exist
+       for num in ${emmc_parts}; do
+               [[ ! -b ${emmc_dev}p${num} ]] && part_valid="0"
+       done
+
+       # If partitions are missing create a new partition table
+       if [ "$part_valid" != "1" ]; then
+               printf "Invalid partition table, creating a new one\n"
+               printf "o\nn\np\n1\n\n+256M\nn\np\n2\n\n+256M\nn\np\n3\n\n+1536M\nn\np\n\n\nw\n" | fdisk -W always $emmc_dev  > /dev/null 2>&1
+
+               # Format the /misc part right away as we will need it for the firmware
+               printf "Formating /misc partition, this make take a while..\n"
+               part_prep ${emmc_dev}p4
+               mkfs.f2fs -q -l misc ${emmc_dev}p4
+               [ $? -eq 0 ] && printf "/misc partition formated successfully\n" || printf "/misc partition formatting failed\n"
+
+               do_initial_setup
+       else
+               printf "Partition table looks ok\n"
+       fi
+}
+
+do_misc_prep() {
+       if [ ! "$(grep -wo /misc /proc/mounts)" ]; then
+               mkdir -p /misc
+               mount ${emmc_dev}p4 /misc
+
+               # If the mount fails, try to reformat partition
+               # Leaving possiblity for multiple iterations
+               if [ $? -ne 0 ]; then
+                       printf "Error while mounting /misc, trying to reformat..\n"
+
+                       format_count=0
+                       while [ "$format_count" -lt "1" ]; do
+                               part_prep ${emmc_dev}p4
+                               mkfs.f2fs -q -l misc ${emmc_dev}p4
+                               mount ${emmc_dev}p4 /misc
+                               if [ $? -ne 0 ]; then
+                                       umount -l /misc
+                                       printf "Failed while mounting /misc\n"
+                                       format_count=$((format_count +1))
+                               else
+                                       printf "Mounted /misc successfully\n"
+                                       break
+                               fi
+                       done
+               fi
+       fi
+}
+
+do_initial_setup() {
+       # Prepare /recovery parition
+       part_prep ${emmc_dev}p2
+       mkfs.ext4 -q ${emmc_dev}p2 | echo y &> /dev/null
+
+       # Prepare /boot partition
+       part_prep ${emmc_dev}p1
+       mkfs.ext4 -q ${emmc_dev}p1 | echo y &> /dev/null
+
+       # Prepare /root partition
+       printf "Formating /root partition, this may take a while..\n"
+       part_prep ${emmc_dev}p3
+       mkfs.f2fs -q -l rootfs ${emmc_dev}p3
+       [ $? -eq 0 ] && printf "/root partition reformated\n"
+}
+
+do_regular_upgrade() {
+       # Clean /boot partition - mfks.ext4 is not available in chroot
+       [ "$(grep -wo /boot /proc/mounts)" ] && umount /boot
+       mkdir -p /tmp/boot
+       mount ${emmc_dev}p1 /tmp/boot
+       rm -rf /tmp/boot/*
+
+       # Clean /root partition - mkfs.f2fs is not available in chroot
+       [ "$(grep -wo /dev/root /proc/mounts)" ] && umount /
+       mkdir -p /tmp/rootpart
+       mount ${emmc_dev}p3 /tmp/rootpart
+       rm -rf /tmp/rootpart/*
+}
+
+platform_do_upgrade_uDPU() {
+       # Prepare and extract firmware on /misc partition
+       do_misc_prep
+
+       [ -f "/misc/firmware" ] && rm -r /misc/firmware
+       mkdir -p /misc/firmware
+       tar xzf "$1" -C /misc/firmware/
+
+       do_regular_upgrade
+
+       printf "Updating /boot partition\n"
+       tar xzf /misc/firmware/boot.tgz -C /tmp/boot
+       [ $? -eq 0 ] && printf "/boot partition updated successfully\n" || printf "/boot partition update failed\n"
+       sync
+
+       printf "Updating /root partition\n"
+       tar xzf /misc/firmware/rootfs.tgz -C /tmp/rootpart
+       [ $? -eq 0 ] && printf "/root partition updated successfully\n" || printf "/root partition update failed\n"
+       sync
+
+       # Saving configuration files over sysupgrade
+       platform_copy_config_uDPU
+
+       # Remove tmp mounts
+       tmp_parts=$(grep "${emmc_dev}" /proc/mounts | awk '{print $2}')
+       for part in ${tmp_parts}; do
+               umount $part
+               # Force umount is necessary
+               [ "$(grep "${part}" /proc/mounts)" ] && umount -l $part
+       done
+
+       # Sysupgrade complains about /tmp and /dev, so we can detach them here
+       umount -l /tmp
+       umount -l /dev
+}
+
+platform_copy_config_uDPU() {
+       # Config is saved on the /misc partition and copied on the rootfs after the reboot
+       if [ -f "/tmp/sysupgrade.tgz" ]; then
+               cp -f /tmp/sysupgrade.tgz /misc
+               sync
+       fi
+}
index 57e5a30491ee5eee15ebaf45684c27a7ce6f7b76..b4b77b70b4b8746f44a4ecb209b80711838284a0 100644 (file)
@@ -68,6 +68,15 @@ define Build/omnia-medkit-initramfs
                --file=$@ -C $(dir $(IMAGE_KERNEL))boot/ .
 endef
 
+define Build/uDPU-firmware
+       (rm -fR $@-fw; mkdir -p $@-fw)
+       $(CP) $(BIN_DIR)/$(IMAGE_PREFIX)-initramfs.itb $@-fw/recovery.itb
+       $(CP) $@-boot.scr $@-fw/boot.scr
+       (cd $(TARGET_DIR); $(TAR) -cvzf $@-fw/rootfs.tgz .)
+       (cd $@.boot; $(TAR) -cvzf $@-fw/boot.tgz .)
+       (cd $@-fw; $(TAR) -cvzf $(KDIR_TMP)/$(IMAGE_PREFIX)-firmware.tgz .)
+endef
+
 define Device/Default
   PROFILES := Default
   BOARD_NAME = $$(DEVICE_DTS)
index 228155ec11ef21919de85b02af2675ef3ab92450..e0b2b5e186ec7f7533b006344aa38b0c7156599c 100644 (file)
@@ -35,7 +35,7 @@ define Device/marvell_armada-3720-db
 endef
 TARGET_DEVICES += marvell_armada-3720-db
 
-define Device/methode_uDPU
+define Device/methode_udpu
   $(call Device/Default-arm64)
   DEVICE_TITLE := Methode micro-DPU (uDPU)
   DEVICE_DTS := armada-3720-uDPU
@@ -44,8 +44,12 @@ define Device/methode_uDPU
   KERNEL_INITRAMFS_SUFFIX := .itb
   DEVICE_PACKAGES := f2fs-tools e2fsprogs fdisk ethtool kmod-usb2 kmod-usb3 \
                        kmod-e100 kmod-e1000 kmod-e1000e kmod-igb kmod-ixgbevf \
-                       kmod-mdio-gpio kmod-switch-mvsw61xx
+                       kmod-mdio-gpio kmod-switch-mvsw61xx kmod-i2c-pxa
+  IMAGE_NAME = $$(IMAGE_PREFIX)-$$(2)
+  IMAGES := firmware.tgz
+  IMAGE/firmware.tgz := boot-scr | boot-img-ext4 | uDPU-firmware | append-metadata
+  BOOT_SCRIPT := udpu
 endef
-TARGET_DEVICES += methode_uDPU
+TARGET_DEVICES += methode_udpu
 
 endif
diff --git a/target/linux/mvebu/image/udpu.bootscript b/target/linux/mvebu/image/udpu.bootscript
new file mode 100644 (file)
index 0000000..1da35a7
--- /dev/null
@@ -0,0 +1,38 @@
+# Bootscript for Methode uDPU device
+# Device and variables may vary between different revisions
+# of device, so we need to make sure everything is set correctly.
+
+# Set the LED's correctly
+gpio clear 12; gpio clear 40; gpio clear 45;
+
+# Find eMMC device,
+if mmc dev 0; then
+       setenv mmcdev 0
+       setenv rootdev 'root=/dev/mmcblk0p3'
+elif mmc dev 1; then
+       setenv mmcdev 1
+       setenv rootdev 'root=/dev/mmcblk1p3'
+fi
+
+# Set the variables if necessary
+if test ${kernel_addr_r}; then
+       setenv kernel_addr_r 0x5000000
+fi
+
+if test ${fdt_add_r}; then
+       setenv fdt_addr_r 0x4f00000
+fi
+
+setenv console 'console=ttyMV0,115200 earlycon=ar3700_uart,0xd0012000'
+setenv bootargs ${console} $rootdev rw rootwait
+
+load mmc ${mmcdev}:1 ${fdt_addr_r} @DTB@.dtb
+load mmc ${mmcdev}:1 ${kernel_addr_r} Image
+
+booti ${kernel_addr_r} - ${fdt_addr_r}
+
+# If the boot command fails, fallback to recovery image
+echo '-- Boot failed, falling back to the recovery image --'
+setenv bootargs $console
+load mmc ${mmcdev}:2 ${kernel_addr_r} recovery.itb
+bootm ${kernel_addr_r}