From 71fb79ca28e06bd74a78684c863e67b2c00ccbfc Mon Sep 17 00:00:00 2001 From: Marco von Rosenberg Date: Mon, 20 Nov 2023 20:23:34 +0100 Subject: [PATCH] ath79: add support for Huawei AP5030DN Huawei AP5030DN is a dual-band, dual-radio 802.11ac Wave 1 3x3 MIMO enterprise access point with two Gigabit Ethernet ports and PoE support. Hardware highlights: - CPU: QCA9550 SoC at 720MHz - RAM: 256MB DDR2 - Flash: 32MB SPI-NOR - Wi-Fi 2.4GHz: QCA9550-internal radio - Wi-Fi 5GHz: QCA9880 PCIe WLAN SoC - Ethernet 1: 10/100/1000 Mbps Ethernet through Broadcom B50612E PHY - Ethernet 2: 10/100/1000 Mbps Ethernet through Marvell 88E1510 PHY - PoE: input through Ethernet 1 port - Standalone 12V/2A power input - Serial console externally available through RJ45 port - External watchdog: SGM706 (1.6s timeout) Serial console: 9600n8 (9600 baud, no stop bits, no parity, 8 data bits) MAC addresses: Each device has 32 consecutive MAC addresses allocated by the vendor, which don't overlap between devices. This was confirmed with multiple devices with consecutive serial numbers. The MAC address range starts with the address on the label. To be able to distinguish between the interfaces, the following MAC address scheme is used: - eth0 = label MAC - eth1 = label MAC + 1 - radio0 (Wi-Fi 5GHz) = label MAC + 2 - radio1 (Wi-Fi 2.4GHz) = label MAC + 3 Installation: 0. Connect some sort of RJ45-to-USB adapter to "Console" port of the AP 1. Power up the AP 2. At prompt "Press f or F to stop Auto-Boot in 3 seconds", do what they say. Log in with default admin password "admin@huawei.com". 3. Boot the OpenWrt initramfs from TFTP using the hidden script "run ramboot". Replace IP address as needed: > setenv serverip 192.168.1.10 > setenv ipaddr 192.168.1.1 > setenv rambootfile openwrt-ath79-generic-huawei_ap5030dn-initramfs-kernel.bin > saveenv > run ramboot 4. Optional but recommended as the factory firmware cannot be downloaded publicly: Back up contents of "firmware" partition using the web interface or ssh: $ ssh root@192.168.1.1 cat /dev/mtd11 > huawei_ap5030dn_fw_backup.bin 5. Run sysupgrade using sysupgrade image. OpenWrt shall boot from flash afterwards. Return to factory firmware (using firmware upgrade package downloaded from non-public Huawei website): 1. Start a TFTP server in the directory where the firmware upgrade package is located 2. Boot to u-boot as described above 3. Install firmware upgrade package and format the config partitions: > update system FatAP5X30XN_SOMEVERSION.bin > format_fs Return to factory firmware (from previously created backup): 1. Copy over the firmware partition backup to /tmp, for example using scp 2. Use sysupgrade with force to restore the backup: sysupgrade -F huawei_ap5030dn_fw_backup.bin 3. Boot AP to U-Boot as described above Quirks and known issues: - On initial power-up, the Huawei-modified bootloader suspends both ethernet PHYs (it sets the "Power Down" bit in the MII control register). Unfortunately, at the time of writing, the kernel driver for the B50612E/BCM54612E PHY behind eth0 doesn't have a resume callback defined which would clear this bit. This makes the PHY unusable since it remains suspended forever. This is why the kernel patches in this commit are required which add this callback and for completeness also a suspend callback. - The stock firmware has a semi dual boot concept where the primary kernel uses a squashfs as root partition and the secondary kernel uses an initramfs. This dual boot concept is circumvented on purpose to gain more flash space and since the stock firmware's flash layout isn't compatible with mtdsplit. - When OpenWrt is built from source, early printk has to be disabled in the kernel config. This is because the external watchdog's timeout of 1.6 seconds is so short that it kills the kernel when boot is slowed down a bit by early printk. Signed-off-by: Marco von Rosenberg --- package/boot/uboot-envtools/files/ath79 | 3 + .../ath79/dts/qca9550_huawei_ap5030dn.dts | 230 ++++++++++++++++++ .../generic/base-files/etc/board.d/02_network | 4 + .../base-files/lib/upgrade/platform.sh | 7 + target/linux/ath79/image/Makefile | 6 + target/linux/ath79/image/generic.mk | 20 ++ .../linux/ath79/image/lzma-loader/src/board.c | 30 +++ ...net-phy-bcm54612e-add-suspend-resume.patch | 24 ++ ...net-phy-bcm54612e-add-suspend-resume.patch | 27 ++ ...net-phy-bcm54612e-add-suspend-resume.patch | 27 ++ 10 files changed, 378 insertions(+) create mode 100644 target/linux/ath79/dts/qca9550_huawei_ap5030dn.dts create mode 100644 target/linux/ath79/patches-5.15/731-net-phy-bcm54612e-add-suspend-resume.patch create mode 100644 target/linux/ath79/patches-6.1/731-net-phy-bcm54612e-add-suspend-resume.patch create mode 100644 target/linux/generic/backport-6.1/738-net-phy-bcm54612e-add-suspend-resume.patch diff --git a/package/boot/uboot-envtools/files/ath79 b/package/boot/uboot-envtools/files/ath79 index 7c0cdf9013f903..099adb8052dab8 100644 --- a/package/boot/uboot-envtools/files/ath79 +++ b/package/boot/uboot-envtools/files/ath79 @@ -127,6 +127,9 @@ domywifi,dw33d) glinet,gl-ar150) ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x8000" "0x10000" ;; +huawei,ap5030dn) + ubootenv_add_uci_config "/dev/mtd3" "0x0" "0x20000" "0x20000" + ;; netgear,wndr3700|\ netgear,wndr3700-v2|\ netgear,wndrmac-v1) diff --git a/target/linux/ath79/dts/qca9550_huawei_ap5030dn.dts b/target/linux/ath79/dts/qca9550_huawei_ap5030dn.dts new file mode 100644 index 00000000000000..d95143e2c1f79f --- /dev/null +++ b/target/linux/ath79/dts/qca9550_huawei_ap5030dn.dts @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qca955x.dtsi" + +#include +#include + +/ { + model = "Huawei AP5030DN"; + compatible = "huawei,ap5030dn", "qca,qca9550", "qca,qca9558"; + + chosen { + bootargs = "console=ttyS0,9600n8"; + }; + + aliases { + led-boot = &led_power_red; + led-failsafe = &led_power_red; + led-running = &led_power_green; + led-upgrade = &led_power_red; + }; + + leds { + compatible = "gpio-leds"; + + led_power_green: power_green { + label = "green:power"; + gpios = <&gpio 18 GPIO_ACTIVE_HIGH>; + default-state = "on"; + }; + + led_power_red: power_red { + label = "red:power"; + gpios = <&gpio 11 GPIO_ACTIVE_HIGH>; + }; + + }; + + keys { + compatible = "gpio-keys"; + + restart { + label = "Restart button"; + linux,code = ; + gpios = <&gpio 21 GPIO_ACTIVE_LOW>; + debounce-interval = <60>; + }; + }; + + watchdog { + compatible = "linux,wdt-gpio"; + gpios = <&gpio 15 GPIO_ACTIVE_HIGH>; + hw_algo = "toggle"; + hw_margin_ms = <100>; + always-running; + }; + + virtual_flash { + compatible = "mtd-concat"; + devices = <&fwconcat0 &fwconcat1>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "firmware"; + reg = <0x0 0x1e00000>; + compatible = "openwrt,uimage", "denx,uimage"; + }; + }; + }; +}; + +&spi { + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <25000000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "u-boot-a"; + reg = <0x0 0x80000>; + read-only; + }; + + partition@80000 { + label = "BootupA"; + reg = <0x80000 0x20000>; + }; + + partition@a0000 { + label = "BootupB"; + reg = <0xa0000 0x20000>; + }; + + partition@c0000 { + label = "u-boot-env"; + reg = <0xc0000 0x20000>; + read-only; + }; + + partition@e0000 { + label = "BoardData"; + reg = <0xe0000 0x20000>; + read-only; + }; + + // In the vendor layout, there are the "SysImageA" (12 MiB) + // and the "ConfigA" (3 MiB) partitions here. + fwconcat0: partition@100000 { + label = "fwconcat0"; + reg = <0x100000 0xF00000>; + }; + + partition@1000000 { + label = "u-boot-b"; + reg = <0x1000000 0x80000>; + read-only; + }; + + partition@1080000 { + label = "ResultA"; + reg = <0x1080000 0x20000>; + read-only; + }; + + partition@10a0000 { + label = "ResultB"; + reg = <0x10a0000 0x20000>; + read-only; + }; + + // In the vendor layout, there are the "SysImageB" (12 MiB) + // and the "ConfigB" (3 MiB) partitions here. + fwconcat1: partition@10c0000 { + label = "fwconcat1"; + reg = <0x10c0000 0xF00000>; + }; + + art: partition@1fc0000 { + label = "art"; + reg = <0x1fc0000 0x40000>; + read-only; + + nvmem-layout { + compatible = "fixed-layout"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_art_2005b: macaddr@2005b { + compatible = "mac-base"; + reg = <0x2005b 0x6>; + #nvmem-cell-cells = <1>; + }; + + cal_art_1000: cal@1000 { + reg = <0x1000 0x440>; + }; + + cal_art_5000: cal@5000 { + reg = <0x5000 0x844>; + }; + }; + }; + }; + }; +}; + +&wmac { + status = "okay"; + + nvmem-cells = <&macaddr_art_2005b 3>, <&cal_art_1000>; + nvmem-cell-names = "mac-address", "calibration"; +}; + +&pcie0 { + status = "okay"; + + wifi@0,0 { + compatible = "qcom,ath10k"; + reg = <0x0000 0 0 0 0>; + nvmem-cells = <&macaddr_art_2005b 2>, <&cal_art_5000>; + nvmem-cell-names = "mac-address", "calibration"; + }; +}; + +ð0 { + status = "okay"; + + nvmem-cells = <&macaddr_art_2005b 0>; + nvmem-cell-names = "mac-address"; + + pll-data = <0xa6000000 0x80000101 0x80001313>; + phy-handle = <&phy0>; +}; + +ð1 { + status = "okay"; + + nvmem-cells = <&macaddr_art_2005b 1>; + nvmem-cell-names = "mac-address"; + + pll-data = <0x03000101 0x00000101 0x00001313>; + phy-handle = <&phy1>; +}; + +&mdio0 { + status = "okay"; + + phy0: ethernet-phy@18 { + reg = <0x18>; + }; +}; + +&mdio1 { + status = "okay"; + + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; diff --git a/target/linux/ath79/generic/base-files/etc/board.d/02_network b/target/linux/ath79/generic/base-files/etc/board.d/02_network index 6c1cb8623554bf..488bd05fb7ede6 100644 --- a/target/linux/ath79/generic/base-files/etc/board.d/02_network +++ b/target/linux/ath79/generic/base-files/etc/board.d/02_network @@ -150,6 +150,7 @@ ath79_setup_interfaces() engenius,enstationac-v1|\ engenius,ews511ap|\ engenius,ews660ap|\ + huawei,ap5030dn|\ ocedo,ursus|\ ruckus,zf7363|\ ruckus,zf7372|\ @@ -747,6 +748,9 @@ ath79_setup_macs() hak5,packet-squirrel) label_mac=$(mtd_get_mac_binary u-boot 0x1fc00) ;; + huawei,ap5030dn) + label_mac=$(mtd_get_mac_binary art 0x2005b) + ;; iodata,etg3-r) lan_mac=$(mtd_get_mac_ascii u-boot-env ethaddr) wan_mac=$(macaddr_add "$lan_mac" -1) diff --git a/target/linux/ath79/generic/base-files/lib/upgrade/platform.sh b/target/linux/ath79/generic/base-files/lib/upgrade/platform.sh index a2b717ef34c715..bbb85cc3ae9326 100644 --- a/target/linux/ath79/generic/base-files/lib/upgrade/platform.sh +++ b/target/linux/ath79/generic/base-files/lib/upgrade/platform.sh @@ -67,6 +67,13 @@ platform_do_upgrade() { ROOTFS_FILE="root.squashfs" platform_do_upgrade_failsafe_datachk "$1" ;; + huawei,ap5030dn) + # Write beginning address of "firmware" partition as KernelA address and KernelB address, each to BootupA & BootupB + echo "Setting Huawei-custom kernel addresses..." + echo -n -e "\x9e\x10\x00\x00\x9e\x10\x00\x00" | dd of=/dev/mtdblock1 bs=1 seek=$((0x254)) conv=notrunc + echo -n -e "\x9e\x10\x00\x00\x9e\x10\x00\x00" | dd of=/dev/mtdblock2 bs=1 seek=$((0x254)) conv=notrunc + default_do_upgrade "$1" + ;; jjplus,ja76pf2) platform_do_upgrade_redboot_fis "$1" linux ;; diff --git a/target/linux/ath79/image/Makefile b/target/linux/ath79/image/Makefile index 8328be7667cf8d..4392bdd4519f8a 100644 --- a/target/linux/ath79/image/Makefile +++ b/target/linux/ath79/image/Makefile @@ -47,6 +47,12 @@ define Build/append-loader-okli-uimage cat "$(KDIR)/loader-$(word 1,$(1)).uImage" >> "$@" endef +define Build/prepend-loader-okli + cat "$(KDIR)/loader-$(word 1,$(1)).$(LOADER_TYPE)" > "$@.new" + cat "$@" >> "$@.new" + mv "$@.new" "$@" +endef + define Build/relocate-kernel rm -rf $@.relocate $(CP) ../../generic/image/relocate $@.relocate diff --git a/target/linux/ath79/image/generic.mk b/target/linux/ath79/image/generic.mk index e7960efbaa2de9..824c66e3a2fda1 100644 --- a/target/linux/ath79/image/generic.mk +++ b/target/linux/ath79/image/generic.mk @@ -1813,6 +1813,26 @@ define Device/hiwifi_hc6361 endef TARGET_DEVICES += hiwifi_hc6361 +define Device/huawei_ap5030dn + SOC := qca9550 + DEVICE_VENDOR := Huawei + DEVICE_MODEL := AP5030DN + DEVICE_PACKAGES := ath10k-firmware-qca988x-ct kmod-ath10k-ct + LOADER_TYPE := bin + LOADER_FLASH_OFFS := 0x110040 + IMAGE_SIZE := 7680k + ROOTFS_MIN_SIZE := 12240k + COMPILE := loader-$(1).bin + COMPILE/loader-$(1).bin := loader-okli-compile | pad-to 64k | uImage none + KERNEL := kernel-bin | append-dtb | lzma | uImage lzma -M 0x4f4b4c49 | prepend-loader-okli $(1) + KERNEL_INITRAMFS := kernel-bin | append-dtb | lzma | loader-kernel | uImage none + IMAGE_SIZE := 30720k + IMAGES += kernel.bin squashfs.bin + IMAGE/kernel.bin := | append-kernel + IMAGE/squashfs.bin := append-rootfs | pad-rootfs | pad-to $$$$(ROOTFS_MIN_SIZE) | pad-to $$$$(BLOCKSIZE) +endef +TARGET_DEVICES += huawei_ap5030dn + define Device/iodata_etg3-r SOC := ar9342 DEVICE_VENDOR := I-O DATA diff --git a/target/linux/ath79/image/lzma-loader/src/board.c b/target/linux/ath79/image/lzma-loader/src/board.c index 7b1e110ee2d902..e1697fb64b20ee 100644 --- a/target/linux/ath79/image/lzma-loader/src/board.c +++ b/target/linux/ath79/image/lzma-loader/src/board.c @@ -182,8 +182,38 @@ static inline void mr18_init(void) static inline void mr18_init(void) { } #endif +#ifdef CONFIG_BOARD_HUAWEI_AP5030DN +static inline void ap5030dn_init(void) +{ + const unsigned int ap5030dn_watchdog_gpio = 15; + unsigned int gpiobase, spibase, reg; + + spibase = KSEG1ADDR(AR71XX_SPI_BASE); + gpiobase = KSEG1ADDR(AR71XX_GPIO_BASE); + + printf("Huawei AP5030DN\n"); + + reg = READREG(gpiobase + AR71XX_GPIO_REG_OE); + WRITEREG(gpiobase + AR71XX_GPIO_REG_OE, + reg & ~(1 << ap5030dn_watchdog_gpio)); + + // Set MUX to output CPU_CLK/4 on GPIO15 + reg = READREG(gpiobase + AR934X_GPIO_REG_FUNC); + WRITEREG(gpiobase + AR934X_GPIO_REG_FUNC, + reg | (1 << 7)); + + // Output stuff on GPIO15 by setting bit 31:24 in gpiobase + AR934X_GPIO_REG_OUT_FUNC3 + reg = READREG(gpiobase + AR934X_GPIO_REG_OUT_FUNC3); + WRITEREG(gpiobase + AR934X_GPIO_REG_OUT_FUNC3, + reg | (84 << 24)); +} +#else +static inline void ap5030dn_init(void) { } +#endif + void board_init(void) { tlwr1043nd_init(); mr18_init(); + ap5030dn_init(); } diff --git a/target/linux/ath79/patches-5.15/731-net-phy-bcm54612e-add-suspend-resume.patch b/target/linux/ath79/patches-5.15/731-net-phy-bcm54612e-add-suspend-resume.patch new file mode 100644 index 00000000000000..fe4d9fa7cfb050 --- /dev/null +++ b/target/linux/ath79/patches-5.15/731-net-phy-bcm54612e-add-suspend-resume.patch @@ -0,0 +1,24 @@ +From: Marco von Rosenberg +Date: Thu, 5 Oct 2023 23:00:42 +0200 +Subject: net: phy: broadcom: Wire suspend/resume for BCM54612E + +The BCM54612E ethernet PHY supports IDDQ-SR. +Therefore wire-up the suspend and resume callbacks +to point to bcm54xx_suspend() and bcm54xx_resume(). + +Signed-off-by: Marco von Rosenberg +--- + drivers/net/phy/broadcom.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/net/phy/broadcom.c ++++ b/drivers/net/phy/broadcom.c +@@ -795,6 +795,8 @@ static struct phy_driver broadcom_driver + .config_init = bcm54xx_config_init, + .config_intr = bcm_phy_config_intr, + .handle_interrupt = bcm_phy_handle_interrupt, ++ .suspend = genphy_suspend, ++ .resume = bcm54xx_resume, + }, { + .phy_id = PHY_ID_BCM54616S, + .phy_id_mask = 0xfffffff0, diff --git a/target/linux/ath79/patches-6.1/731-net-phy-bcm54612e-add-suspend-resume.patch b/target/linux/ath79/patches-6.1/731-net-phy-bcm54612e-add-suspend-resume.patch new file mode 100644 index 00000000000000..8d88d4695521ee --- /dev/null +++ b/target/linux/ath79/patches-6.1/731-net-phy-bcm54612e-add-suspend-resume.patch @@ -0,0 +1,27 @@ +From 380b50ae3a04222334a3779b3787eba844b1177f Mon Sep 17 00:00:00 2001 +From: Marco von Rosenberg +Date: Thu, 16 Nov 2023 20:32:31 +0100 +Subject: net: phy: broadcom: Wire suspend/resume for BCM54612E + +The BCM54612E ethernet PHY supports IDDQ-SR. +Therefore wire-up the suspend and resume callbacks +to point to bcm54xx_suspend() and bcm54xx_resume(). + +Signed-off-by: Marco von Rosenberg +Acked-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + drivers/net/phy/broadcom.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/net/phy/broadcom.c ++++ b/drivers/net/phy/broadcom.c +@@ -941,6 +941,8 @@ static struct phy_driver broadcom_driver + .config_intr = bcm_phy_config_intr, + .handle_interrupt = bcm_phy_handle_interrupt, + .link_change_notify = bcm54xx_link_change_notify, ++ .suspend = bcm54xx_suspend, ++ .resume = bcm54xx_resume, + }, { + .phy_id = PHY_ID_BCM54616S, + .phy_id_mask = 0xfffffff0, diff --git a/target/linux/generic/backport-6.1/738-net-phy-bcm54612e-add-suspend-resume.patch b/target/linux/generic/backport-6.1/738-net-phy-bcm54612e-add-suspend-resume.patch new file mode 100644 index 00000000000000..8d88d4695521ee --- /dev/null +++ b/target/linux/generic/backport-6.1/738-net-phy-bcm54612e-add-suspend-resume.patch @@ -0,0 +1,27 @@ +From 380b50ae3a04222334a3779b3787eba844b1177f Mon Sep 17 00:00:00 2001 +From: Marco von Rosenberg +Date: Thu, 16 Nov 2023 20:32:31 +0100 +Subject: net: phy: broadcom: Wire suspend/resume for BCM54612E + +The BCM54612E ethernet PHY supports IDDQ-SR. +Therefore wire-up the suspend and resume callbacks +to point to bcm54xx_suspend() and bcm54xx_resume(). + +Signed-off-by: Marco von Rosenberg +Acked-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + drivers/net/phy/broadcom.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/net/phy/broadcom.c ++++ b/drivers/net/phy/broadcom.c +@@ -941,6 +941,8 @@ static struct phy_driver broadcom_driver + .config_intr = bcm_phy_config_intr, + .handle_interrupt = bcm_phy_handle_interrupt, + .link_change_notify = bcm54xx_link_change_notify, ++ .suspend = bcm54xx_suspend, ++ .resume = bcm54xx_resume, + }, { + .phy_id = PHY_ID_BCM54616S, + .phy_id_mask = 0xfffffff0,