From d6402eadaa56494b382e389d739b9f80d6883788 Mon Sep 17 00:00:00 2001
From: Kenneth Kasilag <kenneth@kasilag.me>
Date: Sat, 21 Feb 2026 21:49:46 +0000
Subject: [PATCH] an7581: add uboot chainloader for w1700k

Due to issues surrounding the implementation of the vendor BMT/BBT
on Airoha, upstream ATF + uboot has switched to UBI flash partitions.

However, some devices shipped on this platform are bootloader locked,
and thus it is impossible to replace ATF + uboot.

During testing for the Gemtek W1700K (#17869), sysupgrades from Linux
(which is unaware of the underlying BMT/BBT) would occasionally write
data into blocks which were remapped by the vendor uboot when it was
read on the following reboot, causing a soft brick.

An acceptable workaround [1],[2] was discussed where an intermediate
uboot would be written by the vendor uboot (which is aware of Airoha
BMT/BBT). This chainloader would then ignore the regions of flash
used by the vendor uboot, and store all relevant data inside of UBI.

UBI would then be used to handle bad block management. As the vendor
ATF + uboot do not read or interact with the UBI region, we would avoid
unwanted remaps from BMT/BBT.

This commit introduces support for building such a chainloader, by
packaging u-boot and DTS into a FIT image; to be flashed like a kernel.

Configuration for the Gemtek W1700K is provided as an example of how the
chainloader is used.

[1] https://github.com/openwrt/openwrt/pull/17869#discussion_r2836066746
[2] https://github.com/openwrt/openwrt/pull/17869#discussion_r2838395671

Signed-off-by: Kenneth Kasilag <kenneth@kasilag.me>
---
 configs/an7581_w1700k_defconfig                     | 107 ++++++++++
 defenvs/an7581_w1700k_env                           |  21 ++
 dts/upstream/src/arm64/airoha/an7581-w1700k-ubi.dts |  87 +++++
 3 files changed, 215 insertions(+), 0 deletions(-)
 create mode 100644 configs/an7581_w1700k_defconfig
 create mode 100644 defenvs/an7581_w1700k_env
 create mode 100644 dts/upstream/src/arm64/airoha/an7581-w1700k-ubi.dts

--- /dev/null
+++ b/configs/an7581_w1700k_defconfig
@@ -0,0 +1,107 @@
+CONFIG_ARM=y
+CONFIG_ARCH_AIROHA=y
+CONFIG_AUTOBOOT_KEYED=y
+CONFIG_AUTOBOOT_MENU_SHOW=y
+CONFIG_POSITION_INDEPENDENT=y
+CONFIG_TARGET_AN7581=y
+CONFIG_TEXT_BASE=0x81E00000
+CONFIG_SYS_MALLOC_F_LEN=0x4000
+CONFIG_NR_DRAM_BANKS=1
+CONFIG_ENV_SIZE=0x4000
+CONFIG_ENV_OFFSET=0x7c000
+CONFIG_DM_GPIO=y
+CONFIG_DEFAULT_DEVICE_TREE="airoha/an7581-w1700k-ubi"
+CONFIG_SYS_LOAD_ADDR=0x81800000
+CONFIG_BUILD_TARGET="u-boot.bin"
+# CONFIG_EFI_LOADER is not set
+CONFIG_FIT=y
+CONFIG_FIT_VERBOSE=y
+CONFIG_BOOTDELAY=30
+CONFIG_DEFAULT_FDT_FILE="an7581-w1700k-ubi"
+CONFIG_SYS_PBSIZE=1049
+CONFIG_SYS_CONSOLE_IS_IN_ENV=y
+# CONFIG_DISPLAY_BOARDINFO is not set
+CONFIG_HUSH_PARSER=y
+CONFIG_SYS_PROMPT="U-Boot> "
+CONFIG_SYS_MAXARGS=8
+CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_BOOTMENU=y
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_XIMG is not set
+CONFIG_CMD_BIND=y
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_MTD=y
+CONFIG_CMD_SF_TEST=y
+CONFIG_CMD_SPI=y
+# CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_PING=y
+CONFIG_CMD_EXT4=y
+CONFIG_CMD_FAT=y
+CONFIG_CMD_FS_GENERIC=y
+CONFIG_CMD_MTDPARTS=y
+CONFIG_CMD_LOG=y
+CONFIG_OF_UPSTREAM=y
+CONFIG_ENV_OVERWRITE=y
+CONFIG_ENV_IS_IN_MMC=y
+# CONFIG_ENV_IS_IN_MTD is not set
+CONFIG_ENV_RELOC_GD_ENV_ADDR=y
+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_SYS_RX_ETH_BUFFER=8
+CONFIG_REGMAP=y
+CONFIG_SYSCON=y
+CONFIG_CLK=y
+CONFIG_DMA=y
+CONFIG_LED=y
+CONFIG_LED_GPIO=y
+CONFIG_MMC_HS200_SUPPORT=y
+CONFIG_MMC_MTK=y
+CONFIG_MTD=y
+CONFIG_DM_MTD=y
+CONFIG_MTD_SPI_NAND=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_SPI_FLASH_EON=y
+CONFIG_SPI_FLASH_GIGADEVICE=y
+CONFIG_SPI_FLASH_ISSI=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_SPANSION=y
+CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_SPI_FLASH_MTD=y
+CONFIG_AIROHA_ETH=y
+CONFIG_DM_MDIO=y
+CONFIG_CMD_MII=y
+CONFIG_CMD_MDIO=y
+CONFIG_PHY=y
+CONFIG_PINCTRL=y
+CONFIG_PINCONF=y
+CONFIG_POWER_DOMAIN=y
+CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_RAM=y
+CONFIG_DM_SERIAL=y
+CONFIG_SYS_NS16550=y
+CONFIG_SPI=y
+CONFIG_DM_SPI=y
+CONFIG_AIROHA_SNFI_SPI=y
+CONFIG_CMD_UBI=y
+# CONFIG_CMD_UBI_RENAME is not set
+CONFIG_CMD_UBIFS=y
+CONFIG_ENV_IS_IN_UBI=y
+CONFIG_ENV_REDUNDANT=y
+CONFIG_ENV_UBI_PART="ubi"
+CONFIG_ENV_UBI_VOLUME="ubootenv"
+CONFIG_ENV_UBI_VOLUME_REDUND="ubootenv2"
+CONFIG_ENV_UBI_VID_OFFSET=0
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_MODULE=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_LIMIT=20
+# CONFIG_MTD_UBI_FASTMAP is not set
+CONFIG_UBI_BLOCK=y
+# CONFIG_UBIFS_SILENCE_MSG is not set
+# CONFIG_UBIFS_SILENCE_DEBUG_DUMP is not set
+CONFIG_ENV_USE_DEFAULT_ENV_TEXT_FILE=y
+CONFIG_ENV_DEFAULT_ENV_TEXT_FILE="defenvs/an7581_w1700k_env"
+CONFIG_SHA512=y
--- /dev/null
+++ b/defenvs/an7581_w1700k_env
@@ -0,0 +1,27 @@
+loadaddr=0x81800000
+initaddr=0x89000000
+ipaddr=192.168.1.1
+serverip=192.168.1.10
+bootfile=immortalwrt-airoha-an7581-gemtek_w1700k-ubi-initramfs-recovery.itb
+installfile=immortalwrt-airoha-an7581-gemtek_w1700k-ubi-initramfs-installer.itb
+bootled_pwr=status:red
+bootled_rec=status:blue
+boot_ubi=ubi part ubi && run boot_production ; run boot_recovery
+boot_production=led $bootled_pwr on ; run ubi_read_production && bootm $loadaddr#$bootconf ; led $bootled_pwr off
+boot_recovery=led $bootled_rec on ; run ubi_read_recovery ; bootm $initaddr#$bootconf ; led $bootled_rec off
+boot_tftp=tftpboot $initaddr $bootfile && bootm $initaddr#$bootconf
+boot_installer=tftpboot $initaddr $installfile && bootm $initaddr#$bootconf
+bootconf=config-1
+bootcmd=boot_ubi
+bootdelay=3
+bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60
+bootmenu_default=0
+bootmenu_delay=3
+bootmenu_title=      34m( ( ( mOpenWrt34m ) ) )
+bootmenu_0=Run default boot command.=run boot_production
+bootmenu_1=Boot system via TFTP.=run boot_tftp ; run bootmenu_confirm_return
+bootmenu_2=Boot recovery system from flash.=run boot_recovery ; run bootmenu_confirm_return
+bootmenu_3=Boot installer via TFTP.=run boot_installer ; run bootmenu_confirm_return
+bootmenu_4=Reboot.=reset
+ubi_read_production=ubi read $loadaddr fit && iminfo $loadaddr
+ubi_read_recovery=ubi check recovery && ubi read $initaddr recovery
--- /dev/null
+++ b/dts/upstream/src/arm64/airoha/an7581-w1700k-ubi.dts
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/dts-v1/;
+
+/* Bootloader installs ATF here */
+/memreserve/ 0x80000000 0x200000;
+
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/gpio/gpio.h>
+#include "en7581.dtsi"
+
+/ {
+	model = "Gemtek W1700K (UBI)";
+	compatible = "gemtek,w1700k-ubi", "airoha,an7581", "airoha,en7581";
+
+	aliases {
+		serial0 = &uart1;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+		linux,usable-memory-range = <0x0 0x80200000 0x0 0x7fe00000>;
+	};
+
+	memory@80000000 {
+		device_type = "memory";
+		reg = <0x0 0x80000000 0x2 0x00000000>;
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		key-restart {
+			label = "reset";
+			gpios = <&en7581_pinctrl 0 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_RESTART>;
+		};
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+
+		led_status_green {
+			label = "status:green";
+			gpios = <&en7581_pinctrl 17 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led_status_blue {
+			label = "status:blue";
+			gpios = <&en7581_pinctrl 19 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led_status_red {
+			label = "status:red";
+			gpios = <&en7581_pinctrl 29 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+
+		led_status_white {
+			label = "status:white";
+			gpios = <&en7581_pinctrl 20 GPIO_ACTIVE_LOW>;
+			default-state = "off";
+		};
+	};
+};
+
+&snfi {
+	status = "okay";
+};
+
+&spi_nand {
+	partitions {
+		compatible = "fixed-partitions";
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		vendor@0 {
+			label = "vendor";
+			reg = <0x00000000 0x00600000>;
+			read-only;
+		};
+
+		chainloader@600000 {
+			label = "chainloader";
+			reg = <0x00600000 0x00100000>;
+			read-only;
+		};
+
+		ubi@700000 {
+			label = "ubi";
+			reg = <0x00700000 0x1f700000>;
+		};
+
+		/* reserved for bad block table */
+		reserved_bmt@1fe00000 {
+			label = "reserved_bmt";
+			reg = <0x1fe00000 0x00200000>;
+			read-only;
+		};
+	};
+};
+
+&en7581_pinctrl {
+	gpio-ranges = <&en7581_pinctrl 0 13 47>;
+
+	pcie0_rst_pins: pcie0-rst-pins {
+		conf {
+			pins = "pcie_reset0";
+			drive-open-drain = <1>;
+		};
+	};
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_rst_pins>;
+	status = "okay";
+};
+
+&i2c0 {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+};
+
+&gdm1 {
+	status = "okay";
+};
