From 4943afd7818f56053231a5a7ae90e55da44f1f08 Mon Sep 17 00:00:00 2001
From: Chris Blake <chrisrblake93@gmail.com>
Date: Sat, 10 Mar 2018 10:59:18 +0100
Subject: [PATCH] ipq40xx: add Cisco Meraki MR33 Support

This patch adds support for Cisco Meraki MR33

hardware highlights:

SOC:	IPQ4029 Quad-Core ARMv7 Processor rev 5 (v7l) Cortex-A7
DRAM:	256 MiB DDR3L-1600 @ 627 MHz Micron MT41K128M16JT-125IT
NAND:	128 MiB SLC NAND Spansion S34ML01G200TFV00 (106 MiB usable)
ETH:	Qualcomm Atheros AR8035 Gigabit PHY (1 x LAN/WAN) + PoE
WLAN1:	QCA9887 (168c:0050) PCIe 1x1:1 802.11abgn ac Dualband VHT80
WLAN2:	Qualcomm Atheros QCA4029 2.4GHz 802.11bgn 2:2x2
WLAN3:	Qualcomm Atheros QCA4029 5GHz 802.11a/n/ac 2:2x2 VHT80
LEDS:	1 x Programmable RGB+White Status LED (driven by Ti LP5562 on i2c-1)
	1 x Orange LED Fault Indicator (shared with LP5562)
	2 x LAN Activity / Speed LEDs (On the RJ45 Port)
BUTTON:	one Reset button
MISC:	Bluetooth LE Ti cc2650 PG2.3 4x4mm - BL_CONFIG at 0x0001FFD8
	AT24C64 8KiB EEPROM
	Kensington Lock

Serial:
	WARNING: The serial port needs a TTL/RS-232 3V3 level converter!
	The Serial setting is 115200-8-N-1. The board has a populated
	1x4 0.1" header with half-height/low profile pins.
	The pinout is: VCC (little white arrow), RX, TX, GND.

Flashing needs a serial adaptor, as well as patched ubootwrite utility
(needs Little-Endian support). And a modified u-boot (enabled Ethernet).
Meraki's original u-boot source can be found in:
<https://github.com/riptidewave93/meraki-uboot/tree/mr33-20170427>

Add images to do an installation via bootloader:
 0. open up the MR33 and connect the serial console.

 1. start the 2nd stage bootloader transfer from client pc:

  # ubootwrite.py --write=mr33-uboot.bin
  (The ubootwrite tool will interrupt the boot-process and hence
   it needs to listen for cues. If the connection is bad (due to
   the low-profile pins), the tool can fail multiple times and in
   weird ways. If you are not sure, just use a terminal program
   and see what the device is doing there.

 2. power on the MR33 (with ethernet + serial cables attached)
    Warning: Make sure you do this in a private LAN that has
    no connection to the internet.

 - let it upload the u-boot this can take 250-300 seconds -

 3. use a tftp client (in binary mode!) on your PC to upload the sysupgrade.bin
    (the u-boot is listening on 192.168.1.1)
    # tftp 192.168.1.1
    binary
    put openwrt-ipq40xx-meraki_mr33-squashfs-sysupgrade.bin

 4. wait for it to reboot

 5. connect to your MR33 via ssh on 192.168.1.1

For more detailed instructions, please take a look at the:
"Flashing Instructions for the MR33" PDF. This can be found
on the wiki: <https://openwrt.org/toh/meraki/mr33>
(A link to the mr33-uboot.bin + the modified ubootwrite is
also there)

Thanks to Jerome C. for sending an MR33 to Chris.

Signed-off-by: Chris Blake <chrisrblake93@gmail.com>
Signed-off-by: Mathias Kresin <dev@kresin.me>
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
---
 package/firmware/ipq-wifi/Makefile            |   3 +-
 .../firmware/ipq-wifi/board-meraki_mr33.bin   | Bin 0 -> 24276 bytes
 .../ipq40xx/base-files/etc/board.d/01_leds    |   3 +
 .../ipq40xx/base-files/etc/board.d/02_network |   4 +
 .../etc/hotplug.d/firmware/11-ath10k-caldata  |  74 ++++
 .../lib/preinit/05_set_iface_mac_ipq40xx.sh   |  14 +
 .../base-files/lib/upgrade/platform.sh        |   7 +
 target/linux/ipq40xx/config-4.14              |   3 +
 .../arch/arm/boot/dts/qcom-ipq4029-mr33.dts   | 403 ++++++++++++++++++
 target/linux/ipq40xx/image/Makefile           |  11 +
 .../069-arm-boot-add-dts-files.patch          |   3 +-
 .../patches-4.14/712-mr33-essedma.patch       | 340 +++++++++++++++
 12 files changed, 863 insertions(+), 2 deletions(-)
 create mode 100644 package/firmware/ipq-wifi/board-meraki_mr33.bin
 create mode 100644 target/linux/ipq40xx/base-files/lib/preinit/05_set_iface_mac_ipq40xx.sh
 create mode 100644 target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4029-mr33.dts
 create mode 100644 target/linux/ipq40xx/patches-4.14/712-mr33-essedma.patch

diff --git a/package/firmware/ipq-wifi/Makefile b/package/firmware/ipq-wifi/Makefile
index 39d29a4ff38..a92be6fd41b 100644
--- a/package/firmware/ipq-wifi/Makefile
+++ b/package/firmware/ipq-wifi/Makefile
@@ -13,7 +13,7 @@ endef
 define Build/Compile
 endef
 
-ALLWIFIBOARDS:=asus_rt-ac58u avm_fritzbox-4040 glinet_gl-b1300
+ALLWIFIBOARDS:=asus_rt-ac58u avm_fritzbox-4040 glinet_gl-b1300 meraki_mr33
 ALLWIFIPACKAGES:=$(foreach BOARD,$(ALLWIFIBOARDS),ipq-wifi-$(BOARD))
 
 define Package/ipq-wifi-default
@@ -50,5 +50,6 @@ endef
 $(eval $(call generate-ipq-wifi-package,asus_rt-ac58u,board-asus_rt-ac58u.bin,ASUS RT-AC58U))
 $(eval $(call generate-ipq-wifi-package,avm_fritzbox-4040,board-avm_fritzbox-4040.bin,AVM FRITZ!Box 4040))
 $(eval $(call generate-ipq-wifi-package,glinet_gl-b1300,board-glinet_gl-b1300.bin,GL.iNet GL-B1300))
+$(eval $(call generate-ipq-wifi-package,meraki_mr33,board-meraki_mr33.bin,Cisco Meraki MR33))
 
 $(foreach PACKAGE,$(ALLWIFIPACKAGES),$(eval $(call BuildPackage,$(PACKAGE))))
diff --git a/package/firmware/ipq-wifi/board-meraki_mr33.bin b/package/firmware/ipq-wifi/board-meraki_mr33.bin
new file mode 100644
index 0000000000000000000000000000000000000000..e569b32fe36ad5df8f76532af1a949b3f05e9b60
GIT binary patch
literal 24276
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
A5&!@I

literal 0
HcmV?d00001

diff --git a/target/linux/ipq40xx/base-files/etc/board.d/01_leds b/target/linux/ipq40xx/base-files/etc/board.d/01_leds
index 6a493be3ec4..f1f49abb2ea 100755
--- a/target/linux/ipq40xx/base-files/etc/board.d/01_leds
+++ b/target/linux/ipq40xx/base-files/etc/board.d/01_leds
@@ -26,6 +26,9 @@ avm,fritzbox-4040)
 glinet,gl-b1300)
 	ucidef_set_led_wlan "wlan" "WLAN" "${boardname}:green:wlan" "phy0tpt"
 	;;
