MLK-22398-1 pcie_imx: Update PCIE IMX driver
authorYe Li <ye.li@nxp.com>
Tue, 30 Jul 2019 08:34:07 +0000 (01:34 -0700)
committerYe Li <ye.li@nxp.com>
Thu, 29 Apr 2021 07:56:30 +0000 (00:56 -0700)
Update PCIE IMX DM driver supports iMX8QM/QXP and
iMX6QDL/QP/SX. Non-DM driver supports iMX6QDL/QP/SX.
The changes in DM parses cfg/mem/io ranges, gpios, regulators and
clocks (imx8 only) from DTS for RC mode, and set iATU mapping for
each regions.

The original iATU mapping sets full PCI region to CFG space. iATU
translates MEM/IO TLP to CFG TLP when the address is falled into
the region.
The new mapping sets CFG/IO/MEM spaces to align with kernel like below
   ATU region 0 for MEM access
   ATU region 1 for CFG0 or CFG1 access by bus id
   ATU region 2 for IO access

Signed-off-by: Ye Li <ye.li@nxp.com>
(cherry picked from commit eb0959cbf2118342a544440f124e0c81eeba70e3)
(cherry picked from commit bec6f34702a66905f86c5e1b58872200b315ba92)

drivers/pci/pcie_imx.c

index fb5690e..f429240 100644 (file)
@@ -5,6 +5,7 @@
  * Copyright (C) 2013 Marek Vasut <marex@denx.de>
  *
  * Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
+ * Copyright 2019 NXP
  *
  * Based on upstream Linux kernel driver:
  * pci-imx6.c:         Sean Cross <xobs@kosagi.com>
 #include <log.h>
 #include <malloc.h>
 #include <pci.h>
+#if CONFIG_IS_ENABLED(CLK)
+#include <clk.h>
+#else
 #include <asm/arch/clock.h>
+#endif
 #include <asm/arch/iomux.h>
+#ifdef CONFIG_MX6
 #include <asm/arch/crm_regs.h>
+#endif
 #include <asm/gpio.h>
 #include <asm/io.h>
 #include <dm.h>
 #include <linux/delay.h>
 #include <linux/sizes.h>
+#include <linux/ioport.h>
 #include <errno.h>
 #include <asm/arch/sys_proto.h>
+#include <syscon.h>
+#include <regmap.h>
+#include <asm-generic/gpio.h>
+#include <dt-bindings/soc/imx8_hsio.h>
+#include <power/regulator.h>
+#include <dm/device_compat.h>
+
+enum imx_pcie_variants {
+       IMX6Q,
+       IMX6SX,
+       IMX6QP,
+       IMX8QM,
+       IMX8QXP,
+};
 
 #define PCI_ACCESS_READ  0
 #define PCI_ACCESS_WRITE 1
 
 #ifdef CONFIG_MX6SX
 #define MX6_DBI_ADDR   0x08ffc000
-#define MX6_IO_ADDR    0x08000000
-#define MX6_MEM_ADDR   0x08100000
+#define MX6_IO_ADDR    0x08f80000
+#define MX6_MEM_ADDR   0x08000000
 #define MX6_ROOT_ADDR  0x08f00000
 #else
 #define MX6_DBI_ADDR   0x01ffc000
-#define MX6_IO_ADDR    0x01000000
-#define MX6_MEM_ADDR   0x01100000
+#define MX6_IO_ADDR    0x01f80000
+#define MX6_MEM_ADDR   0x01000000
 #define MX6_ROOT_ADDR  0x01f00000
 #endif
 #define MX6_DBI_SIZE   0x4000
-#define MX6_IO_SIZE    0x100000
-#define MX6_MEM_SIZE   0xe00000
-#define MX6_ROOT_SIZE  0xfc000
+#define MX6_IO_SIZE    0x10000
+#define MX6_MEM_SIZE   0xf00000
+#define MX6_ROOT_SIZE  0x80000
 
 /* PCIe Port Logic registers (memory-mapped) */
 #define PL_OFFSET 0x700
 #define PCIE_PHY_DEBUG_R1_LINK_UP              (1 << 4)
 #define PCIE_PHY_DEBUG_R1_LINK_IN_TRAINING     (1 << 29)
 
+#define PCIE_PORT_LINK_CONTROL         0x710
+#define PORT_LINK_MODE_MASK            (0x3f << 16)
+#define PORT_LINK_MODE_1_LANES         (0x1 << 16)
+#define PORT_LINK_MODE_2_LANES         (0x3 << 16)
+#define PORT_LINK_MODE_4_LANES         (0x7 << 16)
+#define PORT_LINK_MODE_8_LANES         (0xf << 16)
+
+
+#define PCIE_LINK_WIDTH_SPEED_CONTROL  0x80C
+#define PORT_LOGIC_SPEED_CHANGE                (0x1 << 17)
+#define PORT_LOGIC_LINK_WIDTH_MASK     (0x1f << 8)
+#define PORT_LOGIC_LINK_WIDTH_1_LANES  (0x1 << 8)
+#define PORT_LOGIC_LINK_WIDTH_2_LANES  (0x2 << 8)
+#define PORT_LOGIC_LINK_WIDTH_4_LANES  (0x4 << 8)
+#define PORT_LOGIC_LINK_WIDTH_8_LANES  (0x8 << 8)
+
 #define PCIE_PHY_CTRL (PL_OFFSET + 0x114)
 #define PCIE_PHY_CTRL_DATA_LOC 0
 #define PCIE_PHY_CTRL_CAP_ADR_LOC 16
 #define PCIE_ATU_VIEWPORT              0x900
 #define PCIE_ATU_REGION_INBOUND                (0x1 << 31)
 #define PCIE_ATU_REGION_OUTBOUND       (0x0 << 31)
+#define PCIE_ATU_REGION_INDEX2         (0x2 << 0)
 #define PCIE_ATU_REGION_INDEX1         (0x1 << 0)
 #define PCIE_ATU_REGION_INDEX0         (0x0 << 0)
 #define PCIE_ATU_CR1                   0x904
 #define PCIE_ATU_FUNC(x)               (((x) & 0x7) << 16)
 #define PCIE_ATU_UPPER_TARGET          0x91C
 
