diff --git a/package/firmware/ipq-wifi/Makefile b/package/firmware/ipq-wifi/Makefile
index f2b705e13a..7d26938e97 100644
--- a/package/firmware/ipq-wifi/Makefile
+++ b/package/firmware/ipq-wifi/Makefile
@@ -13,7 +13,7 @@ endef
 define Build/Compile
 endef
 
-ALLWIFIBOARDS:=rt-ac58u fritz4040 nbg6617
+ALLWIFIBOARDS:=rt-ac58u fritz4040 nbg6617 ex6100v2 ex6150v2
 ALLWIFIPACKAGES:=$(foreach BOARD,$(ALLWIFIBOARDS),ipq-wifi-$(BOARD))
 
 define Package/ipq-wifi-default
@@ -44,5 +44,7 @@ endef
 $(eval $(call generate-ipq-wifi-package,rt-ac58u,ASUS RT-AC58U/RT-ACRH13))
 $(eval $(call generate-ipq-wifi-package,fritz4040,AVM FRITZBox 4040))
 $(eval $(call generate-ipq-wifi-package,nbg6617,ZyXEL NBG6617))
+$(eval $(call generate-ipq-wifi-package,ex6100v2,Netgear EX6100v2))
+$(eval $(call generate-ipq-wifi-package,ex6150v2,Netgear EX6150v2))
 
 $(foreach PACKAGE,$(ALLWIFIPACKAGES),$(eval $(call BuildPackage,$(PACKAGE))))
diff --git a/package/firmware/ipq-wifi/board-ex6100v2.bin b/package/firmware/ipq-wifi/board-ex6100v2.bin
new file mode 100644
index 0000000000000000000000000000000000000000..5bb224b244140a1da38b5eaf12cdacf1cccd4fd1
GIT binary patch
diff --git a/package/firmware/ipq-wifi/board-ex6150v2.bin b/package/firmware/ipq-wifi/board-ex6150v2.bin
new file mode 100644
index 0000000000000000000000000000000000000000..930b87053969674534134d0ccf3e5820ccd47d50
GIT binary patch
diff --git a/target/linux/ipq806x/base-files/etc/board.d/02_network b/target/linux/ipq806x/base-files/etc/board.d/02_network
index ad357b7363..6587b9309d 100755
--- a/target/linux/ipq806x/base-files/etc/board.d/02_network
+++ b/target/linux/ipq806x/base-files/etc/board.d/02_network
@@ -50,6 +50,10 @@ nbg6817)
 	ucidef_set_interface_macaddr "lan" "$(macaddr_add $hw_mac_addr 2)"
 	ucidef_set_interface_macaddr "wan" "$(macaddr_add $hw_mac_addr 3)"
 	;;
+ex6100v2 |\
+ex6150v2)
+	ucidef_set_interface_lan "eth0"
+	;;
 *)
 	echo "Unsupported hardware. Network interfaces not intialized"
 	;;
diff --git a/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata b/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
index 4c5b55bc53..b16b637911 100644
--- a/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
+++ b/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
@@ -47,7 +47,9 @@ board=$(board_name)
 case "$FIRMWARE" in
 "ath10k/pre-cal-ahb-a000000.wifi.bin")
 	case "$board" in
-	ap-dk01.1-c1)
+	ap-dk01.1-c1 |\
+	ex6100v2 |\
+	ex6150v2)
 		ath10kcal_extract "ART" 4096 12064
 		;;
 	fritz4040)
@@ -57,7 +59,9 @@ case "$FIRMWARE" in
 	;;
 "ath10k/pre-cal-ahb-a800000.wifi.bin")
 	case "$board" in
-	ap-dk01.1-c1)
+	ap-dk01.1-c1 |\
+	ex6100v2 |\
+	ex6150v2)
 		ath10kcal_extract "ART" 20480 12064
 		;;
 	fritz4040)
