From d3d3a2d645502e69874531fc45b0e866f2230c1a Mon Sep 17 00:00:00 2001
From: Josef Schlehofer <josef.schlehofer@nic.cz>
Date: Mon, 25 Jul 2022 16:33:07 +0200
Subject: [PATCH] patches/openwrt/5.15: backport OpenWrt patches for mvebu

---
 .../0016-Add-OpenWrt-patches-for-mvebu.patch  | 4630 +++++++++++++++++
 1 file changed, 4630 insertions(+)
 create mode 100644 patches/openwrt/5.15-kernel-configuration/0016-Add-OpenWrt-patches-for-mvebu.patch

diff --git a/patches/openwrt/5.15-kernel-configuration/0016-Add-OpenWrt-patches-for-mvebu.patch b/patches/openwrt/5.15-kernel-configuration/0016-Add-OpenWrt-patches-for-mvebu.patch
new file mode 100644
index 000000000..8b782aeec
--- /dev/null
+++ b/patches/openwrt/5.15-kernel-configuration/0016-Add-OpenWrt-patches-for-mvebu.patch
@@ -0,0 +1,4630 @@
+From 5be155a8a411e9086432ebdbfbaa8957abb2d51e Mon Sep 17 00:00:00 2001
+From: Josef Schlehofer <pepe.schlehofer@gmail.com>
+Date: Mon, 25 Jul 2022 16:32:14 +0200
+Subject: [PATCH] Add OpenWrt patches for mvebu
+
+---
+ ...Mangle-bootloader-s-kernel-arguments.patch |  208 ++++
+ ...-mvebu-armada-38x-enable-libata-leds.patch |   10 +
+ .../patches-5.15/302-add_powertables.patch    |  770 ++++++++++++
+ .../patches-5.15/304-revert_i2c_delay.patch   |   15 +
+ .../305-armada-385-rd-mtd-partitions.patch    |   19 +
+ .../306-ARM-mvebu-385-ap-Add-partitions.patch |   35 +
+ ...-armada-xp-linksys-mamba-broken-idle.patch |   10 +
+ .../308-armada-xp-linksys-mamba-wan.patch     |   11 +
+ .../patches-5.15/309-linksys-status-led.patch |   50 +
+ .../310-linksys-use-eth0-as-cpu-port.patch    |   25 +
+ .../311-adjust-compatible-for-linksys.patch   |   68 ++
+ ...da388-clearfog-emmc-on-clearfog-base.patch |   87 ++
+ .../313-helios4-dts-status-led-alias.patch    |   28 +
+ ...rmada-xp-linksys-mamba-resize-kernel.patch |   37 +
+ ...316-armada-370-dts-fix-crypto-engine.patch |   29 +
+ .../patches-5.15/400-find_active_root.patch   |   60 +
+ .../700-mvneta-tx-queue-workaround.patch      |   38 +
+ ...ethernet-marvell-mvnetaMQPrioOffload.patch |   66 ++
+ ...xt-ethernet-marvell-mvnetaMQPrioFlag.patch |   30 +
+ ...t-ethernet-marvell-mvnetaMQPrioQueue.patch |   97 ++
+ ...hernet-marvell-mvnetaMQPrioTCOffload.patch |  182 +++
+ ...dicate-failure-to-enter-deeper-sleep.patch |   40 +
+ ...-pci-mvebu-time-out-reset-on-link-up.patch |   60 +
+ ...IEI-vendor-prefix-and-IEI-WT61P803-P.patch |  218 ++++
+ ...a-driver-for-IEI-WT61P803-PUZZLE-MCU.patch | 1034 +++++++++++++++++
+ ...d-the-IEI-WT61P803-PUZZLE-HWMON-driv.patch |  469 ++++++++
+ ...d-the-IEI-WT61P803-PUZZLE-LED-driver.patch |  207 ++++
+ ...I-Add-iei-wt61p803-puzzle-driver-sys.patch |   82 ++
+ ...mon-Add-iei-wt61p803-puzzle-hwmon-dr.patch |   74 ++
+ ...an-entry-for-the-IEI-WT61P803-PUZZLE.patch |   41 +
+ ...rs-leds-wt61p803-puzzle-improvements.patch |  271 +++++
+ 31 files changed, 4371 insertions(+)
+ create mode 100644 target/linux/mvebu/patches-5.15/300-mvebu-Mangle-bootloader-s-kernel-arguments.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/301-mvebu-armada-38x-enable-libata-leds.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/302-add_powertables.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/304-revert_i2c_delay.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/305-armada-385-rd-mtd-partitions.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/306-ARM-mvebu-385-ap-Add-partitions.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/307-armada-xp-linksys-mamba-broken-idle.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/308-armada-xp-linksys-mamba-wan.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/309-linksys-status-led.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/310-linksys-use-eth0-as-cpu-port.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/311-adjust-compatible-for-linksys.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/312-ARM-dts-armada388-clearfog-emmc-on-clearfog-base.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/313-helios4-dts-status-led-alias.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/315-armada-xp-linksys-mamba-resize-kernel.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/316-armada-370-dts-fix-crypto-engine.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/400-find_active_root.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/700-mvneta-tx-queue-workaround.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/702-net-next-ethernet-marvell-mvnetaMQPrioOffload.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/703-net-next-ethernet-marvell-mvnetaMQPrioFlag.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/704-net-next-ethernet-marvell-mvnetaMQPrioQueue.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/705-net-next-ethernet-marvell-mvnetaMQPrioTCOffload.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/800-cpuidle-mvebu-indicate-failure-to-enter-deeper-sleep.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/801-pci-mvebu-time-out-reset-on-link-up.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/901-dt-bindings-Add-IEI-vendor-prefix-and-IEI-WT61P803-P.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/902-drivers-mfd-Add-a-driver-for-IEI-WT61P803-PUZZLE-MCU.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/903-drivers-hwmon-Add-the-IEI-WT61P803-PUZZLE-HWMON-driv.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/904-drivers-leds-Add-the-IEI-WT61P803-PUZZLE-LED-driver.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/905-Documentation-ABI-Add-iei-wt61p803-puzzle-driver-sys.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/906-Documentation-hwmon-Add-iei-wt61p803-puzzle-hwmon-dr.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/907-MAINTAINERS-Add-an-entry-for-the-IEI-WT61P803-PUZZLE.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/910-drivers-leds-wt61p803-puzzle-improvements.patch
+
+diff --git a/target/linux/mvebu/patches-5.15/300-mvebu-Mangle-bootloader-s-kernel-arguments.patch b/target/linux/mvebu/patches-5.15/300-mvebu-Mangle-bootloader-s-kernel-arguments.patch
+new file mode 100644
+index 0000000000..071ea6742d
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/300-mvebu-Mangle-bootloader-s-kernel-arguments.patch
+@@ -0,0 +1,208 @@
++From 71270226b14733a4b1f2cde58ea9265caa50b38d Mon Sep 17 00:00:00 2001
++From: Adrian Panella <ianchi74@outlook.com>
++Date: Thu, 9 Mar 2017 09:37:17 +0100
++Subject: [PATCH 67/69] generic: Mangle bootloader's kernel arguments
++
++The command-line arguments provided by the boot loader will be
++appended to a new device tree property: bootloader-args.
++If there is a property "append-rootblock" in DT under /chosen
++and a root= option in bootloaders command line it will be parsed
++and added to DT bootargs with the form: <append-rootblock>XX.
++Only command line ATAG will be processed, the rest of the ATAGs
++sent by bootloader will be ignored.
++This is usefull in dual boot systems, to get the current root partition
++without afecting the rest of the system.
++
++Signed-off-by: Adrian Panella <ianchi74@outlook.com>
++
++This patch has been modified to be mvebu specific. The original patch 
++did not pass the bootloader cmdline on if no append-rootblock stanza 
++was found, resulting in blank cmdline and failure to boot.
++
++Signed-off-by: Michael Gray <michael.gray@lantisproject.com>
++---
++ arch/arm/Kconfig                        | 11 ++++
++ arch/arm/boot/compressed/atags_to_fdt.c | 85 ++++++++++++++++++++++++-
++ init/main.c                             | 16 +++++
++ 3 files changed, 111 insertions(+), 1 deletion(-)
++
++--- a/arch/arm/Kconfig
+++++ b/arch/arm/Kconfig
++@@ -1727,6 +1727,17 @@ config ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEN
++ 	  The command-line arguments provided by the boot loader will be
++ 	  appended to the the device tree bootargs property.
++ 
+++config ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE
+++	bool "Append rootblock parsing bootloader's kernel arguments"
+++	help
+++	  The command-line arguments provided by the boot loader will be
+++	  appended to a new device tree property: bootloader-args.
+++	  If there is a property "append-rootblock" in DT under /chosen 
+++	  and a root= option in bootloaders command line it will be parsed 
+++	  and added to DT bootargs with the form: <append-rootblock>XX.
+++	  Only command line ATAG will be processed, the rest of the ATAGs
+++	  sent by bootloader will be ignored.
+++
++ endchoice
++ 
++ config CMDLINE
++--- a/arch/arm/boot/compressed/atags_to_fdt.c
+++++ b/arch/arm/boot/compressed/atags_to_fdt.c
++@@ -5,6 +5,8 @@
++ 
++ #if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND)
++ #define do_extend_cmdline 1
+++#elif defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE)
+++#define do_extend_cmdline 1
++ #else
++ #define do_extend_cmdline 0
++ #endif
++@@ -69,6 +71,72 @@ static uint32_t get_cell_size(const void
++ 	return cell_size;
++ }
++ 
+++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE)
+++
+++static char *append_rootblock(char *dest, const char *str, int len, void *fdt)
+++{
+++	char *ptr, *end;
+++	char *root="root=";
+++	int i, l;
+++	const char *rootblock;
+++
+++	//ARM doesn't have __HAVE_ARCH_STRSTR, so search manually
+++	ptr = str - 1;
+++
+++	do {
+++		//first find an 'r' at the begining or after a space
+++		do {
+++			ptr++;
+++			ptr = strchr(ptr, 'r');
+++			if (!ptr)
+++				goto no_append;
+++
+++		} while (ptr != str && *(ptr-1) != ' ');
+++
+++		//then check for the rest
+++		for(i = 1; i <= 4; i++)
+++			if(*(ptr+i) != *(root+i)) break;
+++
+++	} while (i != 5);
+++
+++	end = strchr(ptr, ' ');
+++	end = end ? (end - 1) : (strchr(ptr, 0) - 1);
+++
+++	//find partition number (assumes format root=/dev/mtdXX | /dev/mtdblockXX | yy:XX )
+++	for( i = 0; end >= ptr && *end >= '0' && *end <= '9'; end--, i++);
+++	ptr = end + 1;
+++
+++	/* if append-rootblock property is set use it to append to command line */
+++	rootblock = getprop(fdt, "/chosen", "append-rootblock", &l);
+++	if (rootblock == NULL)
+++		goto no_append;
+++
+++	if (*dest != ' ') {
+++		*dest = ' ';
+++		dest++;
+++		len++;
+++	}
+++
+++	if (len + l + i <= COMMAND_LINE_SIZE) {
+++		memcpy(dest, rootblock, l);
+++		dest += l - 1;
+++		memcpy(dest, ptr, i);
+++		dest += i;
+++	}
+++
+++	return dest;
+++
+++no_append:
+++	len = strlen(str);
+++	if (len + 1 < COMMAND_LINE_SIZE) {
+++		memcpy(dest, str, len);
+++		dest += len;
+++	}
+++
+++	return dest;
+++}
+++#endif
+++
++ static void merge_fdt_bootargs(void *fdt, const char *fdt_cmdline)
++ {
++ 	char cmdline[COMMAND_LINE_SIZE];
++@@ -88,12 +156,21 @@ static void merge_fdt_bootargs(void *fdt
++ 
++ 	/* and append the ATAG_CMDLINE */
++ 	if (fdt_cmdline) {
+++
+++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE)
+++		//save original bootloader args
+++		//and append ubi.mtd with root partition number to current cmdline
+++		setprop_string(fdt, "/chosen", "bootloader-args", fdt_cmdline);
+++		ptr = append_rootblock(ptr, fdt_cmdline, len, fdt);
+++
+++#else
++ 		len = strlen(fdt_cmdline);
++ 		if (ptr - cmdline + len + 2 < COMMAND_LINE_SIZE) {
++ 			*ptr++ = ' ';
++ 			memcpy(ptr, fdt_cmdline, len);
++ 			ptr += len;
++ 		}
+++#endif
++ 	}
++ 	*ptr = '\0';
++ 
++@@ -168,7 +245,9 @@ int atags_to_fdt(void *atag_list, void *
++ 			else
++ 				setprop_string(fdt, "/chosen", "bootargs",
++ 					       atag->u.cmdline.cmdline);
++-		} else if (atag->hdr.tag == ATAG_MEM) {
+++		}
+++#ifndef CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE
+++		else if (atag->hdr.tag == ATAG_MEM) {
++ 			if (memcount >= sizeof(mem_reg_property)/4)
++ 				continue;
++ 			if (!atag->u.mem.size)
++@@ -212,6 +291,10 @@ int atags_to_fdt(void *atag_list, void *
++ 		setprop(fdt, "/memory", "reg", mem_reg_property,
++ 			4 * memcount * memsize);
++ 	}
+++#else
+++
+++	}
+++#endif
++ 
++ 	return fdt_pack(fdt);
++ }
++--- a/init/main.c
+++++ b/init/main.c
++@@ -113,6 +113,10 @@
++ 
++ #include <kunit/test.h>
++ 
+++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE)
+++#include <linux/of.h>
+++#endif
+++
++ static int kernel_init(void *);
++ 
++ extern void init_IRQ(void);
++@@ -990,6 +994,18 @@ asmlinkage __visible void __init __no_sa
++ 	page_alloc_init();
++ 
++ 	pr_notice("Kernel command line: %s\n", saved_command_line);
+++
+++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE)
+++	//Show bootloader's original command line for reference
+++	if(of_chosen) {
+++		const char *prop = of_get_property(of_chosen, "bootloader-args", NULL);
+++		if(prop)
+++			pr_notice("Bootloader command line (ignored): %s\n", prop);
+++		else
+++			pr_notice("Bootloader command line not present\n");
+++	}
+++#endif
+++
++ 	/* parameters may set static keys */
++ 	jump_label_init();
++ 	parse_early_param();
+diff --git a/target/linux/mvebu/patches-5.15/301-mvebu-armada-38x-enable-libata-leds.patch b/target/linux/mvebu/patches-5.15/301-mvebu-armada-38x-enable-libata-leds.patch
+new file mode 100644
+index 0000000000..615caac24f
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/301-mvebu-armada-38x-enable-libata-leds.patch
+@@ -0,0 +1,10 @@
++--- a/arch/arm/mach-mvebu/Kconfig
+++++ b/arch/arm/mach-mvebu/Kconfig
++@@ -67,6 +67,7 @@ config MACH_ARMADA_38X
++ 	select HAVE_ARM_TWD if SMP
++ 	select MACH_MVEBU_V7
++ 	select PINCTRL_ARMADA_38X
+++	select ARCH_WANT_LIBATA_LEDS
++ 	help
++ 	  Say 'Y' here if you want your kernel to support boards based
++ 	  on the Marvell Armada 380/385 SoC with device tree.
+diff --git a/target/linux/mvebu/patches-5.15/302-add_powertables.patch b/target/linux/mvebu/patches-5.15/302-add_powertables.patch
+new file mode 100644
+index 0000000000..93ad5de2cc
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/302-add_powertables.patch
+@@ -0,0 +1,770 @@
++--- a/arch/arm/boot/dts/armada-385-linksys.dtsi
+++++ b/arch/arm/boot/dts/armada-385-linksys.dtsi
++@@ -214,11 +214,19 @@
++ &pcie1 {
++ 	/* Marvell 88W8864, 5GHz-only */
++ 	status = "okay";
+++
+++	mwlwifi {
+++		marvell,2ghz = <0>;
+++	};
++ };
++ 
++ &pcie2 {
++ 	/* Marvell 88W8864, 2GHz-only */
++ 	status = "okay";
+++
+++	mwlwifi {
+++		marvell,5ghz = <0>;
+++	};
++ };
++ 
++ &pinctrl {
++--- a/arch/arm/boot/dts/armada-385-linksys-caiman.dts
+++++ b/arch/arm/boot/dts/armada-385-linksys-caiman.dts
++@@ -142,3 +142,205 @@
++ 		};
++ 	};
++ };
+++
+++&pcie1 {
+++	mwlwifi {
+++		marvell,chainmask = <2 2>;
+++		marvell,powertable {
+++			AU =
+++				<36 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<40 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<44 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<48 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<52 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<56 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<60 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<64 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<100 0 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x15 0x17 0x17 0x17 0x14 0x17 0x17 0x17 0x14 0 0xf>,
+++				<104 0 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x15 0x17 0x17 0x17 0x14 0x17 0x17 0x17 0x14 0 0xf>,
+++				<108 0 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x15 0x17 0x17 0x17 0x14 0x17 0x17 0x17 0x14 0 0xf>,
+++				<112 0 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x15 0x17 0x17 0x17 0x14 0x17 0x17 0x17 0x14 0 0xf>,
+++				<116 0 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x15 0x17 0x17 0x17 0x14 0x17 0x17 0x17 0x14 0 0xf>,
+++				<120 0 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x15 0x17 0x17 0x17 0x14 0x17 0x17 0x17 0x14 0 0xf>,
+++				<124 0 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x15 0x17 0x17 0x17 0x14 0x17 0x17 0x17 0x14 0 0xf>,
+++				<128 0 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x15 0x17 0x17 0x17 0x14 0x17 0x17 0x17 0x14 0 0xf>,
+++				<132 0 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x15 0x17 0x17 0x17 0x14 0x17 0x17 0x17 0x14 0 0xf>,
+++				<136 0 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x15 0x17 0x17 0x17 0x14 0x17 0x17 0x17 0x14 0 0xf>,
+++				<140 0 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x15 0x17 0x17 0x17 0x14 0x17 0x17 0x17 0x14 0 0xf>,
+++				<149 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x1a 0x1a 0x17 0x14 0x1a 0x1a 0x17 0x14 0 0xf>,
+++				<153 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x1a 0x1a 0x17 0x14 0x1a 0x1a 0x17 0x14 0 0xf>,
+++				<157 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x1a 0x1a 0x17 0x14 0x1a 0x1a 0x17 0x14 0 0xf>,
+++				<161 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x1a 0x1a 0x17 0x14 0x1a 0x1a 0x17 0x14 0 0xf>,
+++				<165 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x1a 0x1a 0x17 0x14 0x1a 0x1a 0x17 0x14 0 0xf>;
+++			CA =
+++				<36 0 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0 0xf>,
+++				<40 0 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0 0xf>,
+++				<44 0 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0 0xf>,
+++				<48 0 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0 0xf>,
+++				<52 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<56 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<60 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<64 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<100 0 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<104 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<108 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<112 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<116 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<120 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<124 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<128 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<132 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<136 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<140 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<149 0 0x1a 0x1a 0x18 0x17 0x19 0x19 0x17 0x15 0x18 0x18 0x17 0x14 0x15 0x15 0x15 0x14 0 0xf>,
+++				<153 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x1a 0x1a 0x17 0x14 0x15 0x15 0x15 0x14 0 0xf>,
+++				<157 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x1a 0x1a 0x17 0x14 0x15 0x15 0x15 0x14 0 0xf>,
+++				<161 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x1a 0x1a 0x17 0x14 0x15 0x15 0x15 0x14 0 0xf>,
+++				<165 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x1a 0x1a 0x17 0x14 0x15 0x15 0x15 0x14 0 0xf>;
+++			CN =
+++				<36 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<40 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<44 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<48 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<52 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<56 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<60 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<64 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<100 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<104 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<108 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<112 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<116 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<120 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<124 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<128 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<132 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<136 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<140 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<149 0 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0x11 0x11 0x11 0x11 0 0xf>,
+++				<153 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0 0xf>,
+++				<157 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0 0xf>,
+++				<161 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0 0xf>,
+++				<165 0 0x15 0x15 0x15 0x15 0x16 0x16 0x16 0x15 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0 0xf>;
+++			ETSI =
+++				<36 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<40 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<44 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<48 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<52 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<56 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<60 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<64 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<100 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<104 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<108 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<112 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<116 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<120 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<124 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<128 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<132 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<136 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<140 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>,
+++				<149 0 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0 0xf>;
+++			FCC =
+++				<36 0 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<40 0 0x19 0x19 0x18 0x17 0x19 0x19 0x17 0x15 0x17 0x17 0x17 0x14 0x10 0x10 0x10 0x10 0 0xf>,
+++				<44 0 0x19 0x19 0x18 0x17 0x19 0x19 0x17 0x15 0x17 0x17 0x17 0x14 0x10 0x10 0x10 0x10 0 0xf>,
+++				<48 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x17 0x17 0x17 0x14 0x10 0x10 0x10 0x10 0 0xf>,
+++				<52 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<56 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<60 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<64 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<100 0 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<104 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<108 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<112 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<116 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<120 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<124 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<128 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<132 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<136 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<140 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<149 0 0x1a 0x1a 0x18 0x17 0x19 0x19 0x17 0x15 0x18 0x18 0x17 0x14 0x15 0x15 0x15 0x14 0 0xf>,
+++				<153 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x1a 0x1a 0x17 0x14 0x15 0x15 0x15 0x14 0 0xf>,
+++				<157 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x1a 0x1a 0x17 0x14 0x15 0x15 0x15 0x14 0 0xf>,
+++				<161 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x1a 0x1a 0x17 0x14 0x15 0x15 0x15 0x14 0 0xf>,
+++				<165 0 0x1a 0x1a 0x18 0x17 0x1a 0x1a 0x17 0x15 0x1a 0x1a 0x17 0x14 0x15 0x15 0x15 0x14 0 0xf>;
+++		};
+++	};
+++};
+++
+++&pcie2 {
+++	mwlwifi {
+++		marvell,chainmask = <2 2>;
+++		marvell,powertable {
+++			AU =
+++				<1 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<2 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<3 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<4 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<5 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<6 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<7 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<8 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<9 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<10 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<11 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>;
+++			CA =
+++				<1 0 0x19 0x14 0x14 0x14 0x13 0x13 0x13 0x13 0x10 0x10 0x10 0x10 0x00 0x00 0x00 0x00 0 0xf>,
+++				<2 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x00 0x00 0x00 0x00 0 0xf>,
+++				<3 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x00 0x00 0x00 0x00 0 0xf>,
+++				<4 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x00 0x00 0x00 0x00 0 0xf>,
+++				<5 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x00 0x00 0x00 0x00 0 0xf>,
+++				<6 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x00 0x00 0x00 0x00 0 0xf>,
+++				<7 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x00 0x00 0x00 0x00 0 0xf>,
+++				<8 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x00 0x00 0x00 0x00 0 0xf>,
+++				<9 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x00 0x00 0x00 0x00 0 0xf>,
+++				<10 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x00 0x00 0x00 0x00 0 0xf>,
+++				<11 0 0x19 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0x13 0x13 0x13 0x13 0x00 0x00 0x00 0x00 0 0xf>;
+++			CN =
+++				<1 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<2 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<3 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<4 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<5 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<6 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<7 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<8 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<9 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<10 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<11 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<12 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<13 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<14 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>;
+++			ETSI =
+++				<1 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<2 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<3 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<4 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<5 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<6 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<7 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<8 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<9 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<10 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<11 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<12 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>,
+++				<13 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0x0 0x0 0x0 0x0 0 0xf>;
+++			FCC =
+++				<1 0 0x19 0x14 0x14 0x14 0x13 0x13 0x13 0x13 0x10 0x10 0x10 0x10 0x0 0x0 0x0 0x0 0 0xf>,
+++				<2 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x0 0x0 0x0 0x0 0 0xf>,
+++				<3 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x0 0x0 0x0 0x0 0 0xf>,
+++				<4 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x0 0x0 0x0 0x0 0 0xf>,
+++				<5 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x0 0x0 0x0 0x0 0 0xf>,
+++				<6 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x0 0x0 0x0 0x0 0 0xf>,
+++				<7 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x0 0x0 0x0 0x0 0 0xf>,
+++				<8 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x0 0x0 0x0 0x0 0 0xf>,
+++				<9 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x0 0x0 0x0 0x0 0 0xf>,
+++				<10 0 0x1a 0x19 0x18 0x17 0x19 0x19 0x17 0x16 0x14 0x14 0x14 0x14 0x0 0x0 0x0 0x0 0 0xf>,
+++				<11 0 0x19 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0x13 0x13 0x13 0x13 0x0 0x0 0x0 0x0 0 0xf>;
+++		};
+++	};
+++};
++--- a/arch/arm/boot/dts/armada-385-linksys-cobra.dts
+++++ b/arch/arm/boot/dts/armada-385-linksys-cobra.dts
++@@ -142,3 +142,205 @@
++ 		};
++ 	};
++ };
+++
+++&pcie1 {
+++	mwlwifi {
+++		marvell,chainmask = <4 4>;
+++		marvell,powertable {
+++			AU =
+++				<36 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<40 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<44 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<48 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<52 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<56 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<60 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<64 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<100 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++				<104 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++				<108 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++				<112 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++				<116 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++				<120 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++				<124 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++				<128 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++				<132 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++				<136 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++				<140 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++				<149 0 0x19 0x19 0x19 0x17 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0 0xf>,
+++				<153 0 0x19 0x19 0x19 0x17 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0 0xf>,
+++				<157 0 0x19 0x19 0x19 0x17 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0 0xf>,
+++				<161 0 0x19 0x19 0x19 0x17 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0 0xf>,
+++				<165 0 0x19 0x19 0x19 0x17 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0 0xf>;
+++			CA =
+++				<36 0 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0 0xf>,
+++				<40 0 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0 0xf>,
+++				<44 0 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0 0xf>,
+++				<48 0 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0 0xf>,
+++				<52 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<56 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<60 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<64 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<100 0 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<104 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<108 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<112 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<116 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<120 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<124 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<128 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<132 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<136 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<140 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<149 0 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
+++				<153 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
+++				<157 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
+++				<161 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
+++				<165 0 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>;
+++			CN =
+++				<36 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<40 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<44 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<48 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<52 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<56 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<60 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<64 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<100 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<104 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<108 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<112 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<116 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<120 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<124 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<128 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<132 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<136 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<140 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<149 0 0x14 0x14 0x14 0x14 0x13 0x13 0x13 0x13 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<153 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0x10 0x10 0x10 0x10 0 0xf>,
+++				<157 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0x10 0x10 0x10 0x10 0 0xf>,
+++				<161 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0x10 0x10 0x10 0x10 0 0xf>,
+++				<165 0 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x14 0x14 0x14 0x14 0x10 0x10 0x10 0x10 0 0xf>;
+++			ETSI =
+++				<36 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<40 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<44 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<48 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<52 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<56 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<60 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<64 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<100 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<104 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<108 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<112 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<116 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<120 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<124 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<128 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<132 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<136 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<140 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<149 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>;
+++			FCC =
+++				<36 0 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0xf 0xf 0xf 0xf 0 0xf>,
+++				<40 0 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0xf 0xf 0xf 0xf 0 0xf>,
+++				<44 0 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0xf 0xf 0xf 0xf 0 0xf>,
+++				<48 0 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0xf 0xf 0xf 0xf 0 0xf>,
+++				<52 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<56 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<60 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<64 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<100 0 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<104 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<108 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<112 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<116 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<120 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<124 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<128 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<132 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<136 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<140 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<149 0 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
+++				<153 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
+++				<157 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
+++				<161 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
+++				<165 0 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>;
+++		};
+++	};
+++};
+++
+++&pcie2 {
+++	mwlwifi {
+++		marvell,chainmask = <4 4>;
+++		marvell,powertable {
+++			AU =
+++				<1 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<2 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<3 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<4 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<5 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<6 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<7 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<8 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<9 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<10 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<11 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>;
+++			CA =
+++				<1 0 0x17 0x10 0x10 0x10 0xf 0xf 0xf 0xf 0xe 0xe 0xe 0xe 0x0 0x0 0x0 0x0 0 0xf>,
+++				<2 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<3 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<4 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<5 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<6 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<7 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<8 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<9 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<10 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<11 0 0x17 0x12 0x12 0x12 0x13 0x13 0x13 0x13 0xf 0xf 0xf 0xf 0x0 0x0 0x0 0x0 0 0xf>;
+++			CN =
+++				<1 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<2 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<3 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<4 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<5 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<6 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<7 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<8 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<9 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<10 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<11 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<12 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<13 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<14 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>;
+++			ETSI =
+++				<1 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<2 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<3 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<4 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<5 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<6 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<7 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<8 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<9 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<10 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<11 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<12 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<13 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>;
+++			FCC =
+++				<1 0 0x17 0x10 0x10 0x10 0xf 0xf 0xf 0xf 0xe 0xe 0xe 0xe 0x0 0x0 0x0 0x0 0 0xf>,
+++				<2 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<3 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<4 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<5 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<6 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<7 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<8 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<9 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<10 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<11 0 0x17 0x12 0x12 0x12 0x13 0x13 0x13 0x13 0xf 0xf 0xf 0xf 0x0 0x0 0x0 0x0 0 0xf>;
+++		};
+++	};
+++};
++--- a/arch/arm/boot/dts/armada-385-linksys-shelby.dts
+++++ b/arch/arm/boot/dts/armada-385-linksys-shelby.dts
++@@ -142,3 +142,205 @@
++ 		};
++ 	};
++ };
+++
+++&pcie1 {
+++	mwlwifi {
+++		marvell,chainmask = <4 4>;
+++		marvell,powertable {
+++			AU =
+++				<36 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<40 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<44 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<48 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<52 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<56 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<60 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<64 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<100 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++				<104 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++				<108 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++				<112 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++				<116 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++				<120 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++				<124 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++				<128 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++				<132 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++				<136 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++				<140 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++				<149 0 0x19 0x19 0x19 0x17 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0 0xf>,
+++				<153 0 0x19 0x19 0x19 0x17 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0 0xf>,
+++				<157 0 0x19 0x19 0x19 0x17 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0 0xf>,
+++				<161 0 0x19 0x19 0x19 0x17 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0 0xf>,
+++				<165 0 0x19 0x19 0x19 0x17 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0x19 0x19 0x16 0x15 0 0xf>;
+++			CA =
+++				<36 0 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0 0xf>,
+++				<40 0 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0 0xf>,
+++				<44 0 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0 0xf>,
+++				<48 0 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0 0xf>,
+++				<52 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<56 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<60 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<64 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<100 0 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<104 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<108 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<112 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<116 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<120 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<124 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<128 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<132 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<136 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<140 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<149 0 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
+++				<153 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
+++				<157 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
+++				<161 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
+++				<165 0 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>;
+++			CN =
+++				<36 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<40 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<44 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<48 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<52 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<56 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<60 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<64 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<100 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<104 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<108 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<112 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<116 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<120 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<124 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<128 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<132 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<136 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<140 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<149 0 0x14 0x14 0x14 0x14 0x13 0x13 0x13 0x13 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<153 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0x10 0x10 0x10 0x10 0 0xf>,
+++				<157 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0x10 0x10 0x10 0x10 0 0xf>,
+++				<161 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0x10 0x10 0x10 0x10 0 0xf>,
+++				<165 0 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x14 0x14 0x14 0x14 0x10 0x10 0x10 0x10 0 0xf>;
+++			ETSI =
+++				<36 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<40 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<44 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<48 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<52 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<56 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<60 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<64 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<100 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<104 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<108 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<112 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<116 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<120 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<124 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<128 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<132 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<136 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<140 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>,
+++				<149 0 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xd 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0xe 0 0xf>;
+++			FCC =
+++				<36 0 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0xf 0xf 0xf 0xf 0 0xf>,
+++				<40 0 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0xf 0xf 0xf 0xf 0 0xf>,
+++				<44 0 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0xf 0xf 0xf 0xf 0 0xf>,
+++				<48 0 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0xf 0xf 0xf 0xf 0 0xf>,
+++				<52 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<56 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<60 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<64 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<100 0 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<104 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x12 0x12 0x12 0x12 0x10 0x10 0x10 0x10 0 0xf>,
+++				<108 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<112 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<116 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<120 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<124 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<128 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<132 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<136 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<140 0 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0 0xf>,
+++				<149 0 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
+++				<153 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
+++				<157 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
+++				<161 0 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>,
+++				<165 0 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0 0xf>;
+++		};
+++	};
+++};
+++
+++&pcie2 {
+++	mwlwifi {
+++		marvell,chainmask = <4 4>;
+++		marvell,powertable {
+++			AU =
+++				<1 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<2 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<3 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<4 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<5 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<6 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<7 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<8 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<9 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<10 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<11 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>;
+++			CA =
+++				<1 0 0x17 0x10 0x10 0x10 0xf 0xf 0xf 0xf 0xe 0xe 0xe 0xe 0x0 0x0 0x0 0x0 0 0xf>,
+++				<2 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<3 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<4 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<5 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<6 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<7 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<8 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<9 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<10 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<11 0 0x17 0x12 0x12 0x12 0x13 0x13 0x13 0x13 0xf 0xf 0xf 0xf 0x0 0x0 0x0 0x0 0 0xf>;
+++			CN =
+++				<1 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<2 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<3 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<4 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<5 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<6 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<7 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<8 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<9 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<10 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<11 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<12 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<13 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<14 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>;
+++			ETSI =
+++				<1 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<2 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<3 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<4 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<5 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<6 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<7 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<8 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<9 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<10 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<11 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<12 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>,
+++				<13 0 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0xa 0x0 0x0 0x0 0x0 0 0xf>;
+++			FCC =
+++				<1 0 0x17 0x10 0x10 0x10 0xf 0xf 0xf 0xf 0xe 0xe 0xe 0xe 0x0 0x0 0x0 0x0 0 0xf>,
+++				<2 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<3 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<4 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<5 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<6 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<7 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<8 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<9 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<10 0 0x18 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x11 0x11 0x11 0x11 0x0 0x0 0x0 0x0 0 0xf>,
+++				<11 0 0x17 0x12 0x12 0x12 0x13 0x13 0x13 0x13 0xf 0xf 0xf 0xf 0x0 0x0 0x0 0x0 0 0xf>;
+++		};
+++	};
+++};
++--- a/arch/arm/boot/dts/armada-385-linksys-rango.dts
+++++ b/arch/arm/boot/dts/armada-385-linksys-rango.dts
++@@ -157,6 +157,18 @@
++ 	};
++ };
++ 
+++&pcie1 {
+++	mwlwifi {
+++		marvell,chainmask = <4 4>;
+++	};
+++};
+++
+++&pcie2 {
+++	mwlwifi {
+++		marvell,chainmask = <4 4>;
+++	};
+++};
+++
++ &sdhci {
++ 	pinctrl-names = "default";
++ 	pinctrl-0 = <&sdhci_pins>;
++--- a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
+++++ b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
++@@ -225,12 +225,100 @@
++ 	pcie@2,0 {
++ 		/* Port 0, Lane 1 */
++ 		status = "okay";
+++
+++		mwlwifi {
+++			marvell,5ghz = <0>;
+++			marvell,chainmask = <4 4>;
+++			marvell,powertable {
+++				FCC =
+++					<1 0 0x17 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0xf 0xf 0xf 0xf 0x0 0x0 0x0 0x0 0 0xf>,
+++					<2 0 0x17 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x10 0x10 0x10 0x10 0x0 0x0 0x0 0x0 0 0xf>,
+++					<3 0 0x17 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x10 0x10 0x10 0x10 0x0 0x0 0x0 0x0 0 0xf>,
+++					<4 0 0x17 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x10 0x10 0x10 0x10 0x0 0x0 0x0 0x0 0 0xf>,
+++					<5 0 0x17 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x10 0x10 0x10 0x10 0x0 0x0 0x0 0x0 0 0xf>,
+++					<6 0 0x17 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x10 0x10 0x10 0x10 0x0 0x0 0x0 0x0 0 0xf>,
+++					<7 0 0x17 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x10 0x10 0x10 0x10 0x0 0x0 0x0 0x0 0 0xf>,
+++					<8 0 0x17 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x10 0x10 0x10 0x10 0x0 0x0 0x0 0x0 0 0xf>,
+++					<9 0 0x17 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x10 0x10 0x10 0x10 0x0 0x0 0x0 0x0 0 0xf>,
+++					<10 0 0x17 0x16 0x16 0x16 0x16 0x16 0x16 0x14 0x10 0x10 0x10 0x10 0x0 0x0 0x0 0x0 0 0xf>,
+++					<11 0 0x17 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x10 0x10 0x10 0x10 0x0 0x0 0x0 0x0 0 0xf>;
+++
+++				ETSI =
+++					<1 0 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0x0 0x0 0x0 0x0 0 0xf>,
+++					<2 0 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0x0 0x0 0x0 0x0 0 0xf>,
+++					<3 0 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0x0 0x0 0x0 0x0 0 0xf>,
+++					<4 0 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0x0 0x0 0x0 0x0 0 0xf>,
+++					<5 0 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0x0 0x0 0x0 0x0 0 0xf>,
+++					<6 0 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0x0 0x0 0x0 0x0 0 0xf>,
+++					<7 0 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0x0 0x0 0x0 0x0 0 0xf>,
+++					<8 0 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0x0 0x0 0x0 0x0 0 0xf>,
+++					<9 0 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0x0 0x0 0x0 0x0 0 0xf>,
+++					<10 0 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0x0 0x0 0x0 0x0 0 0xf>,
+++					<11 0 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0x0 0x0 0x0 0x0 0 0xf>,
+++					<12 0 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0x0 0x0 0x0 0x0 0 0xf>,
+++					<13 0 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0xb 0x0 0x0 0x0 0x0 0 0xf>;
+++			};
+++		};
++ 	};
++ 
++ 	/* Second mini-PCIe port */
++ 	pcie@3,0 {
++ 		/* Port 0, Lane 3 */
++ 		status = "okay";
+++
+++		mwlwifi {
+++			marvell,2ghz = <0>;
+++			marvell,chainmask = <4 4>;
+++			marvell,powertable {
+++				FCC =
+++					<36 0 0x8 0x8 0x8 0x8 0x8 0x8 0x8 0x8 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0 0xf>,
+++					<40 0 0x8 0x8 0x8 0x8 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0 0xf>,
+++					<44 0 0x8 0x8 0x8 0x8 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0 0xf>,
+++					<48 0 0x8 0x8 0x8 0x8 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0x9 0 0xf>,
+++					<52 0 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0 0xf>,
+++					<56 0 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0 0xf>,
+++					<60 0 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0 0xf>,
+++					<64 0 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0xf 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0 0xf>,
+++					<100 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++					<104 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++					<108 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++					<112 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++					<116 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++					<120 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++					<124 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++					<128 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++					<132 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++					<136 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++					<140 0 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0 0xf>,
+++					<149 0 0x16 0x16 0x16 0x16 0x14 0x14 0x14 0x14 0x15 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0 0xf>,
+++					<153 0 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0 0xf>,
+++					<157 0 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0 0xf>,
+++					<161 0 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0 0xf>,
+++					<165 0 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x15 0x15 0x15 0x15 0x14 0x14 0x14 0x14 0 0xf>;
+++
+++				ETSI =
+++					<36 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
+++					<40 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
+++					<44 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
+++					<48 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
+++					<52 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
+++					<56 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
+++					<60 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
+++					<64 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
+++					<100 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
+++					<104 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
+++					<108 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
+++					<112 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
+++					<116 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
+++					<120 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
+++					<124 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
+++					<128 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
+++					<132 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
+++					<136 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
+++					<140 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>,
+++					<149 0 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xd 0xd 0xd 0xd 0xc 0xc 0xc 0xc 0 0xf>;
+++			};
+++		};
++ 	};
++ };
++ 
+diff --git a/target/linux/mvebu/patches-5.15/304-revert_i2c_delay.patch b/target/linux/mvebu/patches-5.15/304-revert_i2c_delay.patch
+new file mode 100644
+index 0000000000..930c0f9494
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/304-revert_i2c_delay.patch
+@@ -0,0 +1,15 @@
++--- a/arch/arm/boot/dts/armada-xp.dtsi
+++++ b/arch/arm/boot/dts/armada-xp.dtsi
++@@ -237,12 +237,10 @@
++ };
++ 
++ &i2c0 {
++-	compatible = "marvell,mv78230-i2c", "marvell,mv64xxx-i2c";
++ 	reg = <0x11000 0x100>;
++ };
++ 
++ &i2c1 {
++-	compatible = "marvell,mv78230-i2c", "marvell,mv64xxx-i2c";
++ 	reg = <0x11100 0x100>;
++ };
++ 
+diff --git a/target/linux/mvebu/patches-5.15/305-armada-385-rd-mtd-partitions.patch b/target/linux/mvebu/patches-5.15/305-armada-385-rd-mtd-partitions.patch
+new file mode 100644
+index 0000000000..31bd53b1f3
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/305-armada-385-rd-mtd-partitions.patch
+@@ -0,0 +1,19 @@
++--- a/arch/arm/boot/dts/armada-388-rd.dts
+++++ b/arch/arm/boot/dts/armada-388-rd.dts
++@@ -103,6 +103,16 @@
++ 		compatible = "st,m25p128", "jedec,spi-nor";
++ 		reg = <0>; /* Chip select 0 */
++ 		spi-max-frequency = <108000000>;
+++
+++		partition@0 {
+++			label = "uboot";
+++			reg = <0 0x400000>;
+++		};
+++
+++		partition@1 {
+++			label = "firmware";
+++			reg = <0x400000 0xc00000>;
+++		};
++ 	};
++ };
++ 
+diff --git a/target/linux/mvebu/patches-5.15/306-ARM-mvebu-385-ap-Add-partitions.patch b/target/linux/mvebu/patches-5.15/306-ARM-mvebu-385-ap-Add-partitions.patch
+new file mode 100644
+index 0000000000..2057e31c7e
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/306-ARM-mvebu-385-ap-Add-partitions.patch
+@@ -0,0 +1,35 @@
++From 9861f93a59142a3131870df2521eb2deb73026d7 Mon Sep 17 00:00:00 2001
++From: Maxime Ripard <maxime.ripard@free-electrons.com>
++Date: Tue, 13 Jan 2015 11:14:09 +0100
++Subject: [PATCH 2/2] ARM: mvebu: 385-ap: Add partitions
++
++Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
++---
++ arch/arm/boot/dts/armada-385-db-ap.dts | 15 +++++++++++++++
++ 1 file changed, 15 insertions(+)
++
++--- a/arch/arm/boot/dts/armada-385-db-ap.dts
+++++ b/arch/arm/boot/dts/armada-385-db-ap.dts
++@@ -218,19 +218,19 @@
++ 			#size-cells = <1>;
++ 
++ 			partition@0 {
++-				label = "U-Boot";
+++				label = "u-boot";
++ 				reg = <0x00000000 0x00800000>;
++ 				read-only;
++ 			};
++ 
++ 			partition@800000 {
++-				label = "uImage";
+++				label = "kernel";
++ 				reg = <0x00800000 0x00400000>;
++ 				read-only;
++ 			};
++ 
++ 			partition@c00000 {
++-				label = "Root";
+++				label = "ubi";
++ 				reg = <0x00c00000 0x3f400000>;
++ 			};
++ 		};
+diff --git a/target/linux/mvebu/patches-5.15/307-armada-xp-linksys-mamba-broken-idle.patch b/target/linux/mvebu/patches-5.15/307-armada-xp-linksys-mamba-broken-idle.patch
+new file mode 100644
+index 0000000000..16112d53fc
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/307-armada-xp-linksys-mamba-broken-idle.patch
+@@ -0,0 +1,10 @@
++--- a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
+++++ b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
++@@ -485,3 +485,7 @@
++ 		};
++ 	};
++ };
+++
+++&coherencyfab {
+++	broken-idle;
+++};
+diff --git a/target/linux/mvebu/patches-5.15/308-armada-xp-linksys-mamba-wan.patch b/target/linux/mvebu/patches-5.15/308-armada-xp-linksys-mamba-wan.patch
+new file mode 100644
+index 0000000000..4315abc7d2
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/308-armada-xp-linksys-mamba-wan.patch
+@@ -0,0 +1,11 @@
++--- a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
+++++ b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
++@@ -387,7 +387,7 @@
++ 
++ 			port@4 {
++ 				reg = <4>;
++-				label = "internet";
+++				label = "wan";
++ 			};
++ 
++ 			port@5 {
+diff --git a/target/linux/mvebu/patches-5.15/309-linksys-status-led.patch b/target/linux/mvebu/patches-5.15/309-linksys-status-led.patch
+new file mode 100644
+index 0000000000..e5e83572c9
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/309-linksys-status-led.patch
+@@ -0,0 +1,50 @@
++--- a/arch/arm/boot/dts/armada-385-linksys.dtsi
+++++ b/arch/arm/boot/dts/armada-385-linksys.dtsi
++@@ -14,6 +14,13 @@
++ 	compatible = "linksys,armada385", "marvell,armada385",
++ 		     "marvell,armada380";
++ 
+++	aliases {
+++		led-boot = &led_power;
+++		led-failsafe = &led_power;
+++		led-running = &led_power;
+++		led-upgrade = &led_power;
+++	};
+++
++ 	chosen {
++ 		stdout-path = "serial0:115200n8";
++ 	};
++@@ -71,7 +78,7 @@
++ 		pinctrl-0 = <&gpio_leds_pins>;
++ 		pinctrl-names = "default";
++ 
++-		power {
+++		led_power: power {
++ 			gpios = <&gpio1 23 GPIO_ACTIVE_HIGH>;
++ 			default-state = "on";
++ 		};
++--- a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
+++++ b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
++@@ -26,6 +26,13 @@
++ 	compatible = "linksys,mamba", "marvell,armadaxp-mv78230",
++ 		     "marvell,armadaxp", "marvell,armada-370-xp";
++ 
+++	aliases {
+++		led-boot = &led_power;
+++		led-failsafe = &led_power;
+++		led-running = &led_power;
+++		led-upgrade = &led_power;
+++	};
+++
++ 	chosen {
++ 		bootargs = "console=ttyS0,115200";
++ 		stdout-path = &uart0;
++@@ -197,7 +204,7 @@
++ 		pinctrl-0 = <&power_led_pin>;
++ 		pinctrl-names = "default";
++ 
++-		power {
+++		led_power: power {
++ 			label = "mamba:white:power";
++ 			gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>;
++ 			default-state = "on";
+diff --git a/target/linux/mvebu/patches-5.15/310-linksys-use-eth0-as-cpu-port.patch b/target/linux/mvebu/patches-5.15/310-linksys-use-eth0-as-cpu-port.patch
+new file mode 100644
+index 0000000000..84d49a004b
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/310-linksys-use-eth0-as-cpu-port.patch
+@@ -0,0 +1,25 @@
++--- a/arch/arm/boot/dts/armada-385-linksys.dtsi
+++++ b/arch/arm/boot/dts/armada-385-linksys.dtsi
++@@ -116,7 +116,7 @@
++ };
++ 
++ &eth2 {
++-	status = "okay";
+++	status = "disabled";
++ 	phy-mode = "sgmii";
++ 	buffer-manager = <&bm>;
++ 	bm,pool-long = <2>;
++@@ -200,10 +200,10 @@
++ 				label = "wan";
++ 			};
++ 
++-			port@5 {
++-				reg = <5>;
+++			port@6 {
+++				reg = <6>;
++ 				label = "cpu";
++-				ethernet = <&eth2>;
+++				ethernet = <&eth0>;
++ 
++ 				fixed-link {
++ 					speed = <1000>;
+diff --git a/target/linux/mvebu/patches-5.15/311-adjust-compatible-for-linksys.patch b/target/linux/mvebu/patches-5.15/311-adjust-compatible-for-linksys.patch
+new file mode 100644
+index 0000000000..a5d3e63810
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/311-adjust-compatible-for-linksys.patch
+@@ -0,0 +1,68 @@
++--- a/arch/arm/boot/dts/armada-385-linksys-rango.dts
+++++ b/arch/arm/boot/dts/armada-385-linksys-rango.dts
++@@ -12,8 +12,8 @@
++ 
++ / {
++ 	model = "Linksys WRT3200ACM";
++-	compatible = "linksys,rango", "linksys,armada385", "marvell,armada385",
++-		     "marvell,armada380";
+++	compatible = "linksys,wrt3200acm", "linksys,rango", "linksys,armada385",
+++		     "marvell,armada385", "marvell,armada380";
++ };
++ 
++ &expander0 {
++--- a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
+++++ b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
++@@ -22,9 +22,10 @@
++ #include "armada-xp-mv78230.dtsi"
++ 
++ / {
++-	model = "Linksys WRT1900AC";
++-	compatible = "linksys,mamba", "marvell,armadaxp-mv78230",
++-		     "marvell,armadaxp", "marvell,armada-370-xp";
+++	model = "Linksys WRT1900AC v1";
+++	compatible = "linksys,wrt1900ac-v1", "linksys,mamba",
+++		     "marvell,armadaxp-mv78230", "marvell,armadaxp",
+++		     "marvell,armada-370-xp";
++ 
++ 	aliases {
++ 		led-boot = &led_power;
++--- a/arch/arm/boot/dts/armada-385-linksys-cobra.dts
+++++ b/arch/arm/boot/dts/armada-385-linksys-cobra.dts
++@@ -9,8 +9,9 @@
++ #include "armada-385-linksys.dtsi"
++ 
++ / {
++-	model = "Linksys WRT1900ACv2";
++-	compatible = "linksys,cobra", "linksys,armada385", "marvell,armada385",
+++	model = "Linksys WRT1900AC v2";
+++	compatible = "linksys,wrt1900ac-v2", "linksys,cobra",
+++		     "linksys,armada385", "marvell,armada385",
++ 		     "marvell,armada380";
++ };
++ 
++--- a/arch/arm/boot/dts/armada-385-linksys-caiman.dts
+++++ b/arch/arm/boot/dts/armada-385-linksys-caiman.dts
++@@ -10,8 +10,8 @@
++ 
++ / {
++ 	model = "Linksys WRT1200AC";
++-	compatible = "linksys,caiman", "linksys,armada385", "marvell,armada385",
++-		     "marvell,armada380";
+++	compatible = "linksys,wrt1200ac", "linksys,caiman", "linksys,armada385",
+++		     "marvell,armada385", "marvell,armada380";
++ };
++ 
++ &expander0 {
++--- a/arch/arm/boot/dts/armada-385-linksys-shelby.dts
+++++ b/arch/arm/boot/dts/armada-385-linksys-shelby.dts
++@@ -10,7 +10,8 @@
++ 
++ / {
++ 	model = "Linksys WRT1900ACS";
++-	compatible = "linksys,shelby", "linksys,armada385", "marvell,armada385",
+++	compatible = "linksys,wrt1900acs", "linksys,shelby",
+++		     "linksys,armada385", "marvell,armada385",
++ 		     "marvell,armada380";
++ };
++ 
+diff --git a/target/linux/mvebu/patches-5.15/312-ARM-dts-armada388-clearfog-emmc-on-clearfog-base.patch b/target/linux/mvebu/patches-5.15/312-ARM-dts-armada388-clearfog-emmc-on-clearfog-base.patch
+new file mode 100644
+index 0000000000..dd2bef7f63
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/312-ARM-dts-armada388-clearfog-emmc-on-clearfog-base.patch
+@@ -0,0 +1,87 @@
++From 8137da20701c776ad3481115305a5e8e410871ba Mon Sep 17 00:00:00 2001
++From: Russell King <rmk+kernel@armlinux.org.uk>
++Date: Tue, 29 Nov 2016 10:15:45 +0000
++Subject: ARM: dts: armada388-clearfog: emmc on clearfog base
++
++Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
++---
++ arch/arm/boot/dts/armada-388-clearfog-base.dts     |  1 +
++ .../dts/armada-38x-solidrun-microsom-emmc.dtsi     | 62 ++++++++++++++++++++++
++ 2 files changed, 63 insertions(+)
++ create mode 100644 arch/arm/boot/dts/armada-38x-solidrun-microsom-emmc.dtsi
++
++--- a/arch/arm/boot/dts/armada-388-clearfog-base.dts
+++++ b/arch/arm/boot/dts/armada-388-clearfog-base.dts
++@@ -7,6 +7,7 @@
++ 
++ /dts-v1/;
++ #include "armada-388-clearfog.dtsi"
+++#include "armada-38x-solidrun-microsom-emmc.dtsi"
++ 
++ / {
++ 	model = "SolidRun Clearfog Base A1";
++--- /dev/null
+++++ b/arch/arm/boot/dts/armada-38x-solidrun-microsom-emmc.dtsi
++@@ -0,0 +1,62 @@
+++/*
+++ * Device Tree file for SolidRun Armada 38x Microsom add-on for eMMC
+++ *
+++ *  Copyright (C) 2015 Russell King
+++ *
+++ * This board is in development; the contents of this file work with
+++ * the A1 rev 2.0 of the board, which does not represent final
+++ * production board.  Things will change, don't expect this file to
+++ * remain compatible info the future.
+++ *
+++ * This file is dual-licensed: you can use it either under the terms
+++ * of the GPL or the X11 license, at your option. Note that this dual
+++ * licensing only applies to this file, and not this project as a
+++ * whole.
+++ *
+++ *  a) This file is free software; you can redistribute it and/or
+++ *     modify it under the terms of the GNU General Public License
+++ *     version 2 as published by the Free Software Foundation.
+++ *
+++ *     This file is distributed in the hope that it will be useful
+++ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+++ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+++ *     GNU General Public License for more details.
+++ *
+++ * Or, alternatively
+++ *
+++ *  b) Permission is hereby granted, free of charge, to any person
+++ *     obtaining a copy of this software and associated documentation
+++ *     files (the "Software"), to deal in the Software without
+++ *     restriction, including without limitation the rights to use
+++ *     copy, modify, merge, publish, distribute, sublicense, and/or
+++ *     sell copies of the Software, and to permit persons to whom the
+++ *     Software is furnished to do so, subject to the following
+++ *     conditions:
+++ *
+++ *     The above copyright notice and this permission notice shall be
+++ *     included in all copies or substantial portions of the Software.
+++ *
+++ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+++ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+++ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+++ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+++ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+++ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+++ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+++ *     OTHER DEALINGS IN THE SOFTWARE.
+++ */
+++/ {
+++	soc {
+++		internal-regs {
+++			sdhci@d8000 {
+++				bus-width = <4>;
+++				no-1-8-v;
+++				non-removable;
+++				pinctrl-0 = <&microsom_sdhci_pins>;
+++				pinctrl-names = "default";
+++				status = "okay";
+++				wp-inverted;
+++			};
+++		};
+++	};
+++};
+diff --git a/target/linux/mvebu/patches-5.15/313-helios4-dts-status-led-alias.patch b/target/linux/mvebu/patches-5.15/313-helios4-dts-status-led-alias.patch
+new file mode 100644
+index 0000000000..607f436297
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/313-helios4-dts-status-led-alias.patch
+@@ -0,0 +1,28 @@
++--- a/arch/arm/boot/dts/armada-388-helios4.dts
+++++ b/arch/arm/boot/dts/armada-388-helios4.dts
++@@ -15,6 +15,13 @@
++ 	model = "Helios4";
++ 	compatible = "kobol,helios4", "marvell,armada388",
++ 		"marvell,armada385", "marvell,armada380";
+++		
+++	aliases {
+++		led-boot = &led_status;
+++		led-failsafe = &led_status;
+++		led-running = &led_status;
+++		led-upgrade = &led_status;
+++	};
++ 
++ 	memory {
++ 		device_type = "memory";
++@@ -73,10 +80,9 @@
++ 		pinctrl-names = "default";
++ 		pinctrl-0 = <&helios_system_led_pins>;
++ 
++-		status-led {
+++		led_status: status-led {
++ 			label = "helios4:green:status";
++ 			gpios = <&gpio0 24 GPIO_ACTIVE_LOW>;
++-			linux,default-trigger = "heartbeat";
++ 			default-state = "on";
++ 		};
++ 
+diff --git a/target/linux/mvebu/patches-5.15/315-armada-xp-linksys-mamba-resize-kernel.patch b/target/linux/mvebu/patches-5.15/315-armada-xp-linksys-mamba-resize-kernel.patch
+new file mode 100644
+index 0000000000..f1fddceff4
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/315-armada-xp-linksys-mamba-resize-kernel.patch
+@@ -0,0 +1,37 @@
++From 258233f00bcd013050efee00c5d9128ef8cd62dd Mon Sep 17 00:00:00 2001
++From: Tad <tad@spotco.us>
++Date: Fri, 5 Feb 2021 22:32:11 -0500
++Subject: [PATCH] ARM: dts: armada-xp-linksys-mamba: Increase kernel
++ partition to 4MB
++
++Signed-off-by: Tad Davanzo <tad@spotco.us>
++---
++ arch/arm/boot/dts/armada-xp-linksys-mamba.dts | 8 ++++----
++ 1 file changed, 4 insertions(+), 4 deletions(-)
++
++--- a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
+++++ b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
++@@ -456,9 +456,9 @@
++ 				reg = <0xa00000 0x2800000>;  /* 40MB */
++ 			};
++ 
++-			partition@d00000 {
+++			partition@e00000 {
++ 				label = "rootfs1";
++-				reg = <0xd00000 0x2500000>;  /* 37MB */
+++				reg = <0xe00000 0x2400000>;  /* 36MB */
++ 			};
++ 
++ 			/* kernel2 overlaps with rootfs2 by design */
++@@ -467,9 +467,9 @@
++ 				reg = <0x3200000 0x2800000>; /* 40MB */
++ 			};
++ 
++-			partition@3500000 {
+++			partition@3600000 {
++ 				label = "rootfs2";
++-				reg = <0x3500000 0x2500000>; /* 37MB */
+++				reg = <0x3600000 0x2400000>; /* 36MB */
++ 			};
++ 
++ 			/*
+diff --git a/target/linux/mvebu/patches-5.15/316-armada-370-dts-fix-crypto-engine.patch b/target/linux/mvebu/patches-5.15/316-armada-370-dts-fix-crypto-engine.patch
+new file mode 100644
+index 0000000000..19378870ef
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/316-armada-370-dts-fix-crypto-engine.patch
+@@ -0,0 +1,29 @@
++--- a/arch/arm/boot/dts/armada-370.dtsi
+++++ b/arch/arm/boot/dts/armada-370.dtsi
++@@ -234,7 +234,7 @@
++ 				clocks = <&gateclk 23>;
++ 				clock-names = "cesa0";
++ 				marvell,crypto-srams = <&crypto_sram>;
++-				marvell,crypto-sram-size = <0x7e0>;
+++				marvell,crypto-sram-size = <0x800>;
++ 			};
++ 		};
++ 
++@@ -255,12 +255,17 @@
++ 			 * cpuidle workaround.
++ 			 */
++ 			idle-sram@0 {
+++				status = "disabled";
++ 				reg = <0x0 0x20>;
++ 			};
++ 		};
++ 	};
++ };
++ 
+++&coherencyfab {
+++	broken-idle;
+++};
+++
++ /*
++  * Default UART pinctrl setting without RTS/CTS, can be overwritten on
++  * board level if a different configuration is used.
+diff --git a/target/linux/mvebu/patches-5.15/400-find_active_root.patch b/target/linux/mvebu/patches-5.15/400-find_active_root.patch
+new file mode 100644
+index 0000000000..5582d20c68
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/400-find_active_root.patch
+@@ -0,0 +1,60 @@
++The WRT1900AC among other Linksys routers uses a dual-firmware layout.
++Dynamically rename the active partition to "ubi".
++
++Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
++
++--- a/drivers/mtd/parsers/ofpart_core.c
+++++ b/drivers/mtd/parsers/ofpart_core.c
++@@ -38,6 +38,8 @@ static bool node_has_compatible(struct d
++ 	return of_get_property(pp, "compatible", NULL);
++ }
++ 
+++static int mangled_rootblock;
+++
++ static int parse_fixed_partitions(struct mtd_info *master,
++ 				  const struct mtd_partition **pparts,
++ 				  struct mtd_part_parser_data *data)
++@@ -48,6 +50,7 @@ static int parse_fixed_partitions(struct
++ 	struct device_node *mtd_node;
++ 	struct device_node *ofpart_node;
++ 	const char *partname;
+++	const char *owrtpart = "ubi";
++ 	struct device_node *pp;
++ 	int nr_parts, i, ret = 0;
++ 	bool dedicated = true;
++@@ -133,9 +136,13 @@ static int parse_fixed_partitions(struct
++ 		parts[i].size = of_read_number(reg + a_cells, s_cells);
++ 		parts[i].of_node = pp;
++ 
++-		partname = of_get_property(pp, "label", &len);
++-		if (!partname)
++-			partname = of_get_property(pp, "name", &len);
+++		if (mangled_rootblock && (i == mangled_rootblock)) {
+++			partname = owrtpart;
+++		} else {
+++			partname = of_get_property(pp, "label", &len);
+++			if (!partname)
+++				partname = of_get_property(pp, "name", &len);
+++		}
++ 		parts[i].name = partname;
++ 
++ 		if (of_get_property(pp, "read-only", &len))
++@@ -252,6 +259,18 @@ static int __init ofpart_parser_init(voi
++ 	return 0;
++ }
++ 
+++static int __init active_root(char *str)
+++{
+++	get_option(&str, &mangled_rootblock);
+++
+++	if (!mangled_rootblock)
+++		return 1;
+++
+++	return 1;
+++}
+++
+++__setup("mangled_rootblock=", active_root);
+++
++ static void __exit ofpart_parser_exit(void)
++ {
++ 	deregister_mtd_parser(&ofpart_parser);
+diff --git a/target/linux/mvebu/patches-5.15/700-mvneta-tx-queue-workaround.patch b/target/linux/mvebu/patches-5.15/700-mvneta-tx-queue-workaround.patch
+new file mode 100644
+index 0000000000..6c07a2915b
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/700-mvneta-tx-queue-workaround.patch
+@@ -0,0 +1,38 @@
++The hardware queue scheduling is apparently configured with fixed
++priorities, which creates a nasty fairness issue where traffic from one
++CPU can starve traffic from all other CPUs.
++
++Work around this issue by forcing all tx packets to go through one CPU,
++until this issue is fixed properly.
++
++Signed-off-by: Felix Fietkau <nbd@nbd.name>
++---
++--- a/drivers/net/ethernet/marvell/mvneta.c
+++++ b/drivers/net/ethernet/marvell/mvneta.c
++@@ -4987,6 +4987,16 @@ static int mvneta_setup_tc(struct net_de
++ 	}
++ }
++ 
+++#ifndef CONFIG_ARM64
+++static u16 mvneta_select_queue(struct net_device *dev, struct sk_buff *skb,
+++			       struct net_device *sb_dev)
+++{
+++	/* XXX: hardware queue scheduling is broken,
+++	 * use only one queue until it is fixed */
+++	return 0;
+++}
+++#endif
+++
++ static const struct net_device_ops mvneta_netdev_ops = {
++ 	.ndo_open            = mvneta_open,
++ 	.ndo_stop            = mvneta_stop,
++@@ -4997,6 +5007,9 @@ static const struct net_device_ops mvnet
++ 	.ndo_fix_features    = mvneta_fix_features,
++ 	.ndo_get_stats64     = mvneta_get_stats64,
++ 	.ndo_eth_ioctl        = mvneta_ioctl,
+++#ifndef CONFIG_ARM64
+++	.ndo_select_queue    = mvneta_select_queue,
+++#endif
++ 	.ndo_bpf	     = mvneta_xdp,
++ 	.ndo_xdp_xmit        = mvneta_xdp_xmit,
++ 	.ndo_setup_tc	     = mvneta_setup_tc,
+diff --git a/target/linux/mvebu/patches-5.15/702-net-next-ethernet-marvell-mvnetaMQPrioOffload.patch b/target/linux/mvebu/patches-5.15/702-net-next-ethernet-marvell-mvnetaMQPrioOffload.patch
+new file mode 100644
+index 0000000000..96f5042e69
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/702-net-next-ethernet-marvell-mvnetaMQPrioOffload.patch
+@@ -0,0 +1,66 @@
++From 75fa71e3acadbb4ab5eda18505277eb9a1f69b23 Mon Sep 17 00:00:00 2001
++From: Maxime Chevallier <maxime.chevallier@bootlin.com>
++Date: Fri, 26 Nov 2021 12:20:53 +0100
++Subject: net: mvneta: Use struct tc_mqprio_qopt_offload for MQPrio
++ configuration
++
++The struct tc_mqprio_qopt_offload is a container for struct tc_mqprio_qopt,
++that allows passing extra parameters, such as traffic shaping. This commit
++converts the current mqprio code to that new struct.
++
++Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++---
++ drivers/net/ethernet/marvell/mvneta.c | 17 ++++++++++-------
++ 1 file changed, 10 insertions(+), 7 deletions(-)
++
++(limited to 'drivers/net/ethernet/marvell/mvneta.c')
++
++--- a/drivers/net/ethernet/marvell/mvneta.c
+++++ b/drivers/net/ethernet/marvell/mvneta.c
++@@ -38,6 +38,7 @@
++ #include <net/ipv6.h>
++ #include <net/tso.h>
++ #include <net/page_pool.h>
+++#include <net/pkt_cls.h>
++ #include <linux/bpf_trace.h>
++ 
++ /* Registers */
++@@ -4947,14 +4948,14 @@ static void mvneta_setup_rx_prio_map(str
++ }
++ 
++ static int mvneta_setup_mqprio(struct net_device *dev,
++-			       struct tc_mqprio_qopt *qopt)
+++			       struct tc_mqprio_qopt_offload *mqprio)
++ {
++ 	struct mvneta_port *pp = netdev_priv(dev);
++ 	u8 num_tc;
++ 	int i;
++ 
++-	qopt->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
++-	num_tc = qopt->num_tc;
+++	mqprio->qopt.hw = TC_MQPRIO_HW_OFFLOAD_TCS;
+++	num_tc = mqprio->qopt.num_tc;
++ 
++ 	if (num_tc > rxq_number)
++ 		return -EINVAL;
++@@ -4965,13 +4966,15 @@ static int mvneta_setup_mqprio(struct ne
++ 		return 0;
++ 	}
++ 
++-	memcpy(pp->prio_tc_map, qopt->prio_tc_map, sizeof(pp->prio_tc_map));
+++	memcpy(pp->prio_tc_map, mqprio->qopt.prio_tc_map,
+++	       sizeof(pp->prio_tc_map));
++ 
++ 	mvneta_setup_rx_prio_map(pp);
++ 
++-	netdev_set_num_tc(dev, qopt->num_tc);
++-	for (i = 0; i < qopt->num_tc; i++)
++-		netdev_set_tc_queue(dev, i, qopt->count[i], qopt->offset[i]);
+++	netdev_set_num_tc(dev, mqprio->qopt.num_tc);
+++	for (i = 0; i < mqprio->qopt.num_tc; i++)
+++		netdev_set_tc_queue(dev, i, mqprio->qopt.count[i],
+++				    mqprio->qopt.offset[i]);
++ 
++ 	return 0;
++ }
+diff --git a/target/linux/mvebu/patches-5.15/703-net-next-ethernet-marvell-mvnetaMQPrioFlag.patch b/target/linux/mvebu/patches-5.15/703-net-next-ethernet-marvell-mvnetaMQPrioFlag.patch
+new file mode 100644
+index 0000000000..997f301f39
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/703-net-next-ethernet-marvell-mvnetaMQPrioFlag.patch
+@@ -0,0 +1,30 @@
++From e7ca75fe6662f78bfeb0112671c812e4c7b8e214 Mon Sep 17 00:00:00 2001
++From: Maxime Chevallier <maxime.chevallier@bootlin.com>
++Date: Fri, 26 Nov 2021 12:20:54 +0100
++Subject: net: mvneta: Don't force-set the offloading flag
++
++The qopt->hw flag is set by the TC code according to the offloading mode
++asked by user. Don't force-set it in the driver, but instead read it to
++make sure we do what's asked.
++
++Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++---
++ drivers/net/ethernet/marvell/mvneta.c | 4 +++-
++ 1 file changed, 3 insertions(+), 1 deletion(-)
++
++(limited to 'drivers/net/ethernet/marvell/mvneta.c')
++
++--- a/drivers/net/ethernet/marvell/mvneta.c
+++++ b/drivers/net/ethernet/marvell/mvneta.c
++@@ -4954,7 +4954,9 @@ static int mvneta_setup_mqprio(struct ne
++ 	u8 num_tc;
++ 	int i;
++ 
++-	mqprio->qopt.hw = TC_MQPRIO_HW_OFFLOAD_TCS;
+++	if (mqprio->qopt.hw != TC_MQPRIO_HW_OFFLOAD_TCS)
+++		return 0;
+++
++ 	num_tc = mqprio->qopt.num_tc;
++ 
++ 	if (num_tc > rxq_number)
+diff --git a/target/linux/mvebu/patches-5.15/704-net-next-ethernet-marvell-mvnetaMQPrioQueue.patch b/target/linux/mvebu/patches-5.15/704-net-next-ethernet-marvell-mvnetaMQPrioQueue.patch
+new file mode 100644
+index 0000000000..73563a57a0
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/704-net-next-ethernet-marvell-mvnetaMQPrioQueue.patch
+@@ -0,0 +1,97 @@
++From e9f7099d0730341b24c057acbf545dd019581db6 Mon Sep 17 00:00:00 2001
++From: Maxime Chevallier <maxime.chevallier@bootlin.com>
++Date: Fri, 26 Nov 2021 12:20:55 +0100
++Subject: net: mvneta: Allow having more than one queue per TC
++
++The current mqprio implementation assumed that we are only using one
++queue per TC. Use the offset and count parameters to allow using
++multiple queues per TC. In that case, the controller will use a standard
++round-robin algorithm to pick queues assigned to the same TC, with the
++same priority.
++
++This only applies to VLAN priorities in ingress traffic, each TC
++corresponding to a vlan priority.
++
++Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++---
++ drivers/net/ethernet/marvell/mvneta.c | 35 ++++++++++++++++++++---------------
++ 1 file changed, 20 insertions(+), 15 deletions(-)
++
++(limited to 'drivers/net/ethernet/marvell/mvneta.c')
++
++--- a/drivers/net/ethernet/marvell/mvneta.c
+++++ b/drivers/net/ethernet/marvell/mvneta.c
++@@ -493,7 +493,6 @@ struct mvneta_port {
++ 	u8 mcast_count[256];
++ 	u16 tx_ring_size;
++ 	u16 rx_ring_size;
++-	u8 prio_tc_map[8];
++ 
++ 	phy_interface_t phy_interface;
++ 	struct device_node *dn;
++@@ -4936,13 +4935,12 @@ static void mvneta_clear_rx_prio_map(str
++ 	mvreg_write(pp, MVNETA_VLAN_PRIO_TO_RXQ, 0);
++ }
++ 
++-static void mvneta_setup_rx_prio_map(struct mvneta_port *pp)
+++static void mvneta_map_vlan_prio_to_rxq(struct mvneta_port *pp, u8 pri, u8 rxq)
++ {
++-	u32 val = 0;
++-	int i;
+++	u32 val = mvreg_read(pp, MVNETA_VLAN_PRIO_TO_RXQ);
++ 
++-	for (i = 0; i < rxq_number; i++)
++-		val |= MVNETA_VLAN_PRIO_RXQ_MAP(i, pp->prio_tc_map[i]);
+++	val &= ~MVNETA_VLAN_PRIO_RXQ_MAP(pri, 0x7);
+++	val |= MVNETA_VLAN_PRIO_RXQ_MAP(pri, rxq);
++ 
++ 	mvreg_write(pp, MVNETA_VLAN_PRIO_TO_RXQ, val);
++ }
++@@ -4951,8 +4949,8 @@ static int mvneta_setup_mqprio(struct ne
++ 			       struct tc_mqprio_qopt_offload *mqprio)
++ {
++ 	struct mvneta_port *pp = netdev_priv(dev);
+++	int rxq, tc;
++ 	u8 num_tc;
++-	int i;
++ 
++ 	if (mqprio->qopt.hw != TC_MQPRIO_HW_OFFLOAD_TCS)
++ 		return 0;
++@@ -4962,21 +4960,28 @@ static int mvneta_setup_mqprio(struct ne
++ 	if (num_tc > rxq_number)
++ 		return -EINVAL;
++ 
+++	mvneta_clear_rx_prio_map(pp);
+++
++ 	if (!num_tc) {
++-		mvneta_clear_rx_prio_map(pp);
++ 		netdev_reset_tc(dev);
++ 		return 0;
++ 	}
++ 
++-	memcpy(pp->prio_tc_map, mqprio->qopt.prio_tc_map,
++-	       sizeof(pp->prio_tc_map));
+++	netdev_set_num_tc(dev, mqprio->qopt.num_tc);
++ 
++-	mvneta_setup_rx_prio_map(pp);
+++	for (tc = 0; tc < mqprio->qopt.num_tc; tc++) {
+++		netdev_set_tc_queue(dev, tc, mqprio->qopt.count[tc],
+++				    mqprio->qopt.offset[tc]);
+++
+++		for (rxq = mqprio->qopt.offset[tc];
+++		     rxq < mqprio->qopt.count[tc] + mqprio->qopt.offset[tc];
+++		     rxq++) {
+++			if (rxq >= rxq_number)
+++				return -EINVAL;
++ 
++-	netdev_set_num_tc(dev, mqprio->qopt.num_tc);
++-	for (i = 0; i < mqprio->qopt.num_tc; i++)
++-		netdev_set_tc_queue(dev, i, mqprio->qopt.count[i],
++-				    mqprio->qopt.offset[i]);
+++			mvneta_map_vlan_prio_to_rxq(pp, tc, rxq);
+++		}
+++	}
++ 
++ 	return 0;
++ }
+diff --git a/target/linux/mvebu/patches-5.15/705-net-next-ethernet-marvell-mvnetaMQPrioTCOffload.patch b/target/linux/mvebu/patches-5.15/705-net-next-ethernet-marvell-mvnetaMQPrioTCOffload.patch
+new file mode 100644
+index 0000000000..7b837d0b49
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/705-net-next-ethernet-marvell-mvnetaMQPrioTCOffload.patch
+@@ -0,0 +1,182 @@
++From 2551dc9e398c37a15e52122d385c29a8b06be45f Mon Sep 17 00:00:00 2001
++From: Maxime Chevallier <maxime.chevallier@bootlin.com>
++Date: Fri, 26 Nov 2021 12:20:56 +0100
++Subject: net: mvneta: Add TC traffic shaping offload
++
++The mvneta controller is able to do some tocken-bucket per-queue traffic
++shaping. This commit adds support for setting these using the TC mqprio
++interface.
++
++The token-bucket parameters are customisable, but the current
++implementation configures them to have a 10kbps resolution for the
++rate limitation, since it allows to cover the whole range of max_rate
++values from 10kbps to 5Gbps with 10kbps increments.
++
++Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++---
++ drivers/net/ethernet/marvell/mvneta.c | 120 +++++++++++++++++++++++++++++++++-
++ 1 file changed, 119 insertions(+), 1 deletion(-)
++
++(limited to 'drivers/net/ethernet/marvell/mvneta.c')
++
++--- a/drivers/net/ethernet/marvell/mvneta.c
+++++ b/drivers/net/ethernet/marvell/mvneta.c
++@@ -248,12 +248,39 @@
++ #define      MVNETA_TXQ_SENT_DESC_MASK           0x3fff0000
++ #define MVNETA_PORT_TX_RESET                     0x3cf0
++ #define      MVNETA_PORT_TX_DMA_RESET            BIT(0)
+++#define MVNETA_TXQ_CMD1_REG			 0x3e00
+++#define      MVNETA_TXQ_CMD1_BW_LIM_SEL_V1	 BIT(3)
+++#define      MVNETA_TXQ_CMD1_BW_LIM_EN		 BIT(0)
+++#define MVNETA_REFILL_NUM_CLK_REG		 0x3e08
+++#define      MVNETA_REFILL_MAX_NUM_CLK		 0x0000ffff
++ #define MVNETA_TX_MTU                            0x3e0c
++ #define MVNETA_TX_TOKEN_SIZE                     0x3e14
++ #define      MVNETA_TX_TOKEN_SIZE_MAX            0xffffffff
+++#define MVNETA_TXQ_BUCKET_REFILL_REG(q)		 (0x3e20 + ((q) << 2))
+++#define      MVNETA_TXQ_BUCKET_REFILL_PERIOD_MASK	0x3ff00000
+++#define      MVNETA_TXQ_BUCKET_REFILL_PERIOD_SHIFT	20
+++#define      MVNETA_TXQ_BUCKET_REFILL_VALUE_MAX	 0x0007ffff
++ #define MVNETA_TXQ_TOKEN_SIZE_REG(q)             (0x3e40 + ((q) << 2))
++ #define      MVNETA_TXQ_TOKEN_SIZE_MAX           0x7fffffff
++ 
+++/* The values of the bucket refill base period and refill period are taken from
+++ * the reference manual, and adds up to a base resolution of 10Kbps. This allows
+++ * to cover all rate-limit values from 10Kbps up to 5Gbps
+++ */
+++
+++/* Base period for the rate limit algorithm */
+++#define MVNETA_TXQ_BUCKET_REFILL_BASE_PERIOD_NS	100
+++
+++/* Number of Base Period to wait between each bucket refill */
+++#define MVNETA_TXQ_BUCKET_REFILL_PERIOD	1000
+++
+++/* The base resolution for rate limiting, in bps. Any max_rate value should be
+++ * a multiple of that value.
+++ */
+++#define MVNETA_TXQ_RATE_LIMIT_RESOLUTION (NSEC_PER_SEC / \
+++					 (MVNETA_TXQ_BUCKET_REFILL_BASE_PERIOD_NS * \
+++					  MVNETA_TXQ_BUCKET_REFILL_PERIOD))
+++
++ #define MVNETA_LPI_CTRL_0                        0x2cc0
++ #define MVNETA_LPI_CTRL_1                        0x2cc4
++ #define      MVNETA_LPI_REQUEST_ENABLE           BIT(0)
++@@ -4945,11 +4972,74 @@ static void mvneta_map_vlan_prio_to_rxq(
++ 	mvreg_write(pp, MVNETA_VLAN_PRIO_TO_RXQ, val);
++ }
++ 
+++static int mvneta_enable_per_queue_rate_limit(struct mvneta_port *pp)
+++{
+++	unsigned long core_clk_rate;
+++	u32 refill_cycles;
+++	u32 val;
+++
+++	core_clk_rate = clk_get_rate(pp->clk);
+++	if (!core_clk_rate)
+++		return -EINVAL;
+++
+++	refill_cycles = MVNETA_TXQ_BUCKET_REFILL_BASE_PERIOD_NS /
+++			(NSEC_PER_SEC / core_clk_rate);
+++
+++	if (refill_cycles > MVNETA_REFILL_MAX_NUM_CLK)
+++		return -EINVAL;
+++
+++	/* Enable bw limit algorithm version 3 */
+++	val = mvreg_read(pp, MVNETA_TXQ_CMD1_REG);
+++	val &= ~(MVNETA_TXQ_CMD1_BW_LIM_SEL_V1 | MVNETA_TXQ_CMD1_BW_LIM_EN);
+++	mvreg_write(pp, MVNETA_TXQ_CMD1_REG, val);
+++
+++	/* Set the base refill rate */
+++	mvreg_write(pp, MVNETA_REFILL_NUM_CLK_REG, refill_cycles);
+++
+++	return 0;
+++}
+++
+++static void mvneta_disable_per_queue_rate_limit(struct mvneta_port *pp)
+++{
+++	u32 val = mvreg_read(pp, MVNETA_TXQ_CMD1_REG);
+++
+++	val |= (MVNETA_TXQ_CMD1_BW_LIM_SEL_V1 | MVNETA_TXQ_CMD1_BW_LIM_EN);
+++	mvreg_write(pp, MVNETA_TXQ_CMD1_REG, val);
+++}
+++
+++static int mvneta_setup_queue_rates(struct mvneta_port *pp, int queue,
+++				    u64 min_rate, u64 max_rate)
+++{
+++	u32 refill_val, rem;
+++	u32 val = 0;
+++
+++	/* Convert to from Bps to bps */
+++	max_rate *= 8;
+++
+++	if (min_rate)
+++		return -EINVAL;
+++
+++	refill_val = div_u64_rem(max_rate, MVNETA_TXQ_RATE_LIMIT_RESOLUTION,
+++				 &rem);
+++
+++	if (rem || !refill_val ||
+++	    refill_val > MVNETA_TXQ_BUCKET_REFILL_VALUE_MAX)
+++		return -EINVAL;
+++
+++	val = refill_val;
+++	val |= (MVNETA_TXQ_BUCKET_REFILL_PERIOD <<
+++		MVNETA_TXQ_BUCKET_REFILL_PERIOD_SHIFT);
+++
+++	mvreg_write(pp, MVNETA_TXQ_BUCKET_REFILL_REG(queue), val);
+++
+++	return 0;
+++}
+++
++ static int mvneta_setup_mqprio(struct net_device *dev,
++ 			       struct tc_mqprio_qopt_offload *mqprio)
++ {
++ 	struct mvneta_port *pp = netdev_priv(dev);
++-	int rxq, tc;
+++	int rxq, txq, tc, ret;
++ 	u8 num_tc;
++ 
++ 	if (mqprio->qopt.hw != TC_MQPRIO_HW_OFFLOAD_TCS)
++@@ -4963,6 +5053,7 @@ static int mvneta_setup_mqprio(struct ne
++ 	mvneta_clear_rx_prio_map(pp);
++ 
++ 	if (!num_tc) {
+++		mvneta_disable_per_queue_rate_limit(pp);
++ 		netdev_reset_tc(dev);
++ 		return 0;
++ 	}
++@@ -4983,6 +5074,33 @@ static int mvneta_setup_mqprio(struct ne
++ 		}
++ 	}
++ 
+++	if (mqprio->shaper != TC_MQPRIO_SHAPER_BW_RATE) {
+++		mvneta_disable_per_queue_rate_limit(pp);
+++		return 0;
+++	}
+++
+++	if (mqprio->qopt.num_tc > txq_number)
+++		return -EINVAL;
+++
+++	ret = mvneta_enable_per_queue_rate_limit(pp);
+++	if (ret)
+++		return ret;
+++
+++	for (tc = 0; tc < mqprio->qopt.num_tc; tc++) {
+++		for (txq = mqprio->qopt.offset[tc];
+++		     txq < mqprio->qopt.count[tc] + mqprio->qopt.offset[tc];
+++		     txq++) {
+++			if (txq >= txq_number)
+++				return -EINVAL;
+++
+++			ret = mvneta_setup_queue_rates(pp, txq,
+++						       mqprio->min_rate[tc],
+++						       mqprio->max_rate[tc]);
+++			if (ret)
+++				return ret;
+++		}
+++	}
+++
++ 	return 0;
++ }
++ 
+diff --git a/target/linux/mvebu/patches-5.15/800-cpuidle-mvebu-indicate-failure-to-enter-deeper-sleep.patch b/target/linux/mvebu/patches-5.15/800-cpuidle-mvebu-indicate-failure-to-enter-deeper-sleep.patch
+new file mode 100644
+index 0000000000..29f36be460
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/800-cpuidle-mvebu-indicate-failure-to-enter-deeper-sleep.patch
+@@ -0,0 +1,40 @@
++From c28b2d367da8a471482e6a4aa8337ab6369a80c2 Mon Sep 17 00:00:00 2001
++From: Russell King <rmk+kernel@arm.linux.org.uk>
++Date: Sat, 3 Oct 2015 09:13:05 +0100
++Subject: cpuidle: mvebu: indicate failure to enter deeper sleep states
++
++The cpuidle ->enter method expects the return value to be the sleep
++state we entered.  Returning negative numbers or other codes is not
++permissible since coupled CPU idle was merged.
++
++At least some of the mvebu_v7_cpu_suspend() implementations return the
++value from cpu_suspend(), which returns zero if the CPU vectors back
++into the kernel via cpu_resume() (the success case), or the non-zero
++return value of the suspend actor, or one (failure cases).
++
++We do not want to be returning the failure case value back to CPU idle
++as that indicates that we successfully entered one of the deeper idle
++states.  Always return zero instead, indicating that we slept for the
++shortest amount of time.
++
++Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
++---
++ drivers/cpuidle/cpuidle-mvebu-v7.c | 6 +++++-
++ 1 file changed, 5 insertions(+), 1 deletion(-)
++
++--- a/drivers/cpuidle/cpuidle-mvebu-v7.c
+++++ b/drivers/cpuidle/cpuidle-mvebu-v7.c
++@@ -39,8 +39,12 @@ static int mvebu_v7_enter_idle(struct cp
++ 	ret = mvebu_v7_cpu_suspend(deepidle);
++ 	cpu_pm_exit();
++ 
+++	/*
+++	 * If we failed to enter the desired state, indicate that we
+++	 * slept lightly.
+++	 */
++ 	if (ret)
++-		return ret;
+++		return 0;
++ 
++ 	return index;
++ }
+diff --git a/target/linux/mvebu/patches-5.15/801-pci-mvebu-time-out-reset-on-link-up.patch b/target/linux/mvebu/patches-5.15/801-pci-mvebu-time-out-reset-on-link-up.patch
+new file mode 100644
+index 0000000000..dba1253699
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/801-pci-mvebu-time-out-reset-on-link-up.patch
+@@ -0,0 +1,60 @@
++From 287b9df160b6159f8d385424904f8bac501280c1 Mon Sep 17 00:00:00 2001
++From: Russell King <rmk+kernel@armlinux.org.uk>
++Date: Sat, 9 Jul 2016 10:58:16 +0100
++Subject: pci: mvebu: time out reset on link up
++
++If the port reports that the link is up while we are resetting, there's
++little point in waiting for the full duration.
++
++Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
++---
++ drivers/pci/controller/pci-mvebu.c | 20 ++++++++++++++------
++ 1 file changed, 14 insertions(+), 6 deletions(-)
++
++--- a/drivers/pci/controller/pci-mvebu.c
+++++ b/drivers/pci/controller/pci-mvebu.c
++@@ -1023,6 +1023,7 @@ static int mvebu_pcie_powerup(struct mve
++ 
++ 	if (port->reset_gpio) {
++ 		u32 reset_udelay = PCI_PM_D3COLD_WAIT * 1000;
+++		unsigned int i;
++ 
++ 		of_property_read_u32(port->dn, "reset-delay-us",
++ 				     &reset_udelay);
++@@ -1030,7 +1031,13 @@ static int mvebu_pcie_powerup(struct mve
++ 		udelay(100);
++ 
++ 		gpiod_set_value_cansleep(port->reset_gpio, 0);
++-		msleep(reset_udelay / 1000);
+++		for (i = 0; i < reset_udelay; i += 1000) {
+++			if (mvebu_pcie_link_up(port))
+++				break;
+++			msleep(1);
+++		}
+++
+++		printk("%s: reset completed in %dus\n", port->name, i);
++ 	}
++ 
++ 	return 0;
++@@ -1190,15 +1197,16 @@ static int mvebu_pcie_probe(struct platf
++ 		if (!child)
++ 			continue;
++ 
++-		ret = mvebu_pcie_powerup(port);
++-		if (ret < 0)
++-			continue;
++-
++ 		port->base = mvebu_pcie_map_registers(pdev, child, port);
++ 		if (IS_ERR(port->base)) {
++ 			dev_err(dev, "%s: cannot map registers\n", port->name);
++ 			port->base = NULL;
++-			mvebu_pcie_powerdown(port);
+++			continue;
+++		}
+++
+++		ret = mvebu_pcie_powerup(port);
+++		if (ret < 0) {
+++			port->base = NULL;
++ 			continue;
++ 		}
++ 
+diff --git a/target/linux/mvebu/patches-5.15/901-dt-bindings-Add-IEI-vendor-prefix-and-IEI-WT61P803-P.patch b/target/linux/mvebu/patches-5.15/901-dt-bindings-Add-IEI-vendor-prefix-and-IEI-WT61P803-P.patch
+new file mode 100644
+index 0000000000..3446086cad
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/901-dt-bindings-Add-IEI-vendor-prefix-and-IEI-WT61P803-P.patch
+@@ -0,0 +1,218 @@
++From aa4a0ccc41997f2da172165c92803abace43bd1c Mon Sep 17 00:00:00 2001
++From: Luka Kovacic <luka.kovacic () sartura ! hr>
++Date: Tue, 24 Aug 2021 12:44:32 +0000
++Subject: [PATCH 1/7] dt-bindings: Add IEI vendor prefix and IEI WT61P803
++ PUZZLE driver bindings
++
++Add the IEI WT61P803 PUZZLE Device Tree bindings for MFD, HWMON and LED
++drivers. A new vendor prefix is also added accordingly for
++IEI Integration Corp.
++
++Signed-off-by: Luka Kovacic <luka.kovacic@sartura.hr>
++Signed-off-by: Pavo Banicevic <pavo.banicevic@sartura.hr>
++Cc: Luka Perkov <luka.perkov@sartura.hr>
++Cc: Robert Marko <robert.marko@sartura.hr>
++---
++ .../hwmon/iei,wt61p803-puzzle-hwmon.yaml      | 53 ++++++++++++
++ .../leds/iei,wt61p803-puzzle-leds.yaml        | 39 +++++++++
++ .../bindings/mfd/iei,wt61p803-puzzle.yaml     | 82 +++++++++++++++++++
++ .../devicetree/bindings/vendor-prefixes.yaml  |  2 +
++ 4 files changed, 176 insertions(+)
++ create mode 100644 Documentation/devicetree/bindings/hwmon/iei,wt61p803-puzzle-hwmon.yaml
++ create mode 100644 Documentation/devicetree/bindings/leds/iei,wt61p803-puzzle-leds.yaml
++ create mode 100644 Documentation/devicetree/bindings/mfd/iei,wt61p803-puzzle.yaml
++
++--- /dev/null
+++++ b/Documentation/devicetree/bindings/hwmon/iei,wt61p803-puzzle-hwmon.yaml
++@@ -0,0 +1,53 @@
+++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+++%YAML 1.2
+++---
+++$id: http://devicetree.org/schemas/hwmon/iei,wt61p803-puzzle-hwmon.yaml#
+++$schema: http://devicetree.org/meta-schemas/core.yaml#
+++
+++title: IEI WT61P803 PUZZLE MCU HWMON module from IEI Integration Corp.
+++
+++maintainers:
+++  - Luka Kovacic <luka.kovacic@sartura.hr>
+++
+++description: |
+++  This module is a part of the IEI WT61P803 PUZZLE MFD device. For more details
+++  see Documentation/devicetree/bindings/mfd/iei,wt61p803-puzzle.yaml.
+++
+++  The HWMON module is a sub-node of the MCU node in the Device Tree.
+++
+++properties:
+++  compatible:
+++    const: iei,wt61p803-puzzle-hwmon
+++
+++  "#address-cells":
+++    const: 1
+++
+++  "#size-cells":
+++    const: 0
+++
+++patternProperties:
+++  "^fan-group@[0-1]$":
+++    type: object
+++    properties:
+++      reg:
+++        minimum: 0
+++        maximum: 1
+++        description:
+++          Fan group ID
+++
+++      cooling-levels:
+++        minItems: 1
+++        maxItems: 255
+++        description:
+++          Cooling levels for the fans (PWM value mapping)
+++    description: |
+++      Properties for each fan group.
+++    required:
+++      - reg
+++
+++required:
+++  - compatible
+++  - "#address-cells"
+++  - "#size-cells"
+++
+++additionalProperties: false
++--- /dev/null
+++++ b/Documentation/devicetree/bindings/leds/iei,wt61p803-puzzle-leds.yaml
++@@ -0,0 +1,39 @@
+++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+++%YAML 1.2
+++---
+++$id: http://devicetree.org/schemas/leds/iei,wt61p803-puzzle-leds.yaml#
+++$schema: http://devicetree.org/meta-schemas/core.yaml#
+++
+++title: IEI WT61P803 PUZZLE MCU LED module from IEI Integration Corp.
+++
+++maintainers:
+++  - Luka Kovacic <luka.kovacic@sartura.hr>
+++
+++description: |
+++  This module is a part of the IEI WT61P803 PUZZLE MFD device. For more details
+++  see Documentation/devicetree/bindings/mfd/iei,wt61p803-puzzle.yaml.
+++
+++  The LED module is a sub-node of the MCU node in the Device Tree.
+++
+++properties:
+++  compatible:
+++    const: iei,wt61p803-puzzle-leds
+++
+++  "#address-cells":
+++    const: 1
+++
+++  "#size-cells":
+++    const: 0
+++
+++  led@0:
+++    type: object
+++    $ref: common.yaml
+++    description: |
+++      Properties for a single LED.
+++
+++required:
+++  - compatible
+++  - "#address-cells"
+++  - "#size-cells"
+++
+++additionalProperties: false
++--- /dev/null
+++++ b/Documentation/devicetree/bindings/mfd/iei,wt61p803-puzzle.yaml
++@@ -0,0 +1,82 @@
+++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+++%YAML 1.2
+++---
+++$id: http://devicetree.org/schemas/mfd/iei,wt61p803-puzzle.yaml#
+++$schema: http://devicetree.org/meta-schemas/core.yaml#
+++
+++title: IEI WT61P803 PUZZLE MCU from IEI Integration Corp.
+++
+++maintainers:
+++  - Luka Kovacic <luka.kovacic@sartura.hr>
+++
+++description: |
+++  IEI WT61P803 PUZZLE MCU is embedded in some IEI Puzzle series boards.
+++  It's used for controlling system power states, fans, LEDs and temperature
+++  sensors.
+++
+++  For Device Tree bindings of other sub-modules (HWMON, LEDs) refer to the
+++  binding documents under the respective subsystem directories.
+++
+++properties:
+++  compatible:
+++    const: iei,wt61p803-puzzle
+++
+++  current-speed:
+++    description:
+++      Serial bus speed in bps
+++    maxItems: 1
+++
+++  enable-beep: true
+++
+++  hwmon:
+++    $ref: /schemas/hwmon/iei,wt61p803-puzzle-hwmon.yaml
+++
+++  leds:
+++    $ref: /schemas/leds/iei,wt61p803-puzzle-leds.yaml
+++
+++required:
+++  - compatible
+++  - current-speed
+++
+++additionalProperties: false
+++
+++examples:
+++  - |
+++    #include <dt-bindings/leds/common.h>
+++    serial {
+++        mcu {
+++            compatible = "iei,wt61p803-puzzle";
+++            current-speed = <115200>;
+++            enable-beep;
+++
+++            leds {
+++                compatible = "iei,wt61p803-puzzle-leds";
+++                #address-cells = <1>;
+++                #size-cells = <0>;
+++
+++                led@0 {
+++                    reg = <0>;
+++                    function = LED_FUNCTION_POWER;
+++                    color = <LED_COLOR_ID_BLUE>;
+++                };
+++            };
+++
+++            hwmon {
+++                compatible = "iei,wt61p803-puzzle-hwmon";
+++                #address-cells = <1>;
+++                #size-cells = <0>;
+++
+++                fan-group@0 {
+++                    #cooling-cells = <2>;
+++                    reg = <0x00>;
+++                    cooling-levels = <64 102 170 230 250>;
+++                };
+++
+++                fan-group@1 {
+++                    #cooling-cells = <2>;
+++                    reg = <0x01>;
+++                    cooling-levels = <64 102 170 230 250>;
+++                };
+++            };
+++        };
+++    };
++--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
++@@ -519,6 +519,8 @@ patternProperties:
++     description: IC Plus Corp.
++   "^idt,.*":
++     description: Integrated Device Technologies, Inc.
+++  "^iei,.*":
+++    description: IEI Integration Corp.
++   "^ifi,.*":
++     description: Ingenieurburo Fur Ic-Technologie (I/F/I)
++   "^ilitek,.*":
+diff --git a/target/linux/mvebu/patches-5.15/902-drivers-mfd-Add-a-driver-for-IEI-WT61P803-PUZZLE-MCU.patch b/target/linux/mvebu/patches-5.15/902-drivers-mfd-Add-a-driver-for-IEI-WT61P803-PUZZLE-MCU.patch
+new file mode 100644
+index 0000000000..84d995b902
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/902-drivers-mfd-Add-a-driver-for-IEI-WT61P803-PUZZLE-MCU.patch
+@@ -0,0 +1,1034 @@
++From 692cfa85272dd12995b427c0a7a585ced5d54f32 Mon Sep 17 00:00:00 2001
++From: Luka Kovacic <luka.kovacic () sartura ! hr>
++Date: Tue, 24 Aug 2021 12:44:33 +0000
++Subject: [PATCH 2/7] drivers: mfd: Add a driver for IEI WT61P803 PUZZLE MCU
++
++Add a driver for the IEI WT61P803 PUZZLE microcontroller, used in some
++IEI Puzzle series devices. The microcontroller controls system power,
++temperature sensors, fans and LEDs.
++
++This driver implements the core functionality for device communication
++over the system serial (serdev bus). It handles MCU messages and the
++internal MCU properties. Some properties can be managed over sysfs.
++
++Signed-off-by: Luka Kovacic <luka.kovacic@sartura.hr>
++Signed-off-by: Pavo Banicevic <pavo.banicevic@sartura.hr>
++Cc: Luka Perkov <luka.perkov@sartura.hr>
++Cc: Robert Marko <robert.marko@sartura.hr>
++---
++ drivers/mfd/Kconfig                     |   8 +
++ drivers/mfd/Makefile                    |   1 +
++ drivers/mfd/iei-wt61p803-puzzle.c       | 908 ++++++++++++++++++++++++
++ include/linux/mfd/iei-wt61p803-puzzle.h |  66 ++
++ 4 files changed, 983 insertions(+)
++ create mode 100644 drivers/mfd/iei-wt61p803-puzzle.c
++ create mode 100644 include/linux/mfd/iei-wt61p803-puzzle.h
++
++--- a/drivers/mfd/Kconfig
+++++ b/drivers/mfd/Kconfig
++@@ -2187,6 +2187,15 @@ config SGI_MFD_IOC3
++ 	  If you have an SGI Origin, Octane, or a PCI IOC3 card,
++ 	  then say Y. Otherwise say N.
++ 
+++config MFD_IEI_WT61P803_PUZZLE
+++	tristate "IEI WT61P803 PUZZLE MCU driver"
+++	depends on SERIAL_DEV_BUS
+++	select MFD_CORE
+++	help
+++	  IEI WT61P803 PUZZLE is a system power management microcontroller
+++	  used for fan control, temperature sensor reading, LED control
+++	  and system identification.
+++
++ config MFD_INTEL_M10_BMC
++ 	tristate "Intel MAX 10 Board Management Controller"
++ 	depends on SPI_MASTER
++--- a/drivers/mfd/Makefile
+++++ b/drivers/mfd/Makefile
++@@ -237,6 +237,7 @@ obj-$(CONFIG_MFD_DLN2)		+= dln2.o
++ obj-$(CONFIG_MFD_RT4831)	+= rt4831.o
++ obj-$(CONFIG_MFD_RT5033)	+= rt5033.o
++ obj-$(CONFIG_MFD_SKY81452)	+= sky81452.o
+++obj-$(CONFIG_MFD_IEI_WT61P803_PUZZLE)	+= iei-wt61p803-puzzle.o
++ 
++ intel-soc-pmic-objs		:= intel_soc_pmic_core.o intel_soc_pmic_crc.o
++ obj-$(CONFIG_INTEL_SOC_PMIC)	+= intel-soc-pmic.o
++--- /dev/null
+++++ b/drivers/mfd/iei-wt61p803-puzzle.c
++@@ -0,0 +1,908 @@
+++// SPDX-License-Identifier: GPL-2.0-only
+++/* IEI WT61P803 PUZZLE MCU Driver
+++ * System management microcontroller for fan control, temperature sensor reading,
+++ * LED control and system identification on IEI Puzzle series ARM-based appliances.
+++ *
+++ * Copyright (C) 2020 Sartura Ltd.
+++ * Author: Luka Kovacic <luka.kovacic@sartura.hr>
+++ */
+++
+++#include <linux/atomic.h>
+++#include <linux/delay.h>
+++#include <linux/export.h>
+++#include <linux/init.h>
+++#include <linux/kernel.h>
+++#include <linux/mfd/core.h>
+++#include <linux/mfd/iei-wt61p803-puzzle.h>
+++#include <linux/mod_devicetable.h>
+++#include <linux/module.h>
+++#include <linux/of_platform.h>
+++#include <linux/property.h>
+++#include <linux/sched.h>
+++#include <linux/serdev.h>
+++#include <linux/slab.h>
+++#include <linux/sysfs.h>
+++#include <asm/unaligned.h>
+++
+++/* start, payload and XOR checksum at end */
+++#define IEI_WT61P803_PUZZLE_MAX_COMMAND_LENGTH	(1 + 20 + 1)
+++#define IEI_WT61P803_PUZZLE_RESP_BUF_SIZE	512
+++
+++#define IEI_WT61P803_PUZZLE_MAC_LENGTH			17
+++#define IEI_WT61P803_PUZZLE_SN_LENGTH			36
+++#define IEI_WT61P803_PUZZLE_VERSION_LENGTH		 6
+++#define IEI_WT61P803_PUZZLE_BUILD_INFO_LENGTH		16
+++#define IEI_WT61P803_PUZZLE_PROTOCOL_VERSION_LENGTH	 8
+++#define IEI_WT61P803_PUZZLE_NB_MAC			 8
+++
+++/* Use HZ as a timeout value throughout the driver */
+++#define IEI_WT61P803_PUZZLE_GENERAL_TIMEOUT HZ
+++
+++enum iei_wt61p803_puzzle_attribute_type {
+++	IEI_WT61P803_PUZZLE_VERSION,
+++	IEI_WT61P803_PUZZLE_BUILD_INFO,
+++	IEI_WT61P803_PUZZLE_BOOTLOADER_MODE,
+++	IEI_WT61P803_PUZZLE_PROTOCOL_VERSION,
+++	IEI_WT61P803_PUZZLE_SERIAL_NUMBER,
+++	IEI_WT61P803_PUZZLE_MAC_ADDRESS,
+++	IEI_WT61P803_PUZZLE_AC_RECOVERY_STATUS,
+++	IEI_WT61P803_PUZZLE_POWER_LOSS_RECOVERY,
+++	IEI_WT61P803_PUZZLE_POWER_STATUS,
+++};
+++
+++struct iei_wt61p803_puzzle_device_attribute {
+++	struct device_attribute dev_attr;
+++	enum iei_wt61p803_puzzle_attribute_type type;
+++	u8 index;
+++};
+++
+++/**
+++ * struct iei_wt61p803_puzzle_mcu_status - MCU flags state
+++ * @ac_recovery_status_flag:	AC Recovery Status Flag
+++ * @power_loss_recovery:	System recovery after power loss
+++ * @power_status:		System Power-on Method
+++ */
+++struct iei_wt61p803_puzzle_mcu_status {
+++	u8 ac_recovery_status_flag;
+++	u8 power_loss_recovery;
+++	u8 power_status;
+++};
+++
+++/**
+++ * struct iei_wt61p803_puzzle_reply - MCU reply
+++ * @size:	Size of the MCU reply
+++ * @data:	Full MCU reply buffer
+++ * @state:	Current state of the packet
+++ * @received:	Was the response fullfilled
+++ */
+++struct iei_wt61p803_puzzle_reply {
+++	size_t size;
+++	unsigned char data[IEI_WT61P803_PUZZLE_RESP_BUF_SIZE];
+++	struct completion received;
+++};
+++
+++/**
+++ * struct iei_wt61p803_puzzle_mcu_version - MCU version status
+++ * @version:		Primary firmware version
+++ * @build_info:		Build date and time
+++ * @bootloader_mode:	Status of the MCU operation
+++ * @protocol_version:	MCU communication protocol version
+++ * @serial_number:	Device factory serial number
+++ * @mac_address:	Device factory MAC addresses
+++ *
+++ * Last element of arrays is reserved for '\0'.
+++ */
+++struct iei_wt61p803_puzzle_mcu_version {
+++	char version[IEI_WT61P803_PUZZLE_VERSION_LENGTH + 1];
+++	char build_info[IEI_WT61P803_PUZZLE_BUILD_INFO_LENGTH + 1];
+++	bool bootloader_mode;
+++	char protocol_version[IEI_WT61P803_PUZZLE_PROTOCOL_VERSION_LENGTH + 1];
+++	char serial_number[IEI_WT61P803_PUZZLE_SN_LENGTH + 1];
+++	char mac_address[IEI_WT61P803_PUZZLE_NB_MAC][IEI_WT61P803_PUZZLE_MAC_LENGTH + 1];
+++};
+++
+++/**
+++ * struct iei_wt61p803_puzzle - IEI WT61P803 PUZZLE MCU Driver
+++ * @serdev:		Pointer to underlying serdev device
+++ * @dev:		Pointer to underlying dev device
+++ * @reply_lock:		Reply mutex lock
+++ * @reply:		Pointer to the iei_wt61p803_puzzle_reply struct
+++ * @version:		MCU version related data
+++ * @status:		MCU status related data
+++ * @response_buffer	Command response buffer allocation
+++ * @lock		General member mutex lock
+++ */
+++struct iei_wt61p803_puzzle {
+++	struct serdev_device *serdev;
+++	struct device *dev;
+++	struct mutex reply_lock; /* lock to prevent multiple firmware calls */
+++	struct iei_wt61p803_puzzle_reply *reply;
+++	struct iei_wt61p803_puzzle_mcu_version version;
+++	struct iei_wt61p803_puzzle_mcu_status status;
+++	unsigned char response_buffer[IEI_WT61P803_PUZZLE_BUF_SIZE];
+++	struct mutex lock; /* lock to protect response buffer */
+++};
+++
+++static unsigned char iei_wt61p803_puzzle_checksum(unsigned char *buf, size_t len)
+++{
+++	unsigned char checksum = 0;
+++	size_t i;
+++
+++	for (i = 0; i < len; i++)
+++		checksum ^= buf[i];
+++	return checksum;
+++}
+++
+++static int iei_wt61p803_puzzle_process_resp(struct iei_wt61p803_puzzle *mcu,
+++					    const unsigned char *raw_resp_data, size_t size)
+++{
+++	unsigned char checksum;
+++
+++	/* Check the incoming frame header */
+++	if (!(raw_resp_data[0] == IEI_WT61P803_PUZZLE_CMD_HEADER_START ||
+++	      raw_resp_data[0] == IEI_WT61P803_PUZZLE_CMD_HEADER_START_OTHER ||
+++	     (raw_resp_data[0] == IEI_WT61P803_PUZZLE_CMD_HEADER_EEPROM &&
+++	      raw_resp_data[1] == IEI_WT61P803_PUZZLE_CMD_EEPROM_READ))) {
+++		if (mcu->reply->size + size >= sizeof(mcu->reply->data))
+++			return -EIO;
+++
+++		/* Append the frame to existing data */
+++		memcpy(mcu->reply->data + mcu->reply->size, raw_resp_data, size);
+++		mcu->reply->size += size;
+++	} else {
+++		if (size >= sizeof(mcu->reply->data))
+++			return -EIO;
+++
+++		/* Start processing a new frame */
+++		memcpy(mcu->reply->data, raw_resp_data, size);
+++		mcu->reply->size = size;
+++	}
+++
+++	checksum = iei_wt61p803_puzzle_checksum(mcu->reply->data, mcu->reply->size - 1);
+++	if (checksum != mcu->reply->data[mcu->reply->size - 1]) {
+++		/* The checksum isn't matched yet, wait for new frames */
+++		return size;
+++	}
+++
+++	/* Received all the data */
+++	complete(&mcu->reply->received);
+++
+++	return size;
+++}
+++
+++static int iei_wt61p803_puzzle_recv_buf(struct serdev_device *serdev,
+++					const unsigned char *data, size_t size)
+++{
+++	struct iei_wt61p803_puzzle *mcu = serdev_device_get_drvdata(serdev);
+++	int ret;
+++
+++	ret = iei_wt61p803_puzzle_process_resp(mcu, data, size);
+++	/* Return the number of processed bytes if function returns error,
+++	 * discard the remaining incoming data, since the frame this data
+++	 * belongs to is broken anyway
+++	 */
+++	if (ret < 0)
+++		return size;
+++
+++	return ret;
+++}
+++
+++static const struct serdev_device_ops iei_wt61p803_puzzle_serdev_device_ops = {
+++	.receive_buf  = iei_wt61p803_puzzle_recv_buf,
+++	.write_wakeup = serdev_device_write_wakeup,
+++};
+++
+++/**
+++ * iei_wt61p803_puzzle_write_command_watchdog() - Watchdog of the normal cmd
+++ * @mcu: Pointer to the iei_wt61p803_puzzle core MFD struct
+++ * @cmd: Pointer to the char array to send (size should be content + 1 (xor))
+++ * @size: Size of the cmd char array
+++ * @reply_data: Pointer to the reply/response data array (should be allocated)
+++ * @reply_size: Pointer to size_t (size of reply_data)
+++ * @retry_count: Number of times to retry sending the command to the MCU
+++ */
+++int iei_wt61p803_puzzle_write_command_watchdog(struct iei_wt61p803_puzzle *mcu,
+++					       unsigned char *cmd, size_t size,
+++					       unsigned char *reply_data,
+++					       size_t *reply_size, int retry_count)
+++{
+++	struct device *dev = &mcu->serdev->dev;
+++	int ret, i;
+++
+++	for (i = 0; i < retry_count; i++) {
+++		ret = iei_wt61p803_puzzle_write_command(mcu, cmd, size,
+++							reply_data, reply_size);
+++		if (ret != -ETIMEDOUT)
+++			return ret;
+++	}
+++
+++	dev_err(dev, "Command response timed out. Retries: %d\n", retry_count);
+++
+++	return -ETIMEDOUT;
+++}
+++EXPORT_SYMBOL_GPL(iei_wt61p803_puzzle_write_command_watchdog);
+++
+++/**
+++ * iei_wt61p803_puzzle_write_command() - Send a structured command to the MCU
+++ * @mcu: Pointer to the iei_wt61p803_puzzle core MFD struct
+++ * @cmd: Pointer to the char array to send (size should be content + 1 (xor))
+++ * @size: Size of the cmd char array
+++ * @reply_data: Pointer to the reply/response data array (should be allocated)
+++ *
+++ * Sends a structured command to the MCU.
+++ */
+++int iei_wt61p803_puzzle_write_command(struct iei_wt61p803_puzzle *mcu,
+++				      unsigned char *cmd, size_t size,
+++				      unsigned char *reply_data,
+++				      size_t *reply_size)
+++{
+++	struct device *dev = &mcu->serdev->dev;
+++	int ret;
+++
+++	if (size <= 1 || size > IEI_WT61P803_PUZZLE_MAX_COMMAND_LENGTH)
+++		return -EINVAL;
+++
+++	mutex_lock(&mcu->reply_lock);
+++
+++	cmd[size - 1] = iei_wt61p803_puzzle_checksum(cmd, size - 1);
+++
+++	/* Initialize reply struct */
+++	reinit_completion(&mcu->reply->received);
+++	mcu->reply->size = 0;
+++	usleep_range(2000, 10000);
+++	serdev_device_write_flush(mcu->serdev);
+++	ret = serdev_device_write_buf(mcu->serdev, cmd, size);
+++	if (ret < 0)
+++		goto exit;
+++
+++	serdev_device_wait_until_sent(mcu->serdev, IEI_WT61P803_PUZZLE_GENERAL_TIMEOUT);
+++	ret = wait_for_completion_timeout(&mcu->reply->received,
+++					  IEI_WT61P803_PUZZLE_GENERAL_TIMEOUT);
+++	if (ret == 0) {
+++		dev_err(dev, "Command reply receive timeout\n");
+++		ret = -ETIMEDOUT;
+++		goto exit;
+++	}
+++
+++	*reply_size = mcu->reply->size;
+++	/* Copy the received data, as it will not be available after a new frame is received */
+++	memcpy(reply_data, mcu->reply->data, mcu->reply->size);
+++	ret = 0;
+++exit:
+++	mutex_unlock(&mcu->reply_lock);
+++	return ret;
+++}
+++EXPORT_SYMBOL_GPL(iei_wt61p803_puzzle_write_command);
+++
+++static int iei_wt61p803_puzzle_buzzer(struct iei_wt61p803_puzzle *mcu, bool long_beep)
+++{
+++	unsigned char *resp_buf = mcu->response_buffer;
+++	unsigned char buzzer_cmd[4] = {};
+++	size_t reply_size;
+++	int ret;
+++
+++	buzzer_cmd[0] = IEI_WT61P803_PUZZLE_CMD_HEADER_START;
+++	buzzer_cmd[1] = IEI_WT61P803_PUZZLE_CMD_FUNCTION_SINGLE;
+++	buzzer_cmd[2] = long_beep ? '3' : '2'; /* Buzzer 1.5 / 0.5 second beep */
+++
+++	mutex_lock(&mcu->lock);
+++	ret = iei_wt61p803_puzzle_write_command(mcu, buzzer_cmd, sizeof(buzzer_cmd),
+++						resp_buf, &reply_size);
+++	if (ret)
+++		goto exit;
+++
+++	if (reply_size != 3) {
+++		ret = -EIO;
+++		goto exit;
+++	}
+++
+++	if (!(resp_buf[0] == IEI_WT61P803_PUZZLE_CMD_HEADER_START &&
+++	      resp_buf[1] == IEI_WT61P803_PUZZLE_CMD_RESPONSE_OK &&
+++	      resp_buf[2] == IEI_WT61P803_PUZZLE_CHECKSUM_RESPONSE_OK)) {
+++		ret = -EPROTO;
+++		goto exit;
+++	}
+++exit:
+++	mutex_unlock(&mcu->lock);
+++	return ret;
+++}
+++
+++static int iei_wt61p803_puzzle_get_version(struct iei_wt61p803_puzzle *mcu)
+++{
+++	unsigned char version_cmd[3] = {
+++		IEI_WT61P803_PUZZLE_CMD_HEADER_START_OTHER,
+++		IEI_WT61P803_PUZZLE_CMD_OTHER_VERSION,
+++	};
+++	unsigned char build_info_cmd[3] = {
+++		IEI_WT61P803_PUZZLE_CMD_HEADER_START_OTHER,
+++		IEI_WT61P803_PUZZLE_CMD_OTHER_BUILD,
+++	};
+++	unsigned char bootloader_mode_cmd[3] = {
+++		IEI_WT61P803_PUZZLE_CMD_HEADER_START_OTHER,
+++		IEI_WT61P803_PUZZLE_CMD_OTHER_BOOTLOADER_MODE,
+++	};
+++	unsigned char protocol_version_cmd[3] = {
+++		IEI_WT61P803_PUZZLE_CMD_HEADER_START_OTHER,
+++		IEI_WT61P803_PUZZLE_CMD_OTHER_PROTOCOL_VERSION,
+++	};
+++	unsigned char *rb = mcu->response_buffer;
+++	size_t reply_size;
+++	int ret;
+++
+++	mutex_lock(&mcu->lock);
+++
+++	ret = iei_wt61p803_puzzle_write_command(mcu, version_cmd, sizeof(version_cmd),
+++						rb, &reply_size);
+++	if (ret)
+++		goto err;
+++	if (reply_size < 7) {
+++		ret = -EIO;
+++		goto err;
+++	}
+++	sprintf(mcu->version.version, "v%c.%.3s", rb[2], &rb[3]);
+++
+++	ret = iei_wt61p803_puzzle_write_command(mcu, build_info_cmd,
+++						sizeof(build_info_cmd),	rb,
+++						&reply_size);
+++	if (ret)
+++		goto err;
+++	if (reply_size < 15) {
+++		ret = -EIO;
+++		goto err;
+++	}
+++	sprintf(mcu->version.build_info, "%c%c/%c%c/%.4s %c%c:%c%c",
+++		rb[8], rb[9], rb[6], rb[7], &rb[2], rb[10], rb[11],
+++		rb[12], rb[13]);
+++
+++	ret = iei_wt61p803_puzzle_write_command(mcu, bootloader_mode_cmd,
+++						sizeof(bootloader_mode_cmd), rb,
+++						&reply_size);
+++	if (ret)
+++		goto err;
+++	if (reply_size < 4) {
+++		ret = -EIO;
+++		goto err;
+++	}
+++	if (rb[2] == IEI_WT61P803_PUZZLE_CMD_OTHER_MODE_APPS)
+++		mcu->version.bootloader_mode = false;
+++	else if (rb[2] == IEI_WT61P803_PUZZLE_CMD_OTHER_MODE_BOOTLOADER)
+++		mcu->version.bootloader_mode = true;
+++
+++	ret = iei_wt61p803_puzzle_write_command(mcu, protocol_version_cmd,
+++						sizeof(protocol_version_cmd), rb,
+++						&reply_size);
+++	if (ret)
+++		goto err;
+++	if (reply_size < 9) {
+++		ret = -EIO;
+++		goto err;
+++	}
+++	sprintf(mcu->version.protocol_version, "v%c.%c%c%c%c%c",
+++		rb[7], rb[6], rb[5], rb[4], rb[3], rb[2]);
+++err:
+++	mutex_unlock(&mcu->lock);
+++	return ret;
+++}
+++
+++static int iei_wt61p803_puzzle_get_mcu_status(struct iei_wt61p803_puzzle *mcu)
+++{
+++	unsigned char mcu_status_cmd[5] = {
+++		IEI_WT61P803_PUZZLE_CMD_HEADER_START,
+++		IEI_WT61P803_PUZZLE_CMD_FUNCTION_OTHER,
+++		IEI_WT61P803_PUZZLE_CMD_FUNCTION_OTHER_STATUS,
+++		IEI_WT61P803_PUZZLE_CMD_FUNCTION_OTHER_STATUS,
+++	};
+++	unsigned char *resp_buf = mcu->response_buffer;
+++	size_t reply_size;
+++	int ret;
+++
+++	mutex_lock(&mcu->lock);
+++	ret = iei_wt61p803_puzzle_write_command(mcu, mcu_status_cmd, sizeof(mcu_status_cmd),
+++						resp_buf, &reply_size);
+++	if (ret)
+++		goto exit;
+++	if (reply_size < 20) {
+++		ret = -EIO;
+++		goto exit;
+++	}
+++
+++	/* Response format:
+++	 * (IDX	RESPONSE)
+++	 * 0	@
+++	 * 1	O
+++	 * 2	S
+++	 * 3	S
+++	 * ...
+++	 * 5	AC Recovery Status Flag
+++	 * ...
+++	 * 10	Power Loss Recovery
+++	 * ...
+++	 * 19	Power Status (system power on method)
+++	 * 20	XOR checksum
+++	 */
+++	if (resp_buf[0] == IEI_WT61P803_PUZZLE_CMD_HEADER_START &&
+++	    resp_buf[1] == IEI_WT61P803_PUZZLE_CMD_FUNCTION_OTHER &&
+++	    resp_buf[2] == IEI_WT61P803_PUZZLE_CMD_FUNCTION_OTHER_STATUS &&
+++	    resp_buf[3] == IEI_WT61P803_PUZZLE_CMD_FUNCTION_OTHER_STATUS) {
+++		mcu->status.ac_recovery_status_flag = resp_buf[5];
+++		mcu->status.power_loss_recovery = resp_buf[10];
+++		mcu->status.power_status = resp_buf[19];
+++	}
+++exit:
+++	mutex_unlock(&mcu->lock);
+++	return ret;
+++}
+++
+++static int iei_wt61p803_puzzle_get_serial_number(struct iei_wt61p803_puzzle *mcu)
+++{
+++	unsigned char *resp_buf = mcu->response_buffer;
+++	unsigned char serial_number_cmd[5] = {
+++		IEI_WT61P803_PUZZLE_CMD_HEADER_EEPROM,
+++		IEI_WT61P803_PUZZLE_CMD_EEPROM_READ,
+++		0x00,	/* EEPROM read address */
+++		0x24,	/* Data length */
+++	};
+++	size_t reply_size;
+++	int ret;
+++
+++	mutex_lock(&mcu->lock);
+++	ret = iei_wt61p803_puzzle_write_command(mcu, serial_number_cmd,
+++						sizeof(serial_number_cmd),
+++						resp_buf, &reply_size);
+++	if (ret)
+++		goto err;
+++
+++	if (reply_size < IEI_WT61P803_PUZZLE_SN_LENGTH + 4) {
+++		ret = -EIO;
+++		goto err;
+++	}
+++
+++	sprintf(mcu->version.serial_number, "%.*s",
+++		IEI_WT61P803_PUZZLE_SN_LENGTH, resp_buf + 4);
+++err:
+++	mutex_unlock(&mcu->lock);
+++	return ret;
+++}
+++
+++static int iei_wt61p803_puzzle_write_serial_number(struct iei_wt61p803_puzzle *mcu,
+++						   unsigned char serial_number[36])
+++{
+++	unsigned char *resp_buf = mcu->response_buffer;
+++	unsigned char serial_number_header[4] = {
+++		IEI_WT61P803_PUZZLE_CMD_HEADER_EEPROM,
+++		IEI_WT61P803_PUZZLE_CMD_EEPROM_WRITE,
+++		0x00,	/* EEPROM write address */
+++		0xC,	/* Data length */
+++	};
+++	unsigned char serial_number_cmd[4 + 12 + 1]; /* header, serial number, XOR checksum */
+++	int ret, sn_counter;
+++	size_t reply_size;
+++
+++	/* The MCU can only handle 22 byte messages, send the S/N in 12 byte chunks */
+++	mutex_lock(&mcu->lock);
+++	for (sn_counter = 0; sn_counter < 3; sn_counter++) {
+++		serial_number_header[2] = 0x0 + 0xC * sn_counter;
+++
+++		memcpy(serial_number_cmd, serial_number_header, sizeof(serial_number_header));
+++		memcpy(serial_number_cmd + sizeof(serial_number_header),
+++		       serial_number + 0xC * sn_counter, 0xC);
+++
+++		ret = iei_wt61p803_puzzle_write_command(mcu, serial_number_cmd,
+++							sizeof(serial_number_cmd),
+++							resp_buf, &reply_size);
+++		if (ret)
+++			goto err;
+++		if (reply_size != 3) {
+++			ret = -EIO;
+++			goto err;
+++		}
+++		if (!(resp_buf[0] == IEI_WT61P803_PUZZLE_CMD_HEADER_START &&
+++		      resp_buf[1] == IEI_WT61P803_PUZZLE_CMD_RESPONSE_OK &&
+++		      resp_buf[2] == IEI_WT61P803_PUZZLE_CHECKSUM_RESPONSE_OK)) {
+++			ret = -EPROTO;
+++			goto err;
+++		}
+++	}
+++
+++	sprintf(mcu->version.serial_number, "%.*s",
+++		IEI_WT61P803_PUZZLE_SN_LENGTH, serial_number);
+++err:
+++	mutex_unlock(&mcu->lock);
+++	return ret;
+++}
+++
+++static int iei_wt61p803_puzzle_get_mac_address(struct iei_wt61p803_puzzle *mcu, int index)
+++{
+++	unsigned char *resp_buf = mcu->response_buffer;
+++	unsigned char mac_address_cmd[5] = {
+++		IEI_WT61P803_PUZZLE_CMD_HEADER_EEPROM,
+++		IEI_WT61P803_PUZZLE_CMD_EEPROM_READ,
+++		0x00,	/* EEPROM read address */
+++		0x11,	/* Data length */
+++	};
+++	size_t reply_size;
+++	int ret;
+++
+++	mutex_lock(&mcu->lock);
+++	mac_address_cmd[2] = 0x24 + 0x11 * index;
+++
+++	ret = iei_wt61p803_puzzle_write_command(mcu, mac_address_cmd,
+++						sizeof(mac_address_cmd),
+++						resp_buf, &reply_size);
+++	if (ret)
+++		goto err;
+++
+++	if (reply_size < 22) {
+++		ret = -EIO;
+++		goto err;
+++	}
+++
+++	sprintf(mcu->version.mac_address[index], "%.*s",
+++		IEI_WT61P803_PUZZLE_MAC_LENGTH, resp_buf + 4);
+++err:
+++	mutex_unlock(&mcu->lock);
+++	return ret;
+++}
+++
+++static int
+++iei_wt61p803_puzzle_write_mac_address(struct iei_wt61p803_puzzle *mcu,
+++				      unsigned char mac_address[IEI_WT61P803_PUZZLE_MAC_LENGTH],
+++				      int mac_address_idx)
+++{
+++	unsigned char mac_address_cmd[4 + IEI_WT61P803_PUZZLE_MAC_LENGTH + 1];
+++	unsigned char *resp_buf = mcu->response_buffer;
+++	unsigned char mac_address_header[4] = {
+++		IEI_WT61P803_PUZZLE_CMD_HEADER_EEPROM,
+++		IEI_WT61P803_PUZZLE_CMD_EEPROM_WRITE,
+++		0x00,	/* EEPROM write address */
+++		0x11,	/* Data length */
+++	};
+++	size_t reply_size;
+++	int ret;
+++
+++	if (mac_address_idx < 0 || mac_address_idx >= IEI_WT61P803_PUZZLE_NB_MAC)
+++		return -EINVAL;
+++
+++	mac_address_header[2] = 0x24 + 0x11 * mac_address_idx;
+++
+++	/* Concat mac_address_header, mac_address to mac_address_cmd */
+++	memcpy(mac_address_cmd, mac_address_header, sizeof(mac_address_header));
+++	memcpy(mac_address_cmd + sizeof(mac_address_header), mac_address,
+++	       IEI_WT61P803_PUZZLE_MAC_LENGTH);
+++
+++	mutex_lock(&mcu->lock);
+++	ret = iei_wt61p803_puzzle_write_command(mcu, mac_address_cmd,
+++						sizeof(mac_address_cmd),
+++						resp_buf, &reply_size);
+++	if (ret)
+++		goto err;
+++	if (reply_size != 3) {
+++		ret = -EIO;
+++		goto err;
+++	}
+++	if (!(resp_buf[0] == IEI_WT61P803_PUZZLE_CMD_HEADER_START &&
+++	      resp_buf[1] == IEI_WT61P803_PUZZLE_CMD_RESPONSE_OK &&
+++	      resp_buf[2] == IEI_WT61P803_PUZZLE_CHECKSUM_RESPONSE_OK)) {
+++		ret = -EPROTO;
+++		goto err;
+++	}
+++
+++	sprintf(mcu->version.mac_address[mac_address_idx], "%.*s",
+++		IEI_WT61P803_PUZZLE_MAC_LENGTH, mac_address);
+++err:
+++	mutex_unlock(&mcu->lock);
+++	return ret;
+++}
+++
+++static int iei_wt61p803_puzzle_write_power_loss_recovery(struct iei_wt61p803_puzzle *mcu,
+++							 int power_loss_recovery_action)
+++{
+++	unsigned char *resp_buf = mcu->response_buffer;
+++	unsigned char power_loss_recovery_cmd[5] = {};
+++	size_t reply_size;
+++	int ret;
+++
+++	if (power_loss_recovery_action < 0 || power_loss_recovery_action > 4)
+++		return -EINVAL;
+++
+++	power_loss_recovery_cmd[0] = IEI_WT61P803_PUZZLE_CMD_HEADER_START;
+++	power_loss_recovery_cmd[1] = IEI_WT61P803_PUZZLE_CMD_FUNCTION_OTHER;
+++	power_loss_recovery_cmd[2] = IEI_WT61P803_PUZZLE_CMD_FUNCTION_OTHER_POWER_LOSS;
+++	power_loss_recovery_cmd[3] = hex_asc[power_loss_recovery_action];
+++
+++	mutex_lock(&mcu->lock);
+++	ret = iei_wt61p803_puzzle_write_command(mcu, power_loss_recovery_cmd,
+++						sizeof(power_loss_recovery_cmd),
+++						resp_buf, &reply_size);
+++	if (ret)
+++		goto exit;
+++	mcu->status.power_loss_recovery = power_loss_recovery_action;
+++exit:
+++	mutex_unlock(&mcu->lock);
+++	return ret;
+++}
+++
+++#define to_puzzle_dev_attr(_attr) \
+++	container_of(_attr, struct iei_wt61p803_puzzle_device_attribute, dev_attr)
+++
+++static ssize_t show_output(struct device *dev,
+++			   struct device_attribute *attr, char *buf)
+++{
+++	struct iei_wt61p803_puzzle *mcu = dev_get_drvdata(dev);
+++	struct iei_wt61p803_puzzle_device_attribute *pattr = to_puzzle_dev_attr(attr);
+++	int ret;
+++
+++	switch (pattr->type) {
+++	case IEI_WT61P803_PUZZLE_VERSION:
+++		return scnprintf(buf, PAGE_SIZE, "%s\n", mcu->version.version);
+++	case IEI_WT61P803_PUZZLE_BUILD_INFO:
+++		return scnprintf(buf, PAGE_SIZE, "%s\n", mcu->version.build_info);
+++	case IEI_WT61P803_PUZZLE_BOOTLOADER_MODE:
+++		return scnprintf(buf, PAGE_SIZE, "%d\n", mcu->version.bootloader_mode);
+++	case IEI_WT61P803_PUZZLE_PROTOCOL_VERSION:
+++		return scnprintf(buf, PAGE_SIZE, "%s\n", mcu->version.protocol_version);
+++	case IEI_WT61P803_PUZZLE_SERIAL_NUMBER:
+++		ret = iei_wt61p803_puzzle_get_serial_number(mcu);
+++		if (!ret)
+++			ret = scnprintf(buf, PAGE_SIZE, "%s\n", mcu->version.serial_number);
+++		else
+++			ret = 0;
+++		return ret;
+++	case IEI_WT61P803_PUZZLE_MAC_ADDRESS:
+++		ret = iei_wt61p803_puzzle_get_mac_address(mcu, pattr->index);
+++		if (!ret)
+++			ret = scnprintf(buf, PAGE_SIZE, "%s\n",
+++					mcu->version.mac_address[pattr->index]);
+++		else
+++			ret = 0;
+++		return ret;
+++	case IEI_WT61P803_PUZZLE_AC_RECOVERY_STATUS:
+++	case IEI_WT61P803_PUZZLE_POWER_LOSS_RECOVERY:
+++	case IEI_WT61P803_PUZZLE_POWER_STATUS:
+++		ret = iei_wt61p803_puzzle_get_mcu_status(mcu);
+++		if (ret)
+++			return ret;
+++
+++		mutex_lock(&mcu->lock);
+++		switch (pattr->type) {
+++		case IEI_WT61P803_PUZZLE_AC_RECOVERY_STATUS:
+++			ret = scnprintf(buf, PAGE_SIZE, "%x\n",
+++					mcu->status.ac_recovery_status_flag);
+++			break;
+++		case IEI_WT61P803_PUZZLE_POWER_LOSS_RECOVERY:
+++			ret = scnprintf(buf, PAGE_SIZE, "%x\n", mcu->status.power_loss_recovery);
+++			break;
+++		case IEI_WT61P803_PUZZLE_POWER_STATUS:
+++			ret = scnprintf(buf, PAGE_SIZE, "%x\n", mcu->status.power_status);
+++			break;
+++		default:
+++			ret = 0;
+++			break;
+++		}
+++		mutex_unlock(&mcu->lock);
+++		return ret;
+++	default:
+++		return 0;
+++	}
+++
+++	return 0;
+++}
+++
+++static ssize_t store_output(struct device *dev,
+++			    struct device_attribute *attr,
+++			    const char *buf, size_t len)
+++{
+++	unsigned char serial_number[IEI_WT61P803_PUZZLE_SN_LENGTH];
+++	unsigned char mac_address[IEI_WT61P803_PUZZLE_MAC_LENGTH];
+++	struct iei_wt61p803_puzzle *mcu = dev_get_drvdata(dev);
+++	struct iei_wt61p803_puzzle_device_attribute *pattr = to_puzzle_dev_attr(attr);
+++	int power_loss_recovery_action = 0;
+++	int ret;
+++
+++	switch (pattr->type) {
+++	case IEI_WT61P803_PUZZLE_SERIAL_NUMBER:
+++		if (len != (size_t)(IEI_WT61P803_PUZZLE_SN_LENGTH + 1))
+++			return -EINVAL;
+++		memcpy(serial_number, buf, sizeof(serial_number));
+++		ret = iei_wt61p803_puzzle_write_serial_number(mcu, serial_number);
+++		if (ret)
+++			return ret;
+++		return len;
+++	case IEI_WT61P803_PUZZLE_MAC_ADDRESS:
+++		if (len != (size_t)(IEI_WT61P803_PUZZLE_MAC_LENGTH + 1))
+++			return -EINVAL;
+++
+++		memcpy(mac_address, buf, sizeof(mac_address));
+++
+++		if (strlen(attr->attr.name) != 13)
+++			return -EIO;
+++
+++		ret = iei_wt61p803_puzzle_write_mac_address(mcu, mac_address, pattr->index);
+++		if (ret)
+++			return ret;
+++		return len;
+++	case IEI_WT61P803_PUZZLE_POWER_LOSS_RECOVERY:
+++		ret = kstrtoint(buf, 10, &power_loss_recovery_action);
+++		if (ret)
+++			return ret;
+++		ret = iei_wt61p803_puzzle_write_power_loss_recovery(mcu,
+++								    power_loss_recovery_action);
+++		if (ret)
+++			return ret;
+++		return len;
+++	default:
+++		return -EINVAL;
+++	}
+++
+++	return 0;
+++}
+++
+++#define IEI_WT61P803_PUZZLE_ATTR(_name, _mode, _show, _store, _type, _index) \
+++	struct iei_wt61p803_puzzle_device_attribute dev_attr_##_name = \
+++		{ .dev_attr	= __ATTR(_name, _mode, _show, _store), \
+++		  .type		= _type, \
+++		  .index	= _index }
+++
+++#define IEI_WT61P803_PUZZLE_ATTR_RO(_name, _type, _id) \
+++	IEI_WT61P803_PUZZLE_ATTR(_name, 0444, show_output, NULL, _type, _id)
+++
+++#define IEI_WT61P803_PUZZLE_ATTR_RW(_name, _type, _id) \
+++	IEI_WT61P803_PUZZLE_ATTR(_name, 0644, show_output, store_output, _type, _id)
+++
+++static IEI_WT61P803_PUZZLE_ATTR_RO(version, IEI_WT61P803_PUZZLE_VERSION, 0);
+++static IEI_WT61P803_PUZZLE_ATTR_RO(build_info, IEI_WT61P803_PUZZLE_BUILD_INFO, 0);
+++static IEI_WT61P803_PUZZLE_ATTR_RO(bootloader_mode, IEI_WT61P803_PUZZLE_BOOTLOADER_MODE, 0);
+++static IEI_WT61P803_PUZZLE_ATTR_RO(protocol_version, IEI_WT61P803_PUZZLE_PROTOCOL_VERSION, 0);
+++static IEI_WT61P803_PUZZLE_ATTR_RW(serial_number, IEI_WT61P803_PUZZLE_SERIAL_NUMBER, 0);
+++static IEI_WT61P803_PUZZLE_ATTR_RW(mac_address_0, IEI_WT61P803_PUZZLE_MAC_ADDRESS, 0);
+++static IEI_WT61P803_PUZZLE_ATTR_RW(mac_address_1, IEI_WT61P803_PUZZLE_MAC_ADDRESS, 1);
+++static IEI_WT61P803_PUZZLE_ATTR_RW(mac_address_2, IEI_WT61P803_PUZZLE_MAC_ADDRESS, 2);
+++static IEI_WT61P803_PUZZLE_ATTR_RW(mac_address_3, IEI_WT61P803_PUZZLE_MAC_ADDRESS, 3);
+++static IEI_WT61P803_PUZZLE_ATTR_RW(mac_address_4, IEI_WT61P803_PUZZLE_MAC_ADDRESS, 4);
+++static IEI_WT61P803_PUZZLE_ATTR_RW(mac_address_5, IEI_WT61P803_PUZZLE_MAC_ADDRESS, 5);
+++static IEI_WT61P803_PUZZLE_ATTR_RW(mac_address_6, IEI_WT61P803_PUZZLE_MAC_ADDRESS, 6);
+++static IEI_WT61P803_PUZZLE_ATTR_RW(mac_address_7, IEI_WT61P803_PUZZLE_MAC_ADDRESS, 7);
+++static IEI_WT61P803_PUZZLE_ATTR_RO(ac_recovery_status, IEI_WT61P803_PUZZLE_AC_RECOVERY_STATUS, 0);
+++static IEI_WT61P803_PUZZLE_ATTR_RW(power_loss_recovery, IEI_WT61P803_PUZZLE_POWER_LOSS_RECOVERY, 0);
+++static IEI_WT61P803_PUZZLE_ATTR_RO(power_status, IEI_WT61P803_PUZZLE_POWER_STATUS, 0);
+++
+++static struct attribute *iei_wt61p803_puzzle_attrs[] = {
+++	&dev_attr_version.dev_attr.attr,
+++	&dev_attr_build_info.dev_attr.attr,
+++	&dev_attr_bootloader_mode.dev_attr.attr,
+++	&dev_attr_protocol_version.dev_attr.attr,
+++	&dev_attr_serial_number.dev_attr.attr,
+++	&dev_attr_mac_address_0.dev_attr.attr,
+++	&dev_attr_mac_address_1.dev_attr.attr,
+++	&dev_attr_mac_address_2.dev_attr.attr,
+++	&dev_attr_mac_address_3.dev_attr.attr,
+++	&dev_attr_mac_address_4.dev_attr.attr,
+++	&dev_attr_mac_address_5.dev_attr.attr,
+++	&dev_attr_mac_address_6.dev_attr.attr,
+++	&dev_attr_mac_address_7.dev_attr.attr,
+++	&dev_attr_ac_recovery_status.dev_attr.attr,
+++	&dev_attr_power_loss_recovery.dev_attr.attr,
+++	&dev_attr_power_status.dev_attr.attr,
+++	NULL
+++};
+++ATTRIBUTE_GROUPS(iei_wt61p803_puzzle);
+++
+++static int iei_wt61p803_puzzle_sysfs_create(struct device *dev,
+++					    struct iei_wt61p803_puzzle *mcu)
+++{
+++	int ret;
+++
+++	ret = sysfs_create_groups(&mcu->dev->kobj, iei_wt61p803_puzzle_groups);
+++	if (ret)
+++		mfd_remove_devices(mcu->dev);
+++
+++	return ret;
+++}
+++
+++static int iei_wt61p803_puzzle_sysfs_remove(struct device *dev,
+++					    struct iei_wt61p803_puzzle *mcu)
+++{
+++	/* Remove sysfs groups */
+++	sysfs_remove_groups(&mcu->dev->kobj, iei_wt61p803_puzzle_groups);
+++	mfd_remove_devices(mcu->dev);
+++
+++	return 0;
+++}
+++
+++static int iei_wt61p803_puzzle_probe(struct serdev_device *serdev)
+++{
+++	struct device *dev = &serdev->dev;
+++	struct iei_wt61p803_puzzle *mcu;
+++	u32 baud;
+++	int ret;
+++
+++	/* Read the baud rate from 'current-speed', because the MCU supports different rates */
+++	if (device_property_read_u32(dev, "current-speed", &baud)) {
+++		dev_err(dev,
+++			"'current-speed' is not specified in device node\n");
+++		return -EINVAL;
+++	}
+++	dev_dbg(dev, "Driver baud rate: %d\n", baud);
+++
+++	/* Allocate the memory */
+++	mcu = devm_kzalloc(dev, sizeof(*mcu), GFP_KERNEL);
+++	if (!mcu)
+++		return -ENOMEM;
+++
+++	mcu->reply = devm_kzalloc(dev, sizeof(*mcu->reply), GFP_KERNEL);
+++	if (!mcu->reply)
+++		return -ENOMEM;
+++
+++	/* Initialize device struct data */
+++	mcu->serdev = serdev;
+++	mcu->dev = dev;
+++	init_completion(&mcu->reply->received);
+++	mutex_init(&mcu->reply_lock);
+++	mutex_init(&mcu->lock);
+++
+++	/* Setup UART interface */
+++	serdev_device_set_drvdata(serdev, mcu);
+++	serdev_device_set_client_ops(serdev, &iei_wt61p803_puzzle_serdev_device_ops);
+++	ret = devm_serdev_device_open(dev, serdev);
+++	if (ret)
+++		return ret;
+++	serdev_device_set_baudrate(serdev, baud);
+++	serdev_device_set_flow_control(serdev, false);
+++	ret = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE);
+++	if (ret) {
+++		dev_err(dev, "Failed to set parity\n");
+++		return ret;
+++	}
+++
+++	ret = iei_wt61p803_puzzle_get_version(mcu);
+++	if (ret)
+++		return ret;
+++
+++	dev_dbg(dev, "MCU version: %s\n", mcu->version.version);
+++	dev_dbg(dev, "MCU firmware build info: %s\n", mcu->version.build_info);
+++	dev_dbg(dev, "MCU in bootloader mode: %s\n",
+++		mcu->version.bootloader_mode ? "true" : "false");
+++	dev_dbg(dev, "MCU protocol version: %s\n", mcu->version.protocol_version);
+++
+++	if (device_property_read_bool(dev, "enable-beep")) {
+++		ret = iei_wt61p803_puzzle_buzzer(mcu, false);
+++		if (ret)
+++			return ret;
+++	}
+++
+++	ret = iei_wt61p803_puzzle_sysfs_create(dev, mcu);
+++	if (ret)
+++		return ret;
+++
+++	return devm_of_platform_populate(dev);
+++}
+++
+++static void iei_wt61p803_puzzle_remove(struct serdev_device *serdev)
+++{
+++	struct device *dev = &serdev->dev;
+++	struct iei_wt61p803_puzzle *mcu = dev_get_drvdata(dev);
+++
+++	iei_wt61p803_puzzle_sysfs_remove(dev, mcu);
+++}
+++
+++static const struct of_device_id iei_wt61p803_puzzle_dt_ids[] = {
+++	{ .compatible = "iei,wt61p803-puzzle" },
+++	{ }
+++};
+++
+++MODULE_DEVICE_TABLE(of, iei_wt61p803_puzzle_dt_ids);
+++
+++static struct serdev_device_driver iei_wt61p803_puzzle_drv = {
+++	.probe			= iei_wt61p803_puzzle_probe,
+++	.remove			= iei_wt61p803_puzzle_remove,
+++	.driver = {
+++		.name		= "iei-wt61p803-puzzle",
+++		.of_match_table	= iei_wt61p803_puzzle_dt_ids,
+++	},
+++};
+++
+++module_serdev_device_driver(iei_wt61p803_puzzle_drv);
+++
+++MODULE_LICENSE("GPL v2");
+++MODULE_AUTHOR("Luka Kovacic <luka.kovacic@sartura.hr>");
+++MODULE_DESCRIPTION("IEI WT61P803 PUZZLE MCU Driver");
++--- /dev/null
+++++ b/include/linux/mfd/iei-wt61p803-puzzle.h
++@@ -0,0 +1,66 @@
+++/* SPDX-License-Identifier: GPL-2.0-only */
+++/* IEI WT61P803 PUZZLE MCU Driver
+++ * System management microcontroller for fan control, temperature sensor reading,
+++ * LED control and system identification on IEI Puzzle series ARM-based appliances.
+++ *
+++ * Copyright (C) 2020 Sartura Ltd.
+++ * Author: Luka Kovacic <luka.kovacic@sartura.hr>
+++ */
+++
+++#ifndef _MFD_IEI_WT61P803_PUZZLE_H_
+++#define _MFD_IEI_WT61P803_PUZZLE_H_
+++
+++#define IEI_WT61P803_PUZZLE_BUF_SIZE 512
+++
+++/* Command magic numbers */
+++#define IEI_WT61P803_PUZZLE_CMD_HEADER_START		0x40 /* @ */
+++#define IEI_WT61P803_PUZZLE_CMD_HEADER_START_OTHER	0x25 /* % */
+++#define IEI_WT61P803_PUZZLE_CMD_HEADER_EEPROM		0xF7
+++
+++#define IEI_WT61P803_PUZZLE_CMD_RESPONSE_OK		0x30 /* 0 */
+++#define IEI_WT61P803_PUZZLE_CHECKSUM_RESPONSE_OK	0x70
+++
+++#define IEI_WT61P803_PUZZLE_CMD_EEPROM_READ		0xA1
+++#define IEI_WT61P803_PUZZLE_CMD_EEPROM_WRITE		0xA0
+++
+++#define IEI_WT61P803_PUZZLE_CMD_OTHER_VERSION		0x56 /* V */
+++#define IEI_WT61P803_PUZZLE_CMD_OTHER_BUILD		0x42 /* B */
+++#define IEI_WT61P803_PUZZLE_CMD_OTHER_BOOTLOADER_MODE	0x4D /* M */
+++#define IEI_WT61P803_PUZZLE_CMD_OTHER_MODE_BOOTLOADER	0x30
+++#define IEI_WT61P803_PUZZLE_CMD_OTHER_MODE_APPS		0x31
+++#define IEI_WT61P803_PUZZLE_CMD_OTHER_PROTOCOL_VERSION	0x50 /* P */
+++
+++#define IEI_WT61P803_PUZZLE_CMD_FUNCTION_SINGLE		0x43 /* C */
+++#define IEI_WT61P803_PUZZLE_CMD_FUNCTION_OTHER		0x4F /* O */
+++#define IEI_WT61P803_PUZZLE_CMD_FUNCTION_OTHER_STATUS	0x53 /* S */
+++#define IEI_WT61P803_PUZZLE_CMD_FUNCTION_OTHER_POWER_LOSS 0x41 /* A */
+++
+++#define IEI_WT61P803_PUZZLE_CMD_LED			0x52 /* R */
+++#define IEI_WT61P803_PUZZLE_CMD_LED_POWER		0x31 /* 1 */
+++
+++#define IEI_WT61P803_PUZZLE_CMD_TEMP			0x54 /* T */
+++#define IEI_WT61P803_PUZZLE_CMD_TEMP_ALL		0x41 /* A */
+++
+++#define IEI_WT61P803_PUZZLE_CMD_FAN			0x46 /* F */
+++#define IEI_WT61P803_PUZZLE_CMD_FAN_PWM_READ		0x5A /* Z */
+++#define IEI_WT61P803_PUZZLE_CMD_FAN_PWM_WRITE		0x57 /* W */
+++#define IEI_WT61P803_PUZZLE_CMD_FAN_PWM_BASE		0x30
+++#define IEI_WT61P803_PUZZLE_CMD_FAN_RPM_BASE		0x41 /* A */
+++
+++#define IEI_WT61P803_PUZZLE_CMD_FAN_PWM(x) (IEI_WT61P803_PUZZLE_CMD_FAN_PWM_BASE + (x)) /* 0 - 1 */
+++#define IEI_WT61P803_PUZZLE_CMD_FAN_RPM(x) (IEI_WT61P803_PUZZLE_CMD_FAN_RPM_BASE + (x)) /* 0 - 5 */
+++
+++struct iei_wt61p803_puzzle_mcu_version;
+++struct iei_wt61p803_puzzle_reply;
+++struct iei_wt61p803_puzzle;
+++
+++int iei_wt61p803_puzzle_write_command_watchdog(struct iei_wt61p803_puzzle *mcu,
+++					       unsigned char *cmd, size_t size,
+++					       unsigned char *reply_data, size_t *reply_size,
+++					       int retry_count);
+++
+++int iei_wt61p803_puzzle_write_command(struct iei_wt61p803_puzzle *mcu,
+++				      unsigned char *cmd, size_t size,
+++				      unsigned char *reply_data, size_t *reply_size);
+++
+++#endif /* _MFD_IEI_WT61P803_PUZZLE_H_ */
+diff --git a/target/linux/mvebu/patches-5.15/903-drivers-hwmon-Add-the-IEI-WT61P803-PUZZLE-HWMON-driv.patch b/target/linux/mvebu/patches-5.15/903-drivers-hwmon-Add-the-IEI-WT61P803-PUZZLE-HWMON-driv.patch
+new file mode 100644
+index 0000000000..c22314e41c
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/903-drivers-hwmon-Add-the-IEI-WT61P803-PUZZLE-HWMON-driv.patch
+@@ -0,0 +1,469 @@
++From e3310a638cd310bfd93dbbc6d2732ab6aea18dd2 Mon Sep 17 00:00:00 2001
++From: Luka Kovacic <luka.kovacic () sartura ! hr>
++Date: Tue, 24 Aug 2021 12:44:34 +0000
++Subject: [PATCH 3/7] drivers: hwmon: Add the IEI WT61P803 PUZZLE HWMON driver
++
++Add the IEI WT61P803 PUZZLE HWMON driver, that handles the fan speed
++control via PWM, reading fan speed and reading on-board temperature
++sensors.
++
++The driver registers a HWMON device and a simple thermal cooling device to
++enable in-kernel fan management.
++
++This driver depends on the IEI WT61P803 PUZZLE MFD driver.
++
++Signed-off-by: Luka Kovacic <luka.kovacic@sartura.hr>
++Signed-off-by: Pavo Banicevic <pavo.banicevic@sartura.hr>
++Acked-by: Guenter Roeck <linux@roeck-us.net>
++Cc: Luka Perkov <luka.perkov@sartura.hr>
++Cc: Robert Marko <robert.marko@sartura.hr>
++---
++ drivers/hwmon/Kconfig                     |   8 +
++ drivers/hwmon/Makefile                    |   1 +
++ drivers/hwmon/iei-wt61p803-puzzle-hwmon.c | 413 ++++++++++++++++++++++
++ 3 files changed, 422 insertions(+)
++ create mode 100644 drivers/hwmon/iei-wt61p803-puzzle-hwmon.c
++
++--- a/drivers/hwmon/Kconfig
+++++ b/drivers/hwmon/Kconfig
++@@ -732,6 +732,14 @@ config SENSORS_IBMPOWERNV
++ 	  This driver can also be built as a module. If so, the module
++ 	  will be called ibmpowernv.
++ 
+++config SENSORS_IEI_WT61P803_PUZZLE_HWMON
+++	tristate "IEI WT61P803 PUZZLE MFD HWMON Driver"
+++	depends on MFD_IEI_WT61P803_PUZZLE
+++	help
+++	  The IEI WT61P803 PUZZLE MFD HWMON Driver handles reading fan speed
+++	  and writing fan PWM values. It also supports reading on-board
+++	  temperature sensors.
+++
++ config SENSORS_IIO_HWMON
++ 	tristate "Hwmon driver that uses channels specified via iio maps"
++ 	depends on IIO
++--- a/drivers/hwmon/Makefile
+++++ b/drivers/hwmon/Makefile
++@@ -84,6 +84,7 @@ obj-$(CONFIG_SENSORS_HIH6130)	+= hih6130
++ obj-$(CONFIG_SENSORS_ULTRA45)	+= ultra45_env.o
++ obj-$(CONFIG_SENSORS_I5500)	+= i5500_temp.o
++ obj-$(CONFIG_SENSORS_I5K_AMB)	+= i5k_amb.o
+++obj-$(CONFIG_SENSORS_IEI_WT61P803_PUZZLE_HWMON) += iei-wt61p803-puzzle-hwmon.o
++ obj-$(CONFIG_SENSORS_IBMAEM)	+= ibmaem.o
++ obj-$(CONFIG_SENSORS_IBMPEX)	+= ibmpex.o
++ obj-$(CONFIG_SENSORS_IBMPOWERNV)+= ibmpowernv.o
++--- /dev/null
+++++ b/drivers/hwmon/iei-wt61p803-puzzle-hwmon.c
++@@ -0,0 +1,413 @@
+++// SPDX-License-Identifier: GPL-2.0-only
+++/* IEI WT61P803 PUZZLE MCU HWMON Driver
+++ *
+++ * Copyright (C) 2020 Sartura Ltd.
+++ * Author: Luka Kovacic <luka.kovacic@sartura.hr>
+++ */
+++
+++#include <linux/err.h>
+++#include <linux/hwmon.h>
+++#include <linux/interrupt.h>
+++#include <linux/irq.h>
+++#include <linux/math64.h>
+++#include <linux/mfd/iei-wt61p803-puzzle.h>
+++#include <linux/mod_devicetable.h>
+++#include <linux/module.h>
+++#include <linux/platform_device.h>
+++#include <linux/property.h>
+++#include <linux/slab.h>
+++#include <linux/thermal.h>
+++
+++#define IEI_WT61P803_PUZZLE_HWMON_MAX_PWM	2
+++#define IEI_WT61P803_PUZZLE_HWMON_MAX_PWM_VAL	255
+++
+++/**
+++ * struct iei_wt61p803_puzzle_thermal_cooling_device - Thermal cooling device instance
+++ * @mcu_hwmon:		Parent driver struct pointer
+++ * @tcdev:		Thermal cooling device pointer
+++ * @name:		Thermal cooling device name
+++ * @pwm_channel:	Controlled PWM channel (0 or 1)
+++ * @cooling_levels:	Thermal cooling device cooling levels (DT)
+++ */
+++struct iei_wt61p803_puzzle_thermal_cooling_device {
+++	struct iei_wt61p803_puzzle_hwmon *mcu_hwmon;
+++	struct thermal_cooling_device *tcdev;
+++	char name[THERMAL_NAME_LENGTH];
+++	int pwm_channel;
+++	u8 *cooling_levels;
+++};
+++
+++/**
+++ * struct iei_wt61p803_puzzle_hwmon - MCU HWMON Driver
+++ * @mcu:				MCU struct pointer
+++ * @response_buffer			Global MCU response buffer
+++ * @thermal_cooling_dev_present:	Per-channel thermal cooling device control indicator
+++ * @cdev:				Per-channel thermal cooling device private structure
+++ */
+++struct iei_wt61p803_puzzle_hwmon {
+++	struct iei_wt61p803_puzzle *mcu;
+++	unsigned char response_buffer[IEI_WT61P803_PUZZLE_BUF_SIZE];
+++	bool thermal_cooling_dev_present[IEI_WT61P803_PUZZLE_HWMON_MAX_PWM];
+++	struct iei_wt61p803_puzzle_thermal_cooling_device
+++		*cdev[IEI_WT61P803_PUZZLE_HWMON_MAX_PWM];
+++	struct mutex lock; /* mutex to protect response_buffer array */
+++};
+++
+++#define raw_temp_to_milidegree_celsius(x) (((x) - 0x80) * 1000)
+++static int iei_wt61p803_puzzle_read_temp_sensor(struct iei_wt61p803_puzzle_hwmon *mcu_hwmon,
+++						int channel, long *value)
+++{
+++	unsigned char *resp_buf = mcu_hwmon->response_buffer;
+++	unsigned char temp_sensor_ntc_cmd[4] = {
+++		IEI_WT61P803_PUZZLE_CMD_HEADER_START,
+++		IEI_WT61P803_PUZZLE_CMD_TEMP,
+++		IEI_WT61P803_PUZZLE_CMD_TEMP_ALL,
+++	};
+++	size_t reply_size;
+++	int ret;
+++
+++	mutex_lock(&mcu_hwmon->lock);
+++	ret = iei_wt61p803_puzzle_write_command(mcu_hwmon->mcu, temp_sensor_ntc_cmd,
+++						sizeof(temp_sensor_ntc_cmd), resp_buf,
+++						&reply_size);
+++	if (ret)
+++		goto exit;
+++
+++	if (reply_size != 7) {
+++		ret = -EIO;
+++		goto exit;
+++	}
+++
+++	/* Check the number of NTC values */
+++	if (resp_buf[3] != '2') {
+++		ret = -EIO;
+++		goto exit;
+++	}
+++
+++	*value = raw_temp_to_milidegree_celsius(resp_buf[4 + channel]);
+++exit:
+++	mutex_unlock(&mcu_hwmon->lock);
+++	return ret;
+++}
+++
+++#define raw_fan_val_to_rpm(x, y) ((((x) << 8 | (y)) / 2) * 60)
+++static int iei_wt61p803_puzzle_read_fan_speed(struct iei_wt61p803_puzzle_hwmon *mcu_hwmon,
+++					      int channel, long *value)
+++{
+++	unsigned char *resp_buf = mcu_hwmon->response_buffer;
+++	unsigned char fan_speed_cmd[4] = {};
+++	size_t reply_size;
+++	int ret;
+++
+++	fan_speed_cmd[0] = IEI_WT61P803_PUZZLE_CMD_HEADER_START;
+++	fan_speed_cmd[1] = IEI_WT61P803_PUZZLE_CMD_FAN;
+++	fan_speed_cmd[2] = IEI_WT61P803_PUZZLE_CMD_FAN_RPM(channel);
+++
+++	mutex_lock(&mcu_hwmon->lock);
+++	ret = iei_wt61p803_puzzle_write_command(mcu_hwmon->mcu, fan_speed_cmd,
+++						sizeof(fan_speed_cmd), resp_buf,
+++						&reply_size);
+++	if (ret)
+++		goto exit;
+++
+++	if (reply_size != 7) {
+++		ret = -EIO;
+++		goto exit;
+++	}
+++
+++	*value = raw_fan_val_to_rpm(resp_buf[3], resp_buf[4]);
+++exit:
+++	mutex_unlock(&mcu_hwmon->lock);
+++	return ret;
+++}
+++
+++static int iei_wt61p803_puzzle_write_pwm_channel(struct iei_wt61p803_puzzle_hwmon *mcu_hwmon,
+++						 int channel, long pwm_set_val)
+++{
+++	unsigned char *resp_buf = mcu_hwmon->response_buffer;
+++	unsigned char pwm_set_cmd[6] = {};
+++	size_t reply_size;
+++	int ret;
+++
+++	pwm_set_cmd[0] = IEI_WT61P803_PUZZLE_CMD_HEADER_START;
+++	pwm_set_cmd[1] = IEI_WT61P803_PUZZLE_CMD_FAN;
+++	pwm_set_cmd[2] = IEI_WT61P803_PUZZLE_CMD_FAN_PWM_WRITE;
+++	pwm_set_cmd[3] = IEI_WT61P803_PUZZLE_CMD_FAN_PWM(channel);
+++	pwm_set_cmd[4] = pwm_set_val;
+++
+++	mutex_lock(&mcu_hwmon->lock);
+++	ret = iei_wt61p803_puzzle_write_command(mcu_hwmon->mcu, pwm_set_cmd,
+++						sizeof(pwm_set_cmd), resp_buf,
+++						&reply_size);
+++	if (ret)
+++		goto exit;
+++
+++	if (reply_size != 3) {
+++		ret = -EIO;
+++		goto exit;
+++	}
+++
+++	if (!(resp_buf[0] == IEI_WT61P803_PUZZLE_CMD_HEADER_START &&
+++	      resp_buf[1] == IEI_WT61P803_PUZZLE_CMD_RESPONSE_OK &&
+++	      resp_buf[2] == IEI_WT61P803_PUZZLE_CHECKSUM_RESPONSE_OK)) {
+++		ret = -EIO;
+++		goto exit;
+++	}
+++exit:
+++	mutex_unlock(&mcu_hwmon->lock);
+++	return ret;
+++}
+++
+++static int iei_wt61p803_puzzle_read_pwm_channel(struct iei_wt61p803_puzzle_hwmon *mcu_hwmon,
+++						int channel, long *value)
+++{
+++	unsigned char *resp_buf = mcu_hwmon->response_buffer;
+++	unsigned char pwm_get_cmd[5] = {};
+++	size_t reply_size;
+++	int ret;
+++
+++	pwm_get_cmd[0] = IEI_WT61P803_PUZZLE_CMD_HEADER_START;
+++	pwm_get_cmd[1] = IEI_WT61P803_PUZZLE_CMD_FAN;
+++	pwm_get_cmd[2] = IEI_WT61P803_PUZZLE_CMD_FAN_PWM_READ;
+++	pwm_get_cmd[3] = IEI_WT61P803_PUZZLE_CMD_FAN_PWM(channel);
+++
+++	ret = iei_wt61p803_puzzle_write_command(mcu_hwmon->mcu, pwm_get_cmd,
+++						sizeof(pwm_get_cmd), resp_buf,
+++						&reply_size);
+++	if (ret)
+++		return ret;
+++
+++	if (reply_size != 5)
+++		return -EIO;
+++
+++	if (resp_buf[2] != IEI_WT61P803_PUZZLE_CMD_FAN_PWM_READ)
+++		return -EIO;
+++
+++	*value = resp_buf[3];
+++
+++	return 0;
+++}
+++
+++static int iei_wt61p803_puzzle_read(struct device *dev, enum hwmon_sensor_types type,
+++				    u32 attr, int channel, long *val)
+++{
+++	struct iei_wt61p803_puzzle_hwmon *mcu_hwmon = dev_get_drvdata(dev->parent);
+++
+++	switch (type) {
+++	case hwmon_pwm:
+++		return iei_wt61p803_puzzle_read_pwm_channel(mcu_hwmon, channel, val);
+++	case hwmon_fan:
+++		return iei_wt61p803_puzzle_read_fan_speed(mcu_hwmon, channel, val);
+++	case hwmon_temp:
+++		return iei_wt61p803_puzzle_read_temp_sensor(mcu_hwmon, channel, val);
+++	default:
+++		return -EINVAL;
+++	}
+++}
+++
+++static int iei_wt61p803_puzzle_write(struct device *dev, enum hwmon_sensor_types type,
+++				     u32 attr, int channel, long val)
+++{
+++	struct iei_wt61p803_puzzle_hwmon *mcu_hwmon = dev_get_drvdata(dev->parent);
+++
+++	return iei_wt61p803_puzzle_write_pwm_channel(mcu_hwmon, channel, val);
+++}
+++
+++static umode_t iei_wt61p803_puzzle_is_visible(const void *data, enum hwmon_sensor_types type,
+++					      u32 attr, int channel)
+++{
+++	const struct iei_wt61p803_puzzle_hwmon *mcu_hwmon = data;
+++
+++	switch (type) {
+++	case hwmon_pwm:
+++		if (mcu_hwmon->thermal_cooling_dev_present[channel])
+++			return 0444;
+++		if (attr == hwmon_pwm_input)
+++			return 0644;
+++		break;
+++	case hwmon_fan:
+++		if (attr == hwmon_fan_input)
+++			return 0444;
+++		break;
+++	case hwmon_temp:
+++		if (attr == hwmon_temp_input)
+++			return 0444;
+++		break;
+++	default:
+++		return 0;
+++	}
+++
+++	return 0;
+++}
+++
+++static const struct hwmon_ops iei_wt61p803_puzzle_hwmon_ops = {
+++	.is_visible = iei_wt61p803_puzzle_is_visible,
+++	.read = iei_wt61p803_puzzle_read,
+++	.write = iei_wt61p803_puzzle_write,
+++};
+++
+++static const struct hwmon_channel_info *iei_wt61p803_puzzle_info[] = {
+++	HWMON_CHANNEL_INFO(pwm,
+++			   HWMON_PWM_INPUT,
+++			   HWMON_PWM_INPUT),
+++	HWMON_CHANNEL_INFO(fan,
+++			   HWMON_F_INPUT,
+++			   HWMON_F_INPUT,
+++			   HWMON_F_INPUT,
+++			   HWMON_F_INPUT,
+++			   HWMON_F_INPUT),
+++	HWMON_CHANNEL_INFO(temp,
+++			   HWMON_T_INPUT,
+++			   HWMON_T_INPUT),
+++	NULL
+++};
+++
+++static const struct hwmon_chip_info iei_wt61p803_puzzle_chip_info = {
+++	.ops = &iei_wt61p803_puzzle_hwmon_ops,
+++	.info = iei_wt61p803_puzzle_info,
+++};
+++
+++static int iei_wt61p803_puzzle_get_max_state(struct thermal_cooling_device *tcdev,
+++					     unsigned long *state)
+++{
+++	*state = IEI_WT61P803_PUZZLE_HWMON_MAX_PWM_VAL;
+++
+++	return 0;
+++}
+++
+++static int iei_wt61p803_puzzle_get_cur_state(struct thermal_cooling_device *tcdev,
+++					     unsigned long *state)
+++{
+++	struct iei_wt61p803_puzzle_thermal_cooling_device *cdev = tcdev->devdata;
+++	struct iei_wt61p803_puzzle_hwmon *mcu_hwmon = cdev->mcu_hwmon;
+++	long value;
+++	int ret;
+++
+++	ret = iei_wt61p803_puzzle_read_pwm_channel(mcu_hwmon, cdev->pwm_channel, &value);
+++	if (ret)
+++		return ret;
+++	*state = value;
+++	return 0;
+++}
+++
+++static int iei_wt61p803_puzzle_set_cur_state(struct thermal_cooling_device *tcdev,
+++					     unsigned long state)
+++{
+++	struct iei_wt61p803_puzzle_thermal_cooling_device *cdev = tcdev->devdata;
+++	struct iei_wt61p803_puzzle_hwmon *mcu_hwmon = cdev->mcu_hwmon;
+++
+++	return iei_wt61p803_puzzle_write_pwm_channel(mcu_hwmon, cdev->pwm_channel, state);
+++}
+++
+++static const struct thermal_cooling_device_ops iei_wt61p803_puzzle_cooling_ops = {
+++	.get_max_state = iei_wt61p803_puzzle_get_max_state,
+++	.get_cur_state = iei_wt61p803_puzzle_get_cur_state,
+++	.set_cur_state = iei_wt61p803_puzzle_set_cur_state,
+++};
+++
+++static int
+++iei_wt61p803_puzzle_enable_thermal_cooling_dev(struct device *dev,
+++					       struct fwnode_handle *child,
+++					       struct iei_wt61p803_puzzle_hwmon *mcu_hwmon)
+++{
+++	struct iei_wt61p803_puzzle_thermal_cooling_device *cdev;
+++	u32 pwm_channel;
+++	u8 num_levels;
+++	int ret;
+++
+++	ret = fwnode_property_read_u32(child, "reg", &pwm_channel);
+++	if (ret)
+++		return ret;
+++
+++	mcu_hwmon->thermal_cooling_dev_present[pwm_channel] = true;
+++
+++	num_levels = fwnode_property_count_u8(child, "cooling-levels");
+++	if (!num_levels)
+++		return -EINVAL;
+++
+++	cdev = devm_kzalloc(dev, sizeof(*cdev), GFP_KERNEL);
+++	if (!cdev)
+++		return -ENOMEM;
+++
+++	cdev->cooling_levels = devm_kmalloc_array(dev, num_levels, sizeof(u8), GFP_KERNEL);
+++	if (!cdev->cooling_levels)
+++		return -ENOMEM;
+++
+++	ret = fwnode_property_read_u8_array(child, "cooling-levels",
+++					    cdev->cooling_levels,
+++					    num_levels);
+++	if (ret) {
+++		dev_err(dev, "Couldn't read property 'cooling-levels'\n");
+++		return ret;
+++	}
+++
+++	snprintf(cdev->name, THERMAL_NAME_LENGTH, "wt61p803_puzzle_%d", pwm_channel);
+++	cdev->tcdev = devm_thermal_of_cooling_device_register(dev, NULL, cdev->name, cdev,
+++							      &iei_wt61p803_puzzle_cooling_ops);
+++	if (IS_ERR(cdev->tcdev))
+++		return PTR_ERR(cdev->tcdev);
+++
+++	cdev->mcu_hwmon = mcu_hwmon;
+++	cdev->pwm_channel = pwm_channel;
+++	mcu_hwmon->cdev[pwm_channel] = cdev;
+++
+++	return 0;
+++}
+++
+++static int iei_wt61p803_puzzle_hwmon_probe(struct platform_device *pdev)
+++{
+++	struct device *dev = &pdev->dev;
+++	struct iei_wt61p803_puzzle *mcu = dev_get_drvdata(dev->parent);
+++	struct iei_wt61p803_puzzle_hwmon *mcu_hwmon;
+++	struct fwnode_handle *child;
+++	struct device *hwmon_dev;
+++	int ret;
+++
+++	mcu_hwmon = devm_kzalloc(dev, sizeof(*mcu_hwmon), GFP_KERNEL);
+++	if (!mcu_hwmon)
+++		return -ENOMEM;
+++
+++	mcu_hwmon->mcu = mcu;
+++	platform_set_drvdata(pdev, mcu_hwmon);
+++	mutex_init(&mcu_hwmon->lock);
+++
+++	hwmon_dev = devm_hwmon_device_register_with_info(dev, "iei_wt61p803_puzzle",
+++							 mcu_hwmon,
+++							 &iei_wt61p803_puzzle_chip_info,
+++							 NULL);
+++	if (IS_ERR(hwmon_dev))
+++		return PTR_ERR(hwmon_dev);
+++
+++	/* Control fans via PWM lines via Linux Kernel */
+++	if (IS_ENABLED(CONFIG_THERMAL)) {
+++		device_for_each_child_node(dev, child) {
+++			ret = iei_wt61p803_puzzle_enable_thermal_cooling_dev(dev, child, mcu_hwmon);
+++			if (ret) {
+++				dev_err(dev, "Enabling the PWM fan failed\n");
+++				fwnode_handle_put(child);
+++				return ret;
+++			}
+++		}
+++	}
+++	return 0;
+++}
+++
+++static const struct of_device_id iei_wt61p803_puzzle_hwmon_id_table[] = {
+++	{ .compatible = "iei,wt61p803-puzzle-hwmon" },
+++	{}
+++};
+++MODULE_DEVICE_TABLE(of, iei_wt61p803_puzzle_hwmon_id_table);
+++
+++static struct platform_driver iei_wt61p803_puzzle_hwmon_driver = {
+++	.driver = {
+++		.name = "iei-wt61p803-puzzle-hwmon",
+++		.of_match_table = iei_wt61p803_puzzle_hwmon_id_table,
+++	},
+++	.probe = iei_wt61p803_puzzle_hwmon_probe,
+++};
+++
+++module_platform_driver(iei_wt61p803_puzzle_hwmon_driver);
+++
+++MODULE_DESCRIPTION("IEI WT61P803 PUZZLE MCU HWMON Driver");
+++MODULE_AUTHOR("Luka Kovacic <luka.kovacic@sartura.hr>");
+++MODULE_LICENSE("GPL v2");
+diff --git a/target/linux/mvebu/patches-5.15/904-drivers-leds-Add-the-IEI-WT61P803-PUZZLE-LED-driver.patch b/target/linux/mvebu/patches-5.15/904-drivers-leds-Add-the-IEI-WT61P803-PUZZLE-LED-driver.patch
+new file mode 100644
+index 0000000000..0452bd641b
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/904-drivers-leds-Add-the-IEI-WT61P803-PUZZLE-LED-driver.patch
+@@ -0,0 +1,207 @@
++From f3b44eb69cc561cf05d00506dcec0dd9be003ed8 Mon Sep 17 00:00:00 2001
++From: Luka Kovacic <luka.kovacic () sartura ! hr>
++Date: Tue, 24 Aug 2021 12:44:35 +0000
++Subject: [PATCH 4/7] drivers: leds: Add the IEI WT61P803 PUZZLE LED driver
++
++Add support for the IEI WT61P803 PUZZLE LED driver.
++Currently only the front panel power LED is supported,
++since it is the only LED on this board wired through the
++MCU.
++
++The LED is wired directly to the on-board MCU controller
++and is toggled using an MCU command.
++
++Support for more LEDs is going to be added in case more
++boards implement this microcontroller, as LEDs use many
++different GPIOs.
++
++This driver depends on the IEI WT61P803 PUZZLE MFD driver.
++
++Signed-off-by: Luka Kovacic <luka.kovacic@sartura.hr>
++Signed-off-by: Pavo Banicevic <pavo.banicevic@sartura.hr>
++Cc: Luka Perkov <luka.perkov@sartura.hr>
++Cc: Robert Marko <robert.marko@sartura.hr>
++---
++ drivers/leds/Kconfig                    |   8 ++
++ drivers/leds/Makefile                   |   1 +
++ drivers/leds/leds-iei-wt61p803-puzzle.c | 147 ++++++++++++++++++++++++
++ 3 files changed, 156 insertions(+)
++ create mode 100644 drivers/leds/leds-iei-wt61p803-puzzle.c
++
++--- a/drivers/leds/Kconfig
+++++ b/drivers/leds/Kconfig
++@@ -305,6 +305,14 @@ config LEDS_IPAQ_MICRO
++ 	  Choose this option if you want to use the notification LED on
++ 	  Compaq/HP iPAQ h3100 and h3600.
++ 
+++config LEDS_IEI_WT61P803_PUZZLE
+++	tristate "LED Support for the IEI WT61P803 PUZZLE MCU"
+++	depends on LEDS_CLASS
+++	depends on MFD_IEI_WT61P803_PUZZLE
+++	help
+++	  This option enables support for LEDs controlled by the IEI WT61P803
+++	  M801 MCU.
+++
++ config LEDS_HP6XX
++ 	tristate "LED Support for the HP Jornada 6xx"
++ 	depends on LEDS_CLASS
++--- a/drivers/leds/Makefile
+++++ b/drivers/leds/Makefile
++@@ -33,6 +33,7 @@ obj-$(CONFIG_LEDS_HP6XX)		+= leds-hp6xx.
++ obj-$(CONFIG_LEDS_INTEL_SS4200)		+= leds-ss4200.o
++ obj-$(CONFIG_LEDS_IP30)			+= leds-ip30.o
++ obj-$(CONFIG_LEDS_IPAQ_MICRO)		+= leds-ipaq-micro.o
+++obj-$(CONFIG_LEDS_IEI_WT61P803_PUZZLE)	+= leds-iei-wt61p803-puzzle.o
++ obj-$(CONFIG_LEDS_IS31FL319X)		+= leds-is31fl319x.o
++ obj-$(CONFIG_LEDS_IS31FL32XX)		+= leds-is31fl32xx.o
++ obj-$(CONFIG_LEDS_LM3530)		+= leds-lm3530.o
++--- /dev/null
+++++ b/drivers/leds/leds-iei-wt61p803-puzzle.c
++@@ -0,0 +1,147 @@
+++// SPDX-License-Identifier: GPL-2.0-only
+++/* IEI WT61P803 PUZZLE MCU LED Driver
+++ *
+++ * Copyright (C) 2020 Sartura Ltd.
+++ * Author: Luka Kovacic <luka.kovacic@sartura.hr>
+++ */
+++
+++#include <linux/leds.h>
+++#include <linux/mfd/iei-wt61p803-puzzle.h>
+++#include <linux/mod_devicetable.h>
+++#include <linux/module.h>
+++#include <linux/platform_device.h>
+++#include <linux/property.h>
+++#include <linux/slab.h>
+++
+++enum iei_wt61p803_puzzle_led_state {
+++	IEI_LED_OFF = 0x30,
+++	IEI_LED_ON = 0x31,
+++	IEI_LED_BLINK_5HZ = 0x32,
+++	IEI_LED_BLINK_1HZ = 0x33,
+++};
+++
+++/**
+++ * struct iei_wt61p803_puzzle_led - MCU LED Driver
+++ * @cdev:		LED classdev
+++ * @mcu:		MCU struct pointer
+++ * @response_buffer	Global MCU response buffer
+++ * @lock:		General mutex lock to protect simultaneous R/W access to led_power_state
+++ * @led_power_state:	State of the front panel power LED
+++ */
+++struct iei_wt61p803_puzzle_led {
+++	struct led_classdev cdev;
+++	struct iei_wt61p803_puzzle *mcu;
+++	unsigned char response_buffer[IEI_WT61P803_PUZZLE_BUF_SIZE];
+++	struct mutex lock; /* mutex to protect led_power_state */
+++	int led_power_state;
+++};
+++
+++static inline struct iei_wt61p803_puzzle_led *cdev_to_iei_wt61p803_puzzle_led
+++	(struct led_classdev *led_cdev)
+++{
+++	return container_of(led_cdev, struct iei_wt61p803_puzzle_led, cdev);
+++}
+++
+++static int iei_wt61p803_puzzle_led_brightness_set_blocking(struct led_classdev *cdev,
+++							   enum led_brightness brightness)
+++{
+++	struct iei_wt61p803_puzzle_led *priv = cdev_to_iei_wt61p803_puzzle_led(cdev);
+++	unsigned char *resp_buf = priv->response_buffer;
+++	unsigned char led_power_cmd[5] = {};
+++	size_t reply_size;
+++	int ret;
+++
+++	led_power_cmd[0] = IEI_WT61P803_PUZZLE_CMD_HEADER_START;
+++	led_power_cmd[1] = IEI_WT61P803_PUZZLE_CMD_LED;
+++	led_power_cmd[2] = IEI_WT61P803_PUZZLE_CMD_LED_POWER;
+++	led_power_cmd[3] = brightness == LED_OFF ? IEI_LED_OFF : IEI_LED_ON;
+++
+++	ret = iei_wt61p803_puzzle_write_command(priv->mcu, led_power_cmd,
+++						sizeof(led_power_cmd),
+++						resp_buf,
+++						&reply_size);
+++	if (ret)
+++		return ret;
+++
+++	if (reply_size != 3)
+++		return -EIO;
+++
+++	if (!(resp_buf[0] == IEI_WT61P803_PUZZLE_CMD_HEADER_START &&
+++	      resp_buf[1] == IEI_WT61P803_PUZZLE_CMD_RESPONSE_OK &&
+++	      resp_buf[2] == IEI_WT61P803_PUZZLE_CHECKSUM_RESPONSE_OK))
+++		return -EIO;
+++
+++	mutex_lock(&priv->lock);
+++	priv->led_power_state = brightness;
+++	mutex_unlock(&priv->lock);
+++
+++	return 0;
+++}
+++
+++static enum led_brightness iei_wt61p803_puzzle_led_brightness_get(struct led_classdev *cdev)
+++{
+++	struct iei_wt61p803_puzzle_led *priv = cdev_to_iei_wt61p803_puzzle_led(cdev);
+++	int led_state;
+++
+++	mutex_lock(&priv->lock);
+++	led_state = priv->led_power_state;
+++	mutex_unlock(&priv->lock);
+++
+++	return led_state;
+++}
+++
+++static int iei_wt61p803_puzzle_led_probe(struct platform_device *pdev)
+++{
+++	struct device *dev = &pdev->dev;
+++	struct iei_wt61p803_puzzle *mcu = dev_get_drvdata(dev->parent);
+++	struct iei_wt61p803_puzzle_led *priv;
+++	struct led_init_data init_data = {};
+++	struct fwnode_handle *child;
+++	int ret;
+++
+++	if (device_get_child_node_count(dev) != 1)
+++		return -EINVAL;
+++
+++	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+++	if (!priv)
+++		return -ENOMEM;
+++
+++	priv->mcu = mcu;
+++	priv->led_power_state = 1;
+++	mutex_init(&priv->lock);
+++	dev_set_drvdata(dev, priv);
+++
+++	child = device_get_next_child_node(dev, NULL);
+++	init_data.fwnode = child;
+++
+++	priv->cdev.brightness_set_blocking = iei_wt61p803_puzzle_led_brightness_set_blocking;
+++	priv->cdev.brightness_get = iei_wt61p803_puzzle_led_brightness_get;
+++	priv->cdev.max_brightness = 1;
+++
+++	ret = devm_led_classdev_register_ext(dev, &priv->cdev, &init_data);
+++	if (ret)
+++		dev_err(dev, "Could not register LED\n");
+++
+++	fwnode_handle_put(child);
+++	return ret;
+++}
+++
+++static const struct of_device_id iei_wt61p803_puzzle_led_of_match[] = {
+++	{ .compatible = "iei,wt61p803-puzzle-leds" },
+++	{ }
+++};
+++MODULE_DEVICE_TABLE(of, iei_wt61p803_puzzle_led_of_match);
+++
+++static struct platform_driver iei_wt61p803_puzzle_led_driver = {
+++	.driver = {
+++		.name = "iei-wt61p803-puzzle-led",
+++		.of_match_table = iei_wt61p803_puzzle_led_of_match,
+++	},
+++	.probe = iei_wt61p803_puzzle_led_probe,
+++};
+++module_platform_driver(iei_wt61p803_puzzle_led_driver);
+++
+++MODULE_DESCRIPTION("IEI WT61P803 PUZZLE front panel LED driver");
+++MODULE_AUTHOR("Luka Kovacic <luka.kovacic@sartura.hr>");
+++MODULE_LICENSE("GPL v2");
+++MODULE_ALIAS("platform:leds-iei-wt61p803-puzzle");
+diff --git a/target/linux/mvebu/patches-5.15/905-Documentation-ABI-Add-iei-wt61p803-puzzle-driver-sys.patch b/target/linux/mvebu/patches-5.15/905-Documentation-ABI-Add-iei-wt61p803-puzzle-driver-sys.patch
+new file mode 100644
+index 0000000000..b1d420ef0a
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/905-Documentation-ABI-Add-iei-wt61p803-puzzle-driver-sys.patch
+@@ -0,0 +1,82 @@
++From 2fab3b4956c5b2f83c1e1abffc1df39de2933d83 Mon Sep 17 00:00:00 2001
++From: Luka Kovacic <luka.kovacic () sartura ! hr>
++Date: Tue, 24 Aug 2021 12:44:36 +0000
++Subject: [PATCH 5/7] Documentation/ABI: Add iei-wt61p803-puzzle driver sysfs
++ interface documentation
++
++Add the iei-wt61p803-puzzle driver sysfs interface documentation to allow
++monitoring and control of the microcontroller from user space.
++
++Signed-off-by: Luka Kovacic <luka.kovacic@sartura.hr>
++Signed-off-by: Pavo Banicevic <pavo.banicevic@sartura.hr>
++Cc: Luka Perkov <luka.perkov@sartura.hr>
++Cc: Robert Marko <robert.marko@sartura.hr>
++---
++ .../testing/sysfs-driver-iei-wt61p803-puzzle  | 61 +++++++++++++++++++
++ 1 file changed, 61 insertions(+)
++ create mode 100644 Documentation/ABI/testing/sysfs-driver-iei-wt61p803-puzzle
++
++--- /dev/null
+++++ b/Documentation/ABI/testing/sysfs-driver-iei-wt61p803-puzzle
++@@ -0,0 +1,61 @@
+++What:		/sys/bus/serial/devices/.../mac_address_*
+++Date:		September 2020
+++Contact:	Luka Kovacic <luka.kovacic@sartura.hr>
+++Description:	(RW) Internal factory assigned MAC address values
+++
+++What:		/sys/bus/serial/devices/.../serial_number
+++Date:		September 2020
+++Contact:	Luka Kovacic <luka.kovacic@sartura.hr>
+++Description:	(RW) Internal factory assigned serial number
+++
+++What:		/sys/bus/serial/devices/.../version
+++Date:		September 2020
+++Contact:	Luka Kovacic <luka.kovacic@sartura.hr>
+++Description:	(RO) Internal MCU firmware version
+++
+++What:		/sys/bus/serial/devices/.../protocol_version
+++Date:		September 2020
+++Contact:	Luka Kovacic <luka.kovacic@sartura.hr>
+++Description:	(RO) Internal MCU communication protocol version
+++
+++What:		/sys/bus/serial/devices/.../power_loss_recovery
+++Date:		September 2020
+++Contact:	Luka Kovacic <luka.kovacic@sartura.hr>
+++Description:	(RW) Host platform power loss recovery settings
+++		Value mapping: 0 - Always-On, 1 - Always-Off, 2 - Always-AC, 3 - Always-WA
+++
+++What:		/sys/bus/serial/devices/.../bootloader_mode
+++Date:		September 2020
+++Contact:	Luka Kovacic <luka.kovacic@sartura.hr>
+++Description:	(RO) Internal MCU bootloader mode status
+++		Value mapping:
+++		0 - normal mode
+++		1 - bootloader mode
+++
+++What:		/sys/bus/serial/devices/.../power_status
+++Date:		September 2020
+++Contact:	Luka Kovacic <luka.kovacic@sartura.hr>
+++Description:	(RO) Power status indicates the host platform power on method.
+++		Value mapping (bitwise list):
+++		0x80 - Null
+++		0x40 - Firmware flag
+++		0x20 - Power loss detection flag (powered off)
+++		0x10 - Power loss detection flag (AC mode)
+++		0x08 - Button power on
+++		0x04 - Wake-on-LAN power on
+++		0x02 - RTC alarm power on
+++		0x01 - AC recover power on
+++
+++What:		/sys/bus/serial/devices/.../build_info
+++Date:		September 2020
+++Contact:	Luka Kovacic <luka.kovacic@sartura.hr>
+++Description:	(RO) Internal MCU firmware build date
+++		Format: yyyy/mm/dd hh:mm
+++
+++What:		/sys/bus/serial/devices/.../ac_recovery_status
+++Date:		September 2020
+++Contact:	Luka Kovacic <luka.kovacic@sartura.hr>
+++Description:	(RO) Host platform AC recovery status value
+++		Value mapping:
+++		0 - board has not been recovered from power down
+++		1 - board has been recovered from power down
+diff --git a/target/linux/mvebu/patches-5.15/906-Documentation-hwmon-Add-iei-wt61p803-puzzle-hwmon-dr.patch b/target/linux/mvebu/patches-5.15/906-Documentation-hwmon-Add-iei-wt61p803-puzzle-hwmon-dr.patch
+new file mode 100644
+index 0000000000..9015436f6a
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/906-Documentation-hwmon-Add-iei-wt61p803-puzzle-hwmon-dr.patch
+@@ -0,0 +1,74 @@
++From 0aff3e5923fecc6842473ad07a688d6e2f2c2d55 Mon Sep 17 00:00:00 2001
++From: Luka Kovacic <luka.kovacic () sartura ! hr>
++Date: Tue, 24 Aug 2021 12:44:37 +0000
++Subject: [PATCH 6/7] Documentation/hwmon: Add iei-wt61p803-puzzle hwmon driver
++ documentation
++
++Add the iei-wt61p803-puzzle driver hwmon driver interface documentation.
++
++Signed-off-by: Luka Kovacic <luka.kovacic@sartura.hr>
++Signed-off-by: Pavo Banicevic <pavo.banicevic@sartura.hr>
++Cc: Luka Perkov <luka.perkov@sartura.hr>
++Cc: Robert Marko <robert.marko@sartura.hr>
++---
++ .../hwmon/iei-wt61p803-puzzle-hwmon.rst       | 43 +++++++++++++++++++
++ Documentation/hwmon/index.rst                 |  1 +
++ 2 files changed, 44 insertions(+)
++ create mode 100644 Documentation/hwmon/iei-wt61p803-puzzle-hwmon.rst
++
++--- /dev/null
+++++ b/Documentation/hwmon/iei-wt61p803-puzzle-hwmon.rst
++@@ -0,0 +1,43 @@
+++.. SPDX-License-Identifier: GPL-2.0-only
+++
+++Kernel driver iei-wt61p803-puzzle-hwmon
+++=======================================
+++
+++Supported chips:
+++ * IEI WT61P803 PUZZLE for IEI Puzzle M801
+++
+++   Prefix: 'iei-wt61p803-puzzle-hwmon'
+++
+++Author: Luka Kovacic <luka.kovacic@sartura.hr>
+++
+++
+++Description
+++-----------
+++
+++This driver adds fan and temperature sensor reading for some IEI Puzzle
+++series boards.
+++
+++Sysfs attributes
+++----------------
+++
+++The following attributes are supported:
+++
+++- IEI WT61P803 PUZZLE for IEI Puzzle M801
+++
+++/sys files in hwmon subsystem
+++-----------------------------
+++
+++================= == =====================================================
+++fan[1-5]_input    RO files for fan speed (in RPM)
+++pwm[1-2]          RW files for fan[1-2] target duty cycle (0..255)
+++temp[1-2]_input   RO files for temperature sensors, in millidegree Celsius
+++================= == =====================================================
+++
+++/sys files in thermal subsystem
+++-------------------------------
+++
+++================= == =====================================================
+++cur_state         RW file for current cooling state of the cooling device
+++                     (0..max_state)
+++max_state         RO file for maximum cooling state of the cooling device
+++================= == =====================================================
++--- a/Documentation/hwmon/index.rst
+++++ b/Documentation/hwmon/index.rst
++@@ -74,6 +74,7 @@ Hardware Monitoring Kernel Drivers
++    ibmaem
++    ibm-cffps
++    ibmpowernv
+++   iei-wt61p803-puzzle-hwmon
++    ina209
++    ina2xx
++    ina3221
+diff --git a/target/linux/mvebu/patches-5.15/907-MAINTAINERS-Add-an-entry-for-the-IEI-WT61P803-PUZZLE.patch b/target/linux/mvebu/patches-5.15/907-MAINTAINERS-Add-an-entry-for-the-IEI-WT61P803-PUZZLE.patch
+new file mode 100644
+index 0000000000..14b928d332
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/907-MAINTAINERS-Add-an-entry-for-the-IEI-WT61P803-PUZZLE.patch
+@@ -0,0 +1,41 @@
++From 12479baad28d2a08c6cb9e83471057635fa1635c Mon Sep 17 00:00:00 2001
++From: Luka Kovacic <luka.kovacic () sartura ! hr>
++Date: Tue, 24 Aug 2021 12:44:38 +0000
++Subject: [PATCH 7/7] MAINTAINERS: Add an entry for the IEI WT61P803 PUZZLE
++ driver
++
++Add an entry for the IEI WT61P803 PUZZLE driver (MFD, HWMON, LED drivers).
++
++Signed-off-by: Luka Kovacic <luka.kovacic@sartura.hr>
++Signed-off-by: Pavo Banicevic <pavo.banicevic@sartura.hr>
++Cc: Luka Perkov <luka.perkov@sartura.hr>
++Cc: Robert Marko <robert.marko@sartura.hr>
++---
++ MAINTAINERS | 16 ++++++++++++++++
++ 1 file changed, 16 insertions(+)
++
++--- a/MAINTAINERS
+++++ b/MAINTAINERS
++@@ -9060,6 +9060,22 @@ F:	include/net/nl802154.h
++ F:	net/ieee802154/
++ F:	net/mac802154/
++ 
+++IEI WT61P803 M801 MFD DRIVER
+++M:	Luka Kovacic <luka.kovacic@sartura.hr>
+++M:	Luka Perkov <luka.perkov@sartura.hr>
+++M:	Goran Medic <goran.medic@sartura.hr>
+++L:	linux-kernel@vger.kernel.org
+++S:	Maintained
+++F:	Documentation/ABI/stable/sysfs-driver-iei-wt61p803-puzzle
+++F:	Documentation/devicetree/bindings/hwmon/iei,wt61p803-puzzle-hwmon.yaml
+++F:	Documentation/devicetree/bindings/leds/iei,wt61p803-puzzle-leds.yaml
+++F:	Documentation/devicetree/bindings/mfd/iei,wt61p803-puzzle.yaml
+++F:	Documentation/hwmon/iei-wt61p803-puzzle-hwmon.rst
+++F:	drivers/hwmon/iei-wt61p803-puzzle-hwmon.c
+++F:	drivers/leds/leds-iei-wt61p803-puzzle.c
+++F:	drivers/mfd/iei-wt61p803-puzzle.c
+++F:	include/linux/mfd/iei-wt61p803-puzzle.h
+++
++ IFE PROTOCOL
++ M:	Yotam Gigi <yotam.gi@gmail.com>
++ M:	Jamal Hadi Salim <jhs@mojatatu.com>
+diff --git a/target/linux/mvebu/patches-5.15/910-drivers-leds-wt61p803-puzzle-improvements.patch b/target/linux/mvebu/patches-5.15/910-drivers-leds-wt61p803-puzzle-improvements.patch
+new file mode 100644
+index 0000000000..150a65498c
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/910-drivers-leds-wt61p803-puzzle-improvements.patch
+@@ -0,0 +1,271 @@
++--- a/drivers/leds/leds-iei-wt61p803-puzzle.c
+++++ b/drivers/leds/leds-iei-wt61p803-puzzle.c
++@@ -9,9 +9,13 @@
++ #include <linux/mfd/iei-wt61p803-puzzle.h>
++ #include <linux/mod_devicetable.h>
++ #include <linux/module.h>
+++#include <linux/of.h>
++ #include <linux/platform_device.h>
++ #include <linux/property.h>
++ #include <linux/slab.h>
+++#include <linux/workqueue.h>
+++
+++#define IEI_LEDS_MAX		4
++ 
++ enum iei_wt61p803_puzzle_led_state {
++ 	IEI_LED_OFF = 0x30,
++@@ -33,7 +37,11 @@ struct iei_wt61p803_puzzle_led {
++ 	struct iei_wt61p803_puzzle *mcu;
++ 	unsigned char response_buffer[IEI_WT61P803_PUZZLE_BUF_SIZE];
++ 	struct mutex lock; /* mutex to protect led_power_state */
+++	struct work_struct work;
++ 	int led_power_state;
+++	int id;
+++	u8 blinking;
+++	bool active_low;
++ };
++ 
++ static inline struct iei_wt61p803_puzzle_led *cdev_to_iei_wt61p803_puzzle_led
++@@ -51,10 +59,18 @@ static int iei_wt61p803_puzzle_led_brigh
++ 	size_t reply_size;
++ 	int ret;
++ 
+++	if (priv->blinking) {
+++		if (brightness == LED_OFF)
+++			priv->blinking = 0;
+++		else
+++			return 0;
+++	}
+++
++ 	led_power_cmd[0] = IEI_WT61P803_PUZZLE_CMD_HEADER_START;
++ 	led_power_cmd[1] = IEI_WT61P803_PUZZLE_CMD_LED;
++-	led_power_cmd[2] = IEI_WT61P803_PUZZLE_CMD_LED_POWER;
++-	led_power_cmd[3] = brightness == LED_OFF ? IEI_LED_OFF : IEI_LED_ON;
+++	led_power_cmd[2] = IEI_WT61P803_PUZZLE_CMD_LED_SET(priv->id);
+++	led_power_cmd[3] = ((brightness == LED_OFF) ^ priv->active_low) ?
+++				IEI_LED_OFF : priv->blinking?priv->blinking:IEI_LED_ON;
++ 
++ 	ret = iei_wt61p803_puzzle_write_command(priv->mcu, led_power_cmd,
++ 						sizeof(led_power_cmd),
++@@ -90,39 +106,166 @@ static enum led_brightness iei_wt61p803_
++ 	return led_state;
++ }
++ 
+++static void iei_wt61p803_puzzle_led_apply_blink(struct work_struct *work)
+++{
+++	struct iei_wt61p803_puzzle_led *priv = container_of(work, struct iei_wt61p803_puzzle_led, work);
+++	unsigned char led_blink_cmd[5] = {};
+++	unsigned char resp_buf[IEI_WT61P803_PUZZLE_BUF_SIZE];
+++	size_t reply_size;
+++
+++	led_blink_cmd[0] = IEI_WT61P803_PUZZLE_CMD_HEADER_START;
+++	led_blink_cmd[1] = IEI_WT61P803_PUZZLE_CMD_LED;
+++	led_blink_cmd[2] = IEI_WT61P803_PUZZLE_CMD_LED_SET(priv->id);
+++	led_blink_cmd[3] = priv->blinking;
+++
+++	iei_wt61p803_puzzle_write_command(priv->mcu, led_blink_cmd,
+++					  sizeof(led_blink_cmd),
+++					  resp_buf,
+++					  &reply_size);
+++
+++	return;
+++}
+++
+++static int iei_wt61p803_puzzle_led_set_blink(struct led_classdev *cdev,
+++					     unsigned long *delay_on,
+++					     unsigned long *delay_off)
+++{
+++	struct iei_wt61p803_puzzle_led *priv = cdev_to_iei_wt61p803_puzzle_led(cdev);
+++	u8 blink_mode = 0;
+++	int ret = 0;
+++
+++	/* set defaults */
+++	if (!*delay_on && !*delay_off) {
+++		*delay_on = 500;
+++		*delay_off = 500;
+++	}
+++
+++	/* minimum delay for soft-driven blinking is 100ms to keep load low */
+++	if (*delay_on < 100)
+++		*delay_on = 100;
+++
+++	if (*delay_off < 100)
+++		*delay_off = 100;
+++
+++	/* offload blinking to hardware, if possible */
+++	if (*delay_on != *delay_off) {
+++		ret = -EINVAL;
+++	} else if (*delay_on == 100) {
+++		blink_mode = IEI_LED_BLINK_5HZ;
+++		*delay_on = 100;
+++		*delay_off = 100;
+++	} else if (*delay_on <= 500) {
+++		blink_mode = IEI_LED_BLINK_1HZ;
+++		*delay_on = 500;
+++		*delay_off = 500;
+++	} else {
+++		ret = -EINVAL;
+++	}
+++
+++	mutex_lock(&priv->lock);
+++	priv->blinking = blink_mode;
+++	mutex_unlock(&priv->lock);
+++
+++	if (blink_mode)
+++		schedule_work(&priv->work);
+++
+++	return ret;
+++}
+++
+++
+++static int iei_wt61p803_puzzle_led_set_dt_default(struct led_classdev *cdev,
+++				     struct device_node *np)
+++{
+++	const char *state;
+++	int ret = 0;
+++
+++	state = of_get_property(np, "default-state", NULL);
+++	if (state) {
+++		if (!strcmp(state, "on")) {
+++			ret =
+++			iei_wt61p803_puzzle_led_brightness_set_blocking(
+++				cdev, cdev->max_brightness);
+++		} else  {
+++			ret = iei_wt61p803_puzzle_led_brightness_set_blocking(
+++				cdev, LED_OFF);
+++		}
+++	}
+++
+++	return ret;
+++}
+++
++ static int iei_wt61p803_puzzle_led_probe(struct platform_device *pdev)
++ {
++ 	struct device *dev = &pdev->dev;
+++	struct device_node *np = dev_of_node(dev);
+++	struct device_node *child;
++ 	struct iei_wt61p803_puzzle *mcu = dev_get_drvdata(dev->parent);
++ 	struct iei_wt61p803_puzzle_led *priv;
++-	struct led_init_data init_data = {};
++-	struct fwnode_handle *child;
++ 	int ret;
+++	u32 reg;
++ 
++-	if (device_get_child_node_count(dev) != 1)
+++	if (device_get_child_node_count(dev) > IEI_LEDS_MAX)
++ 		return -EINVAL;
++ 
++-	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++-	if (!priv)
++-		return -ENOMEM;
++-
++-	priv->mcu = mcu;
++-	priv->led_power_state = 1;
++-	mutex_init(&priv->lock);
++-	dev_set_drvdata(dev, priv);
++-
++-	child = device_get_next_child_node(dev, NULL);
++-	init_data.fwnode = child;
++-
++-	priv->cdev.brightness_set_blocking = iei_wt61p803_puzzle_led_brightness_set_blocking;
++-	priv->cdev.brightness_get = iei_wt61p803_puzzle_led_brightness_get;
++-	priv->cdev.max_brightness = 1;
+++	for_each_available_child_of_node(np, child) {
+++		struct led_init_data init_data = {};
++ 
++-	ret = devm_led_classdev_register_ext(dev, &priv->cdev, &init_data);
++-	if (ret)
++-		dev_err(dev, "Could not register LED\n");
+++		ret = of_property_read_u32(child, "reg", &reg);
+++		if (ret) {
+++			dev_err(dev, "Failed to read led 'reg' property\n");
+++			goto put_child_node;
+++		}
+++
+++		if (reg > IEI_LEDS_MAX) {
+++			dev_err(dev, "Invalid led reg %u\n", reg);
+++			ret = -EINVAL;
+++			goto put_child_node;
+++		}
+++
+++		priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+++		if (!priv) {
+++			ret = -ENOMEM;
+++			goto put_child_node;
+++		}
+++
+++		mutex_init(&priv->lock);
+++
+++		dev_set_drvdata(dev, priv);
+++
+++		if (of_property_read_bool(child, "active-low"))
+++			priv->active_low = true;
+++
+++		priv->mcu = mcu;
+++		priv->id = reg;
+++		priv->led_power_state = 1;
+++		priv->blinking = 0;
+++		init_data.fwnode = of_fwnode_handle(child);
+++
+++		priv->cdev.brightness_set_blocking = iei_wt61p803_puzzle_led_brightness_set_blocking;
+++		priv->cdev.brightness_get = iei_wt61p803_puzzle_led_brightness_get;
+++		priv->cdev.blink_set = iei_wt61p803_puzzle_led_set_blink;
+++
+++		priv->cdev.max_brightness = 1;
+++
+++		INIT_WORK(&priv->work, iei_wt61p803_puzzle_led_apply_blink);
+++
+++		ret = iei_wt61p803_puzzle_led_set_dt_default(&priv->cdev, child);
+++		if (ret) {
+++			dev_err(dev, "Could apply default from DT\n");
+++			goto put_child_node;
+++		}
+++
+++		ret = devm_led_classdev_register_ext(dev, &priv->cdev, &init_data);
+++		if (ret) {
+++			dev_err(dev, "Could not register LED\n");
+++			goto put_child_node;
+++		}
+++	}
+++
+++	return ret;
++ 
++-	fwnode_handle_put(child);
+++put_child_node:
+++	of_node_put(child);
++ 	return ret;
++ }
++ 
++--- a/include/linux/mfd/iei-wt61p803-puzzle.h
+++++ b/include/linux/mfd/iei-wt61p803-puzzle.h
++@@ -36,7 +36,7 @@
++ #define IEI_WT61P803_PUZZLE_CMD_FUNCTION_OTHER_POWER_LOSS 0x41 /* A */
++ 
++ #define IEI_WT61P803_PUZZLE_CMD_LED			0x52 /* R */
++-#define IEI_WT61P803_PUZZLE_CMD_LED_POWER		0x31 /* 1 */
+++#define IEI_WT61P803_PUZZLE_CMD_LED_SET(n)		(0x30 | (n))
++ 
++ #define IEI_WT61P803_PUZZLE_CMD_TEMP			0x54 /* T */
++ #define IEI_WT61P803_PUZZLE_CMD_TEMP_ALL		0x41 /* A */
++--- a/drivers/mfd/iei-wt61p803-puzzle.c
+++++ b/drivers/mfd/iei-wt61p803-puzzle.c
++@@ -176,6 +176,9 @@ static int iei_wt61p803_puzzle_recv_buf(
++ 	struct iei_wt61p803_puzzle *mcu = serdev_device_get_drvdata(serdev);
++ 	int ret;
++ 
+++	print_hex_dump_debug("puzzle-mcu rx: ", DUMP_PREFIX_NONE,
+++			     16, 1, data, size, false);
+++
++ 	ret = iei_wt61p803_puzzle_process_resp(mcu, data, size);
++ 	/* Return the number of processed bytes if function returns error,
++ 	 * discard the remaining incoming data, since the frame this data
++@@ -246,6 +249,9 @@ int iei_wt61p803_puzzle_write_command(st
++ 
++ 	cmd[size - 1] = iei_wt61p803_puzzle_checksum(cmd, size - 1);
++ 
+++	print_hex_dump_debug("puzzle-mcu tx: ", DUMP_PREFIX_NONE,
+++			     16, 1, cmd, size, false);
+++
++ 	/* Initialize reply struct */
++ 	reinit_completion(&mcu->reply->received);
++ 	mcu->reply->size = 0;
+-- 
+2.34.1
+
-- 
GitLab