diff --git a/target/linux/ath79/base-files/etc/board.d/02_network b/target/linux/ath79/base-files/etc/board.d/02_network
index e2c303e56572743c21136fca9baa5a6f98201290..62318ee2320cc6762f0568ee09b08eca92023b8c 100755
--- a/target/linux/ath79/base-files/etc/board.d/02_network
+++ b/target/linux/ath79/base-files/etc/board.d/02_network
@@ -288,6 +288,10 @@ ath79_setup_macs()
 		lan_mac=$(mtd_get_mac_ascii u-boot-env ethaddr)
 		wan_mac=$(macaddr_add "$lan_mac" -1)
 		;;
+	jjplus,ja76pf2)
+		wan_mac=$(fconfig -s -r -d $(find_mtd_part "RedBoot config") -n alias/ethaddr)
+		lan_mac=$(macaddr_add "$wan_mac" 1)
+		;;
 	nec,wg800hp)
 		lan_mac=$(mtd_get_mac_text board_data 640)
 		wan_mac=$(mtd_get_mac_text board_data 1152)
diff --git a/target/linux/ath79/base-files/lib/upgrade/platform.sh b/target/linux/ath79/base-files/lib/upgrade/platform.sh
index bc19149d5c4de5a32984f34b27d1e9ce15c9593d..c2fe08154d9e297fc4c79443465257af0ef3290b 100644
--- a/target/linux/ath79/base-files/lib/upgrade/platform.sh
+++ b/target/linux/ath79/base-files/lib/upgrade/platform.sh
@@ -5,9 +5,10 @@
 PART_NAME=firmware
 REQUIRE_IMAGE_METADATA=1
 
