ramips: mt7621: Add support for ZyXEL NR7101
authorBjørn Mork <bjorn@mork.no>
Mon, 19 Apr 2021 11:00:56 +0000 (13:00 +0200)
committerPetr Štetiar <ynezz@true.cz>
Thu, 10 Jun 2021 15:09:35 +0000 (17:09 +0200)
The ZyXEL NR7101 is an 802.3at PoE powered 5G outdoor (IP68) CPE
with integrated directional 5G/LTE antennas.

Specifications:

 - SoC: MediaTek MT7621AT
 - RAM: 256 MB
 - Flash: 128 MB MB NAND (MX30LF1G18AC)
 - WiFi: MediaTek MT7603E
 - Switch: 1 LAN port (Gigabiti)
 - 5G/LTE: Quectel RG502Q-EA connected by USB3 to SoC
 - SIM: 2 micro-SIM slots under transparent cover
 - Buttons: Reset, WLAN under same cover
 - LEDs: Multicolour green/red/yellow under same cover (visible)
 - Power: 802.3at PoE via LAN port

The device is built as an outdoor ethernet to 5G/LTE bridge or
router. The Wifi interface is intended for installation and/or
temporary management purposes only.

UART Serial:

57600N1
Located on populated 5 pin header J5:

 [o] GND
 [ ] key - no pin
 [o] RX
 [o] TX
 [o] 3.3V Vcc

Remove the SIM/button/LED cover, the WLAN button and 12 screws
holding the back plate and antenna cover together. The GPS antenna
is fixed to the cover, so be careful with the cable.  Remove 4
screws fixing the antenna board to the main board, again being
careful with the cables.

A bluetooth TTL adapter is recommended for permanent console
access, to keep the router water and dustproof. The 3.3V pin is
able to power such an adapter.

MAC addresses:

OpenWrt OEM   Address          Found as
lan     eth2  08:26:97:*:*:BC  Factory 0xe000 (hex), label
wlan0   ra0   08:26:97:*:*:BD  Factory 0x4 (hex)
wwan0   usb0  random

WARNING!!

ISP managed firmware might at any time update itself to a version
where all known workarounds have been disabled.  Never boot an ISP
managed firmware with a SIM in any of the slots if you intend to use
the router with OpenWrt. The bootloader lock can only be disabled with
root access to running firmware. The flash chip is physically
inaccessible without soldering.

Installation from OEM web GUI:

- Log in as "supervisor" on https://172.17.1.1/
- Upload OpenWrt initramfs-recovery.bin image on the
  Maintenance -> Firmware page
- Wait for OpenWrt to boot and ssh to root@192.168.1.1
- (optional) Copy OpenWrt to the recovery partition. See below
- Sysupgrade to the OpenWrt sysupgrade image and reboot

Installation from OEM ssh:

- Log in as "root" on 172.17.1.1 port 22022
- scp OpenWrt initramfs-recovery.bin image to 172.17.1.1:/tmp
- Prepare bootloader config by running:
    nvram setro uboot DebugFlag 0x1
    nvram setro uboot CheckBypass 0
    nvram commit
- Run "mtd_write -w write initramfs-recovery.bin Kernel" and reboot
- Wait for OpenWrt to boot and ssh to root@192.168.1.1
- (optional) Copy OpenWrt to the recovery partition. See below
- Sysupgrade to the OpenWrt sysupgrade image and reboot

Copying OpenWrt to the recovery partition:

- Verify that you are running a working OpenWrt recovery image
  from flash
- ssh to root@192.168.1.1 and run:
    fw_setenv CheckBypass 0
    mtd -r erase Kernel2
- Wait while the bootloader mirrors Image1 to Image2

NOTE: This should only be done after successfully booting the OpenWrt
  recovery image from the primary partition during installation.  Do
  not do this after having sysupgraded OpenWrt!  Reinstalling the
  recovery image on normal upgrades is not required or recommended.

Installation from Z-Loader:

- Halt boot by pressing Escape on console
- Set up a tftp server to serve the OpenWrt initramfs-recovery.bin
  image at 10.10.10.3
- Type "ATNR 1,initramfs-recovery.bin" at the "ZLB>" prompt
- Wait for OpenWrt to boot and ssh to root@192.168.1.1
- Sysupgrade to the OpenWrt sysupgrade image

