Merge https://gitlab.denx.de/u-boot/custodians/u-boot-marvell

- mvebu: Add Armada 38x pin muxing support (Pali)
- a37xx: pinctrl: Fix requesting GPIOs and pinmux command (Pali)
- mvebu: pinctrl: apply SDHCI PHY config for A7K (Kosta)
- gpio: Add Turris Omnia MCU driver (Pali)
- cmd: mvebu/bubt: Improvements for image verification (Pali)
- mvebu: turris_omnia: Fix mpp26 pin name and comment (Marek)
diff --git a/arch/arm/dts/armada-370-xp.dtsi b/arch/arm/dts/armada-370-xp.dtsi
index 50fc0be..4cd168c 100644
--- a/arch/arm/dts/armada-370-xp.dtsi
+++ b/arch/arm/dts/armada-370-xp.dtsi
@@ -246,7 +246,7 @@
 			};
 
 			nand@d0000 {
-				compatible = "marvell,armada370-nand";
+				compatible = "marvell,armada370-nand-controller";
 				reg = <0xd0000 0x54>;
 				#address-cells = <1>;
 				#size-cells = <1>;
diff --git a/arch/arm/dts/armada-375.dtsi b/arch/arm/dts/armada-375.dtsi
index ff0ad7a..fcb9245 100644
--- a/arch/arm/dts/armada-375.dtsi
+++ b/arch/arm/dts/armada-375.dtsi
@@ -541,7 +541,7 @@
 			};
 
 			nand@d0000 {
-				compatible = "marvell,armada370-nand";
+				compatible = "marvell,armada370-nand-controller";
 				reg = <0xd0000 0x54>;
 				#address-cells = <1>;
 				#size-cells = <1>;
diff --git a/arch/arm/dts/armada-385-turris-omnia-u-boot.dtsi b/arch/arm/dts/armada-385-turris-omnia-u-boot.dtsi
index 5a22cc6..ec12298 100644
--- a/arch/arm/dts/armada-385-turris-omnia-u-boot.dtsi
+++ b/arch/arm/dts/armada-385-turris-omnia-u-boot.dtsi
@@ -28,11 +28,8 @@
 		i2c@5 {
 			u-boot,dm-pre-reloc;
 
-			/* ATSHA204A at address 0x64 */
 			crypto@64 {
 				u-boot,dm-pre-reloc;
-				compatible = "atmel,atsha204a";
-				reg = <0x64>;
 			};
 		};
 	};
