summaryrefslogtreecommitdiff
path: root/drivers/pci/host
diff options
context:
space:
mode:
authorRichard Zhu <hongxing.zhu@nxp.com>2018-07-30 11:01:38 +0800
committerLeonard Crestez <leonard.crestez@nxp.com>2018-08-24 12:41:33 +0300
commite5fc2bf1176a4cbd06e53a44703b591fc866cf75 (patch)
tree353be46168adbd67699c281a905eac08cbe5cc36 /drivers/pci/host
parentf21241f50f268df8459aa22e83bec57327510727 (diff)
MLK-19088-2 PCI: imx: enable the l1.1 aspm support on imx8mq
- Enable the L1.1 ASPM support on iMX8MQ, and verified on the both PCIe ports of the EVK board. - Fix the L1 exit latency larger than 64us issue Otherwise, the L1/L1.1 ASPM would be disabled in the initialization. - Add the internal PLL of the PCIe REF_CLK support, and verify the L1.1 ASPM on port0 of 8MQ EVK board Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
Diffstat (limited to 'drivers/pci/host')
-rw-r--r--drivers/pci/host/pci-imx6.c100
1 files changed, 87 insertions, 13 deletions
diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c
index 96fe59c6f16d..7132a506461a 100644
--- a/drivers/pci/host/pci-imx6.c
+++ b/drivers/pci/host/pci-imx6.c
@@ -256,6 +256,8 @@ struct imx_pcie {
#define IMX8QM_MISC_PHYX1_EPCS_SEL BIT(12)
#define IMX8QM_MISC_PCIE_AB_SELECT BIT(13)
+#define IMX8MQ_PCIE_LINK_CAP_REG_OFFSET 0x7C
+#define IMX8MQ_PCIE_LINK_CAP_L1EL_64US (0x6 << 15)
#define IMX8MQ_SRC_PCIEPHY_RCR_OFFSET 0x2C
#define IMX8MQ_SRC_PCIE2PHY_RCR_OFFSET 0x48
#define IMX8MQ_PCIEPHY_DOMAIN_EN (BIT(31) | (0xF << 24))
@@ -263,6 +265,7 @@ struct imx_pcie {
#define IMX8MQ_PCIEPHY_G_RST BIT(1)
#define IMX8MQ_PCIEPHY_BTN BIT(2)
#define IMX8MQ_PCIEPHY_PERST BIT(3)
+#define IMX8MQ_PCIE_CTRL_APPS_CLK_REQ BIT(4)
#define IMX8MQ_PCIE_CTRL_APPS_EN BIT(6)
#define IMX8MQ_PCIE_CTRL_APPS_TURNOFF BIT(11)
@@ -276,6 +279,15 @@ struct imx_pcie {
#define IMX8MQ_GPC_PGC_PCIE2_BIT_OFFSET 12
#define IMX8MQ_GPC_PCG_PCIE_CTRL_PCR BIT(0)
#define IMX8MQ_GPR_PCIE_REF_USE_PAD BIT(9)
+#define IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN BIT(10)
+#define IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE BIT(11)
+#define IMX8MQ_ANA_PLLOUT_REG 0x74
+#define IMX8MQ_ANA_PLLOUT_CKE BIT(4)
+#define IMX8MQ_ANA_PLLOUT_SEL_MASK 0xF
+#define IMX8MQ_ANA_PLLOUT_SEL_SYSPLL1 0xB
+#define IMX8MQ_ANA_PLLOUT_DIV_REG 0x7C
+#define IMX8MQ_ANA_PLLOUT_SYSPLL1_DIV 0x7
+
#define IMX8MM_GPR_PCIE_REF_CLK_SEL (0x3 << 24)
#define IMX8MM_GPR_PCIE_REF_CLK_PLL (0x3 << 24)
#define IMX8MM_GPR_PCIE_REF_CLK_EXT (0x2 << 24)
@@ -872,6 +884,42 @@ static int imx_pcie_deassert_core_reset(struct imx_pcie *imx_pcie)
IMX8MQ_PCIE_CTRL_APPS_EN |
IMX8MQ_PCIEPHY_DOMAIN_EN,
IMX8MQ_PCIEPHY_DOMAIN_EN);
+ /*
+ * Configure the CLK_REQ# high, let the L1SS
+ * automatically controlled by HW.
+ */
+ regmap_update_bits(imx_pcie->reg_src, val,
+ IMX8MQ_PCIE_CTRL_APPS_CLK_REQ,
+ IMX8MQ_PCIE_CTRL_APPS_CLK_REQ);
+ /*
+ * Set the over ride low and enabled
+ * make sure that REF_CLK is turned on.
+ */
+ if (imx_pcie->ctrl_id == 0)
+ val = IOMUXC_GPR14;
+ else
+ val = IOMUXC_GPR16;
+
+ regmap_update_bits(imx_pcie->iomuxc_gpr, val,
+ IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE,
+ 0);
+ regmap_update_bits(imx_pcie->iomuxc_gpr, val,
+ IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN,
+ IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN);
+
+ if (dw_pcie_readl_rc(pp, PCIE_MISC_CTRL) == 0)
+ dw_pcie_writel_rc(pp, PCIE_MISC_CTRL,
+ PCIE_MISC_DBI_RO_WR_EN);
+ /*
+ * Configure the L1 latency of rc to less than 64us
+ * Otherwise, the L1/L1SUB wouldn't be enable by ASPM.
+ */
+ val = readl(pp->dbi_base + SZ_1M +
+ IMX8MQ_PCIE_LINK_CAP_REG_OFFSET);
+ val &= ~PCI_EXP_LNKCAP_L1EL;
+ val |= IMX8MQ_PCIE_LINK_CAP_L1EL_64US;
+ writel(val, pp->dbi_base + SZ_1M +
+ IMX8MQ_PCIE_LINK_CAP_REG_OFFSET);
break;
}
@@ -1000,6 +1048,8 @@ static void imx_pcie_init_phy(struct imx_pcie *imx_pcie)
{
u32 tmp, val;
int ret;
+ struct device_node *np;
+ void __iomem *base;
if (imx_pcie->variant == IMX8QM
|| imx_pcie->variant == IMX8QXP) {
@@ -1141,14 +1191,14 @@ static void imx_pcie_init_phy(struct imx_pcie *imx_pcie)
"PHY Initialization End!.\n");
}
} else {
+ regmap_update_bits(imx_pcie->iomuxc_gpr, val,
+ IMX8MQ_GPR_PCIE_REF_USE_PAD,
+ 0);
if (imx_pcie->variant == IMX8MM) {
/* Configure the internal PLL as REF clock */
dev_info(imx_pcie->pp.dev,
"Initialize PHY with PLL REfCLK!.\n");
regmap_update_bits(imx_pcie->iomuxc_gpr, val,
- IMX8MQ_GPR_PCIE_REF_USE_PAD,
- 0);
- regmap_update_bits(imx_pcie->iomuxc_gpr, val,
IMX8MM_GPR_PCIE_REF_CLK_SEL,
IMX8MM_GPR_PCIE_REF_CLK_SEL);
regmap_update_bits(imx_pcie->iomuxc_gpr, val,
@@ -1178,8 +1228,23 @@ static void imx_pcie_init_phy(struct imx_pcie *imx_pcie)
dev_info(imx_pcie->pp.dev,
"PHY Initialization End!.\n");
} else {
- dev_err(imx_pcie->pp.dev,
- "Don't support internal PLL.\n");
+ np = of_find_compatible_node(NULL, NULL,
+ "fsl,imx8mq-anatop");
+ base = of_iomap(np, 0);
+ WARN_ON(!base);
+
+ val = readl(base + IMX8MQ_ANA_PLLOUT_REG);
+ val &= ~IMX8MQ_ANA_PLLOUT_SEL_MASK;
+ val |= IMX8MQ_ANA_PLLOUT_SEL_SYSPLL1;
+ writel(val, base + IMX8MQ_ANA_PLLOUT_REG);
+ /* SYS_PLL1 is 800M, PCIE REF CLK is 100M */
+ val = readl(base + IMX8MQ_ANA_PLLOUT_DIV_REG);
+ val |= IMX8MQ_ANA_PLLOUT_SYSPLL1_DIV;
+ writel(val, base + IMX8MQ_ANA_PLLOUT_DIV_REG);
+
+ val = readl(base + IMX8MQ_ANA_PLLOUT_REG);
+ val |= IMX8MQ_ANA_PLLOUT_CKE;
+ writel(val, base + IMX8MQ_ANA_PLLOUT_REG);
}
}
} else if (imx_pcie->variant == IMX7D) {
@@ -1342,7 +1407,6 @@ static irqreturn_t imx_pcie_msi_handler(int irq, void *arg)
static void pci_imx_clk_disable(struct device *dev)
{
- u32 val;
struct imx_pcie *imx_pcie = dev_get_drvdata(dev);
clk_disable_unprepare(imx_pcie->pcie);
@@ -1368,13 +1432,6 @@ static void pci_imx_clk_disable(struct device *dev)
break;
case IMX8MQ:
case IMX8MM:
- if (imx_pcie->ctrl_id == 0)
- val = IOMUXC_GPR14;
- else
- val = IOMUXC_GPR16;
-
- regmap_update_bits(imx_pcie->iomuxc_gpr, val,
- IMX8MQ_GPR_PCIE_REF_USE_PAD, 0);
break;
case IMX8QXP:
case IMX8QM:
@@ -1509,6 +1566,7 @@ err_reset_phy:
static int imx_pcie_host_init(struct pcie_port *pp)
{
+ u32 val;
int ret;
struct imx_pcie *imx_pcie = to_imx_pcie(pp);
@@ -1524,6 +1582,22 @@ static int imx_pcie_host_init(struct pcie_port *pp)
if (!IS_ENABLED(CONFIG_EP_MODE_IN_EP_RC_SYS)) {
dw_pcie_setup_rc(pp);
ret = imx_pcie_establish_link(imx_pcie);
+ /*
+ * Disable the over ride.
+ * Configure the CLK_REQ# high, let the L1SS automatically
+ * controlled by HW when link is up.
+ * Otherwise, turn off the REF_CLK to save power consumption.
+ */
+ if (imx_pcie->variant == IMX8MQ) {
+ if (imx_pcie->ctrl_id == 0)
+ val = IOMUXC_GPR14;
+ else
+ val = IOMUXC_GPR16;
+
+ regmap_update_bits(imx_pcie->iomuxc_gpr, val,
+ IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN,
+ 0);
+ }
if (ret < 0)
return ret;