ipq40xx: add support for Linksys WHW03 V1
authorRodrigo Balerdi <lanchon@gmail.com>
Thu, 11 Apr 2024 15:14:19 +0000 (12:14 -0300)
committerRobert Marko <robimarko@gmail.com>
Sun, 5 May 2024 08:33:13 +0000 (10:33 +0200)
Hardware:
=========
SOC:             Qualcomm IPQ4019
WiFi 1:          QCA4019 IEEE 802.11b/g/n
WiFi 2:          QCA4019 IEEE 802.11a/n/ac
WiFi 3:          QCA9886 IEEE 802.11a/n/ac
Bluetooth:       Qualcomm CSR8510 (A10)
Zigbee:          Silicon Labs EM3581 NCP + Skyworks SE2432L
Ethernet:        Qualcomm Atheros QCA8072 (2-port)
Flash:           Samsung KLM4G1FEPD (4GB eMMC)
RAM (NAND):      512MB
LED Controller:  NXP PCA9633 (I2C)
Buttons:         Single reset button (GPIO).

Ethernet:
=========
The device has 2 ethernet ports, configured as follows by default:
- left port: WAN
- right port: LAN

Wifi:
=====
The Wifi radios are turned off by default. To configure the router,
you will need to connect your computer to the LAN port of the device.

Bluetooth and Zigbee:
=====================
Configuration included but not tested.

Storage:
========
For compatibility with stock firmware, all of OpenWrt runs in a 136 MiB
eMMC partition (of which there are two copies, see below). You can also
use partition /dev/mmcblk0p19 "syscfg" (3.4 GiB) any way you see fit.
During very limited tests, stock firmware did not mount this partition.
However, backing up its stock content before use is recommended anyway.

Firmware:
=========
The device uses a dual firmware mechanism: it automatically reverts to
the previous firmware after 3 failed boot attempts.

You can switch to the inactive firmware copy by changing the "boot_part"
U-Boot environment variable. You can also do it by turning on the device
for a couple of seconds and then back off, 3 times in a row.

Installation:
=============
OpenWrt's "factory" image can be installed via the stock web UI:
1. Login to the UI. (The default password is printed on the label.)
2. Enter support mode by clicking on the "CA" link at the bottom.
3. Click "Connectivity", "Choose file", "Start", and ignore warnings.

This port is based on work done by flipy (https://github.com/flipy).

Signed-off-by: Rodrigo Balerdi <lanchon@gmail.com>
Link: https://github.com/openwrt/openwrt/pull/15345
Signed-off-by: Robert Marko <robimarko@gmail.com>
package/boot/uboot-envtools/files/ipq40xx
target/linux/ipq40xx/base-files/etc/board.d/02_network
target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
target/linux/ipq40xx/base-files/etc/init.d/bootcount
target/linux/ipq40xx/base-files/lib/preinit/05_set_iface_mac_ipq40xx.sh
target/linux/ipq40xx/base-files/lib/upgrade/linksys.sh
target/linux/ipq40xx/base-files/lib/upgrade/platform.sh
target/linux/ipq40xx/files-6.6/arch/arm/boot/dts/qcom/qcom-ipq4019-whw03.dts [new file with mode: 0644]
target/linux/ipq40xx/image/generic.mk

index 8cada7334b326d9db81f99e57cd4ccaec2903cee..717158b0425ea5aa0a86174bdf518b8bd2cfd428 100644 (file)
@@ -67,6 +67,9 @@ linksys,mr8300)
 linksys,whw01)
        ubootenv_add_uci_config "/dev/mtd6" "0x0" "0x40000" "0x10000"
        ;;
+linksys,whw03)
+        ubootenv_add_uci_config "/dev/mmcblk0p11" "0x0" "0x100000"
+        ;;
 linksys,whw03v2)
        ubootenv_add_uci_config "/dev/mtd6" "0x0" "0x80000" "0x20000"
        ;;