diff --git a/target/linux/ipq806x/base-files/etc/hotplug.d/ieee80211/10_fix_wifi_mac b/target/linux/ipq806x/base-files/etc/hotplug.d/ieee80211/10_fix_wifi_mac
index 7884f5117a..0f3231323a 100644
--- a/target/linux/ipq806x/base-files/etc/hotplug.d/ieee80211/10_fix_wifi_mac
+++ b/target/linux/ipq806x/base-files/etc/hotplug.d/ieee80211/10_fix_wifi_mac
@@ -29,6 +29,19 @@ case "$board" in
 	vr2600v)
 		echo $(macaddr_add $(mtd_get_mac_binary default-mac 0)  $(($PHYNBR - 1)) ) > /sys${DEVPATH}/macaddress
 		;;
+	ex6100v2 |\
+	ex6150v2)
+		case "$PHYNBR" in
+		0)
+			# 2.4G
+			echo $(mtd_get_mac_binary dnidata 0) > /sys${DEVPATH}/macaddress
+			;;
+		1)
+			# 5G
+			echo $(mtd_get_mac_binary dnidata 12) > /sys${DEVPATH}/macaddress
+			;;
+		esac
+		;;
 	*)
 		;;
 esac
diff --git a/target/linux/ipq806x/base-files/lib/ipq806x.sh b/target/linux/ipq806x/base-files/lib/ipq806x.sh
index c4d2c8f258..1e011292eb 100644
--- a/target/linux/ipq806x/base-files/lib/ipq806x.sh
+++ b/target/linux/ipq806x/base-files/lib/ipq806x.sh
@@ -7,6 +7,8 @@
 IPQ806X_BOARD_NAME=
 IPQ806X_MODEL=
 
+. /lib/functions.sh
+
 ipq806x_board_detect() {
 	local machine
 	local name
@@ -50,6 +52,28 @@ ipq806x_board_detect() {
 	*"VR2600v")
 		name="vr2600v"
 		;;
+	*"EX61x0v2")
+		# There are two models in this series, which have identical
+		# hardware save for the number of 5G antennas. Since we run
+		# the exact same image on both, we need to check the flash
+		# to distinguish which we're running on.
+		local hw_id="$(dd if="$(find_mtd_part dnidata)" \
+			       bs=1 skip=41 count=25 2>/dev/null)"
+
+		case "$hw_id" in
+		*"1x1")
+			name="ex6100v2"
+			IPQ806X_MODEL="Netgear EX6100v2"
+			;;
+		*"2x2")
+			name="ex6150v2"
+			IPQ806X_MODEL="Netgear EX6150v2"
+			;;
+		*)
+			name="ex6100v2"
+			IPQ806X_MODEL="Netgear EX61?0v2 (ERROR: failed to parse hw_id)"
+		esac
+		;;
 	esac
 
 	[ -z "$name" ] && name="unknown"
diff --git a/target/linux/ipq806x/config-4.9 b/target/linux/ipq806x/config-4.9
index bca4264c8f..6ba480d5a3 100644
--- a/target/linux/ipq806x/config-4.9
+++ b/target/linux/ipq806x/config-4.9
@@ -189,6 +189,7 @@ CONFIG_GENERIC_STRNLEN_USER=y
 CONFIG_GENERIC_TIME_VSYSCALL=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIOLIB_IRQCHIP=y
+CONFIG_GPIO_74X164=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_HANDLE_DOMAIN_IRQ=y
 CONFIG_HARDIRQS_SW_RESEND=y
@@ -452,6 +453,7 @@ CONFIG_SPARSE_IRQ=y
 CONFIG_SPI=y
 # CONFIG_SPI_CADENCE_QUADSPI is not set
 CONFIG_SPI_MASTER=y
+CONFIG_SPI_GPIO=y
 CONFIG_SPI_QUP=y
 CONFIG_SPMI=y
 CONFIG_SPMI_MSM_PMIC_ARB=y