+meraki,mr33)
+	ucidef_set_interface_lan "eth0"
+	;;
 *)
 	;;
 esac
diff --git a/target/linux/ipq40xx/base-files/etc/board.d/02_network b/target/linux/ipq40xx/base-files/etc/board.d/02_network
index 8f8d67db32d..d25a039f2d5 100755
--- a/target/linux/ipq40xx/base-files/etc/board.d/02_network
+++ b/target/linux/ipq40xx/base-files/etc/board.d/02_network
@@ -35,6 +35,10 @@ glinet,gl-b1300)
 openmesh,a42)
 	ucidef_set_interfaces_lan_wan "eth1" "eth0"
 	;;
+
+meraki,mr33)
+	ucidef_set_interface_lan "eth0"
+	;;
 *)
 	echo "Unsupported hardware. Network interfaces not intialized"
 	;;
diff --git a/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata b/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
index bc64d5b8ab0..4322c4f3faf 100644
--- a/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
+++ b/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
@@ -1,5 +1,21 @@
 #!/bin/sh
 
+# xor multiple hex values of the same length
+xor() {
+	local val
+	local ret="0x$1"
+	local retlen=${#1}
+
+	shift
+	while [ -n "$1" ]; do
+		val="0x$1"
+		ret=$((ret ^ val))
+		shift
+	done
+
+	printf "%0${retlen}x" "$ret"
+}
+
 ath10kcal_die() {
 	echo "ath10cal: " "$*"
 	exit 1
@@ -37,6 +53,45 @@ ath10kcal_ubi_extract() {
 		ath10kcal_die "failed to extract from $ubi"
 }
 
+ath10kcal_patch_mac() {
+	local mac=$1
+
+	[ -z "$mac" ] && return
+
+	macaddr_2bin $mac | dd of=/lib/firmware/$FIRMWARE conv=notrunc bs=1 seek=6 count=6
+}
+
+ath10kcal_patch_mac_crc() {
+	local mac=$1
+	local mac_offset=6
+	local chksum_offset=2
+	local xor_mac
+	local xor_fw_mac
+	local xor_fw_chksum
+
+	xor_fw_mac=$(hexdump -v -n 6 -s $mac_offset -e '/1 "%02x"' /lib/firmware/$FIRMWARE)
+	xor_fw_mac="${xor_fw_mac:0:4} ${xor_fw_mac:4:4} ${xor_fw_mac:8:4}"
+
+	ath10kcal_patch_mac "$mac" && {
+		xor_mac=${mac//:/}
+		xor_mac="${xor_mac:0:4} ${xor_mac:4:4} ${xor_mac:8:4}"
+
+		xor_fw_chksum=$(hexdump -v -n 2 -s $chksum_offset -e '/1 "%02x"' /lib/firmware/$FIRMWARE)
+		xor_fw_chksum=$(xor $xor_fw_chksum $xor_fw_mac $xor_mac)
+
+		printf "%b" "\x${xor_fw_chksum:0:2}\x${xor_fw_chksum:2:2}" | \
+			dd of=/lib/firmware/$FIRMWARE conv=notrunc bs=1 seek=$chksum_offset count=2
+	}
+}
+
+ath10kcal_is_caldata_valid() {
+	local expected="$1"
+
+	magic=$(hexdump -v -n 2 -e '1/1 "%02x"' /lib/firmware/$FIRMWARE)
+	[[ "$magic" == "$expected" ]]
+	return $?
+}
+
 [ -e /lib/firmware/$FIRMWARE ] && exit 0
 
 . /lib/functions.sh
@@ -46,6 +101,15 @@ board=$(board_name)
 
 
 case "$FIRMWARE" in
+"ath10k/cal-pci-0000:01:00.0.bin")
+	case "$board" in
+	meraki,mr33)
+		ath10kcal_ubi_extract "ART" 36864 2116
+		ath10kcal_is_caldata_valid "4408" || ath10kcal_extract "ART" 36864 2116
+		ath10kcal_patch_mac $(macaddr_add $(get_mac_binary "/sys/bus/i2c/devices/0-0050/eeprom" 102) +1)
+		;;
+	esac
+	;;
 "ath10k/pre-cal-ahb-a000000.wifi.bin")
 	case "$board" in
 	asus,rt-ac58u)