@@ -42,7 +39,7 @@
 &spi0 {
 	u-boot,dm-pre-reloc;
 
-	spi-nor@0 {
+	flash@0 {
 		u-boot,dm-pre-reloc;
 
 		partitions {
diff --git a/arch/arm/dts/armada-385-turris-omnia.dts b/arch/arm/dts/armada-385-turris-omnia.dts
index 7f1478e..0be55f8 100644
--- a/arch/arm/dts/armada-385-turris-omnia.dts
+++ b/arch/arm/dts/armada-385-turris-omnia.dts
@@ -1,43 +1,10 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
 /*
  * Device Tree file for the Turris Omnia
  *
  * Copyright (C) 2016 Uwe Kleine-König <uwe@kleine-koenig.org>
  * Copyright (C) 2016 Tomas Hlavacek <tmshlvkc@gmail.com>
  *
- * 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 licensed under the terms of the GNU General Public
- *     License version 2.  This program is licensed "as is" without
- *     any warranty of any kind, whether express or implied.
- *
- * 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 "AS IS", 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.
- */
-
-/*
  * Schematic available at https://www.turris.cz/doc/_media/rtrom01-schema.pdf
  */
 
@@ -45,6 +12,7 @@
 
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
 #include "armada-385.dtsi"
 
 / {
@@ -70,7 +38,8 @@
 		ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
 			  MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000
 			  MBUS_ID(0x09, 0x19) 0 0xf1100000 0x10000
-			  MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000>;
+			  MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000
+			  MBUS_ID(0x0c, 0x04) 0 0xf1200000 0x100000>;
 
 		internal-regs {
 
@@ -108,19 +77,48 @@
 			pcie@1,0 {
 				/* Port 0, Lane 0 */
 				status = "okay";
+				slot-power-limit-milliwatt = <10000>;
 			};
 
 			pcie@2,0 {
 				/* Port 1, Lane 0 */
 				status = "okay";
+				slot-power-limit-milliwatt = <10000>;
 			};
 
 			pcie@3,0 {
 				/* Port 2, Lane 0 */
 				status = "okay";
+				slot-power-limit-milliwatt = <10000>;
 			};
 		};
 	};
+
+	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 {
+	status = "okay";
+};
+
+&bm_bppi {
+	status = "okay";
 };
 
 /* Connected to 88E6176 switch, port 6 */
@@ -129,6 +127,9 @@
 	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>;
@@ -142,6 +143,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>;
@@ -151,9 +155,23 @@
 
 /* WAN port */
 &eth2 {
+	/*
+	 * 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>;
+	phy-handle = <&phy1>;
+	phys = <&comphy5 2>;
+	sfp = <&sfp>;
+	buffer-manager = <&bm>;
+	bm,pool-long = <2>;
+	bm,pool-short = <3>;
 };
 
 &i2c0 {
@@ -166,18 +184,128 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 		reg = <0x70>;
-		status = "okay";
 
 		i2c@0 {
 			#address-cells = <1>;
 			#size-cells = <0>;
 			reg = <0>;
 
-			/* STM32F0 command interface at address 0x2a */
-			/* leds device (in STM32F0) at address 0x2b */
+			/* MCU command i2c API */
+			mcu: mcu@2a {
+				compatible = "cznic,turris-omnia-mcu";
+				reg = <0x2a>;
+				gpio-controller;
+				#gpio-cells = <3>;
+			};
+
+			led-controller@2b {
+				compatible = "cznic,turris-omnia-leds";
+				reg = <0x2b>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "okay";
+
+				/*
+				 * LEDs are controlled by MCU (STM32F0) at
+				 * address 0x2b.
+				 *
+				 * 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
+				 */
+
+				multi-led@0 {
+					reg = <0x0>;
+					color = <LED_COLOR_ID_RGB>;
+					function = LED_FUNCTION_INDICATOR;
+					function-enumerator = <2>;
+				};
+
+				multi-led@1 {
+					reg = <0x1>;
+					color = <LED_COLOR_ID_RGB>;
+					function = LED_FUNCTION_INDICATOR;
+					function-enumerator = <1>;
+				};
+
+				multi-led@2 {
+					reg = <0x2>;
+					color = <LED_COLOR_ID_RGB>;
+					function = LED_FUNCTION_WLAN;
+					function-enumerator = <3>;
+				};
+
+				multi-led@3 {
+					reg = <0x3>;
+					color = <LED_COLOR_ID_RGB>;
+					function = LED_FUNCTION_WLAN;
+					function-enumerator = <2>;
+				};
+
+				multi-led@4 {
+					reg = <0x4>;
+					color = <LED_COLOR_ID_RGB>;
+					function = LED_FUNCTION_WLAN;
+					function-enumerator = <1>;
+				};
+
+				multi-led@5 {
+					reg = <0x5>;
+					color = <LED_COLOR_ID_RGB>;
+					function = LED_FUNCTION_WAN;
+				};
+
+				multi-led@6 {
+					reg = <0x6>;
+					color = <LED_COLOR_ID_RGB>;
+					function = LED_FUNCTION_LAN;
+					function-enumerator = <4>;
+				};
+
+				multi-led@7 {
+					reg = <0x7>;
+					color = <LED_COLOR_ID_RGB>;
+					function = LED_FUNCTION_LAN;
+					function-enumerator = <3>;
+				};
+
+				multi-led@8 {
+					reg = <0x8>;
+					color = <LED_COLOR_ID_RGB>;
+					function = LED_FUNCTION_LAN;
+					function-enumerator = <2>;
+				};
+
+				multi-led@9 {
+					reg = <0x9>;
+					color = <LED_COLOR_ID_RGB>;
+					function = LED_FUNCTION_LAN;
+					function-enumerator = <1>;
+				};
+
+				multi-led@a {
+					reg = <0xa>;
+					color = <LED_COLOR_ID_RGB>;
+					function = LED_FUNCTION_LAN;
+					function-enumerator = <0>;
+				};
+
+				multi-led@b {
+					reg = <0xb>;
+					color = <LED_COLOR_ID_RGB>;
+					function = LED_FUNCTION_POWER;
+				};
+			};
 
 			eeprom@54 {
-				compatible = "at,24c64";
+				compatible = "atmel,24c64";
 				reg = <0x54>;
 
 				/* The EEPROM contains data for bootloader.
@@ -216,7 +344,7 @@
 			/* routed to PCIe2 connector (CN62A) */
 		};
 
-		i2c@4 {
+		sfp_i2c: i2c@4 {
 			#address-cells = <1>;
 			#size-cells = <0>;
 			reg = <4>;
@@ -229,7 +357,11 @@
 			#size-cells = <0>;
 			reg = <5>;
 
-			/* ATSHA204A at address 0x64 */
+			/* ATSHA204A-MAHDA-T crypto module */
+			crypto@64 {
+				compatible = "atmel,atsha204a";
+				reg = <0x64>;
+			};
 		};
 
 		i2c@6 {
@@ -271,23 +403,29 @@
 	pinctrl-0 = <&mdio_pins>;
 	status = "okay";
 
-	phy1: phy@1 {
-		status = "okay";
-		compatible = "ethernet-phy-id0141.0DD1", "ethernet-phy-ieee802.3-c22";
+	phy1: ethernet-phy@1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
 		reg = <1>;
+		marvell,reg-init = <3 18 0 0x4985>,
+				   <3 16 0xfff0 0x0001>;
 
 		/* irq is connected to &pcawan pin 7 */
 	};
 
 	/* 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>;
@@ -340,12 +478,17 @@
 		marvell,function = "gpio";
 	};
 
+	swint_pins: swint-pins {
+		marvell,pins = "mpp45";
+		marvell,function = "gpio";
+	};
+
 	spi0cs0_pins: spi0cs0-pins {
 		marvell,pins = "mpp25";
 		marvell,function = "spi0";
 	};
 
-	spi0cs1_pins: spi0cs1-pins {
+	spi0cs2_pins: spi0cs2-pins {
 		marvell,pins = "mpp26";
 		marvell,function = "spi0";
 	};
@@ -356,7 +499,7 @@
 	pinctrl-0 = <&spi0_pins &spi0cs0_pins>;
 	status = "okay";
 
-	spi-nor@0 {
+	flash@0 {
 		compatible = "spansion,s25fl164k", "jedec,spi-nor";
 		#address-cells = <1>;
 		#size-cells = <1>;
@@ -380,7 +523,7 @@
 		};
 	};
 
-	/* MISO, MOSI, SCLK and CS1 are routed to pin header CN11 */
+	/* MISO, MOSI, SCLK and CS2 are routed to pin header CN11 */
 };
 
 &uart0 {
diff --git a/arch/arm/dts/armada-385.dtsi b/arch/arm/dts/armada-385.dtsi
index 581a7d9..48072fc 100644
--- a/arch/arm/dts/armada-385.dtsi
+++ b/arch/arm/dts/armada-385.dtsi
@@ -69,17 +69,26 @@
 				reg = <0x0800 0 0 0 0>;
 				#address-cells = <3>;
 				#size-cells = <2>;
+				interrupt-names = "intx";
+				interrupts-extended = <&gic GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
 				#interrupt-cells = <1>;
 				ranges = <0x82000000 0 0 0x82000000 0x1 0 1 0
 					  0x81000000 0 0 0x81000000 0x1 0 1 0>;
 				bus-range = <0x00 0xff>;
-				interrupt-map-mask = <0 0 0 0>;
-				interrupt-map = <0 0 0 0 &gic GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-map-mask = <0 0 0 7>;
+				interrupt-map = <0 0 0 1 &pcie1_intc 0>,
+						<0 0 0 2 &pcie1_intc 1>,
+						<0 0 0 3 &pcie1_intc 2>,
+						<0 0 0 4 &pcie1_intc 3>;
 				marvell,pcie-port = <0>;
 				marvell,pcie-lane = <0>;
 				clocks = <&gateclk 8>;
 				resets = <&systemc 0 0>;
 				status = "disabled";
+				pcie1_intc: interrupt-controller {
+					interrupt-controller;
+					#interrupt-cells = <1>;
+				};
 			};
 
 			/* x1 port */
@@ -89,17 +98,26 @@
 				reg = <0x1000 0 0 0 0>;
 				#address-cells = <3>;
 				#size-cells = <2>;
+				interrupt-names = "intx";
+				interrupts-extended = <&gic GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
 				#interrupt-cells = <1>;
 				ranges = <0x82000000 0 0 0x82000000 0x2 0 1 0
 					  0x81000000 0 0 0x81000000 0x2 0 1 0>;
 				bus-range = <0x00 0xff>;
-				interrupt-map-mask = <0 0 0 0>;
-				interrupt-map = <0 0 0 0 &gic GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-map-mask = <0 0 0 7>;
+				interrupt-map = <0 0 0 1 &pcie2_intc 0>,
+						<0 0 0 2 &pcie2_intc 1>,
+						<0 0 0 3 &pcie2_intc 2>,
+						<0 0 0 4 &pcie2_intc 3>;
 				marvell,pcie-port = <1>;
 				marvell,pcie-lane = <0>;
 				clocks = <&gateclk 5>;
 				resets = <&systemc 0 1>;
 				status = "disabled";
+				pcie2_intc: interrupt-controller {
+					interrupt-controller;
+					#interrupt-cells = <1>;
+				};
 			};
 
 			/* x1 port */
@@ -109,17 +127,26 @@
 				reg = <0x1800 0 0 0 0>;
 				#address-cells = <3>;
 				#size-cells = <2>;
+				interrupt-names = "intx";
+				interrupts-extended = <&gic GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
 				#interrupt-cells = <1>;
 				ranges = <0x82000000 0 0 0x82000000 0x3 0 1 0
 					  0x81000000 0 0 0x81000000 0x3 0 1 0>;
 				bus-range = <0x00 0xff>;
-				interrupt-map-mask = <0 0 0 0>;
-				interrupt-map = <0 0 0 0 &gic GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-map-mask = <0 0 0 7>;
+				interrupt-map = <0 0 0 1 &pcie3_intc 0>,
+						<0 0 0 2 &pcie3_intc 1>,
+						<0 0 0 3 &pcie3_intc 2>,
+						<0 0 0 4 &pcie3_intc 3>;
 				marvell,pcie-port = <2>;
 				marvell,pcie-lane = <0>;
 				clocks = <&gateclk 6>;
 				resets = <&systemc 0 2>;
 				status = "disabled";
+				pcie3_intc: interrupt-controller {
+					interrupt-controller;
+					#interrupt-cells = <1>;
+				};
 			};
 
 			/*
@@ -132,17 +159,26 @@
 				reg = <0x2000 0 0 0 0>;
 				#address-cells = <3>;
 				#size-cells = <2>;
+				interrupt-names = "intx";
+				interrupts-extended = <&gic GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
 				#interrupt-cells = <1>;
 				ranges = <0x82000000 0 0 0x82000000 0x4 0 1 0
 					  0x81000000 0 0 0x81000000 0x4 0 1 0>;
 				bus-range = <0x00 0xff>;
-				interrupt-map-mask = <0 0 0 0>;
-				interrupt-map = <0 0 0 0 &gic GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-map-mask = <0 0 0 7>;
+				interrupt-map = <0 0 0 1 &pcie4_intc 0>,
+						<0 0 0 2 &pcie4_intc 1>,
+						<0 0 0 3 &pcie4_intc 2>,
+						<0 0 0 4 &pcie4_intc 3>;
 				marvell,pcie-port = <3>;
 				marvell,pcie-lane = <0>;
 				clocks = <&gateclk 7>;
 				resets = <&systemc 0 3>;
 				status = "disabled";
+				pcie4_intc: interrupt-controller {
+					interrupt-controller;
+					#interrupt-cells = <1>;
+				};
 			};
 		};
 	};
diff --git a/arch/arm/dts/armada-38x.dtsi b/arch/arm/dts/armada-38x.dtsi
index 061bd78..3e97009 100644
--- a/arch/arm/dts/armada-38x.dtsi
+++ b/arch/arm/dts/armada-38x.dtsi
@@ -9,13 +9,15 @@
  * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
  */
 
-#include "skeleton.dtsi"
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 
 #define MBUS_ID(target,attributes) (((target) << 24) | ((attributes) << 16))
 
 / {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
 	model = "Marvell Armada 38x family SoC";
 	compatible = "marvell,armada380";
 
@@ -103,6 +105,11 @@
 			#size-cells = <1>;
 			ranges = <0 MBUS_ID(0xf0, 0x01) 0 0x100000>;
 
+			sdramc: sdramc@1400 {
+				compatible = "marvell,armada-xp-sdram-controller";
+				reg = <0x1400 0x500>;
+			};
+
 			L2: cache-controller@8000 {
 				compatible = "arm,pl310-cache";
 				reg = <0x8000 0x1000>;
@@ -148,7 +155,6 @@
 				#address-cells = <1>;
 				#size-cells = <0>;
 				interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
-				timeout-ms = <1000>;
 				clocks = <&coreclk 0>;
 				status = "disabled";
 			};
@@ -159,13 +165,12 @@
 				#address-cells = <1>;
 				#size-cells = <0>;
 				interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
-				timeout-ms = <1000>;
 				clocks = <&coreclk 0>;
 				status = "disabled";
 			};
 
 			uart0: serial@12000 {
-				compatible = "snps,dw-apb-uart";
+				compatible = "marvell,armada-38x-uart", "ns16550a";
 				reg = <0x12000 0x100>;
 				reg-shift = <2>;
 				interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
@@ -175,7 +180,7 @@
 			};
 
 			uart1: serial@12100 {
-				compatible = "snps,dw-apb-uart";
+				compatible = "marvell,armada-38x-uart", "ns16550a";
 				reg = <0x12100 0x100>;
 				reg-shift = <2>;
 				interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
@@ -295,6 +300,7 @@
 				reg-names = "gpio", "pwm";
 				ngpios = <32>;
 				gpio-controller;
+				gpio-ranges = <&pinctrl 0 0 32>;
 				#gpio-cells = <2>;
 				#pwm-cells = <2>;
 				interrupt-controller;
@@ -313,6 +319,7 @@
 				reg-names = "gpio", "pwm";
 				ngpios = <28>;
 				gpio-controller;
+				gpio-ranges = <&pinctrl 0 32 28>;
 				#gpio-cells = <2>;
 				#pwm-cells = <2>;
 				interrupt-controller;
@@ -338,6 +345,44 @@
 				#clock-cells = <1>;
 			};
 
+			comphy: phy@18300 {
+				compatible = "marvell,armada-380-comphy";
+				reg-names = "comphy", "conf";
+				reg = <0x18300 0x100>, <0x18460 4>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				comphy0: phy@0 {
+					reg = <0>;
+					#phy-cells = <1>;
+				};
+
+				comphy1: phy@1 {
+					reg = <1>;
+					#phy-cells = <1>;
+				};
+
+				comphy2: phy@2 {
+					reg = <2>;
+					#phy-cells = <1>;
+				};
+
+				comphy3: phy@3 {
+					reg = <3>;
+					#phy-cells = <1>;
+				};
+
+				comphy4: phy@4 {
+					reg = <4>;
+					#phy-cells = <1>;
+				};
+
+				comphy5: phy@5 {
+					reg = <5>;
+					#phy-cells = <1>;
+				};
+			};
+
 			coreclk: mvebu-sar@18600 {
 				compatible = "marvell,armada-380-core-clock";
 				reg = <0x18600 0x04>;
@@ -379,6 +424,8 @@
 				reg = <0x20300 0x34>, <0x20704 0x4>, <0x18260 0x4>;
 				clocks = <&coreclk 2>, <&refclk>;
 				clock-names = "nbclk", "fixed";
+				interrupts-extended = <&gic GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
+						      <&gic GIC_SPI  9 IRQ_TYPE_LEVEL_HIGH>;
 			};
 
 			cpurst: cpurst@20800 {
@@ -555,7 +602,7 @@
 			};
 
 			nand_controller: nand-controller@d0000 {
-				compatible = "marvell,armada370-nand","marvell,mvebu-pxa3xx-nand";
+				compatible = "marvell,armada370-nand-controller";
 				reg = <0xd0000 0x54>;
 				#address-cells = <1>;
 				#size-cells = <0>;
diff --git a/arch/arm/dts/armada-xp-db-xc3-24g4xg-u-boot.dtsi b/arch/arm/dts/armada-xp-db-xc3-24g4xg-u-boot.dtsi
index 90cad85..fdbe168 100644
--- a/arch/arm/dts/armada-xp-db-xc3-24g4xg-u-boot.dtsi
+++ b/arch/arm/dts/armada-xp-db-xc3-24g4xg-u-boot.dtsi
@@ -5,7 +5,7 @@
 };
 
 &nand_controller {
-	compatible="marvell,mvebu-pxa3xx-nand";
+	compatible="marvell,armada370-nand-controller";
 	status = "okay";
 	label = "pxa3xx_nand-0";
 	nand-rb = <0>;
diff --git a/board/CZ.NIC/turris_omnia/MAINTAINERS b/board/CZ.NIC/turris_omnia/MAINTAINERS
index 8258f4f..8bff97cc 100644
--- a/board/CZ.NIC/turris_omnia/MAINTAINERS
+++ b/board/CZ.NIC/turris_omnia/MAINTAINERS
@@ -6,4 +6,5 @@
 F:	board/CZ.NIC/turris_atsha_otp.*
 F:	board/CZ.NIC/turris_omnia/
 F:	configs/turris_omnia_defconfig
+F:	drivers/gpio/turris_omnia_mcu.c
 F:	include/configs/turris_omnia.h
diff --git a/cmd/mvebu/Kconfig b/cmd/mvebu/Kconfig
index 39963db..120397d 100644
--- a/cmd/mvebu/Kconfig
+++ b/cmd/mvebu/Kconfig
@@ -4,6 +4,7 @@
 config CMD_MVEBU_BUBT
 	bool "bubt"
 	select SHA256 if ARMADA_3700
+	select SHA512 if ARMADA_3700
 	help
 	  bubt - Burn a u-boot image to flash
 	  For details about bubt command please see the documentation
diff --git a/cmd/mvebu/bubt.c b/cmd/mvebu/bubt.c
index 1362c03..ffa05bc 100644
--- a/cmd/mvebu/bubt.c
+++ b/cmd/mvebu/bubt.c
@@ -26,6 +26,7 @@
 #endif
 #include <u-boot/sha1.h>
 #include <u-boot/sha256.h>
+#include <u-boot/sha512.h>
 
 #if defined(CONFIG_ARMADA_8K)
 #define MAIN_HDR_MAGIC		0xB105B002
@@ -56,6 +57,21 @@
 #define IMAGE_VERSION_3_6_0	0x030600
 #define IMAGE_VERSION_3_5_0	0x030500
 
+struct tim_boot_flash_sign {
+	unsigned int id;
+	const char *name;
+};
+
+struct tim_boot_flash_sign tim_boot_flash_signs[] = {
+	{ 0x454d4d08, "mmc"  },
+	{ 0x454d4d0b, "mmc"  },
+	{ 0x5350490a, "spi"  },
+	{ 0x5350491a, "nand" },
+	{ 0x55415223, "uart" },
+	{ 0x53415432, "sata" },
+	{},
+};
+
 struct common_tim_data {
 	u32	version;
 	u32	identifier;
@@ -83,7 +99,7 @@
 	u32	encrypt_start_offset;
 	u32	encrypt_size;
 };
-#endif
+#elif defined(CONFIG_ARMADA_32BIT)
 
 /* Structure of the main header, version 1 (Armada 370/XP/375/38x/39x) */
 struct a38x_main_hdr_v1 {
@@ -123,6 +139,8 @@
 	{},
 };
 
+#endif
+
 struct bubt_dev {
 	char name[8];
 	size_t (*read)(const char *file_name);
@@ -438,11 +456,14 @@
 #ifdef CONFIG_CMD_NET
 static size_t tftp_read_file(const char *file_name)
 {
+	int ret;
+
 	/*
 	 * update global variable image_load_addr before tftp file from network
 	 */
 	image_load_addr = get_load_addr();
-	return net_loop(TFTPGET);
+	ret = net_loop(TFTPGET);
+	return ret > 0 ? ret : 0;
 }
 
 static int is_tftp_active(void)
@@ -546,8 +567,10 @@
 	int image_num;
 	u8 hash_160_output[SHA1_SUM_LEN];
 	u8 hash_256_output[SHA256_SUM_LEN];
+	u8 hash_512_output[SHA512_SUM_LEN];
 	sha1_context hash1_text;
 	sha256_context hash256_text;
+	sha512_context hash512_text;
 	u8 *hash_output;
 	u32 hash_algorithm_id;
 	u32 image_size_to_hash;
@@ -617,6 +640,12 @@
 			sha256_finish(&hash256_text, hash_256_output);
 			hash_output = hash_256_output;
 			break;
+		case SHA512_SUM_LEN:
+			sha512_starts(&hash512_text);
+			sha512_update(&hash512_text, buff, image_size_to_hash);
+			sha512_finish(&hash512_text, hash_512_output);
+			hash_output = hash_512_output;
+			break;
 		default:
 			printf("Error: Unsupported hash_algorithm_id = %d\n",
 			       hash_algorithm_id);
@@ -635,7 +664,7 @@
 
 	return 0;
 }
-#elif defined(CONFIG_ARMADA_38X)
+#elif defined(CONFIG_ARMADA_32BIT)
 static size_t a38x_header_size(const struct a38x_main_hdr_v1 *h)
 {
 	if (h->version == 1)
@@ -691,34 +720,39 @@
 
 static int bubt_check_boot_mode(const struct bubt_dev *dst)
 {
-	if (IS_ENABLED(CONFIG_ARMADA_38X)) {
-		int mode;
-		const struct a38x_main_hdr_v1 *hdr =
-			(struct a38x_main_hdr_v1 *)get_load_addr();
+#if defined(CONFIG_ARMADA_3700) || defined(CONFIG_ARMADA_32BIT)
+	int mode;
+#if defined(CONFIG_ARMADA_3700)
+	const struct tim_boot_flash_sign *boot_modes = tim_boot_flash_signs;
+	const struct common_tim_data *hdr =
+		(struct common_tim_data *)get_load_addr();
+	u32 id = hdr->boot_flash_sign;
+#elif defined(CONFIG_ARMADA_32BIT)
+	const struct a38x_boot_mode *boot_modes = a38x_boot_modes;
+	const struct a38x_main_hdr_v1 *hdr =
+		(struct a38x_main_hdr_v1 *)get_load_addr();
+	u32 id = hdr->blockid;
+#endif
 
-		for (mode = 0; mode < ARRAY_SIZE(a38x_boot_modes); mode++) {
-			if (strcmp(a38x_boot_modes[mode].name, dst->name) == 0)
-				break;
-		}
-
-		if (a38x_boot_modes[mode].id == hdr->blockid)
-			return 0;
-
-		for (int i = 0; i < ARRAY_SIZE(a38x_boot_modes); i++) {
-			if (a38x_boot_modes[i].id == hdr->blockid) {
-				printf("Error: A38x image meant to be booted from "
-				       "\"%s\", not \"%s\"!\n",
-				       a38x_boot_modes[i].name, dst->name);
-				return -ENOEXEC;
-			}
-		}
-
-		printf("Error: unknown boot device in A38x image header: "
-		       "0x%x\n", hdr->blockid);
-		return -ENOEXEC;
-	} else {
-		return 0;
+	for (mode = 0; boot_modes[mode].name; mode++) {
+		if (boot_modes[mode].id == id)
+			break;
 	}
+
+	if (!boot_modes[mode].name) {
+		printf("Error: unknown boot device in image header: 0x%x\n", id);
+		return -ENOEXEC;
+	}
+
+	if (strcmp(boot_modes[mode].name, dst->name) == 0)
+		return 0;
+
+	printf("Error: image meant to be booted from \"%s\", not \"%s\"!\n",
+	       boot_modes[mode].name, dst->name);
+	return -ENOEXEC;
+#else
+	return 0;
+#endif
 }
 
 static int bubt_verify(const struct bubt_dev *dst)
@@ -836,11 +870,11 @@
 	dst = find_bubt_dev(dst_dev_name);
 	if (!dst) {
 		printf("Error: Unknown destination \"%s\"\n", dst_dev_name);
-		return -EINVAL;
+		return 1;
 	}
 
 	if (!bubt_is_dev_active(dst))
-		return -ENODEV;
+		return 1;
 
 	/* Figure out the source device */
 	src = find_bubt_dev(src_dev_name);
@@ -857,15 +891,15 @@
 
 	image_size = bubt_read_file(src);
 	if (!image_size)
-		return -EIO;
+		return 1;
 
 	err = bubt_verify(dst);
 	if (err)
-		return err;
+		return 1;
 
 	err = bubt_write_file(dst, image_size);
 	if (err)
-		return err;
+		return 1;
 
 	return 0;
 }
diff --git a/configs/turris_omnia_defconfig b/configs/turris_omnia_defconfig
index 66c4959..ff16825 100644
--- a/configs/turris_omnia_defconfig
+++ b/configs/turris_omnia_defconfig
@@ -80,7 +80,6 @@
 CONFIG_SPL_OF_TRANSLATE=y
 CONFIG_AHCI_PCI=y
 CONFIG_AHCI_MVEBU=y
-# CONFIG_MVEBU_GPIO is not set
 CONFIG_DM_PCA953X=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_MV=y
@@ -99,6 +98,8 @@
 CONFIG_NVME_PCI=y
 CONFIG_PCI=y
 CONFIG_PCI_MVEBU=y
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_ARMADA_38X=y
 CONFIG_DM_RTC=y
 CONFIG_RTC_ARMADA38X=y
 CONFIG_SCSI=y
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index aaa152f..82a8bca 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -598,4 +598,11 @@
 	   8-bit gpo expander, all gpo lines are controlled by writing
 	   value into data register.
 
+config TURRIS_OMNIA_MCU
+	bool "Turris Omnia MCU GPIO driver"
+	depends on DM_GPIO
+	default y if TARGET_TURRIS_OMNIA
+	help
+	   Support for GPIOs on MCU connected to Turris Omnia via i2c.
+
 endif
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index d755276..219f37e 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -75,3 +75,4 @@
 obj-$(CONFIG_SL28CPLD_GPIO)	+= sl28cpld-gpio.o
 obj-$(CONFIG_ZYNQMP_GPIO_MODEPIN)	+= zynqmp_gpio_modepin.o
 obj-$(CONFIG_SLG7XL45106_I2C_GPO)	+= gpio_slg7xl45106.o
+obj-$(CONFIG_$(SPL_TPL_)TURRIS_OMNIA_MCU)	+= turris_omnia_mcu.o
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index 76f4702..1388018 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -133,7 +133,7 @@
 static int rcar_gpio_request(struct udevice *dev, unsigned offset,
 			     const char *label)
 {
-	return pinctrl_gpio_request(dev, offset);
+	return pinctrl_gpio_request(dev, offset, label);
 }
 
 static int rcar_gpio_free(struct udevice *dev, unsigned offset)
diff --git a/drivers/gpio/mvebu_gpio.c b/drivers/gpio/mvebu_gpio.c
index 4c1c68e..f706a6d 100644
--- a/drivers/gpio/mvebu_gpio.c
+++ b/drivers/gpio/mvebu_gpio.c
@@ -5,6 +5,7 @@
 
 #include <common.h>
 #include <dm.h>
+#include <dm/pinctrl.h>
 #include <asm/gpio.h>
 #include <asm/io.h>
 #include <errno.h>
@@ -22,7 +23,7 @@
 
 struct mvebu_gpio_priv {
 	struct mvebu_gpio_regs *regs;
-	char name[2];
+	char name[sizeof("mvebuX_")];
 };
 
 static int mvebu_gpio_direction_input(struct udevice *dev, unsigned int gpio)
@@ -91,14 +92,18 @@
 	struct mvebu_gpio_priv *priv = dev_get_priv(dev);
 
 	priv->regs = dev_read_addr_ptr(dev);
-	uc_priv->gpio_count = MVEBU_GPIOS_PER_BANK;
-	priv->name[0] = 'A' + dev_seq(dev);
+	uc_priv->gpio_count = dev_read_u32_default(dev, "ngpios", MVEBU_GPIOS_PER_BANK);
+	sprintf(priv->name, "mvebu%d_", dev_seq(dev));
 	uc_priv->bank_name = priv->name;
 
 	return 0;
 }
 
 static const struct dm_gpio_ops mvebu_gpio_ops = {
+#if CONFIG_IS_ENABLED(PINCTRL_ARMADA_38X)
+	.request		= pinctrl_gpio_request,
+	.rfree			= pinctrl_gpio_free,
+#endif
 	.direction_input	= mvebu_gpio_direction_input,
 	.direction_output	= mvebu_gpio_direction_output,
 	.get_function		= mvebu_gpio_get_function,
diff --git a/drivers/gpio/turris_omnia_mcu.c b/drivers/gpio/turris_omnia_mcu.c
new file mode 100644
index 0000000..3e5d74e
--- /dev/null
+++ b/drivers/gpio/turris_omnia_mcu.c
@@ -0,0 +1,309 @@
+// SPDX-License-Identifier: GPL-2.0+
+// (C) 2022 Pali Rohár <pali@kernel.org>
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <asm/gpio.h>
+#include <linux/log2.h>
+
+enum commands_e {
+	CMD_GET_STATUS_WORD                 = 0x01,
+	CMD_GENERAL_CONTROL                 = 0x02,
+
+	/* available if STS_FEATURES_SUPPORTED bit set in status word */
+	CMD_GET_FEATURES                    = 0x10,
+
+	/* available if FEAT_EXT_CMDS bit is set in features */
+	CMD_GET_EXT_STATUS_DWORD            = 0x11,
+	CMD_EXT_CONTROL                     = 0x12,
+	CMD_GET_EXT_CONTROL_STATUS          = 0x13,
+};
+
+/* CMD_GET_STATUS_WORD */
+enum sts_word_e {
+	STS_MCU_TYPE_MASK                = GENMASK(1, 0),
+	STS_MCU_TYPE_STM32               = 0,
+	STS_MCU_TYPE_GD32                = 1,
+	STS_MCU_TYPE_MKL                 = 2,
+	STS_FEATURES_SUPPORTED           = BIT(2),
+	STS_USER_REGULATOR_NOT_SUPPORTED = BIT(3),
+	STS_CARD_DET                     = BIT(4),
+	STS_MSATA_IND                    = BIT(5),
+	STS_USB30_OVC                    = BIT(6),
+	STS_USB31_OVC                    = BIT(7),
+	STS_USB30_PWRON                  = BIT(8),
+	STS_USB31_PWRON                  = BIT(9),
+	STS_ENABLE_4V5                   = BIT(10),
+	STS_BUTTON_MODE                  = BIT(11),
+	STS_BUTTON_PRESSED               = BIT(12),
+	STS_BUTTON_COUNTER_MASK          = GENMASK(15, 13)
+};
+
+/* CMD_GENERAL_CONTROL */
+enum ctl_byte_e {
+	CTL_LIGHT_RST   = BIT(0),
+	CTL_HARD_RST    = BIT(1),
+	/*CTL_RESERVED    = BIT(2),*/
+	CTL_USB30_PWRON = BIT(3),
+	CTL_USB31_PWRON = BIT(4),
+	CTL_ENABLE_4V5  = BIT(5),
+	CTL_BUTTON_MODE = BIT(6),
+	CTL_BOOTLOADER  = BIT(7)
+};
+
+/* CMD_GET_FEATURES */
+enum features_e {
+	FEAT_EXT_CMDS           = BIT(1),
+};
+
+struct turris_omnia_mcu_info {
+	u16 features;
+};
+
+static int turris_omnia_mcu_get_function(struct udevice *dev, uint offset)
+{
+	struct turris_omnia_mcu_info *info = dev_get_plat(dev);
+
+	switch (offset) {
+	/* bank 0 */
+	case 0 ... 15:
+		switch (offset) {
+		case ilog2(STS_USB30_PWRON):
+		case ilog2(STS_USB31_PWRON):
+		case ilog2(STS_ENABLE_4V5):
+		case ilog2(STS_BUTTON_MODE):
+			return GPIOF_OUTPUT;
+		default:
+			return GPIOF_INPUT;
+		}
+
+	/* bank 1 - supported only when FEAT_EXT_CMDS is set */
+	case (16 + 0) ... (16 + 31):
+		if (!(info->features & FEAT_EXT_CMDS))
+			return -EINVAL;
+		return GPIOF_INPUT;
+
+	/* bank 2 - supported only when FEAT_EXT_CMDS is set */
+	case (16 + 32 + 0) ... (16 + 32 + 15):
+		if (!(info->features & FEAT_EXT_CMDS))
+			return -EINVAL;
+		return GPIOF_OUTPUT;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int turris_omnia_mcu_get_value(struct udevice *dev, uint offset)
+{
+	struct turris_omnia_mcu_info *info = dev_get_plat(dev);
+	u8 val16[2];
+	u8 val32[4];
+	int ret;
+
+	switch (offset) {
+	/* bank 0 */
+	case 0 ... 15:
+		ret = dm_i2c_read(dev, CMD_GET_STATUS_WORD, val16, 2);
+		if (ret)
+			return ret;
+		return ((((u16)val16[1] << 8) | val16[0]) >> offset) & 0x1;
+
+	/* bank 1 - supported only when FEAT_EXT_CMDS is set */
+	case (16 + 0) ... (16 + 31):
+		if (!(info->features & FEAT_EXT_CMDS))
+			return -EINVAL;
+		ret = dm_i2c_read(dev, CMD_GET_EXT_STATUS_DWORD, val32, 4);
+		if (ret)
+			return ret;
+		return ((((u32)val32[3] << 24) | ((u32)val32[2] << 16) |
+			 ((u32)val32[1] << 8) | val32[0]) >> (offset - 16)) & 0x1;
+
+	/* bank 2 - supported only when FEAT_EXT_CMDS is set */
+	case (16 + 32 + 0) ... (16 + 32 + 15):
+		if (!(info->features & FEAT_EXT_CMDS))
+			return -EINVAL;
+		ret = dm_i2c_read(dev, CMD_GET_EXT_CONTROL_STATUS, val16, 2);
+		if (ret)
+			return ret;
+		return ((((u16)val16[1] << 8) | val16[0]) >> (offset - 16 - 32)) & 0x1;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int turris_omnia_mcu_set_value(struct udevice *dev, uint offset, int value)
+{
+	struct turris_omnia_mcu_info *info = dev_get_plat(dev);
+	u8 val[2];
+	int ret;
+	u8 reg;
+
+	switch (offset) {
+	/* bank 0 */
+	case ilog2(STS_USB30_PWRON):
+		reg = CMD_GENERAL_CONTROL;
+		val[1] = CTL_USB30_PWRON;
+		break;
+	case ilog2(STS_USB31_PWRON):
+		reg = CMD_GENERAL_CONTROL;
+		val[1] = CTL_USB31_PWRON;
+		break;
+	case ilog2(STS_ENABLE_4V5):
+		reg = CMD_GENERAL_CONTROL;
+		val[1] = CTL_ENABLE_4V5;
+		break;
+	case ilog2(STS_BUTTON_MODE):
+		reg = CMD_GENERAL_CONTROL;
+		val[1] = CTL_BUTTON_MODE;
+		break;
+
+	/* bank 2 - supported only when FEAT_EXT_CMDS is set */
+	case (16 + 32 + 0) ... (16 + 32 + 15):
+		if (!(info->features & FEAT_EXT_CMDS))
+			return -EINVAL;
+		reg = CMD_EXT_CONTROL;
+		val[1] = BIT(offset - 16 - 32);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	val[0] = value ? val[1] : 0;
+
+	ret = dm_i2c_write(dev, reg, val, 2);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int turris_omnia_mcu_direction_input(struct udevice *dev, uint offset)
+{
+	int ret;
+
+	ret = turris_omnia_mcu_get_function(dev, offset);
+	if (ret < 0)
+		return ret;
+	else if (ret != GPIOF_INPUT)
+		return -EOPNOTSUPP;
+
+	return 0;
+}
+
+static int turris_omnia_mcu_direction_output(struct udevice *dev, uint offset, int value)
+{
+	int ret;
+
+	ret = turris_omnia_mcu_get_function(dev, offset);
+	if (ret < 0)
+		return ret;
+	else if (ret != GPIOF_OUTPUT)
+		return -EOPNOTSUPP;
+
+	return turris_omnia_mcu_set_value(dev, offset, value);
+}
+
+static int turris_omnia_mcu_xlate(struct udevice *dev, struct gpio_desc *desc,
+				  struct ofnode_phandle_args *args)
+{
+	uint bank, gpio, flags, offset;
+	int ret;
+
+	if (args->args_count != 3)
+		return -EINVAL;
+
+	bank = args->args[0];
+	gpio = args->args[1];
+	flags = args->args[2];
+
+	switch (bank) {
+	case 0:
+		if (gpio >= 16)
+			return -EINVAL;
+		offset = gpio;
+		break;
+	case 1:
+		if (gpio >= 32)
+			return -EINVAL;
+		offset = 16 + gpio;
+		break;
+	case 2:
+		if (gpio >= 16)
+			return -EINVAL;
+		offset = 16 + 32 + gpio;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = turris_omnia_mcu_get_function(dev, offset);
+	if (ret < 0)
+		return ret;
+
+	desc->offset = offset;
+	desc->flags = gpio_flags_xlate(flags);
+
+	return 0;
+}
+
+static const struct dm_gpio_ops turris_omnia_mcu_ops = {
+	.direction_input	= turris_omnia_mcu_direction_input,
+	.direction_output	= turris_omnia_mcu_direction_output,
+	.get_value		= turris_omnia_mcu_get_value,
+	.set_value		= turris_omnia_mcu_set_value,
+	.get_function		= turris_omnia_mcu_get_function,
+	.xlate			= turris_omnia_mcu_xlate,
+};
+
+static int turris_omnia_mcu_probe(struct udevice *dev)
+{
+	struct turris_omnia_mcu_info *info = dev_get_plat(dev);
+	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+	u16 status;
+	u8 val[2];
+	int ret;
+
+	ret = dm_i2c_read(dev, CMD_GET_STATUS_WORD, val, 2);
+	if (ret) {
+		printf("Error: turris_omnia_mcu CMD_GET_STATUS_WORD failed: %d\n", ret);
+		return ret;
+	}
+
+	status = ((u16)val[1] << 8) | val[0];
+
+	if (status & STS_FEATURES_SUPPORTED) {
+		ret = dm_i2c_read(dev, CMD_GET_FEATURES, val, 2);
+		if (ret) {
+			printf("Error: turris_omnia_mcu CMD_GET_FEATURES failed: %d\n", ret);
+			return ret;
+		}
+		info->features = ((u16)val[1] << 8) | val[0];
+	}
+
+	uc_priv->bank_name = "mcu_";
+
+	if (info->features & FEAT_EXT_CMDS)
+		uc_priv->gpio_count = 16 + 32 + 16;
+	else
+		uc_priv->gpio_count = 16;
+
+	return 0;
+}
+
+static const struct udevice_id turris_omnia_mcu_ids[] = {
+	{ .compatible = "cznic,turris-omnia-mcu" },
+	{ }
+};
+
+U_BOOT_DRIVER(turris_omnia_mcu) = {
+	.name		= "turris-omnia-mcu",
+	.id		= UCLASS_GPIO,
+	.ops		= &turris_omnia_mcu_ops,
+	.probe		= turris_omnia_mcu_probe,
+	.plat_auto	= sizeof(struct turris_omnia_mcu_info),
+	.of_match	= turris_omnia_mcu_ids,
+};
diff --git a/drivers/mtd/nand/raw/pxa3xx_nand.c b/drivers/mtd/nand/raw/pxa3xx_nand.c
index 20d1aee..9c29e8a 100644
--- a/drivers/mtd/nand/raw/pxa3xx_nand.c
+++ b/drivers/mtd/nand/raw/pxa3xx_nand.c
@@ -429,7 +429,7 @@
 
 static const struct udevice_id pxa3xx_nand_dt_ids[] = {
 	{
-		.compatible = "marvell,mvebu-pxa3xx-nand",
+		.compatible = "marvell,armada370-nand-controller",
 		.data = PXA3XX_NAND_VARIANT_ARMADA370,
 	},
 	{
diff --git a/drivers/pinctrl/mvebu/Kconfig b/drivers/pinctrl/mvebu/Kconfig
index 07d4f3e..574fb4d 100644
--- a/drivers/pinctrl/mvebu/Kconfig
+++ b/drivers/pinctrl/mvebu/Kconfig
@@ -1,5 +1,12 @@
 if ARCH_MVEBU
 
+config PINCTRL_ARMADA_38X
+	depends on ARMADA_38X && PINCTRL_FULL
+	bool "Armada 38x pin control driver"
+	help
+	   Support pin multiplexing and pin configuration control on
+	   Marvell's Armada-38x SoC.
+
 config PINCTRL_ARMADA_37XX
 	depends on ARMADA_3700 && PINCTRL_FULL
 	bool "Armada 37xx pin control driver"
diff --git a/drivers/pinctrl/mvebu/Makefile b/drivers/pinctrl/mvebu/Makefile
index c2df96b..15303d8 100644
--- a/drivers/pinctrl/mvebu/Makefile
+++ b/drivers/pinctrl/mvebu/Makefile
@@ -4,5 +4,6 @@
 #
 # https://spdx.org/licenses
 
+obj-$(CONFIG_PINCTRL_ARMADA_38X) += pinctrl-armada-38x.o
 obj-$(CONFIG_PINCTRL_ARMADA_37XX) += pinctrl-armada-37xx.o
 obj-$(CONFIG_PINCTRL_ARMADA_8K)	+= pinctrl-mvebu.o
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
index e76ef15..bb7a76b 100644
--- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
@@ -65,7 +65,6 @@
  *		belonging to the group
  * @npins:	Number of pins included in the second optional range
  * @funcs:	A list of pinmux functions that can be selected for this group.
- * @pins:	List of the pins included in the group
  */
 struct armada_37xx_pin_group {
 	const char	*name;
@@ -76,7 +75,6 @@
 	unsigned int	extra_pin;
 	unsigned int	extra_npins;
 	const char	*funcs[NB_FUNCS];
-	unsigned int	*pins;
 };
 
 struct armada_37xx_pin_data {
@@ -97,8 +95,6 @@
 	const struct armada_37xx_pin_data	*data;
 	struct udevice			*dev;
 	struct pinctrl_dev		*pctl_dev;
-	struct armada_37xx_pin_group	*groups;
-	unsigned int			ngroups;
 	struct armada_37xx_pmx_func	*funcs;
 	unsigned int			nfuncs;
 };
@@ -113,6 +109,16 @@
 		.funcs = {_func1, _func2}	\
 	}
 
+#define PIN_GRP_GPIO_0(_name, _start, _nr)	\
+	{					\
+		.name = _name,			\
+		.start_pin = _start,		\
+		.npins = _nr,			\
+		.reg_mask = 0,			\
+		.val = {0},			\
+		.funcs = {"gpio"}		\
+	}
+
 #define PIN_GRP_GPIO(_name, _start, _nr, _mask, _func1)	\
 	{					\
 		.name = _name,			\
@@ -170,6 +176,7 @@
 		       "pwm", "led"),
 	PIN_GRP_GPIO("pmic1", 7, 1, BIT(7), "pmic"),
 	PIN_GRP_GPIO("pmic0", 6, 1, BIT(8), "pmic"),
+	PIN_GRP_GPIO_0("gpio1_5", 5, 1),
 	PIN_GRP_GPIO("i2c2", 2, 2, BIT(9), "i2c"),
 	PIN_GRP_GPIO("i2c1", 0, 2, BIT(10), "i2c"),
 	PIN_GRP_GPIO("spi_cs1", 17, 1, BIT(12), "spi"),
@@ -186,10 +193,13 @@
 static struct armada_37xx_pin_group armada_37xx_sb_groups[] = {
 	PIN_GRP_GPIO("usb32_drvvbus0", 0, 1, BIT(0), "drvbus"),
 	PIN_GRP_GPIO("usb2_drvvbus1", 1, 1, BIT(1), "drvbus"),
+	PIN_GRP_GPIO_0("gpio2_2", 2, 1),
 	PIN_GRP_GPIO("sdio_sb", 24, 6, BIT(2), "sdio"),
 	PIN_GRP_GPIO("rgmii", 6, 12, BIT(3), "mii"),
 	PIN_GRP_GPIO("smi", 18, 2, BIT(4), "smi"),
-	PIN_GRP_GPIO("pcie1", 3, 3, BIT(5) | BIT(9) | BIT(10), "pcie"),
+	PIN_GRP_GPIO("pcie1", 3, 1, BIT(5), "pcie"), /* this actually controls "pcie1_reset" */
+	PIN_GRP_GPIO("pcie1_clkreq", 4, 1, BIT(9), "pcie"),
+	PIN_GRP_GPIO("pcie1_wakeup", 5, 1, BIT(10), "pcie"),
 	PIN_GRP_GPIO("ptp", 20, 3, BIT(11) | BIT(12) | BIT(13), "ptp"),
 	PIN_GRP("ptp_clk", 21, 1, BIT(6), "ptp", "mii"),
 	PIN_GRP("ptp_trig", 22, 1, BIT(7), "ptp", "mii"),
@@ -197,14 +207,14 @@
 		       "mii", "mii_err"),
 };
 
-const struct armada_37xx_pin_data armada_37xx_pin_nb = {
+static const struct armada_37xx_pin_data armada_37xx_pin_nb = {
 	.nr_pins = 36,
 	.name = "GPIO1",
 	.groups = armada_37xx_nb_groups,
 	.ngroups = ARRAY_SIZE(armada_37xx_nb_groups),
 };
 
-const struct armada_37xx_pin_data armada_37xx_pin_sb = {
+static const struct armada_37xx_pin_data armada_37xx_pin_sb = {
 	.nr_pins = 30,
 	.name = "GPIO2",
 	.groups = armada_37xx_sb_groups,
@@ -237,7 +247,7 @@
 {
 	struct armada_37xx_pinctrl *info = dev_get_priv(dev);
 
-	return info->ngroups;
+	return info->data->ngroups;
 }
 
 static const char *armada_37xx_pmx_dummy_name = "_dummy";
@@ -247,10 +257,10 @@
 {
 	struct armada_37xx_pinctrl *info = dev_get_priv(dev);
 
-	if (!info->groups[selector].name)
+	if (!info->data->groups[selector].name)
 		return armada_37xx_pmx_dummy_name;
 
-	return info->groups[selector].name;
+	return info->data->groups[selector].name;
 }
 
 static int armada_37xx_pmx_get_funcs_count(struct udevice *dev)
@@ -270,12 +280,13 @@
 
 static int armada_37xx_pmx_set_by_name(struct udevice *dev,
 				       const char *name,
-				       struct armada_37xx_pin_group *grp)
+				       struct armada_37xx_pin_group *grp,
+				       bool warn_on_change)
 {
 	struct armada_37xx_pinctrl *info = dev_get_priv(dev);
 	unsigned int reg = SELECTION;
 	unsigned int mask = grp->reg_mask;
-	int func, val;
+	int func, val, old_func;
 
 	dev_dbg(info->dev, "enable function %s group %s\n",
 		name, grp->name);
@@ -287,6 +298,18 @@
 
 	val = grp->val[func];
 
+	if (warn_on_change && val != (readl(info->base + reg) & mask)) {
+		for (old_func = 0; (old_func < NB_FUNCS) && grp->funcs[old_func]; old_func++) {
+			if (grp->val[old_func] == val)
+				break;
+		}
+		dev_warn(info->dev, "Warning: Changing MPPs %u-%u function from %s to %s...\n",
+			 grp->start_pin, grp->start_pin + grp->npins - 1,
+			 ((old_func < NB_FUNCS && grp->funcs[old_func]) ?
+			  grp->funcs[old_func] : "unknown"),
+			 name);
+	}
+
 	clrsetbits_le32(info->base + reg, mask, val);
 
 	return 0;
@@ -297,10 +320,112 @@
 				     unsigned func_selector)
 {
 	struct armada_37xx_pinctrl *info = dev_get_priv(dev);
-	struct armada_37xx_pin_group *grp = &info->groups[group_selector];
+	struct armada_37xx_pin_group *grp = &info->data->groups[group_selector];
 	const char *name = info->funcs[func_selector].name;
 
-	return armada_37xx_pmx_set_by_name(dev, name, grp);
+	return armada_37xx_pmx_set_by_name(dev, name, grp, false);
+}
+
+static int armada_37xx_pmx_gpio_request_enable(struct udevice *dev, unsigned int selector)
+{
+	struct armada_37xx_pinctrl *info = dev_get_priv(dev);
+	int ret = -ENOTSUPP;
+	int n;
+
+	/* Find all groups where is requested selector pin and set each group to gpio function */
+	for (n = 0; n < info->data->ngroups; n++) {
+		struct armada_37xx_pin_group *grp = &info->data->groups[n];
+
+		if ((selector >= grp->start_pin && selector < grp->start_pin + grp->npins) ||
+		    (selector >= grp->extra_pin && selector < grp->extra_pin + grp->extra_npins)) {
+			ret = armada_37xx_pmx_set_by_name(dev, "gpio", grp, true);
+			if (ret)
+				return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int armada_37xx_pmx_gpio_disable_free(struct udevice *dev, unsigned int selector)
+{
+	/* nothing to do */
+	return 0;
+}
+
+static int armada_37xx_pmx_get_pins_count(struct udevice *dev)
+{
+	struct armada_37xx_pinctrl *info = dev_get_priv(dev);
+
+	return info->data->nr_pins;
+}
+
+static const char *armada_37xx_pmx_get_pin_name(struct udevice *dev, unsigned int selector)
+{
+	struct armada_37xx_pinctrl *info = dev_get_priv(dev);
+	static char buf[sizeof("MPPx_XX")];
+
+	sprintf(buf, "MPP%c_%u", info->data->name[4], selector);
+	return buf;
+}
+
+static int armada_37xx_pmx_get_pin_muxing(struct udevice *dev, unsigned int selector,
+					  char *buf, int size)
+{
+	struct armada_37xx_pinctrl *info = dev_get_priv(dev);
+	int n;
+
+	/*
+	 * First check if selected pin is in some extra pin group.
+	 * Function in extra pin group is active only when it is not gpio.
+	 */
+	for (n = 0; n < info->data->ngroups; n++) {
+		struct armada_37xx_pin_group *grp = &info->data->groups[n];
+
+		if (selector >= grp->extra_pin && selector < grp->extra_pin + grp->extra_npins) {
+			unsigned int reg = SELECTION;
+			unsigned int mask = grp->reg_mask;
+			int f, val;
+
+			val = (readl(info->base + reg) & mask);
+
+			for (f = 0; f < NB_FUNCS && grp->funcs[f]; f++) {
+				if (grp->val[f] == val) {
+					if (strcmp(grp->funcs[f], "gpio") != 0) {
+						strlcpy(buf, grp->funcs[f], size);
+						return 0;
+					}
+					break;
+				}
+			}
+		}
+	}
+
+	/* If pin is not active in some extra pin group then check regular groups. */
+	for (n = 0; n < info->data->ngroups; n++) {
+		struct armada_37xx_pin_group *grp = &info->data->groups[n];
+
+		if (selector >= grp->start_pin && selector < grp->start_pin + grp->npins) {
+			unsigned int reg = SELECTION;
+			unsigned int mask = grp->reg_mask;
+			int f, val;
+
+			val = (readl(info->base + reg) & mask);
+
+			for (f = 0; f < NB_FUNCS && grp->funcs[f]; f++) {
+				if (grp->val[f] == val) {
+					strlcpy(buf, grp->funcs[f], size);
+					return 0;
+				}
+			}
+
+			strlcpy(buf, "unknown", size);
+			return 0;
+		}
+	}
+
+	strlcpy(buf, "unknown", size);
+	return 0;
 }
 
 /**
@@ -352,21 +477,9 @@
 {
 	int n, num = 0, funcsize = info->data->nr_pins;
 
-	for (n = 0; n < info->ngroups; n++) {
-		struct armada_37xx_pin_group *grp = &info->groups[n];
-		int i, j, f;
-
-		grp->pins = devm_kzalloc(info->dev,
-					 (grp->npins + grp->extra_npins) *
-					 sizeof(*grp->pins), GFP_KERNEL);
-		if (!grp->pins)
-			return -ENOMEM;
-
-		for (i = 0; i < grp->npins; i++)
-			grp->pins[i] = grp->start_pin + i;
-
-		for (j = 0; j < grp->extra_npins; j++)
-			grp->pins[i+j] = grp->extra_pin + j;
+	for (n = 0; n < info->data->ngroups; n++) {
+		struct armada_37xx_pin_group *grp = &info->data->groups[n];
+		int f;
 
 		for (f = 0; (f < NB_FUNCS) && grp->funcs[f]; f++) {
 			int ret;
@@ -416,8 +529,8 @@
 
 		groups = funcs[n].groups;
 
-		for (g = 0; g < info->ngroups; g++) {
-			struct armada_37xx_pin_group *gp = &info->groups[g];
+		for (g = 0; g < info->data->ngroups; g++) {
+			struct armada_37xx_pin_group *gp = &info->data->groups[g];
 			int f;
 
 			for (f = 0; (f < NB_FUNCS) && gp->funcs[f]; f++) {
@@ -522,6 +635,8 @@
 }
 
 static const struct dm_gpio_ops armada_37xx_gpio_ops = {
+	.request = pinctrl_gpio_request,
+	.rfree = pinctrl_gpio_free,
 	.set_value = armada_37xx_gpio_set,
 	.get_value = armada_37xx_gpio_get,
 	.get_function = armada_37xx_gpio_get_direction,
@@ -574,16 +689,21 @@
 	return 0;
 }
 
-const struct pinctrl_ops armada_37xx_pinctrl_ops  = {
+static const struct pinctrl_ops armada_37xx_pinctrl_ops  = {
+	.get_pins_count = armada_37xx_pmx_get_pins_count,
+	.get_pin_name = armada_37xx_pmx_get_pin_name,
+	.get_pin_muxing = armada_37xx_pmx_get_pin_muxing,
 	.get_groups_count = armada_37xx_pmx_get_groups_count,
 	.get_group_name = armada_37xx_pmx_get_group_name,
 	.get_functions_count = armada_37xx_pmx_get_funcs_count,
 	.get_function_name = armada_37xx_pmx_get_func_name,
 	.pinmux_group_set = armada_37xx_pmx_group_set,
+	.gpio_request_enable = armada_37xx_pmx_gpio_request_enable,
+	.gpio_disable_free = armada_37xx_pmx_gpio_disable_free,
 	.set_state = pinctrl_generic_set_state,
 };
 
-int armada_37xx_pinctrl_probe(struct udevice *dev)
+static int armada_37xx_pinctrl_probe(struct udevice *dev)
 {
 	struct armada_37xx_pinctrl *info = dev_get_priv(dev);
 	const struct armada_37xx_pin_data *pin_data;
@@ -598,9 +718,6 @@
 		return -ENODEV;
 	}
 
-	info->groups = pin_data->groups;
-	info->ngroups = pin_data->ngroups;
-
 	/*
 	 * we allocate functions for number of pins and hope there are
 	 * fewer unique functions than pins available
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-38x.c b/drivers/pinctrl/mvebu/pinctrl-armada-38x.c
new file mode 100644
index 0000000..252151f
--- /dev/null
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-38x.c
@@ -0,0 +1,589 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// (C) 2022 Pali Rohár <pali@kernel.org>
+
+#include <common.h>
+#include <config.h>
+#include <dm.h>
+#include <dm/devres.h>
+#include <dm/lists.h>
+#include <dm/pinctrl.h>
+#include <dm/root.h>
+#include <errno.h>
+#include <asm/io.h>
+
+struct mvebu_mpp_ctrl_setting {
+	const char *name;
+	const char *subname;
+	u8 val;
+	u8 variant;
+};
+
+struct mvebu_mpp_mode {
+	const char *name;
+	size_t nsettings;
+	struct mvebu_mpp_ctrl_setting *settings;
+};
+
+#define MPP_MODE(_name, ...)					\
+	{							\
+		.name = _name,					\
+		.nsettings = ARRAY_SIZE((			\
+			(struct mvebu_mpp_ctrl_setting[])	\
+			 { __VA_ARGS__ })),			\
+		.settings = (struct mvebu_mpp_ctrl_setting[]){	\
+			__VA_ARGS__ },				\
+	}
+
+#define MPP_VAR_FUNCTION(_val, _name, _subname, _mask)		\
+	{							\
+		.val = _val,					\
+		.name = _name,					\
+		.subname = _subname,				\
+		.variant = _mask,				\
+	}
+
+#define MVEBU_MPPS_PER_REG	8
+#define MVEBU_MPP_BITS		4
+#define MVEBU_MPP_MASK		0xf
+
+enum {
+	V_88F6810 = BIT(0),
+	V_88F6820 = BIT(1),
+	V_88F6828 = BIT(2),
+	V_88F6810_PLUS = (V_88F6810 | V_88F6820 | V_88F6828),
+	V_88F6820_PLUS = (V_88F6820 | V_88F6828),
+};
+
+static struct mvebu_mpp_mode armada_38x_mpp_modes[] = {
+	MPP_MODE("mpp0",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ua0",   "rxd",        V_88F6810_PLUS)),
+	MPP_MODE("mpp1",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ua0",   "txd",        V_88F6810_PLUS)),
+	MPP_MODE("mpp2",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "i2c0",  "sck",        V_88F6810_PLUS)),
+	MPP_MODE("mpp3",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "i2c0",  "sda",        V_88F6810_PLUS)),
+	MPP_MODE("mpp4",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ge",    "mdc",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "ua1",   "txd",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "ua0",   "rts",        V_88F6810_PLUS)),
+	MPP_MODE("mpp5",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ge",    "mdio",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "ua1",   "rxd",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "ua0",   "cts",        V_88F6810_PLUS)),
+	MPP_MODE("mpp6",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ge0",   "txclkout",   V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "ge0",   "crs",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "cs3",        V_88F6810_PLUS)),
+	MPP_MODE("mpp7",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ge0",   "txd0",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "ad9",        V_88F6810_PLUS)),
+	MPP_MODE("mpp8",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ge0",   "txd1",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "ad10",       V_88F6810_PLUS)),
+	MPP_MODE("mpp9",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ge0",   "txd2",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "ad11",       V_88F6810_PLUS)),
+	MPP_MODE("mpp10",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ge0",   "txd3",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "ad12",       V_88F6810_PLUS)),
+	MPP_MODE("mpp11",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ge0",   "txctl",      V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "ad13",       V_88F6810_PLUS)),
+	MPP_MODE("mpp12",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ge0",   "rxd0",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "pcie0", "rstout",     V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "spi0",  "cs1",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "ad14",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(6, "pcie3", "clkreq",     V_88F6810_PLUS)),
+	MPP_MODE("mpp13",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ge0",   "rxd1",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "pcie0", "clkreq",     V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "pcie1", "clkreq",     V_88F6820_PLUS),
+		 MPP_VAR_FUNCTION(4, "spi0",  "cs2",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "ad15",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(6, "pcie2", "clkreq",     V_88F6810_PLUS)),
+	MPP_MODE("mpp14",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ge0",   "rxd2",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "ptp",   "clk",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "dram",  "vttctrl",    V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "spi0",  "cs3",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "we1",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(6, "pcie3", "clkreq",     V_88F6810_PLUS)),
+	MPP_MODE("mpp15",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ge0",   "rxd3",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "ge",    "mdc slave",  V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "pcie0", "rstout",     V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "spi0",  "mosi",       V_88F6810_PLUS)),
+	MPP_MODE("mpp16",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ge0",   "rxctl",      V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "ge",    "mdio slave", V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "dram",  "deccerr",    V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "spi0",  "miso",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "pcie0", "clkreq",     V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(6, "pcie1", "clkreq",     V_88F6820_PLUS)),
+	MPP_MODE("mpp17",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ge0",   "rxclk",      V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "ptp",   "clk",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "ua1",   "rxd",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "spi0",  "sck",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "sata1", "prsnt",      V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(6, "sata0", "prsnt",      V_88F6810_PLUS)),
+	MPP_MODE("mpp18",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ge0",   "rxerr",      V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "ptp",   "trig",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "ua1",   "txd",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "spi0",  "cs0",        V_88F6810_PLUS)),
+	MPP_MODE("mpp19",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ge0",   "col",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "ptp",   "evreq",      V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "ge0",   "txerr",      V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "sata1", "prsnt",      V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "ua0",   "cts",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(6, "ua1",   "rxd",        V_88F6810_PLUS)),
+	MPP_MODE("mpp20",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ge0",   "txclk",      V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "ptp",   "clk",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "sata0", "prsnt",      V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "ua0",   "rts",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(6, "ua1",   "txd",        V_88F6810_PLUS)),
+	MPP_MODE("mpp21",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "spi0",  "cs1",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "ge1",   "rxd0",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "sata0", "prsnt",      V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "sd0",   "cmd",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "bootcs",     V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(6, "sata1", "prsnt",      V_88F6810_PLUS)),
+	MPP_MODE("mpp22",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "spi0",  "mosi",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "ad0",        V_88F6810_PLUS)),
+	MPP_MODE("mpp23",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "spi0",  "sck",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "ad2",        V_88F6810_PLUS)),
+	MPP_MODE("mpp24",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "spi0",  "miso",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "ua0",   "cts",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "ua1",   "rxd",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "sd0",   "d4",         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "ready",      V_88F6810_PLUS)),
+	MPP_MODE("mpp25",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "spi0",  "cs0",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "ua0",   "rts",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "ua1",   "txd",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "sd0",   "d5",         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "cs0",        V_88F6810_PLUS)),
+	MPP_MODE("mpp26",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "spi0",  "cs2",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "i2c1",  "sck",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "sd0",   "d6",         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "cs1",        V_88F6810_PLUS)),
+	MPP_MODE("mpp27",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "spi0",  "cs3",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "ge1",   "txclkout",   V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "i2c1",  "sda",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "sd0",   "d7",         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "cs2",        V_88F6810_PLUS)),
+	MPP_MODE("mpp28",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "ge1",   "txd0",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "sd0",   "clk",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "ad5",        V_88F6810_PLUS)),
+	MPP_MODE("mpp29",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "ge1",   "txd1",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "ale0",       V_88F6810_PLUS)),
+	MPP_MODE("mpp30",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "ge1",   "txd2",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "oe",         V_88F6810_PLUS)),
+	MPP_MODE("mpp31",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "ge1",   "txd3",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "ale1",       V_88F6810_PLUS)),
+	MPP_MODE("mpp32",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "ge1",   "txctl",      V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "we0",        V_88F6810_PLUS)),
+	MPP_MODE("mpp33",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "dram",  "deccerr",    V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "ad3",        V_88F6810_PLUS)),
+	MPP_MODE("mpp34",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "ad1",        V_88F6810_PLUS)),
+	MPP_MODE("mpp35",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ref",   "clk_out1",   V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "a1",         V_88F6810_PLUS)),
+	MPP_MODE("mpp36",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ptp",   "trig",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "a0",         V_88F6810_PLUS)),
+	MPP_MODE("mpp37",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ptp",   "clk",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "ge1",   "rxclk",      V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "sd0",   "d3",         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "ad8",        V_88F6810_PLUS)),
+	MPP_MODE("mpp38",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ptp",   "evreq",      V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "ge1",   "rxd1",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "ref",   "clk_out0",   V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "sd0",   "d0",         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "ad4",        V_88F6810_PLUS)),
+	MPP_MODE("mpp39",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "i2c1",  "sck",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "ge1",   "rxd2",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "ua0",   "cts",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "sd0",   "d1",         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "a2",         V_88F6810_PLUS)),
+	MPP_MODE("mpp40",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "i2c1",  "sda",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "ge1",   "rxd3",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "ua0",   "rts",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "sd0",   "d2",         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "ad6",        V_88F6810_PLUS)),
+	MPP_MODE("mpp41",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ua1",   "rxd",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "ge1",   "rxctl",      V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "ua0",   "cts",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "spi1",  "cs3",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "burst/last", V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(6, "nand",  "rb0",        V_88F6810_PLUS)),
+	MPP_MODE("mpp42",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ua1",   "txd",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "ua0",   "rts",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "ad7",        V_88F6810_PLUS)),
+	MPP_MODE("mpp43",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "pcie0", "clkreq",     V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "dram",  "vttctrl",    V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "dram",  "deccerr",    V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "spi1",  "cs2",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dev",   "clkout",     V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(6, "nand",  "rb1",        V_88F6810_PLUS)),
+	MPP_MODE("mpp44",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "sata0", "prsnt",      V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "sata1", "prsnt",      V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "sata2", "prsnt",      V_88F6828),
+		 MPP_VAR_FUNCTION(4, "sata3", "prsnt",      V_88F6828)),
+	MPP_MODE("mpp45",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ref",   "clk_out0",   V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "pcie0", "rstout",     V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(6, "ua1",   "rxd",        V_88F6810_PLUS)),
+	MPP_MODE("mpp46",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ref",   "clk_out1",   V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "pcie0", "rstout",     V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(6, "ua1",   "txd",        V_88F6810_PLUS)),
+	MPP_MODE("mpp47",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "sata0", "prsnt",      V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "sata1", "prsnt",      V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "sata2", "prsnt",      V_88F6828),
+		 MPP_VAR_FUNCTION(5, "sata3", "prsnt",      V_88F6828)),
+	MPP_MODE("mpp48",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "sata0", "prsnt",      V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "dram",  "vttctrl",    V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "tdm",   "pclk",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "audio", "mclk",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "sd0",   "d4",         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(6, "pcie0", "clkreq",     V_88F6810_PLUS)),
+	MPP_MODE("mpp49",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "sata2", "prsnt",      V_88F6828),
+		 MPP_VAR_FUNCTION(2, "sata3", "prsnt",      V_88F6828),
+		 MPP_VAR_FUNCTION(3, "tdm",   "fsync",      V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "audio", "lrclk",      V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "sd0",   "d5",         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(6, "pcie1", "clkreq",     V_88F6820_PLUS)),
+	MPP_MODE("mpp50",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "pcie0", "rstout",     V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "tdm",   "drx",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "audio", "extclk",     V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "sd0",   "cmd",        V_88F6810_PLUS)),
+	MPP_MODE("mpp51",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "tdm",   "dtx",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "audio", "sdo",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "dram",  "deccerr",    V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(6, "ptp",   "trig",       V_88F6810_PLUS)),
+	MPP_MODE("mpp52",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "pcie0", "rstout",     V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "tdm",   "int",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "audio", "sdi",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "sd0",   "d6",         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(6, "ptp",   "clk",        V_88F6810_PLUS)),
+	MPP_MODE("mpp53",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "sata1", "prsnt",      V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "sata0", "prsnt",      V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "tdm",   "rst",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "audio", "bclk",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "sd0",   "d7",         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(6, "ptp",   "evreq",      V_88F6810_PLUS)),
+	MPP_MODE("mpp54",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "sata0", "prsnt",      V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "sata1", "prsnt",      V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "pcie0", "rstout",     V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "ge0",   "txerr",      V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "sd0",   "d3",         V_88F6810_PLUS)),
+	MPP_MODE("mpp55",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ua1",   "cts",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "ge",    "mdio",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "pcie1", "clkreq",     V_88F6820_PLUS),
+		 MPP_VAR_FUNCTION(4, "spi1",  "cs1",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "sd0",   "d0",         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(6, "ua1",   "rxd",        V_88F6810_PLUS)),
+	MPP_MODE("mpp56",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "ua1",   "rts",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "ge",    "mdc",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "dram",  "deccerr",    V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "spi1",  "mosi",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(6, "ua1",   "txd",        V_88F6810_PLUS)),
+	MPP_MODE("mpp57",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "spi1",  "sck",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "sd0",   "clk",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(6, "ua1",   "txd",        V_88F6810_PLUS)),
+	MPP_MODE("mpp58",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "pcie1", "clkreq",     V_88F6820_PLUS),
+		 MPP_VAR_FUNCTION(2, "i2c1",  "sck",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(3, "pcie2", "clkreq",     V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "spi1",  "miso",       V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "sd0",   "d1",         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(6, "ua1",   "rxd",        V_88F6810_PLUS)),
+	MPP_MODE("mpp59",
+		 MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(1, "pcie0", "rstout",     V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(2, "i2c1",  "sda",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(4, "spi1",  "cs0",        V_88F6810_PLUS),
+		 MPP_VAR_FUNCTION(5, "sd0",   "d2",         V_88F6810_PLUS)),
+};
+
+static const char * const armada_38x_mpp_function_names[] = {
+	"gpio", /* make gpio always as function 0 */
+
+	"audio",
+	"dev",
+	"dram",
+	"ge",
+	"ge0",
+	"ge1",
+	"i2c0",
+	"i2c1",
+	"nand",
+	"pcie0",
+	"pcie1",
+	"pcie2",
+	"pcie3",
+	"ptp",
+	"ref",
+	"sata0",
+	"sata1",
+	"sata2",
+	"sata3",
+	"sd0",
+	"spi0",
+	"spi1",
+	"tdm",
+	"ua0",
+	"ua1",
+};
+
+struct armada_38x_pinctrl {
+	void __iomem *base;
+	u8 variant;
+};
+
+static int armada_38x_pinctrl_get_pins_count(struct udevice *dev)
+{
+	return ARRAY_SIZE(armada_38x_mpp_modes);
+}
+
+static const char *armada_38x_pinctrl_get_pin_name(struct udevice *dev, unsigned int selector)
+{
+	return armada_38x_mpp_modes[selector].name;
+}
+
+static int armada_38x_pinctrl_get_functions_count(struct udevice *dev)
+{
+	return ARRAY_SIZE(armada_38x_mpp_function_names);
+}
+
+static const char *armada_38x_pinctrl_get_function_name(struct udevice *dev, unsigned int selector)
+{
+	return armada_38x_mpp_function_names[selector];
+}
+
+static int armada_38x_pinctrl_get_pin_muxing(struct udevice *dev, unsigned int selector,
+					     char *buf, int size)
+{
+	struct armada_38x_pinctrl *info = dev_get_priv(dev);
+	unsigned int off = (selector / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+	unsigned int shift = (selector % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+	const char *func_name = NULL;
+	const char *sub_name = NULL;
+	unsigned long config;
+	int i;
+
+	config = (readl(info->base + off) >> shift) & MVEBU_MPP_MASK;
+
+	for (i = 0; i < armada_38x_mpp_modes[selector].nsettings; i++) {
+		if (armada_38x_mpp_modes[selector].settings[i].val == config)
+			break;
+	}
+
+	if (i < armada_38x_mpp_modes[selector].nsettings) {
+		func_name = armada_38x_mpp_modes[selector].settings[i].name;
+		sub_name = armada_38x_mpp_modes[selector].settings[i].subname;
+	}
+
+	snprintf(buf, size, "%s%s%s",
+		 func_name ? func_name : "unknown",
+		 sub_name ? "_" : "",
+		 sub_name ? sub_name : "");
+	return 0;
+}
+
+static int armada_38x_pinctrl_pinmux_set(struct udevice *dev, unsigned int pin_selector,
+					 unsigned int func_selector)
+{
+	struct armada_38x_pinctrl *info = dev_get_priv(dev);
+	unsigned int off = (pin_selector / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+	unsigned int shift = (pin_selector % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+	const char *func_name = armada_38x_mpp_function_names[func_selector];
+	unsigned long config, reg;
+	int i;
+
+	for (i = 0; i < armada_38x_mpp_modes[pin_selector].nsettings; i++) {
+		if (strcmp(armada_38x_mpp_modes[pin_selector].settings[i].name, func_name) == 0)
+			break;
+	}
+
+	if (i >= armada_38x_mpp_modes[pin_selector].nsettings)
+		return -EINVAL;
+
+	if (!(info->variant & armada_38x_mpp_modes[pin_selector].settings[i].variant))
+		return -EINVAL;
+
+	reg = readl(info->base + off) & ~(MVEBU_MPP_MASK << shift);
+	config = armada_38x_mpp_modes[pin_selector].settings[i].val;
+	writel(reg | (config << shift), info->base + off);
+
+	return 0;
+}
+
+static int armada_38x_pinctrl_gpio_request_enable(struct udevice *dev, unsigned int selector)
+{
+	char buf[20];
+
+	armada_38x_pinctrl_get_pin_muxing(dev, selector, buf, sizeof(buf));
+	if (strcmp(buf, "gpio") != 0)
+		printf("Warning: Changing mpp%u function from %s to gpio...\n", selector, buf);
+
+	return armada_38x_pinctrl_pinmux_set(dev, selector, 0); /* gpio is always function 0 */
+}
+
+static int armada_38x_pinctrl_gpio_disable_free(struct udevice *dev, unsigned int selector)
+{
+	/* nothing to do */
+	return 0;
+}
+
+static int armada_38x_pinctrl_set_state(struct udevice *dev, struct udevice *config)
+{
+	return pinctrl_generic_set_state_prefix(dev, config, "marvell,");
+}
+
+static int armada_38x_pinctrl_probe(struct udevice *dev)
+{
+	struct armada_38x_pinctrl *info = dev_get_priv(dev);
+
+	info->variant = (u8)dev_get_driver_data(dev);
+	info->base = dev_read_addr_ptr(dev);
+
+	if (!info->base)
+		return -EINVAL;
+
+	return 0;
+}
+
+struct pinctrl_ops armada_37xx_pinctrl_ops = {
+	.get_pins_count = armada_38x_pinctrl_get_pins_count,
+	.get_pin_name = armada_38x_pinctrl_get_pin_name,
+	.get_functions_count = armada_38x_pinctrl_get_functions_count,
+	.get_function_name = armada_38x_pinctrl_get_function_name,
+	.get_pin_muxing = armada_38x_pinctrl_get_pin_muxing,
+	.pinmux_set = armada_38x_pinctrl_pinmux_set,
+	.gpio_request_enable = armada_38x_pinctrl_gpio_request_enable,
+	.gpio_disable_free = armada_38x_pinctrl_gpio_disable_free,
+	.set_state = armada_38x_pinctrl_set_state,
+};
+
+static const struct udevice_id armada_38x_pinctrl_of_match[] = {
+	{
+		.compatible = "marvell,mv88f6810-pinctrl",
+		.data       = V_88F6810,
+	},
+	{
+		.compatible = "marvell,mv88f6820-pinctrl",
+		.data       = V_88F6820,
+	},
+	{
+		.compatible = "marvell,mv88f6828-pinctrl",
+		.data       = V_88F6828,
+	},
+	{ },
+};
+
+U_BOOT_DRIVER(armada_38x_pinctrl) = {
+	.name = "armada-38x-pinctrl",
+	.id = UCLASS_PINCTRL,
+	.of_match = of_match_ptr(armada_38x_pinctrl_of_match),
+	.probe = armada_38x_pinctrl_probe,
+	.priv_auto = sizeof(struct armada_38x_pinctrl),
+	.ops = &armada_37xx_pinctrl_ops,
+};
diff --git a/drivers/pinctrl/mvebu/pinctrl-mvebu.c b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
index 536c6af..fd49a97 100644
--- a/drivers/pinctrl/mvebu/pinctrl-mvebu.c
+++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
@@ -52,7 +52,9 @@
 				     EMMC_PHY_CTRL_SDPHY_EN);
 		}
 	} else if (!fdt_node_check_compatible(blob, node,
-					"marvell,armada-8k-cpm-pinctrl")) {
+					"marvell,armada-8k-cpm-pinctrl") ||
+		   !fdt_node_check_compatible(blob, node,
+					"marvell,armada-7k-pinctrl")) {
 		if ((pin == CP110_EMMC_CLK_PIN_ID) &&
 		    (func == CP110_EMMC_CLK_FUNC)) {
 			clrbits_le32(priv->base_reg + CP_EMMC_PHY_CTRL_REG,
diff --git a/drivers/pinctrl/pinctrl-generic.c b/drivers/pinctrl/pinctrl-generic.c
index 3c8e240..ec21d4f 100644
--- a/drivers/pinctrl/pinctrl-generic.c
+++ b/drivers/pinctrl/pinctrl-generic.c
@@ -234,6 +234,24 @@
 	PST_PINMUX,
 };
 
+static const char *alloc_name_with_prefix(const char *name, const char *prefix)
+{
+	if (prefix) {
+		char *name_with_prefix = malloc(strlen(prefix) + sizeof("pins"));
+		if (name_with_prefix)
+			sprintf(name_with_prefix, "%s%s", prefix, name);
+		return name_with_prefix;
+	} else {
+		return name;
+	}
+}
+
+static void free_name_with_prefix(const char *name_with_prefix, const char *prefix)
+{
+	if (prefix)
+		free((char *)name_with_prefix);
+}
+
 /**
  * pinctrl_generic_set_state_one() - set state for a certain pin/group
  * Apply all pin multiplexing and pin configurations specified by @config
@@ -248,9 +266,11 @@
  */
 static int pinctrl_generic_set_state_one(struct udevice *dev,
 					 struct udevice *config,
+					 const char *prefix,
 					 enum pinmux_subnode_type subnode_type,
 					 unsigned selector)
 {
+	const char *function_propname;
 	const char *propname;
 	const void *value;
 	struct ofprop property;
@@ -259,18 +279,26 @@
 
 	assert(subnode_type != PST_NONE);
 
+	function_propname = alloc_name_with_prefix("function", prefix);
+	if (!function_propname)
+		return -ENOMEM;
+
 	dev_for_each_property(property, config) {
 		value = dev_read_prop_by_prop(&property, &propname, &len);
-		if (!value)
+		if (!value) {
+			free_name_with_prefix(function_propname, prefix);
 			return -EINVAL;
+		}
 
 		/* pinmux subnodes already have their muxing set */
 		if (subnode_type != PST_PINMUX &&
-		    !strcmp(propname, "function")) {
+		    !strcmp(propname, function_propname)) {
 			func_selector = pinmux_func_name_to_selector(dev,
 								     value);
-			if (func_selector < 0)
+			if (func_selector < 0) {
+				free_name_with_prefix(function_propname, prefix);
 				return func_selector;
+			}
 			ret = pinmux_enable_setting(dev,
 						    subnode_type == PST_GROUP,
 						    selector,
@@ -291,10 +319,13 @@
 						     selector, param, arg);
 		}
 
-		if (ret)
+		if (ret) {
+			free_name_with_prefix(function_propname, prefix);
 			return ret;
+		}
 	}
 
+	free_name_with_prefix(function_propname, prefix);
 	return 0;
 }
 
@@ -309,20 +340,34 @@
  */
 static enum pinmux_subnode_type pinctrl_generic_get_subnode_type(struct udevice *dev,
 								 struct udevice *config,
+								 const char *prefix,
 								 int *count)
 {
 	const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+	const char *propname;
 
-	*count = dev_read_string_count(config, "pins");
+	propname = alloc_name_with_prefix("pins", prefix);
+	if (!propname)
+		return -ENOMEM;
+	*count = dev_read_string_count(config, propname);
+	free_name_with_prefix(propname, prefix);
 	if (*count >= 0)
 		return PST_PIN;
 
-	*count = dev_read_string_count(config, "groups");
+	propname = alloc_name_with_prefix("groups", prefix);
+	if (!propname)
+		return -ENOMEM;
+	*count = dev_read_string_count(config, propname);
+	free_name_with_prefix(propname, prefix);
 	if (*count >= 0)
 		return PST_GROUP;
 
 	if (ops->pinmux_property_set) {
-		*count = dev_read_size(config, "pinmux");
+		propname = alloc_name_with_prefix("pinmux", prefix);
+		if (!propname)
+			return -ENOMEM;
+		*count = dev_read_size(config, propname);
+		free_name_with_prefix(propname, prefix);
 		if (*count >= 0 && !(*count % sizeof(u32))) {
 			*count /= sizeof(u32);
 			return PST_PINMUX;
@@ -338,23 +383,30 @@
  *
  * @dev: pin controller device
  * @config: pseudo device pointing to config node
+ * @prefix: device tree property prefix (e.g. vendor specific)
  * @return: 0 on success, or negative error code on failure
  */
 static int pinctrl_generic_set_state_subnode(struct udevice *dev,
-					     struct udevice *config)
+					     struct udevice *config,
+					     const char *prefix)
 {
 	enum pinmux_subnode_type subnode_type;
+	const char *propname;
 	const char *name;
 	int count, selector, i, ret, scratch;
 	const u32 *pinmux_groups = NULL; /* prevent use-uninitialized warning */
 
-	subnode_type = pinctrl_generic_get_subnode_type(dev, config, &count);
+	subnode_type = pinctrl_generic_get_subnode_type(dev, config, prefix, &count);
 
 	debug("%s(%s, %s): count=%d\n", __func__, dev->name, config->name,
 	      count);
 
 	if (subnode_type == PST_PINMUX) {
-		pinmux_groups = dev_read_prop(config, "pinmux", &scratch);
+		propname = alloc_name_with_prefix("pinmux", prefix);
+		if (!propname)
+			return -ENOMEM;
+		pinmux_groups = dev_read_prop(config, propname, &scratch);
+		free_name_with_prefix(propname, prefix);
 		if (!pinmux_groups)
 			return -EINVAL;
 	}
@@ -362,13 +414,21 @@
 	for (i = 0; i < count; i++) {
 		switch (subnode_type) {
 		case PST_PIN:
-			ret = dev_read_string_index(config, "pins", i, &name);
+			propname = alloc_name_with_prefix("pins", prefix);
+			if (!propname)
+				return -ENOMEM;
+			ret = dev_read_string_index(config, propname, i, &name);
+			free_name_with_prefix(propname, prefix);
 			if (ret)
 				return ret;
 			selector = pinctrl_pin_name_to_selector(dev, name);
 			break;
 		case PST_GROUP:
-			ret = dev_read_string_index(config, "groups", i, &name);
+			propname = alloc_name_with_prefix("groups", prefix);
+			if (!propname)
+				return -ENOMEM;
+			ret = dev_read_string_index(config, propname, i, &name);
+			free_name_with_prefix(propname, prefix);
 			if (ret)
 				return ret;
 			selector = pinctrl_group_name_to_selector(dev, name);
@@ -390,8 +450,29 @@
 		if (selector < 0)
 			return selector;
 
-		ret = pinctrl_generic_set_state_one(dev, config, subnode_type,
-						    selector);
+		ret = pinctrl_generic_set_state_one(dev, config, prefix,
+						    subnode_type, selector);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int pinctrl_generic_set_state_prefix(struct udevice *dev, struct udevice *config,
+				     const char *prefix)
+{
+	struct udevice *child;
+	int ret;
+
+	ret = pinctrl_generic_set_state_subnode(dev, config, prefix);
+	if (ret)
+		return ret;
+
+	for (device_find_first_child(config, &child);
+	     child;
+	     device_find_next_child(&child)) {
+		ret = pinctrl_generic_set_state_subnode(dev, child, prefix);
 		if (ret)
 			return ret;
 	}
@@ -401,20 +482,5 @@
 
 int pinctrl_generic_set_state(struct udevice *dev, struct udevice *config)
 {
-	struct udevice *child;
-	int ret;
-
-	ret = pinctrl_generic_set_state_subnode(dev, config);
-	if (ret)
-		return ret;
-
-	for (device_find_first_child(config, &child);
-	     child;
-	     device_find_next_child(&child)) {
-		ret = pinctrl_generic_set_state_subnode(dev, child);
-		if (ret)
-			return ret;
-	}
-
-	return 0;
+	return pinctrl_generic_set_state_prefix(dev, config, NULL);
 }
diff --git a/drivers/pinctrl/pinctrl-uclass.c b/drivers/pinctrl/pinctrl-uclass.c
index 38ce2b5..ce2d5dd 100644
--- a/drivers/pinctrl/pinctrl-uclass.c
+++ b/drivers/pinctrl/pinctrl-uclass.c
@@ -222,9 +222,10 @@
  *
  * @dev: GPIO peripheral device
  * @offset: the GPIO pin offset from the GPIO controller
+ * @label: the GPIO pin label
  * @return: 0 on success, or negative error code on failure
  */
-int pinctrl_gpio_request(struct udevice *dev, unsigned offset)
+int pinctrl_gpio_request(struct udevice *dev, unsigned offset, const char *label)
 {
 	const struct pinctrl_ops *ops;
 	struct udevice *pctldev;
diff --git a/include/dm/pinctrl.h b/include/dm/pinctrl.h
index a09b242..e3e50afe 100644
--- a/include/dm/pinctrl.h
+++ b/include/dm/pinctrl.h
@@ -491,6 +491,8 @@
  * Return: 0 on success, or negative error code on failure
  */
 int pinctrl_generic_set_state(struct udevice *pctldev, struct udevice *config);
+int pinctrl_generic_set_state_prefix(struct udevice *pctldev, struct udevice *config,
+				     const char *prefix);
 #else
 static inline int pinctrl_generic_set_state(struct udevice *pctldev,
 					    struct udevice *config)
@@ -609,10 +611,11 @@
  * pinctrl_gpio_request() - Request a single pin to be used as GPIO
  * @dev:	GPIO peripheral device
  * @offset:	GPIO pin offset from the GPIO controller
+ * @label:	GPIO label
  *
  * Return: 0 on success, or negative error code on failure
  */
-int pinctrl_gpio_request(struct udevice *dev, unsigned offset);
+int pinctrl_gpio_request(struct udevice *dev, unsigned offset, const char *label);
 
 /**
  * pinctrl_gpio_free() - Free a single pin used as GPIO