Re: [PATCH v5 6/7] phy: freescale: imx8m-pcie: Add iMX8MP PCIe PHY support
From: Lucas Stach <l.stach@pengutronix.de>
Date: 2022-08-31 08:34:38
Also in:
linux-arm-kernel, linux-pci, linux-phy, lkml
Am Mittwoch, dem 31.08.2022 um 06:16 +0000 schrieb Hongxing Zhu:
quoted
-----Original Message----- From: Lucas Stach <l.stach@pengutronix.de> Sent: 2022年8月30日 21:07 To: Hongxing Zhu <hongxing.zhu@nxp.com>; p.zabel@pengutronix.de; bhelgaas@google.com; lorenzo.pieralisi@arm.com; robh@kernel.org; shawnguo@kernel.org; vkoul@kernel.org; alexander.stein@ew.tq-group.com; marex@denx.de; richard.leitner@linux.dev Cc: linux-phy@lists.infradead.org; devicetree@vger.kernel.org; linux-pci@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org; kernel@pengutronix.de; dl-linux-imx [off-list ref] Subject: Re: [PATCH v5 6/7] phy: freescale: imx8m-pcie: Add iMX8MP PCIe PHY support Am Dienstag, dem 30.08.2022 um 15:46 +0800 schrieb Richard Zhu:quoted
Add i.MX8MP PCIe PHY support. Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com> Signed-off-by: Lucas Stach <l.stach@pengutronix.de> Tested-by: Marek Vasut <marex@denx.de> Tested-by: Richard Leitner <richard.leitner@skidata.com> Tested-by: Alexander Stein <redacted> --- drivers/phy/freescale/phy-fsl-imx8m-pcie.c | 137 +++++++++++++-------- 1 file changed, 89 insertions(+), 48 deletions(-)diff --git a/drivers/phy/freescale/phy-fsl-imx8m-pcie.cb/drivers/phy/freescale/phy-fsl-imx8m-pcie.c index ad7d2edfc414..c76e3a1a5f51 100644--- a/drivers/phy/freescale/phy-fsl-imx8m-pcie.c +++ b/drivers/phy/freescale/phy-fsl-imx8m-pcie.c@@ -11,6 +11,9 @@#include <linux/mfd/syscon.h> #include <linux/mfd/syscon/imx7-iomuxc-gpr.h> #include <linux/module.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_device.h> #include <linux/phy/phy.h> #include <linux/platform_device.h> #include <linux/regmap.h>@@ -31,12 +34,10 @@#define IMX8MM_PCIE_PHY_CMN_REG065 0x194 #define ANA_AUX_RX_TERM (BIT(7) | BIT(4)) #define ANA_AUX_TX_LVL GENMASK(3, 0) -#define IMX8MM_PCIE_PHY_CMN_REG75 0x1D4 -#define PCIE_PHY_CMN_REG75_PLL_DONE 0x3 +#define IMX8MM_PCIE_PHY_CMN_REG075 0x1D4 +#define ANA_PLL_DONE 0x3 #define PCIE_PHY_TRSV_REG5 0x414 -#define PCIE_PHY_TRSV_REG5_GEN1_DEEMP 0x2D #define PCIE_PHY_TRSV_REG6 0x418 -#define PCIE_PHY_TRSV_REG6_GEN2_DEEMP 0xF #define IMX8MM_GPR_PCIE_REF_CLK_SEL GENMASK(25, 24) #define IMX8MM_GPR_PCIE_REF_CLK_PLLFIELD_PREP(IMX8MM_GPR_PCIE_REF_CLK_SEL, 0x3)quoted
@@ -47,16 +48,23 @@#define IMX8MM_GPR_PCIE_SSC_EN BIT(16) #define IMX8MM_GPR_PCIE_AUX_EN_OVERRIDE BIT(9) +enum imx8_pcie_phy_type { + IMX8MM, + IMX8MP, +}; + struct imx8_pcie_phy { void __iomem *base; struct clk *clk; struct phy *phy; struct regmap *iomuxc_gpr; struct reset_control *reset; + struct reset_control *perst; u32 refclk_pad_mode; u32 tx_deemph_gen1; u32 tx_deemph_gen2; bool clkreq_unused; + enum imx8_pcie_phy_type variant; }; static int imx8_pcie_phy_init(struct phy *phy) @@ -68,31 +76,20 @@ static int imx8_pcie_phy_init(struct phy *phy) reset_control_assert(imx8_phy->reset); pad_mode = imx8_phy->refclk_pad_mode; - /* Set AUX_EN_OVERRIDE 1'b0, when the CLKREQ# isn't hooked */ - regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14, - IMX8MM_GPR_PCIE_AUX_EN_OVERRIDE, - imx8_phy->clkreq_unused ? - 0 : IMX8MM_GPR_PCIE_AUX_EN_OVERRIDE); - regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14, - IMX8MM_GPR_PCIE_AUX_EN, - IMX8MM_GPR_PCIE_AUX_EN); - regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14, - IMX8MM_GPR_PCIE_POWER_OFF, 0); - regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14, - IMX8MM_GPR_PCIE_SSC_EN, 0); - - regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14, - IMX8MM_GPR_PCIE_REF_CLK_SEL, - pad_mode == IMX8_PCIE_REFCLK_PAD_INPUT ? - IMX8MM_GPR_PCIE_REF_CLK_EXT : - IMX8MM_GPR_PCIE_REF_CLK_PLL); - usleep_range(100, 200); - - /* Do the PHY common block reset */ - regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14, - IMX8MM_GPR_PCIE_CMN_RST, - IMX8MM_GPR_PCIE_CMN_RST); - usleep_range(200, 500); + switch (imx8_phy->variant) { + case IMX8MM: + /* Tune PHY de-emphasis setting to pass PCIe compliance. */ + if (imx8_phy->tx_deemph_gen1) + writel(imx8_phy->tx_deemph_gen1, + imx8_phy->base + PCIE_PHY_TRSV_REG5); + if (imx8_phy->tx_deemph_gen2) + writel(imx8_phy->tx_deemph_gen2, + imx8_phy->base + PCIE_PHY_TRSV_REG6); + break; + case IMX8MP: + reset_control_assert(imx8_phy->perst); + break; + } if (pad_mode == IMX8_PCIE_REFCLK_PAD_INPUT || pad_mode == IMX8_PCIE_REFCLK_PAD_UNUSED) { @@ - 120,20+117,44 @@quoted
static int imx8_pcie_phy_init(struct phy *phy) imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG065); } - /* Tune PHY de-emphasis setting to pass PCIe compliance. */ - if (imx8_phy->tx_deemph_gen1) - writel(imx8_phy->tx_deemph_gen1, - imx8_phy->base + PCIE_PHY_TRSV_REG5); - if (imx8_phy->tx_deemph_gen2) - writel(imx8_phy->tx_deemph_gen2, - imx8_phy->base + PCIE_PHY_TRSV_REG6); + /* Set AUX_EN_OVERRIDE 1'b0, when the CLKREQ# isn't hooked */ + regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14, + IMX8MM_GPR_PCIE_AUX_EN_OVERRIDE, + imx8_phy->clkreq_unused ? + 0 : IMX8MM_GPR_PCIE_AUX_EN_OVERRIDE); + regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14, + IMX8MM_GPR_PCIE_AUX_EN, + IMX8MM_GPR_PCIE_AUX_EN); + regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14, + IMX8MM_GPR_PCIE_POWER_OFF, 0); + regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14, + IMX8MM_GPR_PCIE_SSC_EN, 0); + + regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14, + IMX8MM_GPR_PCIE_REF_CLK_SEL, + pad_mode == IMX8_PCIE_REFCLK_PAD_INPUT ? + IMX8MM_GPR_PCIE_REF_CLK_EXT : + IMX8MM_GPR_PCIE_REF_CLK_PLL); + usleep_range(100, 200); + + /* Do the PHY common block reset */ + regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14, + IMX8MM_GPR_PCIE_CMN_RST, + IMX8MM_GPR_PCIE_CMN_RST); - reset_control_deassert(imx8_phy->reset); + switch (imx8_phy->variant) { + case IMX8MP: + reset_control_deassert(imx8_phy->perst); + fallthrough; + case IMX8MM: + reset_control_deassert(imx8_phy->reset); + usleep_range(200, 500); + break; + } /* Polling to check the phy is ready or not. */ - ret = readl_poll_timeout(imx8_phy->base +IMX8MM_PCIE_PHY_CMN_REG75,quoted
- val, val == PCIE_PHY_CMN_REG75_PLL_DONE, - 10, 20000); + ret = readl_poll_timeout(imx8_phy->base +IMX8MM_PCIE_PHY_CMN_REG075,quoted
+ val, val == ANA_PLL_DONE, 10, 20000); return ret; }@@ -160,6 +181,13 @@ static const struct phy_opsimx8_pcie_phy_ops = { .owner = THIS_MODULE, }; +static const struct of_device_id imx8_pcie_phy_of_match[] = { + {.compatible = "fsl,imx8mm-pcie-phy", .data = (void *)IMX8MM}, + {.compatible = "fsl,imx8mp-pcie-phy", .data = (void *)IMX8MP}, + { }, +}; +MODULE_DEVICE_TABLE(of, imx8_pcie_phy_of_match); + static int imx8_pcie_phy_probe(struct platform_device *pdev) { struct phy_provider *phy_provider;@@ -172,6 +200,9 @@ static int imx8_pcie_phy_probe(structplatform_device *pdev)quoted
if (!imx8_phy) return -ENOMEM; + imx8_phy->variant = + (enum imx8_pcie_phy_type)of_device_get_match_data(dev); + /* get PHY refclk pad mode */ of_property_read_u32(np, "fsl,refclk-pad-mode", &imx8_phy->refclk_pad_mode);@@ -196,8 +227,16 @@ static int imx8_pcie_phy_probe(structplatform_device *pdev)quoted
} /* Grab GPR config register range */ - imx8_phy->iomuxc_gpr = - syscon_regmap_lookup_by_compatible("fsl,imx6q- iomuxc-gpr"); + switch (imx8_phy->variant) { + case IMX8MM: + imx8_phy->iomuxc_gpr = +syscon_regmap_lookup_by_compatible("fsl,imx8mm-iomuxc-gpr");quoted
+ break; + case IMX8MP: + imx8_phy->iomuxc_gpr = +syscon_regmap_lookup_by_compatible("fsl,imx8mp-iomuxc-gpr");quoted
+ break; + }Oh, I had a real phandle in DT in mind for this, but I see how this would be hard to introduce in a backward compatible manner for the 8MM. At least this way it is fully contained in the driver and doesn't leak into DT compatibles. Maybe we could make this a little nicer by just having an const array of iomux syscon compatibles indexed by imx8_phy->variant, to avoid the switch and the resulting code (almost-)duplication.Hi Lucas: Thanks for your comments. Do you mean a drvdata struct indexed by variant, and contains the const array of iomux syscon compatible like below? +static const struct imx8_pcie_phy_drvdata drvdata[] = { + [IMX8MM] = { + .variant = IMX8MM, + .gpr = "fsl,imx8mm-iomuxc-gpr", + }, + + [IMX8MP] = { + .variant = IMX8MP, + .gpr = "fsl,imx8mp-iomuxc-gpr", + }, +}; + Then, we can get the drvdata, and find the according gpr syscon regmap below. + imx8_phy->drvdata = of_device_get_match_data(dev); ... + imx8_phy->iomuxc_gpr = + syscon_regmap_lookup_by_compatible(imx8_phy-quoted
drvdata->gpr);
I had a simple array of GPR compatible strings in mind, so we could lookup the compatible from the variant. But I think putting it directly in drvdata, like done in your suggestion above, looks even better.
If yes, I would do the changes, and issue the v6 later.
Yep, please change as suggested above. Same comment applies to the next patch "PCI: imx6: Add iMX8MP PCIe support". Also in both patches the dot between i and MX in i.MX8MP is missing in the patch description subject line. Regards, Lucas