Merge branch '2021-02-02-drop-asm_global_data-when-unused'
[platform/kernel/u-boot.git] / drivers / pci / pci_mvebu.c
index 4eedfe1..235d9bb 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * PCIe driver for Marvell MVEBU SoCs
  *
@@ -6,16 +7,23 @@
  * Ported to U-Boot by:
  * Anton Schubert <anton.schubert@gmx.de>
  * Stefan Roese <sr@denx.de>
- *
- * SPDX-License-Identifier:    GPL-2.0
  */
 
 #include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <asm/global_data.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/of_access.h>
 #include <pci.h>
-#include <asm/errno.h>
 #include <asm/io.h>
 #include <asm/arch/cpu.h>
 #include <asm/arch/soc.h>
+#include <linux/bitops.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
 #include <linux/mbus.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -60,108 +68,33 @@ DECLARE_GLOBAL_DATA_PTR;
 #define PCIE_DEBUG_CTRL                        0x1a60
 #define  PCIE_DEBUG_SOFT_RESET         BIT(20)
 
-struct resource {
-       u32 start;
-       u32 end;
-};
-
 struct mvebu_pcie {
        struct pci_controller hose;
-       char *name;
        void __iomem *base;
        void __iomem *membase;
        struct resource mem;
        void __iomem *iobase;
+       struct resource io;
        u32 port;
        u32 lane;
+       int devfn;
        u32 lane_mask;
        pci_dev_t dev;
+       char name[16];
+       unsigned int mem_target;
+       unsigned int mem_attr;
+       unsigned int io_target;
+       unsigned int io_attr;
 };
 
-#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
+ * into SoCs address space. Each controller will map 128M of MEM
  * and 64K of I/O space when registered.
  */
 static void __iomem *mvebu_pcie_membase = (void __iomem *)MBUS_PCI_MEM_BASE;
-#define PCIE_MEM_SIZE  (32 << 20)
-
-#if defined(CONFIG_ARMADA_38X)
-#define PCIE_BASE(if)                                  \
-       ((if) == 0 ?                                    \
-        MVEBU_REG_PCIE_BASE + 0x40000 :                \
-        MVEBU_REG_PCIE_BASE + 0x4000 * (if))
-
-/*
- * On A38x MV6820 these PEX ports are supported:
- *  0 - Port 0.0
- *  1 - Port 0.1
- *  2 - Port 0.2
- */
-#define MAX_PEX 3
-static struct mvebu_pcie pcie_bus[MAX_PEX];
-
-static void mvebu_get_port_lane(struct mvebu_pcie *pcie, int pex_idx,
-                               int *mem_target, int *mem_attr)
-{
-       u8 port[] = { 0, 1, 2 };
-       u8 lane[] = { 0, 0, 0 };
-       u8 target[] = { 8, 4, 4 };
-       u8 attr[] = { 0xe8, 0xe8, 0xd8 };
-
-       pcie->port = port[pex_idx];
-       pcie->lane = lane[pex_idx];
-       *mem_target = target[pex_idx];
-       *mem_attr = attr[pex_idx];
-}
-#else
-#define PCIE_BASE(if)                                                  \
-       ((if) < 8 ?                                                     \
-        (MVEBU_REG_PCIE_BASE + ((if) / 4) * 0x40000 + ((if) % 4) * 0x4000) : \
-        (MVEBU_REG_PCIE_BASE + 0x2000 + ((if) % 8) * 0x40000))
-
-/*
- * On AXP MV78460 these PEX ports are supported:
- *  0 - Port 0.0
- *  1 - Port 0.1
- *  2 - Port 0.2
- *  3 - Port 0.3
- *  4 - Port 1.0
- *  5 - Port 1.1
- *  6 - Port 1.2
- *  7 - Port 1.3
- *  8 - Port 2.0
- *  9 - Port 3.0
- */
-#define MAX_PEX 10
-static struct mvebu_pcie pcie_bus[MAX_PEX];
-
-static void mvebu_get_port_lane(struct mvebu_pcie *pcie, int pex_idx,
-                               int *mem_target, int *mem_attr)
-{
-       u8 port[] = { 0, 0, 0, 0, 1, 1, 1, 1, 2, 3 };
-       u8 lane[] = { 0, 1, 2, 3, 0, 1, 2, 3, 0, 0 };
-       u8 target[] = { 4, 4, 4, 4, 8, 8, 8, 8, 4, 8 };
-       u8 attr[] = { 0xe8, 0xd8, 0xb8, 0x78,
-                     0xe8, 0xd8, 0xb8, 0x78,
-                     0xf8, 0xf8 };
-
-       pcie->port = port[pex_idx];
-       pcie->lane = lane[pex_idx];
-       *mem_target = target[pex_idx];
-       *mem_attr = attr[pex_idx];
-}
-#endif
-
-static int mvebu_pex_unit_is_x4(int pex_idx)
-{
-       int pex_unit = pex_idx < 9 ? pex_idx >> 2 : 3;
-       u32 mask = (0x0f << (pex_unit * 8));
-
-       return (readl(COMPHY_REFCLK_ALIGNMENT) & mask) == mask;
-}
+#define PCIE_MEM_SIZE  (128 << 20)
+static void __iomem *mvebu_pcie_iobase = (void __iomem *)MBUS_PCI_IO_BASE;
 
 static inline bool mvebu_pcie_link_up(struct mvebu_pcie *pcie)
 {
@@ -211,67 +144,71 @@ static inline struct mvebu_pcie *hose_to_pcie(struct pci_controller *hose)
        return container_of(hose, struct mvebu_pcie, hose);
 }
 
