diff options
Diffstat (limited to 'drivers/pci/controller/dwc/pci-imx6.c')
-rw-r--r-- | drivers/pci/controller/dwc/pci-imx6.c | 169 |
1 files changed, 103 insertions, 66 deletions
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index f37b805fd730..1fd06bb5840e 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -40,7 +40,7 @@ #include "pcie-designware.h" #define IMX8MQ_PCIE_LINK_CAP_REG_OFFSET 0x7c -#define IMX8MQ_PCIE_LINK_CAP_L1EL_64US (BIT(18) | BIT(17)) +#define IMX8MQ_PCIE_LINK_CAP_L1EL_64US GENMASK(18, 17) #define IMX8MQ_PCIE_L1SUB_CTRL1_REG_EN_MASK 0xf #define IMX8MQ_GPR_PCIE_REF_USE_PAD BIT(9) #define IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN BIT(10) @@ -62,15 +62,16 @@ #define IMX8MP_GPR_REG2_P_PLL (0xc << 0) #define IMX8MP_GPR_REG2_M_PLL (0x320 << 6) #define IMX8MP_GPR_REG2_S_PLL (0x4 << 16) -#define IMX8MP_GPR_REG2_BYPASS_PLL BIT(21) #define IMX8MP_GPR_REG3 0xc #define IMX8MP_GPR_REG3_PLL_CKE BIT(17) -#define IMX8MP_GPR_REG3_PLL_EXT_BYPASS BIT(18) #define IMX8MP_GPR_REG3_PLL_RST BIT(31) +#define IMX8MP_GPR_PCIE_SSC_EN BIT(16) +#define IMX8MP_GPR_PCIE_PWR_OFF BIT(17) +#define IMX8MP_GPR_PCIE_CMN_RSTN BIT(18) +#define IMX8MP_GPR_PCIE_AUX_EN BIT(19) #define IMX8MP_GPR_PCIE_REF_SEL_MASK GENMASK(25, 24) -#define IMX8MP_GPR_PCIE_REF_PLL (BIT(24) | BIT(25)) +#define IMX8MP_GPR_PCIE_REF_PLL_SYS GENMASK(25, 24) #define IMX8MP_GPR_PCIE_REF_EXT_OSC BIT(25) -#define IMX8MP_GPR_PCIE_REF_EXT_XO BIT(24) #define to_imx6_pcie(x) dev_get_drvdata((x)->dev) @@ -171,6 +172,7 @@ struct imx6_pcie { #define PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK 0xf #define PCIE_RC_LCSR 0x80 +#define PCIE_RC_LC2SR 0xa0 /* PCIe Port Logic registers (memory-mapped) */ #define PL_OFFSET 0x700 @@ -1045,7 +1047,9 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) /* fall through */ case IMX8MP: - reset_control_assert(imx6_pcie->apps_reset); + imx6_pcie_ltssm_disable(dev); + reset_control_assert(imx6_pcie->pciephy_reset); + reset_control_assert(imx6_pcie->pciephy_perst); break; case IMX6SX: regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, @@ -1150,6 +1154,33 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) } } +static void imx6_pcie_set_l1_latency(struct imx6_pcie *imx6_pcie) +{ + u32 val; + struct dw_pcie *pci = imx6_pcie->pci; + + switch (imx6_pcie->drvdata->variant) { + case IMX8MQ: + case IMX8MM: + case IMX8MP: + /* + * Configure the L1 latency of rc to less than 64us + * Otherwise, the L1/L1SUB wouldn't be enable by ASPM. + */ + dw_pcie_dbi_ro_wr_en(pci); + val = readl(pci->dbi_base + SZ_1M + + IMX8MQ_PCIE_LINK_CAP_REG_OFFSET); + val &= ~PCI_EXP_LNKCAP_L1EL; + val |= IMX8MQ_PCIE_LINK_CAP_L1EL_64US; + writel(val, pci->dbi_base + SZ_1M + + IMX8MQ_PCIE_LINK_CAP_REG_OFFSET); + dw_pcie_dbi_ro_wr_dis(pci); + break; + default: + break; + } +} + static int imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) { struct dw_pcie *pci = imx6_pcie->pci; @@ -1252,56 +1283,59 @@ static int imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN, IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN); - if (imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_SUPPORTS_L1SS) { + if (imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_SUPPORTS_L1SS) /* * Configure the CLK_REQ# high, let the L1SS * automatically controlled by HW later. */ reset_control_deassert(imx6_pcie->clkreq_reset); - /* - * Configure the L1 latency of rc to less than 64us - * Otherwise, the L1/L1SUB wouldn't be enable by ASPM. - */ - dw_pcie_dbi_ro_wr_en(pci); - val = readl(pci->dbi_base + SZ_1M + - IMX8MQ_PCIE_LINK_CAP_REG_OFFSET); - val &= ~PCI_EXP_LNKCAP_L1EL; - val |= IMX8MQ_PCIE_LINK_CAP_L1EL_64US; - writel(val, pci->dbi_base + SZ_1M + - IMX8MQ_PCIE_LINK_CAP_REG_OFFSET); - dw_pcie_dbi_ro_wr_dis(pci); - } + imx6_pcie_set_l1_latency(imx6_pcie); break; case IMX8MP: - if (phy_power_on(imx6_pcie->phy) < 0) - dev_err(dev, "Failed to power on PHY!\n"); - reset_control_assert(imx6_pcie->pciephy_perst); - reset_control_assert(imx6_pcie->pciephy_reset); - udelay(10); + reset_control_deassert(imx6_pcie->pciephy_reset); + reset_control_deassert(imx6_pcie->pciephy_perst); + + /* release pcie_phy_apb_reset and pcie_phy_init_resetn */ + val = readl(imx6_pcie->hsmix_base + IMX8MP_GPR_REG0); + val |= IMX8MP_GPR_REG0_PHY_APB_RST; + val |= IMX8MP_GPR_REG0_PHY_INIT_RST; + writel(val, imx6_pcie->hsmix_base + IMX8MP_GPR_REG0); + val = imx6_pcie_grp_offset(imx6_pcie); if (imx6_pcie->ext_osc) { /*TODO Configure the external OSC as REF clock */ regmap_update_bits(imx6_pcie->iomuxc_gpr, val, IMX8MP_GPR_PCIE_REF_SEL_MASK, + IMX8MP_GPR_PCIE_REF_SEL_MASK); + regmap_update_bits(imx6_pcie->iomuxc_gpr, val, + IMX8MP_GPR_PCIE_AUX_EN, + IMX8MP_GPR_PCIE_AUX_EN); + regmap_update_bits(imx6_pcie->iomuxc_gpr, val, + IMX8MP_GPR_PCIE_SSC_EN, 0); + regmap_update_bits(imx6_pcie->iomuxc_gpr, val, + IMX8MP_GPR_PCIE_PWR_OFF, 0); + regmap_update_bits(imx6_pcie->iomuxc_gpr, val, + IMX8MP_GPR_PCIE_CMN_RSTN, 0); + regmap_update_bits(imx6_pcie->iomuxc_gpr, val, + IMX8MP_GPR_PCIE_REF_SEL_MASK, IMX8MP_GPR_PCIE_REF_EXT_OSC); } else { /* Configure the internal PLL as REF clock */ regmap_update_bits(imx6_pcie->iomuxc_gpr, val, IMX8MP_GPR_PCIE_REF_SEL_MASK, - IMX8MP_GPR_PCIE_REF_PLL); + IMX8MP_GPR_PCIE_REF_PLL_SYS); + regmap_update_bits(imx6_pcie->iomuxc_gpr, val, + IMX8MP_GPR_PCIE_AUX_EN, + IMX8MP_GPR_PCIE_AUX_EN); + regmap_update_bits(imx6_pcie->iomuxc_gpr, val, + IMX8MP_GPR_PCIE_SSC_EN, 0); + regmap_update_bits(imx6_pcie->iomuxc_gpr, val, + IMX8MP_GPR_PCIE_PWR_OFF, 0); + regmap_update_bits(imx6_pcie->iomuxc_gpr, val, + IMX8MP_GPR_PCIE_CMN_RSTN, 0); } - udelay(100); - - /* release pcie_phy_apb_reset and pcie_phy_init_resetn */ - val = readl(imx6_pcie->hsmix_base + IMX8MP_GPR_REG0); - val |= IMX8MP_GPR_REG0_PHY_APB_RST; - val |= IMX8MP_GPR_REG0_PHY_INIT_RST; - writel(val, imx6_pcie->hsmix_base + IMX8MP_GPR_REG0); - udelay(1); - - /* turn off pcie ltssm */ - imx6_pcie_ltssm_disable(dev); + phy_calibrate(imx6_pcie->phy); /* * GPR_PCIE_PHY_CTRL_BUS[3:0] * 0:i_ssc_en 1:i_power_off @@ -1309,15 +1343,19 @@ static int imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) */ val = imx6_pcie_grp_offset(imx6_pcie); regmap_update_bits(imx6_pcie->iomuxc_gpr, val, - BIT(18), - BIT(18)); - udelay(200); - - reset_control_deassert(imx6_pcie->pciephy_reset); - udelay(10); + IMX8MP_GPR_PCIE_CMN_RSTN, + IMX8MP_GPR_PCIE_CMN_RSTN); if(imx8_pcie_wait_for_phy_pll_lock(imx6_pcie) != 0) goto err_pll; + + if (imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_SUPPORTS_L1SS) + /* + * Configure the CLK_REQ# high, let the L1SS + * automatically controlled by HW later. + */ + reset_control_deassert(imx6_pcie->clkreq_reset); + imx6_pcie_set_l1_latency(imx6_pcie); break; case IMX7D: reset_control_deassert(imx6_pcie->pciephy_reset); @@ -1606,14 +1644,12 @@ static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie) IMX8MQ_GPR_PCIE_REF_USE_PAD); break; case IMX8MP: + phy_power_on(imx6_pcie->phy); dev_info(imx6_pcie->pci->dev, "%s REF_CLK is used!.\n", imx6_pcie->ext_osc ? "EXT" : "PLL"); imx6_pcie_clk_enable(imx6_pcie); - /* - * Make sure that the bypass_pll of gpr_reg2 is set to - * 1'b1. Set P=12,M=800,S=4 and must set ICP=2'b01. - */ + /* Set P=12,M=800,S=4 and must set ICP=2'b01. */ val = readl(imx6_pcie->hsmix_base + IMX8MP_GPR_REG2); val &= ~IMX8MP_GPR_REG2_P_PLL_MASK; val |= IMX8MP_GPR_REG2_P_PLL; @@ -1621,29 +1657,17 @@ static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie) val |= IMX8MP_GPR_REG2_M_PLL; val &= ~IMX8MP_GPR_REG2_S_PLL_MASK; val |= IMX8MP_GPR_REG2_S_PLL; - val |= IMX8MP_GPR_REG2_BYPASS_PLL; writel(val, imx6_pcie->hsmix_base + IMX8MP_GPR_REG2); /* wait greater than 1/F_FREF =1/2MHZ=0.5us */ udelay(1); - /* release reset */ + val = readl(imx6_pcie->hsmix_base + IMX8MP_GPR_REG3); val |= IMX8MP_GPR_REG3_PLL_RST; writel(val, imx6_pcie->hsmix_base + IMX8MP_GPR_REG3); + udelay(10); - /* - * Make sure that the pll_ext_bypass of gpr_reg3 is set - * to 1'b0. set 1 to pll_cke of GPR_REG3 - */ - val = readl(imx6_pcie->hsmix_base + IMX8MP_GPR_REG2); - val &= ~IMX8MP_GPR_REG2_BYPASS_PLL; - writel(val, imx6_pcie->hsmix_base + IMX8MP_GPR_REG2); - - /* - * Make sure that the pll_ext_bypass of gpr_reg3 is set - * to 1'b0. set 1 to pll_cke of GPR_REG3 - */ + /* Set 1 to pll_cke of GPR_REG3 */ val = readl(imx6_pcie->hsmix_base + IMX8MP_GPR_REG3); - val &= ~IMX8MP_GPR_REG3_PLL_EXT_BYPASS; val |= IMX8MP_GPR_REG3_PLL_CKE; writel(val, imx6_pcie->hsmix_base + IMX8MP_GPR_REG3); @@ -1655,10 +1679,12 @@ static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie) break; udelay(10); } - if (i >= 100) { + if (i >= 100) dev_err(imx6_pcie->pci->dev, "PCIe PHY PLL clock is not locked.\n"); - } + else + dev_info(imx6_pcie->pci->dev, + "PCIe PHY PLL clock is locked.\n"); /* pcie_clock_module_en */ val = readl(imx6_pcie->hsmix_base + IMX8MP_GPR_REG0); @@ -1822,12 +1848,21 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie) /* Start LTSSM. */ imx6_pcie_ltssm_enable(dev); - ret = dw_pcie_wait_for_link(pci); if (ret) goto err_reset_phy; if (imx6_pcie->link_gen >= 2) { + /* Fill up target link speed before speed change. */ + tmp = dw_pcie_readl_dbi(pci, PCIE_RC_LC2SR); + tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK; + tmp |= imx6_pcie->link_gen; + dw_pcie_writel_dbi(pci, PCIE_RC_LC2SR, tmp); + + tmp = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); + tmp &= ~PORT_LOGIC_SPEED_CHANGE; + dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, tmp); + /* Allow Gen2 mode after the link is up. */ tmp = dw_pcie_readl_dbi(pci, PCIE_RC_LCR); tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK; @@ -2396,6 +2431,7 @@ static int imx6_pcie_resume_noirq(struct device *dev) */ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, IMX6Q_GPR1_PCIE_TEST_PD, 0); + msleep(10); } else { imx6_pcie_assert_core_reset(imx6_pcie); imx6_pcie_init_phy(imx6_pcie); @@ -3110,7 +3146,8 @@ static const struct imx6_pcie_drvdata drvdata[] = { }, [IMX8MP] = { .variant = IMX8MP, - .flags = IMX6_PCIE_FLAG_SUPPORTS_SUSPEND, + .flags = IMX6_PCIE_FLAG_SUPPORTS_SUSPEND | + IMX6_PCIE_FLAG_SUPPORTS_L1SS, }, }; |