[openwrt/openwrt] ath79: add Cisco Meraki MR18

LEDE Commits lede-commits at lists.infradead.org
Sat May 13 15:09:14 PDT 2023


chunkeey pushed a commit to openwrt/openwrt.git, branch master:
https://git.openwrt.org/1d49310fdb5e6febd2e7a60d55deb0adb4364307

commit 1d49310fdb5e6febd2e7a60d55deb0adb4364307
Author: Christian Lamparter <chunkeey at gmail.com>
AuthorDate: Fri Jul 30 17:59:25 2021 +0200

    ath79: add Cisco Meraki MR18
    
    Specifications:
    
    SOC:    Atheros/Qualcomm QCA9557-AT4A @ 720MHz
    RAM:    2x Winbond W9751G6KB-25 (128 MiB)
    FLASH:  Hynix H27U1G8F2BTR-BC TSOP48 ONFI NAND (128 MiB)
    WIFI1:  Atheros AR9550 5.0GHz (SoC)
    WIFI2:  Atheros AR9582-AR1A 2.4GHz
    WIFI2:  Atheros AR9582-AR1A 2.4GHz + 5GHz
    PHYETH: Atheros AR8035-A, 802.3af PoE capable Atheros (1x Gigabit LAN)
    LED:    1x Power-LED, 1 x RGB Tricolor-LED
    INPUT:  One Reset Button
    UART:   JP1 on PCB (Labeled UART), 3.3v-Level, 115200n8
            (VCC, RX, TX, GND - VCC is closest to the boot set jumper
             under the console pins.)
    
    Flashing instructions:
    
    Depending on the installed firmware, there are vastly different
    methods to flash a MR18. These have been documented on:
    <https://openwrt.org/toh/meraki/mr18>
    
    Tip:
    Use an initramfs from a previous release and then use sysupgrade
    to get to the later releases. This is because the initramfs can
    no longer be built by the build-bots due to its size (>8 MiB).
    
    Note on that:
    Upgrades from AR71XX releases are possible, but they will
    require the force sysupgrade option ( -F ).
    
    Please backup your MR18's configuration before starting the
    update. The reason here is that a lot of development happend
    since AR71XX got removed, so I do advise to use the ( -n )
    option for sysupgrade as well. This will cause the device
    to drop the old AR71xx configuration and make a new
    configurations from scratch.
    
    Note on LEDs:
    The LEDs has changed since AR71XX. The white LED is now used during
    the boot and when upgrading instead of the green tricolor LED. The
    technical reason is that currently the RGB-LED is brought up later
    by a userspace daemon.
    
    (added warning note about odm-caldata partition. remove initramfs -
    it's too big to be built by the bots. MerakiNAND -> meraki-header.
    sort nu801's targets)
    Signed-off-by: Christian Lamparter <chunkeey at gmail.com>
---
 package/system/gpio-cdev/nu801/Makefile            |   2 +-
 target/linux/ath79/dts/qca9557_meraki_mr18.dts     | 203 +++++++++++++++++++++
 .../ath79/image/lzma-loader/src/ar71xx_regs.h      |  17 ++
 target/linux/ath79/image/lzma-loader/src/board.c   | 133 ++++++++++++++
 target/linux/ath79/image/nand.mk                   |  25 +++
 .../ath79/nand/base-files/etc/board.d/02_network   |   6 +-
 .../etc/hotplug.d/firmware/10-ath9k-eeprom         |  44 +++++
 7 files changed, 428 insertions(+), 2 deletions(-)

diff --git a/package/system/gpio-cdev/nu801/Makefile b/package/system/gpio-cdev/nu801/Makefile
index f91fbbc8ae..67b2a771ec 100644
--- a/package/system/gpio-cdev/nu801/Makefile
+++ b/package/system/gpio-cdev/nu801/Makefile
@@ -20,7 +20,7 @@ define Package/nu801
   SECTION:=utils
   CATEGORY:=Utilities
   SUBMENU:=Userspace GPIO Drivers
-  DEPENDS:=@(TARGET_x86||TARGET_bcm53xx)
+  DEPENDS:=@(TARGET_ath79_nand||TARGET_bcm53xx||TARGET_x86)
   KCONFIG:=CONFIG_GPIO_CDEV=y
   TITLE:=NU801 LED Driver
 endef
diff --git a/target/linux/ath79/dts/qca9557_meraki_mr18.dts b/target/linux/ath79/dts/qca9557_meraki_mr18.dts
new file mode 100644
index 0000000000..a88e2bcd37
--- /dev/null
+++ b/target/linux/ath79/dts/qca9557_meraki_mr18.dts
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+
+#include "qca955x.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
+
+/ {
+	compatible = "meraki,mr18", "qca,qca9558";
+	model = "Meraki MR18";
+
+	aliases {
+		label-mac-device = &eth0;
+		led-boot = &white;
+		led-failsafe = &orange;
+		led-running = &green;
+		led-upgrade = &white;
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		white: white {
+			label = "white:power";
+			gpios = <&gpio 18 GPIO_ACTIVE_LOW>;
+		};
+
+		orange: orange {
+			label = "orange:power";
+			gpios = <&gpio 21 GPIO_ACTIVE_HIGH>;
+			panic-indicator;
+		};
+	};
+
+	uleds {
+		compatible = "virtual-leds";
+#if 0
+		/*
+		 * RGB leds are not supported by uleds driver.
+		 * but this is what the definitions for a as
+		 * of yet unwritten leds_nu801 would look like.
+		 */
+
+		rgbled-0 {
+			function = LED_FUNCTION_POWER;
+			color = <LED_COLOR_ID_RGB>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			led at 0 {
+				reg = <0>;
+				color = <LED_COLOR_ID_RED>;
+			};
+
+			green: led at 1 {
+				reg = <1>;
+				color = <LED_COLOR_ID_GREEN>;
+			};
+
+			led at 2 {
+				reg = <2>;
+				color = <LED_COLOR_ID_BLUE>;
+			};
+		};
+
+#else
+		red {
+			label = "red:tricolor";
+			color = <LED_COLOR_ID_RED>;
+		};
+
+		green: green {
+			label = "green:tricolor";
+			color = <LED_COLOR_ID_GREEN>;
+		};
+
+		blue {
+			label = "blue:tricolor";
+			color = <LED_COLOR_ID_BLUE>;
+		};
+#endif
+	};
+
+	button {
+		compatible = "gpio-keys";
+
+		reset {
+			label = "Reset";
+			linux,code = <KEY_RESTART>;
+			gpios = <&gpio 17 GPIO_ACTIVE_LOW>;
+			debounce-interval = <60>;
+		};
+
+	};
+};
+
+&nand {
+	status = "okay";
+
+	nand-ecc-mode = "soft";
+	nand-ecc-algo = "bch";
+	nand-ecc-strength = <4>;
+	nand-ecc-step-size = <512>;
+	nand-is-boot-medium;
+
+	partitions {
+		compatible = "fixed-partitions";
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		partition at 0 {
+			label = "nandloader";
+			reg = <0x0 0x80000>;
+			read-only;
+		};
+
+		partition at 80000 {
+			label = "kernel";
+			reg = <0x80000 0x800000>;
+		};
+
+		partition at 880000 {
+			label = "recovery";
+			reg = <0x880000 0x800000>;
+		};
+
+		partition at 1080000 {
+			label = "ubi";
+			reg = <0x1080000 0x6f00000>;
+		};
+
+		partition at 7fe0000 {
+			/*
+			 * This is not always present. And if
+			 * it is, then Meraki (or contractor)
+			 * used a different ecc method than
+			 * the one we need for the UBI partition.
+			 * Reading this causes various reading
+			 * errors.
+			 *
+			 * As a result: Please don't convert
+			 * this to nvmem-cells. Instead there's
+			 * a ubi-volume "caldata" that has the
+			 * necessary data.
+			 */
+
+			label = "odm-caldata";
+			reg = <0x7fe0000 0x20000>;
+			read-only;
+		};
+	};
+};
+
+&pcie0 {
+	status = "okay";
+
+	wifi at 0,0 {
+		compatible = "pci168c,0033";
+		reg = <0x0000 0 0 0 0>;
+		qca,no-eeprom;
+	};
+};
+
+&pcie1 {
+	status = "okay";
+
+	wifi at 0,0 {
+		compatible = "pci168c,0033";
+		reg = <0x0000 0 0 0 0>;
+		qca,no-eeprom;
+	};
+};
+
+&uart {
+	status = "okay";
+};
+
+&mdio0 {
+	status = "okay";
+
+	phy: ethernet-phy at 3 {
+		reg = <3>;
+	};
+};
+
+&eth0 {
+	status = "okay";
+	pll-data = <0xa6000000 0xa0000101 0x80001313>;
+	phy-handle = <&phy>;
+
+	gmac-config {
+		device = <&gmac>;
+		rgmii-enabled = <1>;
+		rxd-delay = <3>;
+		rxdv-delay = <3>;
+	};
+};
+
+&wmac {
+	status = "okay";
+	qca,no-eeprom;
+};
diff --git a/target/linux/ath79/image/lzma-loader/src/ar71xx_regs.h b/target/linux/ath79/image/lzma-loader/src/ar71xx_regs.h
index 19a4785bb4..245042fdab 100644
--- a/target/linux/ath79/image/lzma-loader/src/ar71xx_regs.h
+++ b/target/linux/ath79/image/lzma-loader/src/ar71xx_regs.h
@@ -128,6 +128,17 @@
 #define AR9300_OTP_STATUS_SM_BUSY	0x1
 #define AR9300_OTP_READ_DATA	0x15f1c
 
+#define QCA955X_OTP_BASE        (AR71XX_APB_BASE + 0x00130000)
+#define QCA955X_OTP_REG_MEM_0	0x0000
+#define QCA955X_OTP_REG_INTF2	0x1008
+#define QCA955X_OTP_REG_STATUS0	0x1018
+#define QCA955X_OTP_STATUS0_EFUSE_VALID	BIT(2)
+
+#define QCA955X_OTP_REG_STATUS1		0x101c
+#define QCA955X_OTP_REG_LDO_CTRL	0x1024
+#define QCA955X_OTP_REG_LDO_STATUS	0x102c
+#define QCA955X_OTP_LDO_STATUS_POWER_ON		BIT(0)
+
 /*
  * DDR_CTRL block
  */
@@ -344,6 +355,7 @@
 
 #define QCA955X_RESET_REG_BOOTSTRAP		0xb0
 #define QCA955X_RESET_REG_EXT_INT_STATUS	0xac
+#define QCA955X_RESET_REG_RESET_MODULE		0x1c
 
 #define MISC_INT_ETHSW			BIT(12)
 #define MISC_INT_TIMER4			BIT(10)
@@ -436,6 +448,9 @@
 #define AR934X_RESET_MBOX		BIT(1)
 #define AR934X_RESET_I2S		BIT(0)
 
+#define QCA955X_RESET_SGMII_ANALOG	BIT(12)
+#define QCA955X_RESET_SGMII		BIT(8)
+
 #define AR933X_BOOTSTRAP_MDIO_GPIO_EN	BIT(18)
 #define AR933X_BOOTSTRAP_EEPBUSY	BIT(4)
 #define AR933X_BOOTSTRAP_REF_CLK_40	BIT(0)
@@ -722,4 +737,6 @@
 #define QCA955X_ETH_CFG_RGMII_GMAC0	BIT(0)
 #define QCA955X_ETH_CFG_SGMII_GMAC0	BIT(6)
 
+#define QCA955X_GMAC_REG_SGMII_SERDES	0x0018
+
 #endif /* __ASM_MACH_AR71XX_REGS_H */
diff --git a/target/linux/ath79/image/lzma-loader/src/board.c b/target/linux/ath79/image/lzma-loader/src/board.c
index 2f4dd6b1f6..7b1e110ee2 100644
--- a/target/linux/ath79/image/lzma-loader/src/board.c
+++ b/target/linux/ath79/image/lzma-loader/src/board.c
@@ -10,6 +10,7 @@
 
 #include <stddef.h>
 #include "config.h"
+#include "printf.h"
 #include "ar71xx_regs.h"
 
 #define READREG(r)	*(volatile unsigned int *)(r)
@@ -50,7 +51,139 @@ static void tlwr1043nd_init(void)
 static inline void tlwr1043nd_init(void) {}
 #endif
 
+#ifdef CONFIG_BOARD_MERAKI_MR18
+
+static int mr18_extract_sgmii_res_cal(void)
+{
+	unsigned int base;
+	unsigned int reversed_sgmii_value;
+
+	unsigned int otp_value, otp_per_val, rbias_per, read_data;
+	unsigned int rbias_pos_or_neg;
+	unsigned int sgmii_res_cal_value;
+	int res_cal_val;
+
+	base = KSEG1ADDR(QCA955X_OTP_BASE);
+
+	WRITEREG(base + QCA955X_OTP_REG_INTF2, 0x7d);
+	WRITEREG(base + QCA955X_OTP_REG_LDO_CTRL, 0x00);
+
+	while (READREG(base + QCA955X_OTP_REG_LDO_STATUS) &
+		QCA955X_OTP_LDO_STATUS_POWER_ON)
+		;
+
+	READREG(base + QCA955X_OTP_REG_MEM_0 + 4);
+
+	while (!(READREG(base + QCA955X_OTP_REG_STATUS0) &
+		QCA955X_OTP_STATUS0_EFUSE_VALID))
+		;
+
+	read_data = READREG(base + QCA955X_OTP_REG_STATUS1);
+
+	if (!(read_data & 0x1fff))
+		return 0;
+
+	if (read_data & 0x00001000)
+		otp_value = (read_data & 0xfc0) >> 6;
+	else
+		otp_value = read_data & 0x3f;
+
+	if (otp_value > 31) {
+		otp_per_val = 63 - otp_value;
+		rbias_pos_or_neg = 1;
+	} else {
+		otp_per_val = otp_value;
+		rbias_pos_or_neg = 0;
+	}
+
+	rbias_per = otp_per_val * 15;
+
+	if (rbias_pos_or_neg == 1)
+		res_cal_val = (rbias_per + 34) / 21;
+	else if (rbias_per > 34)
+		res_cal_val = -((rbias_per - 34) / 21);
+	else
+		res_cal_val = (34 - rbias_per) / 21;
+
+	sgmii_res_cal_value = (8 + res_cal_val) & 0xf;
+
+	reversed_sgmii_value  = (sgmii_res_cal_value & 8) >> 3;
+	reversed_sgmii_value |= (sgmii_res_cal_value & 4) >> 1;
+	reversed_sgmii_value |= (sgmii_res_cal_value & 2) << 1;
+	reversed_sgmii_value |= (sgmii_res_cal_value & 1) << 3;
+	printf("SGMII cal value = 0x%x\n", reversed_sgmii_value);
+	return reversed_sgmii_value;
+}
+
+#define QCA955X_SGMII_SERDES_RES_CALIBRATION		BIT(23)
+#define QCA955X_SGMII_SERDES_RES_CALIBRATION_MASK	0xf
+#define QCA955X_SGMII_SERDES_RES_CALIBRATION_SHIFT	23
+#define QCA955X_SGMII_SERDES_LOCK_DETECT_STATUS		BIT(15)
+#define QCA955X_PLL_ETH_SGMII_SERDES_LOCK_DETECT	BIT(2)
+#define QCA955X_PLL_ETH_SGMII_SERDES_PLL_REFCLK		BIT(1)
+#define QCA955X_PLL_ETH_SGMII_SERDES_EN_PLL		BIT(0)
+#define QCA955X_PLL_CLK_CTRL_REG			0x08
+#define QCA955X_PLL_ETH_XMII_CONTROL_REG		0x28
+#define QCA955X_PLL_ETH_SGMII_CONTROL_REG		0x48
+#define QCA955X_PLL_ETH_SGMII_SERDES_REG		0x4c
+
+static void qca955x_device_reset_clear(unsigned int mask)
+{
+	unsigned int t, reg;
+
+	reg = KSEG1ADDR(AR71XX_RESET_BASE +
+			QCA955X_RESET_REG_RESET_MODULE);
+
+	t = READREG(reg);
+	WRITEREG(reg, t & ~mask);
+}
+
+static void mr18_setup_qca955x_eth_serdes_cal(unsigned int sgmii_value)
+{
+	unsigned int ethbase, pllbase, t;
+
+	ethbase = KSEG1ADDR(QCA955X_GMAC_BASE);
+	pllbase = KSEG1ADDR(AR71XX_PLL_BASE);
+
+	/* To Check the locking of the SGMII PLL */
+	t = READREG(ethbase + QCA955X_GMAC_REG_SGMII_SERDES);
+	t &= ~(QCA955X_SGMII_SERDES_RES_CALIBRATION_MASK <<
+	       QCA955X_SGMII_SERDES_RES_CALIBRATION_SHIFT);
+	t |= (sgmii_value & QCA955X_SGMII_SERDES_RES_CALIBRATION_MASK) <<
+	     QCA955X_SGMII_SERDES_RES_CALIBRATION_SHIFT;
+	WRITEREG(ethbase + QCA955X_GMAC_REG_SGMII_SERDES, t);
+
+	WRITEREG(pllbase + QCA955X_PLL_ETH_SGMII_SERDES_REG,
+		 QCA955X_PLL_ETH_SGMII_SERDES_LOCK_DETECT |
+		 QCA955X_PLL_ETH_SGMII_SERDES_PLL_REFCLK |
+		 QCA955X_PLL_ETH_SGMII_SERDES_EN_PLL)
+		;
+
+	qca955x_device_reset_clear(QCA955X_RESET_SGMII_ANALOG);
+	qca955x_device_reset_clear(QCA955X_RESET_SGMII);
+
+	while (!(READREG(ethbase + QCA955X_GMAC_REG_SGMII_SERDES) &
+		QCA955X_SGMII_SERDES_LOCK_DETECT_STATUS))
+		;
+}
+
+static inline void mr18_init(void)
+{
+	int res;
+
+	printf("Meraki MR18\n");
+
+	res = mr18_extract_sgmii_res_cal();
+	if (res >= 0)
+		mr18_setup_qca955x_eth_serdes_cal(res);
+
+}
+#else
+static inline void mr18_init(void) { }
+#endif
+
 void board_init(void)
 {
 	tlwr1043nd_init();
+	mr18_init();
 }
diff --git a/target/linux/ath79/image/nand.mk b/target/linux/ath79/image/nand.mk
index 10a5485010..4f34521a50 100644
--- a/target/linux/ath79/image/nand.mk
+++ b/target/linux/ath79/image/nand.mk
@@ -11,6 +11,14 @@ define Build/dongwon-header
 	mv $@.tmp $@
 endef
 
+define Build/meraki-header
+        -$(STAGING_DIR_HOST)/bin/mkmerakifw \
+                -B $(1) -s \
+                -i $@ \
+                -o $@.new
+        @mv $@.new $@
+endef
+
 # attention: only zlib compression is allowed for the boot fs
 define Build/zyxel-buildkerneljffs
 	mkdir -p $@.tmp/boot
@@ -260,6 +268,23 @@ define Device/linksys_ea4500-v3
 endef
 TARGET_DEVICES += linksys_ea4500-v3
 
+define Device/meraki_mr18
+  SOC := qca9557
+  DEVICE_VENDOR := Meraki
+  DEVICE_MODEL := MR18
+  DEVICE_PACKAGES := kmod-spi-gpio nu801
+  KERNEL_SIZE := 8m
+  BLOCKSIZE := 128k
+  PAGESIZE := 2048
+  LOADER_TYPE := bin
+  KERNEL := kernel-bin | append-dtb | lzma | loader-kernel | meraki-header MR18
+# Initramfs-build fails due to size issues
+# KERNEL_INITRAMFS := $$(KERNEL)
+  KERNEL_INITRAMFS :=
+  IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata
+endef
+TARGET_DEVICES += meraki_mr18
+
 # fake rootfs is mandatory, pad-offset 64 equals (1 * uimage_header)
 define Device/netgear_ath79_nand
   DEVICE_VENDOR := NETGEAR
diff --git a/target/linux/ath79/nand/base-files/etc/board.d/02_network b/target/linux/ath79/nand/base-files/etc/board.d/02_network
index 243c5bb7aa..60f085d378 100644
--- a/target/linux/ath79/nand/base-files/etc/board.d/02_network
+++ b/target/linux/ath79/nand/base-files/etc/board.d/02_network
@@ -8,7 +8,8 @@ ath79_setup_interfaces()
 
 	case "$board" in
 	aerohive,hiveap-121|\
-	glinet,gl-e750)
+	glinet,gl-e750|\
+	meraki,mr18)
 		ucidef_set_interface_lan "eth0"
 		;;
 	domywifi,dw33d)