diff --git a/target/linux/ipq806x/files-4.9/arch/arm/boot/dts/qcom-ipq4019-ex61x0v2.dts b/target/linux/ipq806x/files-4.9/arch/arm/boot/dts/qcom-ipq4019-ex61x0v2.dts
new file mode 100644
index 0000000000..a2ae64a1dc
--- /dev/null
+++ b/target/linux/ipq806x/files-4.9/arch/arm/boot/dts/qcom-ipq4019-ex61x0v2.dts
@@ -0,0 +1,211 @@
+#include "qcom-ipq4019-ap.dk01.1.dtsi"
+#include "qcom-ipq4019-bus.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+	model = "Netgear EX61x0v2";
+	compatible = "netgear,ex61x0v2", "qcom,ipq4019";
+
+	memory {
+		device_type = "memory";
+		reg = <0x80000000 0x10000000>;
+	};
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		rsvd@87E00000 {
+			reg = <0x87E00000 0x0200000>;
+			no-map;
+		};
+	};
+
+	aliases {
+		led-boot = &power_amber;
+		led-failsafe = &power_amber;
+		led-running = &power_green;
+		led-upgrade = &power_amber;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	led_spi {
+		compatible = "spi-gpio";
+		#address-cells = <1>;
+		ranges;
+
+		gpio-sck = <&tlmm 5 GPIO_ACTIVE_HIGH>;
+		gpio-mosi = <&tlmm 4 GPIO_ACTIVE_HIGH>;
+		num-chipselects = <0>;
+
+		led_gpio: led_gpio@0 {
+			compatible = "fairchild,74hc595";
+			reg = <0>;
+			gpio-controller;
+			#gpio-cells = <2>;
+			registers-number = <1>;
+			spi-max-frequency = <1000000>;
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		wps {
+			label = "wps";
+			gpios = <&tlmm 0 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_WPS_BUTTON>;
+		};
+
+		reset {
+			label = "reset";
+			gpios = <&tlmm 63 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_RESTART>;
+		};
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+
+		power_amber: power_amber {
+			label = "ex61x0v2:amber:power";
+			gpios = <&led_gpio 7 GPIO_ACTIVE_LOW>;
+		};
+
+		power_green: power_green {
+			label = "ex61x0v2:green:power";
+			gpios = <&led_gpio 6 GPIO_ACTIVE_LOW>;
+		};
+
+		right {
+			label = "ex61x0v2:blue:right";
+			gpios = <&led_gpio 5 GPIO_ACTIVE_LOW>;
+		};
+
+		left {
+			label = "ex61x0v2:blue:left";
+			gpios = <&led_gpio 4 GPIO_ACTIVE_LOW>;
+		};
+
+		client_green {
+			label = "ex61x0v2:green:client";
+			gpios = <&led_gpio 3 GPIO_ACTIVE_LOW>;
+		};
+
+		client_red {
+			label = "ex61x0v2:red:client";
+			gpios = <&led_gpio 2 GPIO_ACTIVE_LOW>;
+		};
+
+		router_green {
+			label = "ex61x0v2:green:router";
+			gpios = <&led_gpio 1 GPIO_ACTIVE_LOW>;
+		};
+
+		router_red {
+			label = "ex61x0v2:red:router";
+			gpios = <&led_gpio 0 GPIO_ACTIVE_LOW>;
+		};
+
+		wps {
+			label = "ex61x0v2:green:wps";
+			gpios = <&tlmm 1 GPIO_ACTIVE_LOW>;
+		};
+	};
+};
+
+&spi_0 {
+	flash@0 {
+		compatible = "winbond,w25q128", "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <24000000>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition0@0 {
+				label = "SBL1";
+				reg = <0x00000000 0x00040000>;
+				read-only;
+			};
+
+			partition1@40000 {
+				label = "MIBIB";
+				reg = <0x00040000 0x00020000>;
+				read-only;
+			};
+
+			partition2@60000 {
+				label = "QSEE";
+				reg = <0x00060000 0x00060000>;
+				read-only;
+			};
+
+			partition3@c0000 {
+				label = "CDT";
+				reg = <0x000c0000 0x00010000>;
+				read-only;
+			};
+
+			partition4@d0000 {
+				label = "DDRPARAMS";
+				reg = <0x000d0000 0x00010000>;
+				read-only;
+			};
+
+			partition5@e0000 {
+				label = "APPSBLENV";
+				reg = <0x000e0000 0x00010000>;
+				read-only;
+			};
+
+			partition6@f0000 {
+				label = "APPSBL";
+				reg = <0x000f0000 0x00080000>;
+				read-only;
+			};
+
+			partition7@170000 {
+				label = "ART";
+				reg = <0x00170000 0x00010000>;
+				read-only;
+			};
+
+			partition8@180000 {
+				label = "config";
+				reg = <0x00180000 0x00010000>;
+				read-only;
+			};
+
+			partition9@190000 {
+				label = "pot";
+				reg = <0x00190000 0x00010000>;
+				read-only;
+			};
+
+			partition10@1a0000 {
+				label = "dnidata";
+				reg = <0x001a0000 0x00010000>;
+				read-only;
+			};
+
+			partition11@1b0000 {
+				label = "firmware";
+				reg = <0x001b0000 0x00e10000>;
+			};
+
+			partition12@fc0000 {
+				label = "language";
+				reg = <0x00fc0000 0x00040000>;
+				read-only;
+			};
+		};
+	};
+};
diff --git a/target/linux/ipq806x/image/Makefile b/target/linux/ipq806x/image/Makefile
index 2e6cb0922e..297062d8b2 100644
--- a/target/linux/ipq806x/image/Makefile
+++ b/target/linux/ipq806x/image/Makefile
@@ -58,7 +58,7 @@ define Device/UbiFit
 	IMAGE/nand-sysupgrade.tar := sysupgrade-tar | append-metadata
 endef
 
