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