@@ -102,6 +103,9 @@ ath79_setup_macs()
 		wan_mac=$(mtd_get_mac_binary art 0x0)
 		lan_mac=$(macaddr_add "$wan_mac" 1)
 		;;
+	meraki,mr18)
+		lan_mac=$(mtd_get_mac_binary_ubi board-config 102)
+		;;
 	netgear,wndr3700-v4|\
 	netgear,wndr4300|\
 	netgear,wndr4300sw|\
diff --git a/target/linux/ath79/nand/base-files/etc/hotplug.d/firmware/10-ath9k-eeprom b/target/linux/ath79/nand/base-files/etc/hotplug.d/firmware/10-ath9k-eeprom
index 36ab24e2df..c4ccb04f5b 100644
--- a/target/linux/ath79/nand/base-files/etc/hotplug.d/firmware/10-ath9k-eeprom
+++ b/target/linux/ath79/nand/base-files/etc/hotplug.d/firmware/10-ath9k-eeprom
@@ -12,6 +12,50 @@ case "$FIRMWARE" in
 	8dev,rambutan)
 		caldata_extract "caldata" 0x1000 0x800
 		;;
+	meraki,mr18)
+		. /lib/upgrade/nand.sh
+
+		if [ -n "$(nand_find_volume ubi0 caldata)" ]; then
+			caldata_extract_ubi "caldata" 0x1000 0x440
+		else
+			caldata_extract "odm-caldata" 0x1000 0x440
+		fi
+		ath9k_patch_mac $(macaddr_add $(mtd_get_mac_binary_ubi board-config 102) 1)
+		;;
+	*)
+		caldata_die "board $board is not supported yet"
+		;;
+	esac
+	;;
+"ath9k-eeprom-pci-0000:00:00.0.bin")
+	case $board in
+	meraki,mr18)
+		. /lib/upgrade/nand.sh
+
+		if [ -n "$(nand_find_volume ubi0 caldata)" ]; then
+			caldata_extract_ubi "caldata" 0x5000 0x440
+		else
+			caldata_extract "odm-caldata" 0x5000 0x440
+		fi
+		ath9k_patch_mac $(macaddr_add $(mtd_get_mac_binary_ubi board-config 102) 2)
+		;;
+	*)
+		caldata_die "board $board is not supported yet"
+		;;
+	esac
+	;;
+"ath9k-eeprom-pci-0000:01:00.0.bin")
+	case $board in
+	meraki,mr18)
+		. /lib/upgrade/nand.sh
+
+		if [ -n "$(nand_find_volume ubi0 caldata)" ]; then
+			caldata_extract_ubi "caldata" 0x9000 0x440
+		else
+			caldata_extract "odm-caldata" 0x9000 0x440
+		fi
+		ath9k_patch_mac $(macaddr_add $(mtd_get_mac_binary_ubi board-config 102) 3)
+		;;
 	*)
 		caldata_die "board $board is not supported yet"
 		;;




More information about the lede-commits mailing list