@@ -59,6 +123,11 @@ case "$FIRMWARE" in
 	qcom,ap-dk01.1-c1)
 		ath10kcal_extract "ART" 4096 12064
 		;;
+	meraki,mr33)
+		ath10kcal_ubi_extract "ART" 4096 12064
+		ath10kcal_is_caldata_valid "202f" || ath10kcal_extract "ART" 4096 12064
+		ath10kcal_patch_mac_crc $(macaddr_add $(get_mac_binary "/sys/bus/i2c/devices/0-0050/eeprom" 102) +2)
+		;;
 	openmesh,a42)
 		ath10kcal_extract "0:ART" 4096 12064
 		;;
@@ -77,6 +146,11 @@ case "$FIRMWARE" in
 	qcom,ap-dk01.1-c1)
 		ath10kcal_extract "ART" 20480 12064
 		;;
+	meraki,mr33)
+		ath10kcal_ubi_extract "ART" 20480 12064
+		ath10kcal_is_caldata_valid "202f" || ath10kcal_extract "ART" 20480 12064
+		ath10kcal_patch_mac_crc $(macaddr_add $(get_mac_binary "/sys/bus/i2c/devices/0-0050/eeprom" 102) +3)
+		;;
 	openmesh,a42)
 		ath10kcal_extract "0:ART" 20480 12064
 		;;
diff --git a/target/linux/ipq40xx/base-files/lib/preinit/05_set_iface_mac_ipq40xx.sh b/target/linux/ipq40xx/base-files/lib/preinit/05_set_iface_mac_ipq40xx.sh
new file mode 100644
index 00000000000..1acd7366c81
--- /dev/null
+++ b/target/linux/ipq40xx/base-files/lib/preinit/05_set_iface_mac_ipq40xx.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+. /lib/functions.sh
+
+preinit_set_mac_address() {
+	case $(board_name) in
+	meraki,mr33)
+		mac_lan=$(get_mac_binary "/sys/bus/i2c/devices/0-0050/eeprom" 102)
+		[ -n "$mac_lan" ] && ip link set dev eth0 address "$mac_lan"
+		;;
+	esac
+}
+
+boot_hook_add preinit_main preinit_set_mac_address
diff --git a/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh b/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh
index 261c468813a..52aa2321e3e 100644
--- a/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh
+++ b/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh
@@ -40,6 +40,10 @@ platform_do_upgrade() {
 		PART_NAME="inactive"
 		platform_do_upgrade_openmesh "$ARGV"
 		;;
+	meraki,mr33)
+		CI_KERNPART="part.safe"
+		nand_do_upgrade "$1"
+		;;
 	*)
 		default_do_upgrade "$ARGV"
 		;;
@@ -52,6 +56,9 @@ platform_nand_pre_upgrade() {
 		CI_UBIPART="UBI_DEV"
 		CI_KERNPART="linux"
 		;;
+	meraki,mr33)
+		CI_KERNPART="part.safe"
+		;;
 	esac
 }
 
diff --git a/target/linux/ipq40xx/config-4.14 b/target/linux/ipq40xx/config-4.14
index fe01754d20a..1bba0617614 100644
--- a/target/linux/ipq40xx/config-4.14
+++ b/target/linux/ipq40xx/config-4.14
@@ -159,6 +159,7 @@ CONFIG_DT_IDLE_STATES=y
 CONFIG_DYNAMIC_DEBUG=y
 CONFIG_EDAC_ATOMIC_SCRUB=y
 CONFIG_EDAC_SUPPORT=y
+CONFIG_EEPROM_AT24=y
 CONFIG_ESSEDMA=y
 CONFIG_EXPORTFS=y
 CONFIG_EXTCON=y
@@ -268,6 +269,8 @@ CONFIG_IRQ_DOMAIN=y
 CONFIG_IRQ_DOMAIN_HIERARCHY=y
 CONFIG_IRQ_FORCED_THREADING=y
 CONFIG_IRQ_WORK=y
+CONFIG_LEDS_LP5562=y
+CONFIG_LEDS_LP55XX_COMMON=y
 CONFIG_LIBFDT=y
 CONFIG_LOCK_SPIN_ON_OWNER=y
 CONFIG_LZO_COMPRESS=y