-define Device/DniImage
+define Device/DniNandImage
 	PROFILES += $$(DEVICE_NAME)
 	FILESYSTEMS := squashfs
 	KERNEL_SUFFIX := -uImage
@@ -71,7 +71,21 @@ define Device/DniImage
 	IMAGE/factory.img := append-kernel | pad-offset $$$$(BLOCKSIZE) 64 | append-uImage-fakeroot-hdr | pad-to $$$$(KERNEL_SIZE) | append-ubi | netgear-dni
 	IMAGE/sysupgrade.tar := append-kernel | pad-offset $$$$(BLOCKSIZE) 64 | append-uImage-fakeroot-hdr | sysupgrade-tar kernel=$$$$@ | append-metadata
 endef
-DEVICE_VARS += NETGEAR_BOARD_ID NETGEAR_HW_ID
+
+define Device/DniNorImage
+	PROFILES += $$(DEVICE_NAME)
+	FILESYSTEMS := squashfs
+	KERNEL_SUFFIX := -fit-uImage.itb
+	KERNEL = kernel-bin | gzip | fit gzip $$(DTS_DIR)/$$(DEVICE_DTS).dtb $$(FIT_CFG_NAME)
+	KERNEL_NAME := Image
+	NETGEAR_BOARD_ID :=
+	NETGEAR_HW_ID :=
+	FIT_CFG_NAME :=
+	IMAGES := sysupgrade.bin factory.img
+	IMAGE/sysupgrade.bin := append-kernel | pad-offset $$$$(BLOCKSIZE) 64 | append-uImage-fakeroot-hdr | append-rootfs | pad-rootfs | append-metadata
+	IMAGE/factory.img := $$(IMAGE/sysupgrade.bin) | netgear-dni
+endef
+DEVICE_VARS += NETGEAR_BOARD_ID NETGEAR_HW_ID FIT_CFG_NAME
 
 define Device/TpSafeImage
 	PROFILES += $$(DEVICE_NAME)
@@ -136,7 +150,7 @@ endef
 TARGET_DEVICES += C2600
 
 define Device/D7800
