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