[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250926073921.1000866-5-sh86.bae@samsung.com>
Date: Fri, 26 Sep 2025 16:39:19 +0900
From: Sanghoon Bae <sh86.bae@...sung.com>
To: robh@...nel.org, krzk@...nel.org, conor+dt@...nel.org, vkoul@...nel.org,
alim.akhtar@...sung.com, kishon@...nel.org, m.szyprowski@...sung.com,
jh80.chung@...sung.com, shradha.t@...sung.com
Cc: krzk+dt@...nel.org, linux-kernel@...r.kernel.org,
devicetree@...r.kernel.org, linux-samsung-soc@...r.kernel.org,
linux-phy@...ts.infradead.org, linux-arm-kernel@...ts.infradead.org,
sh86.bae@...sung.com
Subject: [PATCH 4/4] phy: exynos: Add PCIe PHY support for ExynosAutov920
SoC
Add PCIe PHY support for ExynosAutov920 SoC
Signed-off-by: Sanghoon Bae <sh86.bae@...sung.com>
---
drivers/phy/samsung/phy-exynos-pcie.c | 231 ++++++++++++++++++++++++++
1 file changed, 231 insertions(+)
diff --git a/drivers/phy/samsung/phy-exynos-pcie.c b/drivers/phy/samsung/phy-exynos-pcie.c
index 5a55a22f9661..5b9d65f8f6c7 100644
--- a/drivers/phy/samsung/phy-exynos-pcie.c
+++ b/drivers/phy/samsung/phy-exynos-pcie.c
@@ -129,14 +129,87 @@
#define FSD_PCIE_SYSREG_PHY_1_CMN_RSTN BIT(1)
#define FSD_PCIE_SYSREG_PHY_1_INIT_RSTN BIT(3)
+/* Exynosautov920 register offsets and bits */
+/* EA920: PHY registers */
+#define EA920_PCIE_PHY0_COMMON_CTRL 0x1000
+#define EA920_PCIE_PHY_RTUNE_REQ 0x10000001
+#define EA920_PCIE_PHY0_GEN_CTRL_1 0x1010
+#define EA920_PCIE_PHY0_REFA_CLK_SEL_MASK GENMASK(17, 16)
+#define EA920_PCIE_PHY0_REFB_CLK_SEL_MASK GENMASK(19, 18)
+#define EA920_PCIE_PHY0_PHY0_SRAM_BYPASS BIT(10)
+#define EA920_PCIE_PHY0_PHY0_SRAM_EXT_LD_DONE BIT(11)
+#define EA920_PCIE_PHY0_REFA_B_ALT1 0x061a0060
+#define EA920_PCIE_PHY0_REFA_B_ALT0 0x06100060
+#define EA920_PCIE_PHY0_REFA_B_PAD 0x06150060
+#define EA920_PCIE_PHY0_SRAM_INIT_DONE 31
+#define EA920_PCIE_PHY_EXT_TX_ROPLL_POSTDIV_CTRL 0x11a8
+#define EA920_PCIE_PHY_ROPLL_POSTDIV_VAL 0x1249
+#define EA920_PCIE_PHY_EXT_TX_OVRD_EN_CTRL 0x11c4
+#define EA920_PCIE_PHY_ROPLL_POSTDIV_OVRD_EN_VAL (0xf << 0)
+#define EA920_PCIE_PIPE_LANEX_LANEPLL_BYPASS 0x1384
+#define EA920_PCIE_PIPE_BYPASS_MODE_CTRL_VAL1 0x0
+#define EA920_PCIE_PIPE_BYPASS_MODE_CTRL_VAL2 0x0
+/* EA920: SOC CTRL registers */
+#define EA920_PCIE_REFCLK_CTRL_SOC_OPTION_0 0xa200
+#define EA920_PCIE_REFCLK_OPTION0_RC 0x103f5
+#define EA920_PCIE_REFCLK_CTRL_SOC_OPTION_1 0xa204
+#define EA920_PCIE_REFCLK_OPTION1_RC 0x30c00
+/* EA920: PMU registers */
+#define EA920_PCIE_PHY_4L_CONFIGURATION 0x700
+#define EA920_PCIE_PHY_2L_CONFIGURATION 0x704
+#define EA920_PCIE_PHY_CFG_EN_PHY (0x1 << 0)
+/* EA920: GEN SYS registers */
+#define EA920_GENERAL_SS_RST_CTRL_1 0x48
+#define EA920_GENERAL_RST_PE0_SOFT_WARM_PHY_RESET GENMASK(2, 1)
+#define EA920_GENERAL_RST_PE1_SOFT_COLD_RESET (0x1 << 8)
+#define EA920_GENERAL_RST_PE1_SOFT_WARM_PHY_RESET (0x3 << 9)
+#define EA920_GENERAL_RST_PE0_SOFT_WARM_RESET (0x1 << 1)
+#define EA920_GENERAL_RST_PE1_SOFT_WARM_RESET (0x1 << 9)
+#define EA920_GENERAL_RST_PE0_1_PHY_EN 0x808
+#define EA920_PHY_TIMEOUT 2000
+/* EA920: SYSREG registers */
+#define EA920_HSI0_PCIE_GEN5_PHY_PWRDWN_4L 0x670
+#define EA920_HSI0_PCIE_GEN5_PHY_PWRDWN_2L 0x4
+#define EA920_HSI0_PCIE_PHY_TEST_PWRDWN_MSK BIT(0)
+#define EA920_HSI0_PCIE_PHY_TEST_PWRDUP 0x0
+#define EA920_HSI0_PCIE_PHY_TEST_PWRDWN 0x1
+#define EA920_HSI0_PCIE_GEN5_4LA_PHY_CTRL 0x828
+#define EA920_HSI0_PCIE_GEN5_2LA_PHY_CTRL 0x868
+#define EA920_HSI0_PCIE_IP_CTRL_DEV_TYPE_MSK GENMASK(27, 24)
+#define EA920_HSI0_PCIE_IP_CTRL_DEV_TYPE_RC_A 0x4
+#define EA920_HSI0_PLL_REG0 0x600
+#define EA920_HSI0_PLL_FOUTEN_MSK BIT(8)
+#define EA920_HSI0_PLL_FOUTEN 0x1
+#define EA920_HSI0_PLL_REG1 0x604
+#define EA920_HSI0_PLL_FOUTPOSTDIVEN_MSK BIT(0)
+#define EA920_HSI0_PLL_FOUTPOSTDIVEN 0x1
+#define EA920_HSI0_PLL_REG2 0x608
+#define EA920_HSI0_PLL_PLLEN_MSK BIT(24)
+#define EA920_HSI0_PLL_PLLEN 0x1
+#define EA920_HSI0_CLKBUF0_REG0 0x620
+#define EA920_HSI0_CLKBUF1_REG0 0x630
+#define EA920_HSI0_CLKBUF2_REG0 0x640
+#define EA920_HSI0_CLKBUF3_REG0 0x650
+#define EA920_HSI0_CLKBUF_IMP_CTRL_MSK BIT(0)
+#define EA920_HSI0_CLKBUF_IMP_CTRL 0x1
+
/* For Exynos pcie phy */
struct exynos_pcie_phy {
void __iomem *base;
void __iomem *pcs_base;
struct regmap *pmureg;
struct regmap *fsysreg;
+ int num_lanes;
};
+static u32 exynos_pcie_phy_readl(void __iomem *base, u32 offset)
+{
+ u32 data = 0;
+
+ data = readl(base + offset);
+ return data;
+}
+
static void exynos_pcie_phy_writel(void __iomem *base, u32 val, u32 offset)
{
writel(val, base + offset);
@@ -398,6 +471,152 @@ static int fsd_pcie_phy1_init(struct phy *phy)
return 0;
}
+static int exynosautov920_pcie_phy_init(struct phy *phy)
+{
+ struct exynos_pcie_phy *ep = phy_get_drvdata(phy);
+ u32 val;
+ int timeout;
+
+ /* PHY on */
+ if (ep->num_lanes == 4) {
+ regmap_update_bits(ep->pmureg,
+ EA920_PCIE_PHY_4L_CONFIGURATION,
+ BIT(0), EA920_PCIE_PHY_CFG_EN_PHY);
+ regmap_update_bits(ep->fsysreg,
+ EA920_HSI0_PCIE_GEN5_PHY_PWRDWN_4L,
+ EA920_HSI0_PCIE_PHY_TEST_PWRDWN_MSK,
+ EA920_HSI0_PCIE_PHY_TEST_PWRDUP);
+
+ /* SYSREG set to RC */
+ regmap_update_bits(ep->fsysreg,
+ EA920_HSI0_PCIE_GEN5_4LA_PHY_CTRL,
+ EA920_HSI0_PCIE_IP_CTRL_DEV_TYPE_MSK,
+ EA920_HSI0_PCIE_IP_CTRL_DEV_TYPE_RC_A);
+ } else if (ep->num_lanes == 2) {
+ /* In 2L phy, 4L phy pmu should isolation off first */
+ regmap_update_bits(ep->pmureg,
+ EA920_PCIE_PHY_4L_CONFIGURATION,
+ BIT(0), EA920_PCIE_PHY_CFG_EN_PHY);
+ regmap_update_bits(ep->pmureg,
+ EA920_PCIE_PHY_2L_CONFIGURATION,
+ BIT(0), EA920_PCIE_PHY_CFG_EN_PHY);
+ regmap_update_bits(ep->fsysreg,
+ EA920_HSI0_PCIE_GEN5_PHY_PWRDWN_2L,
+ EA920_HSI0_PCIE_PHY_TEST_PWRDWN_MSK,
+ EA920_HSI0_PCIE_PHY_TEST_PWRDUP);
+ /* SYSREG set to RC */
+ regmap_update_bits(ep->fsysreg,
+ EA920_HSI0_PCIE_GEN5_2LA_PHY_CTRL,
+ EA920_HSI0_PCIE_IP_CTRL_DEV_TYPE_MSK,
+ EA920_HSI0_PCIE_IP_CTRL_DEV_TYPE_RC_A);
+ }
+
+ /* SOC control */
+ exynos_pcie_phy_writel(ep->pcs_base, EA920_PCIE_REFCLK_OPTION0_RC,
+ EA920_PCIE_REFCLK_CTRL_SOC_OPTION_0);
+ exynos_pcie_phy_writel(ep->pcs_base, EA920_PCIE_REFCLK_OPTION1_RC,
+ EA920_PCIE_REFCLK_CTRL_SOC_OPTION_1);
+
+ /* PLL setting */
+ regmap_update_bits(ep->fsysreg, EA920_HSI0_PLL_REG0,
+ EA920_HSI0_PLL_FOUTEN_MSK, EA920_HSI0_PLL_FOUTEN);
+ regmap_update_bits(ep->fsysreg, EA920_HSI0_PLL_REG1,
+ EA920_HSI0_PLL_FOUTPOSTDIVEN_MSK,
+ EA920_HSI0_PLL_FOUTPOSTDIVEN);
+ regmap_update_bits(ep->fsysreg, EA920_HSI0_PLL_REG2,
+ EA920_HSI0_PLL_PLLEN_MSK, EA920_HSI0_PLL_PLLEN);
+ regmap_update_bits(ep->fsysreg, EA920_HSI0_CLKBUF0_REG0,
+ EA920_HSI0_CLKBUF_IMP_CTRL_MSK,
+ EA920_HSI0_CLKBUF_IMP_CTRL);
+ regmap_update_bits(ep->fsysreg, EA920_HSI0_CLKBUF1_REG0,
+ EA920_HSI0_CLKBUF_IMP_CTRL_MSK,
+ EA920_HSI0_CLKBUF_IMP_CTRL);
+ regmap_update_bits(ep->fsysreg, EA920_HSI0_CLKBUF2_REG0,
+ EA920_HSI0_CLKBUF_IMP_CTRL_MSK,
+ EA920_HSI0_CLKBUF_IMP_CTRL);
+ regmap_update_bits(ep->fsysreg, EA920_HSI0_CLKBUF3_REG0,
+ EA920_HSI0_CLKBUF_IMP_CTRL_MSK,
+ EA920_HSI0_CLKBUF_IMP_CTRL);
+
+ /* REFCLK setting */
+ val = exynos_pcie_phy_readl(ep->base, EA920_PCIE_PHY0_GEN_CTRL_1);
+ exynos_pcie_phy_writel(ep->base, val &
+ ~EA920_PCIE_PHY0_REFA_CLK_SEL_MASK,
+ EA920_PCIE_PHY0_GEN_CTRL_1);
+ exynos_pcie_phy_writel(ep->base,
+ val & ~EA920_PCIE_PHY0_REFB_CLK_SEL_MASK,
+ EA920_PCIE_PHY0_GEN_CTRL_1);
+ /* wait for REF CLK source change */
+ usleep_range(100, 110);
+ exynos_pcie_phy_writel(ep->base, EA920_PCIE_PHY_RTUNE_REQ,
+ EA920_PCIE_PHY0_COMMON_CTRL);
+ exynos_pcie_phy_writel(ep->base, EA920_PCIE_PHY_ROPLL_POSTDIV_VAL,
+ EA920_PCIE_PHY_EXT_TX_ROPLL_POSTDIV_CTRL);
+ exynos_pcie_phy_writel(ep->base,
+ EA920_PCIE_PHY_ROPLL_POSTDIV_OVRD_EN_VAL,
+ EA920_PCIE_PHY_EXT_TX_OVRD_EN_CTRL);
+ exynos_pcie_phy_writel(ep->base, EA920_PCIE_PIPE_BYPASS_MODE_CTRL_VAL1,
+ EA920_PCIE_PIPE_LANEX_LANEPLL_BYPASS);
+ exynos_pcie_phy_writel(ep->base, EA920_PCIE_PIPE_BYPASS_MODE_CTRL_VAL2,
+ EA920_PCIE_PIPE_LANEX_LANEPLL_BYPASS);
+ exynos_pcie_phy_writel(ep->base, EA920_PCIE_PHY0_REFA_B_ALT0,
+ EA920_PCIE_PHY0_GEN_CTRL_1);
+
+ /* PHY warm reset */
+ val = exynos_pcie_phy_readl(ep->base, EA920_GENERAL_SS_RST_CTRL_1);
+ exynos_pcie_phy_writel(ep->base, val |
+ EA920_GENERAL_RST_PE0_SOFT_WARM_PHY_RESET,
+ EA920_GENERAL_SS_RST_CTRL_1);
+ usleep_range(10, 12);
+ exynos_pcie_phy_writel(ep->base, val &
+ ~EA920_GENERAL_RST_PE0_SOFT_WARM_PHY_RESET,
+ EA920_GENERAL_SS_RST_CTRL_1);
+
+ /* Set SRAM bypass */
+ val = exynos_pcie_phy_readl(ep->base, EA920_PCIE_PHY0_GEN_CTRL_1);
+ exynos_pcie_phy_writel(ep->base, val | EA920_PCIE_PHY0_PHY0_SRAM_BYPASS,
+ EA920_PCIE_PHY0_GEN_CTRL_1);
+
+ /* Wait SRAM init */
+ timeout = 0;
+ do {
+ udelay(1);
+ timeout++;
+ if (timeout >= EA920_PHY_TIMEOUT)
+ return -ETIME;
+ } while (!(exynos_pcie_phy_readl(ep->base,
+ EA920_PCIE_PHY0_GEN_CTRL_1) >>
+ EA920_PCIE_PHY0_SRAM_INIT_DONE));
+
+ timeout = 0;
+ val = exynos_pcie_phy_readl(ep->base, EA920_PCIE_PHY0_GEN_CTRL_1);
+ exynos_pcie_phy_writel(ep->base, val |
+ EA920_PCIE_PHY0_PHY0_SRAM_EXT_LD_DONE,
+ EA920_PCIE_PHY0_GEN_CTRL_1);
+ /* wait for PHY init done */
+ mdelay(100);
+
+ return 0;
+}
+
+static int exynosautov920_pcie_phy_exit(struct phy *phy)
+{
+ struct exynos_pcie_phy *ep = phy_get_drvdata(phy);
+
+ if (ep->num_lanes == 4)
+ regmap_update_bits(ep->fsysreg,
+ EA920_HSI0_PCIE_GEN5_PHY_PWRDWN_4L,
+ EA920_HSI0_PCIE_PHY_TEST_PWRDWN_MSK,
+ EA920_HSI0_PCIE_PHY_TEST_PWRDWN);
+ else if (ep->num_lanes == 2)
+ regmap_update_bits(ep->fsysreg,
+ EA920_HSI0_PCIE_GEN5_PHY_PWRDWN_2L,
+ EA920_HSI0_PCIE_PHY_TEST_PWRDWN_MSK,
+ EA920_HSI0_PCIE_PHY_TEST_PWRDWN);
+
+ return 0;
+}
+
static const struct phy_ops fsd_phy0_ops = {
.init = fsd_pcie_phy0_init,
.reset = fsd_pcie_phy0_reset,
@@ -410,6 +629,12 @@ static const struct phy_ops fsd_phy1_ops = {
.owner = THIS_MODULE,
};
+static const struct phy_ops exynosautov920_phy_ops = {
+ .init = exynosautov920_pcie_phy_init,
+ .exit = exynosautov920_pcie_phy_exit,
+ .owner = THIS_MODULE,
+};
+
static const struct of_device_id exynos_pcie_phy_match[] = {
{
.compatible = "samsung,exynos5433-pcie-phy",
@@ -423,6 +648,10 @@ static const struct of_device_id exynos_pcie_phy_match[] = {
.compatible = "tesla,fsd-pcie-phy1",
.data = &fsd_phy1_ops,
},
+ {
+ .compatible = "samsung,exynosautov920-pcie-phy",
+ .data = &exynosautov920_phy_ops,
+ },
{},
};
@@ -468,6 +697,8 @@ static int exynos_pcie_phy_probe(struct platform_device *pdev)
exynos_phy->pcs_base = devm_platform_ioremap_resource(pdev, 1);
+ of_property_read_u32(dev->of_node, "num-lanes", &exynos_phy->num_lanes);
+
phy_set_drvdata(generic_phy, exynos_phy);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
--
2.45.2
Powered by blists - more mailing lists