summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2014-08-07 06:14:59 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2014-08-07 06:14:59 +0200
commitf1ee4e8b73a356278056666da8d0c6b5aa53088d (patch)
tree160f8440f19bd0702aed7323900e7412ea11ff0f
parentc138893990013fa9f3008325fdf4fd8ac0628ba2 (diff)
parent11b34ab22f4072db0cdbf605d6ffbd472618175b (diff)
downloadbarebox-f1ee4e8b73a356278056666da8d0c6b5aa53088d.tar.gz
barebox-f1ee4e8b73a356278056666da8d0c6b5aa53088d.tar.xz
Merge branch 'for-next/marvell'
-rw-r--r--arch/arm/Kconfig1
-rw-r--r--arch/arm/cpu/dtb.c1
-rw-r--r--arch/arm/dts/armada-370-mirabox-bb.dts3
-rw-r--r--arch/arm/dts/armada-xp-openblocks-ax3-4-bb.dts4
-rw-r--r--arch/arm/mach-mvebu/Kconfig2
-rw-r--r--arch/arm/mach-mvebu/armada-370-xp.c11
-rw-r--r--arch/arm/mach-mvebu/common.c59
-rw-r--r--arch/arm/mach-mvebu/dove.c6
-rw-r--r--arch/arm/mach-mvebu/include/mach/armada-370-xp-regs.h2
-rw-r--r--arch/arm/mach-mvebu/include/mach/common.h2
-rw-r--r--arch/arm/mach-mvebu/kirkwood.c5
-rw-r--r--drivers/bus/mvebu-mbus.c97
-rw-r--r--drivers/of/Kconfig6
-rw-r--r--drivers/of/Makefile1
-rw-r--r--drivers/of/of_pci.c27
-rw-r--r--drivers/pci/Kconfig6
-rw-r--r--drivers/pci/Makefile2
-rw-r--r--drivers/pci/pci-mvebu-phy.c208
-rw-r--r--drivers/pci/pci-mvebu.c446
-rw-r--r--drivers/pci/pci-mvebu.h37
-rw-r--r--drivers/pci/pci.c28
-rw-r--r--drivers/pinctrl/mvebu/Kconfig8
-rw-r--r--drivers/pinctrl/mvebu/Makefile2
-rw-r--r--drivers/pinctrl/mvebu/armada-370.c416
-rw-r--r--drivers/pinctrl/mvebu/armada-xp.c403
-rw-r--r--include/linux/mbus.h2
-rw-r--r--include/linux/pci.h12
-rw-r--r--include/of_pci.h17
28 files changed, 1786 insertions, 28 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 2d024dc380..a3208d27e4 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -102,6 +102,7 @@ config ARCH_MVEBU
select GPIOLIB
select HAS_DEBUG_LL
select HAVE_PBL_MULTI_IMAGES
+ select HW_HAS_PCI
select MVEBU_MBUS
select OFTREE
select OF_ADDRESS_PCI
diff --git a/arch/arm/cpu/dtb.c b/arch/arm/cpu/dtb.c
index abc3ccb4c0..ae4ff2a9ad 100644
--- a/arch/arm/cpu/dtb.c
+++ b/arch/arm/cpu/dtb.c
@@ -50,6 +50,7 @@ static int of_arm_init(void)
root = of_unflatten_dtb(fdt);
if (root) {
of_set_root_node(root);
+ of_fix_tree(root);
if (IS_ENABLED(CONFIG_OFDEVICE))
of_probe();
}
diff --git a/arch/arm/dts/armada-370-mirabox-bb.dts b/arch/arm/dts/armada-370-mirabox-bb.dts
index de37a75bb9..315678151a 100644
--- a/arch/arm/dts/armada-370-mirabox-bb.dts
+++ b/arch/arm/dts/armada-370-mirabox-bb.dts
@@ -11,9 +11,6 @@
};
soc {
- ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
- MBUS_ID(0x01, 0xe0) 0 0xfff00000 0x100000>;
-
internal-regs {
gpio_leds {
green_pwr_led {
diff --git a/arch/arm/dts/armada-xp-openblocks-ax3-4-bb.dts b/arch/arm/dts/armada-xp-openblocks-ax3-4-bb.dts
index 611d72707f..e88f1dc781 100644
--- a/arch/arm/dts/armada-xp-openblocks-ax3-4-bb.dts
+++ b/arch/arm/dts/armada-xp-openblocks-ax3-4-bb.dts
@@ -11,10 +11,6 @@
};
soc {
- ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000
- MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
- MBUS_ID(0x01, 0x2f) 0 0 0xf0000000 0x8000000>;
-
internal-regs {
gpio_leds {
red_led {
diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig
index 18f61f74f9..131f3a67ea 100644
--- a/arch/arm/mach-mvebu/Kconfig
+++ b/arch/arm/mach-mvebu/Kconfig
@@ -14,11 +14,13 @@ config ARCH_ARMADA_370
bool "Armada 370"
select CPU_V7
select CLOCKSOURCE_MVEBU
+ select PINCTRL_ARMADA_370
config ARCH_ARMADA_XP
bool "Armada XP"
select CPU_V7
select CLOCKSOURCE_MVEBU
+ select PINCTRL_ARMADA_XP
config ARCH_DOVE
bool "Dove 88AP510"
diff --git a/arch/arm/mach-mvebu/armada-370-xp.c b/arch/arm/mach-mvebu/armada-370-xp.c
index e416a38765..f2b991e5a7 100644
--- a/arch/arm/mach-mvebu/armada-370-xp.c
+++ b/arch/arm/mach-mvebu/armada-370-xp.c
@@ -18,6 +18,7 @@
#include <init.h>
#include <io.h>
#include <asm/memory.h>
+#include <linux/mbus.h>
#include <mach/armada-370-xp-regs.h>
static inline void armada_370_xp_memory_find(unsigned long *phys_base,
@@ -46,12 +47,20 @@ static inline void armada_370_xp_memory_find(unsigned long *phys_base,
static int armada_370_xp_init_soc(void)
{
unsigned long phys_base, phys_size;
+ u32 reg;
barebox_set_model("Marvell Armada 370/XP");
barebox_set_hostname("armada");
+ /* Disable MBUS error propagation */
+ reg = readl(ARMADA_370_XP_FABRIC_BASE);
+ reg &= ~BIT(8);
+ writel(reg, ARMADA_370_XP_FABRIC_BASE);
+
armada_370_xp_memory_find(&phys_base, &phys_size);
- arm_add_mem_device("ram0", phys_base, phys_size);
+
+ mvebu_set_memory(phys_base, phys_size);
+ mvebu_mbus_add_range(0xf0, 0x01, MVEBU_REMAP_INT_REG_BASE);
return 0;
}
diff --git a/arch/arm/mach-mvebu/common.c b/arch/arm/mach-mvebu/common.c
index b054bf5aff..ac4b332e01 100644
--- a/arch/arm/mach-mvebu/common.c
+++ b/arch/arm/mach-mvebu/common.c
@@ -79,3 +79,62 @@ static int mvebu_soc_id_init(void)
return 0;
}
postcore_initcall(mvebu_soc_id_init);
+
+static u64 mvebu_mem[2];
+
+void mvebu_set_memory(u64 phys_base, u64 phys_size)
+{
+ mvebu_mem[0] = phys_base;
+ mvebu_mem[1] = phys_size;
+}
+
+/*
+ * Memory size is set up by BootROM and can be read from SoC's ram controller
+ * registers. Fixup provided DTs to reflect accessible amount of directly
+ * attached RAM. Removable RAM, e.g. SODIMM, should be added by a per-board
+ * fixup.
+ */
+static int mvebu_memory_of_fixup(struct device_node *root, void *context)
+{
+ struct device_node *np;
+ __be32 reg[4];
+ int na, ns;
+
+ /* bail out on zero-sized mem */
+ if (!mvebu_mem[1])
+ return -ENODEV;
+
+ np = of_find_node_by_path("/memory");
+ if (!np)
+ np = of_create_node(root, "/memory");
+ if (!np)
+ return -EINVAL;
+
+ na = of_n_addr_cells(np);
+ ns = of_n_size_cells(np);
+
+ if (na == 2) {
+ reg[0] = cpu_to_be32(mvebu_mem[0] >> 32);
+ reg[1] = cpu_to_be32(mvebu_mem[0] & 0xffffffff);
+ } else {
+ reg[0] = cpu_to_be32(mvebu_mem[0] & 0xffffffff);
+ }
+
+ if (ns == 2) {
+ reg[2] = cpu_to_be32(mvebu_mem[1] >> 32);
+ reg[3] = cpu_to_be32(mvebu_mem[1] & 0xffffffff);
+ } else {
+ reg[1] = cpu_to_be32(mvebu_mem[1] & 0xffffffff);
+ }
+
+ if (of_set_property(np, "device_type", "memory", sizeof("memory"), 1) ||
+ of_set_property(np, "reg", reg, sizeof(u32) * (na + ns), 1))
+ pr_err("Unable to fixup memory node\n");
+
+ return 0;
+}
+
+static int mvebu_memory_fixup_register(void) {
+ return of_register_fixup(mvebu_memory_of_fixup, NULL);
+}
+pure_initcall(mvebu_memory_fixup_register);
diff --git a/arch/arm/mach-mvebu/dove.c b/arch/arm/mach-mvebu/dove.c
index bcbf4b8ad7..69c6436b24 100644
--- a/arch/arm/mach-mvebu/dove.c
+++ b/arch/arm/mach-mvebu/dove.c
@@ -18,6 +18,7 @@
#include <init.h>
#include <io.h>
#include <asm/memory.h>
+#include <linux/mbus.h>
#include <mach/dove-regs.h>
static inline void dove_remap_mc_regs(void)
@@ -76,7 +77,10 @@ static int dove_init_soc(void)
dove_remap_mc_regs();
dove_memory_find(&phys_base, &phys_size);
- arm_add_mem_device("ram0", phys_base, phys_size);
+
+ mvebu_set_memory(phys_base, phys_size);
+ mvebu_mbus_add_range(0xf0, 0x01, MVEBU_REMAP_INT_REG_BASE);
+ mvebu_mbus_add_range(0xf0, 0x02, DOVE_REMAP_MC_REGS);
return 0;
}
diff --git a/arch/arm/mach-mvebu/include/mach/armada-370-xp-regs.h b/arch/arm/mach-mvebu/include/mach/armada-370-xp-regs.h
index 5fd16e5733..ccc687c03b 100644
--- a/arch/arm/mach-mvebu/include/mach/armada-370-xp-regs.h
+++ b/arch/arm/mach-mvebu/include/mach/armada-370-xp-regs.h
@@ -42,6 +42,8 @@
#define DDR_SIZE_CS_SHIFT 2
#define DDR_SIZE_MASK 0xff000000
+#define ARMADA_370_XP_FABRIC_BASE (ARMADA_370_XP_INT_REGS_BASE + 0x20200)
+
#define ARMADA_370_XP_TIMER_BASE (ARMADA_370_XP_INT_REGS_BASE + 0x20300)
#endif /* __MACH_MVEBU_DOVE_REGS_H */
diff --git a/arch/arm/mach-mvebu/include/mach/common.h b/arch/arm/mach-mvebu/include/mach/common.h
index 3cc1bf71c0..9f6118e4ec 100644
--- a/arch/arm/mach-mvebu/include/mach/common.h
+++ b/arch/arm/mach-mvebu/include/mach/common.h
@@ -20,4 +20,6 @@
#define MVEBU_REMAP_INT_REG_BASE 0xf1000000
+void mvebu_set_memory(u64 phys_base, u64 phys_size);
+
#endif
diff --git a/arch/arm/mach-mvebu/kirkwood.c b/arch/arm/mach-mvebu/kirkwood.c
index fe9ca9cbe4..c114bdb360 100644
--- a/arch/arm/mach-mvebu/kirkwood.c
+++ b/arch/arm/mach-mvebu/kirkwood.c
@@ -17,6 +17,7 @@
#include <init.h>
#include <io.h>
#include <asm/memory.h>
+#include <linux/mbus.h>
#include <mach/kirkwood-regs.h>
static inline void kirkwood_memory_find(unsigned long *phys_base,
@@ -50,7 +51,9 @@ static int kirkwood_init_soc(void)
barebox_set_hostname("kirkwood");
kirkwood_memory_find(&phys_base, &phys_size);
- arm_add_mem_device("ram0", phys_base, phys_size);
+
+ mvebu_set_memory(phys_base, phys_size);
+ mvebu_mbus_add_range(0xf0, 0x01, MVEBU_REMAP_INT_REG_BASE);
return 0;
}
diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c
index 11e3777a60..b7f78367d4 100644
--- a/drivers/bus/mvebu-mbus.c
+++ b/drivers/bus/mvebu-mbus.c
@@ -53,6 +53,7 @@
#include <common.h>
#include <init.h>
#include <io.h>
+#include <malloc.h>
#include <of.h>
#include <of_address.h>
#include <linux/mbus.h>
@@ -187,7 +188,7 @@ static int mvebu_mbus_window_conflicts(struct mvebu_mbus_state *mbus,
phys_addr_t base, size_t size,
u8 target, u8 attr)
{
- u64 end = (u64)base + size;
+ u64 end = (u64)base + size - 1;
int win;
for (win = 0; win < mbus->soc->num_wins; win++) {
@@ -203,7 +204,7 @@ static int mvebu_mbus_window_conflicts(struct mvebu_mbus_state *mbus,
if (!enabled)
continue;
- wend = wbase + wsize;
+ wend = wbase + wsize - 1;
/*
* Check if the current window overlaps with the
@@ -546,7 +547,7 @@ void mvebu_mbus_get_pcie_io_aperture(struct resource *res)
* - bits 16 to 23: window attribute ID
* - bits 0 to 15: unused
*/
-#define CUSTOM(id) (((id) & 0xF0000000) >> 24)
+#define CUSTOM(id) (((id) & 0xF0000000) >> 28)
#define TARGET(id) (((id) & 0x0F000000) >> 24)
#define ATTR(id) (((id) & 0x00FF0000) >> 16)
@@ -661,7 +662,7 @@ static void mvebu_mbus_get_pcie_resources(struct device_node *np,
reg, ARRAY_SIZE(reg));
if (!ret) {
mem->start = reg[0];
- mem->end = mem->start + reg[1];
+ mem->end = mem->start + reg[1] - 1;
mem->flags = IORESOURCE_MEM;
}
@@ -669,7 +670,7 @@ static void mvebu_mbus_get_pcie_resources(struct device_node *np,
reg, ARRAY_SIZE(reg));
if (!ret) {
io->start = reg[0];
- io->end = io->start + reg[1];
+ io->end = io->start + reg[1] - 1;
io->flags = IORESOURCE_IO;
}
}
@@ -741,3 +742,89 @@ static int mvebu_mbus_init(void)
return platform_driver_register(&mvebu_mbus_driver);
}
postcore_initcall(mvebu_mbus_init);
+
+struct mbus_range {
+ u32 mbusid;
+ u32 remap;
+ struct list_head list;
+};
+
+#define MBUS_ID(t,a) (((t) << 24) | ((attr) << 16))
+static LIST_HEAD(mbus_ranges);
+
+void mvebu_mbus_add_range(u8 target, u8 attr, u32 remap)
+{
+ struct mbus_range *r = xzalloc(sizeof(*r));
+
+ r->mbusid = MBUS_ID(target, attr);
+ r->remap = remap;
+ list_add_tail(&r->list, &mbus_ranges);
+}
+
+/*
+ * Barebox always remaps internal registers to 0xf1000000 on every SoC.
+ * As we (and Linux) need a working DT and there is no way to tell the current
+ * remap address, fixup any provided DT to ensure custom MBUS_IDs are correct.
+ */
+static int mvebu_mbus_of_fixup(struct device_node *root, void *context)
+{
+ struct device_node *np;
+
+ for_each_matching_node(np, mvebu_mbus_dt_ids) {
+ struct property *p;
+ int n, pa, na, ns, lenp, size;
+ u32 *ranges;
+
+ p = of_find_property(np, "ranges", &lenp);
+ if (!p)
+ return -EINVAL;
+
+ pa = of_n_addr_cells(np);
+ if (of_property_read_u32(np, "#address-cells", &na) ||
+ of_property_read_u32(np, "#size-cells", &ns))
+ return -EINVAL;
+
+ size = pa + na + ns;
+ ranges = xzalloc(lenp);
+ of_property_read_u32_array(np, "ranges", ranges, lenp/4);
+
+ /*
+ * Iterate through each ranges tuple and fixup the custom
+ * window ranges low base address. Because Armada XP supports
+ * LPAE, it has 2 cells for the parent address:
+ * <windowid child_base high_base low_base size>
+ *
+ * whereas for Armada 370, there's just one:
+ * <windowid child_base base size>
+ *
+ * For instance, the following tuple:
+ * <MBUS_ID(0xf0, 0x01) child_base {0} base 0x100000>
+ *
+ * would be fixed-up like:
+ * <MBUS_ID(0xf0, 0x01) child_base {0} remap 0x100000>
+ */
+ for (n = 0; n < lenp/4; n += size) {
+ struct mbus_range *r;
+ u32 mbusid = ranges[n];
+
+ if (!CUSTOM(mbusid))
+ continue;
+
+ list_for_each_entry(r, &mbus_ranges, list) {
+ if (r->mbusid == mbusid)
+ ranges[n + na + pa - 1] = r->remap;
+ }
+ }
+
+ if (of_property_write_u32_array(np, "ranges", ranges, lenp/4))
+ pr_err("Unable to fixup mbus ranges\n");
+ free(ranges);
+ }
+
+ return 0;
+}
+
+static int mvebu_mbus_fixup_register(void) {
+ return of_register_fixup(mvebu_mbus_of_fixup, NULL);
+}
+pure_initcall(mvebu_mbus_fixup_register);
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 2b28cf3fb4..81955063d7 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -27,6 +27,12 @@ config OF_GPIO
depends on OFDEVICE
def_bool y
+config OF_PCI
+ bool
+ depends on PCI
+ help
+ OpenFirmware PCI bus accessors
+
config OF_BAREBOX_DRIVERS
depends on OFDEVICE
depends on ENV_HANDLING
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index c883e516c8..0dc2f8d63e 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -1,6 +1,7 @@
obj-y += address.o base.o fdt.o platform.o
obj-$(CONFIG_OFTREE_MEM_GENERIC) += mem_generic.o
obj-$(CONFIG_OF_GPIO) += of_gpio.o
+obj-$(CONFIG_OF_PCI) += of_pci.o
obj-y += partition.o
obj-y += of_net.o
obj-$(CONFIG_MTD) += of_mtd.o
diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
new file mode 100644
index 0000000000..2d0fbd2e5f
--- /dev/null
+++ b/drivers/of/of_pci.c
@@ -0,0 +1,27 @@
+#include <common.h>
+#include <errno.h>
+#include <of.h>
+#include <of_pci.h>
+
+/**
+ * of_pci_get_devfn() - Get device and function numbers for a device node
+ * @np: device node
+ *
+ * Parses a standard 5-cell PCI resource and returns an 8-bit value that can
+ * be passed to the PCI_SLOT() and PCI_FUNC() macros to extract the device
+ * and function numbers respectively. On error a negative error code is
+ * returned.
+ */
+int of_pci_get_devfn(struct device_node *np)
+{
+ unsigned int size;
+ const __be32 *reg;
+
+ reg = of_get_property(np, "reg", &size);
+
+ if (!reg || size < 5 * sizeof(__be32))
+ return -EINVAL;
+
+ return (be32_to_cpup(reg) >> 8) & 0xff;
+}
+EXPORT_SYMBOL_GPL(of_pci_get_devfn);
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 9e4659270d..d17a151082 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -24,6 +24,12 @@ config PCI_DEBUG
When in doubt, say N.
+config PCI_MVEBU
+ bool "Marvell EBU PCIe driver"
+ depends on ARCH_MVEBU
+ select OF_PCI
+ select PCI
+
endmenu
endif
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index edac1a53de..442353173c 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -6,3 +6,5 @@ obj-y += pci.o bus.o pci_iomap.o
ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG
CPPFLAGS += $(ccflags-y)
+
+obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o pci-mvebu-phy.o
diff --git a/drivers/pci/pci-mvebu-phy.c b/drivers/pci/pci-mvebu-phy.c
new file mode 100644
index 0000000000..55a1d39f62
--- /dev/null
+++ b/drivers/pci/pci-mvebu-phy.c
@@ -0,0 +1,208 @@
+/*
+ * SoC specific PCIe PHY setup for Marvell MVEBU SoCs
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * based on Marvell BSP code (C) Marvell International Ltd.
+ *
+ * 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.
+ */
+
+#include <common.h>
+#include <of.h>
+#include <of_address.h>
+
+#include "pci-mvebu.h"
+
+static u32 mvebu_pcie_phy_indirect(void __iomem *phybase, u8 lane,
+ u8 off, u16 val, bool is_read)
+{
+ u32 reg = (lane << 24) | (off << 16) | val;
+
+ if (is_read)
+ reg |= BIT(31);
+ writel(reg, phybase);
+
+ return (is_read) ? readl(phybase) & 0xffff : 0;
+}
+
+static inline u32 mvebu_pcie_phy_read(void __iomem *phybase, u8 lane,
+ u8 off)
+{
+ return mvebu_pcie_phy_indirect(phybase, lane, off, 0, true);
+}
+
+static inline void mvebu_pcie_phy_write(void __iomem *phybase, u8 lane,
+ u8 off, u16 val)
+{
+ mvebu_pcie_phy_indirect(phybase, lane, off, val, false);
+}
+
+/* PCIe registers */
+#define ARMADA_370_XP_PCIE_LINK_CAPS 0x6c
+#define MAX_LINK_WIDTH_MASK MAX_LINK_WIDTH(0x3f)
+#define MAX_LINK_WIDTH(x) ((x) << 4)
+#define MAX_LINK_SPEED_MASK 0xf
+#define MAX_LINK_SPEED_5G0 0x2
+#define MAX_LINK_SPEED_2G5 0x1
+#define ARMADA_370_XP_PHY_OFFSET 0x1b00
+/* System Control registers */
+#define ARMADA_370_XP_SOC_CTRL 0x04
+#define PCIE1_QUADX1_EN BIT(8) /* Armada XP */
+#define PCIE0_QUADX1_EN BIT(7) /* Armada XP */
+#define PCIE0_EN BIT(0)
+#define ARMADA_370_XP_SERDES03_SEL 0x70
+#define ARMADA_370_XP_SERDES47_SEL 0x74
+#define SERDES(x, v) ((v) << ((x) * 0x4))
+#define SERDES_MASK(x) SERDES((x), 0xf)
+
+int armada_370_phy_setup(struct mvebu_pcie *pcie)
+{
+ struct device_node *np = of_find_compatible_node(NULL, NULL,
+ "marvell,armada-370-xp-system-controller");
+ void __iomem *sysctrl = of_iomap(np, 0);
+ void __iomem *phybase = pcie->base + ARMADA_370_XP_PHY_OFFSET;
+ u32 reg;
+
+ if (!sysctrl)
+ return -ENODEV;
+
+ /* Enable PEX */
+ reg = readl(sysctrl + ARMADA_370_XP_SOC_CTRL);
+ reg |= PCIE0_EN << pcie->port;
+ writel(reg, sysctrl + ARMADA_370_XP_SOC_CTRL);
+
+ /* Set SERDES selector */
+ reg = readl(sysctrl + ARMADA_370_XP_SERDES03_SEL);
+ reg &= ~SERDES_MASK(pcie->port);
+ reg |= SERDES(pcie->port, 0x1);
+ writel(reg, sysctrl + ARMADA_370_XP_SERDES03_SEL);
+
+ /* BTS #232 - PCIe clock (undocumented) */
+ writel(0x00000077, sysctrl + 0x2f0);
+
+ /* Set x1 Link Capability */
+ reg = readl(pcie->base + ARMADA_370_XP_PCIE_LINK_CAPS);
+ reg &= ~(MAX_LINK_WIDTH_MASK | MAX_LINK_SPEED_MASK);
+ reg |= MAX_LINK_WIDTH(0x1) | MAX_LINK_SPEED_5G0;
+ writel(reg, pcie->base + ARMADA_370_XP_PCIE_LINK_CAPS);
+
+ /* PEX pipe configuration */
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0xc1, 0x0025);
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0xc3, 0x000f);
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0xc8, 0x0005);
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0xd0, 0x0100);
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0xd1, 0x3014);
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0xc5, 0x011f);
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0x80, 0x1000);
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0x81, 0x0011);
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0x0f, 0x2a21);
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0x45, 0x00df);
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0x4f, 0x6219);
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0x01, 0xfc60);
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0x46, 0x0000);
+
+ reg = mvebu_pcie_phy_read(phybase, pcie->lane, 0x48) & ~0x4;
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0x48, reg & 0xffff);
+
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0x02, 0x0040);
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0xc1, 0x0024);
+
+ mdelay(15);
+
+ return 0;
+}
+
+/*
+ * MV78230: 2 PCIe units Gen2.0, one unit 1x4 or 4x1, one unit 1x1
+ * MV78260: 3 PCIe units Gen2.0, two units 1x4 or 4x1, one unit 1x1/1x4
+ * MV78460: 4 PCIe units Gen2.0, two units 1x4 or 4x1, two units 1x1/1x4
+ */
+#define ARMADA_XP_COMM_PHY_REFCLK_ALIGN 0xf8
+#define REFCLK_ALIGN(x) (0xf << ((x) * 0x4))
+int armada_xp_phy_setup(struct mvebu_pcie *pcie)
+{
+ struct device_node *np = of_find_compatible_node(NULL, NULL,
+ "marvell,armada-370-xp-system-controller");
+ void __iomem *sysctrl = of_iomap(np, 0);
+ void __iomem *phybase = pcie->base + ARMADA_370_XP_PHY_OFFSET;
+ u32 serdes_off = (pcie->port < 2) ? ARMADA_370_XP_SERDES03_SEL :
+ ARMADA_370_XP_SERDES47_SEL;
+ bool single_x4 = (pcie->lane_mask == 0xf);
+ u32 reg, mask;
+
+ if (!sysctrl)
+ return -ENODEV;
+
+ /* Prepare PEX */
+ reg = readl(sysctrl + ARMADA_370_XP_SOC_CTRL);
+ reg &= ~(PCIE0_EN << pcie->port);
+ writel(reg, sysctrl + ARMADA_370_XP_SOC_CTRL);
+
+ if (pcie->port < 2) {
+ mask = PCIE0_QUADX1_EN << pcie->port;
+ if (single_x4)
+ reg &= ~mask;
+ else
+ reg |= mask;
+ }
+ reg |= PCIE0_EN << pcie->port;
+ writel(reg, sysctrl + ARMADA_370_XP_SOC_CTRL);
+
+ /* Set SERDES selector */
+ reg = readl(sysctrl + serdes_off);
+ for (mask = pcie->lane_mask; mask;) {
+ u32 l = ffs(mask)-1;
+ u32 off = 4 * (pcie->port % 2);
+ reg &= ~SERDES_MASK(off + l);
+ reg |= SERDES(off + l, 0x1);
+ mask &= ~BIT(l);
+ }
+ reg &= ~SERDES_MASK(pcie->port % 2);
+ reg |= SERDES(pcie->port % 2, 0x1);
+ writel(reg, sysctrl + serdes_off);
+
+ /* Reference Clock Alignment for 1x4 */
+ reg = readl(sysctrl + ARMADA_XP_COMM_PHY_REFCLK_ALIGN);
+ if (single_x4)
+ reg |= REFCLK_ALIGN(pcie->port);
+ else
+ reg &= ~REFCLK_ALIGN(pcie->port);
+ writel(reg, sysctrl + ARMADA_XP_COMM_PHY_REFCLK_ALIGN);
+
+ /* Set x1/x4 Link Capability */
+ reg = readl(pcie->base + ARMADA_370_XP_PCIE_LINK_CAPS);
+ reg &= ~(MAX_LINK_WIDTH_MASK | MAX_LINK_SPEED_MASK);
+ if (single_x4)
+ reg |= MAX_LINK_WIDTH(0x4);
+ else
+ reg |= MAX_LINK_WIDTH(0x1);
+ reg |= MAX_LINK_SPEED_5G0;
+ writel(reg, pcie->base + ARMADA_370_XP_PCIE_LINK_CAPS);
+
+ /* PEX pipe configuration */
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0xc1, 0x0025);
+ if (single_x4) {
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0xc2, 0x0200);
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0xc3, 0x0001);
+ } else {
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0xc2, 0x0000);
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0xc3, 0x000f);
+ }
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0xc8, 0x0005);
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0x01, 0xfc60);
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0x46, 0x0000);
+
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0x02, 0x0040);
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0xc1, 0x0024);
+ if (single_x4)
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0x48, 0x1080);
+ else
+ mvebu_pcie_phy_write(phybase, pcie->lane, 0x48, 0x9080);
+
+ mdelay(15);
+
+ return 0;
+}
diff --git a/drivers/pci/pci-mvebu.c b/drivers/pci/pci-mvebu.c
new file mode 100644
index 0000000000..45befbba20
--- /dev/null
+++ b/drivers/pci/pci-mvebu.c
@@ -0,0 +1,446 @@
+/*
+ * PCIe driver for Marvell MVEBU SoCs
+ *
+ * Based on Linux drivers/pci/host/pci-mvebu.c
+ *
+ * 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.
+ */
+
+#include <common.h>
+#include <gpio.h>
+#include <init.h>
+#include <io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/mbus.h>
+#include <linux/pci_regs.h>
+#include <malloc.h>
+#include <of_address.h>
+#include <of_gpio.h>
+#include <of_pci.h>
+#include <sizes.h>
+
+#include "pci-mvebu.h"
+
+/* PCIe unit register offsets */
+#define PCIE_DEV_ID_OFF 0x0000
+#define PCIE_CMD_OFF 0x0004
+#define PCIE_DEV_REV_OFF 0x0008
+#define PCIE_BAR_LO_OFF(n) (0x0010 + ((n) << 3))
+#define PCIE_BAR_HI_OFF(n) (0x0014 + ((n) << 3))
+#define PCIE_HEADER_LOG_4_OFF 0x0128
+#define PCIE_BAR_CTRL_OFF(n) (0x1804 + (((n) - 1) * 4))
+#define PCIE_WIN04_CTRL_OFF(n) (0x1820 + ((n) << 4))
+#define PCIE_WIN04_BASE_OFF(n) (0x1824 + ((n) << 4))
+#define PCIE_WIN04_REMAP_OFF(n) (0x182c + ((n) << 4))
+#define PCIE_WIN5_CTRL_OFF 0x1880
+#define PCIE_WIN5_BASE_OFF 0x1884
+#define PCIE_WIN5_REMAP_OFF 0x188c
+#define PCIE_CONF_ADDR_OFF 0x18f8
+#define PCIE_CONF_ADDR_EN BIT(31)
+#define PCIE_CONF_REG(r) ((((r) & 0xf00) << 16) | ((r) & 0xfc))
+#define PCIE_CONF_BUS(b) (((b) & 0xff) << 16)
+#define PCIE_CONF_DEV(d) (((d) & 0x1f) << 11)
+#define PCIE_CONF_FUNC(f) (((f) & 0x7) << 8)
+#define PCIE_CONF_ADDR(bus, devfn, where) \
+ (PCIE_CONF_BUS(bus) | PCIE_CONF_DEV(PCI_SLOT(devfn)) | \
+ PCIE_CONF_FUNC(PCI_FUNC(devfn)) | PCIE_CONF_REG(where) | \
+ PCIE_CONF_ADDR_EN)
+#define PCIE_CONF_DATA_OFF 0x18fc
+#define PCIE_MASK_OFF 0x1910
+#define PCIE_MASK_ENABLE_INTS (0xf << 24)
+#define PCIE_CTRL_OFF 0x1a00
+#define PCIE_CTRL_X1_MODE BIT(0)
+#define PCIE_STAT_OFF 0x1a04
+#define PCIE_STAT_BUS (0xff << 8)
+#define PCIE_STAT_DEV (0x1f << 16)
+#define PCIE_STAT_LINK_DOWN BIT(0)
+#define PCIE_DEBUG_CTRL 0x1a60
+#define PCIE_DEBUG_SOFT_RESET BIT(20)
+
+#define to_pcie(_hc) container_of(_hc, struct mvebu_pcie, pci)
+
+/*
+ * MVEBU PCIe controller needs MEMORY and I/O BARs to be mapped
+ * into SoCs address space. Each controller will map 32M of MEM
+ * and 64K of I/O space when registered.
+ */
+static void __iomem *mvebu_pcie_membase = IOMEM(0xe0000000);
+static void __iomem *mvebu_pcie_iobase = IOMEM(0xffe00000);
+
+static inline bool mvebu_pcie_link_up(struct mvebu_pcie *pcie)
+{
+ return !(readl(pcie->base + PCIE_STAT_OFF) & PCIE_STAT_LINK_DOWN);
+}
+
+static void mvebu_pcie_set_local_bus_nr(struct pci_controller *host, int busno)
+{
+ struct mvebu_pcie *pcie = to_pcie(host);
+ u32 stat;
+
+ stat = readl(pcie->base + PCIE_STAT_OFF);
+ stat &= ~PCIE_STAT_BUS;
+ stat |= busno << 8;
+ writel(stat, pcie->base + PCIE_STAT_OFF);
+}
+
+static void mvebu_pcie_set_local_dev_nr(struct mvebu_pcie *pcie, int devno)
+{
+ u32 stat;
+
+ stat = readl(pcie->base + PCIE_STAT_OFF);
+ stat &= ~PCIE_STAT_DEV;
+ stat |= devno << 16;
+ writel(stat, pcie->base + PCIE_STAT_OFF);
+}
+
+static int mvebu_pcie_indirect_rd_conf(struct pci_bus *bus,
+ unsigned int devfn, int where, int size, u32 *val)
+{
+ struct mvebu_pcie *pcie = to_pcie(bus->host);
+
+ /* Skip all requests not directed to device behind bridge */
+ if (devfn != pcie->devfn || !mvebu_pcie_link_up(pcie)) {
+ *val = 0xffffffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ writel(PCIE_CONF_ADDR(bus->number, devfn, where),
+ pcie->base + PCIE_CONF_ADDR_OFF);
+
+ *val = readl(pcie->base + PCIE_CONF_DATA_OFF);
+
+ if (size == 1)
+ *val = (*val >> (8 * (where & 3))) & 0xff;
+ else if (size == 2)
+ *val = (*val >> (8 * (where & 3))) & 0xffff;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int mvebu_pcie_indirect_wr_conf(struct pci_bus *bus,
+ unsigned int devfn, int where, int size, u32 val)
+{
+ struct mvebu_pcie *pcie = to_pcie(bus->host);
+ u32 _val, shift = 8 * (where & 3);
+
+ /* Skip all requests not directed to device behind bridge */
+ if (devfn != pcie->devfn || !mvebu_pcie_link_up(pcie))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ writel(PCIE_CONF_ADDR(bus->number, devfn, where),
+ pcie->base + PCIE_CONF_ADDR_OFF);
+ _val = readl(pcie->base + PCIE_CONF_DATA_OFF);
+
+ if (size == 4)
+ _val = val;
+ else if (size == 2)
+ _val = (_val & ~(0xffff << shift)) | ((val & 0xffff) << shift);
+ else if (size == 1)
+ _val = (_val & ~(0xff << shift)) | ((val & 0xff) << shift);
+ else
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ writel(_val, pcie->base + PCIE_CONF_DATA_OFF);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int mvebu_pcie_res_start(struct pci_bus *bus, resource_size_t res_addr)
+{
+ struct mvebu_pcie *pcie = to_pcie(bus->host);
+
+ return (int)pcie->membase + (res_addr & (resource_size(&pcie->mem)-1));
+}
+
+static struct pci_ops mvebu_pcie_indirect_ops = {
+ .read = mvebu_pcie_indirect_rd_conf,
+ .write = mvebu_pcie_indirect_wr_conf,
+ .res_start = mvebu_pcie_res_start,
+};
+
+/*
+ * Setup PCIE BARs and Address Decode Wins:
+ * BAR[0,2] -> disabled, BAR[1] -> covers all DRAM banks
+ * WIN[0-3] -> DRAM bank[0-3]
+ */
+static void mvebu_pcie_setup_wins(struct mvebu_pcie *pcie)
+{
+ const struct mbus_dram_target_info *dram = mvebu_mbus_dram_info();
+ u32 size;
+ int i;
+
+ /* First, disable and clear BARs and windows. */
+ for (i = 1; i < 3; i++) {
+ writel(0, pcie->base + PCIE_BAR_CTRL_OFF(i));
+ writel(0, pcie->base + PCIE_BAR_LO_OFF(i));
+ writel(0, pcie->base + PCIE_BAR_HI_OFF(i));
+ }
+
+ for (i = 0; i < 5; i++) {
+ writel(0, pcie->base + PCIE_WIN04_CTRL_OFF(i));
+ writel(0, pcie->base + PCIE_WIN04_BASE_OFF(i));
+ writel(0, pcie->base + PCIE_WIN04_REMAP_OFF(i));
+ }
+
+ writel(0, pcie->base + PCIE_WIN5_CTRL_OFF);
+ writel(0, pcie->base + PCIE_WIN5_BASE_OFF);
+ writel(0, pcie->base + PCIE_WIN5_REMAP_OFF);
+
+ /* Setup windows for DDR banks. Count total DDR size on the fly. */
+ size = 0;
+ for (i = 0; i < dram->num_cs; i++) {
+ const struct mbus_dram_window *cs = dram->cs + i;
+
+ writel(cs->base & 0xffff0000,
+ pcie->base + PCIE_WIN04_BASE_OFF(i));
+ writel(0, pcie->base + PCIE_WIN04_REMAP_OFF(i));
+ writel(((cs->size - 1) & 0xffff0000) |
+ (cs->mbus_attr << 8) |
+ (dram->mbus_dram_target_id << 4) | 1,
+ pcie->base + PCIE_WIN04_CTRL_OFF(i));
+
+ size += cs->size;
+ }
+
+ /* Round up 'size' to the nearest power of two. */
+ if ((size & (size - 1)) != 0)
+ size = 1 << fls(size);
+
+ /* Setup BAR[1] to all DRAM banks. */
+ writel(dram->cs[0].base, pcie->base + PCIE_BAR_LO_OFF(1));
+ writel(0, pcie->base + PCIE_BAR_HI_OFF(1));
+ writel(((size - 1) & 0xffff0000) | 1,
+ pcie->base + PCIE_BAR_CTRL_OFF(1));
+}
+
+#define DT_FLAGS_TO_TYPE(flags) (((flags) >> 24) & 0x03)
+#define DT_TYPE_IO 0x1
+#define DT_TYPE_MEM32 0x2
+#define DT_CPUADDR_TO_TARGET(cpuaddr) (((cpuaddr) >> 56) & 0xFF)
+#define DT_CPUADDR_TO_ATTR(cpuaddr) (((cpuaddr) >> 48) & 0xFF)
+
+static int mvebu_get_target_attr(struct device_node *np, int devfn,
+ unsigned long type, unsigned int *target, unsigned int *attr)
+{
+ const int na = 3, ns = 2;
+ const __be32 *range;
+ int rlen, nranges, rangesz, pna, i;
+
+ *target = -1;
+ *attr = -1;
+
+ range = of_get_property(np, "ranges", &rlen);
+ if (!range)
+ return -EINVAL;
+
+ pna = of_n_addr_cells(np);
+ rangesz = pna + na + ns;
+ nranges = rlen / sizeof(__be32) / rangesz;
+
+ for (i = 0; i < nranges; i++) {
+ u32 flags = of_read_number(range, 1);
+ u32 slot = of_read_number(range + 1, 1);
+ u64 cpuaddr = of_read_number(range + na, pna);
+ unsigned long rtype;
+
+ if (DT_FLAGS_TO_TYPE(flags) == DT_TYPE_IO)
+ rtype = IORESOURCE_IO;
+ else if (DT_FLAGS_TO_TYPE(flags) == DT_TYPE_MEM32)
+ rtype = IORESOURCE_MEM;
+
+ if (slot == PCI_SLOT(devfn) && type == rtype) {
+ *target = DT_CPUADDR_TO_TARGET(cpuaddr);
+ *attr = DT_CPUADDR_TO_ATTR(cpuaddr);
+ return 0;
+ }
+
+ range += rangesz;
+ }
+
+ return -ENOENT;
+}
+
+static struct mvebu_pcie *mvebu_pcie_port_probe(struct device_d *dev,
+ struct device_node *np)
+{
+ struct mvebu_pcie *pcie;
+ struct clk *clk;
+ enum of_gpio_flags flags;
+ struct property *prop;
+ const __be32 *p;
+ int reset_gpio;
+ u32 u, port, lane, lane_mask, devfn;
+ int mem_target, mem_attr;
+ int io_target, io_attr;
+ int ret;
+
+ if (of_property_read_u32(np, "marvell,pcie-port", &port)) {
+ dev_err(dev, "missing pcie-port property\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ lane_mask = 0;
+ of_property_for_each_u32(np, "marvell,pcie-lane", prop, p, u)
+ lane_mask |= BIT(u);
+ lane = ffs(lane_mask)-1;
+
+ devfn = of_pci_get_devfn(np);
+ if (devfn < 0) {
+ dev_err(dev, "unable to parse devfn\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (mvebu_get_target_attr(dev->device_node, devfn, IORESOURCE_MEM,
+ &mem_target, &mem_attr)) {
+ dev_err(dev, "unable to get target/attr for mem window\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ /* I/O windows are optional */
+ mvebu_get_target_attr(dev->device_node, devfn, IORESOURCE_IO,
+ &io_target, &io_attr);
+
+ reset_gpio = of_get_named_gpio_flags(np, "reset-gpios", 0, &flags);
+ if (gpio_is_valid(reset_gpio)) {
+ int reset_active_low = flags & OF_GPIO_ACTIVE_LOW;
+ char *reset_name = asprintf("pcie%d.%d-reset", port, lane);
+ u32 reset_udelay = 20000;
+
+ of_property_read_u32(np, "reset-delay-us", &reset_udelay);
+
+ ret = gpio_request_one(reset_gpio, GPIOF_DIR_OUT, reset_name);
+ if (ret)
+ return ERR_PTR(ret);
+
+ /* Ensure a full reset cycle*/
+ gpio_set_value(reset_gpio, 1 ^ reset_active_low);
+ udelay(reset_udelay);
+ gpio_set_value(reset_gpio, 0 ^ reset_active_low);
+ udelay(reset_udelay);
+ }
+
+ pcie = xzalloc(sizeof(*pcie));
+ pcie->port = port;
+ pcie->lane = lane;
+ pcie->lane_mask = lane_mask;
+ pcie->name = asprintf("pcie%d.%d", port, lane);
+ pcie->devfn = devfn;
+
+ pcie->base = of_iomap(np, 0);
+ if (!pcie->base) {
+ dev_err(dev, "PCIe%d.%d unable to map registers\n", port, lane);
+ free(pcie);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ pcie->membase = mvebu_pcie_membase;
+ pcie->mem.start = (u32)mvebu_pcie_membase;
+ pcie->mem.end = pcie->mem.start + SZ_32M - 1;
+ if (mvebu_mbus_add_window_remap_by_id(mem_target, mem_attr,
+ (resource_size_t)pcie->membase, resource_size(&pcie->mem),
+ (u32)pcie->mem.start)) {
+ dev_err(dev, "PCIe%d.%d unable to add mbus window for mem at %08x+%08x",
+ port, lane, (u32)pcie->mem.start, resource_size(&pcie->mem));
+
+ free(pcie);
+ return ERR_PTR(-EBUSY);
+ }
+ mvebu_pcie_membase += SZ_32M;
+
+ if (io_target >= 0 && io_attr >= 0) {
+ pcie->iobase = mvebu_pcie_iobase;
+ pcie->io.start = (u32)mvebu_pcie_iobase;
+ pcie->io.end = pcie->io.start + SZ_64K - 1;
+
+ mvebu_mbus_add_window_remap_by_id(io_target, io_attr,
+ (resource_size_t)pcie->iobase, resource_size(&pcie->io),
+ (u32)pcie->io.start);
+ mvebu_pcie_iobase += SZ_64K;
+ }
+
+ clk = of_clk_get(np, 0);
+ if (!IS_ERR(clk))
+ clk_enable(clk);
+
+ pcie->pci.set_busno = mvebu_pcie_set_local_bus_nr;
+ pcie->pci.pci_ops = &mvebu_pcie_indirect_ops;
+ pcie->pci.mem_resource = &pcie->mem;
+ pcie->pci.io_resource = &pcie->io;
+
+ return pcie;
+}
+
+static struct mvebu_pcie_ops __maybe_unused armada_370_ops = {
+ .phy_setup = armada_370_phy_setup,
+};
+
+static struct mvebu_pcie_ops __maybe_unused armada_xp_ops = {
+ .phy_setup = armada_xp_phy_setup,
+};
+
+static struct of_device_id mvebu_pcie_dt_ids[] = {
+#if defined(CONFIG_ARCH_ARMADA_XP)
+ { .compatible = "marvell,armada-xp-pcie", .data = (u32)&armada_xp_ops, },
+#endif
+#if defined(CONFIG_ARCH_ARMADA_370)
+ { .compatible = "marvell,armada-370-pcie", .data = (u32)&armada_370_ops, },
+#endif
+#if defined(CONFIG_ARCH_DOVE)
+ { .compatible = "marvell,dove-pcie", },
+#endif
+#if defined(CONFIG_ARCH_KIRKWOOD)
+ { .compatible = "marvell,kirkwood-pcie", },
+#endif
+ { },
+};
+
+static int mvebu_pcie_probe(struct device_d *dev)
+{
+ struct device_node *np = dev->device_node;
+ const struct of_device_id *match = of_match_node(mvebu_pcie_dt_ids, np);
+ struct mvebu_pcie_ops *ops = (struct mvebu_pcie_ops *)match->data;
+ struct device_node *pnp;
+
+ for_each_child_of_node(np, pnp) {
+ struct mvebu_pcie *pcie;
+ u32 reg;
+
+ if (!of_device_is_available(pnp))
+ continue;
+
+ pcie = mvebu_pcie_port_probe(dev, pnp);
+ if (IS_ERR(pcie))
+ continue;
+
+ if (ops && ops->phy_setup)
+ ops->phy_setup(pcie);
+
+ mvebu_pcie_set_local_dev_nr(pcie, 0);
+ mvebu_pcie_setup_wins(pcie);
+
+ /* Master + slave enable. */
+ reg = readl(pcie->base + PCIE_CMD_OFF);
+ reg |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+ reg |= PCI_COMMAND_MASTER;
+ writel(reg, pcie->base + PCIE_CMD_OFF);
+
+ /* Disable interrupts */
+ reg = readl(pcie->base + PCIE_MASK_OFF);
+ reg &= ~PCIE_MASK_ENABLE_INTS;
+ writel(reg, pcie->base + PCIE_MASK_OFF);
+
+ register_pci_controller(&pcie->pci);
+ }
+
+ return 0;
+}
+
+static struct driver_d mvebu_pcie_driver = {
+ .name = "mvebu-pcie",
+ .probe = mvebu_pcie_probe,
+ .of_compatible = mvebu_pcie_dt_ids,
+};
+device_platform_driver(mvebu_pcie_driver);
diff --git a/drivers/pci/pci-mvebu.h b/drivers/pci/pci-mvebu.h
new file mode 100644
index 0000000000..8ced9fefca
--- /dev/null
+++ b/drivers/pci/pci-mvebu.h
@@ -0,0 +1,37 @@
+/*
+ * PCIe include for Marvell MVEBU SoCs
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * 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.
+ */
+
+#ifndef __MVEBU_PCI_H
+#define __MVEBU_PCI_H
+
+#include <linux/pci.h>
+
+struct mvebu_pcie {
+ struct pci_controller pci;
+ char *name;
+ void __iomem *base;
+ void __iomem *membase;
+ struct resource mem;
+ void __iomem *iobase;
+ struct resource io;
+ u32 port;
+ u32 lane;
+ u32 lane_mask;
+ int devfn;
+};
+
+struct mvebu_pcie_ops {
+ int (*phy_setup)(struct mvebu_pcie *pcie);
+};
+
+int armada_370_phy_setup(struct mvebu_pcie *pcie);
+int armada_xp_phy_setup(struct mvebu_pcie *pcie);
+
+#endif
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 3d88b0ff5f..a1b7680254 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -11,6 +11,7 @@ static struct pci_controller *hose_head, **hose_tail = &hose_head;
LIST_HEAD(pci_root_buses);
EXPORT_SYMBOL(pci_root_buses);
+static u8 bus_index;
static struct pci_bus *pci_alloc_bus(void)
{
@@ -36,10 +37,14 @@ void register_pci_controller(struct pci_controller *hose)
bus = pci_alloc_bus();
hose->bus = bus;
+ bus->host = hose;
bus->ops = hose->pci_ops;
bus->resource[0] = hose->mem_resource;
bus->resource[1] = hose->io_resource;
+ bus->number = bus_index++;
+ if (hose->set_busno)
+ hose->set_busno(hose, bus->number);
pci_scan_bus(bus);
list_add_tail(&bus->node, &pci_root_buses);
@@ -186,14 +191,15 @@ unsigned int pci_scan_bus(struct pci_bus *bus)
DBG("PCI: %02x:%02x [%04x/%04x]\n", bus->number, dev->devfn, dev->vendor, dev->device);
- list_add_tail(&dev->bus_list, &bus->devices);
- pci_register_device(dev);
-
if (class == PCI_CLASS_BRIDGE_HOST) {
DBG("PCI: skip pci host bridge\n");
continue;
}
+ pci_read_config_byte(dev, PCI_COMMAND, &cmd);
+ pci_write_config_byte(dev, PCI_COMMAND,
+ cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY));
+
for (bar = 0; bar < 6; bar++) {
resource_size_t last_addr;
@@ -211,20 +217,34 @@ unsigned int pci_scan_bus(struct pci_bus *bus)
size = -(mask & 0xfffffffe);
DBG(" PCI: pbar%d: mask=%08x io %d bytes\n", bar, mask, size);
pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, last_io);
+ dev->resource[bar].flags = IORESOURCE_IO;
last_addr = last_io;
last_io += size;
-
} else { /* MEM */
size = -(mask & 0xfffffff0);
DBG(" PCI: pbar%d: mask=%08x memory %d bytes\n", bar, mask, size);
pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, last_mem);
+ dev->resource[bar].flags = IORESOURCE_MEM;
last_addr = last_mem;
last_mem += size;
+
+ if ((mask & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
+ PCI_BASE_ADDRESS_MEM_TYPE_64) {
+ dev->resource[bar].flags |= IORESOURCE_MEM_64;
+ pci_write_config_dword(dev,
+ PCI_BASE_ADDRESS_1 + bar * 4, 0);
+ }
}
dev->resource[bar].start = last_addr;
dev->resource[bar].end = last_addr + size - 1;
+ if (dev->resource[bar].flags & IORESOURCE_MEM_64)
+ bar++;
}
+
+ pci_write_config_byte(dev, PCI_COMMAND, cmd);
+ list_add_tail(&dev->bus_list, &bus->devices);
+ pci_register_device(dev);
}
/*
diff --git a/drivers/pinctrl/mvebu/Kconfig b/drivers/pinctrl/mvebu/Kconfig
index f5cf60804c..be154ed437 100644
--- a/drivers/pinctrl/mvebu/Kconfig
+++ b/drivers/pinctrl/mvebu/Kconfig
@@ -1,3 +1,11 @@
+config PINCTRL_ARMADA_370
+ bool
+ select PINCTRL
+
+config PINCTRL_ARMADA_XP
+ bool
+ select PINCTRL
+
config PINCTRL_DOVE
bool
select PINCTRL
diff --git a/drivers/pinctrl/mvebu/Makefile b/drivers/pinctrl/mvebu/Makefile
index 05f320d5a3..6255a5f56d 100644
--- a/drivers/pinctrl/mvebu/Makefile
+++ b/drivers/pinctrl/mvebu/Makefile
@@ -1,3 +1,5 @@
obj-y += common.o
+obj-$(CONFIG_ARCH_ARMADA_370) += armada-370.o
+obj-$(CONFIG_ARCH_ARMADA_XP) += armada-xp.o
obj-$(CONFIG_ARCH_DOVE) += dove.o
obj-$(CONFIG_ARCH_KIRKWOOD) += kirkwood.o
diff --git a/drivers/pinctrl/mvebu/armada-370.c b/drivers/pinctrl/mvebu/armada-370.c
new file mode 100644
index 0000000000..4778358fad
--- /dev/null
+++ b/drivers/pinctrl/mvebu/armada-370.c
@@ -0,0 +1,416 @@
+/*
+ * Marvell Armada 370 pinctrl driver based on mvebu pinctrl core
+ *
+ * Copyright (C) 2012 Marvell
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <linux/clk.h>
+#include <malloc.h>
+#include <of.h>
+#include <of_address.h>
+#include <sizes.h>
+
+#include "common.h"
+
+static void __iomem *mpp_base;
+
+static int armada_370_mpp_ctrl_get(unsigned pid, unsigned long *config)
+{
+ return default_mpp_ctrl_get(mpp_base, pid, config);
+}
+
+static int armada_370_mpp_ctrl_set(unsigned pid, unsigned long config)
+{
+ return default_mpp_ctrl_set(mpp_base, pid, config);
+}
+
+static struct mvebu_mpp_mode mv88f6710_mpp_modes[] = {
+ MPP_MODE(0, "mpp0", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "uart0", "rxd")),
+ MPP_MODE(1, "mpp1", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpo", NULL),
+ MPP_FUNCTION(0x1, "uart0", "txd")),
+ MPP_MODE(2, "mpp2", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "i2c0", "sck"),
+ MPP_FUNCTION(0x2, "uart0", "txd")),
+ MPP_MODE(3, "mpp3", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "i2c0", "sda"),
+ MPP_FUNCTION(0x2, "uart0", "rxd")),
+ MPP_MODE(4, "mpp4", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "cpu_pd", "vdd")),
+ MPP_MODE(5, "mpp5", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpo", NULL),
+ MPP_FUNCTION(0x1, "ge0", "txclko"),
+ MPP_FUNCTION(0x2, "uart1", "txd"),
+ MPP_FUNCTION(0x4, "spi1", "clk"),
+ MPP_FUNCTION(0x5, "audio", "mclk")),
+ MPP_MODE(6, "mpp6", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "ge0", "txd0"),
+ MPP_FUNCTION(0x2, "sata0", "prsnt"),
+ MPP_FUNCTION(0x4, "tdm", "rst"),
+ MPP_FUNCTION(0x5, "audio", "sdo")),
+ MPP_MODE(7, "mpp7", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpo", NULL),
+ MPP_FUNCTION(0x1, "ge0", "txd1"),
+ MPP_FUNCTION(0x4, "tdm", "tdx"),
+ MPP_FUNCTION(0x5, "audio", "lrclk")),
+ MPP_MODE(8, "mpp8", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "ge0", "txd2"),
+ MPP_FUNCTION(0x2, "uart0", "rts"),
+ MPP_FUNCTION(0x4, "tdm", "drx"),
+ MPP_FUNCTION(0x5, "audio", "bclk")),
+ MPP_MODE(9, "mpp9", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpo", NULL),
+ MPP_FUNCTION(0x1, "ge0", "txd3"),
+ MPP_FUNCTION(0x2, "uart1", "txd"),
+ MPP_FUNCTION(0x3, "sd0", "clk"),
+ MPP_FUNCTION(0x5, "audio", "spdifo")),
+ MPP_MODE(10, "mpp10", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "ge0", "txctl"),
+ MPP_FUNCTION(0x2, "uart0", "cts"),
+ MPP_FUNCTION(0x4, "tdm", "fsync"),
+ MPP_FUNCTION(0x5, "audio", "sdi")),
+ MPP_MODE(11, "mpp11", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "ge0", "rxd0"),
+ MPP_FUNCTION(0x2, "uart1", "rxd"),
+ MPP_FUNCTION(0x3, "sd0", "cmd"),
+ MPP_FUNCTION(0x4, "spi0", "cs1"),
+ MPP_FUNCTION(0x5, "sata1", "prsnt"),
+ MPP_FUNCTION(0x6, "spi1", "cs1")),
+ MPP_MODE(12, "mpp12", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "ge0", "rxd1"),
+ MPP_FUNCTION(0x2, "i2c1", "sda"),
+ MPP_FUNCTION(0x3, "sd0", "d0"),
+ MPP_FUNCTION(0x4, "spi1", "cs0"),
+ MPP_FUNCTION(0x5, "audio", "spdifi")),
+ MPP_MODE(13, "mpp13", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "ge0", "rxd2"),
+ MPP_FUNCTION(0x2, "i2c1", "sck"),
+ MPP_FUNCTION(0x3, "sd0", "d1"),
+ MPP_FUNCTION(0x4, "tdm", "pclk"),
+ MPP_FUNCTION(0x5, "audio", "rmclk")),
+ MPP_MODE(14, "mpp14", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "ge0", "rxd3"),
+ MPP_FUNCTION(0x2, "pcie", "clkreq0"),
+ MPP_FUNCTION(0x3, "sd0", "d2"),
+ MPP_FUNCTION(0x4, "spi1", "mosi"),
+ MPP_FUNCTION(0x5, "spi0", "cs2")),
+ MPP_MODE(15, "mpp15", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "ge0", "rxctl"),
+ MPP_FUNCTION(0x2, "pcie", "clkreq1"),
+ MPP_FUNCTION(0x3, "sd0", "d3"),
+ MPP_FUNCTION(0x4, "spi1", "miso"),
+ MPP_FUNCTION(0x5, "spi0", "cs3")),
+ MPP_MODE(16, "mpp16", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "ge0", "rxclk"),
+ MPP_FUNCTION(0x2, "uart1", "rxd"),
+ MPP_FUNCTION(0x4, "tdm", "int"),
+ MPP_FUNCTION(0x5, "audio", "extclk")),
+ MPP_MODE(17, "mpp17", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpo", NULL),
+ MPP_FUNCTION(0x1, "ge", "mdc")),
+ MPP_MODE(18, "mpp18", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "ge", "mdio")),
+ MPP_MODE(19, "mpp19", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "ge0", "txclk"),
+ MPP_FUNCTION(0x2, "ge1", "txclkout"),
+ MPP_FUNCTION(0x4, "tdm", "pclk")),
+ MPP_MODE(20, "mpp20", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpo", NULL),
+ MPP_FUNCTION(0x1, "ge0", "txd4"),
+ MPP_FUNCTION(0x2, "ge1", "txd0")),
+ MPP_MODE(21, "mpp21", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpo", NULL),
+ MPP_FUNCTION(0x1, "ge0", "txd5"),
+ MPP_FUNCTION(0x2, "ge1", "txd1"),
+ MPP_FUNCTION(0x4, "uart1", "txd")),
+ MPP_MODE(22, "mpp22", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpo", NULL),
+ MPP_FUNCTION(0x1, "ge0", "txd6"),
+ MPP_FUNCTION(0x2, "ge1", "txd2"),
+ MPP_FUNCTION(0x4, "uart0", "rts")),
+ MPP_MODE(23, "mpp23", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpo", NULL),
+ MPP_FUNCTION(0x1, "ge0", "txd7"),
+ MPP_FUNCTION(0x2, "ge1", "txd3"),
+ MPP_FUNCTION(0x4, "spi1", "mosi")),
+ MPP_MODE(24, "mpp24", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "ge0", "col"),
+ MPP_FUNCTION(0x2, "ge1", "txctl"),
+ MPP_FUNCTION(0x4, "spi1", "cs0")),
+ MPP_MODE(25, "mpp25", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "ge0", "rxerr"),
+ MPP_FUNCTION(0x2, "ge1", "rxd0"),
+ MPP_FUNCTION(0x4, "uart1", "rxd")),
+ MPP_MODE(26, "mpp26", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "ge0", "crs"),
+ MPP_FUNCTION(0x2, "ge1", "rxd1"),
+ MPP_FUNCTION(0x4, "spi1", "miso")),
+ MPP_MODE(27, "mpp27", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "ge0", "rxd4"),
+ MPP_FUNCTION(0x2, "ge1", "rxd2"),
+ MPP_FUNCTION(0x4, "uart0", "cts")),
+ MPP_MODE(28, "mpp28", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "ge0", "rxd5"),
+ MPP_FUNCTION(0x2, "ge1", "rxd3")),
+ MPP_MODE(29, "mpp29", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "ge0", "rxd6"),
+ MPP_FUNCTION(0x2, "ge1", "rxctl"),
+ MPP_FUNCTION(0x4, "i2c1", "sda")),
+ MPP_MODE(30, "mpp30", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "ge0", "rxd7"),
+ MPP_FUNCTION(0x2, "ge1", "rxclk"),
+ MPP_FUNCTION(0x4, "i2c1", "sck")),
+ MPP_MODE(31, "mpp31", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x3, "tclk", NULL),
+ MPP_FUNCTION(0x4, "ge0", "txerr")),
+ MPP_MODE(32, "mpp32", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "spi0", "cs0")),
+ MPP_MODE(33, "mpp33", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "bootcs"),
+ MPP_FUNCTION(0x2, "spi0", "cs0")),
+ MPP_MODE(34, "mpp34", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpo", NULL),
+ MPP_FUNCTION(0x1, "dev", "wen0"),
+ MPP_FUNCTION(0x2, "spi0", "mosi")),
+ MPP_MODE(35, "mpp35", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpo", NULL),
+ MPP_FUNCTION(0x1, "dev", "oen"),
+ MPP_FUNCTION(0x2, "spi0", "sck")),
+ MPP_MODE(36, "mpp36", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpo", NULL),
+ MPP_FUNCTION(0x1, "dev", "a1"),
+ MPP_FUNCTION(0x2, "spi0", "miso")),
+ MPP_MODE(37, "mpp37", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpo", NULL),
+ MPP_FUNCTION(0x1, "dev", "a0"),
+ MPP_FUNCTION(0x2, "sata0", "prsnt")),
+ MPP_MODE(38, "mpp38", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "ready"),
+ MPP_FUNCTION(0x2, "uart1", "cts"),
+ MPP_FUNCTION(0x3, "uart0", "cts")),
+ MPP_MODE(39, "mpp39", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpo", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad0"),
+ MPP_FUNCTION(0x2, "audio", "spdifo")),
+ MPP_MODE(40, "mpp40", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad1"),
+ MPP_FUNCTION(0x2, "uart1", "rts"),
+ MPP_FUNCTION(0x3, "uart0", "rts")),
+ MPP_MODE(41, "mpp41", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad2"),
+ MPP_FUNCTION(0x2, "uart1", "rxd")),
+ MPP_MODE(42, "mpp42", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpo", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad3"),
+ MPP_FUNCTION(0x2, "uart1", "txd")),
+ MPP_MODE(43, "mpp43", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpo", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad4"),
+ MPP_FUNCTION(0x2, "audio", "bclk")),
+ MPP_MODE(44, "mpp44", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpo", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad5"),
+ MPP_FUNCTION(0x2, "audio", "mclk")),
+ MPP_MODE(45, "mpp45", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpo", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad6"),
+ MPP_FUNCTION(0x2, "audio", "lrclk")),
+ MPP_MODE(46, "mpp46", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpo", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad7"),
+ MPP_FUNCTION(0x2, "audio", "sdo")),
+ MPP_MODE(47, "mpp47", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpo", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad8"),
+ MPP_FUNCTION(0x3, "sd0", "clk"),
+ MPP_FUNCTION(0x5, "audio", "spdifo")),
+ MPP_MODE(48, "mpp48", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad9"),
+ MPP_FUNCTION(0x2, "uart0", "rts"),
+ MPP_FUNCTION(0x3, "sd0", "cmd"),
+ MPP_FUNCTION(0x4, "sata1", "prsnt"),
+ MPP_FUNCTION(0x5, "spi0", "cs1")),
+ MPP_MODE(49, "mpp49", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad10"),
+ MPP_FUNCTION(0x2, "pcie", "clkreq1"),
+ MPP_FUNCTION(0x3, "sd0", "d0"),
+ MPP_FUNCTION(0x4, "spi1", "cs0"),
+ MPP_FUNCTION(0x5, "audio", "spdifi")),
+ MPP_MODE(50, "mpp50", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad11"),
+ MPP_FUNCTION(0x2, "uart0", "cts"),
+ MPP_FUNCTION(0x3, "sd0", "d1"),
+ MPP_FUNCTION(0x4, "spi1", "miso"),
+ MPP_FUNCTION(0x5, "audio", "rmclk")),
+ MPP_MODE(51, "mpp51", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad12"),
+ MPP_FUNCTION(0x2, "i2c1", "sda"),
+ MPP_FUNCTION(0x3, "sd0", "d2"),
+ MPP_FUNCTION(0x4, "spi1", "mosi")),
+ MPP_MODE(52, "mpp52", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad13"),
+ MPP_FUNCTION(0x2, "i2c1", "sck"),
+ MPP_FUNCTION(0x3, "sd0", "d3"),
+ MPP_FUNCTION(0x4, "spi1", "sck")),
+ MPP_MODE(53, "mpp53", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad14"),
+ MPP_FUNCTION(0x2, "sd0", "clk"),
+ MPP_FUNCTION(0x3, "tdm", "pclk"),
+ MPP_FUNCTION(0x4, "spi0", "cs2"),
+ MPP_FUNCTION(0x5, "pcie", "clkreq1")),
+ MPP_MODE(54, "mpp54", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpo", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad15"),
+ MPP_FUNCTION(0x3, "tdm", "dtx")),
+ MPP_MODE(55, "mpp55", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "cs1"),
+ MPP_FUNCTION(0x2, "uart1", "txd"),
+ MPP_FUNCTION(0x3, "tdm", "rst"),
+ MPP_FUNCTION(0x4, "sata1", "prsnt"),
+ MPP_FUNCTION(0x5, "sata0", "prsnt")),
+ MPP_MODE(56, "mpp56", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "cs2"),
+ MPP_FUNCTION(0x2, "uart1", "cts"),
+ MPP_FUNCTION(0x3, "uart0", "cts"),
+ MPP_FUNCTION(0x4, "spi0", "cs3"),
+ MPP_FUNCTION(0x5, "pcie", "clkreq0"),
+ MPP_FUNCTION(0x6, "spi1", "cs1")),
+ MPP_MODE(57, "mpp57", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "cs3"),
+ MPP_FUNCTION(0x2, "uart1", "rxd"),
+ MPP_FUNCTION(0x3, "tdm", "fsync"),
+ MPP_FUNCTION(0x4, "sata0", "prsnt"),
+ MPP_FUNCTION(0x5, "audio", "sdo")),
+ MPP_MODE(58, "mpp58", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "cs0"),
+ MPP_FUNCTION(0x2, "uart1", "rts"),
+ MPP_FUNCTION(0x3, "tdm", "int"),
+ MPP_FUNCTION(0x5, "audio", "extclk"),
+ MPP_FUNCTION(0x6, "uart0", "rts")),
+ MPP_MODE(59, "mpp59", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpo", NULL),
+ MPP_FUNCTION(0x1, "dev", "ale0"),
+ MPP_FUNCTION(0x2, "uart1", "rts"),
+ MPP_FUNCTION(0x3, "uart0", "rts"),
+ MPP_FUNCTION(0x5, "audio", "bclk")),
+ MPP_MODE(60, "mpp60", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "ale1"),
+ MPP_FUNCTION(0x2, "uart1", "rxd"),
+ MPP_FUNCTION(0x3, "sata0", "prsnt"),
+ MPP_FUNCTION(0x4, "pcie", "rst-out"),
+ MPP_FUNCTION(0x5, "audio", "sdi")),
+ MPP_MODE(61, "mpp61", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpo", NULL),
+ MPP_FUNCTION(0x1, "dev", "wen1"),
+ MPP_FUNCTION(0x2, "uart1", "txd"),
+ MPP_FUNCTION(0x5, "audio", "rclk")),
+ MPP_MODE(62, "mpp62", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "a2"),
+ MPP_FUNCTION(0x2, "uart1", "cts"),
+ MPP_FUNCTION(0x3, "tdm", "drx"),
+ MPP_FUNCTION(0x4, "pcie", "clkreq0"),
+ MPP_FUNCTION(0x5, "audio", "mclk"),
+ MPP_FUNCTION(0x6, "uart0", "cts")),
+ MPP_MODE(63, "mpp63", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpo", NULL),
+ MPP_FUNCTION(0x1, "spi0", "sck"),
+ MPP_FUNCTION(0x2, "tclk", NULL)),
+ MPP_MODE(64, "mpp64", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "spi0", "miso"),
+ MPP_FUNCTION(0x2, "spi0-1", "cs1")),
+ MPP_MODE(65, "mpp65", armada_370_mpp_ctrl,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "spi0", "mosi"),
+ MPP_FUNCTION(0x2, "spi0-1", "cs2")),
+};
+
+static struct mvebu_pinctrl_soc_info mv88f6710_pinctrl_info = {
+ .modes = mv88f6710_mpp_modes,
+ .nmodes = ARRAY_SIZE(mv88f6710_mpp_modes),
+ .variant = 0,
+};
+
+static struct of_device_id armada_370_pinctrl_of_match[] = {
+ {
+ .compatible = "marvell,mv88f6710-pinctrl",
+ .data = (u32)&mv88f6710_pinctrl_info,
+ },
+ { },
+};
+
+static int armada_370_pinctrl_probe(struct device_d *dev)
+{
+ const struct of_device_id *match =
+ of_match_node(armada_370_pinctrl_of_match, dev->device_node);
+ struct mvebu_pinctrl_soc_info *soc =
+ (struct mvebu_pinctrl_soc_info *)match->data;
+
+ mpp_base = dev_request_mem_region(dev, 0);
+ if (!mpp_base)
+ return -EBUSY;
+
+ return mvebu_pinctrl_probe(dev, soc);
+}
+
+static struct driver_d armada_370_pinctrl_driver = {
+ .name = "pinctrl-armada-370",
+ .probe = armada_370_pinctrl_probe,
+ .of_compatible = armada_370_pinctrl_of_match,
+};
+
+static int armada_370_pinctrl_init(void)
+{
+ return platform_driver_register(&armada_370_pinctrl_driver);
+}
+postcore_initcall(armada_370_pinctrl_init);
diff --git a/drivers/pinctrl/mvebu/armada-xp.c b/drivers/pinctrl/mvebu/armada-xp.c
new file mode 100644
index 0000000000..9f79d373e4
--- /dev/null
+++ b/drivers/pinctrl/mvebu/armada-xp.c
@@ -0,0 +1,403 @@
+/*
+ * Marvell Armada XP pinctrl driver based on mvebu pinctrl core
+ *
+ * Copyright (C) 2012 Marvell
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This file supports the three variants of Armada XP SoCs that are
+ * available: mv78230, mv78260 and mv78460. From a pin muxing
+ * perspective, the mv78230 has 49 MPP pins. The mv78260 and mv78460
+ * both have 67 MPP pins (more GPIOs and address lines for the memory
+ * bus mainly). The only difference between the mv78260 and the
+ * mv78460 in terms of pin muxing is the addition of two functions on
+ * pins 43 and 56 to access the VDD of the CPU2 and 3 (mv78260 has two
+ * cores, mv78460 has four cores).
+ */
+
+#include <common.h>
+#include <init.h>
+#include <linux/clk.h>
+#include <malloc.h>
+#include <of.h>
+#include <of_address.h>
+#include <sizes.h>
+
+#include "common.h"
+
+static void __iomem *mpp_base;
+
+static int armada_xp_mpp_ctrl_get(unsigned pid, unsigned long *config)
+{
+ return default_mpp_ctrl_get(mpp_base, pid, config);
+}
+
+static int armada_xp_mpp_ctrl_set(unsigned pid, unsigned long config)
+{
+ return default_mpp_ctrl_set(mpp_base, pid, config);
+}
+
+enum armada_xp_variant {
+ V_MV78230 = BIT(0),
+ V_MV78260 = BIT(1),
+ V_MV78460 = BIT(2),
+ V_MV78230_PLUS = (V_MV78230 | V_MV78260 | V_MV78460),
+ V_MV78260_PLUS = (V_MV78260 | V_MV78460),
+};
+
+static struct mvebu_mpp_mode armada_xp_mpp_modes[] = {
+ MPP_MODE(0, "mpp0", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ge0", "txclko", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "d0", V_MV78230_PLUS)),
+ MPP_MODE(1, "mpp1", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ge0", "txd0", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "d1", V_MV78230_PLUS)),
+ MPP_MODE(2, "mpp2", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ge0", "txd1", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "d2", V_MV78230_PLUS)),
+ MPP_MODE(3, "mpp3", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ge0", "txd2", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "d3", V_MV78230_PLUS)),
+ MPP_MODE(4, "mpp4", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ge0", "txd3", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "d4", V_MV78230_PLUS)),
+ MPP_MODE(5, "mpp5", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ge0", "txctl", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "d5", V_MV78230_PLUS)),
+ MPP_MODE(6, "mpp6", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ge0", "rxd0", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "d6", V_MV78230_PLUS)),
+ MPP_MODE(7, "mpp7", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ge0", "rxd1", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "d7", V_MV78230_PLUS)),
+ MPP_MODE(8, "mpp8", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ge0", "rxd2", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "d8", V_MV78230_PLUS)),
+ MPP_MODE(9, "mpp9", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ge0", "rxd3", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "d9", V_MV78230_PLUS)),
+ MPP_MODE(10, "mpp10", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ge0", "rxctl", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "d10", V_MV78230_PLUS)),
+ MPP_MODE(11, "mpp11", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ge0", "rxclk", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "d11", V_MV78230_PLUS)),
+ MPP_MODE(12, "mpp12", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ge0", "txd4", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x2, "ge1", "clkout", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "d12", V_MV78230_PLUS)),
+ MPP_MODE(13, "mpp13", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ge0", "txd5", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x2, "ge1", "txd0", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "d13", V_MV78230_PLUS)),
+ MPP_MODE(14, "mpp14", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ge0", "txd6", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x2, "ge1", "txd1", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "d14", V_MV78230_PLUS)),
+ MPP_MODE(15, "mpp15", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ge0", "txd7", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x2, "ge1", "txd2", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "d15", V_MV78230_PLUS)),
+ MPP_MODE(16, "mpp16", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ge0", "txclk", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x2, "ge1", "txd3", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "d16", V_MV78230_PLUS)),
+ MPP_MODE(17, "mpp17", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ge0", "col", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x2, "ge1", "txctl", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "d17", V_MV78230_PLUS)),
+ MPP_MODE(18, "mpp18", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ge0", "rxerr", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x2, "ge1", "rxd0", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "ptp", "trig", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "d18", V_MV78230_PLUS)),
+ MPP_MODE(19, "mpp19", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ge0", "crs", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x2, "ge1", "rxd1", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "ptp", "evreq", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "d19", V_MV78230_PLUS)),
+ MPP_MODE(20, "mpp20", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ge0", "rxd4", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x2, "ge1", "rxd2", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "ptp", "clk", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "d20", V_MV78230_PLUS)),
+ MPP_MODE(21, "mpp21", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ge0", "rxd5", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x2, "ge1", "rxd3", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "mem", "bat", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "d21", V_MV78230_PLUS)),
+ MPP_MODE(22, "mpp22", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ge0", "rxd6", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x2, "ge1", "rxctl", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "sata0", "prsnt", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "d22", V_MV78230_PLUS)),
+ MPP_MODE(23, "mpp23", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ge0", "rxd7", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x2, "ge1", "rxclk", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "sata1", "prsnt", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "d23", V_MV78230_PLUS)),
+ MPP_MODE(24, "mpp24", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "sata1", "prsnt", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x2, "nf", "bootcs-re", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "tdm", "rst", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "hsync", V_MV78230_PLUS)),
+ MPP_MODE(25, "mpp25", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "sata0", "prsnt", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x2, "nf", "bootcs-we", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "tdm", "pclk", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "vsync", V_MV78230_PLUS)),
+ MPP_MODE(26, "mpp26", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "tdm", "fsync", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "clk", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x5, "vdd", "cpu1-pd", V_MV78230_PLUS)),
+ MPP_MODE(27, "mpp27", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ptp", "trig", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "tdm", "dtx", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "e", V_MV78230_PLUS)),
+ MPP_MODE(28, "mpp28", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ptp", "evreq", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "tdm", "drx", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "pwm", V_MV78230_PLUS)),
+ MPP_MODE(29, "mpp29", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "ptp", "clk", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "tdm", "int0", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "ref-clk", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x5, "vdd", "cpu0-pd", V_MV78230_PLUS)),
+ MPP_MODE(30, "mpp30", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "sd0", "clk", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "tdm", "int1", V_MV78230_PLUS)),
+ MPP_MODE(31, "mpp31", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "sd0", "cmd", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "tdm", "int2", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x5, "vdd", "cpu0-pd", V_MV78230_PLUS)),
+ MPP_MODE(32, "mpp32", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "sd0", "d0", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "tdm", "int3", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x5, "vdd", "cpu1-pd", V_MV78230_PLUS)),
+ MPP_MODE(33, "mpp33", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "sd0", "d1", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "tdm", "int4", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "mem", "bat", V_MV78230_PLUS)),
+ MPP_MODE(34, "mpp34", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "sd0", "d2", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x2, "sata0", "prsnt", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "tdm", "int5", V_MV78230_PLUS)),
+ MPP_MODE(35, "mpp35", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "sd0", "d3", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x2, "sata1", "prsnt", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "tdm", "int6", V_MV78230_PLUS)),
+ MPP_MODE(36, "mpp36", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "spi", "mosi", V_MV78230_PLUS)),
+ MPP_MODE(37, "mpp37", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "spi", "miso", V_MV78230_PLUS)),
+ MPP_MODE(38, "mpp38", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "spi", "sck", V_MV78230_PLUS)),
+ MPP_MODE(39, "mpp39", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "spi", "cs0", V_MV78230_PLUS)),
+ MPP_MODE(40, "mpp40", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "spi", "cs1", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x2, "uart2", "cts", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "vdd", "cpu1-pd", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "vga-hsync", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x5, "pcie", "clkreq0", V_MV78230_PLUS)),
+ MPP_MODE(41, "mpp41", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "spi", "cs2", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x2, "uart2", "rts", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "sata1", "prsnt", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "lcd", "vga-vsync", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x5, "pcie", "clkreq1", V_MV78230_PLUS)),
+ MPP_MODE(42, "mpp42", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "uart2", "rxd", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x2, "uart0", "cts", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "tdm", "int7", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "tdm-1", "timer", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x5, "vdd", "cpu0-pd", V_MV78230_PLUS)),
+ MPP_MODE(43, "mpp43", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "uart2", "txd", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x2, "uart0", "rts", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "spi", "cs3", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "pcie", "rstout", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x5, "vdd", "cpu2-3-pd", V_MV78460)),
+ MPP_MODE(44, "mpp44", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "uart2", "cts", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x2, "uart3", "rxd", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "spi", "cs4", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "mem", "bat", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x5, "pcie", "clkreq2", V_MV78230_PLUS)),
+ MPP_MODE(45, "mpp45", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "uart2", "rts", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x2, "uart3", "txd", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "spi", "cs5", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "sata1", "prsnt", V_MV78230_PLUS)),
+ MPP_MODE(46, "mpp46", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "uart3", "rts", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x2, "uart1", "rts", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "spi", "cs6", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "sata0", "prsnt", V_MV78230_PLUS)),
+ MPP_MODE(47, "mpp47", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "uart3", "cts", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x2, "uart1", "cts", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x3, "spi", "cs7", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x4, "ref", "clkout", V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x5, "pcie", "clkreq3", V_MV78230_PLUS)),
+ MPP_MODE(48, "mpp48", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x1, "tclk", NULL, V_MV78230_PLUS),
+ MPP_VAR_FUNCTION(0x2, "dev", "burst/last", V_MV78230_PLUS)),
+ MPP_MODE(49, "mpp49", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS),
+ MPP_VAR_FUNCTION(0x1, "dev", "we3", V_MV78260_PLUS)),
+ MPP_MODE(50, "mpp50", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS),
+ MPP_VAR_FUNCTION(0x1, "dev", "we2", V_MV78260_PLUS)),
+ MPP_MODE(51, "mpp51", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS),
+ MPP_VAR_FUNCTION(0x1, "dev", "ad16", V_MV78260_PLUS)),
+ MPP_MODE(52, "mpp52", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS),
+ MPP_VAR_FUNCTION(0x1, "dev", "ad17", V_MV78260_PLUS)),
+ MPP_MODE(53, "mpp53", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS),
+ MPP_VAR_FUNCTION(0x1, "dev", "ad18", V_MV78260_PLUS)),
+ MPP_MODE(54, "mpp54", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS),
+ MPP_VAR_FUNCTION(0x1, "dev", "ad19", V_MV78260_PLUS)),
+ MPP_MODE(55, "mpp55", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS),
+ MPP_VAR_FUNCTION(0x1, "dev", "ad20", V_MV78260_PLUS),
+ MPP_VAR_FUNCTION(0x2, "vdd", "cpu0-pd", V_MV78260_PLUS)),
+ MPP_MODE(56, "mpp56", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS),
+ MPP_VAR_FUNCTION(0x1, "dev", "ad21", V_MV78260_PLUS),
+ MPP_VAR_FUNCTION(0x2, "vdd", "cpu1-pd", V_MV78260_PLUS)),
+ MPP_MODE(57, "mpp57", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS),
+ MPP_VAR_FUNCTION(0x1, "dev", "ad22", V_MV78260_PLUS),
+ MPP_VAR_FUNCTION(0x2, "vdd", "cpu2-3-pd", V_MV78460)),
+ MPP_MODE(58, "mpp58", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS),
+ MPP_VAR_FUNCTION(0x1, "dev", "ad23", V_MV78260_PLUS)),
+ MPP_MODE(59, "mpp59", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS),
+ MPP_VAR_FUNCTION(0x1, "dev", "ad24", V_MV78260_PLUS)),
+ MPP_MODE(60, "mpp60", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS),
+ MPP_VAR_FUNCTION(0x1, "dev", "ad25", V_MV78260_PLUS)),
+ MPP_MODE(61, "mpp61", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS),
+ MPP_VAR_FUNCTION(0x1, "dev", "ad26", V_MV78260_PLUS)),
+ MPP_MODE(62, "mpp62", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS),
+ MPP_VAR_FUNCTION(0x1, "dev", "ad27", V_MV78260_PLUS)),
+ MPP_MODE(63, "mpp63", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS),
+ MPP_VAR_FUNCTION(0x1, "dev", "ad28", V_MV78260_PLUS)),
+ MPP_MODE(64, "mpp64", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS),
+ MPP_VAR_FUNCTION(0x1, "dev", "ad29", V_MV78260_PLUS)),
+ MPP_MODE(65, "mpp65", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS),
+ MPP_VAR_FUNCTION(0x1, "dev", "ad30", V_MV78260_PLUS)),
+ MPP_MODE(66, "mpp66", armada_xp_mpp_ctrl,
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS),
+ MPP_VAR_FUNCTION(0x1, "dev", "ad31", V_MV78260_PLUS)),
+};
+
+static struct mvebu_pinctrl_soc_info armada_xp_pinctrl_info = {
+ .modes = armada_xp_mpp_modes,
+ .nmodes = ARRAY_SIZE(armada_xp_mpp_modes),
+};
+
+static struct of_device_id armada_xp_pinctrl_of_match[] = {
+ { .compatible = "marvell,mv78230-pinctrl", .data = (u32)V_MV78230, },
+ { .compatible = "marvell,mv78260-pinctrl", .data = (u32)V_MV78260, },
+ { .compatible = "marvell,mv78460-pinctrl", .data = (u32)V_MV78460, },
+ { },
+};
+
+static int armada_xp_pinctrl_probe(struct device_d *dev)
+{
+ const struct of_device_id *match =
+ of_match_node(armada_xp_pinctrl_of_match, dev->device_node);
+ struct mvebu_pinctrl_soc_info *soc = &armada_xp_pinctrl_info;
+
+ mpp_base = dev_request_mem_region(dev, 0);
+ if (!mpp_base)
+ return -EBUSY;
+
+ soc->variant = (enum armada_xp_variant)match->data;
+
+ /*
+ * We don't necessarily want the full list of the armada_xp_mpp_modes,
+ * but only the first 'n' ones that are available on this SoC
+ */
+ if (soc->variant == V_MV78230)
+ soc->nmodes = 49;
+
+ return mvebu_pinctrl_probe(dev, soc);
+}
+
+static struct driver_d armada_xp_pinctrl_driver = {
+ .name = "pinctrl-armada-xp",
+ .probe = armada_xp_pinctrl_probe,
+ .of_compatible = armada_xp_pinctrl_of_match,
+};
+
+static int armada_xp_pinctrl_init(void)
+{
+ return platform_driver_register(&armada_xp_pinctrl_driver);
+}
+postcore_initcall(armada_xp_pinctrl_init);
diff --git a/include/linux/mbus.h b/include/linux/mbus.h
index 578ff33146..ac14982875 100644
--- a/include/linux/mbus.h
+++ b/include/linux/mbus.h
@@ -58,4 +58,6 @@ int mvebu_mbus_add_window_by_id(unsigned int target, unsigned int attribute,
phys_addr_t base, size_t size);
int mvebu_mbus_del_window(phys_addr_t base, size_t size);
+void mvebu_mbus_add_range(u8 target, u8 attr, u32 remap);
+
#endif /* __LINUX_MBUS_H */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 6caed01c99..0ec1320b2f 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -91,9 +91,6 @@ struct pci_dev {
struct list_head bus_list; /* node in per-bus list */
struct pci_bus *bus; /* bus this device is on */
struct pci_bus *subordinate; /* bus this device bridges to */
-
- void *sysdata; /* hook for sys-specific extension */
- struct proc_dir_entry *procent; /* device entry in /proc/bus/pci */
struct pci_slot *slot; /* Physical slot this device is in */
struct device_d dev;
@@ -118,6 +115,7 @@ struct pci_dev {
#define to_pci_dev(dev) container_of(dev, struct pci_dev, dev)
struct pci_bus {
+ struct pci_controller *host; /* associated host controller */
struct list_head node; /* node in list of buses */
struct list_head children; /* list of child buses */
struct list_head devices; /* list of devices on this bus */
@@ -126,8 +124,6 @@ struct pci_bus {
struct list_head resources; /* address space routed to this bus */
struct pci_ops *ops; /* configuration access functions */
- void *sysdata; /* hook for sys-specific extension */
- struct proc_dir_entry *procdir; /* directory entry in /proc/bus/pci */
unsigned char number; /* bus number */
unsigned char primary; /* number of primary bridge */
@@ -167,10 +163,8 @@ struct pci_controller {
unsigned int index;
- /* Optional access methods for reading/writing the bus number
- of the PCI controller */
- int (*get_busno)(void);
- void (*set_busno)(int busno);
+ /* Optional access method for writing the bus number */
+ void (*set_busno)(struct pci_controller *host, int busno);
};
struct pci_driver {
diff --git a/include/of_pci.h b/include/of_pci.h
new file mode 100644
index 0000000000..c95cb0135a
--- /dev/null
+++ b/include/of_pci.h
@@ -0,0 +1,17 @@
+#ifndef __OF_PCI_H
+#define __OF_PCI_H
+
+#include <linux/pci.h>
+
+#ifdef CONFIG_OF_PCI
+int of_pci_get_devfn(struct device_node *np);
+
+#else
+static inline int of_pci_get_devfn(struct device_node *np)
+{
+ return -EINVAL;
+}
+
+#endif
+
+#endif