NOTE: ATNR will write the recovery image to both primary and recovery
  partitions in one go.

Booting from RAM:

- Halt boot by pressing Escape on console
- Type "ATGU" at the "ZLB>" prompt to enter the U-Boot menu
- Press "4" to select "4: Entr boot command line interface."
- Set up a tftp server to serve the OpenWrt initramfs-recovery.bin
  image at 10.10.10.3
- Load it using "tftpboot 0x88000000 initramfs-recovery.bin"
- Boot with "bootm  0x8800017C" to skip the 380 (0x17C) bytes ZyXEL
  header

This method can also be used to RAM boot OEM firmware. The warning
regarding OEM applies!  Never boot an unknown OEM firmware, or any OEM
firmware with a SIM in any slot.

NOTE: U-Boot configuration is incomplete (on some devices?). You may
  have to configure a working mac address before running tftp using
   "setenv eth0addr <mac>"

Unlocking the bootloader:

If you are unebale to halt boot, then the bootloader is locked.

The OEM firmware locks the bootloader on every boot by setting
DebugFlag to 0.  Setting it to 1 is therefore only temporary
when OEM firmware is installed.

- Run "nvram setro uboot DebugFlag 0x1; nvram commit" in OEM firmware
- Run "fw_setenv DebugFlag 0x1" in OpenWrt

  NOTE:
    OpenWrt does this automatically on first boot if necessary

  NOTE2:
    Setting the flag to 0x1 avoids the reset to 0 in known OEM
    versions, but this might change.

  WARNING:
    Writing anything to flash while the bootloader is locked is
    considered extremely risky. Errors might cause a permanent
    brick!

Enabling management access from LAN:

Temporary workaround to allow installing OpenWrt if OEM firmware
has disabled LAN management:

- Connect to console
- Log in as "root"
- Run "iptables -I INPUT -i br0 -j ACCEPT"

Notes on the OEM/bootloader dual partition scheme

The dual partition scheme on this device uses Image2 as a recovery
image only. The device will always boot from Image1, but the
bootloader might copy Image2 to Image1 under specific conditions. This
scheme prevents repurposing of the space occupied by Image2 in any
useful way.

Validation of primary and recovery images is controlled by the
variables CheckBypass, Image1Stable, and Image1Try.

The bootloader sets CheckBypass to 0 and reboots if Image1 fails
validation.

If CheckBypass is 0 and Image1 is invalid then Image2 is copied to
Image1.

If CheckBypass is 0 and Image2 is invalid, then Image1 is copied to
Image2.

If CheckBypass is 1 then all tests are skipped and Image1 is booted
unconditionally.  CheckBypass is set to 1 after each successful
validation of Image1.

Image1Try is incremented if Image1Stable is 0, and Image2 is copied to
Image1 if Image1Try is 3 or larger.  But the bootloader only tests
Image1Try if CheckBypass is 0, which is impossible unless the booted
image sets it to 0 before failing.

The system is therefore not resilient against runtime errors like
failure to mount the rootfs, unless the kernel image sets CheckBypass
to 0 before failing. This is not yet implemented in OpenWrt.

Setting Image1Stable to 1 prevents the bootloader from updating
Image1Try on every boot, saving unnecessary writes to the environment
partition.

Keeping an OpenWrt initramfs recovery as Image2 is recommended
primarily to avoid unwanted OEM firmware boots on failure. Ref the
warning above. It enables console-less recovery in case of some
failures to boot from Image1.

Signed-off-by: Bjørn Mork <bjorn@mork.no>
Tested-by: Bjørn Mork <bjorn@mork.no>
(cherry picked from commit 2449a632084b29632605e5a79ce5d73028eb15dd)

package/boot/uboot-envtools/files/ramips
target/linux/ramips/dts/mt7621_zyxel_nr7101.dts [new file with mode: 0644]
target/linux/ramips/image/mt7621.mk
target/linux/ramips/mt7621/base-files/etc/board.d/02_network
target/linux/ramips/mt7621/base-files/etc/board.d/03_gpio_switches
target/linux/ramips/mt7621/base-files/etc/init.d/bootcount
target/linux/ramips/mt7621/base-files/lib/upgrade/platform.sh

index a47e295..c153b6a 100644 (file)
@@ -54,6 +54,11 @@ xiaomi,mi-router-ac2100|\
 xiaomi,redmi-router-ac2100)
        ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x1000" "0x20000"
        ;;
