diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 2d024dc..a3208d2 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -102,6 +102,7 @@ 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 abc3ccb..ae4ff2a 100644 --- a/arch/arm/cpu/dtb.c +++ b/arch/arm/cpu/dtb.c @@ -50,6 +50,7 @@ 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 de37a75..3156781 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 = ; - 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 611d727..e88f1dc 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 = ; - internal-regs { gpio_leds { red_led { diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index 18f61f7..131f3a6 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -14,11 +14,13 @@ 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 e416a38..f2b991e 100644 --- a/arch/arm/mach-mvebu/armada-370-xp.c +++ b/arch/arm/mach-mvebu/armada-370-xp.c @@ -18,6 +18,7 @@ #include #include #include +#include #include static inline void armada_370_xp_memory_find(unsigned long *phys_base, @@ -46,12 +47,20 @@ 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 b054bf5..ac4b332 100644 --- a/arch/arm/mach-mvebu/common.c +++ b/arch/arm/mach-mvebu/common.c @@ -79,3 +79,62 @@ 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 bcbf4b8..69c6436 100644 --- a/arch/arm/mach-mvebu/dove.c +++ b/arch/arm/mach-mvebu/dove.c @@ -18,6 +18,7 @@ #include #include #include +#include #include static inline void dove_remap_mc_regs(void) @@ -76,7 +77,10 @@ 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 5fd16e5..ccc687c 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 3cc1bf7..9f6118e 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 fe9ca9c..c114bdb 100644 --- a/arch/arm/mach-mvebu/kirkwood.c +++ b/arch/arm/mach-mvebu/kirkwood.c @@ -17,6 +17,7 @@ #include #include #include +#include #include static inline void kirkwood_memory_find(unsigned long *phys_base, @@ -50,7 +51,9 @@ 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 11e3777..b7f7836 100644 --- a/drivers/bus/mvebu-mbus.c +++ b/drivers/bus/mvebu-mbus.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -187,7 +188,7 @@ 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 @@ if (!enabled) continue; - wend = wbase + wsize; + wend = wbase + wsize - 1; /* * Check if the current window overlaps with the @@ -546,7 +547,7 @@ * - 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 @@ 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 @@ 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 @@ 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: + * + * + * whereas for Armada 370, there's just one: + * + * + * For instance, the following tuple: + * + * + * would be fixed-up like: + * + */ + 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 2b28cf3..8195506 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -27,6 +27,12 @@ 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 c883e51..0dc2f8d 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 0000000..2d0fbd2 --- /dev/null +++ b/drivers/of/of_pci.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include + +/** + * 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 9e46592..d17a151 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -24,6 +24,12 @@ 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 edac1a5..4423531 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -6,3 +6,5 @@ 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 0000000..55a1d39 --- /dev/null +++ b/drivers/pci/pci-mvebu-phy.c @@ -0,0 +1,208 @@ +/* + * SoC specific PCIe PHY setup for Marvell MVEBU SoCs + * + * Sebastian Hesselbarth + * + * 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 +#include +#include + +#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 0000000..45befbb --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 0000000..8ced9fe --- /dev/null +++ b/drivers/pci/pci-mvebu.h @@ -0,0 +1,37 @@ +/* + * PCIe include for Marvell MVEBU SoCs + * + * Sebastian Hesselbarth + * + * 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 + +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 3d88b0f..a1b7680 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -11,6 +11,7 @@ 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 @@ 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 @@ 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 @@ 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 f5cf608..be154ed 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 05f320d..6255a5f 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 0000000..4778358 --- /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 + * + * 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 +#include +#include +#include +#include +#include +#include + +#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 0000000..9f79d37 --- /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 + * + * 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 +#include +#include +#include +#include +#include +#include + +#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 578ff33..ac14982 100644 --- a/include/linux/mbus.h +++ b/include/linux/mbus.h @@ -58,4 +58,6 @@ 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 6caed01..0ec1320 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -91,9 +91,6 @@ 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 @@ #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 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 @@ 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 0000000..c95cb01 --- /dev/null +++ b/include/of_pci.h @@ -0,0 +1,17 @@ +#ifndef __OF_PCI_H +#define __OF_PCI_H + +#include + +#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