diff --git a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4029-mr33.dts b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4029-mr33.dts
new file mode 100644
index 00000000000..9c1ef4f020e
--- /dev/null
+++ b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4029-mr33.dts
@@ -0,0 +1,403 @@
+/*
+ * Device Tree Source for Meraki MR33 (Stinkbug)
+ *
+ * Copyright (C) 2017 Chris Blake <chrisrblake93@gmail.com>
+ * Copyright (C) 2017 Christian Lamparter <chunkeey@googlemail.com>
+ *
+ * Based on Cisco Meraki DTS from GPL release r25-linux-3.14-20170427
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without
+ * any warranty of any kind, whether express or implied.
+ */
+
+#include "qcom-ipq4019.dtsi"
+#include "qcom-ipq4019-bus.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/soc/qcom,tcsr.h>
+
+/ {
+	model = "Meraki MR33 Access Point";
+	compatible = "meraki,mr33", "qcom,ipq4019";
+
+	aliases {
+		led-boot = &status_green;
+		led-failsafe = &status_red;
+		led-running = &status_green;
+		led-upgrade = &power_orange;
+	};
+
+	/* Do we really need this defined? */
+	memory {
+		device_type = "memory";
+		reg = <0x80000000 0x10000000>;
+	};
+
+	reserved-memory {
+		#address-cells = <0x1>;
+		#size-cells = <0x1>;
+		ranges;
+
+		tz_apps@87b80000 {
+			reg = <0x87b80000 0x280000>;
+			reusable;
+		};
+
+		smem@87e00000 {
+			reg = <0x87e00000 0x080000>;
+			no-map;
+		};
+
+		tz@87e80000 {
+			reg = <0x87e80000 0x180000>;
+			no-map;
+		};
+	};
+
+	soc {
+		mdio@90000 {
+			status = "okay";
+			pinctrl-0 = <&mdio_pins>;
+			pinctrl-names = "default";
+			phy-reset-gpio = <&tlmm 47 0>;
+			/delete-node/ ethernet-phy@0;
+			/delete-node/ ethernet-phy@2;
+			/delete-node/ ethernet-phy@3;
+			/delete-node/ ethernet-phy@4;
+		};
+
+		/* It is a 56-bit counter that supplies the count to the ARM arch
+		   timers and without upstream driver */
+		counter@4a1000 {
+			compatible = "qcom,qca-gcnt";
+			reg = <0x4a1000 0x4>;
+		};
+
+		ess_tcsr@1953000 {
+			compatible = "qcom,tcsr";
+			reg = <0x1953000 0x1000>;
+			qcom,ess-interface-select = <TCSR_ESS_PSGMII_RGMII5>;
+		};
+
+		tcsr@1949000 {
+			compatible = "qcom,tcsr";
+			reg = <0x1949000 0x100>;
+			qcom,wifi_glb_cfg = <TCSR_WIFI_GLB_CFG>;
+		};
+
+		tcsr@1957000 {
+			compatible = "qcom,tcsr";
+			reg = <0x1957000 0x100>;
+			qcom,wifi_noc_memtype_m0_m2 = <TCSR_WIFI_NOC_MEMTYPE_M0_M2>;
+		};
+
+		serial@78af000 {
+			pinctrl-0 = <&serial_0_pins>;
+			pinctrl-names = "default";
+			status = "okay";
+		};
+
+		serial@78b0000 {
+			pinctrl-0 = <&serial_1_pins>;
+			pinctrl-names = "default";
+			status = "okay";
+
+			bluetooth {
+				compatible = "ti,cc2650";
+				enable-gpios = <&tlmm 12 GPIO_ACTIVE_LOW>;
+			};
+		};
+
+		crypto@8e3a000 {
+			status = "okay";
+		};
+
+		watchdog@b017000 {
+			status = "okay";
+		};
+
+		ess-switch@c000000 {
+			switch_mac_mode = <0x3>; /* mac mode for RGMII RMII */
+			switch_lan_bmp = <0x0>; /* lan port bitmap */
+			switch_wan_bmp = <0x10>; /* wan port bitmap */
+		};
+
+		edma@c080000 {
+			qcom,single-phy;
+			qcom,num_gmac = <1>;
+			phy-mode = "rgmii-rxid";
+			status = "okay";
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		reset {
+			label = "reset";
+			gpios = <&tlmm 18 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_RESTART>;
+		};
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+
+		power_orange: power {
+			label = "mr33:orange:power";
+			gpios = <&tlmm 49 GPIO_ACTIVE_LOW>;
+			panic-indicator;
+		};
+	};
+};
+
+&blsp_dma {
+	status = "okay";
+};
+
+&cryptobam {
+	status = "okay";
+};
+
+&gmac0 {
+	qcom,phy_mdio_addr = <1>;
+	qcom,poll_required = <1>;
+	vlan_tag = <0 0x20>;
+};
+
+&i2c_0 {
+	pinctrl-0 = <&i2c_0_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+	at24@50 {
+		compatible = "atmel,24c64";
+		pagesize = <32>;
+		reg = <0x50>;
+		read-only; /* This holds our MAC & Meraki board-data */
+	};
+};
+
+&i2c_1 {
+	pinctrl-0 = <&i2c_1_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	lp5562@30 {
+		enable-gpio = <&tlmm 48 GPIO_ACTIVE_HIGH>;
+		compatible = "ti,lp5562";
+		clock-mode = /bits/8 <2>;
+		reg = <0x30>;
+
+		/* RGB led */
+		status_red: chan0 {
+			chan-name = "mr33:red:status";
+			led-cur = /bits/ 8 <0x20>;
+			max-cur = /bits/ 8 <0x60>;
+		};
+
+		status_green: chan1 {
+			chan-name = "mr33:green:status";
+			led-cur = /bits/ 8 <0x20>;
+			max-cur = /bits/ 8 <0x60>;
+		};
+
+		chan2 {
+			chan-name = "mr33:blue:status";
+			led-cur = /bits/ 8 <0x20>;
+			max-cur = /bits/ 8 <0x60>;
+		};
+
+		chan3 {
+			chan-name = "mr33:white:status";
+			led-cur = /bits/ 8 <0x20>;
+			max-cur = /bits/ 8 <0x60>;
+		};
+	};
+};
+
+&nand {
+	pinctrl-0 = <&nand_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	nand@0 {
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "sbl1";
+				reg = <0x000000000000 0x000000100000>;
+				read-only;
+			};
+			partition@1 {
+				label = "mibib";
+				reg = <0x000000100000 0x000000100000>;
+				read-only;
+			};
+			partition@2 {
+				label = "bootconfig";
+				reg = <0x000000200000 0x000000100000>;
+				read-only;
+			};
+			partition@3 {
+				label = "qsee";
+				reg = <0x000000300000 0x000000100000>;
+				read-only;
+			};
+			partition@4 {
+				label = "qsee_alt";
+				reg = <0x000000400000 0x000000100000>;
+				read-only;
+			};
+			partition@5 {
+				label = "cdt";
+				reg = <0x000000500000 0x000000080000>;
+				read-only;
+			};
+			partition@6 {
+				label = "cdt_alt";
+				reg = <0x000000580000 0x000000080000>;
+				read-only;
+			};
+			partition@7 {
+				label = "ddrparams";
+				reg = <0x000000600000 0x000000080000>;
+				read-only;
+			};
+			partition@8 {
+				label = "u-boot";
+				reg = <0x000000700000 0x000000200000>;
+				read-only;
+			};
+			partition@9 {
+				label = "u-boot-backup";
+				reg = <0x000000900000 0x000000200000>;
+				read-only;
+			};
+			partition@10 {
+				label = "ART";
+				reg = <0x000000b00000 0x000000080000>;
+				read-only;
+			};
+			partition@11 {
+				label = "ubi";
+				reg = <0x000000c00000 0x000007000000>;
+			};
+		};
+	};
+};
+
+&pcie0 {
+	status = "okay";
+	perst-gpio = <&tlmm 38 GPIO_ACTIVE_LOW>;
+	wake-gpio = <&tlmm 50 GPIO_ACTIVE_LOW>;
+};
+
+&qpic_bam {
+	status = "okay";
+};
+
+&tlmm {
+	/*
+	 * GPIO43 should be 0/1 whenever the unit is
+	 * powered through PoE or AC-Adapter.
+	 * That said, playing with this seems to
+	 * reset the AP.
+	 */
+
+	mdio_pins: mdio_pinmux {
+		mux_1 {
+			pins = "gpio6";
+			function = "mdio";
+			bias-pull-up;
+		};
+		mux_2 {
+			pins = "gpio7";
+			function = "mdc";
+			bias-pull-up;
+		};
+	};
+
+	serial_0_pins: serial_pinmux {
+		mux {
+			pins = "gpio16", "gpio17";
+			function = "blsp_uart0";
+			bias-disable;
+		};
+	};
+
+	serial_1_pins: serial1_pinmux {
+		mux {
+			/* We use the i2c-0 pins for serial_1 */
+			pins = "gpio8", "gpio9";
+			function = "blsp_uart1";
+			bias-disable;
+		};
+	};
+
+	i2c_0_pins: i2c_0_pinmux {
+		pinmux {
+			function = "blsp_i2c0";
+			pins = "gpio20", "gpio21";
+		};
+		pinconf {
+			pins = "gpio20", "gpio21";
+			drive-strength = <16>;
+			bias-disable;
+		};
+	};
+
+	i2c_1_pins: i2c_1_pinmux {
+		pinmux {
+			function = "blsp_i2c1";
+			pins = "gpio34", "gpio35";
+		};
+		pinconf {
+			pins = "gpio34", "gpio35";
+			drive-strength = <16>;
+			bias-disable;
+		};
+	};
+
+	nand_pins: nand_pins {
+		/*
+		 * There are 18 pins. 15 pins are common between LCD and NAND.
+		 * The QPIC controller arbitrates between LCD and NAND. Of the
+		 * remaining 4, 2 are for NAND and 2 are for LCD exclusively.
+		 *
+		 * The meraki source hints that the bluetooth module claims
+		 * pin 52 as well. But sadly, there's no data whenever this
+		 * is a NAND or LCD exclusive pin or not.
+		 */
+
+		pullups {
+			pins = "gpio52", "gpio53", "gpio58",
+				"gpio59";
+			function = "qpic";
+			bias-pull-up;
+		};
+
+		pulldowns {
+			pins = "gpio54", "gpio55", "gpio56",
+				"gpio57", "gpio60", "gpio61",
+				"gpio62", "gpio63", "gpio64",
+				"gpio65", "gpio66", "gpio67",
+				"gpio68", "gpio69";
+			function = "qpic";
+			bias-pull-down;
+		};
+	};
+};
+
+&wifi0 {
+	status = "okay";
+	/* qcom,ath10k-calibration-variant = "MERAKI-MR33"; */
+};
+
+&wifi1 {
+	status = "okay";
+	/* qcom,ath10k-calibration-variant = "MERAKI-MR33"; */
+};
diff --git a/target/linux/ipq40xx/image/Makefile b/target/linux/ipq40xx/image/Makefile
index dd71746cc02..1abbb404d76 100644
--- a/target/linux/ipq40xx/image/Makefile
+++ b/target/linux/ipq40xx/image/Makefile
@@ -77,6 +77,17 @@ define Device/glinet_gl-b1300
 endef
 TARGET_DEVICES += glinet_gl-b1300
 
