[openwrt/openwrt] qualcommax: ipq50xx: add support for Linksys MX2000 and MX5500

LEDE Commits lede-commits at lists.infradead.org
Thu Feb 6 00:51:30 PST 2025


robimarko pushed a commit to openwrt/openwrt.git, branch main:
https://git.openwrt.org/398f4a97378e2f645badc1aef3d0e9fd76f6665d

commit 398f4a97378e2f645badc1aef3d0e9fd76f6665d
Author: George Moussalem <george.moussalem at outlook.com>
AuthorDate: Mon Oct 7 16:09:40 2024 +0400

    qualcommax: ipq50xx: add support for Linksys MX2000 and MX5500
    
    Add support for Linksys MX2000 (Atlas 6) and MX5500 (Atlas 6 Pro).
    These devices are completely identical except for the secondary wifi
    chip used for 5Ghz: QCN6102 is used on MX2000 while QCN9024 is used
    on MX5500
    
    Speficiations:
    * SoC: Qualcomm IPQ5018 (64-bit dual-core ARM Cortex-A53 @ 1.0Ghz)
    * Memory: Winbond W634GU6NB-11 (512 MiB DDR3-933)
    * Serial Port: 3v3 TTL 115200n8
    * Wi-Fi: IPQ5018 (2x2 2.4 Ghz 802.11b/g/n/ax)
    * Wi-Fi: MX2000: QCN6102 (2x2:2 5 Ghz 802.11an/ac/ax)
             MX5500: QCN9024 (4x4:4 5 Ghz 802.11an/ac/ax)
    * Ethernet: IPQ5018 integrated virtual switch connected to an external
                QCA8337 switch (4 Ports 10/100/1000 GBASE-T)
    * Flash: Macronix MX35UF2GE4AD (256 MiB)
    * LEDs: 1x multi-color PWM LED
    * Buttons: 1x WPS (GPIO 27 Active Low)
               1x Reset (GPIO 28 Acive Low)
    
    Flash instructions (in case of MX2000, else replace with MX5500 images):
    1. On OEM firmware, login to the device (typically at http://192.168.1.1) and click 'CA'
    in the bottom right corner -> Connectivity -> Manual Upgrade. Alternatively, browse to
    http://<router IP>/fwupdate.html.
    Upgrade firmware using openwrt-qualcommax-ipq50xx-linksys_mx2000-squashfs-factory.bin image.
    Optionally install on second partition, after first boot check actual partition:
    fw_printenv -n boot_part
    and install firmware on second partition using command in case of 2:
    mtd -r -e kernel -n write openwrt-qualcommax-ipq50xx-linksys_mx2000-squashfs-factory.bin kernel
    and in case of 1:
    mtd -r -e alt_kernel -n write openwrt-qualcommax-ipq50xx-linksys_mx2000-squashfs-factory.bin alt_kernel
    2. Installation using serial connection from OEM firmware (default login: root, password: admin):
    fw_printenv -n boot_part
    In case of 2:
    flash_erase /dev/mtd12 0 0
    nandwrite -p /dev/mtd12 openwrt-qualcommax-ipq50xx-linksys_mx2000-squashfs-factory.bin
    or in case of 1:
    flash_erase /dev/mtd14 0 0
    nandwrite -p /dev/mtd14 openwrt-qualcommax-ipq50xx-linksys_mx2000-squashfs-factory.bin
    After first boot install firmware on second partition:
    mtd -r -e kernel -n write openwrt-qualcommax-ipq50xx-linksys_mx2000-squashfs-factory.bin kernel
    or:
    mtd -r -e alt_kernel -n write openwrt-qualcommax-ipq50xx-linksys_mx2000-squashfs-factory.bin alt_kernel
    3. Back to the OEM firmware.
    Download firmware from OEM website:
    MX2000: https://support.linksys.com/kb/article/585-en/
    MX5500: https://support.linksys.com/kb/article/587-en/
    From serial or SSH:
    fw_printenv boot_part
    in case of 1:
    mtd -r -e alt_kernel -n write FW_MX2000_1.1.7.210469_prod.img alt_kernel
    else in case of 2:
    mtd -r -e kernel -n write FW_MX2000_1.1.7.210469_prod.img kernel
    
    Signed-off-by: George Moussalem <george.moussalem at outlook.com>
    Link: https://github.com/openwrt/openwrt/pull/17182
    Signed-off-by: Robert Marko <robimarko at gmail.com>
---
 .../boot/uboot-envtools/files/qualcommax_ipq50xx   |  22 ++
 package/firmware/ipq-wifi/Makefile                 |   4 +
 .../arch/arm64/boot/dts/qcom/ipq5018-mx-base.dtsi  | 325 +++++++++++++++++++++
 .../arch/arm64/boot/dts/qcom/ipq5018-mx2000.dts    | 262 +++++++++++++++++
 .../arch/arm64/boot/dts/qcom/ipq5018-mx5500.dts    | 240 +++++++++++++++
 target/linux/qualcommax/image/ipq50xx.mk           |  31 ++
 .../ipq50xx/base-files/etc/board.d/02_network      |  45 +++
 .../etc/hotplug.d/firmware/11-ath11k-caldata       |  47 +++
 .../ipq50xx/base-files/etc/init.d/bootcount        |  12 +
 .../ipq50xx/base-files/lib/upgrade/platform.sh     |  84 ++++++
 10 files changed, 1072 insertions(+)

diff --git a/package/boot/uboot-envtools/files/qualcommax_ipq50xx b/package/boot/uboot-envtools/files/qualcommax_ipq50xx
new file mode 100644
index 0000000000..0e78bb8060
--- /dev/null
+++ b/package/boot/uboot-envtools/files/qualcommax_ipq50xx
@@ -0,0 +1,22 @@
+[ -e /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(board_name)
+
+case "$board" in
+linksys,mx2000|\
+linksys,mx5500)
+	idx="$(find_mtd_index u_env)"
+	[ -n "$idx" ] && \
+		ubootenv_add_uci_config "/dev/mtd$idx" "0x0" "0x40000" "0x20000"
+	;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config
+
+exit 0
diff --git a/package/firmware/ipq-wifi/Makefile b/package/firmware/ipq-wifi/Makefile
index ef67490a5f..408c821035 100644
--- a/package/firmware/ipq-wifi/Makefile
+++ b/package/firmware/ipq-wifi/Makefile
@@ -39,8 +39,10 @@ ALLWIFIBOARDS:= \
 	edimax_cax1800 \
 	linksys_homewrk \
 	linksys_mr7350 \
+	linksys_mx2000 \
 	linksys_mx4200 \
 	linksys_mx5300 \
+	linksys_mx5500 \
 	linksys_mx8500 \
 	linksys_whw03 \
 	netgear_lbr20 \
@@ -175,8 +177,10 @@ $(eval $(call generate-ipq-wifi-package,edgecore_eap102,Edgecore EAP102))
 $(eval $(call generate-ipq-wifi-package,edimax_cax1800,Edimax CAX1800))
 $(eval $(call generate-ipq-wifi-package,linksys_homewrk,Linksys HomeWRK))
 $(eval $(call generate-ipq-wifi-package,linksys_mr7350,Linksys MR7350))
+$(eval $(call generate-ipq-wifi-package,linksys_mx2000,Linksys MX2000))
 $(eval $(call generate-ipq-wifi-package,linksys_mx4200,Linksys MX4200))
 $(eval $(call generate-ipq-wifi-package,linksys_mx5300,Linksys MX5300))
+$(eval $(call generate-ipq-wifi-package,linksys_mx5500,Linksys MX5500))
 $(eval $(call generate-ipq-wifi-package,linksys_mx8500,Linksys MX8500))
 $(eval $(call generate-ipq-wifi-package,linksys_whw03,Linksys WHW03))
 $(eval $(call generate-ipq-wifi-package,netgear_lbr20,Netgear LBR20))
diff --git a/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq5018-mx-base.dtsi b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq5018-mx-base.dtsi
new file mode 100644
index 0000000000..57fe5c53a9
--- /dev/null
+++ b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq5018-mx-base.dtsi
@@ -0,0 +1,325 @@
+#include "ipq5018.dtsi"
+#include "ipq5018-ess.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
+
+/ {
+
+	aliases {
+		ethernet0 = &dp1;
+		ethernet1 = &dp2;
+		led-boot = &led_system_blue;
+		led-failsafe = &led_system_red;
+		led-running = &led_system_blue;
+		led-upgrade = &led_system_red;
+		serial0 = &blsp1_uart1;
+	};
+
+	chosen {
+		bootargs-append = " root=/dev/ubiblock0_0 coherent_pool=2M";
+		stdout-path = "serial0:115200n8";
+	};
+
+	keys {
+		compatible = "gpio-keys";
+		pinctrl-0 = <&button_pins>;
+		pinctrl-names = "default";
+
+		wps-button {
+			label = "wps";
+			gpios = <&tlmm 27 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_WPS_BUTTON>;
+		};
+
+		reset-button {
+			label = "reset";
+			gpios = <&tlmm 28 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_RESTART>;
+		};
+	};
+
+	leds {
+		compatible = "pwm-leds";
+
+		led_system_red: red {
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_POWER;
+			pwms = <&pwm 3 1250000>;
+			max-brightness = <255>;
+		};
+
+		green {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_POWER;
+			pwms = <&pwm 0 1250000>;
+			max-brightness = <255>;
+		};
+
+		led_system_blue: blue {
+			color = <LED_COLOR_ID_BLUE>;
+			function = LED_FUNCTION_POWER;
+			pwms = <&pwm 1 1250000>;
+			max-brightness = <255>;
+		};
+	};
+
+	reserved-memory {
+		q6_mem_regions: q6_mem_regions at 4b000000 {
+			no-map;
+			reg = <0x0 0x4b000000 0x0 0x3000000>;
+		};
+	};
+};
+
+&sleep_clk {
+	clock-frequency = <32000>;
+};
+
+&xo_board_clk {
+	clock-frequency = <24000000>;
+};
+
+&blsp1_uart1 {
+	status = "okay";
+
+	pinctrl-0 = <&serial_0_pins>;
+	pinctrl-names = "default";
+};
+
+&crypto {
+	status = "okay";
+};
+
+&cryptobam {
+	status = "okay";
+};
+
+&prng {
+	status = "okay";
+};
+
+&pwm {
+	status = "okay";
+
+	#pwm-cells = <2>;
+	pinctrl-0 = <&pwm_pins>;
+	pinctrl-names = "default";
+};
+
+&qfprom {
+	status = "okay";
+};
+
+&qpic_bam {
+	status = "okay";
+};
+
+&qpic_nand {
+	pinctrl-0 = <&qpic_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	partitions {
+		status = "disabled";
+	};
+
+	nand at 0 {
+		compatible = "spi-nand";
+		reg = <0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		nand-ecc-engine = <&qpic_nand>;
+
+		nand-ecc-strength = <8>;
+		nand-ecc-step-size = <512>;
+		nand-bus-width = <8>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition at 0 {
+				label = "0:SBL1";
+				reg = <0x00000000 0x80000>;
+				read-only;
+			};
+
+			partition at 80000 {
+				label = "0:MIBIB";
+				reg = <0x00080000 0x80000>;
+				read-only;
+			};
+
+			partition at 100000 {
+				label = "0:QSEE";
+				reg = <0x00100000 0x100000>;
+				read-only;
+			};
+
+			partition at 200000 {
+				label = "0:DEVCFG";
+				reg = <0x00200000 0x40000>;
+				read-only;
+			};
+
+			partition at 240000 {
+				label = "0:CDT";
+				reg = <0x00240000 0x40000>;
+				read-only;
+			};
+
+			partition at 280000 {
+				label = "0:APPSBLENV";
+				reg = <0x00280000 0x80000>;
+			};
+
+			partition at 300000 {
+				label = "0:APPSBL";
+				reg = <0x00300000 0x140000>;
+				read-only;
+			};
+
+			partition at 440000 {
+				label = "0:ART";
+				reg = <0x00440000 0x100000>;
+				read-only;
+			};
+
+			partition at 540000 {
+				label = "0:TRAINING";
+				reg = <0x00540000 0x80000>;
+				read-only;
+			};
+
+			partition at 5c0000 {
+				label = "u_env";
+				reg = <0x005c0000 0x80000>;
+			};
+
+			partition at 640000 {
+				label = "s_env";
+				reg = <0x00640000 0x40000>;
+			};
+
+			partition at 680000 {
+				label = "devinfo";
+				reg = <0x00680000 0x40000>;
+				read-only;
+			};
+
+			partition at 6c0000 {
+				label = "kernel";
+				reg = <0x006c0000 0x5200000>;
+			};
+
+			partition at ec0000 {
+				label = "rootfs";
+				reg = <0x0ec0000 0x4a00000>;
+			};
+
+			partition at 58c0000 {
+				label = "alt_kernel";
+				reg = <0x058c0000 0x5200000>;
+			};
+
+			partition at 60c0000 {
+				label = "alt_rootfs";
+				reg = <0x060c0000 0x4a00000>;
+			};
+
+			partition at aac0000 {
+				label = "sysdiag";
+				reg = <0x0aac0000 0x200000>;
+				read-only;
+			};
+
+			partition at acc0000 {
+				label = "syscfg";
+				reg = <0x0acc0000 0x4400000>;
+				read-only;
+			};
+		};
+	};
+};
+
+&tlmm {
+	button_pins: button-state {
+		pins = "gpio27", "gpio28";
+		function = "gpio";
+		drive-strength = <8>;
+		bias-pull-up;
+	};
+
+	mdio1_pins: mdio-state {
+		mdc-pins {
+			pins = "gpio36";
+			function = "mdc";
+			drive-strength = <8>;
+			bias-pull-up;
+		};
+
+		mdio-pins {
+			pins = "gpio37";
+			function = "mdio";
+			drive-strength = <8>;
+			bias-pull-up;
+		};
+	};
+
+	pwm_pins: pwm-state {
+		mux_1 {
+			pins = "gpio1";
+			function = "pwm1";
+			drive-strength = <8>;
+		};
+
+		mux_2 {
+			pins = "gpio30";
+			function = "pwm3";
+			drive-strength = <8>;
+		};
+
+		mux_3 {
+			pins = "gpio46";
+			function = "pwm0";
+			drive-strength = <8>;
+		};
+	};
+
+	qpic_pins: qpic-state {
+		clock-pins {
+			pins = "gpio9";
+			function = "qspi_clk";
+			drive-strength = <8>;
+			bias-disable;
+		};
+
+		cs-pins {
+			pins = "gpio8";
+			function = "qspi_cs";
+			drive-strength = <8>;
+			bias-disable;
+		};
+
+		data-pins {
+			pins = "gpio4", "gpio5", "gpio6", "gpio7";
+			function = "qspi_data";
+			drive-strength = <8>;
+			bias-disable;
+		};
+	};
+
+	serial_0_pins: uart0-state {
+		pins = "gpio20", "gpio21";
+		function = "blsp0_uart0";
+		bias-disable;
+	};
+};
+
+&tsens {
+	status = "okay";
+};
diff --git a/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq5018-mx2000.dts b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq5018-mx2000.dts
new file mode 100644
index 0000000000..108b26f8d1
--- /dev/null
+++ b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq5018-mx2000.dts
@@ -0,0 +1,262 @@
+/dts-v1/;
+
+#include "ipq5018.dtsi"
+#include "ipq5018-mx-base.dtsi"
+
+/ {
+	model = "Linksys MX2000";
+	compatible = "linksys,mx2000", "qcom,ipq5018";
+};
+
+/*
+ * ===============================================================
+ *     _______________________         _______________________
+ *    |        IPQ5018        |       |        QCA8337        |
+ *    | +------+   +--------+ |       | +--------+   +------+ |
+ *    | | MAC0 |---| GE Phy | |       | |  Phy0  |---| MAC1 | |
+ *    | +------+   +--------+ |       | +--------+   +------+ |
+ *    | +------+   +--------+ |       | +--------+   +------+ |
+ *    | | MAC1 |---| Uniphy |-+-SGMII-+-| SerDes |---| MAC6 | |
+ *    | +------+   +--------+ |       | +--------+   +------+ |
+ *    |_______________________|       |_______________________|
+ *
+ * ===============================================================
+ */
+
+&switch {
+	status = "okay";
+
+	switch_mac_mode = <MAC_MODE_SGMII_CHANNEL0>;
+
+	qcom,port_phyinfo {
+		// MAC0 -> GE Phy -> QCA8337 Phy4
+		port at 0 {
+			port_id = <1>;
+			mdiobus = <&mdio0>;
+			phy_address = <7>;
+		};
+
+		// MAC1 ---SGMII---> QCA8337 SerDes
+		port at 1 {
+			port_id = <2>;
+			forced-speed = <1000>;
+			forced-duplex = <1>;
+		};
+	};
+};
+
+// MAC1 ---SGMII---> QCA8337 SerDes
+&dp2 {
+	status = "okay";
+	phy-mode = "sgmii";
+
+	fixed-link {
+		speed = <1000>;
+		full-duplex;
+	};
+};
+
+&mdio0 {
+	status = "okay";
+};
+
+/* IPQ5018 GE Phy -> Not connected 
+ * needs to be enabled for QSDK to identify the IPQ5018 dummy switch
+ */
+&ge_phy {
+	status = "okay";
+};
+
+&mdio1 {
+	status = "okay";
+
+	pinctrl-0 = <&mdio1_pins>;
+	pinctrl-names = "default";
+	reset-gpios = <&tlmm 39 GPIO_ACTIVE_LOW>;
+
+	// QCA8337 Phy0 not connected
+	qca8337_0: ethernet-phy at 0 {
+		reg = <0>;
+	};
+
+	// QCA8337 Phy1 -> WAN
+	qca8337_1: ethernet-phy at 1 {
+		reg = <1>;
+	};
+
+	// QCA8337 Phy2 -> LAN1
+	qca8337_2: ethernet-phy at 2 {
+		reg = <2>;
+	};
+
+	// QCA8337 Phy3 -> LAN2
+	qca8337_3: ethernet-phy at 3 {
+		reg = <3>;
+	};
+
+	// QCA8337 Phy4 -> LAN3
+	qca8337_4: ethernet-phy at 4 {
+		reg = <4>;
+	};
+
+	// QCA8337 switch
+	switch1: ethernet-switch at 17 {
+		compatible = "qca,qca8337";
+		reg = <17>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 2 {
+				reg = <2>;
+				label = "wan";
+				phy-handle = <&qca8337_1>;
+			};
+
+			port at 3 {
+				reg = <3>;
+				label = "lan3";
+				phy-handle = <&qca8337_2>;
+			};
+
+			port at 4 {
+				reg = <4>;
+				label = "lan2";
+				phy-handle = <&qca8337_3>;
+			};
+
+			port at 5 {
+				reg = <5>;
+				label = "lan1";
+				phy-handle = <&qca8337_4>;
+			};
+
+			port at 6 {
+				reg = <6>;
+				label = "cpu";
+				phy-mode = "sgmii";
+				ethernet = <&dp2>;
+				qca,sgmii-enable-pll;
+
+				fixed-link {
+					speed = <1000>;
+					full-duplex;
+				};
+			};
+		};
+	};
+};
+
+&q6v5_wcss {
+	status = "okay";
+
+	memory-region = <&q6_mem_regions>;
+	firmware-name = "ath11k/IPQ5018/hw1.0/q6_fw.mdt",
+					"ath11k/IPQ5018/hw1.0/m3_fw.mdt",
+					"ath11k/QCN6122/hw1.0/m3_fw.mdt";
+
+	/* The QCN6102 radio should map to UPD ID 2. Without       */
+	/* bootargs, the firmware will expect it to be on UPD ID 3 */
+	boot-args = <
+			/*       type:	*/	0x1	/* PCIE0	*/
+			/*     length:	*/	4
+			/*     UPD ID:	*/	2
+			/* reset GPIO:	*/	15
+			/*   reserved:	*/	0 0>;
+
+	// IPQ5018
+	q6_wcss_pd1: pd-1 {
+		firmware-name = "ath11k/IPQ5018/hw1.0/q6_fw.mdt";
+
+		resets =
+			<&gcc GCC_WCSSAON_RESET>,
+			<&gcc GCC_WCSS_BCR>,
+			<&gcc GCC_CE_BCR>;
+		reset-names =
+			"wcss_aon_reset",
+			"wcss_reset",
+			"ce_reset";
+
+		clocks =
+			<&gcc GCC_WCSS_AHB_S_CLK>,
+			<&gcc GCC_WCSS_ACMT_CLK>,
+			<&gcc GCC_WCSS_AXI_M_CLK>;
+		clock-names =
+			"gcc_wcss_ahb_s_clk",
+			"gcc_wcss_acmt_clk",
+			"gcc_wcss_axi_m_clk";
+
+		// qcom,halt-regs = <&tcsr_q6_block 0xa000 0xd000 0x0>;
+		interrupts-extended =
+			<&wcss_smp2p_in 8 IRQ_TYPE_NONE>,
+			<&wcss_smp2p_in 9 IRQ_TYPE_NONE>,
+			<&wcss_smp2p_in 12 IRQ_TYPE_NONE>,
+			<&wcss_smp2p_in 11 IRQ_TYPE_NONE>;
+		interrupt-names =
+			"fatal",
+			"ready",
+			"spawn-ack",
+			"stop-ack";
+
+		qcom,smem-states =
+			<&wcss_smp2p_out 8>,
+			<&wcss_smp2p_out 9>,
+			<&wcss_smp2p_out 10>;
+		qcom,smem-state-names =
+			"shutdown",
+			"stop",
+			"spawn";
+		status = "okay";
+	};
+
+	// QCN6102 5G
+	q6_wcss_pd2: pd-2 {
+		firmware-name = "ath11k/IPQ5018/hw1.0/q6_fw.mdt";
+
+		interrupts-extended =
+			<&wcss_smp2p_in 16 IRQ_TYPE_NONE>,
+			<&wcss_smp2p_in 17 IRQ_TYPE_NONE>,
+			<&wcss_smp2p_in 20 IRQ_TYPE_NONE>,
+			<&wcss_smp2p_in 19 IRQ_TYPE_NONE>;
+		interrupt-names =
+			"fatal",
+			"ready",
+			"spawn-ack",
+			"stop-ack";
+
+		qcom,smem-states =
+			<&wcss_smp2p_out 16>,
+			<&wcss_smp2p_out 17>,
+			<&wcss_smp2p_out 18>;
+		qcom,smem-state-names =
+			"shutdown",
+			"stop",
+			"spawn";
+		status = "okay";
+	};
+};
+
+&wifi0 {
+	// IPQ5018
+	qcom,rproc = <&q6_wcss_pd1>;
+	qcom,ath11k-calibration-variant = "Linksys-MX2000";
+	qcom,ath11k-fw-memory-mode = <2>;
+	qcom,bdf-addr = <0x4c400000>;
+
+	status = "okay";
+};
+
+&wifi1 {
+	// QCN6102 5G
+	qcom,rproc = <&q6_wcss_pd2>;
+	qcom,userpd-subsys-name = "q6v5_wcss_userpd2";
+	qcom,ath11k-calibration-variant = "Linksys-MX2000";
+	qcom,ath11k-fw-memory-mode = <2>;
+	qcom,bdf-addr = <0x4d100000>;
+	qcom,m3-dump-addr = <0x4df00000>;
+
+	status = "okay";
+};
diff --git a/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq5018-mx5500.dts b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq5018-mx5500.dts
new file mode 100644
index 0000000000..630e8ba310
--- /dev/null
+++ b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq5018-mx5500.dts
@@ -0,0 +1,240 @@
+/dts-v1/;
+
+#include "ipq5018.dtsi"
+#include "ipq5018-mx-base.dtsi"
+
+/ {
+	model = "Linksys MX5500";
+	compatible = "linksys,mx5500", "qcom,ipq5018";
+};
+
+/*
+ * ===============================================================
+ *     _______________________         _______________________
+ *    |        IPQ5018        |       |        QCA8337        |
+ *    | +------+   +--------+ |       | +--------+   +------+ |
+ *    | | MAC0 |---| GE Phy | |       | |  Phy0  |---| MAC1 | |
+ *    | +------+   +--------+ |       | +--------+   +------+ |
+ *    | +------+   +--------+ |       | +--------+   +------+ |
+ *    | | MAC1 |---| Uniphy |-+-SGMII-+-| SerDes |---| MAC6 | |
+ *    | +------+   +--------+ |       | +--------+   +------+ |
+ *    |_______________________|       |_______________________|
+ *
+ * ===============================================================
+ */
+
+&switch {
+	status = "okay";
+
+	switch_mac_mode = <MAC_MODE_SGMII_CHANNEL0>;
+
+	qcom,port_phyinfo {
+		// MAC0 -> GE Phy -> QCA8337 Phy4
+		port at 0 {
+			port_id = <1>;
+			mdiobus = <&mdio0>;
+			phy_address = <7>;
+		};
+
+		// MAC1 ---SGMII---> QCA8337 SerDes
+		port at 1 {
+			port_id = <2>;
+			forced-speed = <1000>;
+			forced-duplex = <1>;
+		};
+	};
+};
+
+// MAC1 ---SGMII---> QCA8337 SerDes
+&dp2 {
+	status = "okay";
+	phy-mode = "sgmii";
+
+	fixed-link {
+		speed = <1000>;
+		full-duplex;
+	};
+};
+
+&mdio0 {
+	status = "okay";
+};
+
+/* IPQ5018 GE Phy -> Not connected 
+ * needs to be enabled for QSDK to identify the IPQ5018 dummy switch
+ */
+&ge_phy {
+	status = "okay";
+};
+
+&mdio1 {
+	status = "okay";
+
+	pinctrl-0 = <&mdio1_pins>;
+	pinctrl-names = "default";
+	reset-gpios = <&tlmm 39 GPIO_ACTIVE_LOW>;
+
+	// QCA8337 Phy0 not connected
+	qca8337_0: ethernet-phy at 0 {
+		reg = <0>;
+	};
+
+	// QCA8337 Phy1 -> WAN
+	qca8337_1: ethernet-phy at 1 {
+		reg = <1>;
+	};
+
+	// QCA8337 Phy2 -> LAN1
+	qca8337_2: ethernet-phy at 2 {
+		reg = <2>;
+	};
+
+	// QCA8337 Phy3 -> LAN2
+	qca8337_3: ethernet-phy at 3 {
+		reg = <3>;
+	};
+
+	// QCA8337 Phy4 -> LAN3
+	qca8337_4: ethernet-phy at 4 {
+		reg = <4>;
+	};
+
+	// QCA8337 switch
+	switch1: ethernet-switch at 17 {
+		compatible = "qca,qca8337";
+		reg = <17>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 2 {
+				reg = <2>;
+				label = "wan";
+				phy-handle = <&qca8337_1>;
+			};
+
+			port at 3 {
+				reg = <3>;
+				label = "lan3";
+				phy-handle = <&qca8337_2>;
+			};
+
+			port at 4 {
+				reg = <4>;
+				label = "lan2";
+				phy-handle = <&qca8337_3>;
+			};
+
+			port at 5 {
+				reg = <5>;
+				label = "lan1";
+				phy-handle = <&qca8337_4>;
+			};
+
+			port at 6 {
+				reg = <6>;
+				label = "cpu";
+				phy-mode = "sgmii";
+				ethernet = <&dp2>;
+				qca,sgmii-enable-pll;
+
+				fixed-link {
+					speed = <1000>;
+					full-duplex;
+				};
+			};
+		};
+	};
+};
+
+&pcie0_phy {
+	status = "okay";
+};
+
+&pcie0 {
+	status = "okay";
+
+	perst-gpios = <&tlmm 15 GPIO_ACTIVE_LOW>;
+
+	bridge at 0,0 {
+		reg = <0x00000000 0 0 0 0>;
+		#address-cells = <3>;
+		#size-cells = <2>;
+		ranges;
+
+		wifi at 1,0 {
+			status = "okay";
+
+			/* QCN9074: ath11k lacks DT compatible for PCI cards */
+			compatible = "pci17cb,1104";
+			reg = <0x00010000 0 0 0 0>;
+
+			qcom,ath11k-calibration-variant = "Linksys-MX5500";
+		};
+	};
+};
+
+&q6v5_wcss {
+	status = "okay";
+
+	memory-region = <&q6_mem_regions>;
+	firmware-name = "ath11k/IPQ5018/hw1.0/q6_fw.mdt",
+					"ath11k/IPQ5018/hw1.0/m3_fw.mdt";
+
+	// IPQ5018
+	q6_wcss_pd1: pd-1 {
+		firmware-name = "ath11k/IPQ5018/hw1.0/q6_fw.mdt";
+
+		resets =
+			<&gcc GCC_WCSSAON_RESET>,
+			<&gcc GCC_WCSS_BCR>,
+			<&gcc GCC_CE_BCR>;
+		reset-names =
+			"wcss_aon_reset",
+			"wcss_reset",
+			"ce_reset";
+
+		clocks =
+			<&gcc GCC_WCSS_AHB_S_CLK>,
+			<&gcc GCC_WCSS_ACMT_CLK>,
+			<&gcc GCC_WCSS_AXI_M_CLK>;
+		clock-names =
+			"gcc_wcss_ahb_s_clk",
+			"gcc_wcss_acmt_clk",
+			"gcc_wcss_axi_m_clk";
+
+		interrupts-extended =
+			<&wcss_smp2p_in 8 0>,
+			<&wcss_smp2p_in 9 0>,
+			<&wcss_smp2p_in 12 0>,
+			<&wcss_smp2p_in 11 0>;
+		interrupt-names =
+			"fatal",
+			"ready",
+			"spawn-ack",
+			"stop-ack";
+
+		qcom,smem-states =
+			<&wcss_smp2p_out 8>,
+			<&wcss_smp2p_out 9>,
+			<&wcss_smp2p_out 10>;
+		qcom,smem-state-names =
+			"shutdown",
+			"stop",
+			"spawn";
+		status = "okay";
+	};
+};
+
+&wifi0 {
+	// IPQ5018
+	qcom,rproc = <&q6_wcss_pd1>;
+	qcom,ath11k-calibration-variant = "Linksys-MX5500";
+	qcom,ath11k-fw-memory-mode = <2>;
+	qcom,bdf-addr = <0x4c400000>;
+
+	status = "okay";
+};
diff --git a/target/linux/qualcommax/image/ipq50xx.mk b/target/linux/qualcommax/image/ipq50xx.mk
index e69de29bb2..affd5e6345 100644
--- a/target/linux/qualcommax/image/ipq50xx.mk
+++ b/target/linux/qualcommax/image/ipq50xx.mk
@@ -0,0 +1,31 @@
+define Device/linksys_ipq50xx_mx_base
+	$(call Device/FitImageLzma)
+	DEVICE_VENDOR := Linksys
+	BLOCKSIZE := 128k
+	PAGESIZE := 2048
+	KERNEL_SIZE := 8192k
+	IMAGE_SIZE := 83968k
+	NAND_SIZE := 256m
+	SOC := ipq5018
+	IMAGES += factory.bin
+	IMAGE/factory.bin := append-kernel | pad-to $$$$(KERNEL_SIZE) | append-ubi | linksys-image type=$$$$(DEVICE_MODEL)
+endef
+
+define Device/linksys_mx2000
+	$(call Device/linksys_ipq50xx_mx_base)
+	DEVICE_MODEL := MX2000
+	DEVICE_DTS_CONFIG := config at mp03.5-c1
+	DEVICE_PACKAGES := ath11k-firmware-qcn6122 \
+		ipq-wifi-linksys_mx2000
+endef
+TARGET_DEVICES += linksys_mx2000
+
+define Device/linksys_mx5500
+	$(call Device/linksys_ipq50xx_mx_base)
+	DEVICE_MODEL := MX5500
+	DEVICE_DTS_CONFIG := config at mp03.1
+	DEVICE_PACKAGES := kmod-ath11k-pci \
+		ath11k-firmware-qcn9074 \
+		ipq-wifi-linksys_mx5500
+endef
+TARGET_DEVICES += linksys_mx5500
diff --git a/target/linux/qualcommax/ipq50xx/base-files/etc/board.d/02_network b/target/linux/qualcommax/ipq50xx/base-files/etc/board.d/02_network
new file mode 100644
index 0000000000..57f11bad84
--- /dev/null
+++ b/target/linux/qualcommax/ipq50xx/base-files/etc/board.d/02_network
@@ -0,0 +1,45 @@
+#!/bin/sh
+
+. /lib/functions/uci-defaults.sh
+. /lib/functions/system.sh
+
+ipq50xx_setup_interfaces()
+{
+	local board="$1"
+	case $board in
+		linksys,mx2000|\
+		linksys,mx5500)
+			ucidef_set_interfaces_lan_wan "lan1 lan2 lan3" "wan"
+			;;
+	esac
+}
+
+ipq50xx_setup_macs()
+{
+	local board="$1"
+	local lan_mac=""
+	local wan_mac=""
+	local label_mac=""
+
+	case "$board" in
+		linksys,mx2000|\
+		linksys,mx5500)
+			label_mac=$(mtd_get_mac_ascii devinfo hw_mac_addr)
+			lan_mac=$label_mac
+			wan_mac=$label_mac
+			ucidef_set_network_device_mac eth0 $label_mac
+		;;
+	esac
+
+	[ -n "$lan_mac" ] && ucidef_set_interface_macaddr "lan" $lan_mac
+	[ -n "$wan_mac" ] && ucidef_set_interface_macaddr "wan" $wan_mac
+	[ -n "$label_mac" ] && ucidef_set_label_macaddr $label_mac
+}
+
+board_config_update
+board=$(board_name)
+ipq50xx_setup_interfaces $board
+ipq50xx_setup_macs $board
+board_config_flush
+
+exit 0
diff --git a/target/linux/qualcommax/ipq50xx/base-files/etc/hotplug.d/firmware/11-ath11k-caldata b/target/linux/qualcommax/ipq50xx/base-files/etc/hotplug.d/firmware/11-ath11k-caldata
new file mode 100644
index 0000000000..7c8cc99ee3
--- /dev/null
+++ b/target/linux/qualcommax/ipq50xx/base-files/etc/hotplug.d/firmware/11-ath11k-caldata
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+[ -e /lib/firmware/$FIRMWARE ] && exit 0
+
+. /lib/functions/caldata.sh
+
+board=$(board_name)
+
+case "$FIRMWARE" in
+"ath11k/IPQ5018/hw1.0/cal-ahb-c000000.wifi.bin")
+	case "$board" in
+	linksys,mx2000|\
+	linksys,mx5500)
+		caldata_extract "0:ART" 0x1000 0x20000
+		label_mac=$(mtd_get_mac_ascii devinfo hw_mac_addr)
+		ath11k_patch_mac $(macaddr_add $label_mac 1) 0
+		ath11k_remove_regdomain
+		ath11k_set_macflag
+		;;
+	esac
+	;;
+"ath11k/QCN6122/hw1.0/cal-ahb-b00a040.wifi1.bin")
+	case "$board" in
+	linksys,mx2000)
+		caldata_extract "0:ART" 0x26800 0x20000
+		label_mac=$(mtd_get_mac_ascii devinfo hw_mac_addr)
+		ath11k_patch_mac $(macaddr_add $label_mac 2) 0
+		ath11k_remove_regdomain
+		ath11k_set_macflag
+		;;
+	esac
+	;;
+"ath11k/QCN9074/hw1.0/cal-pci-0001:01:00.0.bin")
+	case "$board" in
+	linksys,mx5500)
+		caldata_extract "0:ART" 0x26800 0x20000
+		label_mac=$(mtd_get_mac_ascii devinfo hw_mac_addr)
+		ath11k_patch_mac $(macaddr_add $label_mac 2) 0
+		ath11k_remove_regdomain
+		ath11k_set_macflag
+		;;
+	esac
+	;;
+*)
+	exit 1
+	;;
+esac
diff --git a/target/linux/qualcommax/ipq50xx/base-files/etc/init.d/bootcount b/target/linux/qualcommax/ipq50xx/base-files/etc/init.d/bootcount
new file mode 100755
index 0000000000..b570428aef
--- /dev/null
+++ b/target/linux/qualcommax/ipq50xx/base-files/etc/init.d/bootcount
@@ -0,0 +1,12 @@
+#!/bin/sh /etc/rc.common
+
+START=99
+
+boot() {
+	case $(board_name) in
+	linksys,mx2000|\
+	linksys,mx5500)
+		mtd resetbc s_env || true
+	;;
+	esac
+}
diff --git a/target/linux/qualcommax/ipq50xx/base-files/lib/upgrade/platform.sh b/target/linux/qualcommax/ipq50xx/base-files/lib/upgrade/platform.sh
new file mode 100644
index 0000000000..a75b6798d2
--- /dev/null
+++ b/target/linux/qualcommax/ipq50xx/base-files/lib/upgrade/platform.sh
@@ -0,0 +1,84 @@
+PART_NAME=firmware
+REQUIRE_IMAGE_METADATA=1
+
+RAMFS_COPY_BIN='fw_printenv fw_setenv head'
+RAMFS_COPY_DATA='/etc/fw_env.config /var/lock/fw_printenv.lock'
+
+remove_oem_ubi_volume() {
+	local oem_volume_name="$1"
+	local oem_ubivol
+	local mtdnum
+	local ubidev
+
+	mtdnum=$(find_mtd_index "$CI_UBIPART")
+	if [ ! "$mtdnum" ]; then
+		return
+	fi
+
+	ubidev=$(nand_find_ubi "$CI_UBIPART")
+	if [ ! "$ubidev" ]; then
+		ubiattach --mtdn="$mtdnum"
+		ubidev=$(nand_find_ubi "$CI_UBIPART")
+	fi
+
+	if [ "$ubidev" ]; then
+		oem_ubivol=$(nand_find_volume "$ubidev" "$oem_volume_name")
+		[ "$oem_ubivol" ] && ubirmvol "/dev/$ubidev" --name="$oem_volume_name"
+	fi
+}
+
+linksys_mx_do_upgrade() {
+	local setenv_script="/tmp/fw_env_upgrade"
+
+	CI_UBIPART="rootfs"
+	boot_part="$(fw_printenv -n boot_part)"
+	if [ -n "$UPGRADE_OPT_USE_CURR_PART" ]; then
+		if [ "$boot_part" -eq "2" ]; then
+			CI_KERNPART="alt_kernel"
+			CI_UBIPART="alt_rootfs"
+		fi
+	else
+		if [ "$boot_part" -eq "1" ]; then
+			echo "boot_part 2" >> $setenv_script
+			CI_KERNPART="alt_kernel"
+			CI_UBIPART="alt_rootfs"
+		else
+			echo "boot_part 1" >> $setenv_script
+		fi
+	fi
+
+	boot_part_ready="$(fw_printenv -n boot_part_ready)"
+	if [ "$boot_part_ready" -ne "3" ]; then
+		echo "boot_part_ready 3" >> $setenv_script
+	fi
+
+	auto_recovery="$(fw_printenv -n auto_recovery)"
+	if [ "$auto_recovery" != "yes" ]; then
+		echo "auto_recovery yes" >> $setenv_script
+	fi
+
+	if [ -f "$setenv_script" ]; then
+		fw_setenv -s $setenv_script || {
+			echo "failed to update U-Boot environment"
+			return 1
+		}
+	fi
+	nand_do_upgrade "$1"
+}
+
+platform_check_image() {
+	return 0;
+}
+
+platform_do_upgrade() {
+	case "$(board_name)" in
+	linksys,mx2000|\
+	linksys,mx5500)
+		remove_oem_ubi_volume rootfs
+		linksys_mx_do_upgrade "$1"
+		;;
+	*)
+		default_do_upgrade "$1"
+		;;
+	esac
+}




More information about the lede-commits mailing list