dm: pci: add Freescale PowerPC PCIe driver
authorHou Zhiqiang <Zhiqiang.Hou@nxp.com>
Wed, 24 Apr 2019 14:33:02 +0000 (22:33 +0800)
committerPrabhakar Kushwaha <prabhakar.kushwaha@nxp.com>
Thu, 20 Jun 2019 05:14:45 +0000 (10:44 +0530)
Add PCIe DM driver for Freescale PowerPC PCIe controllers.

Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
Reviewed-by: Prabhakar Kushwaha <prabhakar.kushwaha@nxp.com>
drivers/pci/Kconfig
drivers/pci/Makefile
drivers/pci/pcie_fsl.c [new file with mode: 0644]
drivers/pci/pcie_fsl.h [new file with mode: 0644]
drivers/pci/pcie_fsl_fixup.c [new file with mode: 0644]

index 429bb836a8a041146ec92b338ba566f2d03d9b2e..3fe38f7315eda618eaffd4b98b2a9c3cd3fa90df 100644 (file)
@@ -60,6 +60,14 @@ config PCIE_DW_MVEBU
          Armada-8K SoCs. The PCIe controller on Armada-8K is based on
          DesignWare hardware.
 
+config PCIE_FSL
+       bool "FSL PowerPC PCIe support"
+       depends on DM_PCI
+       help
+         Say Y here if you want to enable PCIe controller support on FSL
+         PowerPC MPC85xx, MPC86xx, B series, P series and T series SoCs.
+         This driver does not support SRIO_PCIE_BOOT feature.
+
 config PCI_RCAR_GEN2
        bool "Renesas RCar Gen2 PCIe driver"
        depends on DM_PCI
index bd392edba179e35ab5f55cbb507156783c5f48c1..b5ebd50c855f5f0d909435b0c1306da6004c18e8 100644 (file)
@@ -31,6 +31,7 @@ obj-$(CONFIG_SH7780_PCI) +=pci_sh7780.o
 obj-$(CONFIG_PCI_TEGRA) += pci_tegra.o
 obj-$(CONFIG_PCI_AARDVARK) += pci-aardvark.o
 obj-$(CONFIG_PCIE_DW_MVEBU) += pcie_dw_mvebu.o
+obj-$(CONFIG_PCIE_FSL) += pcie_fsl.o pcie_fsl_fixup.o
 obj-$(CONFIG_PCIE_LAYERSCAPE) += pcie_layerscape.o
 obj-$(CONFIG_PCIE_LAYERSCAPE) += pcie_layerscape_fixup.o
 obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie_layerscape_gen4.o \
