From 3571ccaee0087afbcbb48e5747a410e0f225ebf7 Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Wed, 27 May 2020 13:31:30 +0800 Subject: MLK-24171-3 phy: pcie: imx8mp: verify the pll sys ref clock source Verify the PCIe PLL_SYS reference clock source on EVK board. The external OSC clock is used as PCIe REF clock source in default. - sequence should be the following one. phy configuration--> CMN_RSTN--> wait for pll lock - add the calibrate callback to fit the correct init sequence of phy Signed-off-by: Richard Zhu Reviewed-by: Fugang Duan (cherry picked from commit 9afaf7a465858970aee8858fb52067f2ef152c7f) --- drivers/phy/freescale/phy-fsl-imx8-pcie.c | 110 +++++++++++++++++++++++++++--- 1 file changed, 102 insertions(+), 8 deletions(-) diff --git a/drivers/phy/freescale/phy-fsl-imx8-pcie.c b/drivers/phy/freescale/phy-fsl-imx8-pcie.c index 8b96e5f5004a..11f2bff151dd 100644 --- a/drivers/phy/freescale/phy-fsl-imx8-pcie.c +++ b/drivers/phy/freescale/phy-fsl-imx8-pcie.c @@ -11,11 +11,46 @@ #include #define PHY_PLL_LOCK_WAIT_MAX_RETRIES 2000 +#define IMX8MP_PCIE_PHY_FLAG_EXT_OSC BIT(0) + +#define IMX8MP_PCIE_PHY_CMN_REG020 0x80 +#define PLL_ANA_LPF_R_SEL_FINE_0_4 0x04 +#define IMX8MP_PCIE_PHY_CMN_REG036 0xD8 +#define PLL_PMS_SDIV_8_4 0x32 +#define IMX8MP_PCIE_PHY_CMN_REG061 0x184 +#define ANA_PLL_CLK_OUT_TO_EXT_IO_EN BIT(0) +#define IMX8MP_PCIE_PHY_CMN_REG062 0x188 +#define ANA_PLL_CLK_OUT_TO_EXT_IO_SEL BIT(3) +#define IMX8MP_PCIE_PHY_CMN_REG063 0x18C +#define AUX_PLL_REFCLK_SEL_SYS_PLL GENMASK(7, 6) +#define IMX8MP_PCIE_PHY_CMN_REG064 0x190 +#define ANA_AUX_RX_TX_SEL_TX BIT(7) +#define ANA_AUX_RX_TERM_GND_EN BIT(3) +#define ANA_AUX_TX_TERM BIT(2) +#define IMX8MP_PCIE_PHY_CMN_REG065 0x194 +#define ANA_AUX_RX_TERM (BIT(7) | BIT(4)) +#define ANA_AUX_TX_LVL GENMASK(3, 0) +#define IMX8MP_PCIE_PHY_CMN_REG076 0x200 +#define LANE_RESET_MUX_SEL 0x00 +#define IMX8MP_PCIE_PHY_CMN_REG078 0x208 +#define LANE_TX_DATA_CLK_MUX_SEL 0x00 + +#define IMX8MP_PCIE_PHY_TRSV_REG001 0x404 +#define LN0_OVRD_TX_DRV_LVL 0x2D +#define IMX8MP_PCIE_PHY_TRSV_REG020 0x480 +#define LN0_RX_CDR_REFDIV_1_2 1 +#define IMX8MP_PCIE_PHY_TRSV_REG022 0x488 +#define LN0_RX_CDR_REFDIV_1_1 0 +#define IMX8MP_PCIE_PHY_TRSV_REG0BB 0x6EC +#define LN0_TXD_DESKEW_BYPASS BIT(2) +#define IMX8MP_PCIE_PHY_TRSV_REG0CF 0x73C +#define LN0_MISC_TX_CLK_SRC BIT(2) struct imx8_pcie_phy { struct phy *phy; struct clk *clk; void __iomem *base; + u32 flags; }; static int imx8_pcie_phy_init(struct phy *phy) @@ -42,6 +77,7 @@ static int imx8_pcie_phy_init(struct phy *phy) * operation for GEN3 cannot be achieved with the SW workaround * since the buffer structure cannot be bypassed in GEN3 mode. */ + /* wait for pipe0_clk locked by checking status from PCS. */ for (retries = 0; retries < PHY_PLL_LOCK_WAIT_MAX_RETRIES; retries++) { @@ -51,15 +87,58 @@ static int imx8_pcie_phy_init(struct phy *phy) udelay(10); } - /* setup_deskew_fifo_bypass to workaround ERR050442 */ - writel(0x32, imx8_phy->base + 0xd8); - writel(0x1, imx8_phy->base + 0x480); - writel(0x0, imx8_phy->base + 0x488); - writel(0x4, imx8_phy->base + 0x73c); - writel(0x4, imx8_phy->base + 0x6ec); + if (retries >= PHY_PLL_LOCK_WAIT_MAX_RETRIES) { + pr_info("pcie phy pipe clk is not ready\n"); + return -ETIMEDOUT; + } + + return 0; +} - /* Configure TX drive level */ - writel(0x2d, imx8_phy->base + 0x404); +static int imx8_pcie_phy_cal(struct phy *phy) +{ + u32 value; + struct imx8_pcie_phy *imx8_phy = phy_get_drvdata(phy); + + /* export clock to ep when internal clock is used as PHY REF clock */ + if ((imx8_phy->flags & IMX8MP_PCIE_PHY_FLAG_EXT_OSC) == 0) { + writel(ANA_PLL_CLK_OUT_TO_EXT_IO_EN, + imx8_phy->base + IMX8MP_PCIE_PHY_CMN_REG061); + writel(ANA_PLL_CLK_OUT_TO_EXT_IO_SEL, + imx8_phy->base + IMX8MP_PCIE_PHY_CMN_REG062); + writel(AUX_PLL_REFCLK_SEL_SYS_PLL, + imx8_phy->base + IMX8MP_PCIE_PHY_CMN_REG063); + value = ANA_AUX_RX_TX_SEL_TX | ANA_AUX_TX_TERM; + writel(value | ANA_AUX_RX_TERM_GND_EN, + imx8_phy->base + IMX8MP_PCIE_PHY_CMN_REG064); + writel(ANA_AUX_RX_TERM | ANA_AUX_TX_LVL, + imx8_phy->base + IMX8MP_PCIE_PHY_CMN_REG065); + } + + /* Configure TX drive level */ + writel(LN0_OVRD_TX_DRV_LVL, + imx8_phy->base + IMX8MP_PCIE_PHY_TRSV_REG001); + + writel(PLL_ANA_LPF_R_SEL_FINE_0_4, + imx8_phy->base + IMX8MP_PCIE_PHY_CMN_REG020); + writel(LANE_RESET_MUX_SEL, + imx8_phy->base + IMX8MP_PCIE_PHY_CMN_REG076); + writel(LANE_TX_DATA_CLK_MUX_SEL, + imx8_phy->base + IMX8MP_PCIE_PHY_CMN_REG078); + + /* setup_deskew_fifo_bypass to workaround ERR050442 */ + udelay(1); + writel(PLL_PMS_SDIV_8_4, + imx8_phy->base + IMX8MP_PCIE_PHY_CMN_REG036); + writel(LN0_RX_CDR_REFDIV_1_2, + imx8_phy->base + IMX8MP_PCIE_PHY_TRSV_REG020); + writel(LN0_RX_CDR_REFDIV_1_1, + imx8_phy->base + IMX8MP_PCIE_PHY_TRSV_REG022); + writel(LN0_MISC_TX_CLK_SRC, + imx8_phy->base + IMX8MP_PCIE_PHY_TRSV_REG0CF); + writel(LN0_TXD_DESKEW_BYPASS, + imx8_phy->base + IMX8MP_PCIE_PHY_TRSV_REG0BB); + udelay(1); return 0; } @@ -82,6 +161,7 @@ static int imx8_pcie_phy_power_off(struct phy *phy) static struct phy_ops imx8_pcie_phy_ops = { .init = imx8_pcie_phy_init, + .calibrate = imx8_pcie_phy_cal, .power_on = imx8_pcie_phy_power_on, .power_off = imx8_pcie_phy_power_off, .owner = THIS_MODULE, @@ -89,8 +169,10 @@ static struct phy_ops imx8_pcie_phy_ops = { static int imx8_pcie_phy_probe(struct platform_device *pdev) { + u32 val = 0; struct phy_provider *phy_provider; struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; struct imx8_pcie_phy *imx8_phy; struct resource *res; @@ -98,6 +180,18 @@ static int imx8_pcie_phy_probe(struct platform_device *pdev) if (!imx8_phy) return -ENOMEM; + imx8_phy->flags &= ~IMX8MP_PCIE_PHY_FLAG_EXT_OSC; + if (of_property_read_u32(np, "clk_mode", &val) < 0) + /* + * Not specify clk_mod, use the external OSC as default + * CLK mode. + */ + imx8_phy->flags |= IMX8MP_PCIE_PHY_FLAG_EXT_OSC; + if (val == 0) + imx8_phy->flags &= ~IMX8MP_PCIE_PHY_FLAG_EXT_OSC; + else + dev_info(dev, "invalid clk mode %d.\n", val); + imx8_phy->clk = devm_clk_get(dev, "phy"); if (IS_ERR(imx8_phy->clk)) { dev_err(dev, "failed to get imx pcie phy clock\n"); -- cgit v1.2.3