index 02059580a16476b8cafe52bbb3bca3ca2ca24ff7..e86d24fab5b5878e98f9c3bad7820c86d6fe056a 100644 (file)
@@ -37,6 +37,7 @@ ipq40xx_setup_interfaces()
        glinet,gl-ap1300|\
        glinet,gl-b2200|\
        google,wifi|\
+       linksys,whw03|\
        linksys,whw03v2|\
        luma,wrtq-329acn|\
        mikrotik,cap-ac|\
@@ -215,6 +216,10 @@ ipq40xx_setup_macs()
                wan_mac=$(mtd_get_mac_ascii devinfo hw_mac_addr)
                lan_mac=$(macaddr_add "$wan_mac" 1)
                ;;
+       linksys,whw03)
+               wan_mac=$(mmc_get_mac_ascii devinfo hw_mac_addr)
+               lan_mac="$wan_mac"
+               ;;
        mikrotik,cap-ac |\
        mikrotik,hap-ac2|\
        mikrotik,hap-ac3|\
index 654be2697a636266b5bb873cf4073b534094ef91..3b7f44282dcabe5ba94229323268d9ed0dfbc1c1 100644 (file)
@@ -40,6 +40,10 @@ case "$FIRMWARE" in
                # OEM assigns 4 sequential MACs
                ath10k_patch_mac $(macaddr_setbit_la $(macaddr_add "$(cat /sys/class/net/eth0/address)" 4))
                ;;
+       linksys,whw03)
+               caldata_extract_mmc "0:ART" 0x9000 0x2f20
+               ath10k_patch_mac $(macaddr_add "$(cat /sys/class/net/eth0/address)" 3)
+               ;;
        netgear,rbr40|\
        netgear,rbs40|\
        netgear,rbr50|\
@@ -104,6 +108,10 @@ case "$FIRMWARE" in
                caldata_extract "ART" 0x1000 0x2f20
                ath10k_patch_mac $(macaddr_add "$(cat /sys/class/net/eth0/address)" 2)
                ;;
+       linksys,whw03)
+               caldata_extract_mmc "0:ART" 0x1000 0x2f20
+               ath10k_patch_mac $(macaddr_add "$(cat /sys/class/net/eth0/address)" 1)
+               ;;
        meraki,mr33 |\
        meraki,mr74)
                caldata_extract_ubi "ART" 0x1000 0x2f20
@@ -200,6 +208,10 @@ case "$FIRMWARE" in
                caldata_extract "ART" 0x5000 0x2f20
                ath10k_patch_mac $(macaddr_add "$(cat /sys/class/net/eth0/address)" 3)
                ;;
+       linksys,whw03)
+               caldata_extract_mmc "0:ART" 0x5000 0x2f20
+               ath10k_patch_mac $(macaddr_add "$(cat /sys/class/net/eth0/address)" 2)
+               ;;
        meraki,mr33 |\
        meraki,mr74)
                caldata_extract_ubi "ART" 0x5000 0x2f20
index df656c9b85b71c4174cc9387daf163b9dec01d97..0120f78cfe840919f93926d88725c000dcef6474 100755 (executable)
@@ -2,6 +2,35 @@
 
 START=99
 
+mmc_resetbc() {
+       local part_label="$1"
+
+       . /lib/functions.sh
+
+       local part_device="$(find_mmc_part "$part_label")"
+       if [ "$part_device" = "" ]; then
+               >&2 echo "mmc_resetbc: Unknown partition label: $part_label"
+               return 1
+       fi
+
+       local magic_number="$(hexdump -e '"0x%02x\n"' -n 4 "$part_device")"
+       if [ "$magic_number" != "0x20110811" ]; then
+               >&2 echo "mmc_resetbc: Unexpected partition magic: $magic_number"
+               return 1
+       fi
+
+       local last_count=$(hexdump -e '"0x%02x\n"' -n 4 -s 4 "$part_device")
+       if [ "$last_count" != "0x00" ]; then
+               printf "\x00" | dd of="$part_device" bs=4 seek=1 count=1 conv=notrunc 2>/dev/null
+
+               last_count=$(hexdump -e '"0x%02x\n"' -n 4 -s 4 "$part_device")
+               if [ "$last_count" != "0x00" ]; then
+                       >&2 echo "mmc_resetbc: Unable to reset boot counter"
+                       return 1
+               fi
+       fi
+}
+
 boot() {
        case $(board_name) in
        alfa-network,ap120c-ac)
