diff --git a/package/utils/zyxel-bootconfig/Makefile b/package/utils/zyxel-bootconfig/Makefile new file mode 100644 index 0000000000..eb2dd79b82 --- /dev/null +++ b/package/utils/zyxel-bootconfig/Makefile @@ -0,0 +1,38 @@ +# +# Copyright (C) 2022 David Bauer +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=zyxel-bootconfig +PKG_RELEASE:=1 + +include $(INCLUDE_DIR)/package.mk + +define Package/zyxel-bootconfig + SECTION:=utils + CATEGORY:=Base system + TITLE:=Utility for handling ZyXEL Bootconfig settings + MAINTAINER:=David Bauer +endef + +define Package/zyxel-bootconfig/description + This package contains an utility that allows handling ZyXEL Bootconfig settings. +endef + +define Build/Compile + $(MAKE) -C $(PKG_BUILD_DIR) \ + CC="$(TARGET_CC)" \ + CFLAGS="$(TARGET_CFLAGS) -Wall" +endef + +define Package/zyxel-bootconfig/install + $(INSTALL_DIR) $(1)/usr/bin $(1)/lib/preinit + $(INSTALL_BIN) $(PKG_BUILD_DIR)/zyxel-bootconfig $(1)/usr/bin/ + $(CP) ./files/95_apply_bootconfig $(1)/lib/preinit/95_apply_bootconfig +endef + +$(eval $(call BuildPackage,zyxel-bootconfig)) diff --git a/package/utils/zyxel-bootconfig/files/95_apply_bootconfig b/package/utils/zyxel-bootconfig/files/95_apply_bootconfig new file mode 100644 index 0000000000..c47857b082 --- /dev/null +++ b/package/utils/zyxel-bootconfig/files/95_apply_bootconfig @@ -0,0 +1,16 @@ +apply_bootconfig() { + . /lib/functions.sh + + local part + + case $(board_name) in + zyxel,nwa50ax|\ + zyxel,nwa55axe) + mtd_idx=$(find_mtd_index "bootconfig") + zyxel-bootconfig "/dev/mtd$mtd_idx" set-image-status 0 valid + zyxel-bootconfig "/dev/mtd$mtd_idx" set-active-image 0 + ;; + esac +} + +[ "$INITRAMFS" = "1" ] || boot_hook_add preinit_main apply_bootconfig diff --git a/package/utils/zyxel-bootconfig/src/Makefile b/package/utils/zyxel-bootconfig/src/Makefile new file mode 100644 index 0000000000..66741c8acf --- /dev/null +++ b/package/utils/zyxel-bootconfig/src/Makefile @@ -0,0 +1,7 @@ +all: zyxel-bootconfig + +zyxel-bootconfig: + $(CC) $(CFLAGS) -Wall zyxel-bootconfig.c -o zyxel-bootconfig + +clean: + rm -f zyxel-bootconfig diff --git a/package/utils/zyxel-bootconfig/src/zyxel-bootconfig.c b/package/utils/zyxel-bootconfig/src/zyxel-bootconfig.c new file mode 100644 index 0000000000..6dd2f8969f --- /dev/null +++ b/package/utils/zyxel-bootconfig/src/zyxel-bootconfig.c @@ -0,0 +1,331 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Copyright (C) 2022 David Bauer */ + +/* + * First byte: Image status + * + * Possible status-codes: + * 0x0: none + * 0x1: new + * 0x2: valid + * 0x3: invalid + * + * Example: Image 0 valid; Image 1 invalid + * 11001000 + * || || + * img1|| + * img0 + * + * Second byte: Active Image + * Possible values: + * 0x0: Image0 active + * 0x1: Image1 active + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define BOOTCONFIG_SIZE 0x20 +#define BOOTCONFIG_IMAGE_STATUS 0x0 +#define BOOTCONFIG_ACTIVE_IMAGE 0x1 + +#define IMAGE_0_SHIFT 2 +#define IMAGE_0_MASK 0x0c +#define IMAGE_1_SHIFT 6 +#define IMAGE_1_MASK 0xc0 + +#define IMAGE_STATUS(img0, img1) (((img0 << IMAGE_0_SHIFT) & IMAGE_0_MASK) | ((img1 << IMAGE_1_SHIFT) & IMAGE_1_MASK)) + +#define ACTIVE_IMAGE_MASK 0x1 +#define ACTIVE_IMAGE(img) (img & ACTIVE_IMAGE_MASK) + +enum zyxel_bootconfig_image_status { + IMAGE_STATUS_NONE = 0x0, + IMAGE_STATUS_NEW = 0x1, + IMAGE_STATUS_VALID = 0x2, + IMAGE_STATUS_INVALID = 0x3, + __IMAGE_STATUS_EINVAL, +}; + +struct zyxel_bootconfig { + enum zyxel_bootconfig_image_status image0_status; + enum zyxel_bootconfig_image_status image1_status; + unsigned int active_image; +}; + +struct zyxel_bootconfig_mtd { + struct mtd_info_user mtd_info; + int fd; +}; + +struct zyxel_image_status { + enum zyxel_bootconfig_image_status code; + const char *name; +}; + +struct zyxel_image_status image_status_codes[] = { + { .code = IMAGE_STATUS_NONE, .name = "none" }, + { .code = IMAGE_STATUS_NEW, .name = "new" }, + { .code = IMAGE_STATUS_VALID, .name = "valid" }, + { .code = IMAGE_STATUS_INVALID, .name = "invalid" }, + {}, +}; + + +static enum zyxel_bootconfig_image_status zyxel_bootconfig_image_status_parse(const char *status) { + struct zyxel_image_status* s; + + for (s = image_status_codes; s->name; s++) { + if (!strcmp(status, s->name)) { + return s->code; + } + } + + return __IMAGE_STATUS_EINVAL; +} + +const char *zyxel_bootconfig_image_status_name(const enum zyxel_bootconfig_image_status bootconfig) { + struct zyxel_image_status* s; + + for (s = image_status_codes; s->name; s++) { + if (bootconfig == s->code) { + return s->name; + } + } + + return "N/A"; +} + +static void zyxel_bootconfig_mtd_close(struct zyxel_bootconfig_mtd *mtd) { + close(mtd->fd); +} + + +static int zyxel_bootconfig_mtd_open(struct zyxel_bootconfig_mtd *mtd, const char *mtd_name) { + int ret = 0; + + mtd->fd = open(mtd_name, O_RDWR | O_SYNC); + if (mtd->fd < 0) { + fprintf(stderr, "Could not open mtd device: %s\n", mtd_name); + ret = -1; + goto out; + } + + if (ioctl(mtd->fd, MEMGETINFO, &mtd->mtd_info)) { + fprintf(stderr, "Could not get MTD device info from %s\n", mtd_name); + ret = -1; + zyxel_bootconfig_mtd_close(mtd); + goto out; + } + +out: + return ret; +} + + +static int zyxel_bootconfig_read(struct zyxel_bootconfig *config, struct zyxel_bootconfig_mtd *mtd) { + char *args = NULL; + int ret = 0; + + /* Allocate memory for reading boot-config partition */ + args = calloc(1, mtd->mtd_info.erasesize); + if (!args) { + fprintf(stderr, "Could not allocate memory!\n"); + ret = -1; + goto out; + } + + /* Read bootconfig partition */ + pread(mtd->fd, args, mtd->mtd_info.erasesize, 0); + + /* Parse config */ + memset(config, 0, sizeof(*config)); + + config->image0_status = (args[BOOTCONFIG_IMAGE_STATUS] & IMAGE_0_MASK) >> IMAGE_0_SHIFT; + config->image1_status = (args[BOOTCONFIG_IMAGE_STATUS] & IMAGE_1_MASK) >> IMAGE_1_SHIFT; + config->active_image = (args[BOOTCONFIG_ACTIVE_IMAGE] & ACTIVE_IMAGE_MASK); + +out: + if (args) + free(args); + return ret; +} + + +static int zyxel_bootconfig_write(struct zyxel_bootconfig *config, struct zyxel_bootconfig_mtd *mtd) +{ + struct erase_info_user erase_info; + char img_status, img_active; + char *args = NULL; + int ret = 0; + + /* Allocate memory for reading boot-config partition */ + args = calloc(1, mtd->mtd_info.erasesize); + if (!args) { + fprintf(stderr, "Could not allocate memory!\n"); + ret = -1; + goto out; + } + + /* Read bootconfig partition */ + pread(mtd->fd, args, mtd->mtd_info.erasesize, 0); + + img_status = IMAGE_STATUS(config->image0_status, config->image1_status); + img_active = ACTIVE_IMAGE(config->active_image); + + /* Check if bootconfig has to be written */ + if (args[BOOTCONFIG_IMAGE_STATUS] == img_status && args[BOOTCONFIG_ACTIVE_IMAGE] == img_active) { + ret = 0; + goto out; + } + + /* Erase first block (containing the magic) */ + erase_info.start = 0; + erase_info.length = mtd->mtd_info.erasesize; + ret = ioctl(mtd->fd, MEMERASE, &erase_info); + if (ret < 0) { + fprintf(stderr, "Failed to erase block: %i\n", ret); + goto out; + } + + + /* Write bootconfig */ + args[BOOTCONFIG_IMAGE_STATUS] = img_status; + args[BOOTCONFIG_ACTIVE_IMAGE] = img_active; + + if (pwrite(mtd->fd, args, mtd->mtd_info.erasesize, 0) != mtd->mtd_info.erasesize) { + fprintf(stderr, "Error writing bootconfig!\n"); + ret = -1; + goto out; + } + +out: + if (args) + free(args); + return ret; +} + + +static void zyxel_bootconfig_print_usage(char *programm) +{ + struct zyxel_image_status* s = image_status_codes; + + printf("Usage: %s [args]\n", programm); + printf("Available commands:\n"); + printf(" get-status\n"); + printf(" set-image-status [0/1] ["); + + while (s->name) { + printf("%s", s->name); + s++; + + if (s->name) + printf(","); + } + + printf("]\n"); + printf(" set-active-image [0/1]\n"); +} + +int main(int argc, char *argv[]) +{ + enum zyxel_bootconfig_image_status image_status; + struct zyxel_bootconfig_mtd mtd; + struct zyxel_bootconfig config; + const char *mtd_name, *command; + bool writeback = false; + int image_idx; + + if (argc < 3) { + zyxel_bootconfig_print_usage(argv[0]); + return 1; + } + + mtd_name = argv[1]; + command = argv[2]; + + if (zyxel_bootconfig_mtd_open(&mtd, mtd_name)) { + fprintf(stderr, "Error opening %s!\n", mtd_name); + return 1; + } + + if (zyxel_bootconfig_read(&config, &mtd)) { + fprintf(stderr, "Error reading bootconfig!\n"); + zyxel_bootconfig_mtd_close(&mtd); + return 1; + } + + if (!strcmp(command, "set-image-status")) { + if (argc < 5) { + zyxel_bootconfig_print_usage(argv[0]); + zyxel_bootconfig_mtd_close(&mtd); + return 1; + } + + image_idx = atoi(argv[3]); + if (image_idx > 1 || image_idx < 0) { + fprintf(stderr, "Invalid image-slot set!\n"); + zyxel_bootconfig_mtd_close(&mtd); + return 1; + } + + image_status = zyxel_bootconfig_image_status_parse(argv[4]); + if (image_status == __IMAGE_STATUS_EINVAL) { + fprintf(stderr, "Invalid image-status!\n"); + zyxel_bootconfig_mtd_close(&mtd); + return 1; + } + + if (image_idx == 0) { + config.image0_status = image_status; + } else { + config.image1_status = image_status; + } + + writeback = true; + } else if (!strcmp(command, "set-active-image")) { + if (argc < 4) { + zyxel_bootconfig_print_usage(argv[0]); + zyxel_bootconfig_mtd_close(&mtd); + return 1; + } + + image_idx = atoi(argv[3]); + if (image_idx > 1 || image_idx < 0) { + fprintf(stderr, "Invalid image-slot set!\n"); + zyxel_bootconfig_mtd_close(&mtd); + return 1; + } + + config.active_image = image_idx; + + writeback = true; + } else if (!strcmp(command, "get-status")) { + printf("Active Image: %d\n", config.active_image); + printf("Image 0 Status: %s\n", zyxel_bootconfig_image_status_name(config.image0_status)); + printf("Image 1 Status: %s\n", zyxel_bootconfig_image_status_name(config.image1_status)); + + writeback = false; + } + + if (writeback) { + if (zyxel_bootconfig_write(&config, &mtd)) { + fprintf(stderr, "Error writing bootconfig!\n"); + zyxel_bootconfig_mtd_close(&mtd); + return 1; + } + + zyxel_bootconfig_mtd_close(&mtd); + } + + return 0; +} diff --git a/scripts/mkits-zyxel-fit.sh b/scripts/mkits-zyxel-fit.sh new file mode 100755 index 0000000000..8ace1941eb --- /dev/null +++ b/scripts/mkits-zyxel-fit.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# +# Licensed under the terms of the GNU GPL License version 2 or later. +# Author: David Bauer , based on mkits-zyxel-factory.sh. + +usage() { + echo "Usage: `basename $0` output file compat-models" + exit 1 +} + +# We need at least 3 arguments +[ "$#" -lt 3 ] && usage + +# Target output file +OUTPUT="$1"; shift +FILE="$1"; shift +MODELS="$1"; shift + +# Create a default, fully populated DTS file +echo "\ +/dts-v1/; + +/ { + description = \"Zyxel FIT (Flattened Image Tree)\"; + compat-models = [${MODELS}]; + #address-cells = <1>; + + images { + firmware { + data = /incbin/(\"${FILE}\"); + type = \"firmware\"; + compression = \"none\"; + hash@1 { + algo = \"sha1\"; + }; + }; + }; +};" > ${OUTPUT} diff --git a/target/linux/ramips/dts/mt7621_zyxel_nwa-ax.dtsi b/target/linux/ramips/dts/mt7621_zyxel_nwa-ax.dtsi new file mode 100644 index 0000000000..e1353346a8 --- /dev/null +++ b/target/linux/ramips/dts/mt7621_zyxel_nwa-ax.dtsi @@ -0,0 +1,151 @@ +#include "mt7621.dtsi" + +#include +#include + +/ { + aliases { + label-mac-device = &gmac0; + }; +}; + +&nand { + status = "okay"; + + mediatek,nmbm; + mediatek,bmt-max-ratio = <15>; + mediatek,bmt-max-reserved-blocks = <64>; + mediatek,bmt-remap-range = + <0x0 0x980000>, + <0x2980000 0x7800000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "u-boot"; + reg = <0x0 0x80000>; + read-only; + }; + + partition@80000 { + label = "u-boot-env"; + reg = <0x80000 0x80000>; + read-only; + }; + + factory: partition@100000 { + label = "factory"; + reg = <0x100000 0x80000>; + read-only; + }; + + partition@180000 { + label = "firmware"; + reg = <0x180000 0x2800000>; + + /* This concatenates kernel1 & kernel2 & rootfs */ + + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "kernel"; + reg = <0x0 0x800000>; + }; + + partition@400000 { + label = "ubi"; + reg = <0x800000 0x2000000>; + }; + }; + + partition@2980000 { + label = "zy_firmware_1"; + reg = <0x2980000 0x2800000>; + read-only; + }; + + partition@5180000 { + label = "zy_rootfs_data"; + reg = <0x5180000 0x1400000>; + read-only; + }; + + partition@6580000 { + label = "zy_logs"; + reg = <0x6580000 0xd00000>; + read-only; + }; + + partition@7280000 { + label = "myzyxel"; + reg = <0x7280000 0x480000>; + read-only; + }; + + partition@7700000 { + label = "bootconfig"; + reg = <0x7700000 0x80000>; + }; + + mrd: partition@7780000 { + label = "mrd"; + reg = <0x7780000 0x80000>; + read-only; + }; + }; +}; + +&pcie { + status = "okay"; +}; + +&pcie1 { + wlan_5g: wifi@0,0 { + reg = <0x0 0 0 0 0>; + compatible = "mediatek,mt76"; + + mediatek,mtd-eeprom = <&factory 0x0>; + + /* MAC-Address set in userspace */ + }; +}; + +&gmac0 { + nvmem-cells = <&macaddr_mrd_1fff8>; + nvmem-cell-names = "mac-address"; +}; + +&switch0 { + ports { + port@4 { + status = "okay"; + label = "lan"; + }; + }; +}; + +&mrd { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_mrd_1fff8: macaddr@1fff8 { + reg = <0x1fff8 0x6>; + }; +}; + +&state_default { + gpio { + groups = "uart3", "rgmii2"; + function = "gpio"; + }; +}; + +ðernet { + pinctrl-0 = <&mdio_pins>, <&rgmii1_pins>; +}; diff --git a/target/linux/ramips/dts/mt7621_zyxel_nwa50ax.dts b/target/linux/ramips/dts/mt7621_zyxel_nwa50ax.dts new file mode 100644 index 0000000000..70323f2422 --- /dev/null +++ b/target/linux/ramips/dts/mt7621_zyxel_nwa50ax.dts @@ -0,0 +1,45 @@ +#include "mt7621_zyxel_nwa-ax.dtsi" + +#include +#include + +/ { + compatible = "zyxel,nwa50ax", "mediatek,mt7621-soc"; + model = "ZyXEL NWA50AX"; + + aliases { + led-boot = &led_system_green; + led-failsafe = &led_system_red; + led-running = &led_system_green; + led-upgrade = &led_system_red; + }; + + leds { + compatible = "gpio-leds"; + + led_system_red: system_red { + label = "red:system"; + gpios = <&gpio 6 GPIO_ACTIVE_HIGH>; + }; + + led_system_green: system_green { + label = "green:system"; + gpios = <&gpio 7 GPIO_ACTIVE_HIGH>; + }; + + system_blue { + label = "blue:system"; + gpios = <&gpio 8 GPIO_ACTIVE_HIGH>; + }; + }; + + keys { + compatible = "gpio-keys"; + + reset { + label = "reset"; + gpios = <&gpio 30 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; +}; diff --git a/target/linux/ramips/dts/mt7621_zyxel_nwa55axe.dts b/target/linux/ramips/dts/mt7621_zyxel_nwa55axe.dts new file mode 100644 index 0000000000..04bbe340f2 --- /dev/null +++ b/target/linux/ramips/dts/mt7621_zyxel_nwa55axe.dts @@ -0,0 +1,6 @@ +#include "mt7621_zyxel_nwa-ax.dtsi" + +/ { + compatible = "zyxel,nwa55axe", "mediatek,mt7621-soc"; + model = "ZyXEL NWA55AX"; +}; diff --git a/target/linux/ramips/image/mt7621.mk b/target/linux/ramips/image/mt7621.mk index 4d2f2a3610..34eac32112 100644 --- a/target/linux/ramips/image/mt7621.mk +++ b/target/linux/ramips/image/mt7621.mk @@ -95,6 +95,13 @@ define Build/zytrx-header mv $@.new $@ endef +define Build/zyxel-nwa-fit + $(TOPDIR)/scripts/mkits-zyxel-fit.sh \ + $@.its $@ "6b e1 6f e1 ff ff ff ff ff ff" + PATH=$(LINUX_DIR)/scripts/dtc:$(PATH) mkimage -f $@.its $@.new + @mv $@.new $@ +endef + define Device/dsa-migration DEVICE_COMPAT_VERSION := 1.1 DEVICE_COMPAT_MESSAGE := Config cannot be migrated from swconfig to DSA @@ -2211,6 +2218,33 @@ define Device/zyxel_nr7101 endef TARGET_DEVICES += zyxel_nr7101 +define Device/zyxel_nwa-ax + $(Device/dsa-migration) + DEVICE_VENDOR := ZyXEL + BLOCKSIZE := 128k + PAGESIZE := 2048 + KERNEL_SIZE := 8192k + UBINIZE_OPTS := -E 5 + DEVICE_PACKAGES := kmod-mt7915e uboot-envtools 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 + IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata +endef + +define Device/zyxel_nwa50ax + $(Device/zyxel_nwa-ax) + DEVICE_MODEL := NWA50AX +endef +TARGET_DEVICES += zyxel_nwa50ax + +define Device/zyxel_nwa55axe + $(Device/zyxel_nwa-ax) + DEVICE_MODEL := NWA55AXE +endef +TARGET_DEVICES += zyxel_nwa55axe + define Device/zyxel_wap6805 $(Device/dsa-migration) BLOCKSIZE := 128k diff --git a/target/linux/ramips/mt7621/base-files/etc/board.d/02_network b/target/linux/ramips/mt7621/base-files/etc/board.d/02_network index 39e095584d..320325f487 100644 --- a/target/linux/ramips/mt7621/base-files/etc/board.d/02_network +++ b/target/linux/ramips/mt7621/base-files/etc/board.d/02_network @@ -21,7 +21,9 @@ ramips_setup_interfaces() tplink,re650-v1|\ tplink,re650-v2|\ ubnt,unifi-6-lite|\ - ubnt,unifi-nanohd) + ubnt,unifi-nanohd|\ + zyxel,nwa50ax|\ + zyxel,nwa55axe) ucidef_set_interface_lan "lan" ;; ampedwireless,ally-r1900k|\ diff --git a/target/linux/ramips/mt7621/base-files/etc/hotplug.d/ieee80211/10_fix_wifi_mac b/target/linux/ramips/mt7621/base-files/etc/hotplug.d/ieee80211/10_fix_wifi_mac index 4649b9e9d0..bced044234 100644 --- a/target/linux/ramips/mt7621/base-files/etc/hotplug.d/ieee80211/10_fix_wifi_mac +++ b/target/linux/ramips/mt7621/base-files/etc/hotplug.d/ieee80211/10_fix_wifi_mac @@ -104,4 +104,10 @@ case "$board" in [ "$PHYNBR" = "1" ] && \ macaddr_setbit_la "$(mtd_get_mac_binary Factory 0xe000)" > /sys${DEVPATH}/macaddress ;; + zyxel,nwa50ax|\ + zyxel,nwa55axe) + hw_mac_addr="$(mtd_get_mac_binary mrd 0x1fff8)" + [ "$PHYNBR" = "0" ] && macaddr_add $hw_mac_addr 1 > /sys${DEVPATH}/macaddress + [ "$PHYNBR" = "1" ] && macaddr_add $hw_mac_addr 2 > /sys${DEVPATH}/macaddress + ;; esac diff --git a/target/linux/ramips/mt7621/base-files/lib/upgrade/platform.sh b/target/linux/ramips/mt7621/base-files/lib/upgrade/platform.sh index 9becffa357..8a84130ab5 100755 --- a/target/linux/ramips/mt7621/base-files/lib/upgrade/platform.sh +++ b/target/linux/ramips/mt7621/base-files/lib/upgrade/platform.sh @@ -96,7 +96,9 @@ platform_do_upgrade() { xiaomi,mi-router-cr6606|\ xiaomi,mi-router-cr6608|\ xiaomi,mi-router-cr6609|\ - xiaomi,redmi-router-ac2100) + xiaomi,redmi-router-ac2100|\ + zyxel,nwa50ax|\ + zyxel,nwa55axe) nand_do_upgrade "$1" ;; iodata,wn-ax1167gr2|\