+zyxel,nr7101)
+       idx="$(find_mtd_index Config)"
+       [ -n "$idx" ] && \
+               ubootenv_add_uci_config "/dev/mtd$idx" "0x0" "0x1000" "0x80000"
+       ;;
 esac
 
 config_load ubootenv
diff --git a/target/linux/ramips/dts/mt7621_zyxel_nr7101.dts b/target/linux/ramips/dts/mt7621_zyxel_nr7101.dts
new file mode 100644 (file)
index 0000000..f6a4228
--- /dev/null
@@ -0,0 +1,164 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+
+#include "mt7621.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+       compatible = "zyxel,nr7101", "mediatek,mt7621-soc";
+       model = "ZyXEL NR7101";
+
+       aliases {
+               led-boot = &power;
+               led-failsafe = &power;
+               led-running = &power;
+               led-upgrade = &power;
+               label-mac-device = &gmac0;
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               led@13 {
+                       label = "yellow:system";
+                       gpios = <&gpio 13 GPIO_ACTIVE_HIGH>;
+               };
+
+               power: led@14 {
+                       label = "green:system";
+                       gpios = <&gpio 14 GPIO_ACTIVE_HIGH>;
+               };
+
+               led@15 {
+                       label = "red:system";
+                       gpios = <&gpio 15 GPIO_ACTIVE_HIGH>;
+               };
+       };
+
+       keys {
+               compatible = "gpio-keys";
+
+               wps {
+                       label = "wlan";
+                       gpios = <&gpio 8 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_WLAN>;
+               };
+
+               reset {
+                       label = "reset";
+                       gpios = <&gpio 6 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_RESTART>;
+               };
+       };
+};
+
+&gpio {
+       lte_pwrkey {
+               gpio-hog;
+               gpios = <4 GPIO_ACTIVE_HIGH>;
+               output-high;
+               line-name = "lte-pwrkey";
+       };
+
+       lte_power {
+               gpio-hog;
+               gpios = <18 GPIO_ACTIVE_HIGH>;
+               output-high;
+               line-name = "lte-power";
+       };
+};
+
+&nand {
+       status = "okay";
+
+       partitions {
+               compatible = "fixed-partitions";
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               partition@0 {
+                       label = "Bootloader";
+                       reg = <0x0 0x80000>;
+                       read-only;
+               };
+
+               partition@80000 {
+                       label = "Config";
+                       reg = <0x80000 0x80000>;
+               };
+
+               factory: partition@100000 {
+                       label = "Factory";
+                       reg = <0x100000 0x40000>;
+                       read-only;
+               };
+
+               partition@140000 {
+                       label = "Kernel";
+                       reg = <0x140000 0x1ec0000>;
+               };
+
+               partition@540000 {
+                       label = "ubi";
+                       reg = <0x540000 0x1ac0000>;
+               };
+
+               partition@2140000 {
+                       label = "Kernel2";
+                       reg = <0x2140000 0x1ec0000>;
+               };
+
+               partition@4000000 {
+                       label = "wwan";
+                       reg = <0x4000000 0x100000>;
+               };
+
+               partition@4100000 {
+                       label = "data";
+                       reg = <0x4100000 0x1000000>;
+               };
+
+               partition@5100000 {
+                       label = "rom-d";
+                       reg = <0x5100000 0x100000>;
+                       read-only;
+               };
+
+               partition@5200000 {
+                       label = "reserve";
+                       reg = <0x5200000 0x80000>;
+               };
+       };
+};
+
+&pcie {
+       status = "okay";
+};
+
+&pcie0 {
+       mt76@0,0 {
+               reg = <0x0000 0 0 0 0>;
+               mediatek,mtd-eeprom = <&factory 0x0>;
+       };
+};
+
+&gmac0 {
+       mtd-mac-address = <&factory 0xe000>;
+};
+
+&switch0 {
+       ports {
+               port@2 {
+                       status = "okay";
+                       label = "lan";
+               };
+       };
+};
+
+&state_default {
+       gpio {
+               groups = "i2c", "rgmii2", "uart3", "jtag", "wdt";
+               function = "gpio";
+       };
+};
index a8f5583..a7f6c80 100644 (file)
@@ -79,6 +79,13 @@ define Build/ubnt-erx-factory-image
        fi
 endef
 
