MLK-14938-17 pcie: Add support for i.MX8QM/QXP PCIe
authorYe Li <ye.li@nxp.com>
Mon, 27 Mar 2017 07:46:55 +0000 (15:46 +0800)
committerYe Li <ye.li@nxp.com>
Fri, 24 May 2019 08:56:33 +0000 (01:56 -0700)
- one lane pcie gen2 link is okay, the cfg space
  of the rc/ep can be accessed.
  rc cfg base 0x5f00_0000. ep cfg base 0x6000_0000
- limit to gen2 speed
- mask the wait of eq3 finish, because it is used
  for gen3.
- use pcie_ctrla_init_rc() to do the initialization
  of the pciea controller
- setup the common pcie codes in pcie_imx8x.c, separate
  the different soc speicifed initialization codes into
  their own pcie/board codes, move the macro definitions
  into the new header file imx8_hsio.h.
- i.MX8QXP only have PCIe Control B. Enable PORT B at default.
  i.MX8QM needs to set CONFIG_IMX_PCIEB to enable PORT B.
- Disable the LTSSM when link is down.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
Signed-off-by: Shenwei Wang <shenwei.wang@nxp.com>
Signed-off-by: Ye Li <ye.li@nxp.com>
(cherry picked from commit 03141c2b955ce6034f06e701126aea1493dc2b4b)
(cherry picked from commit 99c90ff2de4849aafa0043932353e2c199d22e5f)

drivers/pci/Makefile
drivers/pci/pcie_imx8qm.c [new file with mode: 0644]
drivers/pci/pcie_imx8x.c [new file with mode: 0644]
include/imx8_hsio.h [new file with mode: 0644]
scripts/config_whitelist.txt

index 4923641..73e9df5 100644 (file)
@@ -21,6 +21,7 @@ obj-$(CONFIG_PCI_INDIRECT_BRIDGE) += pci_indirect.o
 obj-$(CONFIG_PCI_GT64120) += pci_gt64120.o
 obj-$(CONFIG_PCI_MSC01) += pci_msc01.o
 obj-$(CONFIG_PCIE_IMX) += pcie_imx.o
+obj-$(CONFIG_PCIE_IMX8X) += pcie_imx8x.o pcie_imx8qm.o
 obj-$(CONFIG_FTPCI100) += pci_ftpci100.o
 obj-$(CONFIG_PCI_MVEBU) += pci_mvebu.o
 obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