-	$(call Device/DniImage)
+	$(call Device/DniNandImage)
 	DEVICE_DTS := qcom-ipq8064-d7800
 	KERNEL_SIZE := 2097152
 	NETGEAR_BOARD_ID := D7800
@@ -193,7 +207,7 @@ endef
 TARGET_DEVICES += FRITZ4040
 
 define Device/R7500
-	$(call Device/DniImage)
+	$(call Device/DniNandImage)
 	DEVICE_DTS := qcom-ipq8064-r7500
 	KERNEL_SIZE := 2097152
 	NETGEAR_BOARD_ID := R7500
@@ -207,7 +221,7 @@ endef
 TARGET_DEVICES += R7500
 
 define Device/R7500v2
-	$(call Device/DniImage)
+	$(call Device/DniNandImage)
 	DEVICE_DTS := qcom-ipq8064-r7500v2
 	KERNEL_SIZE := 2097152
 	NETGEAR_BOARD_ID := R7500v2
@@ -221,7 +235,7 @@ endef
 TARGET_DEVICES += R7500v2
 
 define Device/R7800
-	$(call Device/DniImage)
+	$(call Device/DniNandImage)
 	DEVICE_DTS := qcom-ipq8065-r7800
 	KERNEL_SIZE := 2097152
 	NETGEAR_BOARD_ID := R7800
@@ -294,4 +308,19 @@ define Device/AP-DK04.1-C1
 endef
 TARGET_DEVICES += AP-DK04.1-C1
 
+define Device/EX61x0v2
+	$(call Device/DniNorImage)
+	DEVICE_DTS := qcom-ipq4019-ex61x0v2
+	FIT_CFG_NAME := config@ap.dk01.1-c1
+	KERNEL_LOADADDR := 0x80208000
+	NETGEAR_BOARD_ID := EX6150v2series
+	NETGEAR_HW_ID := 29765285+16+0+128+2x2
+	BLOCKSIZE := 64k
+	PAGESIZE := 256
+	SUPPORTED_DEVICES := ex6100v2 ex6150v2
+	DEVICE_PACKAGES := ath10k-firmware-qca4019 ipq-wifi-ex6100v2 ipq-wifi-ex6150v2
+	DEVICE_TITLE := Netgear EX6100v2/EX6150v2
+endef
+TARGET_DEVICES += EX61x0v2
+
 $(eval $(call BuildImage))
diff --git a/target/linux/ipq806x/patches-4.9/0069-arm-boot-add-dts-files.patch b/target/linux/ipq806x/patches-4.9/0069-arm-boot-add-dts-files.patch
index bab2808789..c4915bdd6d 100644
--- a/target/linux/ipq806x/patches-4.9/0069-arm-boot-add-dts-files.patch
+++ b/target/linux/ipq806x/patches-4.9/0069-arm-boot-add-dts-files.patch
@@ -10,13 +10,14 @@ Signed-off-by: John Crispin <john@phrozen.org>
 
 --- a/arch/arm/boot/dts/Makefile
 +++ b/arch/arm/boot/dts/Makefile
-@@ -618,7 +618,18 @@ dtb-$(CONFIG_ARCH_QCOM) += \
+@@ -618,7 +618,19 @@ dtb-$(CONFIG_ARCH_QCOM) += \
  	qcom-apq8084-mtp.dtb \
  	qcom-ipq4019-ap.dk01.1-c1.dtb \
  	qcom-ipq4019-ap.dk04.1-c1.dtb \
 +	qcom-ipq4019-fritz4040.dtb \
 +	qcom-ipq4019-nbg6617.dtb \
 +	qcom-ipq4019-rt-ac58u.dtb \
++	qcom-ipq4019-ex61x0v2.dtb \
  	qcom-ipq8064-ap148.dtb \
 +	qcom-ipq8064-c2600.dtb \
 +	qcom-ipq8064-d7800.dtb \