-static int mvebu_pcie_read_config_dword(struct pci_controller *hose,
-               pci_dev_t dev, int offset, u32 *val)
+static int mvebu_pcie_read_config(const struct udevice *bus, pci_dev_t bdf,
+                                 uint offset, ulong *valuep,
+                                 enum pci_size_t size)
 {
-       struct mvebu_pcie *pcie = hose_to_pcie(hose);
+       struct mvebu_pcie *pcie = dev_get_plat(bus);
        int local_bus = PCI_BUS(pcie->dev);
        int local_dev = PCI_DEV(pcie->dev);
        u32 reg;
+       u32 data;
 
-       /* Only allow one other device besides the local one on the local bus */
-       if (PCI_BUS(dev) == local_bus && PCI_DEV(dev) != local_dev) {
-               if (local_dev == 0 && PCI_DEV(dev) != 1) {
-                       /*
-                        * If local dev is 0, the first other dev can
-                        * only be 1
-                        */
-                       *val = 0xffffffff;
-                       return 1;
-               } else if (local_dev != 0 && PCI_DEV(dev) != 0) {
-                       /*
-                        * If local dev is not 0, the first other dev can
-                        * only be 0
-                        */
-                       *val = 0xffffffff;
-                       return 1;
-               }
+       debug("PCIE CFG read:  loc_bus=%d loc_dev=%d (b,d,f)=(%2d,%2d,%2d) ",
+             local_bus, local_dev, PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+
+       /* Don't access the local host controller via this API */
+       if (PCI_BUS(bdf) == local_bus && PCI_DEV(bdf) == local_dev) {
+               debug("- skipping host controller\n");
+               *valuep = pci_get_ff(size);
+               return 0;
+       }
+
+       /* If local dev is 0, the first other dev can only be 1 */
+       if (PCI_BUS(bdf) == local_bus && local_dev == 0 && PCI_DEV(bdf) != 1) {
+               debug("- out of range\n");
+               *valuep = pci_get_ff(size);
+               return 0;
        }
 
        /* write address */
-       reg = PCIE_CONF_ADDR(dev, offset);
+       reg = PCIE_CONF_ADDR(bdf, offset);
        writel(reg, pcie->base + PCIE_CONF_ADDR_OFF);
-       *val = readl(pcie->base + PCIE_CONF_DATA_OFF);
+       data = readl(pcie->base + PCIE_CONF_DATA_OFF);
+       debug("(addr,val)=(0x%04x, 0x%08x)\n", offset, data);
+       *valuep = pci_conv_32_to_size(data, offset, size);
 
        return 0;
 }
 
-static int mvebu_pcie_write_config_dword(struct pci_controller *hose,
-               pci_dev_t dev, int offset, u32 val)
+static int mvebu_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
+                                  uint offset, ulong value,
+                                  enum pci_size_t size)
 {
-       struct mvebu_pcie *pcie = hose_to_pcie(hose);
+       struct mvebu_pcie *pcie = dev_get_plat(bus);
        int local_bus = PCI_BUS(pcie->dev);
        int local_dev = PCI_DEV(pcie->dev);
+       u32 data;
 
-       /* Only allow one other device besides the local one on the local bus */
-       if (PCI_BUS(dev) == local_bus && PCI_DEV(dev) != local_dev) {
-               if (local_dev == 0 && PCI_DEV(dev) != 1) {
-                       /*
-                        * If local dev is 0, the first other dev can
-                        * only be 1
-                        */
-                       return 1;
-               } else if (local_dev != 0 && PCI_DEV(dev) != 0) {
-                       /*
-                        * If local dev is not 0, the first other dev can
-                        * only be 0
-                        */
-                       return 1;
-               }
+       debug("PCIE CFG write: loc_bus=%d loc_dev=%d (b,d,f)=(%2d,%2d,%2d) ",
+             local_bus, local_dev, PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+       debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
+
+       /* Don't access the local host controller via this API */
+       if (PCI_BUS(bdf) == local_bus && PCI_DEV(bdf) == local_dev) {
+               debug("- skipping host controller\n");
+               return 0;
+       }
+
+       /* If local dev is 0, the first other dev can only be 1 */
+       if (PCI_BUS(bdf) == local_bus && local_dev == 0 && PCI_DEV(bdf) != 1) {
+               debug("- out of range\n");
+               return 0;
        }
 
-       writel(PCIE_CONF_ADDR(dev, offset), pcie->base + PCIE_CONF_ADDR_OFF);
-       writel(val, pcie->base + PCIE_CONF_DATA_OFF);
+       writel(PCIE_CONF_ADDR(bdf, offset), pcie->base + PCIE_CONF_ADDR_OFF);
+       data = pci_conv_size_to_32(0, value, offset, size);
+       writel(data, pcie->base + PCIE_CONF_DATA_OFF);
 
        return 0;
 }
@@ -331,107 +268,270 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie *pcie)
               pcie->base + PCIE_BAR_CTRL_OFF(1));
 }
 