+define Build/zytrx-header
+       $(eval board=$(word 1,$(1)))
+       $(eval version=$(word 2,$(1)))
+       $(STAGING_DIR_HOST)/bin/zytrx -B '$(board)' -v '$(version)' -i $@ -o $@.new
+       mv $@.new $@
+endef
+
 define Device/dsa-migration
   DEVICE_COMPAT_VERSION := 1.1
   DEVICE_COMPAT_MESSAGE := Config cannot be migrated from swconfig to DSA
@@ -1504,6 +1511,21 @@ define Device/zio_freezio
 endef
 TARGET_DEVICES += zio_freezio
 
+define Device/zyxel_nr7101
+  $(Device/dsa-migration)
+  BLOCKSIZE := 128k
+  PAGESIZE := 2048
+  UBINIZE_OPTS := -E 5
+  DEVICE_VENDOR := ZyXEL
+  DEVICE_MODEL := NR7101
+  DEVICE_PACKAGES := kmod-mt7603 kmod-usb3 uboot-envtools kmod-usb-net-qmi-wwan kmod-usb-serial-option uqmi
+  KERNEL := $(KERNEL_DTB) | uImage lzma | zytrx-header $$(DEVICE_MODEL) $$(VERSION_DIST)-$$(REVISION)
+  KERNEL_INITRAMFS := $(KERNEL_DTB) | uImage lzma | zytrx-header $$(DEVICE_MODEL) 9.99(ABUV.9)$$(VERSION_DIST)-recovery
+  KERNEL_INITRAMFS_SUFFIX := -recovery.bin
+  IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata
+endef
+TARGET_DEVICES += zyxel_nr7101
+
 define Device/zyxel_wap6805
   $(Device/dsa-migration)
   BLOCKSIZE := 128k
index 89e679b..f017e47 100755 (executable)
@@ -64,6 +64,9 @@ ramips_setup_interfaces()
        ubnt,edgerouter-x-sfp)
                ucidef_set_interfaces_lan_wan "eth1 eth2 eth3 eth4 eth5" "eth0"
                ;;
+       zyxel,nr7101)
+               ucidef_set_interfaces_lan_wan "lan" "wan"
+               ;;
        zyxel,wap6805)
                ucidef_set_interface_lan "lan1 lan2 lan3 lan4"
                ucidef_set_interface "qtn" ifname "eth1" protocol "static" ipaddr "1.1.1.1" netmask "255.255.255.0"
index 82bbdd2..8ef8156 100755 (executable)
@@ -23,6 +23,9 @@ ubnt,edgerouter-x-sfp)
        ucidef_add_gpio_switch "poe_power_port3" "PoE Power Port3" "403"
        ucidef_add_gpio_switch "poe_power_port4" "PoE Power Port4" "404"
        ;;
+zyxel,nr7101)
+       ucidef_add_gpio_switch "lte_reset" "Reset LTE/5G modem" "483"
+       ;;
 zyxel,wap6805)
        ucidef_add_gpio_switch "qtn_power" "Quantenna Module Power" "496" "1"
        ;;
index 7ef0053..a155458 100755 (executable)
@@ -16,5 +16,10 @@ boot() {
        samknows,whitebox-v8)
                fw_setenv bootcount 0
                ;;
+       zyxel,nr7101)
+               [ $(printf %d $(fw_printenv -n DebugFlag)) -gt 0 ] || fw_setenv DebugFlag 0x1
+               [ $(printf %d $(fw_printenv -n Image1Stable)) -gt 0 ] || fw_setenv Image1Stable 1
+               [ $(printf %d $(fw_printenv -n Image1Try)) -gt 0 ] && fw_setenv Image1Try 0
+               ;;
        esac
 }
index c9152c5..d30bc3d 100755 (executable)
@@ -82,6 +82,12 @@ platform_do_upgrade() {
        ubnt,edgerouter-x-sfp)
                platform_upgrade_ubnt_erx "$1"
                ;;
+       zyxel,nr7101)
+               fw_setenv CheckBypass 0
+               fw_setenv Image1Stable 0
+               CI_KERNPART="Kernel"
+               nand_do_upgrade "$1"
+               ;;
        zyxel,wap6805)
                local kernel2_mtd="$(find_mtd_part Kernel2)"
                [ "$(hexdump -n 4 -e '"%x"' $kernel2_mtd)" = "56190527" ] &&\