-struct imx_pcie_priv {
-       void __iomem            *dbi_base;
-       void __iomem            *cfg_base;
-};
+#define PCIE_MISC_CTRL                 (PL_OFFSET + 0x1BC)
+#define PCIE_MISC_DBI_RO_WR_EN         BIT(0)
+
+/* iMX8 HSIO registers */
+#define IMX8QM_LPCG_PHYX2_OFFSET               0x00000
+#define IMX8QM_CSR_PHYX2_OFFSET                        0x90000
+#define IMX8QM_CSR_PHYX1_OFFSET                        0xA0000
+#define IMX8QM_CSR_PHYX_STTS0_OFFSET           0x4
+#define IMX8QM_CSR_PCIEA_OFFSET                        0xB0000
+#define IMX8QM_CSR_PCIEB_OFFSET                        0xC0000
+#define IMX8QM_CSR_PCIE_CTRL1_OFFSET           0x4
+#define IMX8QM_CSR_PCIE_CTRL2_OFFSET           0x8
+#define IMX8QM_CSR_PCIE_STTS0_OFFSET           0xC
+#define IMX8QM_CSR_MISC_OFFSET                 0xE0000
+
+#define IMX8QM_LPCG_PHY_PCG0                   BIT(1)
+#define IMX8QM_LPCG_PHY_PCG1                   BIT(5)
+
+#define IMX8QM_CTRL_LTSSM_ENABLE               BIT(4)
+#define IMX8QM_CTRL_READY_ENTR_L23             BIT(5)
+#define IMX8QM_CTRL_PM_XMT_TURNOFF             BIT(9)
+#define IMX8QM_CTRL_BUTTON_RST_N               BIT(21)
+#define IMX8QM_CTRL_PERST_N                    BIT(22)
+#define IMX8QM_CTRL_POWER_UP_RST_N             BIT(23)
+
+#define IMX8QM_CTRL_STTS0_PM_LINKST_IN_L2      BIT(13)
+#define IMX8QM_CTRL_STTS0_PM_REQ_CORE_RST      BIT(19)
+#define IMX8QM_STTS0_LANE0_TX_PLL_LOCK         BIT(4)
+#define IMX8QM_STTS0_LANE1_TX_PLL_LOCK         BIT(12)
+
+#define IMX8QM_PCIE_TYPE_MASK                  (0xF << 24)
+
+#define IMX8QM_PHYX2_CTRL0_APB_MASK            0x3
+#define IMX8QM_PHY_APB_RSTN_0                  BIT(0)
+#define IMX8QM_PHY_APB_RSTN_1                  BIT(1)
+
+#define IMX8QM_MISC_IOB_RXENA                  BIT(0)
+#define IMX8QM_MISC_IOB_TXENA                  BIT(1)
+#define IMX8QM_CSR_MISC_IOB_A_0_TXOE           BIT(2)
+#define IMX8QM_CSR_MISC_IOB_A_0_M1M0_MASK      (0x3 << 3)
+#define IMX8QM_CSR_MISC_IOB_A_0_M1M0_2         BIT(4)
+#define IMX8QM_MISC_PHYX1_EPCS_SEL             BIT(12)
+#define IMX8QM_MISC_PCIE_AB_SELECT             BIT(13)
+
+#define HW_PHYX2_CTRL0_PIPE_LN2LK_MASK (0xF << 13)
+#define HW_PHYX2_CTRL0_PIPE_LN2LK_0    BIT(13)
+#define HW_PHYX2_CTRL0_PIPE_LN2LK_1    BIT(14)
+#define HW_PHYX2_CTRL0_PIPE_LN2LK_2    BIT(15)
+#define HW_PHYX2_CTRL0_PIPE_LN2LK_3    BIT(16)
+
+#define PHY_PLL_LOCK_WAIT_MAX_RETRIES  2000
 
 #ifdef DEBUG
 
@@ -114,6 +200,7 @@ struct imx_pcie_priv {
 
 static void print_regs(int contain_pcie_reg)
 {
+#ifdef CONFIG_MX6
        u32 val;
        struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR;
        struct mxc_ccm_reg *ccm_regs = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
@@ -135,12 +222,53 @@ static void print_regs(int contain_pcie_reg)
                val = readl(MX6_DBI_ADDR + 0x72c);
                DBGF("dbr1 offset 0x72c %08x\n", val);
        }
+#endif
 }
 #else
 #define DBGF(x...)
 static void print_regs(int contain_pcie_reg) {}
 #endif
 
+struct imx_pcie_priv {
+       void __iomem            *dbi_base;
+       void __iomem            *cfg_base;
+       void __iomem            *cfg1_base;
+       enum imx_pcie_variants variant;
+       struct regmap           *iomuxc_gpr;
+       u32                                     hsio_cfg;
+       u32                                     ctrl_id;
+       u32                                     ext_osc;
+       u32                                     cpu_base;
+       u32                                     lanes;
+       u32                                     cfg_size;
+       int                                     cpu_addr_offset;
+       struct gpio_desc                clkreq_gpio;
+       struct gpio_desc                dis_gpio;
+       struct gpio_desc                reset_gpio;
+       struct gpio_desc                power_on_gpio;
+
+       struct pci_region               *io;
+       struct pci_region               *mem;
+       struct pci_region               *pref;
+
+#if CONFIG_IS_ENABLED(CLK)
+       struct clk                      pcie_bus;
+       struct clk                      pcie_phy;
+       struct clk                      pcie_inbound_axi;
+       struct clk                      pcie_per;
+       struct clk                      phy_per;
+       struct clk                      misc_per;
+       struct clk                      pcie;
+       struct clk                      pcie_ext_src;
+#endif
+
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+       struct udevice          *epdev_on;
+       struct udevice          *pcie_bus_regulator;
+       struct udevice          *pcie_phy_regulator;
+#endif
+};
+
 /*
  * PHY access functions
  */
@@ -274,6 +402,32 @@ static int pcie_phy_write(void __iomem *dbi_base, int addr, int data)
        return 0;
 }
 
+#if !CONFIG_IS_ENABLED(DM_PCI)
+void imx_pcie_gpr_read(struct imx_pcie_priv *priv, uint offset, uint *valp)
+{
+       struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR;
+       *valp = readl(&iomuxc_regs->gpr[offset >> 2]);
+}
+
+void imx_pcie_gpr_update_bits(struct imx_pcie_priv *priv, uint offset, uint mask, uint val)
+{
+       struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR;
+       clrsetbits_32(&iomuxc_regs->gpr[offset >> 2], mask, val);
+}
+
+#else
+void imx_pcie_gpr_read(struct imx_pcie_priv *priv, uint offset, uint *valp)
+{
+       regmap_read(priv->iomuxc_gpr, offset, valp);
+}
+
+void imx_pcie_gpr_update_bits(struct imx_pcie_priv *priv, uint offset, uint mask, uint val)
+{
+       regmap_update_bits(priv->iomuxc_gpr, offset, mask, val);
+}
+
+#endif
+
 static int imx6_pcie_link_up(struct imx_pcie_priv *priv)
 {
        u32 rc, ltssm;
@@ -316,45 +470,122 @@ static int imx6_pcie_link_up(struct imx_pcie_priv *priv)
        return 0;
 }
 
-/*
- * iATU region setup
- */
-static int imx_pcie_regions_setup(struct imx_pcie_priv *priv)
+/* Fix class value */
+static void imx_pcie_fix_class(struct imx_pcie_priv *priv)
 {
-       /*
-        * i.MX6 defines 16MB in the AXI address map for PCIe.
-        *
-        * That address space excepted the pcie registers is
-        * split and defined into different regions by iATU,
-        * with sizes and offsets as follows:
-        *
-        * 0x0100_0000 --- 0x010F_FFFF 1MB IORESOURCE_IO
-        * 0x0110_0000 --- 0x01EF_FFFF 14MB IORESOURCE_MEM
-        * 0x01F0_0000 --- 0x01FF_FFFF 1MB Cfg + Registers
-        */
+       writew(PCI_CLASS_BRIDGE_PCI, priv->dbi_base + PCI_CLASS_DEVICE);
+}
 
