xref: /openbmc/u-boot/drivers/pci/pci_mvebu.c (revision 66c433ed)
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