BL31_IMAGE:=an7583-bl31.bin
endef
+define U-Boot/an7581_gemtek_w1700k
+ NAME:=Gemtek W1700K (UBI)
+ UBOOT_CONFIG:=an7581_w1700k
+ BUILD_DEVICES:=gemtek_w1700k-ubi
+ BUILD_SUBTARGET:=an7581
+ UBOOT_IMAGE:=u-boot.bin
+endef
+
UBOOT_TARGETS := \
en7523_rfb \
an7581_rfb \
- an7583_rfb
+ an7583_rfb \
+ an7581_gemtek_w1700k
UBOOT_CUSTOMIZE_CONFIG := \
--disable TOOLS_KWBIMAGE \
endef
define Build/fip-image
- $(if $(LZMA_COMPRESS), $(STAGING_DIR_HOST)/bin/lzma e \
- $(PKG_BUILD_DIR)/u-boot.bin \
- $(PKG_BUILD_DIR)/u-boot.bin.lzma)
$(if $(LZMA_COMPRESS), $(STAGING_DIR_HOST)/bin/lzma e \
files/$(BL31_IMAGE) \
$(PKG_BUILD_DIR)/bl31.bin.lzma)
define Build/Compile
$(call Build/Compile/U-Boot)
+ $(if $(LZMA_COMPRESS), $(STAGING_DIR_HOST)/bin/lzma e \
+ $(PKG_BUILD_DIR)/u-boot.bin \
+ $(PKG_BUILD_DIR)/u-boot.bin.lzma)
ifeq ($(UBOOT_IMAGE),u-boot.fip)
$(call Build/fip-image-bl2)
$(call Build/fip-image)
ifeq ($(UBOOT_IMAGE),u-boot.fip)
$(INSTALL_DATA) $(PKG_BUILD_DIR)/bl2.fip $(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-bl2.fip
$(INSTALL_DATA) $(PKG_BUILD_DIR)/u-boot.fip $(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-bl31-u-boot.fip
+else
+ $(INSTALL_DATA) $(PKG_BUILD_DIR)/u-boot.bin$(if $(LZMA_COMPRESS),.lzma) \
+ $(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-u-boot.bin$(if $(LZMA_COMPRESS),.lzma)
+ $(INSTALL_DATA) $(PKG_BUILD_DIR)/u-boot.dtb \
+ $(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-u-boot.dtb
endif
endef
--- /dev/null
+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=openwrt-airoha-an7581-gemtek_w1700k-ubi-initramfs-recovery.itb
++installfile=openwrt-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";
++};
++
++ð {
++ status = "okay";
++};
++
++&gdm1 {
++ status = "okay";
++};