-       /* CMD reg:I/O space, MEM space, and Bus Master Enable */
-       setbits_le32(priv->dbi_base + PCI_COMMAND,
-                    PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+/* Clear multi-function bit */
+static void imx_pcie_clear_multifunction(struct imx_pcie_priv *priv)
+{
+       writeb(PCI_HEADER_TYPE_BRIDGE, priv->dbi_base + PCI_HEADER_TYPE);
+}
 
-       /* Set the CLASS_REV of RC CFG header to PCI_CLASS_BRIDGE_PCI */
-       setbits_le32(priv->dbi_base + PCI_CLASS_REVISION,
-                    PCI_CLASS_BRIDGE_PCI << 16);
+static void imx_pcie_setup_ctrl(struct imx_pcie_priv *priv)
+{
+       u32 val;
+
+       writel(PCIE_MISC_DBI_RO_WR_EN, priv->dbi_base + PCIE_MISC_CTRL);
+
+       /* Set the number of lanes */
+       val = readl(priv->dbi_base + PCIE_PORT_LINK_CONTROL);
+       val &= ~PORT_LINK_MODE_MASK;
+       switch (priv->lanes) {
+       case 1:
+               val |= PORT_LINK_MODE_1_LANES;
+               break;
+       case 2:
+               val |= PORT_LINK_MODE_2_LANES;
+               break;
+       case 4:
+               val |= PORT_LINK_MODE_4_LANES;
+               break;
+       case 8:
+               val |= PORT_LINK_MODE_8_LANES;
+               break;
+       default:
+               printf("num-lanes %u: invalid value\n", priv->lanes);
+               return;
+       }
+       writel(val, priv->dbi_base + PCIE_PORT_LINK_CONTROL);
+
+       /* Set link width speed control register */
+       val = readl(priv->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
+       val &= ~PORT_LOGIC_LINK_WIDTH_MASK;
+       switch (priv->lanes) {
+       case 1:
+               val |= PORT_LOGIC_LINK_WIDTH_1_LANES;
+               break;
+       case 2:
+               val |= PORT_LOGIC_LINK_WIDTH_2_LANES;
+               break;
+       case 4:
+               val |= PORT_LOGIC_LINK_WIDTH_4_LANES;
+               break;
+       case 8:
+               val |= PORT_LOGIC_LINK_WIDTH_8_LANES;
+               break;
+       }
+       writel(val, priv->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
 
-       /* Region #0 is used for Outbound CFG space access. */
-       writel(0, priv->dbi_base + PCIE_ATU_VIEWPORT);
+       /* setup RC BARs */
+       writel(0, priv->dbi_base + PCI_BASE_ADDRESS_0);
+       writel(0, priv->dbi_base + PCI_BASE_ADDRESS_1);
 
-       writel(lower_32_bits((uintptr_t)priv->cfg_base),
-              priv->dbi_base + PCIE_ATU_LOWER_BASE);
-       writel(upper_32_bits((uintptr_t)priv->cfg_base),
-              priv->dbi_base + PCIE_ATU_UPPER_BASE);
-       writel(lower_32_bits((uintptr_t)priv->cfg_base + MX6_ROOT_SIZE),
-              priv->dbi_base + PCIE_ATU_LIMIT);
+       /* setup bus numbers */
+       val = readl(priv->dbi_base + PCI_PRIMARY_BUS);
+       val &= 0xff000000;
+       val |= 0x00ff0100;
+       writel(val, priv->dbi_base + PCI_PRIMARY_BUS);
+
+       /* setup command register */
+       val = readl(priv->dbi_base + PCI_COMMAND);
+       val &= 0xffff0000;
+       val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+               PCI_COMMAND_MASTER;
+       writel(val, priv->dbi_base + PCI_COMMAND);
+
+       imx_pcie_fix_class(priv);
+       imx_pcie_clear_multifunction(priv);
+
+       writel(0, priv->dbi_base + PCIE_MISC_CTRL);
+}
 
-       writel(0, priv->dbi_base + PCIE_ATU_LOWER_TARGET);
-       writel(0, priv->dbi_base + PCIE_ATU_UPPER_TARGET);
-       writel(PCIE_ATU_TYPE_CFG0, priv->dbi_base + PCIE_ATU_CR1);
+static void imx_pcie_atu_outbound_set(struct imx_pcie_priv *priv, int idx, int type,
+                                     u64 phys, u64 bus_addr, u32 size)
+{
+       writel(PCIE_ATU_REGION_OUTBOUND | idx, priv->dbi_base + PCIE_ATU_VIEWPORT);
+       writel((u32)(phys + priv->cpu_addr_offset), priv->dbi_base + PCIE_ATU_LOWER_BASE);
+       writel((phys + priv->cpu_addr_offset) >> 32, priv->dbi_base + PCIE_ATU_UPPER_BASE);
+       writel((u32)(phys + priv->cpu_addr_offset) + size - 1, priv->dbi_base + PCIE_ATU_LIMIT);
+       writel((u32)bus_addr, priv->dbi_base + PCIE_ATU_LOWER_TARGET);
+       writel(bus_addr >> 32, priv->dbi_base + PCIE_ATU_UPPER_TARGET);
+       writel(type, priv->dbi_base + PCIE_ATU_CR1);
        writel(PCIE_ATU_ENABLE, priv->dbi_base + PCIE_ATU_CR2);
+}
+
+/*
+ * iATU region setup
+ */
+static int imx_pcie_regions_setup(struct imx_pcie_priv *priv)
+{
+       if (priv->io)
+               /* ATU : OUTBOUND : IO */
+               imx_pcie_atu_outbound_set(priv, PCIE_ATU_REGION_INDEX2,
+                                        PCIE_ATU_TYPE_IO,
+                                        priv->io->phys_start,
+                                        priv->io->bus_start,
+                                        priv->io->size);
+
+       if (priv->mem)
+               /* ATU : OUTBOUND : MEM */
+               imx_pcie_atu_outbound_set(priv, PCIE_ATU_REGION_INDEX0,
+                                        PCIE_ATU_TYPE_MEM,
+                                        priv->mem->phys_start,
+                                        priv->mem->bus_start,
+                                        priv->mem->size);
+
 
        return 0;
 }
@@ -367,30 +598,40 @@ static void __iomem *get_bus_address(struct imx_pcie_priv *priv,
 {
        void __iomem *va_address;
 
-       /* Reconfigure Region #0 */
-       writel(0, priv->dbi_base + PCIE_ATU_VIEWPORT);
-
-       if (PCI_BUS(d) < 2)
-               writel(PCIE_ATU_TYPE_CFG0, priv->dbi_base + PCIE_ATU_CR1);
-       else
-               writel(PCIE_ATU_TYPE_CFG1, priv->dbi_base + PCIE_ATU_CR1);
-
        if (PCI_BUS(d) == 0) {
+               /* Outbound TLP matched primary interface of the bridge */
                va_address = priv->dbi_base;
        } else {
-               writel(d << 8, priv->dbi_base + PCIE_ATU_LOWER_TARGET);
-               va_address = priv->cfg_base;
+               if (PCI_BUS(d) < 2) {
+                       /* Outbound TLP matched secondary interface of the bridge changes to CFG0 */
+                       imx_pcie_atu_outbound_set(priv, PCIE_ATU_REGION_INDEX1,
+                                        PCIE_ATU_TYPE_CFG0,
+                                        (ulong)priv->cfg_base,
+                                        (u64)d << 8,
+                                        priv->cfg_size >> 1);
+                       va_address = priv->cfg_base;
+               } else {
+                       /* Outbound TLP matched the bus behind the bridge uses type CFG1 */
+                       imx_pcie_atu_outbound_set(priv, PCIE_ATU_REGION_INDEX1,
+                                        PCIE_ATU_TYPE_CFG1,
+                                        (ulong)priv->cfg1_base,
+                                        (u64)d << 8,
+                                        priv->cfg_size >> 1);
+                       va_address = priv->cfg1_base;
+               }
        }
 
        va_address += (where & ~0x3);
 
        return va_address;
+
 }
 
 static int imx_pcie_addr_valid(pci_dev_t d)
 {
-       if ((PCI_BUS(d) == 0) && (PCI_DEV(d) > 1))
+       if ((PCI_BUS(d) == 0) && (PCI_DEV(d) > 0))
                return -EINVAL;
+       /* ARI forward is not enabled, so non-zero device at downstream must be blocked */
        if ((PCI_BUS(d) == 1) && (PCI_DEV(d) > 0))
                return -EINVAL;
        return 0;
@@ -411,6 +652,7 @@ static int imx_pcie_addr_valid(pci_dev_t d)
  */
 static void imx_pcie_fix_dabt_handler(bool set)
 {
+#ifdef CONFIG_MX6
        extern uint32_t *_data_abort;
        uint32_t *data_abort_addr = (uint32_t *)&_data_abort;
 
@@ -425,6 +667,7 @@ static void imx_pcie_fix_dabt_handler(bool set)
        } else {
                *data_abort_addr = data_abort_backup;
        }
+#endif
 }
 
 static int imx_pcie_read_cfg(struct imx_pcie_priv *priv, pci_dev_t d,
@@ -436,7 +679,7 @@ static int imx_pcie_read_cfg(struct imx_pcie_priv *priv, pci_dev_t d,
        ret = imx_pcie_addr_valid(d);
        if (ret) {
                *val = 0xffffffff;
-               return ret;
+               return 0;
        }
 
        va_address = get_bus_address(priv, d, where);
@@ -480,28 +723,337 @@ static int imx_pcie_write_cfg(struct imx_pcie_priv *priv, pci_dev_t d,
        return 0;
 }
 
+static int imx8_pcie_assert_core_reset(struct imx_pcie_priv *priv,
+                                      bool prepare_for_boot)
+{
+       u32 val;
+
+       switch (priv->variant) {
+       case IMX8QXP:
+                       val = IMX8QM_CSR_PCIEB_OFFSET;
+                       imx_pcie_gpr_update_bits(priv,
+                                       val + IMX8QM_CSR_PCIE_CTRL2_OFFSET,
+                                       IMX8QM_CTRL_BUTTON_RST_N,
+                                       IMX8QM_CTRL_BUTTON_RST_N);
+                       imx_pcie_gpr_update_bits(priv,
+                                       val + IMX8QM_CSR_PCIE_CTRL2_OFFSET,
+                                       IMX8QM_CTRL_PERST_N,
+                                       IMX8QM_CTRL_PERST_N);
+                       imx_pcie_gpr_update_bits(priv,
+                                       val + IMX8QM_CSR_PCIE_CTRL2_OFFSET,
+                                       IMX8QM_CTRL_POWER_UP_RST_N,
+                                       IMX8QM_CTRL_POWER_UP_RST_N);
+               break;
+       case IMX8QM:
+                       val = IMX8QM_CSR_PCIEA_OFFSET + priv->ctrl_id * SZ_64K;
+                       imx_pcie_gpr_update_bits(priv,
+                                       val + IMX8QM_CSR_PCIE_CTRL2_OFFSET,
+                                       IMX8QM_CTRL_BUTTON_RST_N,
+                                       IMX8QM_CTRL_BUTTON_RST_N);
+                       imx_pcie_gpr_update_bits(priv,
+                                       val + IMX8QM_CSR_PCIE_CTRL2_OFFSET,
+                                       IMX8QM_CTRL_PERST_N,
+                                       IMX8QM_CTRL_PERST_N);
+                       imx_pcie_gpr_update_bits(priv,
+                                       val + IMX8QM_CSR_PCIE_CTRL2_OFFSET,
+                                       IMX8QM_CTRL_POWER_UP_RST_N,
+                                       IMX8QM_CTRL_POWER_UP_RST_N);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int imx8_pcie_init_phy(struct imx_pcie_priv *priv)
+{
+       u32 tmp, val;
+
+       if (priv->variant == IMX8QM
+               || priv->variant == IMX8QXP) {
+               switch (priv->hsio_cfg) {
+               case PCIEAX2SATA:
+                       /*
+                        * bit 0 rx ena 1.
+                        * bit12 PHY_X1_EPCS_SEL 1.
+                        * bit13 phy_ab_select 0.
+                        */
+                       imx_pcie_gpr_update_bits(priv,
+                               IMX8QM_CSR_PHYX2_OFFSET,
+                               IMX8QM_PHYX2_CTRL0_APB_MASK,
+                               IMX8QM_PHY_APB_RSTN_0
+                               | IMX8QM_PHY_APB_RSTN_1);
+
+                       imx_pcie_gpr_update_bits(priv,
+                               IMX8QM_CSR_MISC_OFFSET,
+                               IMX8QM_MISC_PHYX1_EPCS_SEL,
+                               IMX8QM_MISC_PHYX1_EPCS_SEL);
+                       imx_pcie_gpr_update_bits(priv,
+                               IMX8QM_CSR_MISC_OFFSET,
+                               IMX8QM_MISC_PCIE_AB_SELECT,
+                               0);
+                       break;
+
+               case PCIEAX1PCIEBX1SATA:
+                       tmp = IMX8QM_PHY_APB_RSTN_1;
+                       tmp |= IMX8QM_PHY_APB_RSTN_0;
+                       imx_pcie_gpr_update_bits(priv,
+                               IMX8QM_CSR_PHYX2_OFFSET,
+                               IMX8QM_PHYX2_CTRL0_APB_MASK, tmp);
+
+                       imx_pcie_gpr_update_bits(priv,
+                               IMX8QM_CSR_MISC_OFFSET,
+                               IMX8QM_MISC_PHYX1_EPCS_SEL,
+                               IMX8QM_MISC_PHYX1_EPCS_SEL);
+                       imx_pcie_gpr_update_bits(priv,
+                               IMX8QM_CSR_MISC_OFFSET,
+                               IMX8QM_MISC_PCIE_AB_SELECT,
+                               IMX8QM_MISC_PCIE_AB_SELECT);
+
+                       imx_pcie_gpr_update_bits(priv,
+                               IMX8QM_CSR_PHYX2_OFFSET,
+                               HW_PHYX2_CTRL0_PIPE_LN2LK_MASK,
+                               HW_PHYX2_CTRL0_PIPE_LN2LK_3 | HW_PHYX2_CTRL0_PIPE_LN2LK_0);
+
+                       break;
+
+               case PCIEAX2PCIEBX1:
+                       /*
+                        * bit 0 rx ena 1.
+                        * bit12 PHY_X1_EPCS_SEL 0.
+                        * bit13 phy_ab_select 1.
+                        */
+                       if (priv->ctrl_id)
+                               imx_pcie_gpr_update_bits(priv,
+                                       IMX8QM_CSR_PHYX1_OFFSET,
+                                       IMX8QM_PHY_APB_RSTN_0,
+                                       IMX8QM_PHY_APB_RSTN_0);
+                       else
+                               imx_pcie_gpr_update_bits(priv,
+                                       IMX8QM_CSR_PHYX2_OFFSET,
+                                       IMX8QM_PHYX2_CTRL0_APB_MASK,
+                                       IMX8QM_PHY_APB_RSTN_0
+                                       | IMX8QM_PHY_APB_RSTN_1);
+
+                       imx_pcie_gpr_update_bits(priv,
+                               IMX8QM_CSR_MISC_OFFSET,
+                               IMX8QM_MISC_PHYX1_EPCS_SEL,
+                               0);
+                       imx_pcie_gpr_update_bits(priv,
+                               IMX8QM_CSR_MISC_OFFSET,
+                               IMX8QM_MISC_PCIE_AB_SELECT,
+                               IMX8QM_MISC_PCIE_AB_SELECT);
+                       break;
+               }
+
+               if (priv->ext_osc) {
+                       imx_pcie_gpr_update_bits(priv,
+                               IMX8QM_CSR_MISC_OFFSET,
+                               IMX8QM_MISC_IOB_RXENA,
+                               IMX8QM_MISC_IOB_RXENA);
+                       imx_pcie_gpr_update_bits(priv,
+                               IMX8QM_CSR_MISC_OFFSET,
+                               IMX8QM_MISC_IOB_TXENA,
+                               0);
+               } else {
+                       /* Try to used the internal pll as ref clk */
+                       imx_pcie_gpr_update_bits(priv,
+                               IMX8QM_CSR_MISC_OFFSET,
+                               IMX8QM_MISC_IOB_RXENA,
+                               0);
+                       imx_pcie_gpr_update_bits(priv,
+                               IMX8QM_CSR_MISC_OFFSET,
+                               IMX8QM_MISC_IOB_TXENA,
+                               IMX8QM_MISC_IOB_TXENA);
+                       imx_pcie_gpr_update_bits(priv,
+                               IMX8QM_CSR_MISC_OFFSET,
+                               IMX8QM_CSR_MISC_IOB_A_0_TXOE
+                               | IMX8QM_CSR_MISC_IOB_A_0_M1M0_MASK,
+                               IMX8QM_CSR_MISC_IOB_A_0_TXOE
+                               | IMX8QM_CSR_MISC_IOB_A_0_M1M0_2);
+               }
+
+               val = IMX8QM_CSR_PCIEA_OFFSET
+                       + priv->ctrl_id * SZ_64K;
+               imx_pcie_gpr_update_bits(priv,
+                               val, IMX8QM_PCIE_TYPE_MASK,
+                               0x4 << 24);
+
+               mdelay(10);
+       }
+
+       return 0;
+}
+
+static int imx8_pcie_wait_for_phy_pll_lock(struct imx_pcie_priv *priv)
+{
+       u32 val, tmp, orig;
+       unsigned int retries = 0;
+
+       if (priv->variant == IMX8QXP
+                       || priv->variant == IMX8QM) {
+               for (retries = 0; retries < PHY_PLL_LOCK_WAIT_MAX_RETRIES;
+                               retries++) {
+                       if (priv->hsio_cfg == PCIEAX1PCIEBX1SATA) {
+                               imx_pcie_gpr_read(priv,
+                                           IMX8QM_CSR_PHYX2_OFFSET + 0x4,
+                                           &tmp);
+                               if (priv->ctrl_id == 0) /* pciea 1 lanes */
+                                       orig = IMX8QM_STTS0_LANE0_TX_PLL_LOCK;
+                               else /* pcieb 1 lanes */
+                                       orig = IMX8QM_STTS0_LANE1_TX_PLL_LOCK;
+                               tmp &= orig;
+                               if (tmp == orig) {
+                                       imx_pcie_gpr_update_bits(priv,
+                                               IMX8QM_LPCG_PHYX2_OFFSET,
+                                               IMX8QM_LPCG_PHY_PCG0
+                                               | IMX8QM_LPCG_PHY_PCG1,
+                                               IMX8QM_LPCG_PHY_PCG0
+                                               | IMX8QM_LPCG_PHY_PCG1);
+                                       break;
+                               }
+                       }
+
+                       if (priv->hsio_cfg == PCIEAX2PCIEBX1) {
+                               val = IMX8QM_CSR_PHYX2_OFFSET
+                                       + priv->ctrl_id * SZ_64K;
+                               imx_pcie_gpr_read(priv,
+                                           val + IMX8QM_CSR_PHYX_STTS0_OFFSET,
+                                           &tmp);
+                               orig = IMX8QM_STTS0_LANE0_TX_PLL_LOCK;
+                               if (priv->ctrl_id == 0) /* pciea 2 lanes */
+                                       orig |= IMX8QM_STTS0_LANE1_TX_PLL_LOCK;
+                               tmp &= orig;
+                               if (tmp == orig) {
+                                       val = IMX8QM_CSR_PHYX2_OFFSET
+                                               + priv->ctrl_id * SZ_64K;
+                                       imx_pcie_gpr_update_bits(priv,
+                                               val, IMX8QM_LPCG_PHY_PCG0,
+                                               IMX8QM_LPCG_PHY_PCG0);
+                                       break;
+                               }
+                       }
+                       udelay(10);
+               }
+       }
+
+       if (retries >= PHY_PLL_LOCK_WAIT_MAX_RETRIES) {
+               printf("pcie phy pll can't be locked.\n");
+               return -ENODEV;
+       } else {
+               debug("pcie phy pll is locked.\n");
+               return 0;
+       }
+}
+
+static int imx8_pcie_deassert_core_reset(struct imx_pcie_priv *priv)
+{
+       int ret, i;
+       u32 val, tmp;
+
+#if CONFIG_IS_ENABLED(CLK)
+       ret = clk_enable(&priv->pcie);
+       if (ret) {
+               printf("unable to enable pcie clock\n");
+               return ret;
+       }
+
+       ret = clk_enable(&priv->pcie_phy);
+       if (ret) {
+               printf("unable to enable pcie_phy clock\n");
+               goto err_pcie;
+       }
+#endif
+
+       if (priv->variant == IMX8QM
+               || priv->variant == IMX8QXP) {
+
+#if CONFIG_IS_ENABLED(CLK)
+               ret = clk_enable(&priv->pcie_inbound_axi);
+               if (ret) {
+                       printf("unable to enable pcie_axi clock\n");
+                       goto err_pcie_phy;
+               }
+               ret = clk_enable(&priv->pcie_per);
+               if (ret) {
+                       printf("unable to enable pcie_per clock\n");
+                       clk_disable(&priv->pcie_inbound_axi);
+                       goto err_pcie_phy;
+               }
+#endif
+               /* allow the clocks to stabilize */
+               udelay(200);
+
+               /* bit19 PM_REQ_CORE_RST of pciex#_stts0 should be cleared. */
+               for (i = 0; i < 100; i++) {
+                       val = IMX8QM_CSR_PCIEA_OFFSET
+                               + priv->ctrl_id * SZ_64K;
+                       imx_pcie_gpr_read(priv,
+                                       val + IMX8QM_CSR_PCIE_STTS0_OFFSET,
+                                       &tmp);
+                       if ((tmp & IMX8QM_CTRL_STTS0_PM_REQ_CORE_RST) == 0)
+                               break;
+                       udelay(10);
+               }
+
+               if ((tmp & IMX8QM_CTRL_STTS0_PM_REQ_CORE_RST) != 0)
+                       printf("ERROR PM_REQ_CORE_RST is still set.\n");
+
+               /* wait for phy pll lock firstly. */
+               if (imx8_pcie_wait_for_phy_pll_lock(priv)) {
+                       ret = -ENODEV;
+                       goto err_ref_clk;;
+               }
+
+               if (dm_gpio_is_valid(&priv->reset_gpio)) {
+                       dm_gpio_set_value(&priv->reset_gpio, 1);
+                       mdelay(20);
+                       dm_gpio_set_value(&priv->reset_gpio, 0);
+                       mdelay(20);
+               }
+
+               return 0;
+       }
+
+err_ref_clk:
+#if CONFIG_IS_ENABLED(CLK)
+       clk_disable(&priv->pcie_per);
+       clk_disable(&priv->pcie_inbound_axi);
+err_pcie_phy:
+       clk_disable(&priv->pcie_phy);
+err_pcie:
+       clk_disable(&priv->pcie);
+#endif
+
+       return ret;
+}
+
+#ifdef CONFIG_MX6
 /*
  * Initial bus setup
  */
 static int imx6_pcie_assert_core_reset(struct imx_pcie_priv *priv,
                                       bool prepare_for_boot)
 {
-       struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR;
-
-       if (is_mx6dqp())
-               setbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_PCIE_SW_RST);
+       if (priv->variant == IMX6QP)
+               imx_pcie_gpr_update_bits(priv, 4, IOMUXC_GPR1_PCIE_SW_RST, IOMUXC_GPR1_PCIE_SW_RST);
 
 #if defined(CONFIG_MX6SX)
-       struct gpc *gpc_regs = (struct gpc *)GPC_BASE_ADDR;
-
-       /* SSP_EN is not used on MX6SX anymore */
-       setbits_le32(&iomuxc_regs->gpr[12], IOMUXC_GPR12_TEST_POWERDOWN);
-       /* Force PCIe PHY reset */
-       setbits_le32(&iomuxc_regs->gpr[5], IOMUXC_GPR5_PCIE_BTNRST);
-       /* Power up PCIe PHY */
-       setbits_le32(&gpc_regs->cntr, PCIE_PHY_PUP_REQ);
-       pcie_power_up();
-#else
+       if (priv->variant == IMX6SX) {
+               struct gpc *gpc_regs = (struct gpc *)GPC_BASE_ADDR;
+
+               /* SSP_EN is not used on MX6SX anymore */
+               imx_pcie_gpr_update_bits(priv, 48, IOMUXC_GPR12_TEST_POWERDOWN, IOMUXC_GPR12_TEST_POWERDOWN);
+               /* Force PCIe PHY reset */
+               imx_pcie_gpr_update_bits(priv, 20, IOMUXC_GPR5_PCIE_BTNRST, IOMUXC_GPR5_PCIE_BTNRST);
+               /* Power up PCIe PHY */
+               setbits_le32(&gpc_regs->cntr, PCIE_PHY_PUP_REQ);
+               pcie_power_up();
+
+               return 0;
+       }
+#endif
        /*
         * If the bootloader already enabled the link we need some special
         * handling to get the core back into a state where it is safe to
@@ -513,11 +1065,11 @@ static int imx6_pcie_assert_core_reset(struct imx_pcie_priv *priv,
         * If both LTSSM_ENABLE and REF_SSP_ENABLE are active we have a strong
         * indication that the bootloader activated the link.
         */
-       if (is_mx6dq() && prepare_for_boot) {
+       if (priv->variant == IMX6Q && prepare_for_boot) {
                u32 val, gpr1, gpr12;
 
-               gpr1 = readl(&iomuxc_regs->gpr[1]);
-               gpr12 = readl(&iomuxc_regs->gpr[12]);
+               imx_pcie_gpr_read(priv, 4, &gpr1);
+               imx_pcie_gpr_read(priv, 48, &gpr12);
                if ((gpr1 & IOMUXC_GPR1_PCIE_REF_CLK_EN) &&
                    (gpr12 & IOMUXC_GPR12_PCIE_CTL_2)) {
                        val = readl(priv->dbi_base + PCIE_PL_PFLR);
@@ -528,44 +1080,44 @@ static int imx6_pcie_assert_core_reset(struct imx_pcie_priv *priv,
                        writel(val, priv->dbi_base + PCIE_PL_PFLR);
                        imx_pcie_fix_dabt_handler(false);
 
-                       gpr12 &= ~IOMUXC_GPR12_PCIE_CTL_2;
-                       writel(val, &iomuxc_regs->gpr[12]);
+                       imx_pcie_gpr_update_bits(priv, 48, IOMUXC_GPR12_PCIE_CTL_2, 0);
                }
        }
-       setbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_TEST_POWERDOWN);
-       clrbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_REF_SSP_EN);
-#endif
+
+       if (priv->variant == IMX6QP || priv->variant == IMX6Q) {
+               imx_pcie_gpr_update_bits(priv, 4, IOMUXC_GPR1_TEST_POWERDOWN,
+                       IOMUXC_GPR1_TEST_POWERDOWN);
+               imx_pcie_gpr_update_bits(priv, 4, IOMUXC_GPR1_REF_SSP_EN, 0);
+       }
 
        return 0;
 }
 
-static int imx6_pcie_init_phy(void)
+static int imx6_pcie_init_phy(struct imx_pcie_priv *priv)
 {
-       struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR;
-
 #ifndef DEBUG
-       clrbits_le32(&iomuxc_regs->gpr[12], IOMUXC_GPR12_APPS_LTSSM_ENABLE);
+       imx_pcie_gpr_update_bits(priv, 48, IOMUXC_GPR12_APPS_LTSSM_ENABLE, 0);
 #endif
 
-       clrsetbits_le32(&iomuxc_regs->gpr[12],
+       imx_pcie_gpr_update_bits(priv, 48,
                        IOMUXC_GPR12_DEVICE_TYPE_MASK,
                        IOMUXC_GPR12_DEVICE_TYPE_RC);
-       clrsetbits_le32(&iomuxc_regs->gpr[12],
+       imx_pcie_gpr_update_bits(priv, 48,
                        IOMUXC_GPR12_LOS_LEVEL_MASK,
                        IOMUXC_GPR12_LOS_LEVEL_9);
 
-#ifdef CONFIG_MX6SX
-       clrsetbits_le32(&iomuxc_regs->gpr[12],
-                       IOMUXC_GPR12_RX_EQ_MASK,
-                       IOMUXC_GPR12_RX_EQ_2);
-#endif
+       if (priv->variant == IMX6SX) {
+               imx_pcie_gpr_update_bits(priv, 48,
+                               IOMUXC_GPR12_RX_EQ_MASK,
+                               IOMUXC_GPR12_RX_EQ_2);
+       }
 
-       writel((0x0 << IOMUXC_GPR8_PCS_TX_DEEMPH_GEN1_OFFSET) |
+       imx_pcie_gpr_update_bits(priv, 32, 0xffffffff,
+               (0x0 << IOMUXC_GPR8_PCS_TX_DEEMPH_GEN1_OFFSET) |
               (0x0 << IOMUXC_GPR8_PCS_TX_DEEMPH_GEN2_3P5DB_OFFSET) |
               (20 << IOMUXC_GPR8_PCS_TX_DEEMPH_GEN2_6DB_OFFSET) |
               (127 << IOMUXC_GPR8_PCS_TX_SWING_FULL_OFFSET) |
-              (127 << IOMUXC_GPR8_PCS_TX_SWING_LOW_OFFSET),
-              &iomuxc_regs->gpr[8]);
+              (127 << IOMUXC_GPR8_PCS_TX_SWING_LOW_OFFSET));
 
        return 0;
 }
@@ -623,19 +1175,20 @@ __weak int imx6_pcie_toggle_reset(void)
 #else
        puts("WARNING: Make sure the PCIe #PERST line is connected!\n");
 #endif
+
        return 0;
 }
 
-static int imx6_pcie_deassert_core_reset(void)
+static int imx6_pcie_deassert_core_reset(struct imx_pcie_priv *priv)
 {
-       struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR;
-
+#if !CONFIG_IS_ENABLED(DM_PCI)
        imx6_pcie_toggle_power();
+#endif
 
        enable_pcie_clock();
 
-       if (is_mx6dqp())
-               clrbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_PCIE_SW_RST);
+       if (priv->variant == IMX6QP)
+               imx_pcie_gpr_update_bits(priv, 4, IOMUXC_GPR1_PCIE_SW_RST, 0);
 
        /*
         * Wait for the clock to settle a bit, when the clock are sourced
@@ -643,32 +1196,135 @@ static int imx6_pcie_deassert_core_reset(void)
         */
        mdelay(50);
 
-#if defined(CONFIG_MX6SX)
-       /* SSP_EN is not used on MX6SX anymore */
-       clrbits_le32(&iomuxc_regs->gpr[12], IOMUXC_GPR12_TEST_POWERDOWN);
-       /* Clear PCIe PHY reset bit */
-       clrbits_le32(&iomuxc_regs->gpr[5], IOMUXC_GPR5_PCIE_BTNRST);
-#else
-       /* Enable PCIe */
-       clrbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_TEST_POWERDOWN);
-       setbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_REF_SSP_EN);
-#endif
+       if (priv->variant == IMX6SX) {
+               /* SSP_EN is not used on MX6SX anymore */
+               imx_pcie_gpr_update_bits(priv, 48, IOMUXC_GPR12_TEST_POWERDOWN, 0);
+               /* Clear PCIe PHY reset bit */
+               imx_pcie_gpr_update_bits(priv, 20, IOMUXC_GPR5_PCIE_BTNRST, 0);
+       } else {
+               /* Enable PCIe */
+               imx_pcie_gpr_update_bits(priv, 4, IOMUXC_GPR1_TEST_POWERDOWN, 0);
+               imx_pcie_gpr_update_bits(priv, 4, IOMUXC_GPR1_REF_SSP_EN, IOMUXC_GPR1_REF_SSP_EN);
+       }
 
+#if !CONFIG_IS_ENABLED(DM_PCI)
        imx6_pcie_toggle_reset();
+#else
+       if (dm_gpio_is_valid(&priv->reset_gpio)) {
+               dm_gpio_set_value(&priv->reset_gpio, 1);
+               mdelay(20);
+               dm_gpio_set_value(&priv->reset_gpio, 0);
+               mdelay(20);
+       }
+#endif
 
        return 0;
 }
+#endif
+
+static int imx_pcie_assert_core_reset(struct imx_pcie_priv *priv,
+                                      bool prepare_for_boot)
+{
+       switch (priv->variant) {
+#ifdef CONFIG_MX6
+       case IMX6Q:
+       case IMX6QP:
+       case IMX6SX:
+               return imx6_pcie_assert_core_reset(priv, prepare_for_boot);
+#endif
+       case IMX8QM:
+       case IMX8QXP:
+               return imx8_pcie_assert_core_reset(priv, prepare_for_boot);
+       default:
+               return -EPERM;
+       }
+}
+
+static int imx_pcie_init_phy(struct imx_pcie_priv *priv)
+{
+       switch (priv->variant) {
+#ifdef CONFIG_MX6
+       case IMX6Q:
+       case IMX6QP:
+       case IMX6SX:
+               return imx6_pcie_init_phy(priv);
+#endif
+       case IMX8QM:
+       case IMX8QXP:
+               return imx8_pcie_init_phy(priv);
+       default:
+               return -EPERM;
+       }
+}
+
+static int imx_pcie_deassert_core_reset(struct imx_pcie_priv *priv)
+{
+       switch (priv->variant) {
+#ifdef CONFIG_MX6
+       case IMX6Q:
+       case IMX6QP:
+       case IMX6SX:
+               return imx6_pcie_deassert_core_reset(priv);
+#endif
+       case IMX8QM:
+       case IMX8QXP:
+               return imx8_pcie_deassert_core_reset(priv);
+       default:
+               return -EPERM;
+       }
+}
+
+static void imx_pcie_ltssm_enable(struct imx_pcie_priv *priv, bool enable)
+{
+       u32 val;
+
+       switch (priv->variant) {
+#ifdef CONFIG_MX6
+       case IMX6Q:
+       case IMX6SX:
+       case IMX6QP:
+               if (enable)
+                       imx_pcie_gpr_update_bits(priv, 48, IOMUXC_GPR12_APPS_LTSSM_ENABLE,
+                               IOMUXC_GPR12_APPS_LTSSM_ENABLE); /* LTSSM enable, starting link. */
+               else
+                       imx_pcie_gpr_update_bits(priv, 48, IOMUXC_GPR12_APPS_LTSSM_ENABLE, 0);
+
+               break;
+#endif
+       case IMX8QXP:
+       case IMX8QM:
+               /* Bit4 of the CTRL2 */
+               val = IMX8QM_CSR_PCIEA_OFFSET
+                       + priv->ctrl_id * SZ_64K;
+               if (enable) {
+                       imx_pcie_gpr_update_bits(priv,
+                               val + IMX8QM_CSR_PCIE_CTRL2_OFFSET,
+                               IMX8QM_CTRL_LTSSM_ENABLE,
+                               IMX8QM_CTRL_LTSSM_ENABLE);
+               } else {
+                       imx_pcie_gpr_update_bits(priv,
+                               val + IMX8QM_CSR_PCIE_CTRL2_OFFSET,
+                               IMX8QM_CTRL_LTSSM_ENABLE,
+                               0);
+               }
+               break;
+       default:
+               break;
+       }
+
+}
+
 
 static int imx_pcie_link_up(struct imx_pcie_priv *priv)
 {
-       struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR;
        uint32_t tmp;
        int count = 0;
 
-       imx6_pcie_assert_core_reset(priv, false);
-       imx6_pcie_init_phy();
-       imx6_pcie_deassert_core_reset();
+       imx_pcie_assert_core_reset(priv, false);
+       imx_pcie_init_phy(priv);
+       imx_pcie_deassert_core_reset(priv);
 
+       imx_pcie_setup_ctrl(priv);
        imx_pcie_regions_setup(priv);
 
        /*
@@ -694,7 +1350,7 @@ static int imx_pcie_link_up(struct imx_pcie_priv *priv)
        writel(tmp, priv->dbi_base + 0x7c);
 
        /* LTSSM enable, starting link. */
-       setbits_le32(&iomuxc_regs->gpr[12], IOMUXC_GPR12_APPS_LTSSM_ENABLE);
+       imx_pcie_ltssm_enable(priv, true);
 
        while (!imx6_pcie_link_up(priv)) {
                udelay(10);
@@ -703,17 +1359,26 @@ static int imx_pcie_link_up(struct imx_pcie_priv *priv)
                        print_regs(1);
                        /* link down, try reset ep, and re-try link here */
                        DBGF("pcie link is down, reset ep, then retry!\n");
+
+#if CONFIG_IS_ENABLED(DM_PCI)
+                       if (dm_gpio_is_valid(&priv->reset_gpio)) {
+                               dm_gpio_set_value(&priv->reset_gpio, 1);
+                               mdelay(20);
+                               dm_gpio_set_value(&priv->reset_gpio, 0);
+                               mdelay(20);
+                       }
+#elif defined(CONFIG_MX6)
                        imx6_pcie_toggle_reset();
+#endif
                        continue;
                }
 #ifdef DEBUG
                else if (count >= 2000) {
                        print_regs(1);
                        /* link is down, stop here */
-                       setenv("bootcmd", "sleep 2;");
+                       env_set("bootcmd", "sleep 2;");
                        DBGF("pcie link is down, stop here!\n");
-                       clrbits_le32(&iomuxc_regs->gpr[12],
-                                    IOMUXC_GPR12_APPS_LTSSM_ENABLE);
+                       imx_pcie_ltssm_enable(priv, false);
                        return -EINVAL;
                }
 #endif
@@ -724,8 +1389,7 @@ static int imx_pcie_link_up(struct imx_pcie_priv *priv)
                        debug("DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n",
                              readl(priv->dbi_base + PCIE_PHY_DEBUG_R0),
                              readl(priv->dbi_base + PCIE_PHY_DEBUG_R1));
-                       clrbits_le32(&iomuxc_regs->gpr[12],
-                                    IOMUXC_GPR12_APPS_LTSSM_ENABLE);
+                       imx_pcie_ltssm_enable(priv, false);
                        return -EINVAL;
                }
        }
@@ -737,10 +1401,14 @@ static int imx_pcie_link_up(struct imx_pcie_priv *priv)
 static struct imx_pcie_priv imx_pcie_priv = {
        .dbi_base       = (void __iomem *)MX6_DBI_ADDR,
        .cfg_base       = (void __iomem *)MX6_ROOT_ADDR,
+       .cfg1_base      = (void __iomem *)(MX6_ROOT_ADDR + MX6_ROOT_SIZE / 2),
+       .cfg_size               = MX6_ROOT_SIZE,
+       .lanes          = 1,
 };
 
 static struct imx_pcie_priv *priv = &imx_pcie_priv;
 
+
 static int imx_pcie_read_config(struct pci_controller *hose, pci_dev_t d,
                                int where, u32 *val)
 {
@@ -770,11 +1438,18 @@ void imx_pcie_init(void)
 
        memset(&pcc, 0, sizeof(pcc));
 
+       if (is_mx6sx())
+               priv->variant = IMX6SX;
+       else if (is_mx6dqp())
+               priv->variant = IMX6QP;
+       else
+               priv->variant = IMX6Q;
+
        hose->priv_data = priv;
 
        /* PCI I/O space */
        pci_set_region(&hose->regions[0],
-                      MX6_IO_ADDR, MX6_IO_ADDR,
+                      0, MX6_IO_ADDR,
                       MX6_IO_SIZE, PCI_REGION_IO);
 
        /* PCI memory space */
@@ -787,6 +1462,9 @@ void imx_pcie_init(void)
                       MMDC0_ARB_BASE_ADDR, MMDC0_ARB_BASE_ADDR,
                       0xefffffff, PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
 
+       priv->io = &hose->regions[0];
+       priv->mem = &hose->regions[1];
+
        hose->region_count = 3;
 
        pci_set_ops(hose,
@@ -824,6 +1502,12 @@ void pci_init_board(void)
 {
        imx_pcie_init();
 }
+
+int pci_skip_dev(struct pci_controller *hose, pci_dev_t dev)
+{
+       return 0;
+}
+
 #else
 static int imx_pcie_dm_read_config(const struct udevice *dev, pci_dev_t bdf,
                                   uint offset, ulong *value,
@@ -859,8 +1543,126 @@ static int imx_pcie_dm_write_config(struct udevice *dev, pci_dev_t bdf,
 
 static int imx_pcie_dm_probe(struct udevice *dev)
 {
+       int ret = 0;
        struct imx_pcie_priv *priv = dev_get_priv(dev);
 
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+       ret = device_get_supply_regulator(dev, "epdev_on", &priv->epdev_on);
+       if (ret) {
+               priv->epdev_on = NULL;
+               dev_dbg(dev, "no epdev_on\n");
+       } else {
+               ret = regulator_set_enable(priv->epdev_on, true);
+               if (ret) {
+                       dev_err(dev, "fail to enable epdev_on\n");
+                       return ret;
+               }
+       }
+
+       mdelay(100);
+#endif
+
+       /* Enable the osc clk */
+       ret = gpio_request_by_name(dev, "clkreq-gpio", 0, &priv->clkreq_gpio,
+                                  (GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE));
+       if (ret) {
+               dev_info(dev, "%d unable to get clkreq.\n", ret);
+       }
+
+       /* enable */
+       ret = gpio_request_by_name(dev, "disable-gpio", 0, &priv->dis_gpio,
+                                  (GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE));
+       if (ret) {
+               dev_info(dev, "%d unable to get disable-gpio.\n", ret);
+       }
+
+       /* Set to power on */
+       ret = gpio_request_by_name(dev, "power-on-gpio", 0, &priv->power_on_gpio,
+                                  (GPIOD_IS_OUT |GPIOD_IS_OUT_ACTIVE));
+       if (ret) {
+               dev_info(dev, "%d unable to get power-on-gpio.\n", ret);
+       }
+
+       /* Set to reset status */
+       ret = gpio_request_by_name(dev, "reset-gpio", 0, &priv->reset_gpio,
+                                  (GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE));
+       if (ret) {
+               dev_info(dev, "%d unable to get power-on-gpio.\n", ret);
+       }
+
+#if CONFIG_IS_ENABLED(CLK)
+       ret = clk_get_by_name(dev, "pcie_phy", &priv->pcie_phy);
+       if (ret) {
+               printf("Failed to get pcie_phy clk\n");
+               return ret;
+       }
+
+       ret = clk_get_by_name(dev, "pcie_bus", &priv->pcie_bus);
+       if (ret) {
+               printf("Failed to get pcie_bus clk\n");
+               return ret;
+       }
+
+       ret = clk_get_by_name(dev, "pcie", &priv->pcie);
+       if (ret) {
+               printf("Failed to get pcie clk\n");
+               return ret;
+       }
+#endif
+
+       if (priv->variant == IMX8QM || priv->variant == IMX8QXP) {
+#if CONFIG_IS_ENABLED(CLK)
+               ret = clk_get_by_name(dev, "pcie_per", &priv->pcie_per);
+               if (ret) {
+                       printf("Failed to get pcie_per clk\n");
+                       return ret;
+               }
+
+               ret = clk_get_by_name(dev, "pcie_inbound_axi", &priv->pcie_inbound_axi);
+               if (ret) {
+                       printf("Failed to get pcie_inbound_axi clk\n");
+                       return ret;
+               }
+#endif
+               priv->iomuxc_gpr =
+                        syscon_regmap_lookup_by_phandle(dev, "hsio");
+               if (IS_ERR(priv->iomuxc_gpr)) {
+                       dev_err(dev, "unable to find gpr registers\n");
+                       return PTR_ERR(priv->iomuxc_gpr);
+               }
+       } else {
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+               if (priv->variant == IMX6QP) {
+                       ret = device_get_supply_regulator(dev, "pcie-bus", &priv->pcie_bus_regulator);
+                       if (ret) {
+                               dev_dbg(dev, "no pcie_bus_regulator\n");
+                               priv->pcie_bus_regulator = NULL;
+                       }
+               } else if (priv->variant == IMX6SX) {
+                       ret = device_get_supply_regulator(dev, "pcie-phy", &priv->pcie_phy_regulator);
+                       if (ret) {
+                               dev_dbg(dev, "no pcie_phy_regulator\n");
+                               priv->pcie_phy_regulator = NULL;
+                       }
+               }
+#endif
+
+               priv->iomuxc_gpr =
+                        syscon_regmap_lookup_by_phandle(dev, "gpr");
+               if (IS_ERR(priv->iomuxc_gpr)) {
+                       dev_err(dev, "unable to find gpr registers\n");
+                       return PTR_ERR(priv->iomuxc_gpr);
+               }
+       }
+
+       pci_get_regions(dev, &priv->io, &priv->mem, &priv->pref);
+
+       if (priv->cpu_base)
+               priv->cpu_addr_offset = priv->cpu_base
+                               - priv->mem->phys_start;
+       else
+               priv->cpu_addr_offset = 0;
+
        return imx_pcie_link_up(priv);
 }
 
@@ -868,7 +1670,7 @@ static int imx_pcie_dm_remove(struct udevice *dev)
 {
        struct imx_pcie_priv *priv = dev_get_priv(dev);
 
-       imx6_pcie_assert_core_reset(priv, true);
+       imx_pcie_assert_core_reset(priv, true);
 
        return 0;
 }
@@ -876,12 +1678,45 @@ static int imx_pcie_dm_remove(struct udevice *dev)
 static int imx_pcie_of_to_plat(struct udevice *dev)
 {
        struct imx_pcie_priv *priv = dev_get_priv(dev);
+       int ret;
+       struct resource cfg_res;
 
        priv->dbi_base = (void __iomem *)devfdt_get_addr_index(dev, 0);
-       priv->cfg_base = (void __iomem *)devfdt_get_addr_index(dev, 1);
-       if (!priv->dbi_base || !priv->cfg_base)
+       if (!priv->dbi_base)
                return -EINVAL;
 
+       ret = dev_read_resource_byname(dev,  "config", &cfg_res);
+       if (ret) {
+               printf("can't get config resource(ret = %d)\n", ret);
+               return -ENOMEM;
+       }
+
+       priv->cfg_base = map_physmem(cfg_res.start,
+                                resource_size(&cfg_res),
+                                MAP_NOCACHE);
+       priv->cfg1_base = priv->cfg_base + resource_size(&cfg_res) / 2;
+       priv->cfg_size = resource_size(&cfg_res);
+
+       priv->variant = (enum imx_pcie_variants)dev_get_driver_data(dev);
+
+       if (dev_read_u32u(dev, "hsio-cfg", &priv->hsio_cfg))
+               priv->hsio_cfg = 0;
+
+       if (dev_read_u32u(dev, "ctrl-id", &priv->ctrl_id))
+               priv->ctrl_id = 0;
+
+       if (dev_read_u32u(dev, "ext_osc", &priv->ext_osc))
+               priv->ext_osc = 0;
+
+       if (dev_read_u32u(dev, "cpu-base-addr", &priv->cpu_base))
+               priv->cpu_base = 0;
+
+       if (dev_read_u32u(dev, "num-lanes", &priv->lanes))
+               priv->lanes = 1;
+
+       debug("hsio-cfg %u, ctrl-id %u, ext_osc %u, cpu-base 0x%x\n",
+               priv->hsio_cfg, priv->ctrl_id, priv->ext_osc, priv->cpu_base);
+
        return 0;
 }
 
@@ -891,8 +1726,11 @@ static const struct dm_pci_ops imx_pcie_ops = {
 };
 
 static const struct udevice_id imx_pcie_ids[] = {
-       { .compatible = "fsl,imx6q-pcie" },
-       { .compatible = "fsl,imx6sx-pcie" },
+       { .compatible = "fsl,imx6q-pcie",  .data = (ulong)IMX6Q,  },
+       { .compatible = "fsl,imx6sx-pcie", .data = (ulong)IMX6SX, },
+       { .compatible = "fsl,imx6qp-pcie", .data = (ulong)IMX6QP, },
+       { .compatible = "fsl,imx8qm-pcie", .data = (ulong)IMX8QM, },
+       { .compatible = "fsl,imx8qxp-pcie", .data = (ulong)IMX8QXP, },
        { }
 };