1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * phy-uniphier-pcie.c - PHY driver for UniPhier PCIe controller 4 * Copyright 2018, Socionext Inc. 5 * Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com> 6 */ 7 8 #include <linux/bitops.h> 9 #include <linux/bitfield.h> 10 #include <linux/clk.h> 11 #include <linux/iopoll.h> 12 #include <linux/mfd/syscon.h> 13 #include <linux/module.h> 14 #include <linux/of_device.h> 15 #include <linux/phy/phy.h> 16 #include <linux/platform_device.h> 17 #include <linux/regmap.h> 18 #include <linux/reset.h> 19 #include <linux/resource.h> 20 21 /* PHY */ 22 #define PCL_PHY_CLKCTRL 0x0000 23 #define PORT_SEL_MASK GENMASK(11, 9) 24 #define PORT_SEL_1 FIELD_PREP(PORT_SEL_MASK, 1) 25 26 #define PCL_PHY_TEST_I 0x2000 27 #define PCL_PHY_TEST_O 0x2004 28 #define TESTI_DAT_MASK GENMASK(13, 6) 29 #define TESTI_ADR_MASK GENMASK(5, 1) 30 #define TESTI_WR_EN BIT(0) 31 32 #define PCL_PHY_RESET 0x200c 33 #define PCL_PHY_RESET_N_MNMODE BIT(8) /* =1:manual */ 34 #define PCL_PHY_RESET_N BIT(0) /* =1:deasssert */ 35 36 /* SG */ 37 #define SG_USBPCIESEL 0x590 38 #define SG_USBPCIESEL_PCIE BIT(0) 39 40 #define PCL_PHY_R00 0 41 #define RX_EQ_ADJ_EN BIT(3) /* enable for EQ adjustment */ 42 #define PCL_PHY_R06 6 43 #define RX_EQ_ADJ GENMASK(5, 0) /* EQ adjustment value */ 44 #define RX_EQ_ADJ_VAL 0 45 #define PCL_PHY_R26 26 46 #define VCO_CTRL GENMASK(7, 4) /* Tx VCO adjustment value */ 47 #define VCO_CTRL_INIT_VAL 5 48 49 struct uniphier_pciephy_priv { 50 void __iomem *base; 51 struct device *dev; 52 struct clk *clk, *clk_gio; 53 struct reset_control *rst, *rst_gio; 54 const struct uniphier_pciephy_soc_data *data; 55 }; 56 57 struct uniphier_pciephy_soc_data { 58 bool is_legacy; 59 void (*set_phymode)(struct regmap *regmap); 60 }; 61 62 static void uniphier_pciephy_testio_write(struct uniphier_pciephy_priv *priv, 63 u32 data) 64 { 65 /* need to read TESTO twice after accessing TESTI */ 66 writel(data, priv->base + PCL_PHY_TEST_I); 67 readl(priv->base + PCL_PHY_TEST_O); 68 readl(priv->base + PCL_PHY_TEST_O); 69 } 70 71 static void uniphier_pciephy_set_param(struct uniphier_pciephy_priv *priv, 72 u32 reg, u32 mask, u32 param) 73 { 74 u32 val; 75 76 /* read previous data */ 77 val = FIELD_PREP(TESTI_DAT_MASK, 1); 78 val |= FIELD_PREP(TESTI_ADR_MASK, reg); 79 uniphier_pciephy_testio_write(priv, val); 80 val = readl(priv->base + PCL_PHY_TEST_O); 81 82 /* update value */ 83 val &= ~FIELD_PREP(TESTI_DAT_MASK, mask); 84 val = FIELD_PREP(TESTI_DAT_MASK, mask & param); 85 val |= FIELD_PREP(TESTI_ADR_MASK, reg); 86 uniphier_pciephy_testio_write(priv, val); 87 uniphier_pciephy_testio_write(priv, val | TESTI_WR_EN); 88 uniphier_pciephy_testio_write(priv, val); 89 90 /* read current data as dummy */ 91 val = FIELD_PREP(TESTI_DAT_MASK, 1); 92 val |= FIELD_PREP(TESTI_ADR_MASK, reg); 93 uniphier_pciephy_testio_write(priv, val); 94 readl(priv->base + PCL_PHY_TEST_O); 95 } 96 97 static void uniphier_pciephy_assert(struct uniphier_pciephy_priv *priv) 98 { 99 u32 val; 100 101 val = readl(priv->base + PCL_PHY_RESET); 102 val &= ~PCL_PHY_RESET_N; 103 val |= PCL_PHY_RESET_N_MNMODE; 104 writel(val, priv->base + PCL_PHY_RESET); 105 } 106 107 static void uniphier_pciephy_deassert(struct uniphier_pciephy_priv *priv) 108 { 109 u32 val; 110 111 val = readl(priv->base + PCL_PHY_RESET); 112 val |= PCL_PHY_RESET_N_MNMODE | PCL_PHY_RESET_N; 113 writel(val, priv->base + PCL_PHY_RESET); 114 } 115 116 static int uniphier_pciephy_init(struct phy *phy) 117 { 118 struct uniphier_pciephy_priv *priv = phy_get_drvdata(phy); 119 u32 val; 120 int ret; 121 122 ret = clk_prepare_enable(priv->clk); 123 if (ret) 124 return ret; 125 126 ret = clk_prepare_enable(priv->clk_gio); 127 if (ret) 128 goto out_clk_disable; 129 130 ret = reset_control_deassert(priv->rst); 131 if (ret) 132 goto out_clk_gio_disable; 133 134 ret = reset_control_deassert(priv->rst_gio); 135 if (ret) 136 goto out_rst_assert; 137 138 /* support only 1 port */ 139 val = readl(priv->base + PCL_PHY_CLKCTRL); 140 val &= ~PORT_SEL_MASK; 141 val |= PORT_SEL_1; 142 writel(val, priv->base + PCL_PHY_CLKCTRL); 143 144 /* legacy controller doesn't have phy_reset and parameters */ 145 if (priv->data->is_legacy) 146 return 0; 147 148 uniphier_pciephy_set_param(priv, PCL_PHY_R00, 149 RX_EQ_ADJ_EN, RX_EQ_ADJ_EN); 150 uniphier_pciephy_set_param(priv, PCL_PHY_R06, RX_EQ_ADJ, 151 FIELD_PREP(RX_EQ_ADJ, RX_EQ_ADJ_VAL)); 152 uniphier_pciephy_set_param(priv, PCL_PHY_R26, VCO_CTRL, 153 FIELD_PREP(VCO_CTRL, VCO_CTRL_INIT_VAL)); 154 usleep_range(1, 10); 155 156 uniphier_pciephy_deassert(priv); 157 usleep_range(1, 10); 158 159 return 0; 160 161 out_rst_assert: 162 reset_control_assert(priv->rst); 163 out_clk_gio_disable: 164 clk_disable_unprepare(priv->clk_gio); 165 out_clk_disable: 166 clk_disable_unprepare(priv->clk); 167 168 return ret; 169 } 170 171 static int uniphier_pciephy_exit(struct phy *phy) 172 { 173 struct uniphier_pciephy_priv *priv = phy_get_drvdata(phy); 174 175 if (!priv->data->is_legacy) 176 uniphier_pciephy_assert(priv); 177 reset_control_assert(priv->rst_gio); 178 reset_control_assert(priv->rst); 179 clk_disable_unprepare(priv->clk_gio); 180 clk_disable_unprepare(priv->clk); 181 182 return 0; 183 } 184 185 static const struct phy_ops uniphier_pciephy_ops = { 186 .init = uniphier_pciephy_init, 187 .exit = uniphier_pciephy_exit, 188 .owner = THIS_MODULE, 189 }; 190 191 static int uniphier_pciephy_probe(struct platform_device *pdev) 192 { 193 struct uniphier_pciephy_priv *priv; 194 struct phy_provider *phy_provider; 195 struct device *dev = &pdev->dev; 196 struct regmap *regmap; 197 struct phy *phy; 198 199 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 200 if (!priv) 201 return -ENOMEM; 202 203 priv->data = of_device_get_match_data(dev); 204 if (WARN_ON(!priv->data)) 205 return -EINVAL; 206 207 priv->dev = dev; 208 209 priv->base = devm_platform_ioremap_resource(pdev, 0); 210 if (IS_ERR(priv->base)) 211 return PTR_ERR(priv->base); 212 213 if (priv->data->is_legacy) { 214 priv->clk_gio = devm_clk_get(dev, "gio"); 215 if (IS_ERR(priv->clk_gio)) 216 return PTR_ERR(priv->clk_gio); 217 218 priv->rst_gio = 219 devm_reset_control_get_shared(dev, "gio"); 220 if (IS_ERR(priv->rst_gio)) 221 return PTR_ERR(priv->rst_gio); 222 223 priv->clk = devm_clk_get(dev, "link"); 224 if (IS_ERR(priv->clk)) 225 return PTR_ERR(priv->clk); 226 227 priv->rst = devm_reset_control_get_shared(dev, "link"); 228 if (IS_ERR(priv->rst)) 229 return PTR_ERR(priv->rst); 230 } else { 231 priv->clk = devm_clk_get(dev, NULL); 232 if (IS_ERR(priv->clk)) 233 return PTR_ERR(priv->clk); 234 235 priv->rst = devm_reset_control_get_shared(dev, NULL); 236 if (IS_ERR(priv->rst)) 237 return PTR_ERR(priv->rst); 238 } 239 240 phy = devm_phy_create(dev, dev->of_node, &uniphier_pciephy_ops); 241 if (IS_ERR(phy)) 242 return PTR_ERR(phy); 243 244 regmap = syscon_regmap_lookup_by_phandle(dev->of_node, 245 "socionext,syscon"); 246 if (!IS_ERR(regmap) && priv->data->set_phymode) 247 priv->data->set_phymode(regmap); 248 249 phy_set_drvdata(phy, priv); 250 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 251 252 return PTR_ERR_OR_ZERO(phy_provider); 253 } 254 255 static void uniphier_pciephy_ld20_setmode(struct regmap *regmap) 256 { 257 regmap_update_bits(regmap, SG_USBPCIESEL, 258 SG_USBPCIESEL_PCIE, SG_USBPCIESEL_PCIE); 259 } 260 261 static const struct uniphier_pciephy_soc_data uniphier_pro5_data = { 262 .is_legacy = true, 263 }; 264 265 static const struct uniphier_pciephy_soc_data uniphier_ld20_data = { 266 .is_legacy = false, 267 .set_phymode = uniphier_pciephy_ld20_setmode, 268 }; 269 270 static const struct uniphier_pciephy_soc_data uniphier_pxs3_data = { 271 .is_legacy = false, 272 }; 273 274 static const struct of_device_id uniphier_pciephy_match[] = { 275 { 276 .compatible = "socionext,uniphier-pro5-pcie-phy", 277 .data = &uniphier_pro5_data, 278 }, 279 { 280 .compatible = "socionext,uniphier-ld20-pcie-phy", 281 .data = &uniphier_ld20_data, 282 }, 283 { 284 .compatible = "socionext,uniphier-pxs3-pcie-phy", 285 .data = &uniphier_pxs3_data, 286 }, 287 { /* sentinel */ }, 288 }; 289 MODULE_DEVICE_TABLE(of, uniphier_pciephy_match); 290 291 static struct platform_driver uniphier_pciephy_driver = { 292 .probe = uniphier_pciephy_probe, 293 .driver = { 294 .name = "uniphier-pcie-phy", 295 .of_match_table = uniphier_pciephy_match, 296 }, 297 }; 298 module_platform_driver(uniphier_pciephy_driver); 299 300 MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>"); 301 MODULE_DESCRIPTION("UniPhier PHY driver for PCIe controller"); 302 MODULE_LICENSE("GPL v2"); 303