#!/bin/sh
# openwrt_one_flash_nor.sh
# 2025-04-21
# by Gernot Walzl
# OpenWrt One: Boot via UART and Flash NOR via TFTP
# The NOR flash chip contains the recovery system of the OpenWrt One.
# By default, this chip is write-protected. To unprotect it,
# a jumper needs to be in place at NOR WP.
# For UART, the USB-C port CONSOLE needs to be connected to the PC.
# For TFTP, the RJ45 port 1G needs to be connected to the PC too.
# The present script needs to be executed before the OpenWrt One boots.
# https://openwrt.org/toh/openwrt/one
# On Debian,
# the following packages are required:
# $ sudo apt install dnsmasq screen
# the user needs permission to access /dev/ttyACM0:
# $ sudo usermod -a -G dialout $USER
# the firewall needs to be disabled:
# $ sudo nft flush ruleset
OPENWRT_VERSION='24.10.1'
OPENWRT_DLURL='https://downloads.openwrt.org'
OPENWRT_DLDIR="releases/${OPENWRT_VERSION}/targets/mediatek/filogic"
OPENWRT_DIR="openwrt/${OPENWRT_DLDIR}"
OPENWRT_FILES="mt7981-ram-ddr4-bl2.bin
openwrt-${OPENWRT_VERSION}-mediatek-filogic-openwrt_one-nor-bl31-uboot.fip
openwrt-${OPENWRT_VERSION}-mediatek-filogic-openwrt_one-nor-preloader.bin
openwrt-${OPENWRT_VERSION}-mediatek-filogic-openwrt_one-initramfs.itb"
MTK_UARTBOOT_VERSION='0.1.1'
MTK_UARTBOOT_DLURL='https://github.com/981213/mtk_uartboot/releases/download'
MTK_UARTBOOT_DIR="mtk_uartboot-v${MTK_UARTBOOT_VERSION}-x86_64-unknown-linux-gnu"
MTK_UARTBOOT_FILE="${MTK_UARTBOOT_DIR}.tar.gz"
CWD=$(pwd)
set -e
if [ ! -f "$MTK_UARTBOOT_FILE" ]; then
wget -O "$MTK_UARTBOOT_FILE" \
"${MTK_UARTBOOT_DLURL}/v${MTK_UARTBOOT_VERSION}/${MTK_UARTBOOT_FILE}"
fi
mkdir -p "$OPENWRT_DIR"
cd "$OPENWRT_DIR" || exit 1
for FILE in $OPENWRT_FILES; do
if [ ! -f "$FILE" ]; then
wget -O "$FILE" "${OPENWRT_DLURL}/${OPENWRT_DLDIR}/${FILE}"
fi
done
# 4. Load BL32+U-Boot FIP via TFTP then write to NOR.
if [ ! -e 'openwrt-mediatek-filogic-openwrt_one-nor-bl31-uboot.fip' ]; then
ln -s \
"openwrt-${OPENWRT_VERSION}-mediatek-filogic-openwrt_one-nor-bl31-uboot.fip" \
'openwrt-mediatek-filogic-openwrt_one-nor-bl31-uboot.fip'
fi
# 5. Load BL2 preloader via TFTP then write to NOR.
if [ ! -e 'openwrt-mediatek-filogic-openwrt_one-nor-preloader.bin' ]; then
ln -s \
"openwrt-${OPENWRT_VERSION}-mediatek-filogic-openwrt_one-nor-preloader.bin" \
'openwrt-mediatek-filogic-openwrt_one-nor-preloader.bin'
fi
# 6. Load recovery system via TFTP then write to NOR.
if [ ! -e 'openwrt-mediatek-filogic-openwrt_one-initramfs.itb' ]; then
ln -s \
"openwrt-${OPENWRT_VERSION}-mediatek-filogic-openwrt_one-initramfs.itb" \
'openwrt-mediatek-filogic-openwrt_one-initramfs.itb'
fi
cd "$CWD" || exit 1
# https://openwrt.org/docs/guide-user/troubleshooting/tftpserver#setting_up_a_tftp_server_on_linux
TFTP_IP='192.168.11.23' # TFTP server IP is hardcoded into recovery
TFTP_DEV=$(ls /sys/class/net | grep "^e") # manually specify if more than one ethernet devices are present
echo
echo "Setting IPv4 ${TFTP_IP} on ${TFTP_DEV}."
sudo ip addr add "${TFTP_IP}/24" dev "$TFTP_DEV" || true
PID_DNSMASQ=$(ps -C dnsmasq -opid,cmd | grep enable-tftp | awk '{ print $1 }')
if [ -n "$PID_DNSMASQ" ]; then
echo
echo "Killing already running dnsmasq (pid=${PID_DNSMASQ})."
kill "$PID_DNSMASQ"
fi
echo
echo "Serving the following files via TFTP:"
ls "${CWD}/${OPENWRT_DIR}"
sudo dnsmasq \
--listen-address="$TFTP_IP" \
--port=0 \
--enable-tftp \
--tftp-root="${CWD}/${OPENWRT_DIR}" \
--tftp-no-blocksize \
--user="$USER"
# https://openwrt.org/toh/openwrt/one#boot_into_uart_recoveryflash_nor_from_tftp
echo
tar xvf "$MTK_UARTBOOT_FILE"
echo
"${MTK_UARTBOOT_DIR}/mtk_uartboot" \
--aarch64 \
--brom-load-baudrate 115200 \
--bl2-load-baudrate 115200 \
-s /dev/ttyACM0 \
-p "${OPENWRT_DIR}/mt7981-ram-ddr4-bl2.bin" \
-f "${OPENWRT_DIR}/openwrt-mediatek-filogic-openwrt_one-nor-bl31-uboot.fip" \
&& screen /dev/ttyACM0 115200 # to kill screen, press CTRL+A, then K.