@@ -15,6 +44,9 @@ boot() {
        linksys,whw03v2)
                mtd resetbc s_env || true
                ;;
+       linksys,whw03)
+               mmc_resetbc s_env || true
+               ;;
        netgear,wac510)
                fw_setenv boot_cnt=0
                ;;
index 96e70f62a9234925ed986d5ebba387bef16d7612..1ede544aacc3b0fb294295f65b6b361b42cfd6c9 100644 (file)
@@ -30,6 +30,12 @@ preinit_set_mac_address() {
                ip link set dev lan1 address $(macaddr_add "$base_mac" 1)
                ip link set dev eth0 address $(macaddr_setbit "$base_mac" 7)
                ;;
+       linksys,whw03)
+               base_mac=$(mmc_get_mac_ascii devinfo hw_mac_addr)
+               ip link set dev eth0 address "$base_mac"
+               ip link set dev lan address "$base_mac"
+               ip link set dev wan address "$base_mac"
+               ;;
        mikrotik,wap-ac|\
        mikrotik,wap-ac-lte|\
        mikrotik,wap-r-ac)
index 18366fc622a4784530f0b5a650ca5fa3c06814c4..860c3fd2de997a271d62df92318bdc677c98ec82 100644 (file)
@@ -123,3 +123,71 @@ platform_do_upgrade_linksys() {
                get_image "$1" | mtd -e "$part_label" write - "$part_label"
        }
 }
+
+linksys_get_cmdline_rootfs_device() {
+       if read cmdline < /proc/cmdline; then
+               case "$cmdline" in
+               *root=*)
+                       local str="${cmdline##*root=}"
+                       echo "${str%% *}"
+                       return
+                       ;;
+               esac
+       fi
+       return 1
+}
+
+linksys_get_current_boot_part_emmc() {
+       local boot_part="$(fw_printenv -n boot_part)"
+       if [ "$boot_part" = 1 ] || [ "$boot_part" = 2 ]; then
+               v "Current boot_part=$boot_part selected from bootloader environment"
+       else
+               local rootfs_device="$(linksys_get_cmdline_rootfs_device)"
+               if [ "$rootfs_device" = "$(find_mmc_part "rootfs")" ]; then
+                       boot_part=1
+               elif [ "$rootfs_device" = "$(find_mmc_part "alt_rootfs")" ]; then
+                       boot_part=2
+               else
+                       v "Could not determine current boot_part"
+                       return 1
+               fi
+               v "Current boot_part=$boot_part selected from cmdline rootfs=$rootfs_device"
+       fi
+       echo $boot_part
+}
+
+linksys_set_target_partitions_emmc() {
+       local current_boot_part="$1"
+
+       if [ "$current_boot_part" = 1 ]; then
+               CI_KERNPART="alt_kernel"
+               CI_ROOTPART="alt_rootfs"
+               fw_setenv -s - <<-EOF
+                       boot_part 2
+                       auto_recovery yes
+               EOF
+       elif [ "$current_boot_part" = 2 ]; then
+               CI_KERNPART="kernel"
+               CI_ROOTPART="rootfs"
+               fw_setenv -s - <<-EOF
+                       boot_part 1
+                       auto_recovery yes
+               EOF
+       else
+               v "Could not set target eMMC partitions"
+               return 1
+       fi
+
+       v "Target eMMC partitions: $CI_KERNPART, $CI_ROOTPART"
+}
+
+platform_do_upgrade_linksys_emmc() {
+       local file="$1"
+
+       mkdir -p /var/lock
+       local current_boot_part="$(linksys_get_current_boot_part_emmc)"
+       linksys_set_target_partitions_emmc "$current_boot_part" || exit 1
+       touch /var/lock/fw_printenv.lock
+
+       emmc_do_upgrade "$file"
+}
index e93432684956ef5b963e0c01d02436944048e6e6..53a95611487b50071d23fb5640e14b28650772fb 100644 (file)
@@ -175,6 +175,9 @@ platform_do_upgrade() {
        linksys,whw03v2)
                platform_do_upgrade_linksys "$1"
                ;;