-void pci_init_board(void)
+static int mvebu_pcie_probe(struct udevice *dev)
 {
-       int mem_target, mem_attr, i;
-       int bus = 0;
+       struct mvebu_pcie *pcie = dev_get_plat(dev);
+       struct udevice *ctlr = pci_get_controller(dev);
+       struct pci_controller *hose = dev_get_uclass_priv(ctlr);
+       static int bus;
        u32 reg;
-       u32 soc_ctrl = readl(MVEBU_SYSTEM_REG_BASE + 0x4);
 
-       /* Check SoC Control Power State */
-       debug("%s: SoC Control %08x, 0en %01lx, 1en %01lx, 2en %01lx\n",
-             __func__, soc_ctrl, SELECT(soc_ctrl, 0), SELECT(soc_ctrl, 1),
-             SELECT(soc_ctrl, 2));
+       debug("%s: PCIe %d.%d - up, base %08x\n", __func__,
+             pcie->port, pcie->lane, (u32)pcie->base);
+
+       /* Read Id info and local bus/dev */
+       debug("direct conf read %08x, local bus %d, local dev %d\n",
+             readl(pcie->base), mvebu_pcie_get_local_bus_nr(pcie),
+             mvebu_pcie_get_local_dev_nr(pcie));
+
+       mvebu_pcie_set_local_bus_nr(pcie, bus);
+       mvebu_pcie_set_local_dev_nr(pcie, 0);
+       pcie->dev = PCI_BDF(bus, 0, 0);
+
+       pcie->mem.start = (u32)mvebu_pcie_membase;
+       pcie->mem.end = pcie->mem.start + PCIE_MEM_SIZE - 1;
+       mvebu_pcie_membase += PCIE_MEM_SIZE;
+
+       if (mvebu_mbus_add_window_by_id(pcie->mem_target, pcie->mem_attr,
+                                       (phys_addr_t)pcie->mem.start,
+                                       PCIE_MEM_SIZE)) {
+               printf("PCIe unable to add mbus window for mem at %08x+%08x\n",
+                      (u32)pcie->mem.start, PCIE_MEM_SIZE);
+       }
+
+       pcie->io.start = (u32)mvebu_pcie_iobase;
+       pcie->io.end = pcie->io.start + MBUS_PCI_IO_SIZE - 1;
+       mvebu_pcie_iobase += MBUS_PCI_IO_SIZE;
+
+       if (mvebu_mbus_add_window_by_id(pcie->io_target, pcie->io_attr,
+                                       (phys_addr_t)pcie->io.start,
+                                       MBUS_PCI_IO_SIZE)) {
+               printf("PCIe unable to add mbus window for IO at %08x+%08x\n",
+                      (u32)pcie->io.start, MBUS_PCI_IO_SIZE);
+       }
 
-       for (i = 0; i < MAX_PEX; i++) {
-               struct mvebu_pcie *pcie = &pcie_bus[i];
-               struct pci_controller *hose = &pcie->hose;
+       /* Setup windows and configure host bridge */
+       mvebu_pcie_setup_wins(pcie);
+
+       /* Master + slave enable. */
+       reg = readl(pcie->base + PCIE_CMD_OFF);
+       reg |= PCI_COMMAND_MEMORY;
+       reg |= PCI_COMMAND_IO;
+       reg |= PCI_COMMAND_MASTER;
+       reg |= BIT(10);         /* disable interrupts */
+       writel(reg, pcie->base + PCIE_CMD_OFF);
+
+       /* PCI memory space */
+       pci_set_region(hose->regions + 0, pcie->mem.start,
+                      pcie->mem.start, PCIE_MEM_SIZE, PCI_REGION_MEM);
+       pci_set_region(hose->regions + 1,
+                      0, 0,
+                      gd->ram_size,
+                      PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+       pci_set_region(hose->regions + 2, pcie->io.start,
+                      pcie->io.start, MBUS_PCI_IO_SIZE, PCI_REGION_IO);
+       hose->region_count = 3;
+
+       /* Set BAR0 to internal registers */
+       writel(SOC_REGS_PHY_BASE, pcie->base + PCIE_BAR_LO_OFF(0));
+       writel(0, pcie->base + PCIE_BAR_HI_OFF(0));
+
+       bus++;
 
-               /* Get port number, lane number and memory target / attr */
-               mvebu_get_port_lane(pcie, i, &mem_target, &mem_attr);
+       return 0;
+}
 
-               /* Don't read at all from pci registers if port power is down */
-               if (pcie->lane == 0 && SELECT(soc_ctrl, pcie->port) == 0) {
-                       i += 3;
-                       debug("%s: skipping port %d\n", __func__, pcie->port);
+static int mvebu_pcie_port_parse_dt(ofnode node, struct mvebu_pcie *pcie)
+{
+       const u32 *addr;
+       int len;
+
+       addr = ofnode_get_property(node, "assigned-addresses", &len);
+       if (!addr) {
+               pr_err("property \"assigned-addresses\" not found");
+               return -FDT_ERR_NOTFOUND;
+       }
+
+       pcie->base = (void *)(fdt32_to_cpu(addr[2]) + SOC_REGS_PHY_BASE);
+
+       return 0;
+}
+
+#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_tgt_attr(ofnode node, int devfn,
+                             unsigned long type,
+                             unsigned int *tgt,
+                             unsigned int *attr)
+{
+       const int na = 3, ns = 2;
+       const __be32 *range;
+       int rlen, nranges, rangesz, pna, i;
+
+       *tgt = -1;
+       *attr = -1;
+
+       range = ofnode_get_property(node, "ranges", &rlen);
+       if (!range)
+               return -EINVAL;
+
+       /*
+        * Linux uses of_n_addr_cells() to get the number of address cells
+        * here. Currently this function is only available in U-Boot when
+        * CONFIG_OF_LIVE is enabled. Until this is enabled for MVEBU in
+        * general, lets't hardcode the "pna" value in the U-Boot code.
+        */
+       pna = 2; /* hardcoded for now because of lack of of_n_addr_cells() */
+       rangesz = pna + na + ns;
+       nranges = rlen / sizeof(__be32) / rangesz;
+
+       for (i = 0; i < nranges; i++, range += rangesz) {
+               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;
+               else
                        continue;
+
+               /*
+                * The Linux code used PCI_SLOT() here, which expects devfn
+                * in bits 7..0. PCI_DEV() in U-Boot is similar to PCI_SLOT(),
+                * only expects devfn in 15..8, where its saved in this driver.
+                */
+               if (slot == PCI_DEV(devfn) && type == rtype) {
+                       *tgt = DT_CPUADDR_TO_TARGET(cpuaddr);
+                       *attr = DT_CPUADDR_TO_ATTR(cpuaddr);
+                       return 0;
                }
+       }
+
+       return -ENOENT;
+}
+
+static int mvebu_pcie_of_to_plat(struct udevice *dev)
+{
+       struct mvebu_pcie *pcie = dev_get_plat(dev);
+       int ret = 0;
+
+       /* Get port number, lane number and memory target / attr */
+       if (ofnode_read_u32(dev_ofnode(dev), "marvell,pcie-port",
+                           &pcie->port)) {
+               ret = -ENODEV;
+               goto err;
+       }
+
+       if (ofnode_read_u32(dev_ofnode(dev), "marvell,pcie-lane", &pcie->lane))
+               pcie->lane = 0;
+
+       sprintf(pcie->name, "pcie%d.%d", pcie->port, pcie->lane);
+
+       /* pci_get_devfn() returns devfn in bits 15..8, see PCI_DEV usage */
+       pcie->devfn = pci_get_devfn(dev);
+       if (pcie->devfn < 0) {
+               ret = -ENODEV;
+               goto err;
+       }
+
+       ret = mvebu_get_tgt_attr(dev_ofnode(dev->parent), pcie->devfn,
+                                IORESOURCE_MEM,
+                                &pcie->mem_target, &pcie->mem_attr);
+       if (ret < 0) {
+               printf("%s: cannot get tgt/attr for mem window\n", pcie->name);
+               goto err;
+       }
+
+       ret = mvebu_get_tgt_attr(dev_ofnode(dev->parent), pcie->devfn,
+                                IORESOURCE_IO,
+                                &pcie->io_target, &pcie->io_attr);
+       if (ret < 0) {
+               printf("%s: cannot get tgt/attr for IO window\n", pcie->name);
+               goto err;
+       }
+
+       /* Parse PCIe controller register base from DT */
+       ret = mvebu_pcie_port_parse_dt(dev_ofnode(dev), pcie);
+       if (ret < 0)
+               goto err;
+
+       /* Check link and skip ports that have no link */
+       if (!mvebu_pcie_link_up(pcie)) {
+               debug("%s: %s - down\n", __func__, pcie->name);
+               ret = -ENODEV;
+               goto err;
+       }
 
-               pcie->base = (void __iomem *)PCIE_BASE(i);
+       return 0;
+
+err:
+       return ret;
+}
+
+static const struct dm_pci_ops mvebu_pcie_ops = {
+       .read_config    = mvebu_pcie_read_config,
+       .write_config   = mvebu_pcie_write_config,
+};
+
+static struct driver pcie_mvebu_drv = {
+       .name                   = "pcie_mvebu",
+       .id                     = UCLASS_PCI,
+       .ops                    = &mvebu_pcie_ops,
+       .probe                  = mvebu_pcie_probe,
+       .of_to_plat     = mvebu_pcie_of_to_plat,
+       .plat_auto      = sizeof(struct mvebu_pcie),
+};
+
+/*
+ * Use a MISC device to bind the n instances (child nodes) of the
+ * PCIe base controller in UCLASS_PCI.
+ */
+static int mvebu_pcie_bind(struct udevice *parent)
+{
+       struct mvebu_pcie *pcie;
+       struct uclass_driver *drv;
+       struct udevice *dev;
+       ofnode subnode;
+
+       /* Lookup eth driver */
+       drv = lists_uclass_lookup(UCLASS_PCI);
+       if (!drv) {
+               puts("Cannot find PCI driver\n");
+               return -ENOENT;
+       }
 
-               /* Check link and skip ports that have no link */
-               if (!mvebu_pcie_link_up(pcie)) {
-                       debug("%s: PCIe %d.%d - down\n", __func__,
-                             pcie->port, pcie->lane);
+       ofnode_for_each_subnode(subnode, dev_ofnode(parent)) {
+               if (!ofnode_is_available(subnode))
                        continue;
-               }
-               debug("%s: PCIe %d.%d - up, base %08x\n", __func__,
-                     pcie->port, pcie->lane, (u32)pcie->base);
-
-               /* Read Id info and local bus/dev */
-               debug("direct conf read %08x, local bus %d, local dev %d\n",
-                     readl(pcie->base), mvebu_pcie_get_local_bus_nr(pcie),
-                     mvebu_pcie_get_local_dev_nr(pcie));
-
-               mvebu_pcie_set_local_bus_nr(pcie, bus);
-               mvebu_pcie_set_local_dev_nr(pcie, 0);
-               pcie->dev = PCI_BDF(bus, 0, 0);
-
-               pcie->mem.start = (u32)mvebu_pcie_membase;
-               pcie->mem.end = pcie->mem.start + PCIE_MEM_SIZE - 1;
-               mvebu_pcie_membase += PCIE_MEM_SIZE;
-
-               if (mvebu_mbus_add_window_by_id(mem_target, mem_attr,
-                                               (phys_addr_t)pcie->mem.start,
-                                               PCIE_MEM_SIZE)) {
-                       printf("PCIe unable to add mbus window for mem at %08x+%08x\n",
-                              (u32)pcie->mem.start, PCIE_MEM_SIZE);
-               }
 
-               /* Setup windows and configure host bridge */
-               mvebu_pcie_setup_wins(pcie);
-
-               /* Master + slave enable. */
-               reg = readl(pcie->base + PCIE_CMD_OFF);
-               reg |= PCI_COMMAND_MEMORY;
-               reg |= PCI_COMMAND_MASTER;
-               reg |= BIT(10);         /* disable interrupts */
-               writel(reg, pcie->base + PCIE_CMD_OFF);
-
-               /* Setup U-Boot PCI Controller */
-               hose->first_busno = 0;
-               hose->current_busno = bus;
-
-               /* PCI memory space */
-               pci_set_region(hose->regions + 0, pcie->mem.start,
-                              pcie->mem.start, PCIE_MEM_SIZE, PCI_REGION_MEM);
-               pci_set_region(hose->regions + 1,
-                              0, 0,
-                              gd->ram_size,
-                              PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
-               hose->region_count = 2;
-
-               pci_set_ops(hose,
-                           pci_hose_read_config_byte_via_dword,
-                           pci_hose_read_config_word_via_dword,
-                           mvebu_pcie_read_config_dword,
-                           pci_hose_write_config_byte_via_dword,
-                           pci_hose_write_config_word_via_dword,
-                           mvebu_pcie_write_config_dword);
-               pci_register_hose(hose);
-
-               hose->last_busno = pci_hose_scan(hose);
-
-               /* Set BAR0 to internal registers */
-               writel(SOC_REGS_PHY_BASE, pcie->base + PCIE_BAR_LO_OFF(0));
-               writel(0, pcie->base + PCIE_BAR_HI_OFF(0));
-
-               bus = hose->last_busno + 1;
-
-               /* need to skip more for X4 links, otherwise scan will hang */
-               if (mvebu_soc_family() == MVEBU_SOC_AXP) {
-                       if (mvebu_pex_unit_is_x4(i))
-                               i += 3;
-               }
+               pcie = calloc(1, sizeof(*pcie));
+               if (!pcie)
+                       return -ENOMEM;
+
+               /* Create child device UCLASS_PCI and bind it */
+               device_bind(parent, &pcie_mvebu_drv, pcie->name, pcie, subnode,
+                           &dev);
        }
+
+       return 0;
 }
+
+static const struct udevice_id mvebu_pcie_ids[] = {
+       { .compatible = "marvell,armada-xp-pcie" },
+       { .compatible = "marvell,armada-370-pcie" },
+       { }
+};
+
+U_BOOT_DRIVER(pcie_mvebu_base) = {
+       .name                   = "pcie_mvebu_base",
+       .id                     = UCLASS_MISC,
+       .of_match               = mvebu_pcie_ids,
+       .bind                   = mvebu_pcie_bind,
+};