Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

phy: uniphier-ahci: Add support for Pro4 SoC

Add support for PHY interface built into ahci controller implemented
in UniPhier Pro4 SoC.

Pro4 SoC distinguishes it from other SoCs as "legacy" SoC, which has GIO
clock line. And Pro4 AHCI-PHY needs to control additional reset lines
("pm", "tx", and "rx").

Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
Link: https://lore.kernel.org/r/1635503947-18250-9-git-send-email-hayashi.kunihiko@socionext.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Kunihiko Hayashi and committed by
Vinod Koul
b1f9f454 34f92b67

+198 -5
+1 -1
drivers/phy/socionext/Kconfig
··· 43 43 select GENERIC_PHY 44 44 help 45 45 Enable this to support PHY implemented in AHCI controller 46 - on UniPhier SoCs. This driver supports PXs2 and PXs3 SoCs. 46 + on UniPhier SoCs. This driver supports Pro4, PXs2 and PXs3 SoCs.
+197 -4
drivers/phy/socionext/phy-uniphier-ahci.c
··· 19 19 struct uniphier_ahciphy_priv { 20 20 struct device *dev; 21 21 void __iomem *base; 22 - struct clk *clk, *clk_parent; 23 - struct reset_control *rst, *rst_parent; 22 + struct clk *clk, *clk_parent, *clk_parent_gio; 23 + struct reset_control *rst, *rst_parent, *rst_parent_gio; 24 + struct reset_control *rst_pm, *rst_tx, *rst_rx; 24 25 const struct uniphier_ahciphy_soc_data *data; 25 26 }; 26 27 ··· 29 28 int (*init)(struct uniphier_ahciphy_priv *priv); 30 29 int (*power_on)(struct uniphier_ahciphy_priv *priv); 31 30 int (*power_off)(struct uniphier_ahciphy_priv *priv); 31 + bool is_legacy; 32 32 bool is_ready_high; 33 33 bool is_phy_clk; 34 34 }; 35 + 36 + /* for Pro4 */ 37 + #define CKCTRL0 0x0 38 + #define CKCTRL0_CK_OFF BIT(9) 39 + #define CKCTRL0_NCY_MASK GENMASK(8, 4) 40 + #define CKCTRL0_NCY5_MASK GENMASK(3, 2) 41 + #define CKCTRL0_PRESCALE_MASK GENMASK(1, 0) 42 + #define CKCTRL1 0x4 43 + #define CKCTRL1_LOS_LVL_MASK GENMASK(20, 16) 44 + #define CKCTRL1_TX_LVL_MASK GENMASK(12, 8) 45 + #define RXTXCTRL 0x8 46 + #define RXTXCTRL_RX_EQ_VALL_MASK GENMASK(31, 29) 47 + #define RXTXCTRL_RX_DPLL_MODE_MASK GENMASK(28, 26) 48 + #define RXTXCTRL_TX_ATTEN_MASK GENMASK(14, 12) 49 + #define RXTXCTRL_TX_BOOST_MASK GENMASK(11, 8) 50 + #define RXTXCTRL_TX_EDGERATE_MASK GENMASK(3, 2) 51 + #define RXTXCTRL_TX_CKO_EN BIT(0) 52 + #define RSTPWR 0x30 53 + #define RSTPWR_RX_EN_VAL BIT(18) 35 54 36 55 /* for PXs2/PXs3 */ 37 56 #define CKCTRL 0x0 ··· 70 49 #define RXCTRL_LOS_LVL_MASK GENMASK(20, 16) 71 50 #define RXCTRL_LOS_BIAS_MASK GENMASK(10, 8) 72 51 #define RXCTRL_RX_EQ_MASK GENMASK(2, 0) 52 + 53 + static int uniphier_ahciphy_pro4_init(struct uniphier_ahciphy_priv *priv) 54 + { 55 + u32 val; 56 + 57 + /* set phy MPLL parameters */ 58 + val = readl(priv->base + CKCTRL0); 59 + val &= ~CKCTRL0_NCY_MASK; 60 + val |= FIELD_PREP(CKCTRL0_NCY_MASK, 0x6); 61 + val &= ~CKCTRL0_NCY5_MASK; 62 + val |= FIELD_PREP(CKCTRL0_NCY5_MASK, 0x2); 63 + val &= ~CKCTRL0_PRESCALE_MASK; 64 + val |= FIELD_PREP(CKCTRL0_PRESCALE_MASK, 0x1); 65 + writel(val, priv->base + CKCTRL0); 66 + 67 + /* setup phy control parameters */ 68 + val = readl(priv->base + CKCTRL1); 69 + val &= ~CKCTRL1_LOS_LVL_MASK; 70 + val |= FIELD_PREP(CKCTRL1_LOS_LVL_MASK, 0x10); 71 + val &= ~CKCTRL1_TX_LVL_MASK; 72 + val |= FIELD_PREP(CKCTRL1_TX_LVL_MASK, 0x06); 73 + writel(val, priv->base + CKCTRL1); 74 + 75 + val = readl(priv->base + RXTXCTRL); 76 + val &= ~RXTXCTRL_RX_EQ_VALL_MASK; 77 + val |= FIELD_PREP(RXTXCTRL_RX_EQ_VALL_MASK, 0x6); 78 + val &= ~RXTXCTRL_RX_DPLL_MODE_MASK; 79 + val |= FIELD_PREP(RXTXCTRL_RX_DPLL_MODE_MASK, 0x3); 80 + val &= ~RXTXCTRL_TX_ATTEN_MASK; 81 + val |= FIELD_PREP(RXTXCTRL_TX_ATTEN_MASK, 0x3); 82 + val &= ~RXTXCTRL_TX_BOOST_MASK; 83 + val |= FIELD_PREP(RXTXCTRL_TX_BOOST_MASK, 0x5); 84 + val &= ~RXTXCTRL_TX_EDGERATE_MASK; 85 + val |= FIELD_PREP(RXTXCTRL_TX_EDGERATE_MASK, 0x0); 86 + writel(val, priv->base + RXTXCTRL); 87 + 88 + return 0; 89 + } 90 + 91 + static int uniphier_ahciphy_pro4_power_on(struct uniphier_ahciphy_priv *priv) 92 + { 93 + u32 val; 94 + int ret; 95 + 96 + /* enable reference clock for phy */ 97 + val = readl(priv->base + CKCTRL0); 98 + val &= ~CKCTRL0_CK_OFF; 99 + writel(val, priv->base + CKCTRL0); 100 + 101 + /* enable TX clock */ 102 + val = readl(priv->base + RXTXCTRL); 103 + val |= RXTXCTRL_TX_CKO_EN; 104 + writel(val, priv->base + RXTXCTRL); 105 + 106 + /* wait until RX is ready */ 107 + ret = readl_poll_timeout(priv->base + RSTPWR, val, 108 + !(val & RSTPWR_RX_EN_VAL), 200, 2000); 109 + if (ret) { 110 + dev_err(priv->dev, "Failed to check whether Rx is ready\n"); 111 + goto out_disable_clock; 112 + } 113 + 114 + /* release all reset */ 115 + ret = reset_control_deassert(priv->rst_pm); 116 + if (ret) { 117 + dev_err(priv->dev, "Failed to release PM reset\n"); 118 + goto out_disable_clock; 119 + } 120 + 121 + ret = reset_control_deassert(priv->rst_tx); 122 + if (ret) { 123 + dev_err(priv->dev, "Failed to release Tx reset\n"); 124 + goto out_reset_pm_assert; 125 + } 126 + 127 + ret = reset_control_deassert(priv->rst_rx); 128 + if (ret) { 129 + dev_err(priv->dev, "Failed to release Rx reset\n"); 130 + goto out_reset_tx_assert; 131 + } 132 + 133 + return 0; 134 + 135 + out_reset_tx_assert: 136 + reset_control_assert(priv->rst_tx); 137 + out_reset_pm_assert: 138 + reset_control_assert(priv->rst_pm); 139 + 140 + out_disable_clock: 141 + /* disable TX clock */ 142 + val = readl(priv->base + RXTXCTRL); 143 + val &= ~RXTXCTRL_TX_CKO_EN; 144 + writel(val, priv->base + RXTXCTRL); 145 + 146 + /* disable reference clock for phy */ 147 + val = readl(priv->base + CKCTRL0); 148 + val |= CKCTRL0_CK_OFF; 149 + writel(val, priv->base + CKCTRL0); 150 + 151 + return ret; 152 + } 153 + 154 + static int uniphier_ahciphy_pro4_power_off(struct uniphier_ahciphy_priv *priv) 155 + { 156 + u32 val; 157 + 158 + reset_control_assert(priv->rst_rx); 159 + reset_control_assert(priv->rst_tx); 160 + reset_control_assert(priv->rst_pm); 161 + 162 + /* disable TX clock */ 163 + val = readl(priv->base + RXTXCTRL); 164 + val &= ~RXTXCTRL_TX_CKO_EN; 165 + writel(val, priv->base + RXTXCTRL); 166 + 167 + /* disable reference clock for phy */ 168 + val = readl(priv->base + CKCTRL0); 169 + val |= CKCTRL0_CK_OFF; 170 + writel(val, priv->base + CKCTRL0); 171 + 172 + return 0; 173 + } 73 174 74 175 static void uniphier_ahciphy_pxs2_enable(struct uniphier_ahciphy_priv *priv, 75 176 bool enable) ··· 285 142 struct uniphier_ahciphy_priv *priv = phy_get_drvdata(phy); 286 143 int ret; 287 144 288 - ret = clk_prepare_enable(priv->clk_parent); 145 + ret = clk_prepare_enable(priv->clk_parent_gio); 289 146 if (ret) 290 147 return ret; 291 148 292 - ret = reset_control_deassert(priv->rst_parent); 149 + ret = clk_prepare_enable(priv->clk_parent); 150 + if (ret) 151 + goto out_clk_gio_disable; 152 + 153 + ret = reset_control_deassert(priv->rst_parent_gio); 293 154 if (ret) 294 155 goto out_clk_disable; 156 + 157 + ret = reset_control_deassert(priv->rst_parent); 158 + if (ret) 159 + goto out_rst_gio_assert; 295 160 296 161 if (priv->data->init) { 297 162 ret = priv->data->init(priv); ··· 311 160 312 161 out_rst_assert: 313 162 reset_control_assert(priv->rst_parent); 163 + out_rst_gio_assert: 164 + reset_control_assert(priv->rst_parent_gio); 314 165 out_clk_disable: 315 166 clk_disable_unprepare(priv->clk_parent); 167 + out_clk_gio_disable: 168 + clk_disable_unprepare(priv->clk_parent_gio); 316 169 317 170 return ret; 318 171 } ··· 326 171 struct uniphier_ahciphy_priv *priv = phy_get_drvdata(phy); 327 172 328 173 reset_control_assert(priv->rst_parent); 174 + reset_control_assert(priv->rst_parent_gio); 329 175 clk_disable_unprepare(priv->clk_parent); 176 + clk_disable_unprepare(priv->clk_parent_gio); 330 177 331 178 return 0; 332 179 } ··· 422 265 if (IS_ERR(priv->rst)) 423 266 return PTR_ERR(priv->rst); 424 267 268 + if (priv->data->is_legacy) { 269 + priv->clk_parent_gio = devm_clk_get(dev, "gio"); 270 + if (IS_ERR(priv->clk_parent_gio)) 271 + return PTR_ERR(priv->clk_parent_gio); 272 + priv->rst_parent_gio = 273 + devm_reset_control_get_shared(dev, "gio"); 274 + if (IS_ERR(priv->rst_parent_gio)) 275 + return PTR_ERR(priv->rst_parent_gio); 276 + 277 + priv->rst_pm = devm_reset_control_get_shared(dev, "pm"); 278 + if (IS_ERR(priv->rst_pm)) 279 + return PTR_ERR(priv->rst_pm); 280 + 281 + priv->rst_tx = devm_reset_control_get_shared(dev, "tx"); 282 + if (IS_ERR(priv->rst_tx)) 283 + return PTR_ERR(priv->rst_tx); 284 + 285 + priv->rst_rx = devm_reset_control_get_shared(dev, "rx"); 286 + if (IS_ERR(priv->rst_rx)) 287 + return PTR_ERR(priv->rst_rx); 288 + } 289 + 425 290 phy = devm_phy_create(dev, dev->of_node, &uniphier_ahciphy_ops); 426 291 if (IS_ERR(phy)) { 427 292 dev_err(dev, "failed to create phy\n"); ··· 458 279 return 0; 459 280 } 460 281 282 + static const struct uniphier_ahciphy_soc_data uniphier_pro4_data = { 283 + .init = uniphier_ahciphy_pro4_init, 284 + .power_on = uniphier_ahciphy_pro4_power_on, 285 + .power_off = uniphier_ahciphy_pro4_power_off, 286 + .is_legacy = true, 287 + .is_phy_clk = false, 288 + }; 289 + 461 290 static const struct uniphier_ahciphy_soc_data uniphier_pxs2_data = { 462 291 .power_on = uniphier_ahciphy_pxs2_power_on, 463 292 .power_off = uniphier_ahciphy_pxs2_power_off, 293 + .is_legacy = false, 464 294 .is_ready_high = false, 465 295 .is_phy_clk = false, 466 296 }; ··· 478 290 .init = uniphier_ahciphy_pxs3_init, 479 291 .power_on = uniphier_ahciphy_pxs2_power_on, 480 292 .power_off = uniphier_ahciphy_pxs2_power_off, 293 + .is_legacy = false, 481 294 .is_ready_high = true, 482 295 .is_phy_clk = true, 483 296 }; 484 297 485 298 static const struct of_device_id uniphier_ahciphy_match[] = { 299 + { 300 + .compatible = "socionext,uniphier-pro4-ahci-phy", 301 + .data = &uniphier_pro4_data, 302 + }, 486 303 { 487 304 .compatible = "socionext,uniphier-pxs2-ahci-phy", 488 305 .data = &uniphier_pxs2_data,