diff --git a/package/boot/uboot-tools/uboot-envtools/files/ipq806x b/package/boot/uboot-tools/uboot-envtools/files/ipq806x index 44dae17c1b..a018d0d7e5 100644 --- a/package/boot/uboot-tools/uboot-envtools/files/ipq806x +++ b/package/boot/uboot-tools/uboot-envtools/files/ipq806x @@ -35,6 +35,12 @@ arris,tr4400-v2|\ askey,rt4230w-rev6) ubootenv_add_uci_config "/dev/mtd9" "0x0" "0x40000" "0x20000" ;; +aruba,ap-32x|\ +ignitenet,ss-w2-ac2600|\ +qcom,ipq8064-ap148|\ +qcom,ipq8064-db149) + ubootenv_add_uci_config $(ubootenv_mtdinfo) + ;; edgecore,ecw5410) ubootenv_add_uci_config "/dev/mtd11" "0x0" "0x10000" "0x10000" ;; @@ -42,11 +48,6 @@ extreme,ap3935) ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x10000" "0x10000" ubootenv_add_uci_config "/dev/mtd3" "0x0" "0x10000" "0x10000" ;; -ignitenet,ss-w2-ac2600|\ -qcom,ipq8064-ap148|\ -qcom,ipq8064-db149) - ubootenv_add_uci_config $(ubootenv_mtdinfo) - ;; linksys,ea7500-v1|\ linksys,ea8500) ubootenv_add_uci_config "/dev/mtd10" "0x0" "0x20000" "0x20000" diff --git a/scripts/aruba-header.py b/scripts/aruba-header.py new file mode 100755 index 0000000000..e7dfa62e14 --- /dev/null +++ b/scripts/aruba-header.py @@ -0,0 +1,225 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (C) 2025 Lukas Stockner +# +# ./aruba-header.py +# +# Generates a header for use with the APBoot bootloader on (some?) Aruba APs. + +import argparse + +LEN_BUILD = 256 +LEN_VERSION = 24 +LEN_OEM = 32 + +HEADER_MAGIC = b'ARUBA\0\0\0' + + +class ValidFlag: + YES = 1 + + +class FormatVersion: + CURRENT = 2 + + +class ImageType: + ELF = 0 + FPGA_BINARY = 1 + CPBOOT_BINARY = 2 + APBOOT_BINARY = 3 + TPMINFO = 4 + APBOOT_STAGE1_BINARY = 5 + APBOOT_STAGE2_BINARY = 6 + APBOOT_COMBINED_BINARY = 7 + OS_ANCILLARY_IMAGE = 8 + XLOADER_BINARY = 9 + GRUB_BIN = 10 + LSM_PACKAGE = 11 + + +class CompressionType: + NONE = 0 + BZIP2 = 1 + GZIP = 2 + + +MACHINE_TYPES = { + 'MSWITCH': 0, + 'CABERNET': 1, + 'SYRAH': 2, + 'MERLOT': 3, + 'MUSCAT': 4, + 'NEBBIOLO': 5, + 'MALBEC': 6, + 'PALOMINO': 7, + 'GRENACHE': 8, + 'MOSCATO': 9, + 'TALISKER': 10, + 'JURA_R': 11, + 'SCAPA': 12, + 'JURA_O': 13, + 'CORVINA': 14, + 'ARRAN': 15, + 'BLUEBLOOD': 16, + 'MSR2K': 17, + 'PORFIDIO': 18, + 'CAZULO': 19, + 'SCAPA_H': 20, + 'CARDHU': 21, + 'BOWMORE': 22, + 'TAMDHU': 23, + 'ARDBEG': 24, + 'ARDMORE': 25, + 'DALMORE': 26, + 'K2': 27, + 'GRAPPA': 28, + 'SHUMWAY': 29, + 'SPRINGBANK': 30, + 'OUZO': 31, + 'AMARULA': 32, + 'GROZDOVA': 33, + 'PALINKA': 34, + 'HAZELBURN': 35, + 'TOMATIN': 36, + 'HAZELBURN_H': 37, + 'TOMATIN_16': 38, + 'SPRINGBANK_16': 39, + 'OCTOMORE': 40, + 'BALVENIE': 41, + 'OUZO_PLUS': 42, + 'X4': 43, + 'EINAR': 44, + 'GLENFARCLAS': 45, + 'GLENFIDDICH': 46, + 'EIGER': 47, + 'GLENMORANGIE': 48, + 'MILAGRO': 49, + 'OPUSONE': 50, + 'ABERLOUR': 51, + 'MILLSTONE': 52, + 'DEWARS': 53, + 'BUNKER': 54, + 'MASTERSON': 55, + 'SIERRA': 56, + 'KILCHOMAN': 57, + 'SPEYBURN': 58, + 'LAGAVULIN': 59, + 'LAPHROAIG': 60, + 'TOBA': 61, + 'ARRANTA': 62, +} + + +class NextHeader: + NONE = 0x00000000 + SIGN = 0x01111111 + + +class Flags: + C_TEST_BUILD = 0x00000001 + SWATCH = 0x00000002 + # Preserves the image with "clear all" + DONT_CLEAR_ON_PURGE = 0x00000004 + SECURE_BOOTLOADER = 0x00000008 + FACTORY_IMAGE = 0x00000010 + FIPS_CERTIFIED = 0x00000020 + + +def make_header(data: bytes, build: str, version: str, oem: str, imageType: int, machine: int) -> bytes: + buildBytes = build.encode(encoding='ascii') + assert len(buildBytes) < LEN_BUILD + buildBytes += b'\0' * (LEN_BUILD - len(buildBytes)) + + versionBytes = version.encode(encoding='ascii') + assert len(versionBytes) < LEN_VERSION + versionBytes += b'\0' * (LEN_VERSION - len(versionBytes)) + + oemBytes = oem.encode(encoding='ascii') + assert len(oemBytes) < LEN_OEM + oemBytes += b'\0' * (LEN_OEM - len(oemBytes)) + + header = b'' + # Payload size, image plus optional signature (which we don't use) + header += len(data).to_bytes(4, 'big') + # Use what appears to be the current version + header += FormatVersion.CURRENT.to_bytes(4, 'big') + # Checksum is computed later + header += b'\0\0\0\0' + # Vendor magic number + header += HEADER_MAGIC + # Long build information string + header += buildBytes + # Short version information string + header += versionBytes + # Image is valid + header += ValidFlag.YES.to_bytes(1, 'big') + # Image type + header += imageType.to_bytes(1, 'big') + # APBoot doesn't appear to actually support compression + header += CompressionType.NONE.to_bytes(1, 'big') + # Machine type + header += machine.to_bytes(1, 'big') + # Image size + header += len(data).to_bytes(4, 'big') + # Next header (we don't support signing) + header += NextHeader.NONE.to_bytes(4, 'big') + # MD5 checksum plus fudge factor (to ensure non-zero hash), appears unused + header += b'\0' * 16 + header += b'\0' * 4 + # No flags are set + header += int(0).to_bytes(4, 'big') + # No next header is used + header += b'\0' * 12 + # Padding + header += b'\0' * 36 + # OEM string + header += oemBytes + # Padding + header += b'\0' * 96 + + assert len(header) == 512 + assert len(data) % 4 == 0 + + # Compute checksum such that the big-endian sum of all 32-bit integers becomes zero. + curSum = sum(int.from_bytes(header[i : i + 4], 'big') for i in range(0, 512, 4)) + curSum += sum(int.from_bytes(data[i : i + 4], 'big') for i in range(0, len(data), 4)) + + # Set checksum + checksum = 0x100000000 - (curSum % 0x100000000) + header = header[:8] + checksum.to_bytes(4, 'big') + header[12:] + + return header + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Generate Aruba header.') + parser.add_argument('source') + parser.add_argument('dest') + parser.add_argument('build') + parser.add_argument('version') + parser.add_argument('oem') + parser.add_argument('type', choices=['os', 'boot']) + parser.add_argument('machine', choices=MACHINE_TYPES.keys(), type=str.upper) + args = parser.parse_args() + + # Parse image type. + # The OS image must be type "ELF" even though it's not an ELF file... + imageType = {'os': ImageType.ELF, 'boot': ImageType.APBOOT_BINARY}[args.type] + # Parse machine type. + machineType = MACHINE_TYPES[args.machine] + + source = open(args.source, 'rb') + image = source.read() + # Pad image. + if len(image) % 4 != 0: + image += b'\0' * (4 - len(image) % 4) + + # Generate header. + header = make_header(image, args.build, args.version, args.oem, imageType, machineType) + + # Write output. + dest = open(args.dest, 'wb') + dest.write(header) + dest.write(image) diff --git a/target/linux/ipq806x/base-files/etc/board.d/02_network b/target/linux/ipq806x/base-files/etc/board.d/02_network index 6f490cb55d..e034172886 100644 --- a/target/linux/ipq806x/base-files/etc/board.d/02_network +++ b/target/linux/ipq806x/base-files/etc/board.d/02_network @@ -14,6 +14,11 @@ ipq806x_setup_interfaces() arris,tr4400-v2) ucidef_set_interfaces_lan_wan "lan1 lan2 lan3 lan4" "eth2" ;; + aruba,ap-32x|\ + edgecore,ecw5410|\ + extreme,ap3935) + ucidef_set_interfaces_lan_wan "eth1" "eth0" + ;; askey,rt4230w-rev6|\ asrock,g10|\ buffalo,wxr-2533dhp|\ @@ -47,10 +52,6 @@ ipq806x_setup_interfaces() ucidef_set_network_device_conduit "lan1" "eth1" ucidef_set_network_device_conduit "wan" "eth0" ;; - edgecore,ecw5410|\ - extreme,ap3935) - ucidef_set_interfaces_lan_wan "eth1" "eth0" - ;; fortinet,fap-421e|\ ignitenet,ss-w2-ac2600|\ ubnt,unifi-ac-hd|\ diff --git a/target/linux/ipq806x/base-files/etc/init.d/bootcount b/target/linux/ipq806x/base-files/etc/init.d/bootcount index 669b815e39..1b9ace9f63 100755 --- a/target/linux/ipq806x/base-files/etc/init.d/bootcount +++ b/target/linux/ipq806x/base-files/etc/init.d/bootcount @@ -6,13 +6,14 @@ START=99 boot() { case $(board_name) in - asrock,g10) - asrock_bootconfig_mangle "bootcheck" && reboot - ;; + aruba,ap-32x|\ edgecore,ecw5410|\ ignitenet,ss-w2-ac2600) fw_setenv bootcount 0 ;; + asrock,g10) + asrock_bootconfig_mangle "bootcheck" && reboot + ;; extreme,ap3935) fw_setenv WATCHDOG_COUNT 0x00000000 ;; diff --git a/target/linux/ipq806x/base-files/lib/upgrade/platform.sh b/target/linux/ipq806x/base-files/lib/upgrade/platform.sh index 972aa41a85..e980598a38 100644 --- a/target/linux/ipq806x/base-files/lib/upgrade/platform.sh +++ b/target/linux/ipq806x/base-files/lib/upgrade/platform.sh @@ -26,6 +26,21 @@ platform_do_upgrade() { qcom,ipq8064-ap161) nand_do_upgrade "$1" ;; + aruba,ap-32x) + # The bootloader on this device unfortunately enforces a particular set of UBI volumes, + # and will mess with the partitioning if it doesn't find it. + # Therefore, we have to make do with the stock layout, which is a set of three + # MTD partitions, each containing a single UBI volume with the same name. + # Luckily, it doesn't check size, so we can have a "rootfs_data" volume next to a dummy + # "ubifs" volume on the "ubifs" partition. + CI_KERNPART="aos0" + CI_ROOTPART="aos1" + CI_KERN_UBIPART="aos0" + CI_ROOT_UBIPART="aos1" + CI_DATA_UBIPART="ubifs" + CI_SKIP_KERNEL_MTD=1 + nand_do_upgrade "$1" + ;; asrock,g10) asrock_upgrade_prepare nand_do_upgrade "$1" diff --git a/target/linux/ipq806x/dts/qcom-ipq8068-ap-32x.dts b/target/linux/ipq806x/dts/qcom-ipq8068-ap-32x.dts new file mode 100644 index 0000000000..b6f1b7b110 --- /dev/null +++ b/target/linux/ipq806x/dts/qcom-ipq8068-ap-32x.dts @@ -0,0 +1,377 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qcom-ipq8064-v2.0.dtsi" + +#include +#include +#include + +/ { + model = "Aruba AP-32x"; + compatible = "aruba,ap-32x", "qcom,ipq8064"; + + memory@0 { + reg = <0x41500000 0x1eb00000>; + device_type = "memory"; + }; + + aliases { + serial0 = &gsbi4_serial; + serial1 = &gsbi2_serial; + + ethernet0 = &gmac2; + ethernet1 = &gmac3; + + led-boot = &led_power_amber; + led-failsafe = &led_power_red; + led-running = &led_power_green; + led-upgrade = &led_power_amber; + + label-mac-device = &gmac2; + }; + + chosen { + stdout-path = "serial0:115200n8"; + bootargs-append = " ubi.mtd=aos1 ubi.mtd=ubifs ubi.block=0,aos1 root=/dev/ubiblock0_0"; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 9 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + led_power_green: power_green { + function = LED_FUNCTION_POWER; + color = ; + gpios = <&qcom_pinmux 28 GPIO_ACTIVE_HIGH>; + }; + + led_power_amber: power_amber { + function = LED_FUNCTION_POWER; + color = ; + gpios = <&qcom_pinmux 29 GPIO_ACTIVE_HIGH>; + }; + + led_power_red: power_red { + function = LED_FUNCTION_POWER; + color = ; + gpios = <&qcom_pinmux 30 GPIO_ACTIVE_HIGH>; + }; + + led_wlan_green { + function = LED_FUNCTION_WLAN; + color = ; + gpios = <&qcom_pinmux 31 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "phy0tpt"; + }; + + led_wlan_amber { + function = LED_FUNCTION_WLAN; + color = ; + gpios = <&qcom_pinmux 32 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "phy1tpt"; + }; + }; + + watchdog { + compatible = "linux,wdt-gpio"; + gpios = <&qcom_pinmux 61 GPIO_ACTIVE_LOW>; + hw_algo = "toggle"; + hw_margin_ms = <1000>; + always-running; + + pinctrl-names = "default"; + pinctrl-0 = <&watchdog_pins>; + }; + + i2c { + compatible = "i2c-gpio"; + + sda-gpios = <&qcom_pinmux 24 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + scl-gpios = <&qcom_pinmux 25 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + + #address-cells = <1>; + #size-cells = <0>; + + tpm@29 { + compatible = "atmel,at97sc3204t"; + reg = <0x29>; + }; + }; +}; + +&qcom_pinmux { + led_pins: led_pins { + mux { + pins = "gpio28", "gpio29", "gpio30", "gpio31", "gpio32"; + function = "gpio"; + drive-strength = <12>; + bias-pull-up; + }; + }; + + button_pins: button_pins { + mux { + pins = "gpio9"; + function = "gpio"; + bias-pull-up; + }; + }; + + uart0_pins: uart0_pins { + mux { + pins = "gpio10", "gpio11"; + function = "gsbi4"; + drive-strength = <10>; + bias-disable; + }; + }; + + uart1_pins: uart1_pins { + mux { + pins = "gpio22", "gpio23"; + function = "gsbi2"; + drive-strength = <10>; + bias-disable; + }; + }; + + watchdog_pins: watchdog_pins { + mux { + pins = "gpio61"; + function = "gpio"; + drive-strength = <10>; + bias-disable; + }; + }; + /* used for USB over-current detection instead */ + /delete-node/ pcie2_pins; +}; + +&gsbi4 { + status = "okay"; + qcom,mode = ; +}; + +&gsbi4_serial { + status = "okay"; + pinctrl-0 = <&uart0_pins>; + pinctrl-names = "default"; +}; + +&gsbi2 { + status = "okay"; + qcom,mode = ; +}; + +&gsbi2_serial { + status = "okay"; + pinctrl-0 = <&uart1_pins>; + pinctrl-names = "default"; +}; + +&gsbi5 { + qcom,mode = ; + status = "okay"; + + spi@1a280000 { + status = "okay"; + spi-max-frequency = <50000000>; + + pinctrl-0 = <&spi_pins>; + pinctrl-names = "default"; + + cs-gpios = <&qcom_pinmux 20 GPIO_ACTIVE_LOW>; + + mx25u3235f@0 { + compatible = "jedec,spi-nor"; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <50000000>; + reg = <0>; + + partitions { + compatible = "qcom,smem-part"; + + partition-art { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + label = "0:art"; + + precal_art_1000: precal@1000 { + reg = <0x1000 0x2f20>; + }; + + precal_art_5000: precal@5000 { + reg = <0x5000 0x2f20>; + }; + }; + + partition-appsblenv { + label = "0:appsblenv"; + + nvmem-layout { + compatible = "u-boot,env"; + + macaddr_lan: ethaddr { + #nvmem-cell-cells = <1>; + }; + }; + }; + }; + }; + }; +}; + +&pcie0 { + status = "okay"; +}; + +&pcie_bridge0 { + wifi@0,0 { + compatible = "qcom,ath10k"; + status = "okay"; + reg = <0x10000 0 0 0 0>; + + nvmem-cells = <&precal_art_1000>; + nvmem-cell-names = "pre-calibration"; + }; +}; + +&pcie1 { + status = "okay"; +}; + +&pcie_bridge1 { + wifi@0,0 { + compatible = "qcom,ath10k"; + status = "okay"; + reg = <0x10000 0 0 0 0>; + + nvmem-cells = <&precal_art_5000>; + nvmem-cell-names = "pre-calibration"; + }; +}; + +&nand { + status = "okay"; + + nand@0 { + compatible = "qcom,nandcs"; + + reg = <0>; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + aos0@0 { + label = "aos0"; + reg = <0x0 0x2000000>; + }; + + aos1@2000000 { + label = "aos1"; + reg = <0x2000000 0x2000000>; + }; + + ubifs@4000000 { + label = "ubifs"; + reg = <0x4000000 0x4000000>; + }; + }; + }; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy0: ethernet-phy@0 { + reg = <0>; + }; + + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + +&gmac2 { + status = "okay"; + + qcom,id = <2>; + mdiobus = <&mdio0>; + + phy-mode = "sgmii"; + phy-handle = <&phy0>; + + nvmem-cells = <&macaddr_lan 0>; + nvmem-cell-names = "mac-address"; +}; + +&gmac3 { + status = "okay"; + + qcom,id = <3>; + mdiobus = <&mdio0>; + + phy-mode = "sgmii"; + phy-handle = <&phy1>; + + nvmem-cells = <&macaddr_lan 1>; + nvmem-cell-names = "mac-address"; +}; + +&adm_dma { + status = "okay"; +}; + +/* USB Port 0 is connected to the onboard BLE SoC. + * The stock FW on that doesn't implement USB, so to prevent errors from + * being logged when the host fails to initialize it, it's disabled by + * default here. */ +&hs_phy_0 { + status = "disabled"; +}; + +&ss_phy_0 { + status = "disabled"; +}; + +&usb3_0 { + status = "disabled"; +}; + +&hs_phy_1 { + status = "okay"; +}; + +&ss_phy_1 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; diff --git a/target/linux/ipq806x/image/generic.mk b/target/linux/ipq806x/image/generic.mk index 5fbb3a79e6..9da73c4c03 100644 --- a/target/linux/ipq806x/image/generic.mk +++ b/target/linux/ipq806x/image/generic.mk @@ -48,6 +48,18 @@ define Build/linksys-addfwhdr ;mv "$@.new" "$@" endef +define Build/apboot-addfwhdr + $(SCRIPT_DIR)/aruba-header.py \ + $@ $@.new \ + "$(call toupper,$(LINUX_KARCH)) $(VERSION_DIST) Linux-$(LINUX_VERSION), $(VERSION_NUMBER) $(VERSION_CODE)"\ + "$(VERSION_NUMBER)" \ + "$(VERSION_DIST)" \ + os \ + "$(word 1,$(1))" + + mv "$@.new" "$@" +endef + define Device/DniImage KERNEL_SUFFIX := -uImage KERNEL = kernel-bin | append-dtb | uImage none @@ -102,6 +114,25 @@ define Device/arris_tr4400-v2 endef TARGET_DEVICES += arris_tr4400-v2 +define Device/aruba_ap-32x + $(call Device/LegacyImage) + DEVICE_VENDOR := Aruba + DEVICE_MODEL := AP-325 + DEVICE_ALT0_VENDOR := Aruba + DEVICE_ALT0_MODEL := AP-324 + DEVICE_ALT1_VENDOR := Siemens + DEVICE_ALT1_MODEL := Scalance W1750D + SOC := qcom-ipq8068 + PAGESIZE := 2048 + BLOCKSIZE := 128k + KERNEL_SUFFIX := .ari + KERNEL = kernel-bin | append-dtb | uImage none | apboot-addfwhdr Octomore + KERNEL_LOADADDR = 0x41508000 + KERNEL_SIZE := 30720k + DEVICE_PACKAGES := ath10k-firmware-qca99x0-ct kmod-i2c-gpio kmod-tpm-i2c-atmel +endef +TARGET_DEVICES += aruba_ap-32x + define Device/askey_rt4230w-rev6 $(call Device/LegacyImage) $(Device/dsa-migration)