-routerstation_do_upgrade() {
+redboot_fis_do_upgrade() {
 	local append
 	local sysup_file="$1"
+	local kern_part="$2"
 	local magic=$(get_magic_word "$sysup_file")
 
 	if [ "$magic" = "4349" ]; then
@@ -15,7 +16,7 @@ routerstation_do_upgrade() {
 
 		[ -f "$CONF_TAR" -a "$SAVE_CONFIG" -eq 1 ] && append="-j $CONF_TAR"
 		dd if="$sysup_file" bs=64k skip=1 2>/dev/null | \
-			mtd -r $append -Fkernel:$kern_length:0x80060000,rootfs write - kernel:rootfs
+			mtd -r $append -F$kern_part:$kern_length:0x80060000,rootfs write - $kern_part:rootfs
 
 	elif [ "$magic" = "7379" ]; then
 		local board_dir=$(tar tf $sysup_file | grep -m 1 '^sysupgrade-.*/$')
@@ -23,7 +24,7 @@ routerstation_do_upgrade() {
 
 		[ -f "$CONF_TAR" -a "$SAVE_CONFIG" -eq 1 ] && append="-j $CONF_TAR"
 		tar xf $sysup_file ${board_dir}kernel ${board_dir}root -O | \
-			mtd -r $append -Fkernel:$kern_length:0x80060000,rootfs write - kernel:rootfs
+			mtd -r $append -F$kern_part:$kern_length:0x80060000,rootfs write - $kern_part:rootfs
 
 	else
 		echo "Unknown image, aborting!"
@@ -39,9 +40,12 @@ platform_do_upgrade() {
 	local board=$(board_name)
 
 	case "$board" in
+	jjplus,ja76pf2)
+		redboot_fis_do_upgrade "$ARGV" linux
+		;;
 	ubnt,routerstation|\
 	ubnt,routerstation-pro)
-		routerstation_do_upgrade "$ARGV"
+		redboot_fis_do_upgrade "$ARGV" kernel
 		;;
 	*)
 		default_do_upgrade "$ARGV"
diff --git a/target/linux/ath79/dts/ar7161_jjplus_ja76pf2.dts b/target/linux/ath79/dts/ar7161_jjplus_ja76pf2.dts
new file mode 100644
index 0000000000000000000000000000000000000000..76f140fa5576e3082b7e3f8b6fe667972726f47a
--- /dev/null
+++ b/target/linux/ath79/dts/ar7161_jjplus_ja76pf2.dts
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+#include "ar7100.dtsi"
+
+/ {
+	model = "jjPlus JA76PF2";
+	compatible = "jjplus,ja76pf2", "qca,ar7161";
+
+	memory@0 {
+		device_type = "memory";
+		reg = <0x0 0x4000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200n8";
+	};
+
+	aliases {
+		led-boot = &d2;
+		led-failsafe = &d2;
+		led-running = &d2;
+		led-upgrade = &d2;
+	};
+
+	extosc: ref {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-output-names = "ref";
+		clock-frequency = <40000000>;
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		d2: d2 {
+			label = "ja76pf2:green:d2";
+			gpios = <&gpio 5 GPIO_ACTIVE_LOW>;
+		};
+
+		d3 {
+			label = "ja76pf2:green:d3";
+			gpios = <&gpio 4 GPIO_ACTIVE_HIGH>;
+		};
+
+		d4 {
+			label = "ja76pf2:green:d4";
+			gpios = <&gpio 3 GPIO_ACTIVE_HIGH>;
+		};
+	};
+
+	keys {
+		compatible = "gpio-keys-polled";
+		poll-interval = <20>;
+
+		sw1 {
+			label = "sw1";
+			linux,code = <KEY_RESTART>;
+			gpios = <&gpio 7 GPIO_ACTIVE_LOW>;
+			debounce-interval = <60>;
+		};
+
+		sw2 {
+			label = "sw2";
+			linux,code = <KEY_WPS_BUTTON>;
+			gpios = <&gpio 8 GPIO_ACTIVE_LOW>;
+			debounce-interval = <60>;
+		};
+	};
+};
+
+&mdio0 {
+	status = "okay";
+
+	phy-mask = <0x1>;
+
+	phy0: ethernet-phy@0 {
+		reg = <0>;
+		phy-mode = "rgmii";
+	};
+
+	phy4: ethernet-phy@4 {
+		reg = <4>;
+		phy-mode = "rgmii";
+	};
+};
+
+&eth0 {
+	status = "okay";
+
+	phy-handle = <&phy0>;
+};
+
+&eth1 {
+	status = "okay";
+
+	phy-handle = <&phy4>;
+};
+
+&pcie0 {
+	status = "okay";
+};
+
+&spi {
+	status = "okay";
+	num-cs = <1>;
+
+	flash@0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <104000000>;
+
+		partitions {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "ecoscentric,redboot-fis-partitions";
+		};
+	};
+};
+
+&uart {
+	status = "okay";
+};
diff --git a/target/linux/ath79/generic/config-default b/target/linux/ath79/generic/config-default
index fddcb1d704b65a080765c9bba0912a846706d48f..313ab8604bd0096b47484c2e990373c6c13cfc2a 100644
--- a/target/linux/ath79/generic/config-default
+++ b/target/linux/ath79/generic/config-default
@@ -8,6 +8,7 @@ CONFIG_LEDS_RESET=y
 CONFIG_MARVELL_PHY=y
 CONFIG_MICREL_PHY=y
 CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-2
 CONFIG_MTD_SPLIT_EVA_FW=y
 CONFIG_OF_ADDRESS_PCI=y
 CONFIG_OF_PCI=y
diff --git a/target/linux/ath79/image/generic.mk b/target/linux/ath79/image/generic.mk
index 6b20b66669c4a4287cf9c3111ce2393d3419ca48..ddf0e62898bf210a63ea997f24f7cb1f3fcc1a49 100644
--- a/target/linux/ath79/image/generic.mk
+++ b/target/linux/ath79/image/generic.mk
@@ -417,6 +417,18 @@ define Device/iodata_wn-ag300dgr
 endef
 TARGET_DEVICES += iodata_wn-ag300dgr
 
+define Device/jjplus_ja76pf2
+  ATH_SOC := ar7161
+  DEVICE_TITLE := jjPlus JA76PF2
+  DEVICE_PACKAGES += -kmod-ath9k -swconfig -wpad-mini -uboot-envtools fconfig
+  IMAGE/sysupgrade.bin := append-rootfs | pad-rootfs | combined-image | check-size $$$$(IMAGE_SIZE)
+#  IMAGE/sysupgrade.bin := append-rootfs | pad-rootfs | check-size $$$$(IMAGE_SIZE) | sysupgrade-tar rootfs=$$$$@ | append-metadata
+  KERNEL := kernel-bin | append-dtb | lzma | pad-to $$(BLOCKSIZE)
+  KERNEL_INITRAMFS := kernel-bin | append-dtb
+  IMAGE_SIZE := 16000k
+endef
+TARGET_DEVICES += jjplus_ja76pf2
+
 define Device/librerouter_librerouter-v1
   ATH_SOC := qca9558
   DEVICE_TITLE := LibreRouter v1
diff --git a/target/linux/ath79/patches-4.14/408-mtd-redboot_partition_scan.patch b/target/linux/ath79/patches-4.14/408-mtd-redboot_partition_scan.patch
new file mode 100644
index 0000000000000000000000000000000000000000..cd41e7ceb27289f9c9b635dde3d48df0afc3f5f8
--- /dev/null
+++ b/target/linux/ath79/patches-4.14/408-mtd-redboot_partition_scan.patch
@@ -0,0 +1,44 @@
+--- a/drivers/mtd/redboot.c
++++ b/drivers/mtd/redboot.c
+@@ -76,12 +76,18 @@ static int parse_redboot_partitions(stru
+ 	static char nullstring[] = "unallocated";
+ #endif
+ 
++	buf = vmalloc(master->erasesize);
++	if (!buf)
++		return -ENOMEM;
++
++ restart:
+ 	if ( directory < 0 ) {
+ 		offset = master->size + directory * master->erasesize;
+ 		while (mtd_block_isbad(master, offset)) {
+ 			if (!offset) {
+ 			nogood:
+ 				printk(KERN_NOTICE "Failed to find a non-bad block to check for RedBoot partition table\n");
++				vfree(buf);
+ 				return -EIO;
+ 			}
+ 			offset -= master->erasesize;
+@@ -94,10 +100,6 @@ static int parse_redboot_partitions(stru
+ 				goto nogood;
+ 		}
+ 	}
+-	buf = vmalloc(master->erasesize);
+-
+-	if (!buf)
+-		return -ENOMEM;
+ 
+ 	printk(KERN_NOTICE "Searching for RedBoot partition table in %s at offset 0x%lx\n",
+ 	       master->name, offset);
+@@ -170,6 +172,11 @@ static int parse_redboot_partitions(stru
+ 	}
+ 	if (i == numslots) {
+ 		/* Didn't find it */
++		if (offset + master->erasesize < master->size) {
++			/* not at the end of the flash yet, maybe next block :) */
++			directory++;
++			goto restart;
++		}
+ 		printk(KERN_NOTICE "No RedBoot partition table detected in %s\n",
+ 		       master->name);
+ 		ret = 0;