From c2c75b67ebe84c63bfdc772fe0dcb4ac960a00c7 Mon Sep 17 00:00:00 2001 From: Piotr Dymacz Date: Thu, 10 Mar 2022 08:23:33 +0100 Subject: [PATCH] ipq807x: add initial support for YunCore AX840 This adds initial support for the YunCore AX840, an IPQ6010 based 802.11ax ceiling AP. Specifications: - Qualcomm IPQ6010 - 1 GB of RAM (DDR3) - 8 MB of serial flash (SPI NOR) - 256 MB of parallel flash (NAND) - 2x2 2.4 GHz WiFi (IPQ6010) - 2x2 5 GHz WiFi (IPQ6010) - 2x IPEX/U.FL antenna connectors - 4x 3 dBi dual-band antennas - 2x 1 Gbps Ethernet (QCA8075) with 802.3at PoE input support - 1x RGB LED - 1x push-button (reset) - DC jack for main power input (12 V) - UART (4-pin, 2.54 mm pitch) header on PCB Flash instruction under stock QSDK image: sysupgrade -n openwrt-ipq807x-yuncore_ax840-squashfs-nand-factory.bin Flash instruction under U-Boot: tftpb 0x44000000 openwrt-ipq807x-yuncore_ax840-squashfs-nand-factory.ubi flash rootfs reset Signed-off-by: Piotr Dymacz --- .../ipq807x/base-files/etc/board.d/02_network | 1 + .../etc/hotplug.d/firmware/10-ath11k-caldata | 1 + .../base-files/lib/upgrade/platform.sh | 2 + .../boot/dts/qcom-ipq6018-yuncore-ax840.dts | 18 + .../dts/qcom/qcom-ipq6018-yuncore-ax840.dts | 343 ++++++++++++++++++ feeds/ipq807x/ipq807x/image/ipq60xx.mk | 9 + feeds/wifi-ax/ath11k-wifi/Makefile | 4 +- .../board-yuncore-ax840.bin.IPQ6018 | Bin 0 -> 65536 bytes profiles/yuncore_ax840.yml | 12 + 9 files changed, 389 insertions(+), 1 deletion(-) create mode 100644 feeds/ipq807x/ipq807x/files/arch/arm/boot/dts/qcom-ipq6018-yuncore-ax840.dts create mode 100644 feeds/ipq807x/ipq807x/files/arch/arm64/boot/dts/qcom/qcom-ipq6018-yuncore-ax840.dts create mode 100644 feeds/wifi-ax/ath11k-wifi/board-yuncore-ax840.bin.IPQ6018 create mode 100644 profiles/yuncore_ax840.yml diff --git a/feeds/ipq807x/ipq807x/base-files/etc/board.d/02_network b/feeds/ipq807x/ipq807x/base-files/etc/board.d/02_network index d35b67670..f7b4a625a 100755 --- a/feeds/ipq807x/ipq807x/base-files/etc/board.d/02_network +++ b/feeds/ipq807x/ipq807x/base-files/etc/board.d/02_network @@ -32,6 +32,7 @@ qcom_setup_interfaces() cig,wf194c4|\ edgecore,eap106|\ qcom,ipq5018-mp03.3|\ + yuncore,ax840|\ sercomm,wallaby) ucidef_set_interface_lan "eth0" ucidef_set_interface_wan "eth1" diff --git a/feeds/ipq807x/ipq807x/base-files/etc/hotplug.d/firmware/10-ath11k-caldata b/feeds/ipq807x/ipq807x/base-files/etc/hotplug.d/firmware/10-ath11k-caldata index e52d8e018..7c85b9874 100755 --- a/feeds/ipq807x/ipq807x/base-files/etc/hotplug.d/firmware/10-ath11k-caldata +++ b/feeds/ipq807x/ipq807x/base-files/etc/hotplug.d/firmware/10-ath11k-caldata @@ -81,6 +81,7 @@ case "$FIRMWARE" in qcom,ipq807x-hk14|\ tplink,ex227|\ tplink,ex447|\ + yuncore,ax840|\ sercomm,wallaby) caldata_extract "0:ART" 0x1000 0x20000 ;; diff --git a/feeds/ipq807x/ipq807x/base-files/lib/upgrade/platform.sh b/feeds/ipq807x/ipq807x/base-files/lib/upgrade/platform.sh index 10d543d0e..4d6c7ca17 100755 --- a/feeds/ipq807x/ipq807x/base-files/lib/upgrade/platform.sh +++ b/feeds/ipq807x/ipq807x/base-files/lib/upgrade/platform.sh @@ -37,6 +37,7 @@ platform_check_image() { hfcl,ion4xe|\ tplink,ex227|\ tplink,ex447|\ + yuncore,ax840|\ qcom,ipq6018-cp01|\ qcom,ipq807x-hk01|\ qcom,ipq807x-hk14|\ @@ -72,6 +73,7 @@ platform_do_upgrade() { qcom,ipq5018-mp03.3|\ wallys,dr6018|\ wallys,dr6018-v4|\ + yuncore,ax840|\ tplink,ex447|\ tplink,ex227) nand_upgrade_tar "$1" diff --git a/feeds/ipq807x/ipq807x/files/arch/arm/boot/dts/qcom-ipq6018-yuncore-ax840.dts b/feeds/ipq807x/ipq807x/files/arch/arm/boot/dts/qcom-ipq6018-yuncore-ax840.dts new file mode 100644 index 000000000..a84bcf361 --- /dev/null +++ b/feeds/ipq807x/ipq807x/files/arch/arm/boot/dts/qcom-ipq6018-yuncore-ax840.dts @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "../../../arm64/boot/dts/qcom/qcom-ipq6018-yuncore-ax840.dts" +#include "qcom-ipq6018.dtsi" diff --git a/feeds/ipq807x/ipq807x/files/arch/arm64/boot/dts/qcom/qcom-ipq6018-yuncore-ax840.dts b/feeds/ipq807x/ipq807x/files/arch/arm64/boot/dts/qcom/qcom-ipq6018-yuncore-ax840.dts new file mode 100644 index 000000000..0eb8cd6bc --- /dev/null +++ b/feeds/ipq807x/ipq807x/files/arch/arm64/boot/dts/qcom/qcom-ipq6018-yuncore-ax840.dts @@ -0,0 +1,343 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/dts-v1/; + +#include "qcom-ipq6018.dtsi" +#include "qcom-ipq6018-rpm-regulator.dtsi" +#include "qcom-ipq6018-cpr-regulator.dtsi" +#include "qcom-ipq6018-cp-cpu.dtsi" +#include +#include + +/ { + model = "YunCore AX840"; + compatible = "yuncore,ax840", "qcom,ipq6018-cp03", "qcom,ipq6018"; + + #address-cells = <0x2>; + #size-cells = <0x2>; + interrupt-parent = <&intc>; + + aliases { + /* Aliases as required by u-boot to patch MAC addresses */ + ethernet0 = "/soc/dp2"; + ethernet1 = "/soc/dp1"; + + serial0 = &blsp1_uart3; + serial1 = &blsp1_uart2; + + led-boot = &led_system; + led-failsafe = &led_system; + led-running = &led_system; + led-upgrade = &led_system; + }; + + chosen { + bootargs = "console=ttyMSM0,115200,n8 rw init=/init"; + bootargs-append = " swiotlb=1 coherent_pool=2M"; + }; + + reserved-memory { + tzapp:tzapp@49B00000 { /* TZAPPS */ + no-map; + reg = <0x0 0x49B00000 0x0 0x00600000>; + }; + }; +}; + +&tlmm { + uart_pins: uart_pins { + mux { + pins = "gpio44", "gpio45"; + function = "blsp2_uart"; + drive-strength = <8>; + bias-pull-down; + }; + }; + + spi_0_pins: spi_0_pins { + mux { + pins = "gpio38", "gpio39", "gpio40", "gpio41"; + function = "blsp0_spi"; + drive-strength = <8>; + bias-pull-down; + }; + }; + + qpic_pins: qpic_pins { + data_0 { + pins = "gpio15"; + function = "qpic_pad0"; + drive-strength = <8>; + bias-pull-down; + }; + + data_1 { + pins = "gpio12"; + function = "qpic_pad1"; + drive-strength = <8>; + bias-pull-down; + }; + + data_2 { + pins = "gpio13"; + function = "qpic_pad2"; + drive-strength = <8>; + bias-pull-down; + }; + + data_3 { + pins = "gpio14"; + function = "qpic_pad3"; + drive-strength = <8>; + bias-pull-down; + }; + + data_4 { + pins = "gpio5"; + function = "qpic_pad4"; + drive-strength = <8>; + bias-pull-down; + }; + + data_5 { + pins = "gpio6"; + function = "qpic_pad5"; + drive-strength = <8>; + bias-pull-down; + }; + + data_6 { + pins = "gpio7"; + function = "qpic_pad6"; + drive-strength = <8>; + bias-pull-down; + }; + + data_7 { + pins = "gpio8"; + function = "qpic_pad7"; + drive-strength = <8>; + bias-pull-down; + }; + + qpic_pad { + pins = "gpio1", "gpio3", "gpio4", + "gpio10", "gpio11", "gpio17"; + function = "qpic_pad"; + drive-strength = <8>; + bias-pull-down; + }; + }; + + button_pins: button_pins { + rst_button { + pins = "gpio19"; + function = "gpio"; + drive-strength = <8>; + bias-pull-up; + }; + }; + + mdio_pins: mdio_pinmux { + mux_0 { + pins = "gpio64"; + function = "mdc"; + drive-strength = <8>; + bias-pull-up; + }; + + mux_1 { + pins = "gpio65"; + function = "mdio"; + drive-strength = <8>; + bias-pull-up; + }; + + mux_2 { + pins = "gpio75"; + function = "gpio"; + bias-pull-up; + }; + }; + + leds_pins: leds_pins { + led_blue { + pins = "gpio35"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + led_green { + pins = "gpio37"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + led_red { + pins = "gpio32"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + }; +}; + +&soc { + mdio: mdio@90000 { + status = "ok"; + + pinctrl-0 = <&mdio_pins>; + pinctrl-names = "default"; + phy-reset-gpio = <&tlmm 75 0>; + + ethernet-phy@0 { + reg = <0x03>; + }; + + ethernet-phy@1 { + reg = <0x04>; + }; + }; + + ess-switch@3a000000 { + switch_cpu_bmp = <0x01>; /* cpu port bitmap */ + switch_lan_bmp = <0x10>; /* lan port bitmap */ + switch_wan_bmp = <0x20>; /* wan port bitmap */ + switch_inner_bmp = <0x80>; /*inner port bitmap*/ + switch_mac_mode = <0x00>; /* mac mode for uniphy instance0*/ + switch_mac_mode1 = <0xff>; /* mac mode for uniphy instance1*/ + switch_mac_mode2 = <0xff>; /* mac mode for uniphy instance2*/ + + qcom,port_phyinfo { + port@3 { + port_id = <0x04>; + phy_address = <0x03>; + }; + + port@4 { + port_id = <0x05>; + phy_address = <0x04>; + }; + }; + }; + + dp1 { + device_type = "network"; + compatible = "qcom,nss-dp"; + qcom,id = <0x05>; + reg = <0x3a001800 0x200>; + qcom,mactype = <0x00>; + local-mac-address = [00 00 00 00 00 00]; + qcom,link-poll = <0x01>; + qcom,phy-mdio-addr = <0x04>; + phy-mode = "sgmii"; + }; + + dp2 { + device_type = "network"; + compatible = "qcom,nss-dp"; + qcom,id = <0x04>; + reg = <0x3a001600 0x200>; + qcom,mactype = <0x00>; + local-mac-address = [00 00 00 00 00 00]; + qcom,link-poll = <0x01>; + qcom,phy-mdio-addr = <0x03>; + phy-mode = "sgmii"; + }; + + gpio_keys { + compatible = "gpio-keys"; + + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + reset { + label = "reset"; + linux,code = ; + gpios = <&tlmm 19 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + debounce-interval = <60>; + }; + }; + + leds { + compatible = "gpio-leds"; + + pinctrl-0 = <&leds_pins>; + pinctrl-names = "default"; + + led_system: system { + label = "ax860:green:system"; + gpio = <&tlmm 37 GPIO_ACTIVE_HIGH>; + }; + + wlan2g { + label = "ax860:blue:wlan2g"; + gpio = <&tlmm 35 GPIO_ACTIVE_HIGH>; + }; + + wlan5g { + label = "ax860:red:wlan5g"; + gpio = <&tlmm 32 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&blsp1_uart3 { + pinctrl-0 = <&uart_pins>; + pinctrl-names = "default"; + status = "ok"; +}; + +&spi_0 { + pinctrl-0 = <&spi_0_pins>; + pinctrl-names = "default"; + cs-select = <0>; + status = "ok"; + + m25p80@0 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0>; + compatible = "n25q128a11"; + linux,modalias = "m25p80", "n25q128a11"; + spi-max-frequency = <50000000>; + use-default-sizes; + }; +}; + +&qpic_bam { + status = "ok"; +}; + +&nand { + pinctrl-0 = <&qpic_pins>; + pinctrl-names = "default"; + status = "ok"; +}; + +&nss_crypto { + status = "ok"; +}; + +&cpu0_opp_table { + compatible = "operating-points-v2"; + opp-shared; + + opp03 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <3>; + clock-latency-ns = <200000>; + }; + + /delete-node/ opp04; + /delete-node/ opp05; + /delete-node/ opp06; +}; + +&qseecom { + mem-start = <0x49B00000>; + mem-size = <0x600000>; + status = "ok"; +}; diff --git a/feeds/ipq807x/ipq807x/image/ipq60xx.mk b/feeds/ipq807x/ipq807x/image/ipq60xx.mk index 5f981ad1e..34c14edf4 100644 --- a/feeds/ipq807x/ipq807x/image/ipq60xx.mk +++ b/feeds/ipq807x/ipq807x/image/ipq60xx.mk @@ -81,3 +81,12 @@ define Device/glinet_ax1800 DEVICE_PACKAGES := ath11k-wifi-gl-ax1800 -kmod-usb-dwc3-of-simple kmod-usb-dwc3-qcom kmod-usb3 endef TARGET_DEVICES += glinet_ax1800 + +define Device/yuncore_ax840 + DEVICE_TITLE := YunCore AX840 + DEVICE_DTS := qcom-ipq6018-yuncore-ax840 + DEVICE_DTS_CONFIG := config@cp03-c1 + SUPPORTED_DEVICES := yuncore,ax840 + DEVICE_PACKAGES := ath11k-wifi-yuncore-ax840 uboot-env +endef +TARGET_DEVICES += yuncore_ax840 diff --git a/feeds/wifi-ax/ath11k-wifi/Makefile b/feeds/wifi-ax/ath11k-wifi/Makefile index 47643cf16..10f407f3c 100644 --- a/feeds/wifi-ax/ath11k-wifi/Makefile +++ b/feeds/wifi-ax/ath11k-wifi/Makefile @@ -38,7 +38,8 @@ ALLWIFIBOARDS:= \ wallys-dr6018 \ wallys-dr6018-v4 \ tplink-ex227 \ - tplink-ex447 + tplink-ex447 \ + yuncore-ax840 ALLWIFIPACKAGES:=$(foreach BOARD,$(ALLWIFIBOARDS),ath11k-wifi-$(BOARD)) @@ -186,6 +187,7 @@ $(eval $(call generate-ath11k-wifi-package,edgecore-eap102,Edgecore EAP102)) $(eval $(call generate-ath11k-wifi-package,edgecore-eap104,Edgecore EAP104)) $(eval $(call generate-ath11k-wifi-package,tplink-ex227,TP-Link EX227)) $(eval $(call generate-ath11k-wifi-package,tplink-ex447,TP-Link EX447)) +$(eval $(call generate-ath11k-wifi-package,yuncore-ax840,YunCore AX840)) $(foreach PACKAGE,$(ALLWIFIPACKAGES),$(eval $(call BuildPackage,$(PACKAGE)))) $(eval $(call BuildPackage,ath11k-wifi-qcom-ipq5018)) diff --git a/feeds/wifi-ax/ath11k-wifi/board-yuncore-ax840.bin.IPQ6018 b/feeds/wifi-ax/ath11k-wifi/board-yuncore-ax840.bin.IPQ6018 new file mode 100644 index 0000000000000000000000000000000000000000..349d35304e7200ccadf7e368e074acf5e7fa1105 GIT binary patch literal 65536 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 yDWDWk3Md7X0!jg;fKosypcGIFC