1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Broadcom Northstar USB 3.0 PHY Driver 4 * 5 * Copyright (C) 2016 Rafał Miłecki <rafal@milecki.pl> 6 * Copyright (C) 2016 Broadcom 7 * 8 * All magic values used for initialization (and related comments) were obtained 9 * from Broadcom's SDK: 10 * Copyright (c) Broadcom Corp, 2012 11 */ 12 13 #include <linux/bcma/bcma.h> 14 #include <linux/delay.h> 15 #include <linux/err.h> 16 #include <linux/iopoll.h> 17 #include <linux/mdio.h> 18 #include <linux/module.h> 19 #include <linux/of_address.h> 20 #include <linux/of_platform.h> 21 #include <linux/platform_device.h> 22 #include <linux/phy/phy.h> 23 #include <linux/slab.h> 24 25 #define BCM_NS_USB3_MII_MNG_TIMEOUT_US 1000 /* usecs */ 26 27 #define BCM_NS_USB3_PHY_BASE_ADDR_REG 0x1f 28 #define BCM_NS_USB3_PHY_PLL30_BLOCK 0x8000 29 #define BCM_NS_USB3_PHY_TX_PMD_BLOCK 0x8040 30 #define BCM_NS_USB3_PHY_PIPE_BLOCK 0x8060 31 32 /* Registers of PLL30 block */ 33 #define BCM_NS_USB3_PLL_CONTROL 0x01 34 #define BCM_NS_USB3_PLLA_CONTROL0 0x0a 35 #define BCM_NS_USB3_PLLA_CONTROL1 0x0b 36 37 /* Registers of TX PMD block */ 38 #define BCM_NS_USB3_TX_PMD_CONTROL1 0x01 39 40 /* Registers of PIPE block */ 41 #define BCM_NS_USB3_LFPS_CMP 0x02 42 #define BCM_NS_USB3_LFPS_DEGLITCH 0x03 43 44 enum bcm_ns_family { 45 BCM_NS_UNKNOWN, 46 BCM_NS_AX, 47 BCM_NS_BX, 48 }; 49 50 struct bcm_ns_usb3 { 51 struct device *dev; 52 enum bcm_ns_family family; 53 void __iomem *dmp; 54 void __iomem *ccb_mii; 55 struct mdio_device *mdiodev; 56 struct phy *phy; 57 58 int (*phy_write)(struct bcm_ns_usb3 *usb3, u16 reg, u16 value); 59 }; 60 61 static const struct of_device_id bcm_ns_usb3_id_table[] = { 62 { 63 .compatible = "brcm,ns-ax-usb3-phy", 64 .data = (int *)BCM_NS_AX, 65 }, 66 { 67 .compatible = "brcm,ns-bx-usb3-phy", 68 .data = (int *)BCM_NS_BX, 69 }, 70 {}, 71 }; 72 MODULE_DEVICE_TABLE(of, bcm_ns_usb3_id_table); 73 74 static int bcm_ns_usb3_mdio_phy_write(struct bcm_ns_usb3 *usb3, u16 reg, 75 u16 value) 76 { 77 return usb3->phy_write(usb3, reg, value); 78 } 79 80 static int bcm_ns_usb3_phy_init_ns_bx(struct bcm_ns_usb3 *usb3) 81 { 82 int err; 83 84 /* USB3 PLL Block */ 85 err = bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG, 86 BCM_NS_USB3_PHY_PLL30_BLOCK); 87 if (err < 0) 88 return err; 89 90 /* Assert Ana_Pllseq start */ 91 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLL_CONTROL, 0x1000); 92 93 /* Assert CML Divider ratio to 26 */ 94 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLLA_CONTROL0, 0x6400); 95 96 /* Asserting PLL Reset */ 97 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLLA_CONTROL1, 0xc000); 98 99 /* Deaaserting PLL Reset */ 100 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLLA_CONTROL1, 0x8000); 101 102 /* Deasserting USB3 system reset */ 103 writel(0, usb3->dmp + BCMA_RESET_CTL); 104 105 /* PLL frequency monitor enable */ 106 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLL_CONTROL, 0x9000); 107 108 /* PIPE Block */ 109 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG, 110 BCM_NS_USB3_PHY_PIPE_BLOCK); 111 112 /* CMPMAX & CMPMINTH setting */ 113 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_LFPS_CMP, 0xf30d); 114 115 /* DEGLITCH MIN & MAX setting */ 116 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_LFPS_DEGLITCH, 0x6302); 117 118 /* TXPMD block */ 119 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG, 120 BCM_NS_USB3_PHY_TX_PMD_BLOCK); 121 122 /* Enabling SSC */ 123 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_TX_PMD_CONTROL1, 0x1003); 124 125 return 0; 126 } 127 128 static int bcm_ns_usb3_phy_init_ns_ax(struct bcm_ns_usb3 *usb3) 129 { 130 int err; 131 132 /* PLL30 block */ 133 err = bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG, 134 BCM_NS_USB3_PHY_PLL30_BLOCK); 135 if (err < 0) 136 return err; 137 138 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLLA_CONTROL0, 0x6400); 139 140 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG, 0x80e0); 141 142 bcm_ns_usb3_mdio_phy_write(usb3, 0x02, 0x009c); 143 144 /* Enable SSC */ 145 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG, 146 BCM_NS_USB3_PHY_TX_PMD_BLOCK); 147 148 bcm_ns_usb3_mdio_phy_write(usb3, 0x02, 0x21d3); 149 150 bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_TX_PMD_CONTROL1, 0x1003); 151 152 /* Deasserting USB3 system reset */ 153 writel(0, usb3->dmp + BCMA_RESET_CTL); 154 155 return 0; 156 } 157 158 static int bcm_ns_usb3_phy_init(struct phy *phy) 159 { 160 struct bcm_ns_usb3 *usb3 = phy_get_drvdata(phy); 161 int err; 162 163 /* Perform USB3 system soft reset */ 164 writel(BCMA_RESET_CTL_RESET, usb3->dmp + BCMA_RESET_CTL); 165 166 switch (usb3->family) { 167 case BCM_NS_AX: 168 err = bcm_ns_usb3_phy_init_ns_ax(usb3); 169 break; 170 case BCM_NS_BX: 171 err = bcm_ns_usb3_phy_init_ns_bx(usb3); 172 break; 173 default: 174 WARN_ON(1); 175 err = -ENOTSUPP; 176 } 177 178 return err; 179 } 180 181 static const struct phy_ops ops = { 182 .init = bcm_ns_usb3_phy_init, 183 .owner = THIS_MODULE, 184 }; 185 186 /************************************************** 187 * MDIO driver code 188 **************************************************/ 189 190 static int bcm_ns_usb3_mdiodev_phy_write(struct bcm_ns_usb3 *usb3, u16 reg, 191 u16 value) 192 { 193 struct mdio_device *mdiodev = usb3->mdiodev; 194 195 return mdiobus_write(mdiodev->bus, mdiodev->addr, reg, value); 196 } 197 198 static int bcm_ns_usb3_mdio_probe(struct mdio_device *mdiodev) 199 { 200 struct device *dev = &mdiodev->dev; 201 const struct of_device_id *of_id; 202 struct phy_provider *phy_provider; 203 struct device_node *syscon_np; 204 struct bcm_ns_usb3 *usb3; 205 struct resource res; 206 int err; 207 208 usb3 = devm_kzalloc(dev, sizeof(*usb3), GFP_KERNEL); 209 if (!usb3) 210 return -ENOMEM; 211 212 usb3->dev = dev; 213 usb3->mdiodev = mdiodev; 214 215 of_id = of_match_device(bcm_ns_usb3_id_table, dev); 216 if (!of_id) 217 return -EINVAL; 218 usb3->family = (enum bcm_ns_family)of_id->data; 219 220 syscon_np = of_parse_phandle(dev->of_node, "usb3-dmp-syscon", 0); 221 err = of_address_to_resource(syscon_np, 0, &res); 222 of_node_put(syscon_np); 223 if (err) 224 return err; 225 226 usb3->dmp = devm_ioremap_resource(dev, &res); 227 if (IS_ERR(usb3->dmp)) { 228 dev_err(dev, "Failed to map DMP regs\n"); 229 return PTR_ERR(usb3->dmp); 230 } 231 232 usb3->phy_write = bcm_ns_usb3_mdiodev_phy_write; 233 234 usb3->phy = devm_phy_create(dev, NULL, &ops); 235 if (IS_ERR(usb3->phy)) { 236 dev_err(dev, "Failed to create PHY\n"); 237 return PTR_ERR(usb3->phy); 238 } 239 240 phy_set_drvdata(usb3->phy, usb3); 241 242 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 243 244 return PTR_ERR_OR_ZERO(phy_provider); 245 } 246 247 static struct mdio_driver bcm_ns_usb3_mdio_driver = { 248 .mdiodrv = { 249 .driver = { 250 .name = "bcm_ns_mdio_usb3", 251 .of_match_table = bcm_ns_usb3_id_table, 252 }, 253 }, 254 .probe = bcm_ns_usb3_mdio_probe, 255 }; 256 257 /************************************************** 258 * Platform driver code 259 **************************************************/ 260 261 static int bcm_ns_usb3_wait_reg(struct bcm_ns_usb3 *usb3, void __iomem *addr, 262 u32 mask, u32 value, int usec) 263 { 264 u32 val; 265 int ret; 266 267 ret = readl_poll_timeout_atomic(addr, val, ((val & mask) == value), 268 10, usec); 269 if (ret) 270 dev_err(usb3->dev, "Timeout waiting for register %p\n", addr); 271 272 return ret; 273 } 274 275 static inline int bcm_ns_usb3_mii_mng_wait_idle(struct bcm_ns_usb3 *usb3) 276 { 277 return bcm_ns_usb3_wait_reg(usb3, usb3->ccb_mii + BCMA_CCB_MII_MNG_CTL, 278 0x0100, 0x0000, 279 BCM_NS_USB3_MII_MNG_TIMEOUT_US); 280 } 281 282 static int bcm_ns_usb3_platform_phy_write(struct bcm_ns_usb3 *usb3, u16 reg, 283 u16 value) 284 { 285 u32 tmp = 0; 286 int err; 287 288 err = bcm_ns_usb3_mii_mng_wait_idle(usb3); 289 if (err < 0) { 290 dev_err(usb3->dev, "Couldn't write 0x%08x value\n", value); 291 return err; 292 } 293 294 /* TODO: Use a proper MDIO bus layer */ 295 tmp |= 0x58020000; /* Magic value for MDIO PHY write */ 296 tmp |= reg << 18; 297 tmp |= value; 298 writel(tmp, usb3->ccb_mii + BCMA_CCB_MII_MNG_CMD_DATA); 299 300 return bcm_ns_usb3_mii_mng_wait_idle(usb3); 301 } 302 303 static int bcm_ns_usb3_probe(struct platform_device *pdev) 304 { 305 struct device *dev = &pdev->dev; 306 const struct of_device_id *of_id; 307 struct bcm_ns_usb3 *usb3; 308 struct resource *res; 309 struct phy_provider *phy_provider; 310 311 usb3 = devm_kzalloc(dev, sizeof(*usb3), GFP_KERNEL); 312 if (!usb3) 313 return -ENOMEM; 314 315 usb3->dev = dev; 316 317 of_id = of_match_device(bcm_ns_usb3_id_table, dev); 318 if (!of_id) 319 return -EINVAL; 320 usb3->family = (enum bcm_ns_family)of_id->data; 321 322 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmp"); 323 usb3->dmp = devm_ioremap_resource(dev, res); 324 if (IS_ERR(usb3->dmp)) { 325 dev_err(dev, "Failed to map DMP regs\n"); 326 return PTR_ERR(usb3->dmp); 327 } 328 329 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ccb-mii"); 330 usb3->ccb_mii = devm_ioremap_resource(dev, res); 331 if (IS_ERR(usb3->ccb_mii)) { 332 dev_err(dev, "Failed to map ChipCommon B MII regs\n"); 333 return PTR_ERR(usb3->ccb_mii); 334 } 335 336 /* Enable MDIO. Setting MDCDIV as 26 */ 337 writel(0x0000009a, usb3->ccb_mii + BCMA_CCB_MII_MNG_CTL); 338 339 /* Wait for MDIO? */ 340 udelay(2); 341 342 usb3->phy_write = bcm_ns_usb3_platform_phy_write; 343 344 usb3->phy = devm_phy_create(dev, NULL, &ops); 345 if (IS_ERR(usb3->phy)) { 346 dev_err(dev, "Failed to create PHY\n"); 347 return PTR_ERR(usb3->phy); 348 } 349 350 phy_set_drvdata(usb3->phy, usb3); 351 platform_set_drvdata(pdev, usb3); 352 353 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 354 if (!IS_ERR(phy_provider)) 355 dev_info(dev, "Registered Broadcom Northstar USB 3.0 PHY driver\n"); 356 357 return PTR_ERR_OR_ZERO(phy_provider); 358 } 359 360 static struct platform_driver bcm_ns_usb3_driver = { 361 .probe = bcm_ns_usb3_probe, 362 .driver = { 363 .name = "bcm_ns_usb3", 364 .of_match_table = bcm_ns_usb3_id_table, 365 }, 366 }; 367 368 static int __init bcm_ns_usb3_module_init(void) 369 { 370 int err; 371 372 /* 373 * For backward compatibility we register as MDIO and platform driver. 374 * After getting MDIO binding commonly used (e.g. switching all DT files 375 * to use it) we should deprecate the old binding and eventually drop 376 * support for it. 377 */ 378 379 err = mdio_driver_register(&bcm_ns_usb3_mdio_driver); 380 if (err) 381 return err; 382 383 err = platform_driver_register(&bcm_ns_usb3_driver); 384 if (err) 385 mdio_driver_unregister(&bcm_ns_usb3_mdio_driver); 386 387 return err; 388 } 389 module_init(bcm_ns_usb3_module_init); 390 391 static void __exit bcm_ns_usb3_module_exit(void) 392 { 393 platform_driver_unregister(&bcm_ns_usb3_driver); 394 mdio_driver_unregister(&bcm_ns_usb3_mdio_driver); 395 } 396 module_exit(bcm_ns_usb3_module_exit) 397 398 MODULE_LICENSE("GPL v2"); 399