diff --git a/drivers/pci/pcie_fsl.c b/drivers/pci/pcie_fsl.c
new file mode 100644 (file)
index 0000000..4d61a46
--- /dev/null
@@ -0,0 +1,610 @@
+// SPDX-License-Identifier: GPL-2.0+ OR X11
+/*
+ * Copyright 2019 NXP
+ *
+ * PCIe DM U-Boot driver for Freescale PowerPC SoCs
+ * Author: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <pci.h>
+#include <asm/fsl_pci.h>
+#include <asm/fsl_serdes.h>
+#include <asm/io.h>
+#include "pcie_fsl.h"
+
+LIST_HEAD(fsl_pcie_list);
+
+static int fsl_pcie_link_up(struct fsl_pcie *pcie);
+
+static int fsl_pcie_addr_valid(struct fsl_pcie *pcie, pci_dev_t bdf)
+{
+       struct udevice *bus = pcie->bus;
+
+       if (!pcie->enabled)
+               return -ENXIO;
+
+       if (PCI_BUS(bdf) < bus->seq)
+               return -EINVAL;
+
+       if (PCI_BUS(bdf) > bus->seq && (!fsl_pcie_link_up(pcie) || pcie->mode))
+               return -EINVAL;
+
+       if (PCI_BUS(bdf) == bus->seq && (PCI_DEV(bdf) > 0 || PCI_FUNC(bdf) > 0))
+               return -EINVAL;
+
+       if (PCI_BUS(bdf) == (bus->seq + 1) && (PCI_DEV(bdf) > 0))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int fsl_pcie_read_config(struct udevice *bus, pci_dev_t bdf,
+                               uint offset, ulong *valuep,
+                               enum pci_size_t size)
+{
+       struct fsl_pcie *pcie = dev_get_priv(bus);
+       ccsr_fsl_pci_t *regs = pcie->regs;
+       u32 val;
+
+       if (fsl_pcie_addr_valid(pcie, bdf)) {
+               *valuep = pci_get_ff(size);
+               return 0;
+       }
+
+       bdf = bdf - PCI_BDF(bus->seq, 0, 0);
+       val = bdf | (offset & 0xfc) | ((offset & 0xf00) << 16) | 0x80000000;
+       out_be32(&regs->cfg_addr, val);
+
+       sync();
+
+       switch (size) {
+       case PCI_SIZE_8:
+               *valuep = in_8((u8 *)&regs->cfg_data + (offset & 3));
+               break;
+       case PCI_SIZE_16:
+               *valuep = in_le16((u16 *)((u8 *)&regs->cfg_data +
+                         (offset & 2)));
+               break;
+       case PCI_SIZE_32:
+               *valuep = in_le32(&regs->cfg_data);
+               break;
+       }
+
+       return 0;
+}
+
+static int fsl_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
+                                uint offset, ulong value,
+                                enum pci_size_t size)
+{
+       struct fsl_pcie *pcie = dev_get_priv(bus);
+       ccsr_fsl_pci_t *regs = pcie->regs;
+       u32 val;
+       u8 val_8;
+       u16 val_16;
+       u32 val_32;
+
+       if (fsl_pcie_addr_valid(pcie, bdf))
+               return 0;
+
+       bdf = bdf - PCI_BDF(bus->seq, 0, 0);
+       val = bdf | (offset & 0xfc) | ((offset & 0xf00) << 16) | 0x80000000;
+       out_be32(&regs->cfg_addr, val);
+
+       sync();
+
+       switch (size) {
+       case PCI_SIZE_8:
+               val_8 = value;
+               out_8((u8 *)&regs->cfg_data + (offset & 3), val_8);
+               break;
+       case PCI_SIZE_16:
+               val_16 = value;
+               out_le16((u16 *)((u8 *)&regs->cfg_data + (offset & 2)), val_16);
+               break;
+       case PCI_SIZE_32:
+               val_32 = value;
+               out_le32(&regs->cfg_data, val_32);
+               break;
+       }
+
+       return 0;
+}
+
+static int fsl_pcie_hose_read_config(struct fsl_pcie *pcie, uint offset,
+                                    ulong *valuep, enum pci_size_t size)
+{
+       int ret;
+       struct udevice *bus = pcie->bus;
+
+       ret = fsl_pcie_read_config(bus, PCI_BDF(bus->seq, 0, 0),
+                                  offset, valuep, size);
+
+       return ret;
+}
+
+static int fsl_pcie_hose_write_config(struct fsl_pcie *pcie, uint offset,
+                                     ulong value, enum pci_size_t size)
+{
+       struct udevice *bus = pcie->bus;
+
+       return fsl_pcie_write_config(bus, PCI_BDF(bus->seq, 0, 0),
+                                    offset, value, size);
+}
+
+static int fsl_pcie_hose_read_config_byte(struct fsl_pcie *pcie, uint offset,
+                                         u8 *valuep)
+{
+       ulong val;
+       int ret;
+
+       ret = fsl_pcie_hose_read_config(pcie, offset, &val, PCI_SIZE_8);
+       *valuep = val;
+
+       return ret;
+}
+
+static int fsl_pcie_hose_read_config_word(struct fsl_pcie *pcie, uint offset,
+                                         u16 *valuep)
+{
+       ulong val;
+       int ret;
+
+       ret = fsl_pcie_hose_read_config(pcie, offset, &val, PCI_SIZE_16);
+       *valuep = val;
+
+       return ret;
+}
+
+static int fsl_pcie_hose_read_config_dword(struct fsl_pcie *pcie, uint offset,
+                                          u32 *valuep)
+{
+       ulong val;
+       int ret;
+
+       ret = fsl_pcie_hose_read_config(pcie, offset, &val, PCI_SIZE_32);
+       *valuep = val;
+
+       return ret;
+}
+
+static int fsl_pcie_hose_write_config_byte(struct fsl_pcie *pcie, uint offset,
+                                          u8 value)
+{
+       return fsl_pcie_hose_write_config(pcie, offset, value, PCI_SIZE_8);
+}
+
+static int fsl_pcie_hose_write_config_word(struct fsl_pcie *pcie, uint offset,
+                                          u16 value)
+{
+       return fsl_pcie_hose_write_config(pcie, offset, value, PCI_SIZE_16);
+}
+
+static int fsl_pcie_hose_write_config_dword(struct fsl_pcie *pcie, uint offset,
+                                           u32 value)
+{
+       return fsl_pcie_hose_write_config(pcie, offset, value, PCI_SIZE_32);
+}
+
+static int fsl_pcie_link_up(struct fsl_pcie *pcie)
+{
+       ccsr_fsl_pci_t *regs = pcie->regs;
+       u16 ltssm;
+
+       if (pcie->block_rev >= PEX_IP_BLK_REV_3_0) {
+               ltssm = (in_be32(&regs->pex_csr0)
+                       & PEX_CSR0_LTSSM_MASK) >> PEX_CSR0_LTSSM_SHIFT;
+               return ltssm == LTSSM_L0_REV3;
+       }
+
+       fsl_pcie_hose_read_config_word(pcie, PCI_LTSSM, &ltssm);
+
+       return ltssm == LTSSM_L0;
+}
+
+static bool fsl_pcie_is_agent(struct fsl_pcie *pcie)
+{
+       u8 header_type;
+
+       fsl_pcie_hose_read_config_byte(pcie, PCI_HEADER_TYPE, &header_type);
+
+       return (header_type & 0x7f) == PCI_HEADER_TYPE_NORMAL;
+}
+
+static int fsl_pcie_setup_law(struct fsl_pcie *pcie)
+{
+       struct pci_region *io, *mem, *pref;
+
+       pci_get_regions(pcie->bus, &io, &mem, &pref);
+
+       if (mem)
+               set_next_law(mem->phys_start,
+                            law_size_bits(mem->size),
+                            pcie->law_trgt_if);
+
+       if (io)
+               set_next_law(io->phys_start,
+                            law_size_bits(io->size),
+                            pcie->law_trgt_if);
+
+       return 0;
+}
+
+static void fsl_pcie_config_ready(struct fsl_pcie *pcie)
+{
+       ccsr_fsl_pci_t *regs = pcie->regs;
+
+       if (pcie->block_rev >= PEX_IP_BLK_REV_3_0) {
+               setbits_be32(&regs->config, FSL_PCIE_V3_CFG_RDY);
+               return;
+       }
+
+       fsl_pcie_hose_write_config_byte(pcie, FSL_PCIE_CFG_RDY, 0x1);
+}
+
+static int fsl_pcie_setup_outbound_win(struct fsl_pcie *pcie, int idx,
+                                      int type, u64 phys, u64 bus_addr,
+                                      pci_size_t size)
+{
+       ccsr_fsl_pci_t *regs = pcie->regs;
+       pot_t *po = &regs->pot[idx];
+       u32 war, sz;
+
+       if (idx < 0)
+               return -EINVAL;
+
+       out_be32(&po->powbar, phys >> 12);
+       out_be32(&po->potar, bus_addr >> 12);
+#ifdef CONFIG_SYS_PCI_64BIT
+       out_be32(&po->potear, bus_addr >> 44);
+#else
+       out_be32(&po->potear, 0);
+#endif
+
+       sz = (__ilog2_u64((u64)size) - 1);
+       war = POWAR_EN | sz;
+
+       if (type == PCI_REGION_IO)
+               war |= POWAR_IO_READ | POWAR_IO_WRITE;
+       else
+               war |= POWAR_MEM_READ | POWAR_MEM_WRITE;
+
+       out_be32(&po->powar, war);
+
+       return 0;
+}
+
+static int fsl_pcie_setup_inbound_win(struct fsl_pcie *pcie, int idx,
+                                     bool pf, u64 phys, u64 bus_addr,
+                                     pci_size_t size)
+{
+       ccsr_fsl_pci_t *regs = pcie->regs;
+       pit_t *pi = &regs->pit[idx];
+       u32 sz = (__ilog2_u64(size) - 1);
+       u32 flag = PIWAR_LOCAL;
+
+       if (idx < 0)
+               return -EINVAL;
+
+       out_be32(&pi->pitar, phys >> 12);
+       out_be32(&pi->piwbar, bus_addr >> 12);
+
+#ifdef CONFIG_SYS_PCI_64BIT
+       out_be32(&pi->piwbear, bus_addr >> 44);
+#else
+       out_be32(&pi->piwbear, 0);
+#endif
+
+       if (IS_ENABLED(CONFIG_SYS_FSL_ERRATUM_A005434))
+               flag = 0;
+
+       flag |= PIWAR_EN | PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP;
+       if (pf)
+               flag |= PIWAR_PF;
+       out_be32(&pi->piwar, flag | sz);
+
+       return 0;
+}
+
+static int fsl_pcie_setup_outbound_wins(struct fsl_pcie *pcie)
+{
+       struct pci_region *io, *mem, *pref;
+       int idx = 1; /* skip 0 */
+
+       pci_get_regions(pcie->bus, &io, &mem, &pref);
+
+       if (io)
+               /* ATU : OUTBOUND : IO */
+               fsl_pcie_setup_outbound_win(pcie, idx++,
+                                           PCI_REGION_IO,
+                                           io->phys_start,
+                                           io->bus_start,
+                                           io->size);
+
+       if (mem)
+               /* ATU : OUTBOUND : MEM */
+               fsl_pcie_setup_outbound_win(pcie, idx++,
+                                           PCI_REGION_MEM,
+                                           mem->phys_start,
+                                           mem->bus_start,
+                                           mem->size);
+       return 0;
+}
+
+static int fsl_pcie_setup_inbound_wins(struct fsl_pcie *pcie)
+{
+       phys_addr_t phys_start = CONFIG_SYS_PCI_MEMORY_PHYS;
+       pci_addr_t bus_start = CONFIG_SYS_PCI_MEMORY_BUS;
+       u64 sz = min((u64)gd->ram_size, (1ull << 32));
+       pci_size_t pci_sz;
+       int idx;
+
+       if (pcie->block_rev >= PEX_IP_BLK_REV_2_2)
+               idx = 2;
+       else
+               idx = 3;
+
+       pci_sz = 1ull << __ilog2_u64(sz);
+
+       dev_dbg(pcie->bus, "R0 bus_start: %llx phys_start: %llx size: %llx\n",
+               (u64)bus_start, (u64)phys_start, (u64)sz);
+
+       /* if we aren't an exact power of two match, pci_sz is smaller
+        * round it up to the next power of two.  We report the actual
+        * size to pci region tracking.
+        */
+       if (pci_sz != sz)
+               sz = 2ull << __ilog2_u64(sz);
+
+       fsl_pcie_setup_inbound_win(pcie, idx--, true,
+                                  CONFIG_SYS_PCI_MEMORY_PHYS,
+                                  CONFIG_SYS_PCI_MEMORY_BUS, sz);
+#if defined(CONFIG_PHYS_64BIT) && defined(CONFIG_SYS_PCI_64BIT)
+       /*
+        * On 64-bit capable systems, set up a mapping for all of DRAM
+        * in high pci address space.
+        */
+       pci_sz = 1ull << __ilog2_u64(gd->ram_size);
+       /* round up to the next largest power of two */
+       if (gd->ram_size > pci_sz)
+               pci_sz = 1ull << (__ilog2_u64(gd->ram_size) + 1);
+
+       dev_dbg(pcie->bus, "R64 bus_start: %llx phys_start: %llx size: %llx\n",
+               (u64)CONFIG_SYS_PCI64_MEMORY_BUS,
+               (u64)CONFIG_SYS_PCI_MEMORY_PHYS, (u64)pci_sz);
+
+       fsl_pcie_setup_inbound_win(pcie, idx--, true,
+                                  CONFIG_SYS_PCI_MEMORY_PHYS,
+                                  CONFIG_SYS_PCI64_MEMORY_BUS, pci_sz);
+#endif
+
+       return 0;
+}
+
+static int fsl_pcie_init_atmu(struct fsl_pcie *pcie)
+{
+       fsl_pcie_setup_outbound_wins(pcie);
+       fsl_pcie_setup_inbound_wins(pcie);
+
+       return 0;
+}
+
+static int fsl_pcie_init_port(struct fsl_pcie *pcie)
+{
+       ccsr_fsl_pci_t *regs = pcie->regs;
+       u32 val_32;
+       u16 val_16;
+
+       fsl_pcie_init_atmu(pcie);
+
+       if (IS_ENABLED(CONFIG_FSL_PCIE_DISABLE_ASPM)) {
+               val_32 = 0;
+               fsl_pcie_hose_read_config_dword(pcie, PCI_LCR, &val_32);
+               val_32 &= ~0x03;
+               fsl_pcie_hose_write_config_dword(pcie, PCI_LCR, val_32);
+               udelay(1);
+       }
+
+       if (IS_ENABLED(CONFIG_FSL_PCIE_RESET)) {
+               u16 ltssm;
+               int i;
+
+               if (pcie->block_rev >= PEX_IP_BLK_REV_3_0) {
+                       /* assert PCIe reset */
+                       setbits_be32(&regs->pdb_stat, 0x08000000);
+                       (void)in_be32(&regs->pdb_stat);
+                       udelay(1000);
+                       /* clear PCIe reset */
+                       clrbits_be32(&regs->pdb_stat, 0x08000000);
+                       asm("sync;isync");
+                       for (i = 0; i < 100 && !fsl_pcie_link_up(pcie); i++)
+                               udelay(1000);
+               } else {
+                       fsl_pcie_hose_read_config_word(pcie, PCI_LTSSM, &ltssm);
+                       if (ltssm == 1) {
+                               /* assert PCIe reset */
+                               setbits_be32(&regs->pdb_stat, 0x08000000);
+                               (void)in_be32(&regs->pdb_stat);
+                               udelay(100);
+                               /* clear PCIe reset */
+                               clrbits_be32(&regs->pdb_stat, 0x08000000);
+                               asm("sync;isync");
+                               for (i = 0; i < 100 &&
+                                    !fsl_pcie_link_up(pcie); i++)
+                                       udelay(1000);
+                       }
+               }
+       }
+
+       if (IS_ENABLED(CONFIG_SYS_P4080_ERRATUM_PCIE_A003) &&
+           !fsl_pcie_link_up(pcie)) {
+               serdes_corenet_t *srds_regs;
+
+               srds_regs = (void *)CONFIG_SYS_FSL_CORENET_SERDES_ADDR;
+               val_32 = in_be32(&srds_regs->srdspccr0);
+
+               if ((val_32 >> 28) == 3) {
+                       int i;
+
+                       out_be32(&srds_regs->srdspccr0, 2 << 28);
+                       setbits_be32(&regs->pdb_stat, 0x08000000);
+                       in_be32(&regs->pdb_stat);
+                       udelay(100);
+                       clrbits_be32(&regs->pdb_stat, 0x08000000);
+                       asm("sync;isync");
+                       for (i = 0; i < 100 && !fsl_pcie_link_up(pcie); i++)
+                               udelay(1000);
+               }
+       }
+
+       /*
+        * The Read-Only Write Enable bit defaults to 1 instead of 0.
+        * Set to 0 to protect the read-only registers.
+        */
+       if (IS_ENABLED(CONFIG_SYS_FSL_ERRATUM_A007815))
+               clrbits_be32(&regs->dbi_ro_wr_en, 0x01);
+
+       /*
+        * Enable All Error Interrupts except
+        * - Master abort (pci)
+        * - Master PERR (pci)
+        * - ICCA (PCIe)
+        */
+       out_be32(&regs->peer, ~0x20140);
+
+       /* set URR, FER, NFER (but not CER) */
+       fsl_pcie_hose_read_config_dword(pcie, PCI_DCR, &val_32);
+       val_32 |= 0xf000e;
+       fsl_pcie_hose_write_config_dword(pcie, PCI_DCR, val_32);
+
+       /* Clear all error indications */
+       out_be32(&regs->pme_msg_det, 0xffffffff);
+       out_be32(&regs->pme_msg_int_en, 0xffffffff);
+       out_be32(&regs->pedr, 0xffffffff);
+
+       fsl_pcie_hose_read_config_word(pcie, PCI_DSR, &val_16);
+       if (val_16)
+               fsl_pcie_hose_write_config_word(pcie, PCI_DSR, 0xffff);
+
+       fsl_pcie_hose_read_config_word(pcie, PCI_SEC_STATUS, &val_16);
+       if (val_16)
+               fsl_pcie_hose_write_config_word(pcie, PCI_SEC_STATUS, 0xffff);
+
+       return 0;
+}
+
+static int fsl_pcie_fixup_classcode(struct fsl_pcie *pcie)
+{
+       ccsr_fsl_pci_t *regs = pcie->regs;
+       u32 val;
+
+       setbits_be32(&regs->dbi_ro_wr_en, 0x01);
+       fsl_pcie_hose_read_config_dword(pcie, PCI_CLASS_REVISION, &val);
+       val &= 0xff;
+       val |= PCI_CLASS_BRIDGE_PCI << 16;
+       fsl_pcie_hose_write_config_dword(pcie, PCI_CLASS_REVISION, val);
+       clrbits_be32(&regs->dbi_ro_wr_en, 0x01);
+
+       return 0;
+}
+
+static int fsl_pcie_init_rc(struct fsl_pcie *pcie)
+{
+       return fsl_pcie_fixup_classcode(pcie);
+}
+
+static int fsl_pcie_init_ep(struct fsl_pcie *pcie)
+{
+       fsl_pcie_config_ready(pcie);
+
+       return 0;
+}
+
+static int fsl_pcie_probe(struct udevice *dev)
+{
+       struct fsl_pcie *pcie = dev_get_priv(dev);
+       ccsr_fsl_pci_t *regs = pcie->regs;
+       u16 val_16;
+
+       pcie->bus = dev;
+       pcie->block_rev = in_be32(&regs->block_rev1);
+
+       list_add(&pcie->list, &fsl_pcie_list);
+       pcie->enabled = is_serdes_configured(PCIE1 + pcie->idx);
+       if (!pcie->enabled) {
+               printf("PCIe%d: %s disabled\n", pcie->idx, dev->name);
+               return 0;
+       }
+
+       fsl_pcie_setup_law(pcie);
+
+       pcie->mode = fsl_pcie_is_agent(pcie);
+
+       fsl_pcie_init_port(pcie);
+
+       printf("PCIe%d: %s ", pcie->idx, dev->name);
+
+       if (pcie->mode) {
+               printf("Endpoint");
+               fsl_pcie_init_ep(pcie);
+       } else {
+               printf("Root Complex");
+               fsl_pcie_init_rc(pcie);
+       }
+
+       if (!fsl_pcie_link_up(pcie)) {
+               printf(": %s\n", pcie->mode ? "undetermined link" : "no link");
+               return 0;
+       }
+
+       fsl_pcie_hose_read_config_word(pcie, PCI_LSR, &val_16);
+       printf(": x%d gen%d\n", (val_16 & 0x3f0) >> 4, (val_16 & 0xf));
+
+       return 0;
+}
+
+static int fsl_pcie_ofdata_to_platdata(struct udevice *dev)
+{
+       struct fsl_pcie *pcie = dev_get_priv(dev);
+       int ret;
+
+       pcie->regs = dev_remap_addr(dev);
+       if (!pcie->regs) {
+               pr_err("\"reg\" resource not found\n");
+               return -EINVAL;
+       }
+
+       ret = dev_read_u32(dev, "law_trgt_if", &pcie->law_trgt_if);
+       if (ret < 0) {
+               pr_err("\"law_trgt_if\" not found\n");
+               return ret;
+       }
+
+       pcie->idx = (dev_read_addr(dev) - 0xffe240000) / 0x10000;
+
+       return 0;
+}
+
+static const struct dm_pci_ops fsl_pcie_ops = {
+       .read_config    = fsl_pcie_read_config,
+       .write_config   = fsl_pcie_write_config,
+};
+
+static const struct udevice_id fsl_pcie_ids[] = {
+       { .compatible = "fsl,pcie-t2080" },
+       { }
+};
+
+U_BOOT_DRIVER(fsl_pcie) = {
+       .name = "fsl_pcie",
+       .id = UCLASS_PCI,
+       .of_match = fsl_pcie_ids,
+       .ops = &fsl_pcie_ops,
+       .ofdata_to_platdata = fsl_pcie_ofdata_to_platdata,
+       .probe = fsl_pcie_probe,
+       .priv_auto_alloc_size = sizeof(struct fsl_pcie),
+};
diff --git a/drivers/pci/pcie_fsl.h b/drivers/pci/pcie_fsl.h
new file mode 100644 (file)
index 0000000..5eefc31
--- /dev/null
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2019 NXP
+ *
+ * PCIe DM U-Boot driver for Freescale PowerPC SoCs
+ * Author: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+ */
+
+#ifndef _PCIE_FSL_H_
+#define _PCIE_FSL_H_
+
+#ifdef CONFIG_SYS_FSL_PCI_VER_3_X
+#define FSL_PCIE_CAP_ID                        0x70
+#else
+#define FSL_PCIE_CAP_ID                        0x4c
+#endif
+/* PCIe Device Control Register */
+#define PCI_DCR                                (FSL_PCIE_CAP_ID + 0x08)
+/* PCIe Device Status Register */
+#define PCI_DSR                                (FSL_PCIE_CAP_ID + 0x0a)
+/* PCIe Link Control Register */
+#define PCI_LCR                                (FSL_PCIE_CAP_ID + 0x10)
+/* PCIe Link Status Register */
+#define PCI_LSR                                (FSL_PCIE_CAP_ID + 0x12)
+
+#ifndef CONFIG_SYS_PCI_MEMORY_BUS
+#define CONFIG_SYS_PCI_MEMORY_BUS      0
+#endif
+
+#ifndef CONFIG_SYS_PCI_MEMORY_PHYS
+#define CONFIG_SYS_PCI_MEMORY_PHYS     0
+#endif
+
+#if defined(CONFIG_SYS_PCI_64BIT) && !defined(CONFIG_SYS_PCI64_MEMORY_BUS)
+#define CONFIG_SYS_PCI64_MEMORY_BUS    (64ull * 1024 * 1024 * 1024)
+#endif
+
+#define PEX_CSR0_LTSSM_MASK            0xFC
+#define PEX_CSR0_LTSSM_SHIFT           2
+#define LTSSM_L0_REV3                  0x11
+#define LTSSM_L0                       0x16
+
+struct fsl_pcie {
+       int idx;
+       struct udevice *bus;
+       void __iomem *regs;
+       u32 law_trgt_if;                /* LAW target ID */
+       u32 block_rev;                  /* IP block revision */
+       bool mode;                      /* RC&EP mode flag */
+       bool enabled;                   /* Enable status */
+       struct list_head list;
+};
+
+extern struct list_head fsl_pcie_list;
+
+#endif /* _PCIE_FSL_H_ */
diff --git a/drivers/pci/pcie_fsl_fixup.c b/drivers/pci/pcie_fsl_fixup.c
new file mode 100644 (file)
index 0000000..cbdc0ef
--- /dev/null
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0+ OR X11
+/*
+ * Copyright 2019 NXP
+ *
+ * PCIe Kernel DT fixup of DM U-Boot driver for Freescale PowerPC SoCs
+ * Author: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+ */
+
+#include <common.h>
+#ifdef CONFIG_OF_BOARD_SETUP
+#include <dm.h>
+#include <fdt_support.h>
+#include <asm/fsl_pci.h>
+#include <linux/libfdt.h>
+#include "pcie_fsl.h"
+
+static void ft_fsl_pcie_setup(void *blob, struct fsl_pcie *pcie)
+{
+       struct pci_controller *hose = dev_get_uclass_priv(pcie->bus);
+       fdt_addr_t regs_addr;
+       int off;
+
+       regs_addr = dev_read_addr(pcie->bus);
+       off = fdt_node_offset_by_compat_reg(blob, FSL_PCIE_COMPAT, regs_addr);
+       if (off < 0) {
+               printf("%s: Fail to find PCIe node@0x%pa\n",
+                      FSL_PCIE_COMPAT, &regs_addr);
+               return;
+       }
+
+       if (!hose || !pcie->enabled)
+               fdt_del_node(blob, off);
+       else
+               fdt_pci_dma_ranges(blob, off, hose);
+}
+
+/* Fixup Kernel DT for PCIe */
+void pci_of_setup(void *blob, bd_t *bd)
+{
+       struct fsl_pcie *pcie;
+
+       list_for_each_entry(pcie, &fsl_pcie_list, list)
+               ft_fsl_pcie_setup(blob, pcie);
+}
+
+#else
+void pci_of_setup(void *blob, bd_t *bd)
+{
+}
+#endif