+       linksys,whw03)
+               platform_do_upgrade_linksys_emmc "$1"
+               ;;
        meraki,mr33 |\
        meraki,mr74)
                CI_KERNPART="part.safe"
@@ -236,7 +239,8 @@ platform_do_upgrade() {
 platform_copy_config() {
        case "$(board_name)" in
        glinet,gl-b2200 |\
-       google,wifi)
+       google,wifi |\
+       linksys,whw03)
                emmc_copy_config
                ;;
        esac
diff --git a/target/linux/ipq40xx/files-6.6/arch/arm/boot/dts/qcom/qcom-ipq4019-whw03.dts b/target/linux/ipq40xx/files-6.6/arch/arm/boot/dts/qcom/qcom-ipq4019-whw03.dts
new file mode 100644 (file)
index 0000000..c835a22
--- /dev/null
@@ -0,0 +1,351 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+
+#include "qcom-ipq4019.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/soc/qcom,tcsr.h>
+#include <dt-bindings/leds/common.h>
+
+/ {
+       model = "Linksys WHW03 (Velop)";
+       compatible = "linksys,whw03", "qcom,ipq4019";
+
+       aliases {
+               led-boot = &led_blue;
+               led-failsafe = &led_red;
+               led-running = &led_blue;
+               led-upgrade = &led_red;
+       };
+
+       // Default bootargs include rootfstype=ext4 and need to be overriden.
+       chosen {
+               bootargs-append = " rootfstype=squashfs";
+       };
+
+       soc {
+               ess-tcsr@1953000 {
+                       compatible = "qcom,tcsr";
+                       reg = <0x1953000 0x1000>;
+                       qcom,ess-interface-select = <TCSR_ESS_PSGMII>;
+               };
+
+
+               tcsr@1949000 {
+                       compatible = "qcom,tcsr";
+                       reg = <0x1949000 0x100>;
+                       qcom,wifi_glb_cfg = <TCSR_WIFI_GLB_CFG>;
+               };
+
+               tcsr@194b000 {
+                       compatible = "qcom,tcsr";
+                       reg = <0x194b000 0x100>;
+                       qcom,usb-hsphy-mode-select = <TCSR_USB_HSPHY_HOST_MODE>;
+               };
+
+               tcsr@1957000 {
+                       compatible = "qcom,tcsr";
+                       reg = <0x1957000 0x100>;
+                       qcom,wifi_noc_memtype_m0_m2 = <TCSR_WIFI_NOC_MEMTYPE_M0_M2>;
+               };
+       };
+
+
+       keys {
+               compatible = "gpio-keys";
+
+               reset {
+                       label = "reset";
+                       gpios = <&tlmm 18 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_RESTART>;
+               };
+       };
+};
+
+
+&tlmm {
+       mdio_pins: mdio-pinmux {
+               mux-1 {
+                       pins = "gpio6";
+                       function = "mdio";
+                       bias-pull-up;
+               };
+
+               mux-2 {
+                       pins = "gpio7";
+                       function = "mdc";
+                       bias-pull-up;
+               };
+       };
+
+       sd_pins: sd-pinmux {
+               pins = "gpio23", "gpio24", "gpio25", "gpio26",
+                       "gpio27", "gpio28", "gpio29", "gpio30",
+                       "gpio31", "gpio32";
+               function = "sdio";
+       };
+
+       i2c_0_pins: i2c-0-pinmux {
+               pins = "gpio58", "gpio59";
+               function = "blsp_i2c0";
+               bias-disable;
+       };
+
+       serial_0_pins: serial0-pinmux {
+               pins = "gpio16", "gpio17";
+               function = "blsp_uart0";
+               bias-disable;
+       };
+
+       serial_1_pins: serial1-pinmux {
+               pins = "gpio8", "gpio9", "gpio10", "gpio11";
+               function = "blsp_uart1";
+               bias-disable;
+       };
+
+       spi_0_pins: spi-0-pinmux {
+               pins = "gpio12", "gpio13", "gpio14", "gpio15";
+               function = "blsp_spi0";
+               bias-disable;
+       };
+
+       spi_1_pins: spi-1-pinmux {
+               mux-1 {
+                       pins = "gpio44", "gpio46", "gpio47";
+                       function = "blsp_spi1";
+                       bias-disable;
+               };
+
+               mux-2 {
+                       pins = "gpio45", "gpio49";
+                       function = "gpio";
+                       bias-pull-up;
+                       output-high;
+               };
+
+               host-interrupt {
+                       pins = "gpio42";
+                       function = "gpio";
+                       input;
+               };
+       };
+
+       wifi_0_pins: wifi0-pinmux {
+               pins = "gpio52";
+               function = "gpio";
+               drive-strength = <6>;
+               bias-pull-up;
+               output-high;
+       };
+
+       zigbee-0 {
+               gpio-hog;
+               gpios = <29 GPIO_ACTIVE_HIGH>;
+               bias-disable;
+               output-low;
+       };
+
+       zigbee-1 {
+               gpio-hog;
+               gpios = <50 GPIO_ACTIVE_HIGH>;
+               bias-disable;
+               input;
+       };
+
+       bluetooth-enable {
+               gpio-hog;
+               gpios = <32 GPIO_ACTIVE_HIGH>;
+               output-high;
+       };
+};
+
+&mdio {
+       status = "okay";
+       pinctrl-0 = <&mdio_pins>;
+       pinctrl-names = "default";
+       reset-gpios = <&tlmm 41 GPIO_ACTIVE_LOW>;
+};
+
+&ethphy0 {
+       status = "disabled";
+};
+
+&ethphy1 {
+       status = "disabled";
+};
+
+&ethphy2 {
+       status = "disabled";
+};
+
+&watchdog {
+       status = "okay";
+};
+
+&prng {
+       status = "okay";
+};
+
+&blsp_dma {
+       status = "okay";
+};
+
+&cryptobam {
+       num-channels = <4>;
+       qcom,num-ees = <2>;
+
+       status = "okay";
+};
+
+&crypto {
+       status = "okay";
+};
+
+&vqmmc {
+       status = "okay";
+};
+
+&blsp1_uart1 {
+       status = "okay";
+       pinctrl-0 = <&serial_0_pins>;
+       pinctrl-names = "default";
+};
+
+&blsp1_uart2 {
+       status = "okay";
+       pinctrl-0 = <&serial_1_pins>;
+       pinctrl-names = "default";
+
+       bluetooth {
+               compatible = "csr,8811";
+
+               enable-gpios = <&tlmm 32 GPIO_ACTIVE_HIGH>;
+       };
+};
+
+&blsp1_spi2 {
+       pinctrl-0 = <&spi_1_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+
+       cs-gpios = <&tlmm 45 GPIO_ACTIVE_HIGH>;
+
+       zigbee@0 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               compatible = "silabs,em3581";
+               reg = <0>;
+               spi-max-frequency = <12000000>;
+       };
+};
+
+&blsp1_i2c3 {
+       pinctrl-0 = <&i2c_0_pins>;
+       pinctrl-names = "default";
+
+       status = "okay";
+
+       // RGB LEDs
+       pca9633: led-controller@62 {
+               compatible = "nxp,pca9633";
+               nxp,hw-blink;
+               reg = <0x62>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               led_red: red@0 {
+                       color = <LED_COLOR_ID_RED>;
+                       function = LED_FUNCTION_INDICATOR;
+                       reg = <0>;
+               };
+
+               led_green: green@1 {
+                       color = <LED_COLOR_ID_GREEN>;
+                       function = LED_FUNCTION_INDICATOR;
+                       reg = <1>;
+               };
+
+               led_blue: blue@2 {
+                       color = <LED_COLOR_ID_BLUE>;
+                       function = LED_FUNCTION_INDICATOR;
+                       reg = <2>;
+               };
+       };
+};
+
+&sdhci {
+       vqmmc-supply = <&vqmmc>;
+       pinctrl-0 = <&sd_pins>;
+       pinctrl-names = "default";
+       cd-gpios = <&tlmm 22 GPIO_ACTIVE_LOW>;
+       sd-ldo-gpios = <&tlmm 33 GPIO_ACTIVE_LOW>;
+       status = "okay";
+};
+
+&pcie0 {
+       status = "okay";
+
+       perst-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>;
+       wake-gpios = <&tlmm 40 GPIO_ACTIVE_LOW>;
+       clkreq-gpios = <&tlmm 39 GPIO_ACTIVE_LOW>;
+
+       bridge@0,0 {
+               reg = <0x00000000 0 0 0 0>;
+               #address-cells = <3>;
+               #size-cells = <2>;
+               ranges;
+
+               wifi2: wifi@1,0 {
+                       compatible = "qcom,ath10k";
+                       reg = <0x00000000 0 0 0 0>;
+               };
+       };
+};
+
+&qpic_bam {
+       status = "okay";
+};
+
+&gmac {
+       status = "okay";
+};
+
+&switch {
+       status = "okay";
+};
+
+&swport4 {
+       status = "okay";
+       label = "lan";
+};
+
+&swport5 {
+       status = "okay";
+       label = "wan";
+};
+
+&wifi0 {
+       pinctrl-0 = <&wifi_0_pins>;
+       pinctrl-names = "default";
+
+       status = "okay";
+
+       qcom,coexist-support = <1>;
+       qcom,coexist-gpio-pin = <52>;
+
+       qcom,ath10k-calibration-variant = "linksys-whw03";
+};
+
+&wifi1 {
+       status = "okay";
+
+       ieee80211-freq-limit = <5170000 5330000>;
+       qcom,ath10k-calibration-variant = "linksys-whw03";
+};
+
+&wifi2 {
+       status = "okay";
+
+       ieee80211-freq-limit = <5490000 5835000>;
+       qcom,ath10k-calibration-variant = "linksys-whw03";
+};
index 3b6d1119053c6bec7c4ac629aaedd6eb3b6eab30..7af777248d49048480baecf841ee3b2df9b01cc6 100644 (file)
@@ -723,6 +723,20 @@ define Device/linksys_mr8300
 endef
 TARGET_DEVICES += linksys_mr8300
 
+define Device/linksys_whw03
+       $(call Device/FitzImage)
+       DEVICE_VENDOR := Linksys
+       DEVICE_MODEL := WHW03
+       SOC := qcom-ipq4019
+       KERNEL_SIZE := 8192k
+       IMAGE_SIZE := 131072k
+       IMAGES += factory.bin
+       IMAGE/factory.bin  := append-kernel | pad-to $$$$(KERNEL_SIZE) | append-rootfs | pad-rootfs | linksys-image type=WHW03
+       DEVICE_PACKAGES := ath10k-firmware-qca9888-ct kmod-leds-pca963x kmod-spi-dev kmod-bluetooth \
+               kmod-fs-ext4 e2fsprogs kmod-fs-f2fs mkf2fs losetup
+endef
+TARGET_DEVICES += linksys_whw03
+
 define Device/linksys_whw03v2
        $(call Device/FitzImage)
        DEVICE_VENDOR := Linksys