183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0
29c28d61cSAnton Schubert /*
39c28d61cSAnton Schubert * PCIe driver for Marvell MVEBU SoCs
49c28d61cSAnton Schubert *
59c28d61cSAnton Schubert * Based on Barebox drivers/pci/pci-mvebu.c
69c28d61cSAnton Schubert *
79c28d61cSAnton Schubert * Ported to U-Boot by:
89c28d61cSAnton Schubert * Anton Schubert <anton.schubert@gmx.de>
99c28d61cSAnton Schubert * Stefan Roese <sr@denx.de>
109c28d61cSAnton Schubert */
119c28d61cSAnton Schubert
129c28d61cSAnton Schubert #include <common.h>
1394f453eaSStefan Roese #include <dm.h>
1494f453eaSStefan Roese #include <dm/device-internal.h>
1594f453eaSStefan Roese #include <dm/lists.h>
1694f453eaSStefan Roese #include <dm/of_access.h>
179c28d61cSAnton Schubert #include <pci.h>
189c28d61cSAnton Schubert #include <asm/io.h>
199c28d61cSAnton Schubert #include <asm/arch/cpu.h>
209c28d61cSAnton Schubert #include <asm/arch/soc.h>
2194f453eaSStefan Roese #include <linux/errno.h>
2294f453eaSStefan Roese #include <linux/ioport.h>
239c28d61cSAnton Schubert #include <linux/mbus.h>
249c28d61cSAnton Schubert
259c28d61cSAnton Schubert DECLARE_GLOBAL_DATA_PTR;
269c28d61cSAnton Schubert
279c28d61cSAnton Schubert /* PCIe unit register offsets */
289c28d61cSAnton Schubert #define SELECT(x, n) ((x >> n) & 1UL)
299c28d61cSAnton Schubert
309c28d61cSAnton Schubert #define PCIE_DEV_ID_OFF 0x0000
319c28d61cSAnton Schubert #define PCIE_CMD_OFF 0x0004
329c28d61cSAnton Schubert #define PCIE_DEV_REV_OFF 0x0008
339c28d61cSAnton Schubert #define PCIE_BAR_LO_OFF(n) (0x0010 + ((n) << 3))
349c28d61cSAnton Schubert #define PCIE_BAR_HI_OFF(n) (0x0014 + ((n) << 3))
359c28d61cSAnton Schubert #define PCIE_CAPAB_OFF 0x0060
369c28d61cSAnton Schubert #define PCIE_CTRL_STAT_OFF 0x0068
379c28d61cSAnton Schubert #define PCIE_HEADER_LOG_4_OFF 0x0128
389c28d61cSAnton Schubert #define PCIE_BAR_CTRL_OFF(n) (0x1804 + (((n) - 1) * 4))
399c28d61cSAnton Schubert #define PCIE_WIN04_CTRL_OFF(n) (0x1820 + ((n) << 4))
409c28d61cSAnton Schubert #define PCIE_WIN04_BASE_OFF(n) (0x1824 + ((n) << 4))
419c28d61cSAnton Schubert #define PCIE_WIN04_REMAP_OFF(n) (0x182c + ((n) << 4))
429c28d61cSAnton Schubert #define PCIE_WIN5_CTRL_OFF 0x1880
439c28d61cSAnton Schubert #define PCIE_WIN5_BASE_OFF 0x1884
449c28d61cSAnton Schubert #define PCIE_WIN5_REMAP_OFF 0x188c
459c28d61cSAnton Schubert #define PCIE_CONF_ADDR_OFF 0x18f8
469c28d61cSAnton Schubert #define PCIE_CONF_ADDR_EN BIT(31)
479c28d61cSAnton Schubert #define PCIE_CONF_REG(r) ((((r) & 0xf00) << 16) | ((r) & 0xfc))
489c28d61cSAnton Schubert #define PCIE_CONF_BUS(b) (((b) & 0xff) << 16)
499c28d61cSAnton Schubert #define PCIE_CONF_DEV(d) (((d) & 0x1f) << 11)
509c28d61cSAnton Schubert #define PCIE_CONF_FUNC(f) (((f) & 0x7) << 8)
519c28d61cSAnton Schubert #define PCIE_CONF_ADDR(dev, reg) \
529c28d61cSAnton Schubert (PCIE_CONF_BUS(PCI_BUS(dev)) | PCIE_CONF_DEV(PCI_DEV(dev)) | \
539c28d61cSAnton Schubert PCIE_CONF_FUNC(PCI_FUNC(dev)) | PCIE_CONF_REG(reg) | \
549c28d61cSAnton Schubert PCIE_CONF_ADDR_EN)
559c28d61cSAnton Schubert #define PCIE_CONF_DATA_OFF 0x18fc
569c28d61cSAnton Schubert #define PCIE_MASK_OFF 0x1910
579c28d61cSAnton Schubert #define PCIE_MASK_ENABLE_INTS (0xf << 24)
589c28d61cSAnton Schubert #define PCIE_CTRL_OFF 0x1a00
599c28d61cSAnton Schubert #define PCIE_CTRL_X1_MODE BIT(0)
609c28d61cSAnton Schubert #define PCIE_STAT_OFF 0x1a04
619c28d61cSAnton Schubert #define PCIE_STAT_BUS (0xff << 8)
629c28d61cSAnton Schubert #define PCIE_STAT_DEV (0x1f << 16)
639c28d61cSAnton Schubert #define PCIE_STAT_LINK_DOWN BIT(0)
649c28d61cSAnton Schubert #define PCIE_DEBUG_CTRL 0x1a60
659c28d61cSAnton Schubert #define PCIE_DEBUG_SOFT_RESET BIT(20)
669c28d61cSAnton Schubert
679c28d61cSAnton Schubert struct mvebu_pcie {
689c28d61cSAnton Schubert struct pci_controller hose;
699c28d61cSAnton Schubert void __iomem *base;
709c28d61cSAnton Schubert void __iomem *membase;
719c28d61cSAnton Schubert struct resource mem;
729c28d61cSAnton Schubert void __iomem *iobase;
739c28d61cSAnton Schubert u32 port;
749c28d61cSAnton Schubert u32 lane;
7594f453eaSStefan Roese int devfn;
769c28d61cSAnton Schubert u32 lane_mask;
779c28d61cSAnton Schubert pci_dev_t dev;
7894f453eaSStefan Roese char name[16];
7994f453eaSStefan Roese unsigned int mem_target;
8094f453eaSStefan Roese unsigned int mem_attr;
819c28d61cSAnton Schubert };
829c28d61cSAnton Schubert
839c28d61cSAnton Schubert /*
849c28d61cSAnton Schubert * MVEBU PCIe controller needs MEMORY and I/O BARs to be mapped
8549b23e03SVlaoMao * into SoCs address space. Each controller will map 128M of MEM
869c28d61cSAnton Schubert * and 64K of I/O space when registered.
879c28d61cSAnton Schubert */
889c28d61cSAnton Schubert static void __iomem *mvebu_pcie_membase = (void __iomem *)MBUS_PCI_MEM_BASE;
8949b23e03SVlaoMao #define PCIE_MEM_SIZE (128 << 20)
909c28d61cSAnton Schubert
mvebu_pcie_link_up(struct mvebu_pcie * pcie)919c28d61cSAnton Schubert static inline bool mvebu_pcie_link_up(struct mvebu_pcie *pcie)
929c28d61cSAnton Schubert {
939c28d61cSAnton Schubert u32 val;
949c28d61cSAnton Schubert val = readl(pcie->base + PCIE_STAT_OFF);
959c28d61cSAnton Schubert return !(val & PCIE_STAT_LINK_DOWN);
969c28d61cSAnton Schubert }
979c28d61cSAnton Schubert
mvebu_pcie_set_local_bus_nr(struct mvebu_pcie * pcie,int busno)989c28d61cSAnton Schubert static void mvebu_pcie_set_local_bus_nr(struct mvebu_pcie *pcie, int busno)
999c28d61cSAnton Schubert {
1009c28d61cSAnton Schubert u32 stat;
1019c28d61cSAnton Schubert
1029c28d61cSAnton Schubert stat = readl(pcie->base + PCIE_STAT_OFF);
1039c28d61cSAnton Schubert stat &= ~PCIE_STAT_BUS;
1049c28d61cSAnton Schubert stat |= busno << 8;
1059c28d61cSAnton Schubert writel(stat, pcie->base + PCIE_STAT_OFF);
1069c28d61cSAnton Schubert }
1079c28d61cSAnton Schubert
mvebu_pcie_set_local_dev_nr(struct mvebu_pcie * pcie,int devno)1089c28d61cSAnton Schubert static void mvebu_pcie_set_local_dev_nr(struct mvebu_pcie *pcie, int devno)
1099c28d61cSAnton Schubert {
1109c28d61cSAnton Schubert u32 stat;
1119c28d61cSAnton Schubert
1129c28d61cSAnton Schubert stat = readl(pcie->base + PCIE_STAT_OFF);
1139c28d61cSAnton Schubert stat &= ~PCIE_STAT_DEV;
1149c28d61cSAnton Schubert stat |= devno << 16;
1159c28d61cSAnton Schubert writel(stat, pcie->base + PCIE_STAT_OFF);
1169c28d61cSAnton Schubert }
1179c28d61cSAnton Schubert
mvebu_pcie_get_local_bus_nr(struct mvebu_pcie * pcie)1189c28d61cSAnton Schubert static int mvebu_pcie_get_local_bus_nr(struct mvebu_pcie *pcie)
1199c28d61cSAnton Schubert {
1209c28d61cSAnton Schubert u32 stat;
1219c28d61cSAnton Schubert
1229c28d61cSAnton Schubert stat = readl(pcie->base + PCIE_STAT_OFF);
1239c28d61cSAnton Schubert return (stat & PCIE_STAT_BUS) >> 8;
1249c28d61cSAnton Schubert }
1259c28d61cSAnton Schubert
mvebu_pcie_get_local_dev_nr(struct mvebu_pcie * pcie)1269c28d61cSAnton Schubert static int mvebu_pcie_get_local_dev_nr(struct mvebu_pcie *pcie)
1279c28d61cSAnton Schubert {
1289c28d61cSAnton Schubert u32 stat;
1299c28d61cSAnton Schubert
1309c28d61cSAnton Schubert stat = readl(pcie->base + PCIE_STAT_OFF);
1319c28d61cSAnton Schubert return (stat & PCIE_STAT_DEV) >> 16;
1329c28d61cSAnton Schubert }
1339c28d61cSAnton Schubert
hose_to_pcie(struct pci_controller * hose)1349c28d61cSAnton Schubert static inline struct mvebu_pcie *hose_to_pcie(struct pci_controller *hose)
1359c28d61cSAnton Schubert {
1369c28d61cSAnton Schubert return container_of(hose, struct mvebu_pcie, hose);
1379c28d61cSAnton Schubert }
1389c28d61cSAnton Schubert
mvebu_pcie_read_config(struct udevice * bus,pci_dev_t bdf,uint offset,ulong * valuep,enum pci_size_t size)13994f453eaSStefan Roese static int mvebu_pcie_read_config(struct udevice *bus, pci_dev_t bdf,
14094f453eaSStefan Roese uint offset, ulong *valuep,
14194f453eaSStefan Roese enum pci_size_t size)
1429c28d61cSAnton Schubert {
14394f453eaSStefan Roese struct mvebu_pcie *pcie = dev_get_platdata(bus);
1449c28d61cSAnton Schubert int local_bus = PCI_BUS(pcie->dev);
1459c28d61cSAnton Schubert int local_dev = PCI_DEV(pcie->dev);
1469c28d61cSAnton Schubert u32 reg;
14794f453eaSStefan Roese u32 data;
14894f453eaSStefan Roese
14994f453eaSStefan Roese debug("PCIE CFG read: (b,d,f)=(%2d,%2d,%2d) ",
15094f453eaSStefan Roese PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
1519c28d61cSAnton Schubert
1529c28d61cSAnton Schubert /* Only allow one other device besides the local one on the local bus */
15394f453eaSStefan Roese if (PCI_BUS(bdf) == local_bus && PCI_DEV(bdf) != local_dev) {
15494f453eaSStefan Roese if (local_dev == 0 && PCI_DEV(bdf) != 1) {
15594f453eaSStefan Roese debug("- out of range\n");
1569c28d61cSAnton Schubert /*
1579c28d61cSAnton Schubert * If local dev is 0, the first other dev can
1589c28d61cSAnton Schubert * only be 1
1599c28d61cSAnton Schubert */
16094f453eaSStefan Roese *valuep = pci_get_ff(size);
16194f453eaSStefan Roese return 0;
16294f453eaSStefan Roese } else if (local_dev != 0 && PCI_DEV(bdf) != 0) {
16394f453eaSStefan Roese debug("- out of range\n");
1649c28d61cSAnton Schubert /*
1659c28d61cSAnton Schubert * If local dev is not 0, the first other dev can
1669c28d61cSAnton Schubert * only be 0
1679c28d61cSAnton Schubert */
16894f453eaSStefan Roese *valuep = pci_get_ff(size);
16994f453eaSStefan Roese return 0;
1709c28d61cSAnton Schubert }
1719c28d61cSAnton Schubert }
1729c28d61cSAnton Schubert
1739c28d61cSAnton Schubert /* write address */
17494f453eaSStefan Roese reg = PCIE_CONF_ADDR(bdf, offset);
1759c28d61cSAnton Schubert writel(reg, pcie->base + PCIE_CONF_ADDR_OFF);
17694f453eaSStefan Roese data = readl(pcie->base + PCIE_CONF_DATA_OFF);
17794f453eaSStefan Roese debug("(addr,val)=(0x%04x, 0x%08x)\n", offset, data);
17894f453eaSStefan Roese *valuep = pci_conv_32_to_size(data, offset, size);
1799c28d61cSAnton Schubert
1809c28d61cSAnton Schubert return 0;
1819c28d61cSAnton Schubert }
1829c28d61cSAnton Schubert
mvebu_pcie_write_config(struct udevice * bus,pci_dev_t bdf,uint offset,ulong value,enum pci_size_t size)18394f453eaSStefan Roese static int mvebu_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
18494f453eaSStefan Roese uint offset, ulong value,
18594f453eaSStefan Roese enum pci_size_t size)
1869c28d61cSAnton Schubert {
18794f453eaSStefan Roese struct mvebu_pcie *pcie = dev_get_platdata(bus);
1889c28d61cSAnton Schubert int local_bus = PCI_BUS(pcie->dev);
1899c28d61cSAnton Schubert int local_dev = PCI_DEV(pcie->dev);
19094f453eaSStefan Roese u32 data;
19194f453eaSStefan Roese
19294f453eaSStefan Roese debug("PCIE CFG write: (b,d,f)=(%2d,%2d,%2d) ",
19394f453eaSStefan Roese PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
19494f453eaSStefan Roese debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
1959c28d61cSAnton Schubert
1969c28d61cSAnton Schubert /* Only allow one other device besides the local one on the local bus */
19794f453eaSStefan Roese if (PCI_BUS(bdf) == local_bus && PCI_DEV(bdf) != local_dev) {
19894f453eaSStefan Roese if (local_dev == 0 && PCI_DEV(bdf) != 1) {
1999c28d61cSAnton Schubert /*
2009c28d61cSAnton Schubert * If local dev is 0, the first other dev can
2019c28d61cSAnton Schubert * only be 1
2029c28d61cSAnton Schubert */
20394f453eaSStefan Roese return 0;
20494f453eaSStefan Roese } else if (local_dev != 0 && PCI_DEV(bdf) != 0) {
2059c28d61cSAnton Schubert /*
2069c28d61cSAnton Schubert * If local dev is not 0, the first other dev can
2079c28d61cSAnton Schubert * only be 0
2089c28d61cSAnton Schubert */
20994f453eaSStefan Roese return 0;
2109c28d61cSAnton Schubert }
2119c28d61cSAnton Schubert }
2129c28d61cSAnton Schubert
21394f453eaSStefan Roese writel(PCIE_CONF_ADDR(bdf, offset), pcie->base + PCIE_CONF_ADDR_OFF);
21494f453eaSStefan Roese data = pci_conv_size_to_32(0, value, offset, size);
21594f453eaSStefan Roese writel(data, pcie->base + PCIE_CONF_DATA_OFF);
2169c28d61cSAnton Schubert
2179c28d61cSAnton Schubert return 0;
2189c28d61cSAnton Schubert }
2199c28d61cSAnton Schubert
2209c28d61cSAnton Schubert /*
2219c28d61cSAnton Schubert * Setup PCIE BARs and Address Decode Wins:
2229c28d61cSAnton Schubert * BAR[0,2] -> disabled, BAR[1] -> covers all DRAM banks
2239c28d61cSAnton Schubert * WIN[0-3] -> DRAM bank[0-3]
2249c28d61cSAnton Schubert */
mvebu_pcie_setup_wins(struct mvebu_pcie * pcie)2259c28d61cSAnton Schubert static void mvebu_pcie_setup_wins(struct mvebu_pcie *pcie)
2269c28d61cSAnton Schubert {
2279c28d61cSAnton Schubert const struct mbus_dram_target_info *dram = mvebu_mbus_dram_info();
2289c28d61cSAnton Schubert u32 size;
2299c28d61cSAnton Schubert int i;
2309c28d61cSAnton Schubert
2319c28d61cSAnton Schubert /* First, disable and clear BARs and windows. */
2329c28d61cSAnton Schubert for (i = 1; i < 3; i++) {
2339c28d61cSAnton Schubert writel(0, pcie->base + PCIE_BAR_CTRL_OFF(i));
2349c28d61cSAnton Schubert writel(0, pcie->base + PCIE_BAR_LO_OFF(i));
2359c28d61cSAnton Schubert writel(0, pcie->base + PCIE_BAR_HI_OFF(i));
2369c28d61cSAnton Schubert }
2379c28d61cSAnton Schubert
2389c28d61cSAnton Schubert for (i = 0; i < 5; i++) {
2399c28d61cSAnton Schubert writel(0, pcie->base + PCIE_WIN04_CTRL_OFF(i));
2409c28d61cSAnton Schubert writel(0, pcie->base + PCIE_WIN04_BASE_OFF(i));
2419c28d61cSAnton Schubert writel(0, pcie->base + PCIE_WIN04_REMAP_OFF(i));
2429c28d61cSAnton Schubert }
2439c28d61cSAnton Schubert
2449c28d61cSAnton Schubert writel(0, pcie->base + PCIE_WIN5_CTRL_OFF);
2459c28d61cSAnton Schubert writel(0, pcie->base + PCIE_WIN5_BASE_OFF);
2469c28d61cSAnton Schubert writel(0, pcie->base + PCIE_WIN5_REMAP_OFF);
2479c28d61cSAnton Schubert
2489c28d61cSAnton Schubert /* Setup windows for DDR banks. Count total DDR size on the fly. */
2499c28d61cSAnton Schubert size = 0;
2509c28d61cSAnton Schubert for (i = 0; i < dram->num_cs; i++) {
2519c28d61cSAnton Schubert const struct mbus_dram_window *cs = dram->cs + i;
2529c28d61cSAnton Schubert
2539c28d61cSAnton Schubert writel(cs->base & 0xffff0000,
2549c28d61cSAnton Schubert pcie->base + PCIE_WIN04_BASE_OFF(i));
2559c28d61cSAnton Schubert writel(0, pcie->base + PCIE_WIN04_REMAP_OFF(i));
2569c28d61cSAnton Schubert writel(((cs->size - 1) & 0xffff0000) |
2579c28d61cSAnton Schubert (cs->mbus_attr << 8) |
2589c28d61cSAnton Schubert (dram->mbus_dram_target_id << 4) | 1,
2599c28d61cSAnton Schubert pcie->base + PCIE_WIN04_CTRL_OFF(i));
2609c28d61cSAnton Schubert
2619c28d61cSAnton Schubert size += cs->size;
2629c28d61cSAnton Schubert }
2639c28d61cSAnton Schubert
2649c28d61cSAnton Schubert /* Round up 'size' to the nearest power of two. */
2659c28d61cSAnton Schubert if ((size & (size - 1)) != 0)
2669c28d61cSAnton Schubert size = 1 << fls(size);
2679c28d61cSAnton Schubert
2689c28d61cSAnton Schubert /* Setup BAR[1] to all DRAM banks. */
2699c28d61cSAnton Schubert writel(dram->cs[0].base | 0xc, pcie->base + PCIE_BAR_LO_OFF(1));
2709c28d61cSAnton Schubert writel(0, pcie->base + PCIE_BAR_HI_OFF(1));
2719c28d61cSAnton Schubert writel(((size - 1) & 0xffff0000) | 0x1,
2729c28d61cSAnton Schubert pcie->base + PCIE_BAR_CTRL_OFF(1));
2739c28d61cSAnton Schubert }
2749c28d61cSAnton Schubert
mvebu_pcie_probe(struct udevice * dev)27594f453eaSStefan Roese static int mvebu_pcie_probe(struct udevice *dev)
2769c28d61cSAnton Schubert {
27794f453eaSStefan Roese struct mvebu_pcie *pcie = dev_get_platdata(dev);
27894f453eaSStefan Roese struct udevice *ctlr = pci_get_controller(dev);
27994f453eaSStefan Roese struct pci_controller *hose = dev_get_uclass_priv(ctlr);
28094f453eaSStefan Roese static int bus;
2819c28d61cSAnton Schubert u32 reg;
2829c28d61cSAnton Schubert
2839c28d61cSAnton Schubert debug("%s: PCIe %d.%d - up, base %08x\n", __func__,
2849c28d61cSAnton Schubert pcie->port, pcie->lane, (u32)pcie->base);
2859c28d61cSAnton Schubert
2869c28d61cSAnton Schubert /* Read Id info and local bus/dev */
2879c28d61cSAnton Schubert debug("direct conf read %08x, local bus %d, local dev %d\n",
2889c28d61cSAnton Schubert readl(pcie->base), mvebu_pcie_get_local_bus_nr(pcie),
2899c28d61cSAnton Schubert mvebu_pcie_get_local_dev_nr(pcie));
2909c28d61cSAnton Schubert
2919c28d61cSAnton Schubert mvebu_pcie_set_local_bus_nr(pcie, bus);
2929c28d61cSAnton Schubert mvebu_pcie_set_local_dev_nr(pcie, 0);
2939c28d61cSAnton Schubert pcie->dev = PCI_BDF(bus, 0, 0);
2949c28d61cSAnton Schubert
2959c28d61cSAnton Schubert pcie->mem.start = (u32)mvebu_pcie_membase;
2969c28d61cSAnton Schubert pcie->mem.end = pcie->mem.start + PCIE_MEM_SIZE - 1;
2979c28d61cSAnton Schubert mvebu_pcie_membase += PCIE_MEM_SIZE;
2989c28d61cSAnton Schubert
29994f453eaSStefan Roese if (mvebu_mbus_add_window_by_id(pcie->mem_target, pcie->mem_attr,
3009c28d61cSAnton Schubert (phys_addr_t)pcie->mem.start,
3019c28d61cSAnton Schubert PCIE_MEM_SIZE)) {
3029c28d61cSAnton Schubert printf("PCIe unable to add mbus window for mem at %08x+%08x\n",
3039c28d61cSAnton Schubert (u32)pcie->mem.start, PCIE_MEM_SIZE);
3049c28d61cSAnton Schubert }
3059c28d61cSAnton Schubert
3069c28d61cSAnton Schubert /* Setup windows and configure host bridge */
3079c28d61cSAnton Schubert mvebu_pcie_setup_wins(pcie);
3089c28d61cSAnton Schubert
3099c28d61cSAnton Schubert /* Master + slave enable. */
3109c28d61cSAnton Schubert reg = readl(pcie->base + PCIE_CMD_OFF);
3119c28d61cSAnton Schubert reg |= PCI_COMMAND_MEMORY;
3129c28d61cSAnton Schubert reg |= PCI_COMMAND_MASTER;
3139c28d61cSAnton Schubert reg |= BIT(10); /* disable interrupts */
3149c28d61cSAnton Schubert writel(reg, pcie->base + PCIE_CMD_OFF);
3159c28d61cSAnton Schubert
31694f453eaSStefan Roese /* Set BAR0 to internal registers */
31794f453eaSStefan Roese writel(SOC_REGS_PHY_BASE, pcie->base + PCIE_BAR_LO_OFF(0));
31894f453eaSStefan Roese writel(0, pcie->base + PCIE_BAR_HI_OFF(0));
3199c28d61cSAnton Schubert
3209c28d61cSAnton Schubert /* PCI memory space */
3219c28d61cSAnton Schubert pci_set_region(hose->regions + 0, pcie->mem.start,
3229c28d61cSAnton Schubert pcie->mem.start, PCIE_MEM_SIZE, PCI_REGION_MEM);
3239c28d61cSAnton Schubert pci_set_region(hose->regions + 1,
3249c28d61cSAnton Schubert 0, 0,
3259c28d61cSAnton Schubert gd->ram_size,
3269c28d61cSAnton Schubert PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
3279c28d61cSAnton Schubert hose->region_count = 2;
3289c28d61cSAnton Schubert
32994f453eaSStefan Roese bus++;
3309c28d61cSAnton Schubert
33194f453eaSStefan Roese return 0;
33294f453eaSStefan Roese }
3339c28d61cSAnton Schubert
mvebu_pcie_port_parse_dt(ofnode node,struct mvebu_pcie * pcie)33494f453eaSStefan Roese static int mvebu_pcie_port_parse_dt(ofnode node, struct mvebu_pcie *pcie)
33594f453eaSStefan Roese {
33694f453eaSStefan Roese const u32 *addr;
33794f453eaSStefan Roese int len;
3389c28d61cSAnton Schubert
33994f453eaSStefan Roese addr = ofnode_get_property(node, "assigned-addresses", &len);
34094f453eaSStefan Roese if (!addr) {
34194f453eaSStefan Roese pr_err("property \"assigned-addresses\" not found");
34294f453eaSStefan Roese return -FDT_ERR_NOTFOUND;
34394f453eaSStefan Roese }
3449a045278SPhil Sutter
34594f453eaSStefan Roese pcie->base = (void *)(fdt32_to_cpu(addr[2]) + SOC_REGS_PHY_BASE);
34694f453eaSStefan Roese
34794f453eaSStefan Roese return 0;
34894f453eaSStefan Roese }
34994f453eaSStefan Roese
35094f453eaSStefan Roese #define DT_FLAGS_TO_TYPE(flags) (((flags) >> 24) & 0x03)
35194f453eaSStefan Roese #define DT_TYPE_IO 0x1
35294f453eaSStefan Roese #define DT_TYPE_MEM32 0x2
35394f453eaSStefan Roese #define DT_CPUADDR_TO_TARGET(cpuaddr) (((cpuaddr) >> 56) & 0xFF)
35494f453eaSStefan Roese #define DT_CPUADDR_TO_ATTR(cpuaddr) (((cpuaddr) >> 48) & 0xFF)
35594f453eaSStefan Roese
mvebu_get_tgt_attr(ofnode node,int devfn,unsigned long type,unsigned int * tgt,unsigned int * attr)35694f453eaSStefan Roese static int mvebu_get_tgt_attr(ofnode node, int devfn,
35794f453eaSStefan Roese unsigned long type,
35894f453eaSStefan Roese unsigned int *tgt,
35994f453eaSStefan Roese unsigned int *attr)
36094f453eaSStefan Roese {
36194f453eaSStefan Roese const int na = 3, ns = 2;
36294f453eaSStefan Roese const __be32 *range;
36394f453eaSStefan Roese int rlen, nranges, rangesz, pna, i;
36494f453eaSStefan Roese
36594f453eaSStefan Roese *tgt = -1;
36694f453eaSStefan Roese *attr = -1;
36794f453eaSStefan Roese
36894f453eaSStefan Roese range = ofnode_get_property(node, "ranges", &rlen);
36994f453eaSStefan Roese if (!range)
37094f453eaSStefan Roese return -EINVAL;
37194f453eaSStefan Roese
372*0df62e8dSStefan Roese /*
373*0df62e8dSStefan Roese * Linux uses of_n_addr_cells() to get the number of address cells
374*0df62e8dSStefan Roese * here. Currently this function is only available in U-Boot when
375*0df62e8dSStefan Roese * CONFIG_OF_LIVE is enabled. Until this is enabled for MVEBU in
376*0df62e8dSStefan Roese * general, lets't hardcode the "pna" value in the U-Boot code.
377*0df62e8dSStefan Roese */
37894f453eaSStefan Roese pna = 2; /* hardcoded for now because of lack of of_n_addr_cells() */
37994f453eaSStefan Roese rangesz = pna + na + ns;
38094f453eaSStefan Roese nranges = rlen / sizeof(__be32) / rangesz;
38194f453eaSStefan Roese
38294f453eaSStefan Roese for (i = 0; i < nranges; i++, range += rangesz) {
38394f453eaSStefan Roese u32 flags = of_read_number(range, 1);
38494f453eaSStefan Roese u32 slot = of_read_number(range + 1, 1);
38594f453eaSStefan Roese u64 cpuaddr = of_read_number(range + na, pna);
38694f453eaSStefan Roese unsigned long rtype;
38794f453eaSStefan Roese
38894f453eaSStefan Roese if (DT_FLAGS_TO_TYPE(flags) == DT_TYPE_IO)
38994f453eaSStefan Roese rtype = IORESOURCE_IO;
39094f453eaSStefan Roese else if (DT_FLAGS_TO_TYPE(flags) == DT_TYPE_MEM32)
39194f453eaSStefan Roese rtype = IORESOURCE_MEM;
39294f453eaSStefan Roese else
39394f453eaSStefan Roese continue;
39494f453eaSStefan Roese
39594f453eaSStefan Roese /*
39694f453eaSStefan Roese * The Linux code used PCI_SLOT() here, which expects devfn
39794f453eaSStefan Roese * in bits 7..0. PCI_DEV() in U-Boot is similar to PCI_SLOT(),
39894f453eaSStefan Roese * only expects devfn in 15..8, where its saved in this driver.
39994f453eaSStefan Roese */
40094f453eaSStefan Roese if (slot == PCI_DEV(devfn) && type == rtype) {
40194f453eaSStefan Roese *tgt = DT_CPUADDR_TO_TARGET(cpuaddr);
40294f453eaSStefan Roese *attr = DT_CPUADDR_TO_ATTR(cpuaddr);
40394f453eaSStefan Roese return 0;
4049a045278SPhil Sutter }
4059c28d61cSAnton Schubert }
40694f453eaSStefan Roese
40794f453eaSStefan Roese return -ENOENT;
4089c28d61cSAnton Schubert }
40994f453eaSStefan Roese
mvebu_pcie_ofdata_to_platdata(struct udevice * dev)41094f453eaSStefan Roese static int mvebu_pcie_ofdata_to_platdata(struct udevice *dev)
41194f453eaSStefan Roese {
41294f453eaSStefan Roese struct mvebu_pcie *pcie = dev_get_platdata(dev);
41394f453eaSStefan Roese int ret = 0;
41494f453eaSStefan Roese
41594f453eaSStefan Roese /* Get port number, lane number and memory target / attr */
41694f453eaSStefan Roese if (ofnode_read_u32(dev_ofnode(dev), "marvell,pcie-port",
41794f453eaSStefan Roese &pcie->port)) {
41894f453eaSStefan Roese ret = -ENODEV;
41994f453eaSStefan Roese goto err;
42094f453eaSStefan Roese }
42194f453eaSStefan Roese
42294f453eaSStefan Roese if (ofnode_read_u32(dev_ofnode(dev), "marvell,pcie-lane", &pcie->lane))
42394f453eaSStefan Roese pcie->lane = 0;
42494f453eaSStefan Roese
42594f453eaSStefan Roese sprintf(pcie->name, "pcie%d.%d", pcie->port, pcie->lane);
42694f453eaSStefan Roese
42794f453eaSStefan Roese /* pci_get_devfn() returns devfn in bits 15..8, see PCI_DEV usage */
42894f453eaSStefan Roese pcie->devfn = pci_get_devfn(dev);
42994f453eaSStefan Roese if (pcie->devfn < 0) {
43094f453eaSStefan Roese ret = -ENODEV;
43194f453eaSStefan Roese goto err;
43294f453eaSStefan Roese }
43394f453eaSStefan Roese
43494f453eaSStefan Roese ret = mvebu_get_tgt_attr(dev_ofnode(dev->parent), pcie->devfn,
43594f453eaSStefan Roese IORESOURCE_MEM,
43694f453eaSStefan Roese &pcie->mem_target, &pcie->mem_attr);
43794f453eaSStefan Roese if (ret < 0) {
43894f453eaSStefan Roese printf("%s: cannot get tgt/attr for mem window\n", pcie->name);
43994f453eaSStefan Roese goto err;
44094f453eaSStefan Roese }
44194f453eaSStefan Roese
44294f453eaSStefan Roese /* Parse PCIe controller register base from DT */
44394f453eaSStefan Roese ret = mvebu_pcie_port_parse_dt(dev_ofnode(dev), pcie);
44494f453eaSStefan Roese if (ret < 0)
44594f453eaSStefan Roese goto err;
44694f453eaSStefan Roese
44794f453eaSStefan Roese /* Check link and skip ports that have no link */
44894f453eaSStefan Roese if (!mvebu_pcie_link_up(pcie)) {
44994f453eaSStefan Roese debug("%s: %s - down\n", __func__, pcie->name);
45094f453eaSStefan Roese ret = -ENODEV;
45194f453eaSStefan Roese goto err;
45294f453eaSStefan Roese }
45394f453eaSStefan Roese
45494f453eaSStefan Roese return 0;
45594f453eaSStefan Roese
45694f453eaSStefan Roese err:
45794f453eaSStefan Roese return ret;
45894f453eaSStefan Roese }
45994f453eaSStefan Roese
46094f453eaSStefan Roese static const struct dm_pci_ops mvebu_pcie_ops = {
46194f453eaSStefan Roese .read_config = mvebu_pcie_read_config,
46294f453eaSStefan Roese .write_config = mvebu_pcie_write_config,
46394f453eaSStefan Roese };
46494f453eaSStefan Roese
46594f453eaSStefan Roese static struct driver pcie_mvebu_drv = {
46694f453eaSStefan Roese .name = "pcie_mvebu",
46794f453eaSStefan Roese .id = UCLASS_PCI,
46894f453eaSStefan Roese .ops = &mvebu_pcie_ops,
46994f453eaSStefan Roese .probe = mvebu_pcie_probe,
47094f453eaSStefan Roese .ofdata_to_platdata = mvebu_pcie_ofdata_to_platdata,
47194f453eaSStefan Roese .platdata_auto_alloc_size = sizeof(struct mvebu_pcie),
47294f453eaSStefan Roese };
47394f453eaSStefan Roese
47494f453eaSStefan Roese /*
47594f453eaSStefan Roese * Use a MISC device to bind the n instances (child nodes) of the
47694f453eaSStefan Roese * PCIe base controller in UCLASS_PCI.
47794f453eaSStefan Roese */
mvebu_pcie_bind(struct udevice * parent)47894f453eaSStefan Roese static int mvebu_pcie_bind(struct udevice *parent)
47994f453eaSStefan Roese {
48094f453eaSStefan Roese struct mvebu_pcie *pcie;
48194f453eaSStefan Roese struct uclass_driver *drv;
48294f453eaSStefan Roese struct udevice *dev;
48394f453eaSStefan Roese ofnode subnode;
48494f453eaSStefan Roese
48594f453eaSStefan Roese /* Lookup eth driver */
48694f453eaSStefan Roese drv = lists_uclass_lookup(UCLASS_PCI);
48794f453eaSStefan Roese if (!drv) {
48894f453eaSStefan Roese puts("Cannot find PCI driver\n");
48994f453eaSStefan Roese return -ENOENT;
49094f453eaSStefan Roese }
49194f453eaSStefan Roese
49294f453eaSStefan Roese ofnode_for_each_subnode(subnode, dev_ofnode(parent)) {
49394f453eaSStefan Roese if (!ofnode_is_available(subnode))
49494f453eaSStefan Roese continue;
49594f453eaSStefan Roese
49694f453eaSStefan Roese pcie = calloc(1, sizeof(*pcie));
49794f453eaSStefan Roese if (!pcie)
49894f453eaSStefan Roese return -ENOMEM;
49994f453eaSStefan Roese
50094f453eaSStefan Roese /* Create child device UCLASS_PCI and bind it */
50194f453eaSStefan Roese device_bind_ofnode(parent, &pcie_mvebu_drv, pcie->name, pcie,
50294f453eaSStefan Roese subnode, &dev);
50394f453eaSStefan Roese }
50494f453eaSStefan Roese
50594f453eaSStefan Roese return 0;
50694f453eaSStefan Roese }
50794f453eaSStefan Roese
50894f453eaSStefan Roese static const struct udevice_id mvebu_pcie_ids[] = {
50994f453eaSStefan Roese { .compatible = "marvell,armada-xp-pcie" },
51094f453eaSStefan Roese { .compatible = "marvell,armada-370-pcie" },
51194f453eaSStefan Roese { }
51294f453eaSStefan Roese };
51394f453eaSStefan Roese
51494f453eaSStefan Roese U_BOOT_DRIVER(pcie_mvebu_base) = {
51594f453eaSStefan Roese .name = "pcie_mvebu_base",
51694f453eaSStefan Roese .id = UCLASS_MISC,
51794f453eaSStefan Roese .of_match = mvebu_pcie_ids,
51894f453eaSStefan Roese .bind = mvebu_pcie_bind,
51994f453eaSStefan Roese };
520