+define Device/meraki_mr33
+	$(call Device/FitImage)
+	DEVICE_DTS := qcom-ipq4029-mr33
+	BLOCKSIZE := 131072
+	PAGESIZE := 2048
+	DEVICE_TITLE := Cisco Meraki MR33
+	IMAGES = sysupgrade.bin
+	DEVICE_PACKAGES := -swconfig ipq-wifi-meraki_mr33 ath10k-firmware-qca9887
+endef
+TARGET_DEVICES += meraki_mr33
+
 define Device/openmesh_a42
 	$(call Device/FitImageLzma)
 	DEVICE_DTS := qcom-ipq4018-a42
diff --git a/target/linux/ipq40xx/patches-4.14/069-arm-boot-add-dts-files.patch b/target/linux/ipq40xx/patches-4.14/069-arm-boot-add-dts-files.patch
index 745a39e05db..b472c122d09 100644
--- a/target/linux/ipq40xx/patches-4.14/069-arm-boot-add-dts-files.patch
+++ b/target/linux/ipq40xx/patches-4.14/069-arm-boot-add-dts-files.patch
@@ -10,7 +10,7 @@ Signed-off-by: John Crispin <john@phrozen.org>
 
 --- a/arch/arm/boot/dts/Makefile
 +++ b/arch/arm/boot/dts/Makefile
-@@ -697,7 +697,12 @@ dtb-$(CONFIG_ARCH_QCOM) += \
+@@ -697,7 +697,13 @@ dtb-$(CONFIG_ARCH_QCOM) += \
  	qcom-apq8074-dragonboard.dtb \
  	qcom-apq8084-ifc6540.dtb \
  	qcom-apq8084-mtp.dtb \
@@ -20,6 +20,7 @@ Signed-off-by: John Crispin <john@phrozen.org>
 +	qcom-ipq4019-ap.dk04.1-c1.dtb \
 +	qcom-ipq4019-fritz4040.dtb \
 +	qcom-ipq4029-gl-b1300.dtb \
