From: Rui Salvaterra Date: Mon, 4 Apr 2022 14:47:03 +0000 (+0100) Subject: mvebu: copy 5.10 patches to 5.15 X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=05cd4a59f019c4586073417b7384d55e0fd17a4a;p=openwrt%2Fstaging%2Fnbd.git mvebu: copy 5.10 patches to 5.15 Linux 5.15 on Marvell EBU, here we go! Signed-off-by: Rui Salvaterra --- diff --git a/target/linux/mvebu/patches-5.15/001-v5.11-arm64-dts-mcbin-singleshot-add-heartbeat-LED.patch b/target/linux/mvebu/patches-5.15/001-v5.11-arm64-dts-mcbin-singleshot-add-heartbeat-LED.patch new file mode 100644 index 0000000000..c3abae60a6 --- /dev/null +++ b/target/linux/mvebu/patches-5.15/001-v5.11-arm64-dts-mcbin-singleshot-add-heartbeat-LED.patch @@ -0,0 +1,65 @@ +From da57203dc7fd556fbb3f0ec7d7d7c0b0e893b386 Mon Sep 17 00:00:00 2001 +From: Tomasz Maciej Nowak +Date: Tue, 10 Nov 2020 16:38:31 +0100 +Subject: [PATCH] arm64: dts: mcbin-singleshot: add heartbeat LED + +With board revision 1.3, SolidRun moved the power LED to the middle of +the board. In old place of power LED a GPIO controllable heartbeat LED +was added. This commit only touches Single Shot variant, since only this +variant is all revision 1.3. + +Note: +This is slightly modified patch. Some boards could be placed in an +enclosure, so the LED18 is enabled by default, since that'll be the only +visible indicator that the board is operating. + +Reported-by: Alexandra Alth +Signed-off-by: Tomasz Maciej Nowak +Signed-off-by: Gregory CLEMENT +--- + .../marvell/armada-8040-mcbin-singleshot.dts | 22 +++++++++++++++++++ + 1 file changed, 22 insertions(+) + +--- a/arch/arm64/boot/dts/marvell/armada-8040-mcbin-singleshot.dts ++++ b/arch/arm64/boot/dts/marvell/armada-8040-mcbin-singleshot.dts +@@ -5,6 +5,8 @@ + * Device Tree file for MACCHIATOBin Armada 8040 community board platform + */ + ++#include ++ + #include "armada-8040-mcbin.dtsi" + + / { +@@ -12,6 +14,20 @@ + compatible = "marvell,armada8040-mcbin-singleshot", + "marvell,armada8040-mcbin", "marvell,armada8040", + "marvell,armada-ap806-quad", "marvell,armada-ap806"; ++ ++ leds { ++ compatible = "gpio-leds"; ++ pinctrl-0 = <&cp0_led18_pins>; ++ pinctrl-names = "default"; ++ ++ led18 { ++ gpios = <&cp0_gpio2 1 GPIO_ACTIVE_LOW>; ++ function = LED_FUNCTION_HEARTBEAT; ++ color = ; ++ linux,default-trigger = "heartbeat"; ++ default-state = "on"; ++ }; ++ }; + }; + + &cp0_eth0 { +@@ -27,3 +43,10 @@ + managed = "in-band-status"; + sfp = <&sfp_eth1>; + }; ++ ++&cp0_pinctrl { ++ cp0_led18_pins: led18-pins { ++ marvell,pins = "mpp33"; ++ marvell,function = "gpio"; ++ }; ++}; diff --git a/target/linux/mvebu/patches-5.15/002-v5.11-ARM-dts-turris-omnia-enable-HW-buffer-management.patch b/target/linux/mvebu/patches-5.15/002-v5.11-ARM-dts-turris-omnia-enable-HW-buffer-management.patch new file mode 100644 index 0000000000..7a4b511998 --- /dev/null +++ b/target/linux/mvebu/patches-5.15/002-v5.11-ARM-dts-turris-omnia-enable-HW-buffer-management.patch @@ -0,0 +1,74 @@ +From 018b88eee1a2efda26ed2f09aab33ccdc40ef18f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marek=20Beh=C3=BAn?= +Date: Sun, 15 Nov 2020 14:59:17 +0100 +Subject: ARM: dts: turris-omnia: enable HW buffer management +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The buffer manager is available on Turris Omnia but needs to be +described in device-tree to be used. + +Signed-off-by: Marek Behún +Fixes: 26ca8b52d6e1 ("ARM: dts: add support for Turris Omnia") +Cc: linux-arm-kernel@lists.infradead.org +Cc: Uwe Kleine-König +Cc: Jason Cooper +Cc: Gregory CLEMENT +Cc: Andreas Färber +Cc: Andrew Lunn +Cc: Rob Herring +Cc: devicetree@vger.kernel.org +Signed-off-by: Gregory CLEMENT +--- + arch/arm/boot/dts/armada-385-turris-omnia.dts | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +(limited to 'arch/arm/boot/dts/armada-385-turris-omnia.dts') + +--- a/arch/arm/boot/dts/armada-385-turris-omnia.dts ++++ b/arch/arm/boot/dts/armada-385-turris-omnia.dts +@@ -84,12 +84,23 @@ + }; + }; + ++&bm { ++ status = "okay"; ++}; ++ ++&bm_bppi { ++ status = "okay"; ++}; ++ + /* Connected to 88E6176 switch, port 6 */ + ð0 { + pinctrl-names = "default"; + pinctrl-0 = <&ge0_rgmii_pins>; + status = "okay"; + phy-mode = "rgmii"; ++ buffer-manager = <&bm>; ++ bm,pool-long = <0>; ++ bm,pool-short = <3>; + + fixed-link { + speed = <1000>; +@@ -103,6 +114,9 @@ + pinctrl-0 = <&ge1_rgmii_pins>; + status = "okay"; + phy-mode = "rgmii"; ++ buffer-manager = <&bm>; ++ bm,pool-long = <1>; ++ bm,pool-short = <3>; + + fixed-link { + speed = <1000>; +@@ -115,6 +129,9 @@ + status = "okay"; + phy-mode = "sgmii"; + phy = <&phy1>; ++ buffer-manager = <&bm>; ++ bm,pool-long = <2>; ++ bm,pool-short = <3>; + }; + + &i2c0 { diff --git a/target/linux/mvebu/patches-5.15/003-v5.11-ARM-dts-turris-omnia-add-comphy-handle-to-eth2.patch b/target/linux/mvebu/patches-5.15/003-v5.11-ARM-dts-turris-omnia-add-comphy-handle-to-eth2.patch new file mode 100644 index 0000000000..99ed07e13b --- /dev/null +++ b/target/linux/mvebu/patches-5.15/003-v5.11-ARM-dts-turris-omnia-add-comphy-handle-to-eth2.patch @@ -0,0 +1,37 @@ +From 9ec25ef84832209a8326f9a71fe3ba14f4bcf301 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marek=20Beh=C3=BAn?= +Date: Sun, 15 Nov 2020 14:59:18 +0100 +Subject: ARM: dts: turris-omnia: add comphy handle to eth2 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The eth2 controller on Turris Omnia is connected to SerDes. For SFP to +be able to switch between 1G and 2.5G modes the comphy link has to be +defined. + +Signed-off-by: Marek Behún +Fixes: f3a6a9f3704a ("ARM: dts: add description for Armada 38x ...") +Reviewed-by: Andrew Lunn +Reviewed-by: Andreas Färber +Cc: linux-arm-kernel@lists.infradead.org +Cc: Uwe Kleine-König +Cc: Jason Cooper +Cc: Gregory CLEMENT +Cc: Rob Herring +Cc: devicetree@vger.kernel.org +Signed-off-by: Gregory CLEMENT +--- + arch/arm/boot/dts/armada-385-turris-omnia.dts | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/arm/boot/dts/armada-385-turris-omnia.dts ++++ b/arch/arm/boot/dts/armada-385-turris-omnia.dts +@@ -129,6 +129,7 @@ + status = "okay"; + phy-mode = "sgmii"; + phy = <&phy1>; ++ phys = <&comphy5 2>; + buffer-manager = <&bm>; + bm,pool-long = <2>; + bm,pool-short = <3>; diff --git a/target/linux/mvebu/patches-5.15/004-v5.11-ARM-dts-turris-omnia-describe-switch-interrupt.patch b/target/linux/mvebu/patches-5.15/004-v5.11-ARM-dts-turris-omnia-describe-switch-interrupt.patch new file mode 100644 index 0000000000..4bbd80aac4 --- /dev/null +++ b/target/linux/mvebu/patches-5.15/004-v5.11-ARM-dts-turris-omnia-describe-switch-interrupt.patch @@ -0,0 +1,61 @@ +From d29b67c220caf5f4905e1f1576e71bcb6de4af9e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marek=20Beh=C3=BAn?= +Date: Sun, 15 Nov 2020 14:59:19 +0100 +Subject: ARM: dts: turris-omnia: describe switch interrupt +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Describe switch interrupt for Turris Omnia so that the CPU does not have +to poll the switch. We also need to to set mpp45 pin to gpio function +for this. + +Signed-off-by: Marek Behún +Fixes: 26ca8b52d6e1 ("ARM: dts: add support for Turris Omnia") +Cc: linux-arm-kernel@lists.infradead.org +Cc: Uwe Kleine-König +Cc: Jason Cooper +Cc: Gregory CLEMENT +Cc: Andreas Färber +Cc: Andrew Lunn +Cc: Rob Herring +Cc: devicetree@vger.kernel.org +Signed-off-by: Gregory CLEMENT +--- + arch/arm/boot/dts/armada-385-turris-omnia.dts | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/armada-385-turris-omnia.dts ++++ b/arch/arm/boot/dts/armada-385-turris-omnia.dts +@@ -261,13 +261,18 @@ + + /* Switch MV88E6176 at address 0x10 */ + switch@10 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&swint_pins>; + compatible = "marvell,mv88e6085"; + #address-cells = <1>; + #size-cells = <0>; +- dsa,member = <0 0>; + ++ dsa,member = <0 0>; + reg = <0x10>; + ++ interrupt-parent = <&gpio1>; ++ interrupts = <13 IRQ_TYPE_LEVEL_LOW>; ++ + ports { + #address-cells = <1>; + #size-cells = <0>; +@@ -320,6 +325,11 @@ + marvell,function = "gpio"; + }; + ++ swint_pins: swint-pins { ++ marvell,pins = "mpp45"; ++ marvell,function = "gpio"; ++ }; ++ + spi0cs0_pins: spi0cs0-pins { + marvell,pins = "mpp25"; + marvell,function = "spi0"; diff --git a/target/linux/mvebu/patches-5.15/005-v5.11-ARM-dts-turris-omnia-add-SFP-node.patch b/target/linux/mvebu/patches-5.15/005-v5.11-ARM-dts-turris-omnia-add-SFP-node.patch new file mode 100644 index 0000000000..2447a4e240 --- /dev/null +++ b/target/linux/mvebu/patches-5.15/005-v5.11-ARM-dts-turris-omnia-add-SFP-node.patch @@ -0,0 +1,90 @@ +From add2d65962977caf23ca2fa21a2457d31b636574 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marek=20Beh=C3=BAn?= +Date: Mon, 16 Nov 2020 13:24:22 +0100 +Subject: ARM: dts: turris-omnia: add SFP node +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Turris Omnia has an SFP cage that, together with WAN PHY, is connected +to eth2 SerDes via a SerDes multiplexor. When a SFP module is present, +the multiplexor switches the SerDes signal from PHY to SFP. + +Describe the SFP cage, but leave it disabled. Until phylink has support +for such configuration, we are leaving it to U-Boot to enable SFP and +disable WAN PHY at boot time depending on whether a SFP module is +present. + +Signed-off-by: Marek Behún +Fixes: 26ca8b52d6e1 ("ARM: dts: add support for Turris Omnia") +Reviewed-by: Andrew Lunn +Cc: Russell King - ARM Linux admin +Cc: linux-arm-kernel@lists.infradead.org +Cc: Uwe Kleine-König +Cc: Jason Cooper +Cc: Gregory CLEMENT +Cc: Andreas Färber +Cc: Rob Herring +Cc: devicetree@vger.kernel.org +Signed-off-by: Gregory CLEMENT +--- + arch/arm/boot/dts/armada-385-turris-omnia.dts | 30 ++++++++++++++++++++++++++- + 1 file changed, 29 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/armada-385-turris-omnia.dts ++++ b/arch/arm/boot/dts/armada-385-turris-omnia.dts +@@ -82,6 +82,24 @@ + }; + }; + }; ++ ++ sfp: sfp { ++ compatible = "sff,sfp"; ++ i2c-bus = <&sfp_i2c>; ++ tx-fault-gpios = <&pcawan 0 GPIO_ACTIVE_HIGH>; ++ tx-disable-gpios = <&pcawan 1 GPIO_ACTIVE_HIGH>; ++ rate-select0-gpios = <&pcawan 2 GPIO_ACTIVE_HIGH>; ++ los-gpios = <&pcawan 3 GPIO_ACTIVE_HIGH>; ++ mod-def0-gpios = <&pcawan 4 GPIO_ACTIVE_LOW>; ++ maximum-power-milliwatt = <3000>; ++ ++ /* ++ * For now this has to be enabled at boot time by U-Boot when ++ * a SFP module is present. Read more in the comment in the ++ * eth2 node below. ++ */ ++ status = "disabled"; ++ }; + }; + + &bm { +@@ -126,10 +144,20 @@ + + /* WAN port */ + ð2 { ++ /* ++ * eth2 is connected via a multiplexor to both the SFP cage and to ++ * ethernet-phy@1. The multiplexor switches the signal to SFP cage when ++ * a SFP module is present, as determined by the mode-def0 GPIO. ++ * ++ * Until kernel supports this configuration properly, in case SFP module ++ * is present, U-Boot has to enable the sfp node above, remove phy ++ * handle and add managed = "in-band-status" property. ++ */ + status = "okay"; + phy-mode = "sgmii"; + phy = <&phy1>; + phys = <&comphy5 2>; ++ sfp = <&sfp>; + buffer-manager = <&bm>; + bm,pool-long = <2>; + bm,pool-short = <3>; +@@ -195,7 +223,7 @@ + /* routed to PCIe2 connector (CN62A) */ + }; + +- i2c@4 { ++ sfp_i2c: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; diff --git a/target/linux/mvebu/patches-5.15/006-v5.11-ARM-dts-turris-omnia-add-LED-controller-node.patch b/target/linux/mvebu/patches-5.15/006-v5.11-ARM-dts-turris-omnia-add-LED-controller-node.patch new file mode 100644 index 0000000000..c69067dbdc --- /dev/null +++ b/target/linux/mvebu/patches-5.15/006-v5.11-ARM-dts-turris-omnia-add-LED-controller-node.patch @@ -0,0 +1,160 @@ +From 91dd42d0e30fdbb250c61d1192af569f07e6ada4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marek=20Beh=C3=BAn?= +Date: Sun, 15 Nov 2020 14:59:21 +0100 +Subject: ARM: dts: turris-omnia: add LED controller node +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Linux now has incomplete support for the LED controller on Turris Omnia: +it can set brightness and colors for each LED. + +The controller can also put these LEDs into HW controlled mode, in which +the LEDs are controlled by HW: for example the WAN LED is connected via +MCU to the WAN PHY LED pin. + +The driver does not support these HW controlled modes yet, and on probe +puts the LEDs into SW controlled mode. + +Add node describing the LED controller, but disable it for now. + +Signed-off-by: Marek Behún +Cc: linux-arm-kernel@lists.infradead.org +Cc: Uwe Kleine-König +Cc: Jason Cooper +Cc: Gregory CLEMENT +Cc: Andreas Färber +Cc: Rob Herring +Cc: devicetree@vger.kernel.org +Signed-off-by: Gregory CLEMENT +--- + arch/arm/boot/dts/armada-385-turris-omnia.dts | 111 +++++++++++++++++++++++++- + 1 file changed, 110 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/armada-385-turris-omnia.dts ++++ b/arch/arm/boot/dts/armada-385-turris-omnia.dts +@@ -12,6 +12,7 @@ + + #include + #include ++#include + #include "armada-385.dtsi" + + / { +@@ -181,7 +182,115 @@ + reg = <0>; + + /* STM32F0 command interface at address 0x2a */ +- /* leds device (in STM32F0) at address 0x2b */ ++ ++ led-controller@2b { ++ compatible = "cznic,turris-omnia-leds"; ++ reg = <0x2b>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ /* ++ * LEDs are controlled by MCU (STM32F0) at ++ * address 0x2b. ++ * ++ * The driver does not support HW control mode ++ * for the LEDs yet. Disable the LEDs for now. ++ * ++ * Also LED functions are not stable yet: ++ * - there are 3 LEDs connected via MCU to PCIe ++ * ports. One of these ports supports mSATA. ++ * There is no mSATA nor PCIe function. ++ * For now we use LED_FUNCTION_WLAN, since ++ * in most cases users have wifi cards in ++ * these slots ++ * - there are 2 LEDs dedicated for user: A and ++ * B. Again there is no such function defined. ++ * For now we use LED_FUNCTION_INDICATOR ++ */ ++ status = "disabled"; ++ ++ multi-led@0 { ++ reg = <0x0>; ++ color = ; ++ function = LED_FUNCTION_INDICATOR; ++ function-enumerator = <2>; ++ }; ++ ++ multi-led@1 { ++ reg = <0x1>; ++ color = ; ++ function = LED_FUNCTION_INDICATOR; ++ function-enumerator = <1>; ++ }; ++ ++ multi-led@2 { ++ reg = <0x2>; ++ color = ; ++ function = LED_FUNCTION_WLAN; ++ function-enumerator = <3>; ++ }; ++ ++ multi-led@3 { ++ reg = <0x3>; ++ color = ; ++ function = LED_FUNCTION_WLAN; ++ function-enumerator = <2>; ++ }; ++ ++ multi-led@4 { ++ reg = <0x4>; ++ color = ; ++ function = LED_FUNCTION_WLAN; ++ function-enumerator = <1>; ++ }; ++ ++ multi-led@5 { ++ reg = <0x5>; ++ color = ; ++ function = LED_FUNCTION_WAN; ++ }; ++ ++ multi-led@6 { ++ reg = <0x6>; ++ color = ; ++ function = LED_FUNCTION_LAN; ++ function-enumerator = <4>; ++ }; ++ ++ multi-led@7 { ++ reg = <0x7>; ++ color = ; ++ function = LED_FUNCTION_LAN; ++ function-enumerator = <3>; ++ }; ++ ++ multi-led@8 { ++ reg = <0x8>; ++ color = ; ++ function = LED_FUNCTION_LAN; ++ function-enumerator = <2>; ++ }; ++ ++ multi-led@9 { ++ reg = <0x9>; ++ color = ; ++ function = LED_FUNCTION_LAN; ++ function-enumerator = <1>; ++ }; ++ ++ multi-led@a { ++ reg = <0xa>; ++ color = ; ++ function = LED_FUNCTION_LAN; ++ function-enumerator = <0>; ++ }; ++ ++ multi-led@b { ++ reg = <0xb>; ++ color = ; ++ function = LED_FUNCTION_POWER; ++ }; ++ }; + + eeprom@54 { + compatible = "atmel,24c64"; diff --git a/target/linux/mvebu/patches-5.15/007-v5.11-ARM-dts-turris-omnia-update-ethernet-phy-node-and-handle-name.patch b/target/linux/mvebu/patches-5.15/007-v5.11-ARM-dts-turris-omnia-update-ethernet-phy-node-and-handle-name.patch new file mode 100644 index 0000000000..603a29106b --- /dev/null +++ b/target/linux/mvebu/patches-5.15/007-v5.11-ARM-dts-turris-omnia-update-ethernet-phy-node-and-handle-name.patch @@ -0,0 +1,52 @@ +From 8ee4a5f4f40da60bb85e13d9dd218a3c9197e3e3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marek=20Beh=C3=BAn?= +Date: Sun, 15 Nov 2020 14:59:22 +0100 +Subject: ARM: dts: turris-omnia: update ethernet-phy node and handle name +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Use property name `phy-handle` instead of the deprecated `phy` to +connect eth2 to the PHY. +Rename the node from "phy@1" to "ethernet-phy@1", since "phy@1" is +incorrect according to device-tree bindings documentation. +Also remove the "ethernet-phy-id0141.0DD1" compatible string, it is not +needed. Kernel can read the PHY identifier itself. + +Signed-off-by: Marek Behún +Reviewed-by: Andrew Lunn +Cc: linux-arm-kernel@lists.infradead.org +Cc: Uwe Kleine-König +Cc: Jason Cooper +Cc: Gregory CLEMENT +Cc: Andreas Färber +Cc: Rob Herring +Cc: devicetree@vger.kernel.org +Signed-off-by: Gregory CLEMENT +--- + arch/arm/boot/dts/armada-385-turris-omnia.dts | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/arch/arm/boot/dts/armada-385-turris-omnia.dts ++++ b/arch/arm/boot/dts/armada-385-turris-omnia.dts +@@ -156,7 +156,7 @@ + */ + status = "okay"; + phy-mode = "sgmii"; +- phy = <&phy1>; ++ phy-handle = <&phy1>; + phys = <&comphy5 2>; + sfp = <&sfp>; + buffer-manager = <&bm>; +@@ -387,9 +387,9 @@ + pinctrl-0 = <&mdio_pins>; + status = "okay"; + +- phy1: phy@1 { ++ phy1: ethernet-phy@1 { + status = "okay"; +- compatible = "ethernet-phy-id0141.0DD1", "ethernet-phy-ieee802.3-c22"; ++ compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + marvell,reg-init = <3 18 0 0x4985>; + diff --git a/target/linux/mvebu/patches-5.15/008-v5.12-ARM-dts-turris-omnia-fix-hardware-buffer-management.patch b/target/linux/mvebu/patches-5.15/008-v5.12-ARM-dts-turris-omnia-fix-hardware-buffer-management.patch new file mode 100644 index 0000000000..7f5322e7f3 --- /dev/null +++ b/target/linux/mvebu/patches-5.15/008-v5.12-ARM-dts-turris-omnia-fix-hardware-buffer-management.patch @@ -0,0 +1,33 @@ +From 5b2c7e0ae762fff2b172caf16b2766cc3e1ad859 Mon Sep 17 00:00:00 2001 +From: Rui Salvaterra +Date: Wed, 17 Feb 2021 15:30:38 +0000 +Subject: ARM: dts: turris-omnia: fix hardware buffer management +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Hardware buffer management has never worked on the Turris Omnia, as the +required MBus window hadn't been reserved. Fix thusly. + +Fixes: 018b88eee1a2 ("ARM: dts: turris-omnia: enable HW buffer management") + +Signed-off-by: Rui Salvaterra +Reviewed-by: Marek Behún +Tested-by: Klaus Kudielka +Signed-off-by: Gregory CLEMENT +--- + arch/arm/boot/dts/armada-385-turris-omnia.dts | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/armada-385-turris-omnia.dts ++++ b/arch/arm/boot/dts/armada-385-turris-omnia.dts +@@ -32,7 +32,8 @@ + ranges = ; ++ MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000 ++ MBUS_ID(0x0c, 0x04) 0 0xf1200000 0x100000>; + + internal-regs { + 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..36f10fcfb5 --- /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 +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: 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 + +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 +--- + 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 +@@ -1781,6 +1781,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: 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 +@@ -110,6 +110,10 @@ + + #include + ++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE) ++#include ++#endif ++ + static int kernel_init(void *); + + extern void init_IRQ(void); +@@ -904,6 +908,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..efbbbc7d78 --- /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 +@@ -212,11 +212,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/303-linksys_hardcode_nand_ecc_settings.patch b/target/linux/mvebu/patches-5.15/303-linksys_hardcode_nand_ecc_settings.patch new file mode 100644 index 0000000000..89a5e19803 --- /dev/null +++ b/target/linux/mvebu/patches-5.15/303-linksys_hardcode_nand_ecc_settings.patch @@ -0,0 +1,17 @@ +Newer Linksys boards might come with a Winbond W29N02GV which can be +configured in different ways. Make sure we configure it the same way +as the older chips so everything keeps working. + +Signed-off-by: Imre Kaloz + +--- a/arch/arm/boot/dts/armada-385-linksys.dtsi ++++ b/arch/arm/boot/dts/armada-385-linksys.dtsi +@@ -148,6 +148,8 @@ + reg = <0>; + label = "pxa3xx_nand-0"; + nand-rb = <0>; ++ nand-ecc-strength = <4>; ++ nand-ecc-step-size = <512>; + marvell,nand-keep-config; + nand-on-flash-bbt; + }; 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 +Date: Tue, 13 Jan 2015 11:14:09 +0100 +Subject: [PATCH 2/2] ARM: mvebu: 385-ap: Add partitions + +Signed-off-by: Maxime Ripard +--- + 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 @@ + }; + + ð2 { +- 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 = <ð2>; ++ ethernet = <ð0>; + + 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 +Date: Tue, 29 Nov 2016 10:15:45 +0000 +Subject: ARM: dts: armada388-clearfog: emmc on clearfog base + +Signed-off-by: Russell King +--- + 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 = <µsom_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/314-arm64-dts-uDPU-switch-PHY-operation-mode-to-2500base.patch b/target/linux/mvebu/patches-5.15/314-arm64-dts-uDPU-switch-PHY-operation-mode-to-2500base.patch new file mode 100644 index 0000000000..2240d0b39e --- /dev/null +++ b/target/linux/mvebu/patches-5.15/314-arm64-dts-uDPU-switch-PHY-operation-mode-to-2500base.patch @@ -0,0 +1,34 @@ +Certain SFP modules (most notably Nokia GPON ones) first check +connectivity on 1000base-x, and switch to 2500base-x afterwards. This +is considered a quirk so the phylink switches the interface to +2500base-x as well. + +However, after power-cycling the uDPU device, network interface/SFP module +will not work correctly until the module is re-seated. This patch +resolves this issue by forcing the interface to be brought up in +2500base-x mode by default. + +Signed-off-by: Jakov Petrina +Signed-off-by: Vladimir Vid +Cc: Luka Perkov + +--- a/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts ++++ b/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts +@@ -162,7 +162,7 @@ + }; + + ð0 { +- phy-mode = "sgmii"; ++ phy-mode = "2500base-x"; + status = "okay"; + managed = "in-band-status"; + phys = <&comphy1 0>; +@@ -170,7 +170,7 @@ + }; + + ð1 { +- phy-mode = "sgmii"; ++ phy-mode = "2500base-x"; + status = "okay"; + managed = "in-band-status"; + phys = <&comphy0 1>; 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 +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 +--- + 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 + +--- 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..a0f15681f5 --- /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 +--- +--- a/drivers/net/ethernet/marvell/mvneta.c ++++ b/drivers/net/ethernet/marvell/mvneta.c +@@ -4903,6 +4903,16 @@ static int mvneta_ethtool_set_eee(struct + return phylink_ethtool_set_eee(pp->phylink, eee); + } + ++#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, +@@ -4913,6 +4923,9 @@ static const struct net_device_ops mvnet + .ndo_fix_features = mvneta_fix_features, + .ndo_get_stats64 = mvneta_get_stats64, + .ndo_do_ioctl = mvneta_ioctl, ++#ifndef CONFIG_ARM64 ++ .ndo_select_queue = mvneta_select_queue, ++#endif + .ndo_bpf = mvneta_xdp, + .ndo_xdp_xmit = mvneta_xdp_xmit, + }; diff --git a/target/linux/mvebu/patches-5.15/701-v5.14-net-ethernet-marvell-mvnetaMQPrio.patch b/target/linux/mvebu/patches-5.15/701-v5.14-net-ethernet-marvell-mvnetaMQPrio.patch new file mode 100644 index 0000000000..36d4942f8b --- /dev/null +++ b/target/linux/mvebu/patches-5.15/701-v5.14-net-ethernet-marvell-mvnetaMQPrio.patch @@ -0,0 +1,109 @@ +From 4906887a8ae5f1296f8079bcf4565a6092a8e402 Mon Sep 17 00:00:00 2001 +From: Maxime Chevallier +Date: Tue, 16 Feb 2021 10:25:36 +0100 +Subject: net: mvneta: Implement mqprio support + +Implement a basic MQPrio support, inserting rules in RX that translate +the TC to prio mapping into vlan prio to queues. + +The TX logic stays the same as when we don't offload the qdisc. + +Signed-off-by: Maxime Chevallier +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/marvell/mvneta.c | 61 +++++++++++++++++++++++++++++++++++ + 1 file changed, 61 insertions(+) + +(limited to 'drivers/net/ethernet/marvell/mvneta.c') + +--- a/drivers/net/ethernet/marvell/mvneta.c ++++ b/drivers/net/ethernet/marvell/mvneta.c +@@ -102,6 +102,8 @@ + #define MVNETA_TX_NO_DATA_SWAP BIT(5) + #define MVNETA_DESC_SWAP BIT(6) + #define MVNETA_TX_BRST_SZ_MASK(burst) ((burst) << 22) ++#define MVNETA_VLAN_PRIO_TO_RXQ 0x2440 ++#define MVNETA_VLAN_PRIO_RXQ_MAP(prio, rxq) ((rxq) << ((prio) * 3)) + #define MVNETA_PORT_STATUS 0x2444 + #define MVNETA_TX_IN_PRGRS BIT(0) + #define MVNETA_TX_FIFO_EMPTY BIT(8) +@@ -490,6 +492,7 @@ 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; +@@ -4913,6 +4916,63 @@ static u16 mvneta_select_queue(struct ne + } + #endif + ++static void mvneta_clear_rx_prio_map(struct mvneta_port *pp) ++{ ++ mvreg_write(pp, MVNETA_VLAN_PRIO_TO_RXQ, 0); ++} ++ ++static void mvneta_setup_rx_prio_map(struct mvneta_port *pp) ++{ ++ u32 val = 0; ++ int i; ++ ++ for (i = 0; i < rxq_number; i++) ++ val |= MVNETA_VLAN_PRIO_RXQ_MAP(i, pp->prio_tc_map[i]); ++ ++ mvreg_write(pp, MVNETA_VLAN_PRIO_TO_RXQ, val); ++} ++ ++static int mvneta_setup_mqprio(struct net_device *dev, ++ struct tc_mqprio_qopt *qopt) ++{ ++ struct mvneta_port *pp = netdev_priv(dev); ++ u8 num_tc; ++ int i; ++ ++ qopt->hw = TC_MQPRIO_HW_OFFLOAD_TCS; ++ num_tc = qopt->num_tc; ++ ++ if (num_tc > rxq_number) ++ return -EINVAL; ++ ++ if (!num_tc) { ++ mvneta_clear_rx_prio_map(pp); ++ netdev_reset_tc(dev); ++ return 0; ++ } ++ ++ memcpy(pp->prio_tc_map, 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]); ++ ++ return 0; ++} ++ ++static int mvneta_setup_tc(struct net_device *dev, enum tc_setup_type type, ++ void *type_data) ++{ ++ switch (type) { ++ case TC_SETUP_QDISC_MQPRIO: ++ return mvneta_setup_mqprio(dev, type_data); ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ + static const struct net_device_ops mvneta_netdev_ops = { + .ndo_open = mvneta_open, + .ndo_stop = mvneta_stop, +@@ -4928,6 +4988,7 @@ static const struct net_device_ops mvnet + #endif + .ndo_bpf = mvneta_xdp, + .ndo_xdp_xmit = mvneta_xdp_xmit, ++ .ndo_setup_tc = mvneta_setup_tc, + }; + + static const struct ethtool_ops mvneta_eth_tool_ops = { 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..41f8c1fbfd --- /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 +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 +Signed-off-by: David S. Miller +--- + 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 + #include + #include ++#include + #include + + /* Registers */ +@@ -4933,14 +4934,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; +@@ -4951,13 +4952,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..8529b6ae5e --- /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 +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 +Signed-off-by: David S. Miller +--- + 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 +@@ -4940,7 +4940,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..ed4f0441dd --- /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 +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 +Signed-off-by: David S. Miller +--- + 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; +@@ -4922,13 +4921,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); + } +@@ -4937,8 +4935,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; +@@ -4948,21 +4946,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..15a0ce6b58 --- /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 +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 +Signed-off-by: David S. Miller +--- + 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) +@@ -4931,11 +4958,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) +@@ -4949,6 +5039,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; + } +@@ -4969,6 +5060,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 +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 +--- + 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..a5e49552e9 --- /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 +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 +--- + 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 +@@ -941,6 +941,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); +@@ -948,7 +949,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; +@@ -1108,15 +1115,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..28b2b19499 --- /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 +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 +Signed-off-by: Pavo Banicevic +Cc: Luka Perkov +Cc: Robert Marko +--- + .../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 ++ ++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 ++ ++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 ++ ++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 ++ 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 = ; ++ }; ++ }; ++ ++ 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 +@@ -475,6 +475,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..01c2ecce0d --- /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 +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 +Signed-off-by: Pavo Banicevic +Cc: Luka Perkov +Cc: Robert Marko +--- + 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 +@@ -2155,6 +2155,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_HI655X_PMIC) += hi655 + obj-$(CONFIG_MFD_DLN2) += dln2.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 ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* 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 "); ++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 ++ */ ++ ++#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..684f09c800 --- /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 +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 +Signed-off-by: Pavo Banicevic +Acked-by: Guenter Roeck +Cc: Luka Perkov +Cc: Robert Marko +--- + 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 +@@ -722,6 +722,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 +@@ -83,6 +83,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 ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 "); ++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..37f98b6ba8 --- /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 +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 +Signed-off-by: Pavo Banicevic +Cc: Luka Perkov +Cc: Robert Marko +--- + 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 +@@ -333,6 +333,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 +@@ -35,6 +35,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_KTD2692) += leds-ktd2692.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 ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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 "); ++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 +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 +Signed-off-by: Pavo Banicevic +Cc: Luka Perkov +Cc: Robert Marko +--- + .../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 ++Description: (RW) Internal factory assigned MAC address values ++ ++What: /sys/bus/serial/devices/.../serial_number ++Date: September 2020 ++Contact: Luka Kovacic ++Description: (RW) Internal factory assigned serial number ++ ++What: /sys/bus/serial/devices/.../version ++Date: September 2020 ++Contact: Luka Kovacic ++Description: (RO) Internal MCU firmware version ++ ++What: /sys/bus/serial/devices/.../protocol_version ++Date: September 2020 ++Contact: Luka Kovacic ++Description: (RO) Internal MCU communication protocol version ++ ++What: /sys/bus/serial/devices/.../power_loss_recovery ++Date: September 2020 ++Contact: Luka Kovacic ++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 ++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 ++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 ++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 ++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..345d4ca03b --- /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 +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 +Signed-off-by: Pavo Banicevic +Cc: Luka Perkov +Cc: Robert Marko +--- + .../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 ++ ++ ++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 +@@ -71,6 +71,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..577a9b40de --- /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 +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 +Signed-off-by: Pavo Banicevic +Cc: Luka Perkov +Cc: Robert Marko +--- + MAINTAINERS | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -8538,6 +8538,22 @@ F: include/net/nl802154.h + F: net/ieee802154/ + F: net/mac802154/ + ++IEI WT61P803 M801 MFD DRIVER ++M: Luka Kovacic ++M: Luka Perkov ++M: Goran Medic ++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 + M: Jamal Hadi Salim 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 + #include + #include ++#include + #include + #include + #include ++#include ++ ++#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", ®); ++ 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;