2023-12-03 01:23:17 +01:00
|
|
|
{
|
|
|
|
system = {
|
|
|
|
crossSystem = {
|
|
|
|
config = "mipsel-unknown-linux-musl";
|
|
|
|
gcc = {
|
|
|
|
abi = "32";
|
|
|
|
arch = "mips32"; # mips32r2?
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
description = ''
|
|
|
|
Zyxel NWA50AX
|
|
|
|
********************
|
|
|
|
|
|
|
|
Zyxel NWA50AX is quite close to the GL-MT300N-v2 "Mango" device, but it is based on the MT7621
|
|
|
|
chipset instead of the MT7628.
|
|
|
|
|
|
|
|
Installation
|
|
|
|
============
|
|
|
|
|
2024-02-19 02:57:29 +01:00
|
|
|
This device is pretty, but, due to its A/B capabilities, can be a bit hard
|
|
|
|
to use completely.
|
2023-12-03 01:23:17 +01:00
|
|
|
|
2024-02-19 02:57:29 +01:00
|
|
|
The stock vendor firmware is a downstream fork of U-Boot: <https://github.com/RaitoBezarius/uboot-nwa50ax>
|
2023-12-03 01:23:17 +01:00
|
|
|
with restricted boot commands. Fortunately, OpenWrt folks figured out trivial command injections,
|
|
|
|
so you can use most of the OpenWrt commands without trouble by just command injecting
|
|
|
|
atns, atna or atnf, e.g. atns "; $real_command".
|
|
|
|
|
2024-02-19 02:57:29 +01:00
|
|
|
From factory web UI, you can upload the result of the zyxel-nwa-fit output.
|
|
|
|
From another operating system, you need to `dumpimage -T flat_dt -p 0 $zyxel-nwa-fit -o firmware.bin`,
|
|
|
|
`flash_erase $(mtd partition of the target partition firmware or zy_firmware) 0 0`, then you complete by
|
|
|
|
`nandwrite -p $(mtd partition of the target partition firmware or zy_firmware) firmware.bin`.
|
|
|
|
|
|
|
|
How to put the firmware.bin on the machine is left to you as an exercise, e.g. SSH, TFTP, whatever.
|
|
|
|
|
2023-12-03 01:23:17 +01:00
|
|
|
From serial, you have two choices:
|
|
|
|
|
2024-02-19 02:57:29 +01:00
|
|
|
- Flash this system via U-Boot:
|
|
|
|
same reasoning as from an existing Linux system, two choices:
|
|
|
|
- ymodem the binary, perform the write manually, you can inspire yourself
|
|
|
|
from the `script` contained in the vendor firmware, those are just a FIT containing a script.
|
|
|
|
- prepare a FIT containing a script executing your commands, tftpboot this.
|
|
|
|
|
2023-12-03 01:23:17 +01:00
|
|
|
- boot from an existing Liminix system, e.g. TFTPBOOT image.
|
|
|
|
- boot from an OpenWrt system, i.e. follow OpenWrt steps.
|
|
|
|
|
|
|
|
Once you are in a Linux system, understand that this device has A/B boot.
|
|
|
|
|
|
|
|
OpenWrt provides you with `zyxel-bootconfig` to set/unset the image status and choice.
|
2024-02-19 02:57:29 +01:00
|
|
|
|
2023-12-03 01:23:17 +01:00
|
|
|
The kernel is booted with `bootImage=<number>` which tells you which slot are you on.
|
|
|
|
|
|
|
|
You should find yourself with 10ish MTD partitions, the most interesting ones are two:
|
|
|
|
|
|
|
|
- firmware: 40MB
|
|
|
|
- firmware_1: 40MB
|
|
|
|
|
|
|
|
In the current setup, they are split further into kernel (8MB) and ubi (32MB).
|
|
|
|
|
2024-02-19 02:57:29 +01:00
|
|
|
Once you are done with first installation, note that if you want to use the A/B feature,
|
|
|
|
you need to write a _secondary_ image on the slot B. There is no proper flashing code
|
|
|
|
that will set the being-updated slot to `new` and boot on it to verify if it's working.
|
|
|
|
This is a WIP.
|
|
|
|
|
|
|
|
Upgrading your system can be achieved via:
|
|
|
|
|
|
|
|
- `liminix-rebuild` for the userspace.
|
|
|
|
- `flash_erase` + `nandwrite` for the kernelspace to the other slot than the one you are booted on,
|
|
|
|
note that you can just nandwrite the mtd partition corresponding to the *kernel* and not the whole firmware.
|
|
|
|
|
|
|
|
If you soft-bricked your AP, i.e. you cannot boot anything in U-Boot, no worries, just plug the serial console,
|
|
|
|
prepare a TFTP server (via `tufted` for example), download vendor firmware, set up `atns`, `atnf`, etc. and run `atnz`.
|
2023-12-03 01:23:17 +01:00
|
|
|
|
2024-02-19 02:57:29 +01:00
|
|
|
This will reflash everything back to normal via TFTP.
|
2023-12-03 01:23:17 +01:00
|
|
|
|
2024-02-19 02:57:29 +01:00
|
|
|
If you hard-bricked your AP, i.e. U-Boot is telling you to transfer a valid bootloader via ymodem, just extract
|
|
|
|
a U-Boot from the vendor OS, send it via ymodem and use the previous operations to perform a full flash this time
|
|
|
|
of all partitions.
|
2023-12-03 01:23:17 +01:00
|
|
|
|
2024-02-19 02:57:29 +01:00
|
|
|
Note that if you erased your MRD partition, you lost your serial and MAC address. There's no way to recover the original one
|
|
|
|
except by reading the physical label on your… device!
|
2023-12-03 01:23:17 +01:00
|
|
|
|
2024-02-19 02:57:29 +01:00
|
|
|
If you super-hard-bricked your AP, i.e. no output on serial console, congratulations, you reached one of the rare state
|
|
|
|
of this device. You need an external NAND flasher to repair it and write the first stage from Mediatek to continue the previous
|
|
|
|
recovery operations.
|
2023-12-03 01:23:17 +01:00
|
|
|
|
2024-02-19 03:05:22 +01:00
|
|
|
Development TODO list:
|
|
|
|
|
|
|
|
- Better support for upgrade automation w.r.t. to A/B, e.g. automagic scripts.
|
|
|
|
- Mount the logs partition, mount / as overlayfs of firmware ? rootfs and rootfs_data for extended data.
|
|
|
|
- Jitter-based entropy injection? Device can be slow to initialize its CRNG and hostapd will reject few clients at the start because of that.
|
|
|
|
- Defaults for hostapd based on MT7915 capabilities? See the example for one possible list.
|
|
|
|
- Offer ways to reflash the *bootloader* itself to support direct boot via UBI and kernel upgrades via filesystem rewrite.
|
|
|
|
|
2023-12-03 01:23:17 +01:00
|
|
|
Vendor web page: https://www.zyxel.com/fr/fr/products/wireless/ax1800-wifi-6-dual-radio-nebulaflex-access-point-nwa50ax
|
|
|
|
|
|
|
|
OpenWrt web page: https://openwrt.org/inbox/toh/zyxel/nwa50ax
|
|
|
|
OpenWrt tech data: https://openwrt.org/toh/hwdata/zyxel/zyxel_nwa50ax
|
|
|
|
|
|
|
|
'';
|
|
|
|
|
|
|
|
module = { pkgs, config, lib, lim, ...}:
|
|
|
|
let
|
|
|
|
inherit (pkgs.liminix.networking) interface;
|
|
|
|
inherit (pkgs.liminix.services) oneshot;
|
|
|
|
inherit (pkgs.pseudofile) dir symlink;
|
|
|
|
inherit (pkgs) openwrt;
|
|
|
|
|
|
|
|
mac80211 = pkgs.mac80211.override {
|
|
|
|
drivers = [ "mt7915e" ];
|
|
|
|
klibBuild = config.system.outputs.kernel.modulesupport;
|
|
|
|
};
|
2024-02-19 02:48:40 +01:00
|
|
|
# v204520220929
|
2023-12-03 01:23:17 +01:00
|
|
|
wlan_firmware = pkgs.fetchurl {
|
2024-02-19 02:48:40 +01:00
|
|
|
url = "https://github.com/openwrt/mt76/raw/1b88dd07f153b202e57fe29734806744ed006b0e/firmware/mt7915_wa.bin";
|
2023-12-03 01:23:17 +01:00
|
|
|
hash = "sha256-wooyefzb0i8640+lwq3vNhcBXRFCtGuo+jiL7afZaKA=";
|
|
|
|
};
|
|
|
|
wlan_firmware' = pkgs.fetchurl {
|
2024-02-19 02:48:40 +01:00
|
|
|
url = "https://github.com/openwrt/mt76/raw/1b88dd07f153b202e57fe29734806744ed006b0e/firmware/mt7915_wm.bin";
|
2023-12-03 01:23:17 +01:00
|
|
|
hash = "sha256-k62nQewRuKjBLd5R3RxU4F74YKnQx5zr6gqMMImqVQw=";
|
|
|
|
};
|
|
|
|
wlan_firmware'' = pkgs.fetchurl {
|
2024-02-19 02:48:40 +01:00
|
|
|
url = "https://github.com/openwrt/mt76/raw/1b88dd07f153b202e57fe29734806744ed006b0e/firmware/mt7915_rom_patch.bin";
|
2023-12-03 01:23:17 +01:00
|
|
|
hash = "sha256-ifriAjWzFACrxVWCANZpUaEZgB/0pdbhnTVQytx6ddg=";
|
|
|
|
};
|
|
|
|
in {
|
|
|
|
imports = [
|
2024-02-19 01:20:01 +01:00
|
|
|
# We include it to ensure the bridge functionality
|
|
|
|
# is available on the target kernel.
|
|
|
|
../../modules/bridge
|
2023-12-03 01:23:17 +01:00
|
|
|
../../modules/arch/mipsel.nix
|
|
|
|
../../modules/outputs/tftpboot.nix
|
|
|
|
../../modules/outputs/zyxel-nwa-fit.nix
|
2024-02-18 22:35:27 +01:00
|
|
|
../../modules/zyxel-dual-image
|
2023-12-03 01:23:17 +01:00
|
|
|
];
|
|
|
|
|
|
|
|
filesystem = dir {
|
|
|
|
lib = dir {
|
|
|
|
firmware = dir {
|
|
|
|
mediatek = dir {
|
|
|
|
"mt7915_wa.bin" = symlink wlan_firmware;
|
|
|
|
"mt7915_wm.bin" = symlink wlan_firmware';
|
|
|
|
"mt7915_rom_patch.bin" = symlink wlan_firmware'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
rootfsType = "ubifs";
|
|
|
|
hardware = {
|
|
|
|
# Taken from OpenWRT
|
|
|
|
# root@OpenWrt:/# ubinfo /dev/ubi0
|
|
|
|
# ubi0
|
|
|
|
# Volumes count: 2
|
|
|
|
# Logical eraseblock size: 126976 bytes, 124.0 KiB
|
|
|
|
# Total amount of logical eraseblocks: 256 (32505856 bytes, 31.0 MiB)
|
|
|
|
# Amount of available logical eraseblocks: 0 (0 bytes)
|
|
|
|
# Maximum count of volumes 128
|
|
|
|
# Count of bad physical eraseblocks: 0
|
|
|
|
# Count of reserved physical eraseblocks: 19
|
|
|
|
# Current maximum erase counter value: 2
|
|
|
|
# Minimum input/output unit size: 2048 bytes
|
|
|
|
# Character device major/minor: 250:0
|
|
|
|
# Present volumes: 0, 1
|
|
|
|
ubi = {
|
|
|
|
minIOSize = "2048";
|
|
|
|
logicalEraseBlockSize = "126976";
|
|
|
|
physicalEraseBlockSize = "128KiB";
|
|
|
|
maxLEBcount = "256";
|
|
|
|
};
|
|
|
|
|
2024-08-26 18:24:44 +02:00
|
|
|
flash.eraseBlockSize = 64 * 1024;
|
2024-04-21 17:26:31 +02:00
|
|
|
|
2023-12-03 01:23:17 +01:00
|
|
|
# This is a FIT containing a kernel padded and
|
|
|
|
# a UBI volume rootfs.
|
|
|
|
defaultOutput = "zyxel-nwa-fit";
|
2024-02-19 01:20:19 +01:00
|
|
|
|
2023-12-03 01:23:17 +01:00
|
|
|
loadAddress = lim.parseInt "0x80001000";
|
|
|
|
entryPoint = lim.parseInt "0x80001000";
|
|
|
|
# Aligned on 2kb.
|
|
|
|
alignment = 2048;
|
|
|
|
|
2024-08-26 18:32:46 +02:00
|
|
|
rootDevice = "ubi0:rootfs";
|
|
|
|
alternativeRootDevice = "ubi1:rootfs";
|
2024-04-21 17:26:31 +02:00
|
|
|
|
|
|
|
# Auto-attach MTD devices: ubi_a then ubi_b.
|
|
|
|
ubi.mtds = [ "ubi_a" "ubi_b" ];
|
2023-12-03 01:23:17 +01:00
|
|
|
|
|
|
|
dts = {
|
2024-04-21 17:26:31 +02:00
|
|
|
# Strong DTB assumptions:
|
|
|
|
# ubi_a and ubi_b are two MTD devices.
|
|
|
|
# If those changes, disaster will occur.
|
|
|
|
src = ./dtb/mt7621_zyxel_nwa50ax.dtsi;
|
2023-12-03 01:23:17 +01:00
|
|
|
includes = [
|
2024-04-21 17:26:31 +02:00
|
|
|
"${./dtb}"
|
2023-12-03 01:23:17 +01:00
|
|
|
"${openwrt.src}/target/linux/ramips/dts"
|
|
|
|
];
|
|
|
|
};
|
|
|
|
networkInterfaces =
|
|
|
|
let
|
|
|
|
inherit (config.system.service.network) link;
|
|
|
|
in {
|
|
|
|
eth = link.build { ifname = "eth0"; };
|
|
|
|
lan = link.build { ifname = "lan"; };
|
|
|
|
wlan0 = link.build {
|
|
|
|
ifname = "wlan0";
|
|
|
|
dependencies = [ mac80211 ];
|
|
|
|
};
|
|
|
|
wlan1 = link.build {
|
|
|
|
ifname = "wlan1";
|
|
|
|
dependencies = [ mac80211 ];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
2024-02-18 22:35:27 +01:00
|
|
|
|
2023-12-03 01:23:17 +01:00
|
|
|
boot = {
|
|
|
|
# Critical because NWA50AX will extend your cmdline with the image number booted.
|
|
|
|
# and some bootloader version.
|
|
|
|
# You don't want to find yourself being overridden.
|
|
|
|
commandLineDtbNode = "bootargs-override";
|
|
|
|
|
|
|
|
imageFormat = "fit";
|
|
|
|
tftp = {
|
2024-09-07 23:38:18 +02:00
|
|
|
# 20MB is pretty good on this device as we have plenty of RAM.
|
|
|
|
freeSpaceBytes = 20 * 1024 * 1024;
|
2024-08-26 18:38:01 +02:00
|
|
|
appendDTB = true;
|
2023-12-03 01:23:17 +01:00
|
|
|
loadAddress = lim.parseInt "0x2000000";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2024-02-18 22:35:27 +01:00
|
|
|
# Dual image management service in userspace.
|
|
|
|
services.zyxel-dual-image = config.boot.zyxel-dual-image.build {
|
|
|
|
ensureActiveImage = "primary";
|
|
|
|
# TODO: use mtd names rather…
|
2024-02-19 03:13:35 +01:00
|
|
|
# primary and secondary are always /dev/mtd3 by virtue of the
|
|
|
|
# dtb being not too wrong…
|
|
|
|
# TODO: remove this hack.
|
2024-02-18 22:35:27 +01:00
|
|
|
primaryMtdPartition = "/dev/mtd3";
|
2024-02-19 03:13:35 +01:00
|
|
|
secondaryMtdPartition = "/dev/mtd3";
|
|
|
|
bootConfigurationMtdPartition = "/dev/mtd12";
|
2024-02-18 22:35:27 +01:00
|
|
|
};
|
|
|
|
|
2023-12-03 01:23:17 +01:00
|
|
|
# DEVICE_VENDOR := ZyXEL
|
|
|
|
# KERNEL_SIZE := 8192k
|
|
|
|
# DEVICE_PACKAGES := kmod-mt7915-firmware zyxel-bootconfig
|
|
|
|
# KERNEL := kernel-bin | lzma | fit lzma $$(KDIR)/image-$$(firstword $$(DEVICE_DTS)).dtb
|
|
|
|
# IMAGES += factory.bin ramboot-factory.bin
|
|
|
|
# IMAGE/factory.bin := append-kernel | pad-to $$(KERNEL_SIZE) | append-ubi | zyxel-nwa-fit
|
|
|
|
# IMAGE/ramboot-factory.bin := append-kernel | pad-to $$(KERNEL_SIZE) | append-ubi
|
|
|
|
|
|
|
|
kernel = {
|
|
|
|
src = pkgs.fetchurl {
|
|
|
|
name = "linux.tar.gz";
|
|
|
|
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
|
|
|
|
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
|
|
|
|
};
|
|
|
|
extraPatchPhase = ''
|
|
|
|
${openwrt.applyPatches.ramips}
|
|
|
|
|
|
|
|
'';
|
|
|
|
config = {
|
|
|
|
|
|
|
|
RALINK = "y";
|
|
|
|
PCI = "y";
|
|
|
|
PHY_MT7621_PCI = "y";
|
|
|
|
PCIE_MT7621 = "y";
|
|
|
|
SOC_MT7621 = "y";
|
|
|
|
CLK_MT7621 = "y";
|
|
|
|
CLOCKSOURCE_WATCHDOG = "y";
|
|
|
|
|
|
|
|
SERIAL_8250_CONSOLE = "y";
|
|
|
|
SERIAL_8250 = "y";
|
|
|
|
SERIAL_CORE_CONSOLE = "y";
|
|
|
|
SERIAL_OF_PLATFORM = "y";
|
|
|
|
SERIAL_8250_NR_UARTS = "3";
|
|
|
|
SERIAL_8250_RUNTIME_UARTS = "3";
|
|
|
|
SERIAL_MCTRL_GPIO = "y";
|
|
|
|
|
|
|
|
CONSOLE_LOGLEVEL_DEFAULT = "8";
|
|
|
|
CONSOLE_LOGLEVEL_QUIET = "4";
|
|
|
|
|
|
|
|
# MTD_UBI_BEB_LIMIT = "20";
|
|
|
|
# MTD_UBI_WL_THRESHOLD = "4096";
|
|
|
|
|
|
|
|
MTD = "y";
|
|
|
|
MTD_BLOCK = "y"; # fix undefined ref to register_mtd_blktrans_dev
|
|
|
|
MTD_RAW_NAND = "y";
|
|
|
|
MTD_NAND_MT7621 = "y";
|
|
|
|
MTD_NAND_MTK_BMT = "y"; # Bad-block Management Table
|
|
|
|
MTD_NAND_ECC_SW_HAMMING= "y";
|
|
|
|
MTD_SPI_NAND= "y";
|
|
|
|
MTD_OF_PARTS = "y";
|
|
|
|
MTD_NAND_CORE= "y";
|
|
|
|
MTD_SPLIT_FIRMWARE= "y";
|
|
|
|
MTD_SPLIT_FIT_FW= "y";
|
|
|
|
|
|
|
|
PINCTRL = "y";
|
|
|
|
PINCTRL_MT7621 = "y";
|
|
|
|
|
|
|
|
I2C = "y";
|
|
|
|
I2C_MT7621 = "y";
|
|
|
|
|
|
|
|
SPI = "y";
|
|
|
|
MTD_SPI_NOR = "y";
|
|
|
|
SPI_MT7621 = "y";
|
|
|
|
SPI_MASTER = "y";
|
|
|
|
SPI_MEM = "y";
|
|
|
|
|
|
|
|
REGULATOR = "y";
|
|
|
|
REGULATOR_FIXED_VOLTAGE = "y";
|
|
|
|
RESET_CONTROLLER = "y";
|
|
|
|
POWER_RESET = "y";
|
|
|
|
POWER_RESET_GPIO = "y";
|
|
|
|
POWER_SUPPLY = "y";
|
|
|
|
LED_TRIGGER_PHY = "y";
|
|
|
|
|
|
|
|
PCI_DISABLE_COMMON_QUIRKS = "y";
|
|
|
|
PCI_DOMAINS = "y";
|
|
|
|
PCI_DOMAINS_GENERIC = "y";
|
|
|
|
PCI_DRIVERS_GENERIC = "y";
|
|
|
|
PCS_MTK_LYNXI = "y";
|
|
|
|
|
|
|
|
SOC_BUS = "y";
|
|
|
|
|
|
|
|
NET = "y";
|
|
|
|
ETHERNET = "y";
|
|
|
|
WLAN = "y";
|
|
|
|
|
|
|
|
PHYLIB = "y";
|
|
|
|
AT803X_PHY = "y";
|
|
|
|
FIXED_PHY = "y";
|
|
|
|
GENERIC_PHY = "y";
|
|
|
|
NET_DSA = "y";
|
|
|
|
NET_DSA_MT7530 = "y";
|
|
|
|
NET_DSA_MT7530_MDIO = "y";
|
|
|
|
NET_DSA_TAG_MTK = "y";
|
|
|
|
NET_MEDIATEK_SOC = "y";
|
|
|
|
NET_SWITCHDEV = "y";
|
|
|
|
NET_VENDOR_MEDIATEK = "y";
|
|
|
|
|
|
|
|
SWPHY = "y";
|
|
|
|
|
|
|
|
GPIOLIB = "y";
|
|
|
|
GPIO_MT7621 = "y";
|
|
|
|
OF_GPIO = "y";
|
|
|
|
|
|
|
|
EARLY_PRINTK = "y";
|
|
|
|
|
|
|
|
NEW_LEDS = "y";
|
|
|
|
LEDS_TRIGGERS = "y";
|
|
|
|
LEDS_CLASS = "y"; # required by rt2x00lib
|
|
|
|
LEDS_CLASS_MULTICOLOR = "y";
|
|
|
|
LEDS_BRIGHTNESS_HW_CHANGED = "y";
|
|
|
|
|
|
|
|
PRINTK_TIME = "y";
|
|
|
|
} // lib.optionalAttrs (config.system.service ? vlan) {
|
|
|
|
SWCONFIG = "y";
|
|
|
|
} // lib.optionalAttrs (config.system.service ? watchdog) {
|
|
|
|
RALINK_WDT = "y"; # watchdog
|
|
|
|
MT7621_WDT = "y"; # or it might be this one
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|