++	qcom-ipq4029-mr33.dtb \
  	qcom-ipq8064-ap148.dtb \
  	qcom-msm8660-surf.dtb \
  	qcom-msm8960-cdp.dtb \
diff --git a/target/linux/ipq40xx/patches-4.14/712-mr33-essedma.patch b/target/linux/ipq40xx/patches-4.14/712-mr33-essedma.patch
new file mode 100644
index 00000000000..6be30070d66
--- /dev/null
+++ b/target/linux/ipq40xx/patches-4.14/712-mr33-essedma.patch
@@ -0,0 +1,340 @@
+--- a/drivers/net/ethernet/qualcomm/essedma/edma_axi.c
++++ b/drivers/net/ethernet/qualcomm/essedma/edma_axi.c
+@@ -17,6 +17,11 @@
+ #include <linux/of.h>
+ #include <linux/of_net.h>
+ #include <linux/timer.h>
++#include <linux/of_platform.h>
++#include <linux/of_address.h>
++#include <linux/clk.h>
++#include <linux/string.h>
++#include <linux/reset.h>
+ #include "edma.h"
+ #include "ess_edma.h"
+ 
+@@ -83,7 +88,103 @@ void edma_read_reg(u16 reg_addr, volatil
+ 	*reg_value = readl((void __iomem *)(edma_hw_addr + reg_addr));
+ }
+ 
+-/* edma_change_tx_coalesce()
++static void ess_write_reg(struct edma_common_info *edma, u16 reg_addr, u32 reg_value)
++{
++	writel(reg_value, ((void __iomem *)
++		((unsigned long)edma->ess_hw_addr + reg_addr)));
++}
++
++static void ess_read_reg(struct edma_common_info *edma, u16 reg_addr,
++		  volatile u32 *reg_value)
++{
++	*reg_value = readl((void __iomem *)
++		((unsigned long)edma->ess_hw_addr + reg_addr));
++}
++
++static int ess_reset(struct edma_common_info *edma)
++{
++	struct device_node *switch_node = NULL;
++	struct reset_control *ess_rst;
++	u32 regval;
++
++	switch_node = of_find_node_by_name(NULL, "ess-switch");
++	if (!switch_node) {
++		pr_err("switch-node not found\n");
++		return -EINVAL;
++	}
++
++	ess_rst = of_reset_control_get(switch_node, "ess_rst");
++	of_node_put(switch_node);
++
++	if (IS_ERR(ess_rst)) {
++		pr_err("failed to find ess_rst!\n");
++		return -ENOENT;
++	}
++
++	reset_control_assert(ess_rst);
++	msleep(10);
++	reset_control_deassert(ess_rst);
++	msleep(100);
++	reset_control_put(ess_rst);
++
++	/* Enable only port 5 <--> port 0
++	 * bits 0:6 bitmap of ports it can fwd to */
++#define SET_PORT_BMP(r,v) \
++		ess_read_reg(edma, r, &regval); \
++		ess_write_reg(edma, r, ((regval & ~0x3F) | v));
++
++	SET_PORT_BMP(ESS_PORT0_LOOKUP_CTRL,0x20);
++	SET_PORT_BMP(ESS_PORT1_LOOKUP_CTRL,0x00);
++	SET_PORT_BMP(ESS_PORT2_LOOKUP_CTRL,0x00);
++	SET_PORT_BMP(ESS_PORT3_LOOKUP_CTRL,0x00);
++	SET_PORT_BMP(ESS_PORT4_LOOKUP_CTRL,0x00);
++	SET_PORT_BMP(ESS_PORT5_LOOKUP_CTRL,0x01);
++	ess_write_reg(edma, ESS_RGMII_CTRL, 0x400);
++	ess_write_reg(edma, ESS_PORT0_STATUS, ESS_PORT_1G_FDX);
++	ess_write_reg(edma, ESS_PORT5_STATUS, ESS_PORT_1G_FDX);
++	ess_write_reg(edma, ESS_PORT0_HEADER_CTRL, 0);
++#undef SET_PORT_BMP
++
++	/* forward multicast and broadcast frames to CPU */
++	ess_write_reg(edma, ESS_FWD_CTRL1,
++		(ESS_PORTS_ALL << ESS_FWD_CTRL1_UC_FLOOD_S) |
++		(ESS_PORTS_ALL << ESS_FWD_CTRL1_MC_FLOOD_S) |
++		(ESS_PORTS_ALL << ESS_FWD_CTRL1_BC_FLOOD_S));
++
++	return 0;
++}
++
++void ess_set_port_status_speed(struct edma_common_info *edma,
++			       struct phy_device *phydev, uint8_t port_id)
++{
++	uint16_t reg_off = ESS_PORT0_STATUS + (4 * port_id);
++	uint32_t reg_val = 0;
++
++	ess_read_reg(edma, reg_off, &reg_val);
++
++	/* reset the speed bits [0:1] */
++	reg_val &= ~ESS_PORT_STATUS_SPEED_INV;
++
++	/* set the new speed */
++	switch(phydev->speed) {
++		case SPEED_1000:  reg_val |= ESS_PORT_STATUS_SPEED_1000; break;
++		case SPEED_100:   reg_val |= ESS_PORT_STATUS_SPEED_100;  break;
++		case SPEED_10:    reg_val |= ESS_PORT_STATUS_SPEED_10;   break;
++		default:          reg_val |= ESS_PORT_STATUS_SPEED_INV;  break;
++	}
++
++	/* check full/half duplex */
++	if (phydev->duplex) {
++		reg_val |= ESS_PORT_STATUS_DUPLEX_MODE;
++	} else {
++		reg_val &= ~ESS_PORT_STATUS_DUPLEX_MODE;
++	}
++
++	ess_write_reg(edma, reg_off, reg_val);
++}
++
++/*
++ * edma_change_tx_coalesce()
+  *	change tx interrupt moderation timer
+  */
+ void edma_change_tx_coalesce(int usecs)
+@@ -551,6 +652,31 @@ static struct ctl_table edma_table[] = {
+ 	{}
+ };
+ 
++static int ess_parse(struct edma_common_info *edma)
++{
++	struct device_node *switch_node;
++	int ret = -EINVAL;
++
++	switch_node = of_find_node_by_name(NULL, "ess-switch");
++	if (!switch_node) {
++		pr_err("cannot find ess-switch node\n");
++		goto out;
++	}
++
++	edma->ess_hw_addr = of_io_request_and_map(switch_node,
++						  0, KBUILD_MODNAME);
++	if (!edma->ess_hw_addr) {
++		pr_err("%s ioremap fail.", __func__);
++		goto out;
++	}
++
++	edma->ess_clk = of_clk_get_by_name(switch_node, "ess_clk");
++	ret = clk_prepare_enable(edma->ess_clk);
++out:
++	of_node_put(switch_node);
++	return ret;
++}
++
+ /* edma_axi_netdev_ops
+  *	Describe the operations supported by registered netdevices
+  *
+@@ -786,6 +912,17 @@ static int edma_axi_probe(struct platfor
+ 		miibus = mdio_data->mii_bus;
+ 	}
+ 
++	if (of_property_read_bool(np, "qcom,single-phy") &&
++	    edma_cinfo->num_gmac == 1) {
++		err = ess_parse(edma_cinfo);
++		if (!err)
++			err = ess_reset(edma_cinfo);
++		if (err)
++			goto err_single_phy_init;
++		else
++			edma_cinfo->is_single_phy = true;
++	}
++
+ 	for_each_available_child_of_node(np, pnp) {
+ 		const char *mac_addr;
+ 
+@@ -1074,11 +1211,15 @@ static int edma_axi_probe(struct platfor
+ 
+ 	for (i = 0; i < edma_cinfo->num_gmac; i++) {
+ 		if (adapter[i]->poll_required) {
++			int phy_mode = of_get_phy_mode(np);
++
++			if (phy_mode < 0)
++				phy_mode = PHY_INTERFACE_MODE_SGMII;
+ 			adapter[i]->phydev =
+ 				phy_connect(edma_netdev[i],
+ 					    (const char *)adapter[i]->phy_id,
+ 					    &edma_adjust_link,
+-					    PHY_INTERFACE_MODE_SGMII);
++					    phy_mode);
+ 			if (IS_ERR(adapter[i]->phydev)) {
+ 				dev_dbg(&pdev->dev, "PHY attach FAIL");
+ 				err = -EIO;
+@@ -1125,6 +1266,9 @@ err_rmap_alloc_fail:
+ 	for (i = 0; i < edma_cinfo->num_gmac; i++)
+ 		unregister_netdev(edma_netdev[i]);
+ err_register:
++err_single_phy_init:
++	iounmap(edma_cinfo->ess_hw_addr);
++	clk_disable_unprepare(edma_cinfo->ess_clk);
+ err_mdiobus_init_fail:
+ 	edma_free_rx_rings(edma_cinfo);
+ err_rx_rinit:
+@@ -1185,6 +1329,8 @@ static int edma_axi_remove(struct platfo
+ 	del_timer_sync(&edma_stats_timer);
+ 	edma_free_irqs(adapter);
+ 	unregister_net_sysctl_table(edma_cinfo->edma_ctl_table_hdr);
++	iounmap(edma_cinfo->ess_hw_addr);
++	clk_disable_unprepare(edma_cinfo->ess_clk);
+ 	edma_free_tx_resources(edma_cinfo);
+ 	edma_free_rx_resources(edma_cinfo);
+ 	edma_free_tx_rings(edma_cinfo);
+--- a/drivers/net/ethernet/qualcomm/essedma/edma.c
++++ b/drivers/net/ethernet/qualcomm/essedma/edma.c
+@@ -161,8 +161,10 @@ static void edma_configure_rx(struct edm
+ 	/* Set Rx FIFO threshold to start to DMA data to host */
+ 	rxq_ctrl_data = EDMA_FIFO_THRESH_128_BYTE;
+ 
+-	/* Set RX remove vlan bit */
+-	rxq_ctrl_data |= EDMA_RXQ_CTRL_RMV_VLAN;
++	if (!edma_cinfo->is_single_phy) {
++		/* Set RX remove vlan bit */
++		rxq_ctrl_data |= EDMA_RXQ_CTRL_RMV_VLAN;
++	}
+ 
+ 	edma_write_reg(EDMA_REG_RXQ_CTRL, rxq_ctrl_data);
+ }
+@@ -1295,6 +1297,10 @@ void edma_adjust_link(struct net_device
+ 	if (status == __EDMA_LINKUP && adapter->link_state == __EDMA_LINKDOWN) {
+ 		dev_info(&adapter->pdev->dev, "%s: GMAC Link is up with phy_speed=%d\n", netdev->name, phydev->speed);
+ 		adapter->link_state = __EDMA_LINKUP;
++		if (adapter->edma_cinfo->is_single_phy) {
++			ess_set_port_status_speed(adapter->edma_cinfo, phydev,
++						  ffs(adapter->dp_bitmap) - 1);
++		}
+ 		netif_carrier_on(netdev);
+ 		if (netif_running(netdev))
+ 			netif_tx_wake_all_queues(netdev);
+@@ -1388,10 +1394,12 @@ netdev_tx_t edma_xmit(struct sk_buff *sk
+ 	}
+ 
+ 	/* Check and mark VLAN tag offload */
+-	if (skb_vlan_tag_present(skb))
+-		flags_transmit |= EDMA_VLAN_TX_TAG_INSERT_FLAG;
+-	else if (adapter->default_vlan_tag)
+-		flags_transmit |= EDMA_VLAN_TX_TAG_INSERT_DEFAULT_FLAG;
++	if (!adapter->edma_cinfo->is_single_phy) {
++		if (unlikely(skb_vlan_tag_present(skb)))
++			flags_transmit |= EDMA_VLAN_TX_TAG_INSERT_FLAG;
++		else if (adapter->default_vlan_tag)
++			flags_transmit |= EDMA_VLAN_TX_TAG_INSERT_DEFAULT_FLAG;
++	}
+ 
+ 	/* Check and mark checksum offload */
+ 	if (likely(skb->ip_summed == CHECKSUM_PARTIAL))
+--- a/drivers/net/ethernet/qualcomm/essedma/edma.h
++++ b/drivers/net/ethernet/qualcomm/essedma/edma.h
+@@ -31,6 +31,7 @@
+ #include <linux/platform_device.h>
+ #include <linux/of.h>
+ #include <linux/of_device.h>
++#include <linux/clk.h>
+ #include <linux/kernel.h>
+ #include <linux/device.h>
+ #include <linux/sysctl.h>
+@@ -331,6 +332,10 @@ struct edma_common_info {
+ 	struct edma_hw hw; /* edma hw specific structure */
+ 	struct edma_per_cpu_queues_info edma_percpu_info[CONFIG_NR_CPUS]; /* per cpu information */
+ 	spinlock_t stats_lock; /* protect edma stats area for updation */
++
++	bool is_single_phy;
++	void __iomem *ess_hw_addr;
++	struct clk *ess_clk;
+ };
+ 
+ /* transimit packet descriptor (tpd) ring */
+@@ -443,4 +448,6 @@ void edma_change_tx_coalesce(int usecs);
+ void edma_change_rx_coalesce(int usecs);
+ void edma_get_tx_rx_coalesce(u32 *reg_val);
+ void edma_clear_irq_status(void);
++void ess_set_port_status_speed(struct edma_common_info *edma_cinfo,
++                               struct phy_device *phydev, uint8_t port_id);
+ #endif /* _EDMA_H_ */
+--- a/drivers/net/ethernet/qualcomm/essedma/ess_edma.h
++++ b/drivers/net/ethernet/qualcomm/essedma/ess_edma.h
+@@ -329,4 +329,61 @@ struct edma_hw;
+ #define EDMA_RRD_PRIORITY_MASK 0x7
+ #define EDMA_RRD_PORT_TYPE_SHIFT 7
+ #define EDMA_RRD_PORT_TYPE_MASK 0x1F
++
++#define ESS_RGMII_CTRL		0x0004
++
++/* Port status registers */
++#define ESS_PORT0_STATUS	0x007C
++#define ESS_PORT1_STATUS	0x0080
++#define ESS_PORT2_STATUS	0x0084
++#define ESS_PORT3_STATUS	0x0088
++#define ESS_PORT4_STATUS	0x008C
++#define ESS_PORT5_STATUS	0x0090
++
++#define ESS_PORT_STATUS_HDX_FLOW_CTL	0x80
++#define ESS_PORT_STATUS_DUPLEX_MODE	0x40
++#define ESS_PORT_STATUS_RX_FLOW_EN	0x20
++#define ESS_PORT_STATUS_TX_FLOW_EN	0x10
++#define ESS_PORT_STATUS_RX_MAC_EN	0x08
++#define ESS_PORT_STATUS_TX_MAC_EN	0x04
++#define ESS_PORT_STATUS_SPEED_INV	0x03
++#define ESS_PORT_STATUS_SPEED_1000	0x02
++#define ESS_PORT_STATUS_SPEED_100	0x01
++#define ESS_PORT_STATUS_SPEED_10	0x00
++
++#define ESS_PORT_1G_FDX      (ESS_PORT_STATUS_DUPLEX_MODE | ESS_PORT_STATUS_RX_FLOW_EN | \
++			       ESS_PORT_STATUS_TX_FLOW_EN  | ESS_PORT_STATUS_RX_MAC_EN  | \
++			       ESS_PORT_STATUS_TX_MAC_EN   | ESS_PORT_STATUS_SPEED_1000)
++
++#define PHY_STATUS_REG			0x11
++#define PHY_STATUS_SPEED		0xC000
++#define PHY_STATUS_SPEED_SHIFT		14
++#define PHY_STATUS_DUPLEX		0x2000
++#define PHY_STATUS_DUPLEX_SHIFT	13
++#define PHY_STATUS_SPEED_DUPLEX_RESOLVED 0x0800
++#define PHY_STATUS_CARRIER		0x0400
++#define PHY_STATUS_CARRIER_SHIFT	10
++
++/* Port lookup control registers */
++#define ESS_PORT0_LOOKUP_CTRL	0x0660
++#define ESS_PORT1_LOOKUP_CTRL	0x066C
++#define ESS_PORT2_LOOKUP_CTRL	0x0678
++#define ESS_PORT3_LOOKUP_CTRL	0x0684
++#define ESS_PORT4_LOOKUP_CTRL	0x0690
++#define ESS_PORT5_LOOKUP_CTRL	0x069C
++
++#define ESS_PORT0_HEADER_CTRL	0x009C
++
++#define ESS_PORTS_ALL		0x3f
++
++#define ESS_FWD_CTRL1		0x0624
++#define   ESS_FWD_CTRL1_UC_FLOOD		BITS(0, 7)
++#define   ESS_FWD_CTRL1_UC_FLOOD_S		0
++#define   ESS_FWD_CTRL1_MC_FLOOD		BITS(8, 7)
++#define   ESS_FWD_CTRL1_MC_FLOOD_S		8
++#define   ESS_FWD_CTRL1_BC_FLOOD		BITS(16, 7)
++#define   ESS_FWD_CTRL1_BC_FLOOD_S		16
++#define   ESS_FWD_CTRL1_IGMP			BITS(24, 7)
++#define   ESS_FWD_CTRL1_IGMP_S			24
++
+ #endif /* _ESS_EDMA_H_ */
-- 
GitLab