#!/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.