diff --git a/drivers/pci/pcie_imx8qm.c b/drivers/pci/pcie_imx8qm.c
new file mode 100644 (file)
index 0000000..37223d8
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ *
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/arch/sci/sci.h>
+#include <common.h>
+#include <linux/sizes.h>
+#include <imx8_hsio.h>
+
+void pcie_ctrlx2_rst(void)
+{
+       /* gpio config */
+       /* dir  wakeup input clkreq and pereset output */
+       writel(0x2d, HSIO_GPIO_BASE_ADDR + 0x4);
+       writel(0x24, HSIO_GPIO_BASE_ADDR + 0x0); /* do pereset 1 */
+
+       clrbits_le32(HW_PCIEX2_CTRL2_ADDR, HW_PCIEX2_CTRL2_BUTTON_RST_N);
+       clrbits_le32(HW_PCIEX2_CTRL2_ADDR, HW_PCIEX2_CTRL2_PERST_N);
+       clrbits_le32(HW_PCIEX2_CTRL2_ADDR, HW_PCIEX2_CTRL2_POWER_UP_RST_N);
+       udelay(10);
+       setbits_le32(HW_PCIEX2_CTRL2_ADDR, HW_PCIEX2_CTRL2_BUTTON_RST_N);
+       setbits_le32(HW_PCIEX2_CTRL2_ADDR, HW_PCIEX2_CTRL2_PERST_N);
+       setbits_le32(HW_PCIEX2_CTRL2_ADDR, HW_PCIEX2_CTRL2_POWER_UP_RST_N);
+}
+
+void pcie_ctrlx1_rst(void)
+{
+       /* gpio config */
+       /* dir  wakeup input clkreq and pereset output */
+       writel(0x2d, HSIO_GPIO_BASE_ADDR + 0x4);
+       writel(0x24, HSIO_GPIO_BASE_ADDR + 0x0); /* do pereset 1 */
+
+       clrbits_le32(HW_PCIEX1_CTRL2_ADDR, HW_PCIEX1_CTRL2_BUTTON_RST_N);
+       setbits_le32(HW_PCIEX1_CTRL2_ADDR, HW_PCIEX1_CTRL2_BUTTON_RST_N);
+       clrbits_le32(HW_PCIEX1_CTRL2_ADDR, HW_PCIEX1_CTRL2_PERST_N);
+       setbits_le32(HW_PCIEX1_CTRL2_ADDR, HW_PCIEX1_CTRL2_PERST_N);
+       clrbits_le32(HW_PCIEX1_CTRL2_ADDR, HW_PCIEX1_CTRL2_POWER_UP_RST_N);
+       setbits_le32(HW_PCIEX1_CTRL2_ADDR, HW_PCIEX1_CTRL2_POWER_UP_RST_N);
+}
+
+int pcie_ctrla_init_rc(int lane)
+{
+       u32 val, i = 0;
+
+       setbits_le32(HW_PHYX2_CTRL0_ADDR, HW_PHYX2_CTRL0_APB_RSTN_0
+                       | HW_PHYX2_CTRL0_APB_RSTN_1); /* APB_RSTN_0/1 */
+
+       clrbits_le32(HW_PCIEX2_CTRL0_ADDR, HW_PCIEX2_CTRL0_DEVICE_TYPE_MASK);
+       setbits_le32(HW_PCIEX2_CTRL0_ADDR, HW_PCIEX2_CTRL0_DEVICE_TYPE_RC);
+
+       if (lane == 1) {
+               /*
+                * bit 0 rx ena. bit 11 fast_init.
+                * bit12 PHY_X1_EPCS_SEL 1.
+                * bit13 phy_ab_select 1.
+                */
+               setbits_le32(HW_MISC_CTRL0_ADDR, HW_MISC_CTRL0_IOB_RXENA
+                               | HW_MISC_CTRL0_PHY_X1_EPCS_SEL
+                               | HW_MISC_CTRL0_PCIE_AB_SELECT);
+               /* pipe_ln2lk = 1001 */
+               clrbits_le32(HW_PHYX2_CTRL0_ADDR,
+                               HW_PHYX2_CTRL0_PIPE_LN2LK_MASK);
+               setbits_le32(HW_PHYX2_CTRL0_ADDR, HW_PHYX2_CTRL0_PIPE_LN2LK_3
+                               | HW_PHYX2_CTRL0_PIPE_LN2LK_0);
+               for (i = 0; i < 100; i++) {
+                       val = readl(HW_PHYX2_STTS0_ADDR);
+                       val &= HW_PHYX2_STTS0_LANE0_TX_PLL_LOCK;
+                       if (val == HW_PHYX2_STTS0_LANE0_TX_PLL_LOCK)
+                               break;
+                       udelay(10);
+               }
+
+               if (val != HW_PHYX2_STTS0_LANE0_TX_PLL_LOCK) {
+                       printf("TX PLL is not locked.\n");
+                       return -ENODEV;
+               }
+               setbits_le32(GPR_LPCG_PHYX2APB_0_APB, BIT(1));
+               /* Set the link_capable to be lane1 */
+               clrbits_le32(PORT0_LINK_CTRL, PORT_LINK_CTRL_LNK_EN_MASK);
+               setbits_le32(PORT0_LINK_CTRL, PORT_LINK_CTRL_LNK_LANE1);
+               clrbits_le32(PORT0_GEN2_CTRL, PORT_GEN2_CTRL_NUM_LANES_MASK);
+               setbits_le32(PORT0_GEN2_CTRL, PORT_GEN2_CTRL_NUM_LANES_1);
+       } else if (lane == 2) {
+               /*
+                * bit 0 rx ena. bit 11 fast_init.
+                * bit12 PHY_X1_EPCS_SEL 1.
+                */
+               setbits_le32(HW_MISC_CTRL0_ADDR, HW_MISC_CTRL0_IOB_RXENA
+                               | HW_MISC_CTRL0_PHY_X1_EPCS_SEL);
+               /* pipe_ln2lk = 0011 */
+               clrbits_le32(HW_PHYX2_CTRL0_ADDR,
+                               HW_PHYX2_CTRL0_PIPE_LN2LK_MASK);
+               setbits_le32(HW_PHYX2_CTRL0_ADDR, HW_PHYX2_CTRL0_PIPE_LN2LK_1
+                               | HW_PHYX2_CTRL0_PIPE_LN2LK_0);
+               for (i = 0; i < 100; i++) {
+                       val = readl(HW_PHYX2_STTS0_ADDR);
+                       val &= (HW_PHYX2_STTS0_LANE0_TX_PLL_LOCK | HW_PHYX2_STTS0_LANE1_TX_PLL_LOCK);
+                       if (val == (HW_PHYX2_STTS0_LANE0_TX_PLL_LOCK | HW_PHYX2_STTS0_LANE1_TX_PLL_LOCK))
+                               break;
+                       udelay(10);
+               }
+
+               if (val != (HW_PHYX2_STTS0_LANE0_TX_PLL_LOCK | HW_PHYX2_STTS0_LANE1_TX_PLL_LOCK)) {
+                       printf("TX PLL is not locked.\n");
+                       return -ENODEV;
+               }
+               setbits_le32(GPR_LPCG_PHYX2APB_0_APB, BIT(1) + BIT(5));
+               /* Set the link_capable to be lane2 */
+               clrbits_le32(PORT0_LINK_CTRL, PORT_LINK_CTRL_LNK_EN_MASK);
+               setbits_le32(PORT0_LINK_CTRL, PORT_LINK_CTRL_LNK_LANE2);
+               clrbits_le32(PORT0_GEN2_CTRL, PORT_GEN2_CTRL_NUM_LANES_MASK);
+               setbits_le32(PORT0_GEN2_CTRL, PORT_GEN2_CTRL_NUM_LANES_2);
+       } else {
+               printf("%s %d lane %d is invalid.\n", __func__, __LINE__, lane);
+       }
+
+       /* bit19 PM_REQ_CORE_RST of pciex2_stts0 should be cleared. */
+       for (i = 0; i < 100; i++) {
+               val = readl(HW_PCIEX2_STTS0_ADDR);
+               if ((val & HW_PCIEX2_STTS0_PM_REQ_CORE_RST) == 0)
+                       break;
+               udelay(10);
+       }
+
+       if ((val & HW_PCIEX2_STTS0_PM_REQ_CORE_RST) != 0)
+               printf("ERROR PM_REQ_CORE_RST is set.\n");
+
+       /* DBI_RO_WR_EN =1 to write PF0_SPCIE_CAP_OFF_0CH_REG */
+       writel(0x1, PORT0_MISC_CONTROL_1);
+       writel(0x35353535, PF0_SPCIE_CAP_OFF_0CH_REG); /* set preset not golden */
+       setbits_le32(PORT0_LINK_CTRL, PORT_LINK_CTRL_LNK_FAST_LNK);
+       setbits_le32(HW_PCIEX2_CTRL2_ADDR, HW_PCIEX2_CTRL2_APP_LTSSM_ENABLE);
+
+       do {
+               udelay(100);
+               val = readl(PORT0_LINK_DEBUG1);
+       } while (((val & PORT_LINK_DEBUG1_LINK_UP) == 0) && (i++ < 100));
+
+       if ((val & PORT_LINK_DEBUG1_LINK_UP) == PORT_LINK_DEBUG1_LINK_UP)
+               printf("[%s] LNK UP %x\r\n", __func__, val);
+       else {
+               printf("[%s] LNK DOWN %x\r\n", __func__, val);
+               clrbits_le32(HW_PCIEX2_CTRL2_ADDR, HW_PCIEX2_CTRL2_APP_LTSSM_ENABLE);
+               return -ENODEV;
+       }
+
+       clrbits_le32(PORT0_LINK_CTRL, PORT_LINK_CTRL_LNK_FAST_LNK);
+
+       val = readl(PF0_LINK_CONTROL_LINK_STATUS_REG);
+       printf("[%s] PCIe GEN[%d] Lane[%d] is up.\n", __func__,
+               (val >> 16) & 0xF, (val >> 20) & 0x3F);
+
+       /* EQ phase 3 finish
+        * wait_read_check(LINK_CONTROL2_LINK_STATUS2_REG,BIT(17),BIT(17),1000);
+        */
+       /* make sure that pciea is L0 state now */
+       for (i = 0; i < 100; i++) {
+               val = readl(HW_PCIEX2_STTS0_ADDR);
+               if ((val & 0x3f) == 0x11)
+                       break;
+               udelay(10);
+       }
+
+       if ((val & 0x3f) != 0x11)
+               printf("can't return back to L0 state.\n");
+
+       writel(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER,
+               PF0_TYPE1_STATUS_COMMAND_REG);
+       printf("pcie ctrla initialization is finished.\n");
+
+       return 0;
+}
+
+int pcie_ctrlb_sata_phy_init_rc(void)
+{
+       u32 val, i = 0;
+
+       setbits_le32(HW_PHYX1_CTRL0_ADDR, HW_PHYX1_CTRL0_APB_RSTN); /* APB_RSTN */
+
+       clrbits_le32(HW_PCIEX1_CTRL0_ADDR, HW_PCIEX1_CTRL0_DEVICE_TYPE_MASK);
+       setbits_le32(HW_PCIEX1_CTRL0_ADDR, HW_PCIEX1_CTRL0_DEVICE_TYPE_RC);
+
+       setbits_le32(HW_PCIEX1_CTRL2_ADDR, HW_PCIEX1_CTRL2_BUTTON_RST_N);
+       clrbits_le32(HW_PCIEX1_CTRL2_ADDR, HW_PCIEX1_CTRL2_PERST_N);
+       setbits_le32(HW_PCIEX1_CTRL2_ADDR, HW_PCIEX1_CTRL2_PERST_N);
+       clrbits_le32(HW_PCIEX1_CTRL2_ADDR, HW_PCIEX1_CTRL2_POWER_UP_RST_N);
+       setbits_le32(HW_PCIEX1_CTRL2_ADDR, HW_PCIEX1_CTRL2_POWER_UP_RST_N);
+
+       /*
+        * bit 0 rx ena. bit 11 fast_init.
+        * bit13 phy_ab_select 1.
+        */
+       setbits_le32(HW_MISC_CTRL0_ADDR, HW_MISC_CTRL0_IOB_RXENA);
+       clrbits_le32(HW_MISC_CTRL0_ADDR, HW_MISC_CTRL0_PHY_X1_EPCS_SEL);
+
+       /* pipe_ln2lk = 0011 */
+       clrbits_le32(HW_PHYX1_CTRL0_ADDR,
+                       HW_PHYX1_CTRL0_PIPE_LN2LK_MASK);
+       setbits_le32(HW_PHYX1_CTRL0_ADDR, HW_PHYX1_CTRL0_PIPE_LN2LK_1
+                       | HW_PHYX2_CTRL0_PIPE_LN2LK_0);
+       for (i = 0; i < 100; i++) {
+               val = readl(HW_PHYX1_STTS0_ADDR);
+               val &= HW_PHYX1_STTS0_LANE0_TX_PLL_LOCK;
+               if (val == HW_PHYX1_STTS0_LANE0_TX_PLL_LOCK)
+                       break;
+               udelay(10);
+       }
+
+       if (val != HW_PHYX1_STTS0_LANE0_TX_PLL_LOCK) {
+               printf("TX PLL is not locked.\n");
+               return -ENODEV;
+       }
+
+       setbits_le32(GPR_LPCG_PHYX1_APB, BIT(1));
+
+       /* bit19 PM_REQ_CORE_RST of pciex1_stts0 should be cleared. */
+       for (i = 0; i < 100; i++) {
+               val = readl(HW_PCIEX1_STTS0_ADDR);
+               if ((val & HW_PCIEX1_STTS0_PM_REQ_CORE_RST) == 0)
+                       break;
+               udelay(10);
+       }
+
+       if ((val & HW_PCIEX1_STTS0_PM_REQ_CORE_RST) != 0)
+               printf("ERROR PM_REQ_CORE_RST is set.\n");
+
+       /* DBI_RO_WR_EN =1 to write PF1_SPCIE_CAP_OFF_0CH_REG */
+       writel(0x1, PORT1_MISC_CONTROL_1);
+       writel(0x35353535, PF1_SPCIE_CAP_OFF_0CH_REG); /* set preset not golden */
+       setbits_le32(PORT1_LINK_CTRL, PORT_LINK_CTRL_LNK_FAST_LNK);
+       setbits_le32(HW_PCIEX1_CTRL2_ADDR, HW_PCIEX1_CTRL2_APP_LTSSM_ENABLE);
+
+       do {
+               udelay(100);
+               val = readl(PORT1_LINK_DEBUG1);
+       } while (((val & PORT_LINK_DEBUG1_LINK_UP) == 0) && (i++ < 100));
+
+       if ((val & PORT_LINK_DEBUG1_LINK_UP) == PORT_LINK_DEBUG1_LINK_UP) {
+               printf("[%s] LNK UP %x\r\n", __func__, val);
+       } else {
+               printf("[%s] LNK DOWN %x\r\n", __func__, val);
+               clrbits_le32(HW_PCIEX1_CTRL2_ADDR, HW_PCIEX1_CTRL2_APP_LTSSM_ENABLE);
+               return -ENODEV;
+       }
+       clrbits_le32(PORT1_LINK_CTRL, PORT_LINK_CTRL_LNK_FAST_LNK);
+
+       val = readl(PF1_LINK_CONTROL_LINK_STATUS_REG);
+       printf("[%s] PCIe GEN[%d] Lane[%d] is up.\n", __func__,
+              (val >> 16) & 0xF, (val >> 20) & 0x3F);
+
+       /* EQ phase 3 finish
+        * wait_read_check(LINK_CONTROL2_LINK_STATUS2_REG,BIT(17),BIT(17),1000);
+        */
+       /* make sure that pcieb is L0 state now */
+       for (i = 0; i < 100; i++) {
+               val = readl(HW_PCIEX1_STTS0_ADDR);
+               if ((val & 0x3f) == 0x11)
+                       break;
+               udelay(10);
+       }
+
+       if ((val & 0x3f) != 0x11) {
+               printf("can't return back to L0 state.\n");
+               return -ENODEV;
+       }
+
+       writel(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER,
+               PF1_TYPE1_STATUS_COMMAND_REG);
+
+       return 0;
+}
+
+DECLARE_GLOBAL_DATA_PTR;
+void mx8qxp_pcie_init(void)
+{
+       pcie_ctrlx1_rst();
+       if (!pcie_ctrlb_sata_phy_init_rc())
+               mx8x_pcie_ctrlb_setup_regions();
+}
+
+void mx8qm_pcie_init(void)
+{
+       pcie_ctrlx2_rst();
+       if (!pcie_ctrla_init_rc(1))
+               mx8x_pcie_ctrla_setup_regions();
+
+#ifdef CONFIG_IMX_PCIEB
+       pcie_ctrlx1_rst();
+       if (!pcie_ctrlb_sata_phy_init_rc())
+               mx8x_pcie_ctrlb_setup_regions();
+#endif
+}
diff --git a/drivers/pci/pcie_imx8x.c b/drivers/pci/pcie_imx8x.c
new file mode 100644 (file)
index 0000000..131eb43
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ *
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+#include <common.h>
+#include <pci.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/arch/sci/sci.h>
+#include <linux/sizes.h>
+#include <errno.h>
+#include <imx8_hsio.h>
+
+void mx8x_pcie_controller_reset(sc_ipc_t ipc, u32 scr)
+{
+       sc_err_t err;
+       int i;
+
+       err = sc_misc_set_control(ipc, scr, SC_C_PCIE_G_RST, 1);
+       if (err != SC_ERR_NONE)
+               printf("SC_R_PCIE G_RST failed! (error = %d)\n", err);
+       for (i = 0; i < 200; i = i + 1)
+               asm("nop");
+
+       err = sc_misc_set_control(ipc, scr, SC_C_PCIE_G_RST, 0);
+       if (err != SC_ERR_NONE)
+               printf("SC_R_PCIE G_RST failed! (error = %d)\n", err);
+
+       err = sc_misc_set_control(ipc, scr, SC_C_PCIE_PERST, 1);
+       if (err != SC_ERR_NONE)
+               printf("SC_R_PCIE PCIE_RST failed! (error = %d)\n", err);
+
+       err = sc_misc_set_control(ipc, scr, SC_C_PCIE_BUTTON_RST, 1);
+       if (err != SC_ERR_NONE)
+               printf("SC_R_PCIE BUTTON_RST failed! (error = %d)\n", err);
+}
+
+static void pcie_mapping_region(u32 index, u32 direction, u32 type,
+                               u32 addr, u32 size, u32 target_l, u32 target_h)
+{
+       /* Select a iATU and configure its direction */
+       pcie_writel(index | direction, PCIE0_ATU_VIEWPORT);
+       setbits_le32(PCIE0_ATU_CR1, type);
+
+       /* Set memory address and size */
+       pcie_writel(addr, PCIE0_ATU_LOWER_BASE);
+       pcie_writel(0, PCIE0_ATU_UPPER_BASE);
+       pcie_writel((addr + size - 1), PCIE0_ATU_LIMIT);
+
+       pcie_writel(target_l, PCIE0_ATU_LOWER_TARGET);
+       pcie_writel(target_h, PCIE0_ATU_UPPER_TARGET);
+
+       /* Enable this iATU */
+       setbits_le32(PCIE0_ATU_CR2, PCIE_ATU_ENABLE);
+}
+
+static void pcie_ctrlb_mapping_region(u32 index, u32 direction, u32 type,
+                                     u32 addr, u32 size, u32 target_l, u32 target_h)
+{
+       /* Select a iATU and configure its direction */
+       pcie_writel(index | direction, PCIE1_ATU_VIEWPORT);
+       setbits_le32(PCIE1_ATU_CR1, type);
+
+       /* Set memory address and size */
+       pcie_writel(addr, PCIE1_ATU_LOWER_BASE);
+       pcie_writel(0, PCIE1_ATU_UPPER_BASE);
+       pcie_writel((addr + size - 1), PCIE1_ATU_LIMIT);
+
+       pcie_writel(target_l, PCIE1_ATU_LOWER_TARGET);
+       pcie_writel(target_h, PCIE1_ATU_UPPER_TARGET);
+
+       /* Enable this iATU */
+       setbits_le32(PCIE1_ATU_CR2, PCIE_ATU_ENABLE);
+}
+
+/* CFG Space  -->   0x40000000
+ * 1st Region -->   0x41000000
+ * 2nd Region -->   0x42000000
+ * ...
+ */
+void mx8x_pcie_ctrla_setup_regions(void)
+{
+       u32 i, cmd;
+       u32 val, index;
+       u32 is_32bit;
+       u32 type, size;
+       u64 size64;
+       const u32 region_types[] = {
+               PCIE_ATU_TYPE_MEM,
+               PCIE_ATU_TYPE_IO,
+       };
+
+       cmd = PCI_COMMAND_MASTER;
+
+       pcie_mapping_region(0, PCIE_ATU_REGION_OUTBOUND, PCIE_ATU_TYPE_CFG0,
+                           PCIEA_CFG_PCI_BASE, PCIE_CFG_MEM_SIZE, 0, 0);
+
+       index = 1;
+       udelay(1000);
+
+       for (i = 0; i < 6; i++) {
+               val = pcie_readl(PCIEA_CFG_CPU_BASE + 0x10 + i * 4);
+               printf("#### [%d] val=%X addr=%X\r\n ", i, val,
+                      PCIEA_CFG_CPU_BASE + 0x10 + i * 4);
+               if (!val)
+                       continue;
+               type = region_types[val & 0x1];
+               is_32bit = ((val & 0x4) == 0);
+               pcie_writel(0xFFFFFFFF, PCIEA_CFG_CPU_BASE + 0x10 + i * 4);
+               size = pcie_readl(PCIEA_CFG_CPU_BASE + 0x10 + i * 4);
+               size = 0xFFFFFFFF - (size & ~0xF) + 1;
+               if (is_32bit) {
+                       pcie_mapping_region(index, PCIE_ATU_REGION_OUTBOUND,
+                                           type, PCIEA_CFG_PCI_BASE
+                                           + index * 0x1000000, size,
+                                           index * 0x1000000, 0);
+                       val = (val & 0xF) + index * 0x1000000;
+                       pcie_writel(val, (PCIEA_CFG_CPU_BASE + 0x10 + i * 4));
+               } else {
+                       pcie_writel(0xFFFFFFFF, (PCIEA_CFG_CPU_BASE + 0x10
+                                               + i * 4 + 4));
+                       size64 = pcie_readl(PCIEA_CFG_CPU_BASE
+                                       + 0x10 + i * 4 + 4);
+                       size64 = 0xFFFFFFFF - size64;
+                       size64 <<= 32;
+                       size64 |= size;
+                       size64++;
+                       pcie_mapping_region(index, PCIE_ATU_REGION_OUTBOUND,
+                                           type, PCIEA_CFG_PCI_BASE
+                                           + index * 0x1000000, size64,
+                                           index * 0x1000000, 0);
+                       val = (val & 0xF) + index * 0x1000000;
+                       pcie_writel(val, (PCIEA_CFG_CPU_BASE + 0x10 + i * 4));
+                       pcie_writel(0, (PCIEA_CFG_CPU_BASE + 0x10 + i * 4 + 4));
+                       i++;
+               }
+
+               index++;
+
+               if (type == PCIE_ATU_TYPE_MEM)
+                       cmd |= PCI_COMMAND_MEMORY;
+               else
+                       cmd |= PCI_COMMAND_IO;
+       }
+
+       pcie_writel(cmd, PCIEA_CFG_CPU_BASE + 4);
+}
+
+/* CFG Space  -->   0x80000000
+ * 1st Region -->   0x81000000
+ * 2nd Region -->   0x82000000
+ * ...
+ */
+void mx8x_pcie_ctrlb_setup_regions(void)
+{
+       u32 i, cmd;
+       u32 val, index;
+       u32 is_32bit;
+       u32 type, size;
+       u64 size64;
+       const u32 region_types[] = {
+               PCIE_ATU_TYPE_MEM,
+               PCIE_ATU_TYPE_IO,
+       };
+
+       cmd = PCI_COMMAND_MASTER;
+
+       pcie_ctrlb_mapping_region(0, PCIE_ATU_REGION_OUTBOUND, PCIE_ATU_TYPE_CFG0,
+                                 PCIEB_CFG_PCI_BASE, PCIE_CFG_MEM_SIZE, 0, 0);
+
+       index = 1;
+       udelay(1000);
+
+       for (i = 0; i < 6; i++) {
+               val = pcie_readl(PCIEB_CFG_CPU_BASE + 0x10 + i * 4);
+               printf("#### [%d] val=%X addr=%X\r\n ", i, val,
+                      PCIEB_CFG_CPU_BASE + 0x10 + i * 4);
+               if (!val)
+                       continue;
+               type = region_types[val & 0x1];
+               is_32bit = ((val & 0x4) == 0);
+               pcie_writel(0xFFFFFFFF, PCIEB_CFG_CPU_BASE + 0x10 + i * 4);
+               size = pcie_readl(PCIEB_CFG_CPU_BASE + 0x10 + i * 4);
+               size = 0xFFFFFFFF - (size & ~0xF) + 1;
+               if (is_32bit) {
+                       pcie_ctrlb_mapping_region(index, PCIE_ATU_REGION_OUTBOUND,
+                                                 type, PCIEB_CFG_PCI_BASE
+                                                 + index * 0x1000000, size,
+                                                 index * 0x1000000, 0);
+                       val = (val & 0xF) + index * 0x1000000;
+                       pcie_writel(val, (PCIEB_CFG_CPU_BASE + 0x10 + i * 4));
+               } else {
+                       pcie_writel(0xFFFFFFFF, (PCIEB_CFG_CPU_BASE + 0x10
+                                               + i * 4 + 4));
+                       size64 = pcie_readl(PCIEB_CFG_CPU_BASE
+                                       + 0x10 + i * 4 + 4);
+                       size64 = 0xFFFFFFFF - size64;
+                       size64 <<= 32;
+                       size64 |= size;
+                       size64++;
+                       pcie_ctrlb_mapping_region(index, PCIE_ATU_REGION_OUTBOUND,
+                                                 type, PCIEB_CFG_PCI_BASE
+                                                 + index * 0x1000000, size64,
+                                                 index * 0x1000000, 0);
+                       val = (val & 0xF) + index * 0x1000000;
+                       pcie_writel(val, (PCIEB_CFG_CPU_BASE + 0x10 + i * 4));
+                       pcie_writel(0, (PCIEB_CFG_CPU_BASE + 0x10 + i * 4 + 4));
+                       i++;
+               }
+
+               index++;
+
+               if (type == PCIE_ATU_TYPE_MEM)
+                       cmd |= PCI_COMMAND_MEMORY;
+               else
+                       cmd |= PCI_COMMAND_IO;
+       }
+
+       pcie_writel(cmd, PCIEB_CFG_CPU_BASE + 4);
+}
+
diff --git a/include/imx8_hsio.h b/include/imx8_hsio.h
new file mode 100644 (file)
index 0000000..13cc881
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef _IMX8_HSIO_H_
+#define _IMX8_HSIO_H_
+
+#define PCIEA_CFG_CPU_BASE     0x60000000
+#define PCIEA_CFG_PCI_BASE     0x40000000
+#define PCIEB_CFG_CPU_BASE     0x70000000
+#define PCIEB_CFG_PCI_BASE     0x80000000
+#define PCIE_CFG_MEM_SIZE      0x4000
+
+#define PCIE_DBI_BASE_ADDR     0x5f000000
+#define PCIE_CTRLA_BASE_ADDR   PCIE_DBI_BASE_ADDR
+#define PCIE_CTRLB_BASE_ADDR   (PCIE_DBI_BASE_ADDR + 0x10000)
+
+/* For 8DV */
+#define DEVICE_TYPE_RC         BIT(14)
+#define REFCLK_SEL             BIT(4)
+#define CMN_REG_RST            BIT(3)
+
+#define HSIO_BASE_ADDR                  0x5F070000
+#define HSIO_GPR_PCIE_CTRL0_ADDR       (HSIO_BASE_ADDR + 0x00000000)
+#define HSIO_GPR_PCIE_CTRL1_ADDR       (HSIO_BASE_ADDR + 0x00000004)
+#define HSIO_GPR_PCIE_STATUS0_ADDR     (HSIO_BASE_ADDR + 0x00000008)
+
+/* For 8QM */
+#define AHCI_BASE_ADDR                 0x5F020000
+#define HW_SATA_CTRL0_ADDR             (HSIO_CRR_BASE_ADDR + 0x00040000)
+#define HW_SATA_CTRL0_ADDR_MASK                0x000017fb
+#define HW_SATA_CTRL0_ADDR_RESET       0x0
+#define HW_SATA_CTRL0_PHY_FOMREQ       BIT(0)
+#define HW_SATA_CTRL0_PHY_PMA_DRVN     BIT(1)
+#define HW_SATA_CTRL0_EPCS_SKIPBIT     BIT(3)
+#define HW_SATA_CTRL0_EPCS_RXERR       BIT(4)
+#define HW_SATA_CTRL0_EPCS_TXDEEMP     BIT(5)
+#define HW_SATA_CTRL0_EPCS_TXDEEMP_SEL BIT(6)
+#define HW_SATA_CTRL0_PHY_RESET                BIT(7)
+#define HW_SATA_CTRL0_EPCS_PHYRESET_SEL        BIT(8)
+#define HW_SATA_CTRL0_EPCS_RXOOB       BIT(9)
+#define HW_SATA_CTRL0_EPCS_RXOOB_SEL   BIT(10)
+#define HW_SATA_CTRL0_RESET            BIT(12)
+
+#define HSIO_LPCG_BASE_ADDR            0x5F050000
+#define HSIO_GPIO_BASE_ADDR            0x5F170000
+
+#define GPR_LPCG_PCIEA_CTRL_MSTR_ACLK (HSIO_LPCG_BASE_ADDR + 0x00000000)
+#define GPR_LPCG_PCIEB_CTRL_MSTR_ACLK (HSIO_LPCG_BASE_ADDR + 0x00010000)
+#define GPR_LPCG_PHYX2APB_0_APB       (HSIO_LPCG_BASE_ADDR + 0x00030000)
+#define GPR_LPCG_PHYX1_APB            (HSIO_LPCG_BASE_ADDR + 0x00040000)
+#define GPR_LPCG_CRR_0                (HSIO_LPCG_BASE_ADDR + 0x00050000)
+#define GPR_LPCG_CRR_1                (HSIO_LPCG_BASE_ADDR + 0x00060000)
+#define GPR_LPCG_CRR_2                (HSIO_LPCG_BASE_ADDR + 0x00070000)
+#define GPR_LPCG_CRR_3                (HSIO_LPCG_BASE_ADDR + 0x00080000)
+#define GPR_LPCG_CRR_4                (HSIO_LPCG_BASE_ADDR + 0x00090000)
+#define GPR_LPCG_CRR_5                (HSIO_LPCG_BASE_ADDR + 0x000a0000)
+#define GPR_LPCG_GPIO                 (HSIO_LPCG_BASE_ADDR + 0x000b0000)
+
+#define HSIO_CRR_BASE_ADDR             0x5F110000
+
+#define HW_PHYX2_CTRL0_ADDR            (HSIO_CRR_BASE_ADDR + 0x00000000)
+#define HW_PHYX2_CTRL0_APB_RSTN_0      BIT(0)
+#define HW_PHYX2_CTRL0_APB_RSTN_1      BIT(1)
+#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 HW_PHYX2_STTS0_ADDR            (HSIO_CRR_BASE_ADDR + 0x00000004)
+#define HW_PHYX2_STTS0_LANE0_TX_PLL_LOCK       BIT(4)
+#define HW_PHYX2_STTS0_LANE1_TX_PLL_LOCK       BIT(12)
+
+#define HW_PHYX1_CTRL0_ADDR            (HSIO_CRR_BASE_ADDR + 0x00010000)
+#define HW_PHYX1_CTRL0_APB_RSTN                BIT(0)
+#define HW_PHYX1_CTRL0_PIPE_LN2LK_MASK  (0xF << 13)
+#define HW_PHYX1_CTRL0_PIPE_LN2LK_0     BIT(13)
+#define HW_PHYX1_CTRL0_PIPE_LN2LK_1     BIT(14)
+#define HW_PHYX1_CTRL0_PIPE_LN2LK_2     BIT(15)
+#define HW_PHYX1_CTRL0_PIPE_LN2LK_3     BIT(16)
+
+#define HW_PHYX1_STTS0_ADDR            (HSIO_CRR_BASE_ADDR + 0x00010004)
+#define HW_PHYX1_STTS0_LANE0_TX_PLL_LOCK       BIT(4)
+#define HW_PHYX1_STTS0_LANE0_RX_PLL_LOCK       BIT(5)
+
+#define HW_MISC_CTRL0_ADDR             (HSIO_CRR_BASE_ADDR + 0x00050000)
+#define HW_MISC_CTRL0_IOB_RXENA                BIT(0)
+#define HW_MISC_CTRL0_IOB_TXENA                BIT(1)
+#define HW_MISC_CTRL0_FAST_INIT                BIT(11)
+#define HW_MISC_CTRL0_PHY_X1_EPCS_SEL  BIT(12)
+#define HW_MISC_CTRL0_PCIE_AB_SELECT   BIT(13)
+
+#define HW_PCIEX2_CTRL0_ADDR                   (HSIO_CRR_BASE_ADDR + 0x00020000)
+#define HW_PCIEX2_CTRL0_DEVICE_TYPE_MASK       (0xF << 24)
+#define HW_PCIEX2_CTRL0_DEVICE_TYPE_RC         BIT(26)
+
+#define HW_PCIEX2_CTRL2_ADDR                   (HSIO_CRR_BASE_ADDR + 0x00020008)
+#define HW_PCIEX2_CTRL2_APP_LTSSM_ENABLE       BIT(4)
+#define HW_PCIEX2_CTRL2_BUTTON_RST_N           BIT(21)
+#define HW_PCIEX2_CTRL2_PERST_N                        BIT(22)
+#define HW_PCIEX2_CTRL2_POWER_UP_RST_N         BIT(23)
+
+#define HW_PCIEX2_STTS0_ADDR           (HSIO_CRR_BASE_ADDR + 0x0002000C)
+#define HW_PCIEX2_STTS0_PM_REQ_CORE_RST BIT(19)
+
+#define HW_PCIEX1_CTRL0_ADDR           (HSIO_CRR_BASE_ADDR + 0x00030000)
+#define HW_PCIEX1_CTRL0_DEVICE_TYPE_MASK       (0xF << 24)
+#define HW_PCIEX1_CTRL0_DEVICE_TYPE_RC         BIT(26)
+
+#define HW_PCIEX1_CTRL2_ADDR           (HSIO_CRR_BASE_ADDR + 0x00030008)
+#define HW_PCIEX1_CTRL2_APP_LTSSM_ENABLE       BIT(4)
+#define HW_PCIEX1_CTRL2_BUTTON_RST_N           BIT(21)
+#define HW_PCIEX1_CTRL2_PERST_N                        BIT(22)
+#define HW_PCIEX1_CTRL2_POWER_UP_RST_N         BIT(23)
+
+#define HW_PCIEX1_STTS0_ADDR           (HSIO_CRR_BASE_ADDR + 0x0003000c)
+#define HW_PCIEX1_STTS0_PM_REQ_CORE_RST BIT(19)
+
+/* PCIe Port Logic registers (memory-mapped) */
+#define PF0_PORT_LOGIC                 (PCIE_CTRLA_BASE_ADDR + 0x700)
+#define PF1_PORT_LOGIC                 (PCIE_CTRLB_BASE_ADDR + 0x700)
+
+#define PORT0_LINK_CTRL                        (PF0_PORT_LOGIC + 0x10)
+#define PORT1_LINK_CTRL                        (PF1_PORT_LOGIC + 0x10)
+#define PORT_LINK_CTRL_LNK_EN_MASK     (0x3F << 16)
+#define PORT_LINK_CTRL_LNK_LANE1       (0x1 << 16)
+#define PORT_LINK_CTRL_LNK_LANE2       (0x3 << 16)
+#define PORT_LINK_CTRL_LNK_FAST_LNK    BIT(7)
+
+#define PORT0_LINK_DEBUG1              (PF0_PORT_LOGIC + 0x2C)
+#define PORT1_LINK_DEBUG1              (PF1_PORT_LOGIC + 0x2C)
+#define PORT_LINK_DEBUG1_LINK_UP       BIT(4)
+
+#define PORT0_GEN2_CTRL                        (PF0_PORT_LOGIC + 0x10C)
+#define PORT1_GEN2_CTRL                        (PF1_PORT_LOGIC + 0x10C)
+#define PORT_GEN2_CTRL_NUM_LANES_MASK  (0xFF << 8)
+#define PORT_GEN2_CTRL_NUM_LANES_1     (0x1 << 8)
+#define PORT_GEN2_CTRL_NUM_LANES_2     (0x2 << 8)
+
+#define PORT0_MISC_CONTROL_1           (PF0_PORT_LOGIC + 0x1BC)
+#define PORT1_MISC_CONTROL_1           (PF1_PORT_LOGIC + 0x1BC)
+
+#define PORT0_DBI_LNK_STS_CTRL2                (PCIE_CTRLA_BASE_ADDR + 0xA0)
+
+#define PF0_TYPE1_HDR                  (PCIE_CTRLA_BASE_ADDR + 0x0)
+#define PF0_TYPE1_STATUS_COMMAND_REG   (PF0_TYPE1_HDR + 0x4)
+#define PF1_TYPE1_HDR                  (PCIE_CTRLB_BASE_ADDR + 0x0)
+#define PF1_TYPE1_STATUS_COMMAND_REG   (PF1_TYPE1_HDR + 0x4)
+
+#define PF0_PCIE_CAP                           (PCIE_CTRLA_BASE_ADDR + 0x70)
+#define PF0_LINK_CONTROL_LINK_STATUS_REG       (PF0_PCIE_CAP + 0x10)
+#define PF1_PCIE_CAP                           (PCIE_CTRLB_BASE_ADDR + 0x70)
+#define PF1_LINK_CONTROL_LINK_STATUS_REG       (PF1_PCIE_CAP + 0x10)
+
+#define PF0_SPICE_CAP                  (PCIE_CTRLA_BASE_ADDR + 0x148)
+#define PF0_SPCIE_CAP_OFF_0CH_REG      (PF0_SPICE_CAP + 0xC)
+#define PF1_SPICE_CAP                  (PCIE_CTRLB_BASE_ADDR + 0x148)
+#define PF1_SPCIE_CAP_OFF_0CH_REG      (PF1_SPICE_CAP + 0xC)
+
+/* iATU registers */
+#define PCIE0_ATU_VIEWPORT             (PCIE_CTRLA_BASE_ADDR + 0x900)
+#define PCIE1_ATU_VIEWPORT             (PCIE_CTRLB_BASE_ADDR + 0x900)
+#define PCIE_ATU_REGION_INBOUND                (0x1 << 31)
+#define PCIE_ATU_REGION_OUTBOUND       (0x0 << 31)
+#define PCIE_ATU_REGION_INDEX1         (0x1 << 0)
+#define PCIE_ATU_REGION_INDEX0         (0x0 << 0)
+#define PCIE0_ATU_CR1                  (PCIE_CTRLA_BASE_ADDR + 0x904)
+#define PCIE1_ATU_CR1                  (PCIE_CTRLB_BASE_ADDR + 0x904)
+#define PCIE_ATU_TYPE_MEM              (0x0 << 0)
+#define PCIE_ATU_TYPE_IO               (0x2 << 0)
+#define PCIE_ATU_TYPE_CFG0             (0x4 << 0)
+#define PCIE_ATU_TYPE_CFG1             (0x5 << 0)
+#define PCIE0_ATU_CR2                  (PCIE_CTRLA_BASE_ADDR + 0x908)
+#define PCIE1_ATU_CR2                  (PCIE_CTRLB_BASE_ADDR + 0x908)
+#define PCIE_ATU_ENABLE                        (0x1 << 31)
+#define PCIE_ATU_BAR_MODE_ENABLE       (0x1 << 30)
+#define PCIE0_ATU_LOWER_BASE           (PCIE_CTRLA_BASE_ADDR + 0x90C)
+#define PCIE0_ATU_UPPER_BASE           (PCIE_CTRLA_BASE_ADDR + 0x910)
+#define PCIE0_ATU_LIMIT                        (PCIE_CTRLA_BASE_ADDR + 0x914)
+#define PCIE0_ATU_LOWER_TARGET         (PCIE_CTRLA_BASE_ADDR + 0x918)
+#define PCIE0_ATU_UPPER_TARGET         (PCIE_CTRLA_BASE_ADDR + 0x91C)
+#define PCIE1_ATU_LOWER_BASE           (PCIE_CTRLB_BASE_ADDR + 0x90C)
+#define PCIE1_ATU_UPPER_BASE           (PCIE_CTRLB_BASE_ADDR + 0x910)
+#define PCIE1_ATU_LIMIT                        (PCIE_CTRLB_BASE_ADDR + 0x914)
+#define PCIE1_ATU_LOWER_TARGET         (PCIE_CTRLB_BASE_ADDR + 0x918)
+#define PCIE1_ATU_UPPER_TARGET         (PCIE_CTRLB_BASE_ADDR + 0x91C)
+
+#define  PCI_COMMAND_IO                0x1 /* Enable response in I/O space */
+#define  PCI_COMMAND_MEMORY    0x2 /* Enable response in Memory space */
+#define  PCI_COMMAND_MASTER    0x4 /* Enable bus mastering */
+
+#define pcie_readl(x)                  readl((unsigned long)x)
+#define pcie_writel(v, c)              writel(v, (unsigned long)c)
+#define pcie_clrbits_le32(addr, clear) clrbits_le32((unsigned long)addr, clear)
+
+void mx8x_pcie_controller_reset(sc_ipc_t ipc, u32 SC_R_PCIE);
+void mx8x_pcie_ctrla_setup_regions(void);
+void mx8x_pcie_ctrlb_setup_regions(void);
+
+void mx8dv_pcie_init(void);
+void mx8qm_pcie_init(void);
+void mx8qxp_pcie_init(void);
+
+int sata_init(void);
+
+#endif /* _IMX8_HSIO_H_ */
index 8c7c159..bdbaf20 100644 (file)
@@ -632,6 +632,7 @@ CONFIG_FSL_ESDHC_PIN_MUX
 CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK
 CONFIG_FSL_FIXED_MMC_LOCATION
 CONFIG_FSL_FM_10GEC_REGULAR_NOTATION
+CONFIG_FSL_HSIO
 CONFIG_FSL_I2C_CUSTOM_DFSR
 CONFIG_FSL_I2C_CUSTOM_FDR
 CONFIG_FSL_IIM
@@ -936,6 +937,7 @@ CONFIG_IMX6_PWM_PER_CLK
 CONFIG_IMX_HDMI
 CONFIG_IMX_NAND
 CONFIG_IMX_OTP
+CONFIG_IMX_PCIEB
 CONFIG_IMX_VIDEO_SKIP
 CONFIG_INETSPACE_V2
 CONFIG_INITRD_TAG
@@ -1410,6 +1412,7 @@ CONFIG_PCIE2
 CONFIG_PCIE3
 CONFIG_PCIE4
 CONFIG_PCIE_IMX
+CONFIG_PCIE_IMX8X
 CONFIG_PCIE_IMX_PERST_GPIO
 CONFIG_PCIE_IMX_POWER_GPIO
 CONFIG_PCISLAVE