summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/dts/armada-7040-db.dts64
-rw-r--r--arch/arm/dts/armada-8040-db.dts114
-rw-r--r--arch/arm/dts/armada-ap806.dtsi18
-rw-r--r--arch/arm/dts/armada-cp110-master.dtsi32
-rw-r--r--arch/arm/dts/armada-cp110-slave.dtsi19
-rw-r--r--arch/arm/include/asm/arch-armada8k/cache_llc.h21
-rw-r--r--arch/arm/include/asm/arch-armada8k/soc-info.h17
-rw-r--r--arch/arm/mach-mvebu/armada8k/Makefile1
-rw-r--r--arch/arm/mach-mvebu/armada8k/cache_llc.S39
-rw-r--r--cmd/Kconfig3
-rw-r--r--cmd/Makefile2
-rw-r--r--cmd/mvebu/Kconfig52
-rw-r--r--cmd/mvebu/Makefile8
-rw-r--r--cmd/mvebu/bubt.c767
-rw-r--r--configs/mvebu_db-88f7040_defconfig6
-rw-r--r--configs/mvebu_db-88f8040_defconfig3
-rw-r--r--doc/device-tree-bindings/pinctrl/marvell,armada-apn806-pinctrl.txt25
-rw-r--r--doc/device-tree-bindings/pinctrl/marvell,armada-cp110-pinctrl.txt270
-rw-r--r--doc/device-tree-bindings/pinctrl/marvell,mvebu-pinctrl.txt113
-rw-r--r--doc/mvebu/cmd/bubt.txt64
-rw-r--r--drivers/pinctrl/Kconfig1
-rw-r--r--drivers/pinctrl/Makefile1
-rw-r--r--drivers/pinctrl/mvebu/Kconfig7
-rw-r--r--drivers/pinctrl/mvebu/Makefile7
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-mvebu.c179
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-mvebu.h31
26 files changed, 1800 insertions, 64 deletions
diff --git a/arch/arm/dts/armada-7040-db.dts b/arch/arm/dts/armada-7040-db.dts
index b8fe5a9cb9..466c6dcc3f 100644
--- a/arch/arm/dts/armada-7040-db.dts
+++ b/arch/arm/dts/armada-7040-db.dts
@@ -66,36 +66,14 @@
};
};
-&i2c0 {
- status = "okay";
- clock-frequency = <100000>;
-};
-
-&spi0 {
- status = "okay";
-
- spi-flash@0 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "jedec,spi-nor";
- reg = <0>;
- spi-max-frequency = <10000000>;
-
- partitions {
- compatible = "fixed-partitions";
- #address-cells = <1>;
- #size-cells = <1>;
-
- partition@0 {
- label = "U-Boot";
- reg = <0 0x200000>;
- };
- partition@400000 {
- label = "Filesystem";
- reg = <0x200000 0xce0000>;
- };
- };
- };
+&ap_pinctl {
+ /* MPP Bus:
+ * SDIO [0-5]
+ * UART0 [11,19]
+ */
+ /* 0 1 2 3 4 5 6 7 8 9 */
+ pin-func = < 1 1 1 1 1 1 0 0 0 0
+ 0 3 0 0 0 0 0 0 0 3 >;
};
&uart0 {
@@ -108,11 +86,37 @@
};
&cpm_i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&cpm_i2c0_pins>;
status = "okay";
clock-frequency = <100000>;
};
+&cpm_pinctl {
+ /* MPP Bus:
+ * TDM [0-11]
+ * SPI [13-16]
+ * SATA1 [28]
+ * UART0 [29-30]
+ * SMI [32,34]
+ * XSMI [35-36]
+ * I2C [37-38]
+ * RGMII1[44-55]
+ * SD [56-62]
+ */
+ /* 0 1 2 3 4 5 6 7 8 9 */
+ pin-func = < 4 4 4 4 4 4 4 4 4 4
+ 4 4 0 3 3 3 3 0 0 0
+ 0 0 0 0 0 0 0 0 9 0xA
+ 0xA 0 7 0 7 7 7 2 2 0
+ 0 0 0 0 1 1 1 1 1 1
+ 1 1 1 1 1 1 0xE 0xE 0xE 0xE
+ 0xE 0xE 0xE >;
+};
+
&cpm_spi1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&cpm_spi0_pins>;
status = "okay";
spi-flash@0 {
diff --git a/arch/arm/dts/armada-8040-db.dts b/arch/arm/dts/armada-8040-db.dts
index 7fb674b8b7..40def9d6cd 100644
--- a/arch/arm/dts/armada-8040-db.dts
+++ b/arch/arm/dts/armada-8040-db.dts
@@ -57,7 +57,7 @@
aliases {
i2c0 = &cpm_i2c0;
- spi0 = &spi0;
+ spi0 = &cps_spi1;
};
memory@00000000 {
@@ -66,50 +66,55 @@
};
};
-&i2c0 {
+/* Accessible over the mini-USB CON9 connector on the main board */
+&uart0 {
status = "okay";
- clock-frequency = <100000>;
};
-&spi0 {
- status = "okay";
-
- spi-flash@0 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "jedec,spi-nor";
- reg = <0>;
- spi-max-frequency = <10000000>;
-
- partitions {
- compatible = "fixed-partitions";
- #address-cells = <1>;
- #size-cells = <1>;
-
- partition@0 {
- label = "U-Boot";
- reg = <0 0x200000>;
- };
- partition@400000 {
- label = "Filesystem";
- reg = <0x200000 0xce0000>;
- };
- };
- };
+&ap_pinctl {
+ /* MPP Bus:
+ * SDIO [0-10]
+ * UART0 [11,19]
+ */
+ /* 0 1 2 3 4 5 6 7 8 9 */
+ pin-func = < 1 1 1 1 1 1 1 1 1 1
+ 1 3 0 0 0 0 0 0 0 3 >;
};
-/* Accessible over the mini-USB CON9 connector on the main board */
-&uart0 {
- status = "okay";
+&cpm_pinctl {
+ /* MPP Bus:
+ * [0-31] = 0xff: Keep default CP0_shared_pins:
+ * [11] CLKOUT_MPP_11 (out)
+ * [23] LINK_RD_IN_CP2CP (in)
+ * [25] CLKOUT_MPP_25 (out)
+ * [29] AVS_FB_IN_CP2CP (in)
+ * [32,34] SMI
+ * [31] GPIO: push button/Wake
+ * [35-36] GPIO
+ * [37-38] I2C
+ * [40-41] SATA[0/1]_PRESENT_ACTIVEn
+ * [42-43] XSMI
+ * [44-55] RGMII1
+ * [56-62] SD
+ */
+ /* 0 1 2 3 4 5 6 7 8 9 */
+ pin-func = < 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
+ 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
+ 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
+ 0xff 0 7 0 7 0 0 2 2 0
+ 0 0 8 8 1 1 1 1 1 1
+ 1 1 1 1 1 1 0xe 0xe 0xe 0xe
+ 0xe 0xe 0xe >;
};
-
/* CON5 on CP0 expansion */
&cpm_pcie2 {
status = "okay";
};
&cpm_i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&cpm_i2c0_pins>;
status = "okay";
clock-frequency = <100000>;
};
@@ -129,14 +134,55 @@
status = "okay";
};
+&cps_pinctl {
+ /* MPP Bus:
+ * [0-11] RGMII0
+ * [13-16] SPI1
+ * [27,31] GE_MDIO/MDC
+ * [32-62] = 0xff: Keep default CP1_shared_pins:
+ */
+ /* 0 1 2 3 4 5 6 7 8 9 */
+ pin-func = < 0x3 0x3 0x3 0x3 0x3 0x3 0x3 0x3 0x3 0x3
+ 0x3 0x3 0xff 0x3 0x3 0x3 0x3 0xff 0xff 0xff
+ 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0x8 0xff 0xff
+ 0xff 0x8 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
+ 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
+ 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
+ 0xff 0xff 0xff >;
+};
+
/* CON5 on CP1 expansion */
&cps_pcie2 {
status = "okay";
};
-&cps_i2c0 {
+&cps_spi1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&cps_spi1_pins>;
status = "okay";
- clock-frequency = <100000>;
+
+ spi-flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <10000000>;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "U-Boot";
+ reg = <0 0x200000>;
+ };
+ partition@400000 {
+ label = "Filesystem";
+ reg = <0x200000 0xce0000>;
+ };
+ };
+ };
};
/* CON4 on CP1 expansion */
diff --git a/arch/arm/dts/armada-ap806.dtsi b/arch/arm/dts/armada-ap806.dtsi
index d315b29cd0..efb383b9f3 100644
--- a/arch/arm/dts/armada-ap806.dtsi
+++ b/arch/arm/dts/armada-ap806.dtsi
@@ -140,6 +140,24 @@
marvell,spi-base = <128>, <136>, <144>, <152>;
};
+ ap_pinctl: ap-pinctl@6F4000 {
+ compatible = "marvell,armada-ap806-pinctrl";
+ bank-name ="apn-806";
+ reg = <0x6F4000 0x10>;
+ pin-count = <20>;
+ max-func = <3>;
+
+ ap_i2c0_pins: i2c-pins-0 {
+ marvell,pins = < 4 5 >;
+ marvell,function = <3>;
+ };
+ ap_emmc_pins: emmc-pins-0 {
+ marvell,pins = < 0 1 2 3 4 5 6 7
+ 8 9 10 >;
+ marvell,function = <1>;
+ };
+ };
+
xor@400000 {
compatible = "marvell,mv-xor-v2";
reg = <0x400000 0x1000>,
diff --git a/arch/arm/dts/armada-cp110-master.dtsi b/arch/arm/dts/armada-cp110-master.dtsi
index 422d754401..d637867615 100644
--- a/arch/arm/dts/armada-cp110-master.dtsi
+++ b/arch/arm/dts/armada-cp110-master.dtsi
@@ -81,6 +81,38 @@
"cpm-usb3dev", "cpm-eip150", "cpm-eip197";
};
+ cpm_pinctl: cpm-pinctl@440000 {
+ compatible = "marvell,mvebu-pinctrl",
+ "marvell,a70x0-pinctrl",
+ "marvell,a80x0-cp0-pinctrl";
+ bank-name ="cp0-110";
+ reg = <0x440000 0x20>;
+ pin-count = <63>;
+ max-func = <0xf>;
+
+ cpm_i2c0_pins: cpm-i2c-pins-0 {
+ marvell,pins = < 37 38 >;
+ marvell,function = <2>;
+ };
+ cpm_ge2_rgmii_pins: cpm-ge-rgmii-pins-0 {
+ marvell,pins = < 44 45 46 47 48 49 50 51
+ 52 53 54 55 >;
+ marvell,function = <1>;
+ };
+ pca0_pins: cpm-pca0_pins {
+ marvell,pins = <62>;
+ marvell,function = <0>;
+ };
+ cpm_sdhci_pins: cpm-sdhi-pins-0 {
+ marvell,pins = < 56 57 58 59 60 61 >;
+ marvell,function = <14>;
+ };
+ cpm_spi0_pins: cpm-spi-pins-0 {
+ marvell,pins = < 13 14 15 16 >;
+ marvell,function = <3>;
+ };
+ };
+
cpm_sata0: sata@540000 {
compatible = "marvell,armada-8k-ahci";
reg = <0x540000 0x30000>;
diff --git a/arch/arm/dts/armada-cp110-slave.dtsi b/arch/arm/dts/armada-cp110-slave.dtsi
index a7f77b9515..92ef55cf26 100644
--- a/arch/arm/dts/armada-cp110-slave.dtsi
+++ b/arch/arm/dts/armada-cp110-slave.dtsi
@@ -81,6 +81,25 @@
"cps-usb3dev", "cps-eip150", "cps-eip197";
};
+ cps_pinctl: cps-pinctl@440000 {
+ compatible = "marvell,mvebu-pinctrl",
+ "marvell,a80x0-cp1-pinctrl";
+ bank-name ="cp1-110";
+ reg = <0x440000 0x20>;
+ pin-count = <63>;
+ max-func = <0xf>;
+
+ cps_ge1_rgmii_pins: cps-ge-rgmii-pins-0 {
+ marvell,pins = < 0 1 2 3 4 5 6 7
+ 8 9 10 11 >;
+ marvell,function = <3>;
+ };
+ cps_spi1_pins: cps-spi-pins-1 {
+ marvell,pins = < 13 14 15 16 >;
+ marvell,function = <3>;
+ };
+ };
+
cps_sata0: sata@540000 {
compatible = "marvell,armada-8k-ahci";
reg = <0x540000 0x30000>;
diff --git a/arch/arm/include/asm/arch-armada8k/cache_llc.h b/arch/arm/include/asm/arch-armada8k/cache_llc.h
new file mode 100644
index 0000000000..8f97e6d776
--- /dev/null
+++ b/arch/arm/include/asm/arch-armada8k/cache_llc.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ * https://spdx.org/licenses
+ */
+
+#ifndef _CACHE_LLC_H_
+#define _CACHE_LLC_H_
+
+/* Armada-7K/8K last level cache */
+
+#define MVEBU_A8K_REGS_BASE_MSB 0xf000
+#define LLC_BASE_ADDR 0x8000
+#define LLC_CACHE_SYNC 0x700
+#define LLC_CACHE_SYNC_COMPLETE 0x730
+#define LLC_FLUSH_BY_WAY 0x7fc
+#define LLC_WAY_MASK 0xffffffff
+#define LLC_CACHE_SYNC_MASK 0x1
+
+#endif /* _CACHE_LLC_H_ */
diff --git a/arch/arm/include/asm/arch-armada8k/soc-info.h b/arch/arm/include/asm/arch-armada8k/soc-info.h
new file mode 100644
index 0000000000..bae39951ee
--- /dev/null
+++ b/arch/arm/include/asm/arch-armada8k/soc-info.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2016 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ * https://spdx.org/licenses
+ */
+
+#ifndef _SOC_INFO_H_
+#define _SOC_INFO_H_
+
+/* Pin Ctrl driver definitions */
+#define BITS_PER_PIN 4
+#define PIN_FUNC_MASK ((1 << BITS_PER_PIN) - 1)
+#define PIN_REG_SHIFT 3
+#define PIN_FIELD_MASK ((1 << PIN_REG_SHIFT) - 1)
+
+#endif /* _SOC_INFO_H_ */
diff --git a/arch/arm/mach-mvebu/armada8k/Makefile b/arch/arm/mach-mvebu/armada8k/Makefile
index 84c69d90e7..0facf14942 100644
--- a/arch/arm/mach-mvebu/armada8k/Makefile
+++ b/arch/arm/mach-mvebu/armada8k/Makefile
@@ -5,3 +5,4 @@
#
obj-y = cpu.o
+obj-y += cache_llc.o
diff --git a/arch/arm/mach-mvebu/armada8k/cache_llc.S b/arch/arm/mach-mvebu/armada8k/cache_llc.S
new file mode 100644
index 0000000000..71aecb2dde
--- /dev/null
+++ b/arch/arm/mach-mvebu/armada8k/cache_llc.S
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ * https://spdx.org/licenses
+ */
+
+#include <asm/arch-armada8k/cache_llc.h>
+#include <linux/linkage.h>
+
+/*
+ * int __asm_flush_l3_dcache
+ *
+ * flush Armada-8K last level cache.
+ *
+ */
+ENTRY(__asm_flush_l3_dcache)
+ /* flush cache */
+ mov x0, #LLC_BASE_ADDR
+ add x0, x0, #LLC_FLUSH_BY_WAY
+ movk x0, #MVEBU_A8K_REGS_BASE_MSB, lsl #16
+ mov w1, #LLC_WAY_MASK
+ str w1, [x0]
+ /* sync cache */
+ mov x0, #LLC_BASE_ADDR
+ add x0, x0, #LLC_CACHE_SYNC
+ movk x0, #MVEBU_A8K_REGS_BASE_MSB, lsl #16
+ str wzr, [x0]
+ /* check that cache sync completed */
+ mov x0, #LLC_BASE_ADDR
+ add x0, x0, #LLC_CACHE_SYNC_COMPLETE
+ movk x0, #MVEBU_A8K_REGS_BASE_MSB, lsl #16
+1: ldr w1, [x0]
+ and w1, w1, #LLC_CACHE_SYNC_MASK
+ cbnz w1, 1b
+ /* return success */
+ mov x0, #0
+ ret
+ENDPROC(__asm_flush_l3_dcache)
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 586a6456e4..bffa7134f7 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -653,6 +653,9 @@ config CMD_QFW
This provides access to the QEMU firmware interface. The main
feature is to allow easy loading of files passed to qemu-system
via -kernel / -initrd
+
+source "cmd/mvebu/Kconfig"
+
endmenu
config CMD_BOOTSTAGE
diff --git a/cmd/Makefile b/cmd/Makefile
index 9c9a9d112b..34bc5448b9 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -163,3 +163,5 @@ obj-$(CONFIG_CMD_BLOB) += blob.o
# core command
obj-y += nvedit.o
+
+obj-$(CONFIG_ARCH_MVEBU) += mvebu/
diff --git a/cmd/mvebu/Kconfig b/cmd/mvebu/Kconfig
new file mode 100644
index 0000000000..ad10a572a3
--- /dev/null
+++ b/cmd/mvebu/Kconfig
@@ -0,0 +1,52 @@
+menu "MVEBU commands"
+depends on ARCH_MVEBU
+
+config CMD_MVEBU_BUBT
+ bool "bubt"
+ default n
+ help
+ bubt - Burn a u-boot image to flash
+ For details about bubt command please see the documentation
+ in doc/mvebu/cmd/bubt.txt
+
+choice
+ prompt "Flash for image"
+ default MVEBU_SPI_BOOT
+
+config MVEBU_NAND_BOOT
+ bool "NAND flash boot"
+ depends on NAND_PXA3XX
+ help
+ Enable boot from NAND flash.
+ Allow usage of NAND flash as a target for "bubt" command
+ For details about bubt command please see the documentation
+ in doc/mvebu/cmd/bubt.txt
+
+config MVEBU_SPI_BOOT
+ bool "SPI flash boot"
+ depends on SPI_FLASH
+ help
+ Enable boot from SPI flash.
+ Allow usage of SPI flash as a target for "bubt" command
+ For details about bubt command please see the documentation
+ in doc/mvebu/cmd/bubt.txt
+
+config MVEBU_MMC_BOOT
+ bool "eMMC flash boot"
+ depends on MVEBU_MMC
+ help
+ Enable boot from eMMC boot partition
+ Allow usage of eMMC/SD device as a target for "bubt" command
+ For details about bubt command please see the documentation
+ in doc/mvebu/cmd/bubt.txt
+
+endchoice
+
+config MVEBU_UBOOT_DFLT_NAME
+ string "Default image name for bubt command"
+ default "flash-image.bin"
+ help
+ This option should contain a default file name to be used with
+ MVEBU "bubt" command if the source file name is omitted
+
+endmenu
diff --git a/cmd/mvebu/Makefile b/cmd/mvebu/Makefile
new file mode 100644
index 0000000000..03de53ecdd
--- /dev/null
+++ b/cmd/mvebu/Makefile
@@ -0,0 +1,8 @@
+#
+# Copyright (C) 2016 Marvell International Ltd.
+#
+# SPDX-License-Identifier: GPL-2.0
+# https://spdx.org/licenses
+
+
+obj-$(CONFIG_CMD_MVEBU_BUBT) += bubt.o
diff --git a/cmd/mvebu/bubt.c b/cmd/mvebu/bubt.c
new file mode 100644
index 0000000000..1cbfcf0863
--- /dev/null
+++ b/cmd/mvebu/bubt.c
@@ -0,0 +1,767 @@
+/*
+ * Copyright (C) 2016 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ * https://spdx.org/licenses
+ */
+
+#include <config.h>
+#include <common.h>
+#include <command.h>
+#include <vsprintf.h>
+#include <errno.h>
+#include <dm.h>
+
+#include <spi_flash.h>
+#include <spi.h>
+#include <nand.h>
+#include <usb.h>
+#include <fs.h>
+#include <mmc.h>
+#include <u-boot/sha1.h>
+#include <u-boot/sha256.h>
+
+#ifndef CONFIG_SYS_MMC_ENV_DEV
+#define CONFIG_SYS_MMC_ENV_DEV 0
+#endif
+
+#if defined(CONFIG_ARMADA_8K)
+#define MAIN_HDR_MAGIC 0xB105B002
+
+struct mvebu_image_header {
+ u32 magic; /* 0-3 */
+ u32 prolog_size; /* 4-7 */
+ u32 prolog_checksum; /* 8-11 */
+ u32 boot_image_size; /* 12-15 */
+ u32 boot_image_checksum; /* 16-19 */
+ u32 rsrvd0; /* 20-23 */
+ u32 load_addr; /* 24-27 */
+ u32 exec_addr; /* 28-31 */
+ u8 uart_cfg; /* 32 */
+ u8 baudrate; /* 33 */
+ u8 ext_count; /* 34 */
+ u8 aux_flags; /* 35 */
+ u32 io_arg_0; /* 36-39 */
+ u32 io_arg_1; /* 40-43 */
+ u32 io_arg_2; /* 43-47 */
+ u32 io_arg_3; /* 48-51 */
+ u32 rsrvd1; /* 52-55 */
+ u32 rsrvd2; /* 56-59 */
+ u32 rsrvd3; /* 60-63 */
+};
+#elif defined(CONFIG_ARMADA_3700) /* A3700 */
+#define HASH_SUM_LEN 16
+#define IMAGE_VERSION_3_6_0 0x030600
+#define IMAGE_VERSION_3_5_0 0x030500
+
+struct common_tim_data {
+ u32 version;
+ u32 identifier;
+ u32 trusted;
+ u32 issue_date;
+ u32 oem_unique_id;
+ u32 reserved[5]; /* Reserve 20 bytes */
+ u32 boot_flash_sign;
+ u32 num_images;
+ u32 num_keys;
+ u32 size_of_reserved;
+};
+
+struct mvebu_image_info {
+ u32 image_id;
+ u32 next_image_id;
+ u32 flash_entry_addr;
+ u32 load_addr;
+ u32 image_size;
+ u32 image_size_to_hash;
+ u32 hash_algorithm_id;
+ u32 hash[HASH_SUM_LEN]; /* Reserve 512 bits for the hash */
+ u32 partition_number;
+ u32 enc_algorithm_id;
+ u32 encrypt_start_offset;
+ u32 encrypt_size;
+};
+#endif /* CONFIG_ARMADA_XXX */
+
+struct bubt_dev {
+ char name[8];
+ size_t (*read)(const char *file_name);
+ int (*write)(size_t image_size);
+ int (*active)(void);
+};
+
+static ulong get_load_addr(void)
+{
+ const char *addr_str;
+ unsigned long addr;
+
+ addr_str = getenv("loadaddr");
+ if (addr_str)
+ addr = simple_strtoul(addr_str, NULL, 16);
+ else
+ addr = CONFIG_SYS_LOAD_ADDR;
+
+ return addr;
+}
+
+/********************************************************************
+ * eMMC services
+ ********************************************************************/
+#ifdef CONFIG_DM_MMC
+static int mmc_burn_image(size_t image_size)
+{
+ struct mmc *mmc;
+ lbaint_t start_lba;
+ lbaint_t blk_count;
+ ulong blk_written;
+ int err;
+ const u8 mmc_dev_num = CONFIG_SYS_MMC_ENV_DEV;
+
+ mmc = find_mmc_device(mmc_dev_num);
+ if (!mmc) {
+ printf("No SD/MMC/eMMC card found\n");
+ return -ENOMEDIUM;
+ }
+
+ err = mmc_init(mmc);
+ if (err) {
+ printf("%s(%d) init failed\n", IS_SD(mmc) ? "SD" : "MMC",
+ mmc_dev_num);
+ return err;
+ }
+
+#ifdef CONFIG_SYS_MMC_ENV_PART
+ if (mmc->part_num != CONFIG_SYS_MMC_ENV_PART) {
+ err = mmc_switch_part(mmc_dev_num, CONFIG_SYS_MMC_ENV_PART);
+ if (err) {
+ printf("MMC partition switch failed\n");
+ return err;
+ }
+ }
+#endif
+
+ /* SD reserves LBA-0 for MBR and boots from LBA-1,
+ * MMC/eMMC boots from LBA-0
+ */
+ start_lba = IS_SD(mmc) ? 1 : 0;
+ blk_count = image_size / mmc->block_dev.blksz;
+ if (image_size % mmc->block_dev.blksz)
+ blk_count += 1;
+
+ blk_written = mmc->block_dev.block_write(mmc_dev_num,
+ start_lba, blk_count,
+ (void *)get_load_addr());
+ if (blk_written != blk_count) {
+ printf("Error - written %#lx blocks\n", blk_written);
+ return -ENOSPC;
+ }
+ printf("Done!\n");
+
+#ifdef CONFIG_SYS_MMC_ENV_PART
+ if (mmc->part_num != CONFIG_SYS_MMC_ENV_PART)
+ mmc_switch_part(mmc_dev_num, mmc->part_num);
+#endif
+
+ return 0;
+}
+
+static size_t mmc_read_file(const char *file_name)
+{
+ loff_t act_read = 0;
+ int rc;
+ struct mmc *mmc;
+ const u8 mmc_dev_num = CONFIG_SYS_MMC_ENV_DEV;
+
+ mmc = find_mmc_device(mmc_dev_num);
+ if (!mmc) {
+ printf("No SD/MMC/eMMC card found\n");
+ return 0;
+ }
+
+ if (mmc_init(mmc)) {
+ printf("%s(%d) init failed\n", IS_SD(mmc) ? "SD" : "MMC",
+ mmc_dev_num);
+ return 0;
+ }
+
+ /* Load from data partition (0) */
+ if (fs_set_blk_dev("mmc", "0", FS_TYPE_ANY)) {
+ printf("Error: MMC 0 not found\n");
+ return 0;
+ }
+
+ /* Perfrom file read */
+ rc = fs_read(file_name, get_load_addr(), 0, 0, &act_read);
+ if (rc)
+ return 0;
+
+ return act_read;
+}
+
+static int is_mmc_active(void)
+{
+ return 1;
+}
+#else /* CONFIG_DM_MMC */
+static int mmc_burn_image(size_t image_size)
+{
+ return -ENODEV;
+}
+
+static size_t mmc_read_file(const char *file_name)
+{
+ return 0;
+}
+
+static int is_mmc_active(void)
+{
+ return 0;
+}
+#endif /* CONFIG_DM_MMC */
+
+/********************************************************************
+ * SPI services
+ ********************************************************************/
+#ifdef CONFIG_SPI_FLASH
+static int spi_burn_image(size_t image_size)
+{
+ int ret;
+ struct spi_flash *flash;
+ u32 erase_bytes;
+
+ /* Probe the SPI bus to get the flash device */
+ flash = spi_flash_probe(CONFIG_ENV_SPI_BUS,
+ CONFIG_ENV_SPI_CS,
+ CONFIG_SF_DEFAULT_SPEED,
+ CONFIG_SF_DEFAULT_MODE);
+ if (!flash) {
+ printf("Failed to probe SPI Flash\n");
+ return -ENOMEDIUM;
+ }
+
+#ifdef CONFIG_SPI_FLASH_PROTECTION
+ spi_flash_protect(flash, 0);
+#endif
+ erase_bytes = image_size +
+ (flash->erase_size - image_size % flash->erase_size);
+ printf("Erasing %d bytes (%d blocks) at offset 0 ...",
+ erase_bytes, erase_bytes / flash->erase_size);
+ ret = spi_flash_erase(flash, 0, erase_bytes);
+ if (ret)
+ printf("Error!\n");
+ else
+ printf("Done!\n");
+
+ printf("Writing %d bytes from 0x%lx to offset 0 ...",
+ (int)image_size, get_load_addr());
+ ret = spi_flash_write(flash, 0, image_size, (void *)get_load_addr());
+ if (ret)
+ printf("Error!\n");
+ else
+ printf("Done!\n");
+
+#ifdef CONFIG_SPI_FLASH_PROTECTION
+ spi_flash_protect(flash, 1);
+#endif
+
+ return ret;
+}
+
+static int is_spi_active(void)
+{
+ return 1;
+}
+
+#else /* CONFIG_SPI_FLASH */
+static int spi_burn_image(size_t image_size)
+{
+ return -ENODEV;
+}
+
+static int is_spi_active(void)
+{
+ return 0;
+}
+#endif /* CONFIG_SPI_FLASH */
+
+/********************************************************************
+ * NAND services
+ ********************************************************************/
+#ifdef CONFIG_CMD_NAND
+static int nand_burn_image(size_t image_size)
+{
+ int ret, block_size;
+ nand_info_t *nand;
+ int dev = nand_curr_device;
+
+ if ((dev < 0) || (dev >= CONFIG_SYS_MAX_NAND_DEVICE) ||
+ (!nand_info[dev].name)) {
+ puts("\nno devices available\n");
+ return -ENOMEDIUM;
+ }
+ nand = &nand_info[dev];
+ block_size = nand->erasesize;
+
+ /* Align U-Boot size to currently used blocksize */
+ image_size = ((image_size + (block_size - 1)) & (~(block_size - 1)));
+
+ /* Erase the U-BOOT image space */
+ printf("Erasing 0x%x - 0x%x:...", 0, (int)image_size);
+ ret = nand_erase(nand, 0, image_size);
+ if (ret) {
+ printf("Error!\n");
+ goto error;
+ }
+ printf("Done!\n");
+
+ /* Write the image to flash */
+ printf("Writing image:...");
+ printf("&image_size = 0x%p\n", (void *)&image_size);
+ ret = nand_write(nand, 0, &image_size, (void *)get_load_addr());
+ if (ret)
+ printf("Error!\n");
+ else
+ printf("Done!\n");
+
+error:
+ return ret;
+}
+
+static int is_nand_active(void)
+{
+ return 1;
+}
+
+#else /* CONFIG_CMD_NAND */
+static int nand_burn_image(size_t image_size)
+{
+ return -ENODEV;
+}
+
+static int is_nand_active(void)
+{
+ return 0;
+}
+#endif /* CONFIG_CMD_NAND */
+
+/********************************************************************
+ * USB services
+ ********************************************************************/
+#if defined(CONFIG_USB_STORAGE) && defined(CONFIG_BLK)
+static size_t usb_read_file(const char *file_name)
+{
+ loff_t act_read = 0;
+ struct udevice *dev;
+ int rc;
+
+ usb_stop();
+
+ if (usb_init() < 0) {
+ printf("Error: usb_init failed\n");
+ return 0;
+ }
+
+ /* Try to recognize storage devices immediately */
+ blk_first_device(IF_TYPE_USB, &dev);
+ if (!dev) {
+ printf("Error: USB storage device not found\n");
+ return 0;
+ }
+
+ /* Always load from usb 0 */
+ if (fs_set_blk_dev("usb", "0", FS_TYPE_ANY)) {
+ printf("Error: USB 0 not found\n");
+ return 0;
+ }
+
+ /* Perfrom file read */
+ rc = fs_read(file_name, get_load_addr(), 0, 0, &act_read);
+ if (rc)
+ return 0;
+
+ return act_read;
+}
+
+static int is_usb_active(void)
+{
+ return 1;
+}
+
+#else /* defined(CONFIG_USB_STORAGE) && defined (CONFIG_BLK) */
+static size_t usb_read_file(const char *file_name)
+{
+ return 0;
+}
+
+static int is_usb_active(void)
+{
+ return 0;
+}
+#endif /* defined(CONFIG_USB_STORAGE) && defined (CONFIG_BLK) */
+
+/********************************************************************
+ * Network services
+ ********************************************************************/
+#ifdef CONFIG_CMD_NET
+static size_t tftp_read_file(const char *file_name)
+{
+ /* update global variable load_addr before tftp file from network */
+ load_addr = get_load_addr();
+ return net_loop(TFTPGET);
+}
+
+static int is_tftp_active(void)
+{
+ return 1;
+}
+
+#else
+static size_t tftp_read_file(const char *file_name)
+{
+ return 0;
+}
+
+static int is_tftp_active(void)
+{
+ return 0;
+}
+#endif /* CONFIG_CMD_NET */
+
+enum bubt_devices {
+ BUBT_DEV_NET = 0,
+ BUBT_DEV_USB,
+ BUBT_DEV_MMC,
+ BUBT_DEV_SPI,
+ BUBT_DEV_NAND,
+
+ BUBT_MAX_DEV
+};
+
+struct bubt_dev bubt_devs[BUBT_MAX_DEV] = {
+ {"tftp", tftp_read_file, NULL, is_tftp_active},
+ {"usb", usb_read_file, NULL, is_usb_active},
+ {"mmc", mmc_read_file, mmc_burn_image, is_mmc_active},
+ {"spi", NULL, spi_burn_image, is_spi_active},
+ {"nand", NULL, nand_burn_image, is_nand_active},
+};
+
+static int bubt_write_file(struct bubt_dev *dst, size_t image_size)
+{
+ if (!dst->write) {
+ printf("Error: Write not supported on device %s\n", dst->name);
+ return -ENOTSUPP;
+ }
+
+ return dst->write(image_size);
+}
+
+#if defined(CONFIG_ARMADA_8K)
+u32 do_checksum32(u32 *start, int32_t len)
+{
+ u32 sum = 0;
+ u32 *startp = start;
+
+ do {
+ sum += *startp;
+ startp++;
+ len -= 4;
+ } while (len > 0);
+
+ return sum;
+}
+
+static int check_image_header(void)
+{
+ struct mvebu_image_header *hdr =
+ (struct mvebu_image_header *)get_load_addr();
+ u32 header_len = hdr->prolog_size;
+ u32 checksum;
+ u32 checksum_ref = hdr->prolog_checksum;
+
+ /*
+ * For now compare checksum, and magic. Later we can
+ * verify more stuff on the header like interface type, etc
+ */
+ if (hdr->magic != MAIN_HDR_MAGIC) {
+ printf("ERROR: Bad MAGIC 0x%08x != 0x%08x\n",
+ hdr->magic, MAIN_HDR_MAGIC);
+ return -ENOEXEC;
+ }
+
+ /* The checksum value is discarded from checksum calculation */
+ hdr->prolog_checksum = 0;
+
+ checksum = do_checksum32((u32 *)hdr, header_len);
+ if (checksum != checksum_ref) {
+ printf("Error: Bad Image checksum. 0x%x != 0x%x\n",
+ checksum, checksum_ref);
+ return -ENOEXEC;
+ }
+
+ /* Restore the checksum before writing */
+ hdr->prolog_checksum = checksum_ref;
+ printf("Image checksum...OK!\n");
+
+ return 0;
+}
+#elif defined(CONFIG_ARMADA_3700) /* Armada 3700 */
+static int check_image_header(void)
+{
+ struct common_tim_data *hdr = (struct common_tim_data *)get_load_addr();
+ int image_num;
+ u8 hash_160_output[SHA1_SUM_LEN];
+ u8 hash_256_output[SHA256_SUM_LEN];
+ sha1_context hash1_text;
+ sha256_context hash256_text;
+ u8 *hash_output;
+ u32 hash_algorithm_id;
+ u32 image_size_to_hash;
+ u32 flash_entry_addr;
+ u32 *hash_value;
+ u32 internal_hash[HASH_SUM_LEN];
+ const u8 *buff;
+ u32 num_of_image = hdr->num_images;
+ u32 version = hdr->version;
+ u32 trusted = hdr->trusted;
+
+ /* bubt checksum validation only supports nontrusted images */
+ if (trusted == 1) {
+ printf("bypass image validation, ");
+ printf("only untrusted image is supported now\n");
+ return 0;
+ }
+ /* only supports image version 3.5 and 3.6 */
+ if (version != IMAGE_VERSION_3_5_0 && version != IMAGE_VERSION_3_6_0) {
+ printf("Error: Unsupported Image version = 0x%08x\n", version);
+ return -ENOEXEC;
+ }
+ /* validate images hash value */
+ for (image_num = 0; image_num < num_of_image; image_num++) {
+ struct mvebu_image_info *info =
+ (struct mvebu_image_info *)(get_load_addr() +
+ sizeof(struct common_tim_data) +
+ image_num * sizeof(struct mvebu_image_info));
+ hash_algorithm_id = info->hash_algorithm_id;
+ image_size_to_hash = info->image_size_to_hash;
+ flash_entry_addr = info->flash_entry_addr;
+ hash_value = info->hash;
+ buff = (const u8 *)(get_load_addr() + flash_entry_addr);
+
+ if (image_num == 0) {
+ /*
+ * The first image includes hash values in its content.
+ * For hash calculation, we need to save the original
+ * hash values to a local variable that will be
+ * copied back for comparsion and set all zeros to
+ * the orignal hash values for calculating new value.
+ * First image original format :
+ * x...x (datum1) x...x(orig. hash values) x...x(datum2)
+ * Replaced first image format :
+ * x...x (datum1) 0...0(hash values) x...x(datum2)
+ */
+ memcpy(internal_hash, hash_value,
+ sizeof(internal_hash));
+ memset(hash_value, 0, sizeof(internal_hash));
+ }
+ if (image_size_to_hash == 0) {
+ printf("Warning: Image_%d hash checksum is disabled, ",
+ image_num);
+ printf("skip the image validation.\n");
+ continue;
+ }
+ switch (hash_algorithm_id) {
+ case SHA1_SUM_LEN:
+ sha1_starts(&hash1_text);
+ sha1_update(&hash1_text, buff, image_size_to_hash);
+ sha1_finish(&hash1_text, hash_160_output);
+ hash_output = hash_160_output;
+ break;
+ case SHA256_SUM_LEN:
+ sha256_starts(&hash256_text);
+ sha256_update(&hash256_text, buff, image_size_to_hash);
+ sha256_finish(&hash256_text, hash_256_output);
+ hash_output = hash_256_output;
+ break;
+ default:
+ printf("Error: Unsupported hash_algorithm_id = %d\n",
+ hash_algorithm_id);
+ return -ENOEXEC;
+ }
+ if (image_num == 0)
+ memcpy(hash_value, internal_hash,
+ sizeof(internal_hash));
+ if (memcmp(hash_value, hash_output, hash_algorithm_id) != 0) {
+ printf("Error: Image_%d checksum is not correct\n",
+ image_num);
+ return -ENOEXEC;
+ }
+ }
+ printf("Image checksum...OK!\n");
+
+ return 0;
+}
+
+#else /* Not ARMADA? */
+static int check_image_header(void)
+{
+ printf("bubt cmd does not support this SoC device or family!\n");
+ return -ENOEXEC;
+}
+#endif
+
+static int bubt_verify(size_t image_size)
+{
+ int err;
+
+ /* Check a correct image header exists */
+ err = check_image_header();
+ if (err) {
+ printf("Error: Image header verification failed\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static int bubt_read_file(struct bubt_dev *src)
+{
+ size_t image_size;
+
+ if (!src->read) {
+ printf("Error: Read not supported on device \"%s\"\n",
+ src->name);
+ return 0;
+ }
+
+ image_size = src->read(net_boot_file_name);
+ if (image_size <= 0) {
+ printf("Error: Failed to read file %s from %s\n",
+ net_boot_file_name, src->name);
+ return 0;
+ }
+
+ return image_size;
+}
+
+static int bubt_is_dev_active(struct bubt_dev *dev)
+{
+ if (!dev->active) {
+ printf("Device \"%s\" not supported by U-BOOT image\n",
+ dev->name);
+ return 0;
+ }
+
+ if (!dev->active()) {
+ printf("Device \"%s\" is inactive\n", dev->name);
+ return 0;
+ }
+
+ return 1;
+}
+
+struct bubt_dev *find_bubt_dev(char *dev_name)
+{
+ int dev;
+
+ for (dev = 0; dev < BUBT_MAX_DEV; dev++) {
+ if (strcmp(bubt_devs[dev].name, dev_name) == 0)
+ return &bubt_devs[dev];
+ }
+
+ return 0;
+}
+
+#define DEFAULT_BUBT_SRC "tftp"
+
+#ifndef DEFAULT_BUBT_DST
+#ifdef CONFIG_MVEBU_SPI_BOOT
+#define DEFAULT_BUBT_DST "spi"
+#elif defined(CONFIG_MVEBU_NAND_BOOT)
+#define DEFAULT_BUBT_DST "nand"
+#elif defined(CONFIG_MVEBU_MMC_BOOT)
+#define DEFAULT_BUBT_DST "mmc"
+else
+#define DEFAULT_BUBT_DST "error"
+#endif
+#endif /* DEFAULT_BUBT_DST */
+
+int do_bubt_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ struct bubt_dev *src, *dst;
+ size_t image_size;
+ char src_dev_name[8];
+ char dst_dev_name[8];
+ char *name;
+ int err;
+
+ if (argc < 2)
+ copy_filename(net_boot_file_name,
+ CONFIG_MVEBU_UBOOT_DFLT_NAME,
+ sizeof(net_boot_file_name));
+ else
+ copy_filename(net_boot_file_name, argv[1],
+ sizeof(net_boot_file_name));
+
+ if (argc >= 3) {
+ strncpy(dst_dev_name, argv[2], 8);
+ } else {
+ name = DEFAULT_BUBT_DST;
+ strncpy(dst_dev_name, name, 8);
+ }
+
+ if (argc >= 4)
+ strncpy(src_dev_name, argv[3], 8);
+ else
+ strncpy(src_dev_name, DEFAULT_BUBT_SRC, 8);
+
+ /* Figure out the destination device */
+ dst = find_bubt_dev(dst_dev_name);
+ if (!dst) {
+ printf("Error: Unknown destination \"%s\"\n", dst_dev_name);
+ return -EINVAL;
+ }
+
+ if (!bubt_is_dev_active(dst))
+ return -ENODEV;
+
+ /* Figure out the source device */
+ src = find_bubt_dev(src_dev_name);
+ if (!src) {
+ printf("Error: Unknown source \"%s\"\n", src_dev_name);
+ return 1;
+ }
+
+ if (!bubt_is_dev_active(src))
+ return -ENODEV;
+
+ printf("Burning U-BOOT image \"%s\" from \"%s\" to \"%s\"\n",
+ net_boot_file_name, src->name, dst->name);
+
+ image_size = bubt_read_file(src);
+ if (!image_size)
+ return -EIO;
+
+ err = bubt_verify(image_size);
+ if (err)
+ return err;
+
+ err = bubt_write_file(dst, image_size);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ bubt, 4, 0, do_bubt_cmd,
+ "Burn a u-boot image to flash",
+ "[file-name] [destination [source]]\n"
+ "\t-file-name The image file name to burn. Default = flash-image.bin\n"
+ "\t-destination Flash to burn to [spi, nand, mmc]. Default = active boot device\n"
+ "\t-source The source to load image from [tftp, usb, mmc]. Default = tftp\n"
+ "Examples:\n"
+ "\tbubt - Burn flash-image.bin from tftp to active boot device\n"
+ "\tbubt flash-image-new.bin nand - Burn flash-image-new.bin from tftp to NAND flash\n"
+ "\tbubt backup-flash-image.bin mmc usb - Burn backup-flash-image.bin from usb to MMC\n"
+
+);
diff --git a/configs/mvebu_db-88f7040_defconfig b/configs/mvebu_db-88f7040_defconfig
index f153b9cd77..a2bb97a9ba 100644
--- a/configs/mvebu_db-88f7040_defconfig
+++ b/configs/mvebu_db-88f7040_defconfig
@@ -27,6 +27,7 @@ CONFIG_CMD_EXT4=y
CONFIG_CMD_EXT4_WRITE=y
CONFIG_CMD_FAT=y
CONFIG_CMD_FS_GENERIC=y
+CONFIG_CMD_MVEBU_BUBT=y
CONFIG_BLOCK_CACHE=y
CONFIG_DM_I2C=y
CONFIG_SYS_I2C_MVTWSI=y
@@ -36,6 +37,9 @@ CONFIG_SPI_FLASH_MACRONIX=y
CONFIG_SPI_FLASH_SPANSION=y
CONFIG_SPI_FLASH_STMICRO=y
CONFIG_PHYLIB=y
+CONFIG_PCI=y
+CONFIG_DM_PCI=y
+CONFIG_PCIE_DW_MVEBU=y
CONFIG_MVEBU_COMPHY_SUPPORT=y
# CONFIG_SPL_SERIAL_PRESENT is not set
CONFIG_DEBUG_UART=y
@@ -50,3 +54,5 @@ CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_STORAGE=y
CONFIG_SMBIOS_MANUFACTURER=""
+CONFIG_PINCTRL=y
+CONFIG_HUSH_PARSER=y
diff --git a/configs/mvebu_db-88f8040_defconfig b/configs/mvebu_db-88f8040_defconfig
index 61d58b50c2..1e92e9fa5b 100644
--- a/configs/mvebu_db-88f8040_defconfig
+++ b/configs/mvebu_db-88f8040_defconfig
@@ -27,6 +27,7 @@ CONFIG_CMD_EXT4=y
CONFIG_CMD_EXT4_WRITE=y
CONFIG_CMD_FAT=y
CONFIG_CMD_FS_GENERIC=y
+CONFIG_CMD_MVEBU_BUBT=y
CONFIG_BLOCK_CACHE=y
CONFIG_DM_I2C=y
CONFIG_SYS_I2C_MVTWSI=y
@@ -53,3 +54,5 @@ CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_STORAGE=y
CONFIG_SMBIOS_MANUFACTURER=""
+CONFIG_PINCTRL=y
+CONFIG_HUSH_PARSER=y
diff --git a/doc/device-tree-bindings/pinctrl/marvell,armada-apn806-pinctrl.txt b/doc/device-tree-bindings/pinctrl/marvell,armada-apn806-pinctrl.txt
new file mode 100644
index 0000000000..51f2f2c79c
--- /dev/null
+++ b/doc/device-tree-bindings/pinctrl/marvell,armada-apn806-pinctrl.txt
@@ -0,0 +1,25 @@
+ Functions of Armada APN806 pin controller
+ Function 0x0 for any MPP ID activates GPIO pin mode
+----------------------------------------------------------------------
+MPP# 0x1 0x2 0x3 0x4
+----------------------------------------------------------------------
+0 SDIO_CLK - SPI0_CLK -
+1 SDIO_CMD - SPI0_MISO -
+2 SDIO_D[0] - SPI0_MOSI -
+3 SDIO_D[1] - SPI0_CS0n -
+4 SDIO_D[2] - I2C0_SDA SPI0_CS1n
+5 SDIO_D[3] - I2C0_SCK -
+6 SDIO_DS - - -
+7 SDIO_D[4] - UART1_RXD -
+8 SDIO_D[5] - UART1_TXD -
+9 SDIO_D[6] - SPI0_CS1n -
+10 SDIO_D[7] - - -
+11 - - UART0_TXD -
+12 SDIO_CARD_PW_OFF SDIO_HW_RST - -
+13 - - - -
+14 - - - -
+15 - - - -
+16 - - - -
+17 - - - -
+18 - - - -
+19 - - UART0_RXD -
diff --git a/doc/device-tree-bindings/pinctrl/marvell,armada-cp110-pinctrl.txt b/doc/device-tree-bindings/pinctrl/marvell,armada-cp110-pinctrl.txt
new file mode 100644
index 0000000000..3adcf3aae4
--- /dev/null
+++ b/doc/device-tree-bindings/pinctrl/marvell,armada-cp110-pinctrl.txt
@@ -0,0 +1,270 @@
+ Functions of Armada CP110 pin controller
+ Function 0x0 for any MPP ID activates GPIO pin mode
+ Function 0xc for any MPP ID activates DEBUG_BUS pin mode
+-------------------------------------------------------------------------------
+MPP# 0x1 0x2 0x3 0x4
+-------------------------------------------------------------------------------
+0 DEV_ALE[1] AU_I2SMCLK GE0_RXD[3] TDM_PCLK
+1 DEV_ALE[0] AU_I2SDO_SPDIFO GE0_RXD[2] TDM_DRX
+2 DEV_AD[15] AU_I2SEXTCLK GE0_RXD[1] TDM_DTX
+3 DEV_AD[14] AU_I2SLRCLK GE0_RXD[0] TDM_FSYNC
+4 DEV_AD[13] AU_I2SBCLK GE0_RXCTL TDM_RSTn
+5 DEV_AD[12] AU_I2SDI GE0_RXCLK TDM_INTn
+6 DEV_AD[11] - GE0_TXD[3] SPI0_CSn[2]
+7 DEV_AD[10] - GE0_TXD[2] SPI0_CSn[1]
+8 DEV_AD[9] - GE0_TXD[1] SPI0_CSn[0]
+9 DEV_AD[8] - GE0_TXD[0] SPI0_MOSI
+10 DEV_READYn - GE0_TXCTL SPI0_MISO
+11 DEV_WEn[1] - GE0_TXCLKOUT SPI0_CLK
+12 DEV_CLK_OUT NF_RBn[1] SPI1_CSn[1] GE0_RXCLK
+13 DEV_BURSTn NF_RBn[0] SPI1_MISO GE0_RXCTL
+14 DEV_BOOTCSn DEV_CSn[0] SPI1_CSn[0] SPI0_CSn[3]
+15 DEV_AD[7] - SPI1_MOSI -
+16 DEV_AD[6] - SPI1_CLK -
+17 DEV_AD[5] - - GE0_TXD[3]
+18 DEV_AD[4] - - GE0_TXD[2]
+19 DEV_AD[3] - - GE0_TXD[1]
+20 DEV_AD[2] - - GE0_TXD[0]
+21 DEV_AD[1] - - GE0_TXCTL
+22 DEV_AD[0] - - GE0_TXCLKOUT
+23 DEV_A[1] - - -
+24 DEV_A[0] - - -
+25 DEV_OEn - - - -
+26 DEV_WEn[0] - - -
+27 DEV_CSn[0] SPI1_MISO MSS_GPIO[4] GE0_RXD[3]
+28 DEV_CSn[1] SPI1_CSn[0] MSS_GPIO[5] GE0_RXD[2]
+29 DEV_CSn[2] SPI1_MOSI MSS_GPIO[6] GE0_RXD[1]
+30 DEV_CSn[3] SPI1_CLK MSS_GPIO[7] GE0_RXD[0]
+31 DEV_A[2] - MSS_GPIO[4] -
+32 MII_COL MII_TXERR MSS_SPI_MISO TDM_DRX
+33 MII_TXCLK SDIO_PWR1[0] MSS_SPI_CSn TDM_FSYNC
+34 MII_RXERR SDIO_PWR1[1] MSS_SPI_MOSI TDM_DTX
+35 SATA1_PRESENT_ACTIVEn TWSI1_SDA MSS_SPI_CLK TDM_PCLK
+36 SYNCE2_CLK TWSI1_SCK PTP_CLK SYNCE1_CLK
+37 UART2_RXD TWSI0_SCK PTP_PCLK_OUT TDM_INTn
+38 UART2_TXD TWSI0_SDA PTP_PULSE TDM_RSTn
+39 SDIO_WR_PROTECT - - AU_I2SBCLK PTP_CLK
+40 SDIO_PWR1[1] SYNCE1_CLK MSS_TWSI_SDA AU_I2SDO_SPDIFO
+41 SDIO_PWR1[0] SDIO_BUS_PWR MSS_TWSI_SCK AU_I2SLRCLK
+42 SDIO_V18_EN SDIO_WR_PROTECT SYNCE2_CLK AU_I2SMCLK
+43 SDIO_CARD_DETECT - SYNCE1_CLK AU_I2SEXTCLK
+44 GE1_TXD[2] - - -
+45 GE1_TXD[3] - - -
+46 GE1_TXD[1] - - -
+47 GE1_TXD[0] - - -
+48 GE1_TXCTL_MII_TXEN - - -
+49 GE1_TXCLKOUT MII_CRS - -
+50 GE1_RXCLK MSS_TWSI_SDA - -
+51 GE1_RXD[0] MSS_TWSI_SCK - -
+52 GE1_RXD[1] SYNCE1_CLK - SYNCE2_CLK
+53 GE1_RXD[2] - PTP_CLK -
+54 GE1_RXD[3] SYNCE2_CLK PTP_PCLK_OUT SYNCE1_CLK
+55 GE1_RXCTL_MII_RXDV - PTP_PULSE -
+56 - - - TDM_DRX
+57 - MSS_TWSI_SDA PTP_PCLK_OUT TDM_INTn
+58 - MSS_TWSI_SCK PTP_CLK TDM_RSTn
+59 MSS_GPIO[7] SYNCE2_CLK - TDM_FSYNC
+60 MSS_GPIO[6] - PTP_PULSE TDM_DTX
+61 MSS_GPIO[5] - PTP_CLK TDM_PCLK
+62 MSS_GPIO[4] SYNCE1_CLK PTP_PCLK_OUT -
+
+-------------------------------------------------------------------------------
+MPP# 0x5 0x6 0x7
+-------------------------------------------------------------------------------
+0 - PTP_PULSE MSS_TWSI_SDA
+1 - PTP_CLK MSS_TWSI_SCK
+2 MSS_UART_RXD PTP_PCLK_OUT TWSI1_SCK
+3 MSS_UART_TXD PCIe_RSTOUTn TWSI1_SDA
+4 MSS_UART_RXD UART1_CTS PCIe0_CLKREQ
+5 MSS_UART_TXD UART1_RTS PCIe1_CLKREQ
+6 AU_I2SEXTCLK SATA1_PRESENT_ACTIVEn PCIe2_CLKREQ
+7 SPI1_CSn[1] SATA0_PRESENT_ACTIVEn LED_DATA
+8 SPI1_CSn[0] UART0_CTS LED_STB
+9 SPI1_MOSI - PCIe_RSTOUTn
+10 SPI1_MISO UART0_CTS SATA1_PRESENT_ACTIVEn
+11 SPI1_CLK UART0_RTS LED_CLK
+12 - - -
+13 - - -
+14 AU_I2SEXTCLK SPI0_MISO SATA0_PRESENT_ACTIVEn
+15 - SPI0_MOSI -
+16 - - -
+17 - - -
+18 - - -
+19 - - -
+20 - - -
+21 - - -
+22 - - -
+23 AU_I2SMCLK - -
+24 AU_I2SLRCLK - -
+25 AU_I2SDO_SPDIFO - -
+26 AU_I2SBCLK - -
+27 SPI0_CSn[4] - -
+28 SPI0_CSn[5] PCIe2_CLKREQ PTP_PULSE
+29 SPI0_CSn[6] PCIe1_CLKREQ PTP_CLK
+30 SPI0_CSn[7] PCIe0_CLKREQ PTP_PCLK_OUT
+31 - PCIe_RSTOUTn -
+32 AU_I2SEXTCLK AU_I2SDI GE_MDIO
+33 AU_I2SMCLK SDIO_BUS_PWR -
+34 AU_I2SLRCLK SDIO_WR_PROTECT GE_MDC
+35 AU_I2SDO_SPDIFO SDIO_CARD_DETECT XG_MDIO
+36 AU_I2SBCLK SATA0_PRESENT_ACTIVEn XG_MDC
+37 MSS_TWSI_SCK SATA1_PRESENT_ACTIVEn GE_MDC
+38 MSS_TWSI_SDA SATA0_PRESENT_ACTIVEn GE_MDIO
+39 SPI0_CSn[1] - -
+40 PTP_PCLK_OUT SPI0_CLK UART1_TXD
+41 PTP_PULSE SPI0_MOSI UART1_RXD
+42 MSS_UART_TXD SPI0_MISO UART1_CTS
+43 MSS_UART_RXD SPI0_CSn[0] UART1_RTS
+44 - - UART0_RTS
+45 - - UART0_TXD
+46 - - UART1_RTS
+47 SPI1_CLK - UART1_TXD
+48 SPI1_MOSI - -
+49 SPI1_MISO - UART1_RXD
+50 SPI1_CSn[0] UART2_TXD UART0_RXD
+51 SPI1_CSn[1] UART2_RXD UART0_CTS
+52 SPI1_CSn[2] - UART1_CTS
+53 SPI1_CSn[3] - UART1_RXD
+54 - - -
+55 - - -
+56 AU_I2SDO_SPDIFO SPI0_CLK UART1_RXD
+57 AU_I2SBCLK SPI0_MOSI UART1_TXD
+58 AU_I2SDI SPI0_MISO UART1_CTS
+59 AU_I2SLRCLK SPI0_CSn[0] UART0_CTS
+60 AU_I2SMCLK SPI0_CSn[1] UART0_RTS
+61 AU_I2SEXTCLK SPI0_CSn[2] UART0_TXD
+62 SATA1_PRESENT_ACTIVEn SPI0_CSn[3] UART0_RXD
+
+-------------------------------------------------------------------------------
+MPP# 0x8 0x9 0xA
+-------------------------------------------------------------------------------
+0 UART0_RXD SATA0_PRESENT_ACTIVEn GE_MDIO
+1 UART0_TXD SATA1_PRESENT_ACTIVEn GE_MDC
+2 UART1_RXD SATA0_PRESENT_ACTIVEn XG_MDC
+3 UART1_TXD SATA1_PRESENT_ACTIVEn XG_MDIO
+4 UART3_RXD - GE_MDC
+5 UART3_TXD - GE_MDIO
+6 UART0_RXD PTP_PULSE -
+7 UART0_TXD PTP_CLK -
+8 UART2_RXD PTP_PCLK_OUT SYNCE1_CLK
+9 - - SYNCE2_CLK
+10 - - -
+11 UART2_TXD SATA0_PRESENT_ACTIVEn -
+12 - - -
+13 MSS_SPI_MISO - -
+14 MSS_SPI_CSn - -
+15 MSS_SPI_MOSI - -
+16 MSS_SPI_CLK - -
+17 - - -
+18 - - -
+19 - - -
+20 - - -
+21 - - -
+22 - - -
+23 - - -
+24 - - -
+25 - - -
+26 - - -
+27 GE_MDIO SATA0_PRESENT_ACTIVEn UART0_RTS
+28 GE_MDC SATA1_PRESENT_ACTIVEn UART0_CTS
+29 MSS_TWSI_SDA SATA0_PRESENT_ACTIVEn UART0_RXD
+30 MSS_TWSI_SCK SATA1_PRESENT_ACTIVEn UART0_TXD
+31 GE_MDC - -
+32 SDIO_V18_EN PCIe1_CLKREQ MSS_GPIO[0]
+33 XG_MDIO PCIe2_CLKREQ MSS_GPIO[1]
+34 - PCIe0_CLKREQ MSS_GPIO[2]
+35 GE_MDIO PCIe_RSTOUTn MSS_GPIO[3]
+36 GE_MDC PCIe2_CLKREQ MSS_GPIO[5]
+37 XG_MDC PCIe1_CLKREQ MSS_GPIO[6]
+38 XG_MDIO AU_I2SEXTCLK MSS_GPIO[7]
+39 SATA1_PRESENT_ACTIVEn MSS_GPIO[0]
+40 GE_MDIO SATA0_PRESENT_ACTIVEn MSS_GPIO[1]
+41 GE_MDC SATA1_PRESENT_ACTIVEn MSS_GPIO[2]
+42 XG_MDC SATA0_PRESENT_ACTIVEn MSS_GPIO[4]
+43 XG_MDIO SATA1_PRESENT_ACTIVEn MSS_GPIO[5]
+44 - - -
+45 - PCIe_RSTOUTn -
+46 - - -
+47 GE_MDC CLKOUT -
+48 XG_MDC - -
+49 GE_MDIO PCIe0_CLKREQ SDIO_V18_EN
+50 XG_MDIO - SDIO_PWR1[1]
+51 - - SDIO_PWR1[0]
+52 LED_CLK PCIe_RSTOUTn PCIe0_CLKREQ
+53 LED_STB - -
+54 LED_DATA - SDIO_HW_RST
+55 - - SDIO_LED
+56 - SATA1_PRESENT_ACTIVEn -
+57 - SATA0_PRESENT_ACTIVEn -
+58 LED_CLK - -
+59 LED_STB UART1_TXD -
+60 LED_DATA UART1_RXD -
+61 UART2_TXD SATA1_PRESENT_ACTIVEn GE_MDIO
+62 UART2_RXD SATA0_PRESENT_ACTIVEn GE_MDC
+
+-------------------------------------------------------------------------------
+MPP# 0xB 0xD 0xE
+-------------------------------------------------------------------------------
+0 - - -
+1 - - -
+2 - - -
+3 - - -
+4 - - -
+5 - - -
+6 - - -
+7 - - -
+8 - - -
+9 - - -
+10 - - -
+11 - CLKOUT_MPP_11 -
+12 - - -
+13 - - -
+14 - - -
+15 PTP_PULSE_CP2CP SAR_IN[5] -
+16 - SAR_IN[3] -
+17 - SAR_IN[6] -
+18 PTP_CLK_CP2CP SAR_IN[11] -
+19 WAKEUP_OUT_CP2CP SAR_IN[7] -
+20 - SAR_IN[9] -
+21 SEI_IN_CP2CP SAR_IN[8] -
+22 WAKEUP_IN_CP2CP SAR_IN[10] -
+23 LINK_RD_IN_CP2CP SAR_IN[4] -
+24 - - -
+25 - CLKOUT_MPP_25 -
+26 - SAR_IN[0] -
+27 REI_IN_CP2CP SAR_IN[1] -
+28 LED_DATA SAR_IN[2] -
+29 LED_STB AVS_FB_IN_CP2CP -
+30 LED_CLK SAR_IN[13] -
+31 - - -
+32 - SAR_CP2CP_OUT[0] -
+33 - SAR_CP2CP_OUT[1] -
+34 - SAR_CP2CP_OUT[2] -
+35 - SAR_CP2CP_OUT[3] -
+36 - CLKIN -
+37 LINK_RD_OUT_CP2CP SAR_CP2CP_OUT[4] -
+38 PTP_PULSE_CP2CP SAR_CP2CP_OUT[5] -
+39 - AVS_FB_OUT_CP2CP -
+40 - - -
+41 REI_OUT_CP2CP - -
+42 - SAR_CP2CP_OUT[9] -
+43 WAKEUP_OUT_CP2CP SAR_CP2CP_OUT[10] -
+44 PTP_CLK_CP2CP SAR_CP2CP_OUT[11] -
+45 - SAR_CP2CP_OUT[6] -
+46 - SAR_CP2CP_OUT[13] -
+47 - - -
+48 WAKEUP_IN_CP2CP SAR_CP2CP_OUT[7] -
+49 SEI_OUT_CP2CP SAR_CP2CP_OUT[8] -
+50 - - -
+51 - - -
+52 - - -
+53 SDIO_LED - -
+54 SDIO_WR_PROTECT - -
+55 SDIO_CARD_DETECT - -
+56 - - SDIO0_CLK
+57 - - SDIO0_CMD
+58 - - SDIO0_D[0]
+59 - - SDIO0_D[1]
+60 - - SDIO0_D[2]
+61 - - SDIO0_D[3]
+62 - - -
diff --git a/doc/device-tree-bindings/pinctrl/marvell,mvebu-pinctrl.txt b/doc/device-tree-bindings/pinctrl/marvell,mvebu-pinctrl.txt
new file mode 100644
index 0000000000..5f86c0a00b
--- /dev/null
+++ b/doc/device-tree-bindings/pinctrl/marvell,mvebu-pinctrl.txt
@@ -0,0 +1,113 @@
+The pinctrl driver enables Marvell Armada 8K SoCs to configure the multi-purpose
+pins (mpp) to a specific function.
+A Marvell SoC pin configuration node is a node of a group of pins which can
+be used for a specific device or function. Each node requires one or more
+mpp pins or group of pins and a mpp function common to all pins.
+
+Required properties for the pinctrl driver:
+- compatible: "marvell,mvebu-pinctrl",
+ "marvell,armada-ap806-pinctrl",
+ "marvell,a70x0-pinctrl",
+ "marvell,a80x0-cp0-pinctrl",
+ "marvell,a80x0-cp1-pinctrl"
+- bank-name: A string defining the pinc controller bank name
+- reg: A pair of values defining the pin controller base address
+ and the address space
+- pin-count: Numeric value defining the amount of multi purpose pins
+ included in this bank
+- max-func: Numeric value defining the maximum function value for
+ pins in this bank
+- pin-func: Array of pin function values for every pin in the bank.
+ When the function value for a specific pin equal 0xFF,
+ the pin configuration is skipped and a default function
+ value is used for this pin.
+
+The A8K is a hybrid SoC that contains several silicon dies interconnected in
+a single package. Each such die may have a separate pin controller.
+
+Example:
+/ {
+ ap806 {
+ config-space {
+ pinctl: pinctl@6F4000 {
+ compatible = "marvell,mvebu-pinctrl",
+ "marvell,armada-ap806-pinctrl";
+ bank-name ="apn-806";
+ reg = <0x6F4000 0x10>;
+ pin-count = <20>;
+ max-func = <3>;
+ /* MPP Bus:
+ * SPI0 [0-3]
+ * I2C0 [4-5]
+ * UART0 [11,19]
+ */
+ /* 0 1 2 3 4 5 6 7 8 9 */
+ pin-func = < 3 3 3 3 3 3 0 0 0 0
+ 0 3 0 0 0 0 0 0 0 3>;
+ };
+ };
+ };
+
+ cp110-master {
+ config-space {
+ cpm_pinctl: pinctl@44000 {
+ compatible = "marvell,mvebu-pinctrl",
+ "marvell,a70x0-pinctrl",
+ "marvell,a80x0-cp0-pinctrl";
+ bank-name ="cp0-110";
+ reg = <0x440000 0x20>;
+ pin-count = <63>;
+ max-func = <0xf>;
+ /* MPP Bus:
+ * [0-31] = 0xff: Keep default CP0_shared_pins:
+ * [11] CLKOUT_MPP_11 (out)
+ * [23] LINK_RD_IN_CP2CP (in)
+ * [25] CLKOUT_MPP_25 (out)
+ * [29] AVS_FB_IN_CP2CP (in)
+ * [32,34] SMI
+ * [31] GPIO: push button/Wake
+ * [35-36] GPIO
+ * [37-38] I2C
+ * [40-41] SATA[0/1]_PRESENT_ACTIVEn
+ * [42-43] XSMI
+ * [44-55] RGMII1
+ * [56-62] SD
+ */
+ /* 0 1 2 3 4 5 6 7 8 9 */
+ pin-func = < 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
+ 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
+ 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
+ 0xff 0 7 0 7 0 0 2 2 0
+ 0 0 8 8 1 1 1 1 1 1
+ 1 1 1 1 1 1 0xE 0xE 0xE 0xE
+ 0xE 0xE 0xE>;
+ };
+ };
+ };
+
+ cp110-slave {
+ config-space {
+ cps_pinctl: pinctl@44000 {
+ compatible = "marvell,mvebu-pinctrl",
+ "marvell,a80x0-cp1-pinctrl";
+ bank-name ="cp1-110";
+ reg = <0x440000 0x20>;
+ pin-count = <63>;
+ max-func = <0xf>;
+ /* MPP Bus:
+ * [0-11] RGMII0
+ * [27,31] GE_MDIO/MDC
+ * [32-62] = 0xff: Keep default CP1_shared_pins:
+ */
+ /* 0 1 2 3 4 5 6 7 8 9 */
+ pin-func = < 0x3 0x3 0x3 0x3 0x3 0x3 0x3 0x3 0x3 0x3
+ 0x3 0x3 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
+ 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0x8 0xff 0xff
+ 0xff 0x8 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
+ 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
+ 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
+ 0xff 0xff 0xff>;
+ };
+ };
+ };
+}
diff --git a/doc/mvebu/cmd/bubt.txt b/doc/mvebu/cmd/bubt.txt
new file mode 100644
index 0000000000..6f9f525936
--- /dev/null
+++ b/doc/mvebu/cmd/bubt.txt
@@ -0,0 +1,64 @@
+BUBT (Burn ATF) command
+--------------------------
+Bubt command is used to burn a new ATF image to flash device.
+
+The bubt command gets the following parameters: ATF file name, destination device and source device.
+bubt [file-name] [destination [source]]
+ - file-name Image file name to burn. default = flash-image.bin
+ - destination Flash to burn to [spi, nand, mmc]. default = active flash
+ - source Source to load image from [tftp, usb]. default = tftp
+
+Examples:
+ bubt - Burn flash-image.bin from tftp to active flash
+ bubt latest-spi.bin nand - Burn latest-spi.bin from tftp to NAND flash
+
+Notes:
+- For the TFTP interface set serverip and ipaddr.
+- To burn image to SD/eMMC device, the target is defined
+ by parameters CONFIG_SYS_MMC_ENV_DEV and CONFIG_SYS_MMC_ENV_PART.
+
+Bubt command details (burn image step by-step)
+----------------------------------------------
+This section describes bubt command flow:
+
+1. Fetch the requested ATF image from an available interface (USB/SD/SATA/XDB, etc.)
+ into the DRAM, and place it at <load_address>
+ Example: when using the FAT file system on USB flash device:
+ # usb reset
+ # fatls usb 0 (see files in device)
+ # fatload usb 0 <load_address> <file_name>
+
+2. Erase the target device:
+ - NAND: # nand erase 0 100000
+ - SPI: # sf probe 0
+ # sf erase 0 100000
+ - SD/eMMC: # mmc dev <dev_id> <boot_partition>
+
+Notes:
+- The eMMC has 2 boot partitions (BOOT0 and BOOT1) and a user data partition (DATA).
+ The boot partitions are numbered as partition 1 and 2 in MMC driver.
+ Number 0 is used for user data partition and should not be utilized for storing
+ boot images and U-Boot environment in RAW mode since it will break file system
+ structures usually located here.
+ The default boot partition is BOOT0. It is selected by the following parameter:
+ CONFIG_SYS_MMC_ENV_PART=1
+ Valid values for this parameter are 1 for BOOT0 and 2 for BOOT1.
+ Please never use partition number 0 here!
+ The eMMC has 2 boot partitions (BOOT0 and BOOT1) and a user data partition (DATA).
+ The boot partitions are numbered as partition 1 and 2 in MMC driver.
+ Number 0 is used for user data partition and should not be utilized for storing
+ boot images and U-Boot environment in RAW mode since it will break file system
+ structures usually located here.
+ The default boot partition is BOOT0. It is selected by the following parameter:
+ CONFIG_SYS_MMC_ENV_PART=1
+ Valid values for this parameter are 1 for BOOT0 and 2 for BOOT1.
+ Please never use partition number 0 here!
+- The partition number is ignored if the target device is SD card.
+- The boot image offset starts at block 0 for eMMC and block 1 for SD devices.
+ The block 0 on SD devices is left for MBR storage.
+
+3. Write the ATF image:
+ - NAND: # nand write <load_address> 0 <ATF Size>
+ - SPI: # sf write <load_address> 0 <ATF Size>
+ - SD/eMMC: # mmc write <load_address> [0|1] <ATF Size>/<block_size>
+
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 12be3cfe0b..efcb4c0003 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -181,5 +181,6 @@ source "drivers/pinctrl/meson/Kconfig"
source "drivers/pinctrl/nxp/Kconfig"
source "drivers/pinctrl/uniphier/Kconfig"
source "drivers/pinctrl/exynos/Kconfig"
+source "drivers/pinctrl/mvebu/Kconfig"
endmenu
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index f28b5c18f6..512112af64 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -15,3 +15,4 @@ obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/
obj-$(CONFIG_PIC32_PINCTRL) += pinctrl_pic32.o
obj-$(CONFIG_PINCTRL_EXYNOS) += exynos/
obj-$(CONFIG_PINCTRL_MESON) += meson/
+obj-$(CONFIG_PINCTRL_MVEBU) += mvebu/
diff --git a/drivers/pinctrl/mvebu/Kconfig b/drivers/pinctrl/mvebu/Kconfig
new file mode 100644
index 0000000000..cf9c299f13
--- /dev/null
+++ b/drivers/pinctrl/mvebu/Kconfig
@@ -0,0 +1,7 @@
+config PINCTRL_MVEBU
+ depends on ARCH_MVEBU
+ bool
+ default y
+ help
+ Support pin multiplexing and pin configuration control on
+ Marvell's Armada-8K SoC.
diff --git a/drivers/pinctrl/mvebu/Makefile b/drivers/pinctrl/mvebu/Makefile
new file mode 100644
index 0000000000..f4f78640b9
--- /dev/null
+++ b/drivers/pinctrl/mvebu/Makefile
@@ -0,0 +1,7 @@
+#
+# Copyright (C) 2016 Marvell International Ltd.
+#
+# SPDX-License-Identifier: GPL-2.0
+# https://spdx.org/licenses
+
+obj-$(CONFIG_PINCTRL_MVEBU) += pinctrl-mvebu.o
diff --git a/drivers/pinctrl/mvebu/pinctrl-mvebu.c b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
new file mode 100644
index 0000000000..b07763931f
--- /dev/null
+++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2016 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ * https://spdx.org/licenses
+ */
+
+#include <common.h>
+#include <config.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <dm/pinctrl.h>
+#include <dm/root.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/arch-armada8k/soc-info.h>
+#include "pinctrl-mvebu.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * mvebu_pinctrl_set_state: configure pin functions.
+ * @dev: the pinctrl device to be configured.
+ * @config: the state to be configured.
+ * @return: 0 in success
+ */
+int mvebu_pinctrl_set_state(struct udevice *dev, struct udevice *config)
+{
+ const void *blob = gd->fdt_blob;
+ int node = config->of_offset;
+ struct mvebu_pinctrl_priv *priv;
+ u32 pin_arr[MVEBU_MAX_PINS_PER_BANK];
+ u32 function;
+ int i, pin_count;
+
+ priv = dev_get_priv(dev);
+
+ pin_count = fdtdec_get_int_array_count(blob, node,
+ "marvell,pins",
+ pin_arr,
+ MVEBU_MAX_PINS_PER_BANK);
+ if (pin_count <= 0) {
+ debug("Failed reading pins array for pinconfig %s (%d)\n",
+ config->name, pin_count);
+ return -EINVAL;
+ }
+
+ function = fdtdec_get_int(blob, node, "marvell,function", 0xff);
+
+ for (i = 0; i < pin_count; i++) {
+ int reg_offset;
+ int field_offset;
+ int pin = pin_arr[i];
+
+ if (function > priv->max_func) {
+ debug("Illegal function %d for pinconfig %s\n",
+ function, config->name);
+ return -EINVAL;
+ }
+
+ /* Calculate register address and bit in register */
+ reg_offset = priv->reg_direction * 4 *
+ (pin >> (PIN_REG_SHIFT));
+ field_offset = (BITS_PER_PIN) * (pin & PIN_FIELD_MASK);
+
+ clrsetbits_le32(priv->base_reg + reg_offset,
+ PIN_FUNC_MASK << field_offset,
+ (function & PIN_FUNC_MASK) << field_offset);
+ }
+
+ return 0;
+}
+
+/*
+ * mvebu_pinctrl_set_state_all: configure the entire bank pin functions.
+ * @dev: the pinctrl device to be configured.
+ * @config: the state to be configured.
+ * @return: 0 in success
+ */
+static int mvebu_pinctrl_set_state_all(struct udevice *dev,
+ struct udevice *config)
+{
+ const void *blob = gd->fdt_blob;
+ int node = config->of_offset;
+ struct mvebu_pinctrl_priv *priv;
+ u32 func_arr[MVEBU_MAX_PINS_PER_BANK];
+ int pin, err;
+
+ priv = dev_get_priv(dev);
+
+ err = fdtdec_get_int_array(blob, node, "pin-func",
+ func_arr, priv->pin_cnt);
+ if (err) {
+ debug("Failed reading pin functions for bank %s\n",
+ priv->bank_name);
+ return -EINVAL;
+ }
+
+ for (pin = 0; pin < priv->pin_cnt; pin++) {
+ int reg_offset;
+ int field_offset;
+ u32 func = func_arr[pin];
+
+ /* Bypass pins with function 0xFF */
+ if (func == 0xff) {
+ debug("Warning: pin %d value is not modified ", pin);
+ debug("(kept as default)\n");
+ continue;
+ } else if (func > priv->max_func) {
+ debug("Illegal function %d for pin %d\n", func, pin);
+ return -EINVAL;
+ }
+
+ /* Calculate register address and bit in register */
+ reg_offset = priv->reg_direction * 4 *
+ (pin >> (PIN_REG_SHIFT));
+ field_offset = (BITS_PER_PIN) * (pin & PIN_FIELD_MASK);
+
+ clrsetbits_le32(priv->base_reg + reg_offset,
+ PIN_FUNC_MASK << field_offset,
+ (func & PIN_FUNC_MASK) << field_offset);
+ }
+
+ return 0;
+}
+
+int mvebu_pinctl_probe(struct udevice *dev)
+{
+ const void *blob = gd->fdt_blob;
+ int node = dev->of_offset;
+ struct mvebu_pinctrl_priv *priv;
+
+ priv = dev_get_priv(dev);
+ if (!priv) {
+ debug("%s: Failed to get private\n", __func__);
+ return -EINVAL;
+ }
+
+ priv->base_reg = dev_get_addr_ptr(dev);
+ if (priv->base_reg == (void *)FDT_ADDR_T_NONE) {
+ debug("%s: Failed to get base address\n", __func__);
+ return -EINVAL;
+ }
+
+ priv->pin_cnt = fdtdec_get_int(blob, node, "pin-count",
+ MVEBU_MAX_PINS_PER_BANK);
+ priv->max_func = fdtdec_get_int(blob, node, "max-func",
+ MVEBU_MAX_FUNC);
+ priv->bank_name = fdt_getprop(blob, node, "bank-name", NULL);
+
+ priv->reg_direction = 1;
+ if (fdtdec_get_bool(blob, node, "reverse-reg"))
+ priv->reg_direction = -1;
+
+ return mvebu_pinctrl_set_state_all(dev, dev);
+}
+
+static struct pinctrl_ops mvebu_pinctrl_ops = {
+ .set_state = mvebu_pinctrl_set_state
+};
+
+static const struct udevice_id mvebu_pinctrl_ids[] = {
+ { .compatible = "marvell,mvebu-pinctrl" },
+ { .compatible = "marvell,armada-ap806-pinctrl" },
+ { .compatible = "marvell,a70x0-pinctrl" },
+ { .compatible = "marvell,a80x0-cp0-pinctrl" },
+ { .compatible = "marvell,a80x0-cp1-pinctrl" },
+ { }
+};
+
+U_BOOT_DRIVER(pinctrl_mvebu) = {
+ .name = "mvebu_pinctrl",
+ .id = UCLASS_PINCTRL,
+ .of_match = mvebu_pinctrl_ids,
+ .priv_auto_alloc_size = sizeof(struct mvebu_pinctrl_priv),
+ .ops = &mvebu_pinctrl_ops,
+ .probe = mvebu_pinctl_probe
+};
diff --git a/drivers/pinctrl/mvebu/pinctrl-mvebu.h b/drivers/pinctrl/mvebu/pinctrl-mvebu.h
new file mode 100644
index 0000000000..1a1d3ef5e0
--- /dev/null
+++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ * https://spdx.org/licenses
+ */
+
+ #ifndef __PINCTRL_MVEBU_H_
+ #define __PINCTRL_MVEBU_H_
+
+ #define MVEBU_MAX_PINCTL_BANKS 4
+ #define MVEBU_MAX_PINS_PER_BANK 100
+ #define MVEBU_MAX_FUNC 0xF
+
+/*
+ * struct mvebu_pin_bank_data: mvebu-pinctrl bank data
+ * @base_reg: controller base address for this bank
+ * @pin_cnt: number of pins included in this bank
+ * @max_func: maximum configurable function value for pins in this bank
+ * @reg_direction:
+ * @bank_name: the pin's bank name
+ */
+struct mvebu_pinctrl_priv {
+ void *base_reg;
+ uint pin_cnt;
+ uint max_func;
+ int reg_direction;
+ const char *bank_name;
+};
+
+#endif /* __PINCTRL_MVEBU_H_ */