1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * COMBPHY driver for HiSilicon STB SoCs 4 * 5 * Copyright (C) 2016-2017 HiSilicon Co., Ltd. http://www.hisilicon.com 6 * 7 * Authors: Jianguo Sun <sunjianguo1@huawei.com> 8 */ 9 10 #include <linux/clk.h> 11 #include <linux/delay.h> 12 #include <linux/io.h> 13 #include <linux/kernel.h> 14 #include <linux/mfd/syscon.h> 15 #include <linux/module.h> 16 #include <linux/of_device.h> 17 #include <linux/phy/phy.h> 18 #include <linux/regmap.h> 19 #include <linux/reset.h> 20 #include <dt-bindings/phy/phy.h> 21 22 #define COMBPHY_MODE_PCIE 0 23 #define COMBPHY_MODE_USB3 1 24 #define COMBPHY_MODE_SATA 2 25 26 #define COMBPHY_CFG_REG 0x0 27 #define COMBPHY_BYPASS_CODEC BIT(31) 28 #define COMBPHY_TEST_WRITE BIT(24) 29 #define COMBPHY_TEST_DATA_SHIFT 20 30 #define COMBPHY_TEST_DATA_MASK GENMASK(23, 20) 31 #define COMBPHY_TEST_ADDR_SHIFT 12 32 #define COMBPHY_TEST_ADDR_MASK GENMASK(16, 12) 33 #define COMBPHY_CLKREF_OUT_OEN BIT(0) 34 35 struct histb_combphy_mode { 36 int fixed; 37 int select; 38 u32 reg; 39 u32 shift; 40 u32 mask; 41 }; 42 43 struct histb_combphy_priv { 44 void __iomem *mmio; 45 struct regmap *syscon; 46 struct reset_control *por_rst; 47 struct clk *ref_clk; 48 struct phy *phy; 49 struct histb_combphy_mode mode; 50 }; 51 52 static void nano_register_write(struct histb_combphy_priv *priv, 53 u32 addr, u32 data) 54 { 55 void __iomem *reg = priv->mmio + COMBPHY_CFG_REG; 56 u32 val; 57 58 /* Set up address and data for the write */ 59 val = readl(reg); 60 val &= ~COMBPHY_TEST_ADDR_MASK; 61 val |= addr << COMBPHY_TEST_ADDR_SHIFT; 62 val &= ~COMBPHY_TEST_DATA_MASK; 63 val |= data << COMBPHY_TEST_DATA_SHIFT; 64 writel(val, reg); 65 66 /* Flip strobe control to trigger the write */ 67 val &= ~COMBPHY_TEST_WRITE; 68 writel(val, reg); 69 val |= COMBPHY_TEST_WRITE; 70 writel(val, reg); 71 } 72 73 static int is_mode_fixed(struct histb_combphy_mode *mode) 74 { 75 return (mode->fixed != PHY_NONE) ? true : false; 76 } 77 78 static int histb_combphy_set_mode(struct histb_combphy_priv *priv) 79 { 80 struct histb_combphy_mode *mode = &priv->mode; 81 struct regmap *syscon = priv->syscon; 82 u32 hw_sel; 83 84 if (is_mode_fixed(mode)) 85 return 0; 86 87 switch (mode->select) { 88 case PHY_TYPE_SATA: 89 hw_sel = COMBPHY_MODE_SATA; 90 break; 91 case PHY_TYPE_PCIE: 92 hw_sel = COMBPHY_MODE_PCIE; 93 break; 94 case PHY_TYPE_USB3: 95 hw_sel = COMBPHY_MODE_USB3; 96 break; 97 default: 98 return -EINVAL; 99 } 100 101 return regmap_update_bits(syscon, mode->reg, mode->mask, 102 hw_sel << mode->shift); 103 } 104 105 static int histb_combphy_init(struct phy *phy) 106 { 107 struct histb_combphy_priv *priv = phy_get_drvdata(phy); 108 u32 val; 109 int ret; 110 111 ret = histb_combphy_set_mode(priv); 112 if (ret) 113 return ret; 114 115 /* Clear bypass bit to enable encoding/decoding */ 116 val = readl(priv->mmio + COMBPHY_CFG_REG); 117 val &= ~COMBPHY_BYPASS_CODEC; 118 writel(val, priv->mmio + COMBPHY_CFG_REG); 119 120 ret = clk_prepare_enable(priv->ref_clk); 121 if (ret) 122 return ret; 123 124 reset_control_deassert(priv->por_rst); 125 126 /* Enable EP clock */ 127 val = readl(priv->mmio + COMBPHY_CFG_REG); 128 val |= COMBPHY_CLKREF_OUT_OEN; 129 writel(val, priv->mmio + COMBPHY_CFG_REG); 130 131 /* Need to wait for EP clock stable */ 132 mdelay(5); 133 134 /* Configure nano phy registers as suggested by vendor */ 135 nano_register_write(priv, 0x1, 0x8); 136 nano_register_write(priv, 0xc, 0x9); 137 nano_register_write(priv, 0x1a, 0x4); 138 139 return 0; 140 } 141 142 static int histb_combphy_exit(struct phy *phy) 143 { 144 struct histb_combphy_priv *priv = phy_get_drvdata(phy); 145 u32 val; 146 147 /* Disable EP clock */ 148 val = readl(priv->mmio + COMBPHY_CFG_REG); 149 val &= ~COMBPHY_CLKREF_OUT_OEN; 150 writel(val, priv->mmio + COMBPHY_CFG_REG); 151 152 reset_control_assert(priv->por_rst); 153 clk_disable_unprepare(priv->ref_clk); 154 155 return 0; 156 } 157 158 static const struct phy_ops histb_combphy_ops = { 159 .init = histb_combphy_init, 160 .exit = histb_combphy_exit, 161 .owner = THIS_MODULE, 162 }; 163 164 static struct phy *histb_combphy_xlate(struct device *dev, 165 struct of_phandle_args *args) 166 { 167 struct histb_combphy_priv *priv = dev_get_drvdata(dev); 168 struct histb_combphy_mode *mode = &priv->mode; 169 170 if (args->args_count < 1) { 171 dev_err(dev, "invalid number of arguments\n"); 172 return ERR_PTR(-EINVAL); 173 } 174 175 mode->select = args->args[0]; 176 177 if (mode->select < PHY_TYPE_SATA || mode->select > PHY_TYPE_USB3) { 178 dev_err(dev, "invalid phy mode select argument\n"); 179 return ERR_PTR(-EINVAL); 180 } 181 182 if (is_mode_fixed(mode) && mode->select != mode->fixed) { 183 dev_err(dev, "mode select %d mismatch fixed phy mode %d\n", 184 mode->select, mode->fixed); 185 return ERR_PTR(-EINVAL); 186 } 187 188 return priv->phy; 189 } 190 191 static int histb_combphy_probe(struct platform_device *pdev) 192 { 193 struct phy_provider *phy_provider; 194 struct device *dev = &pdev->dev; 195 struct histb_combphy_priv *priv; 196 struct device_node *np = dev->of_node; 197 struct histb_combphy_mode *mode; 198 struct resource *res; 199 u32 vals[3]; 200 int ret; 201 202 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 203 if (!priv) 204 return -ENOMEM; 205 206 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 207 priv->mmio = devm_ioremap_resource(dev, res); 208 if (IS_ERR(priv->mmio)) { 209 ret = PTR_ERR(priv->mmio); 210 return ret; 211 } 212 213 priv->syscon = syscon_node_to_regmap(np->parent); 214 if (IS_ERR(priv->syscon)) { 215 dev_err(dev, "failed to find peri_ctrl syscon regmap\n"); 216 return PTR_ERR(priv->syscon); 217 } 218 219 mode = &priv->mode; 220 mode->fixed = PHY_NONE; 221 222 ret = of_property_read_u32(np, "hisilicon,fixed-mode", &mode->fixed); 223 if (ret == 0) 224 dev_dbg(dev, "found fixed phy mode %d\n", mode->fixed); 225 226 ret = of_property_read_u32_array(np, "hisilicon,mode-select-bits", 227 vals, ARRAY_SIZE(vals)); 228 if (ret == 0) { 229 if (is_mode_fixed(mode)) { 230 dev_err(dev, "found select bits for fixed mode phy\n"); 231 return -EINVAL; 232 } 233 234 mode->reg = vals[0]; 235 mode->shift = vals[1]; 236 mode->mask = vals[2]; 237 dev_dbg(dev, "found mode select bits\n"); 238 } else { 239 if (!is_mode_fixed(mode)) { 240 dev_err(dev, "no valid select bits found for non-fixed phy\n"); 241 return -ENODEV; 242 } 243 } 244 245 priv->ref_clk = devm_clk_get(dev, NULL); 246 if (IS_ERR(priv->ref_clk)) { 247 dev_err(dev, "failed to find ref clock\n"); 248 return PTR_ERR(priv->ref_clk); 249 } 250 251 priv->por_rst = devm_reset_control_get(dev, NULL); 252 if (IS_ERR(priv->por_rst)) { 253 dev_err(dev, "failed to get poweron reset\n"); 254 return PTR_ERR(priv->por_rst); 255 } 256 257 priv->phy = devm_phy_create(dev, NULL, &histb_combphy_ops); 258 if (IS_ERR(priv->phy)) { 259 dev_err(dev, "failed to create combphy\n"); 260 return PTR_ERR(priv->phy); 261 } 262 263 dev_set_drvdata(dev, priv); 264 phy_set_drvdata(priv->phy, priv); 265 266 phy_provider = devm_of_phy_provider_register(dev, histb_combphy_xlate); 267 return PTR_ERR_OR_ZERO(phy_provider); 268 } 269 270 static const struct of_device_id histb_combphy_of_match[] = { 271 { .compatible = "hisilicon,hi3798cv200-combphy" }, 272 { }, 273 }; 274 MODULE_DEVICE_TABLE(of, histb_combphy_of_match); 275 276 static struct platform_driver histb_combphy_driver = { 277 .probe = histb_combphy_probe, 278 .driver = { 279 .name = "combphy", 280 .of_match_table = histb_combphy_of_match, 281 }, 282 }; 283 module_platform_driver(histb_combphy_driver); 284 285 MODULE_DESCRIPTION("HiSilicon STB COMBPHY driver"); 286 MODULE_LICENSE("GPL v2"); 287