1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Vitesse PHY drivers 4 * 5 * Copyright 2010-2014 Freescale Semiconductor, Inc. 6 * Original Author: Andy Fleming 7 * Add vsc8662 phy support - Priyanka Jain 8 */ 9 #include <miiphy.h> 10 11 /* Cicada Auxiliary Control/Status Register */ 12 #define MIIM_CIS82xx_AUX_CONSTAT 0x1c 13 #define MIIM_CIS82xx_AUXCONSTAT_INIT 0x0004 14 #define MIIM_CIS82xx_AUXCONSTAT_DUPLEX 0x0020 15 #define MIIM_CIS82xx_AUXCONSTAT_SPEED 0x0018 16 #define MIIM_CIS82xx_AUXCONSTAT_GBIT 0x0010 17 #define MIIM_CIS82xx_AUXCONSTAT_100 0x0008 18 19 /* Cicada Extended Control Register 1 */ 20 #define MIIM_CIS82xx_EXT_CON1 0x17 21 #define MIIM_CIS8201_EXTCON1_INIT 0x0000 22 23 /* Cicada 8204 Extended PHY Control Register 1 */ 24 #define MIIM_CIS8204_EPHY_CON 0x17 25 #define MIIM_CIS8204_EPHYCON_INIT 0x0006 26 #define MIIM_CIS8204_EPHYCON_RGMII 0x1100 27 28 /* Cicada 8204 Serial LED Control Register */ 29 #define MIIM_CIS8204_SLED_CON 0x1b 30 #define MIIM_CIS8204_SLEDCON_INIT 0x1115 31 32 /* Vitesse VSC8601 Extended PHY Control Register 1 */ 33 #define MII_VSC8601_EPHY_CTL 0x17 34 #define MII_VSC8601_EPHY_CTL_RGMII_SKEW (1 << 8) 35 36 #define PHY_EXT_PAGE_ACCESS 0x1f 37 #define PHY_EXT_PAGE_ACCESS_GENERAL 0x10 38 #define PHY_EXT_PAGE_ACCESS_EXTENDED3 0x3 39 40 /* Vitesse VSC8574 control register */ 41 #define MIIM_VSC8574_MAC_SERDES_CON 0x10 42 #define MIIM_VSC8574_MAC_SERDES_ANEG 0x80 43 #define MIIM_VSC8574_GENERAL18 0x12 44 #define MIIM_VSC8574_GENERAL19 0x13 45 46 /* Vitesse VSC8574 gerenal purpose register 18 */ 47 #define MIIM_VSC8574_18G_SGMII 0x80f0 48 #define MIIM_VSC8574_18G_QSGMII 0x80e0 49 #define MIIM_VSC8574_18G_CMDSTAT 0x8000 50 51 /* Vitesse VSC8514 control register */ 52 #define MIIM_VSC8514_MAC_SERDES_CON 0x10 53 #define MIIM_VSC8514_GENERAL18 0x12 54 #define MIIM_VSC8514_GENERAL19 0x13 55 #define MIIM_VSC8514_GENERAL23 0x17 56 57 /* Vitesse VSC8514 gerenal purpose register 18 */ 58 #define MIIM_VSC8514_18G_QSGMII 0x80e0 59 #define MIIM_VSC8514_18G_CMDSTAT 0x8000 60 61 /* Vitesse VSC8664 Control/Status Register */ 62 #define MIIM_VSC8664_SERDES_AND_SIGDET 0x13 63 #define MIIM_VSC8664_ADDITIONAL_DEV 0x16 64 #define MIIM_VSC8664_EPHY_CON 0x17 65 #define MIIM_VSC8664_LED_CON 0x1E 66 67 #define PHY_EXT_PAGE_ACCESS_EXTENDED 0x0001 68 69 /* CIS8201 */ 70 static int vitesse_config(struct phy_device *phydev) 71 { 72 /* Override PHY config settings */ 73 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT, 74 MIIM_CIS82xx_AUXCONSTAT_INIT); 75 /* Set up the interface mode */ 76 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_EXT_CON1, 77 MIIM_CIS8201_EXTCON1_INIT); 78 79 genphy_config_aneg(phydev); 80 81 return 0; 82 } 83 84 static int vitesse_parse_status(struct phy_device *phydev) 85 { 86 int speed; 87 int mii_reg; 88 89 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT); 90 91 if (mii_reg & MIIM_CIS82xx_AUXCONSTAT_DUPLEX) 92 phydev->duplex = DUPLEX_FULL; 93 else 94 phydev->duplex = DUPLEX_HALF; 95 96 speed = mii_reg & MIIM_CIS82xx_AUXCONSTAT_SPEED; 97 switch (speed) { 98 case MIIM_CIS82xx_AUXCONSTAT_GBIT: 99 phydev->speed = SPEED_1000; 100 break; 101 case MIIM_CIS82xx_AUXCONSTAT_100: 102 phydev->speed = SPEED_100; 103 break; 104 default: 105 phydev->speed = SPEED_10; 106 break; 107 } 108 109 return 0; 110 } 111 112 static int vitesse_startup(struct phy_device *phydev) 113 { 114 int ret; 115 116 ret = genphy_update_link(phydev); 117 if (ret) 118 return ret; 119 return vitesse_parse_status(phydev); 120 } 121 122 static int cis8204_config(struct phy_device *phydev) 123 { 124 /* Override PHY config settings */ 125 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT, 126 MIIM_CIS82xx_AUXCONSTAT_INIT); 127 128 genphy_config_aneg(phydev); 129 130 if (phy_interface_is_rgmii(phydev)) 131 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8204_EPHY_CON, 132 MIIM_CIS8204_EPHYCON_INIT | 133 MIIM_CIS8204_EPHYCON_RGMII); 134 else 135 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8204_EPHY_CON, 136 MIIM_CIS8204_EPHYCON_INIT); 137 138 return 0; 139 } 140 141 /* Vitesse VSC8601 */ 142 /* This adds a skew for both TX and RX clocks, so the skew should only be 143 * applied to "rgmii-id" interfaces. It may not work as expected 144 * on "rgmii-txid", "rgmii-rxid" or "rgmii" interfaces. */ 145 static int vsc8601_add_skew(struct phy_device *phydev) 146 { 147 int ret; 148 149 ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_VSC8601_EPHY_CTL); 150 if (ret < 0) 151 return ret; 152 153 ret |= MII_VSC8601_EPHY_CTL_RGMII_SKEW; 154 return phy_write(phydev, MDIO_DEVAD_NONE, MII_VSC8601_EPHY_CTL, ret); 155 } 156 157 static int vsc8601_config(struct phy_device *phydev) 158 { 159 int ret = 0; 160 161 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) 162 ret = vsc8601_add_skew(phydev); 163 164 if (ret < 0) 165 return ret; 166 167 return genphy_config_aneg(phydev); 168 } 169 170 static int vsc8574_config(struct phy_device *phydev) 171 { 172 u32 val; 173 /* configure register 19G for MAC */ 174 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 175 PHY_EXT_PAGE_ACCESS_GENERAL); 176 177 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL19); 178 if (phydev->interface == PHY_INTERFACE_MODE_QSGMII) { 179 /* set bit 15:14 to '01' for QSGMII mode */ 180 val = (val & 0x3fff) | (1 << 14); 181 phy_write(phydev, MDIO_DEVAD_NONE, 182 MIIM_VSC8574_GENERAL19, val); 183 /* Enable 4 ports MAC QSGMII */ 184 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18, 185 MIIM_VSC8574_18G_QSGMII); 186 } else { 187 /* set bit 15:14 to '00' for SGMII mode */ 188 val = val & 0x3fff; 189 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL19, val); 190 /* Enable 4 ports MAC SGMII */ 191 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18, 192 MIIM_VSC8574_18G_SGMII); 193 } 194 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18); 195 /* When bit 15 is cleared the command has completed */ 196 while (val & MIIM_VSC8574_18G_CMDSTAT) 197 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18); 198 199 /* Enable Serdes Auto-negotiation */ 200 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 201 PHY_EXT_PAGE_ACCESS_EXTENDED3); 202 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_MAC_SERDES_CON); 203 val = val | MIIM_VSC8574_MAC_SERDES_ANEG; 204 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_MAC_SERDES_CON, val); 205 206 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); 207 208 genphy_config_aneg(phydev); 209 210 return 0; 211 } 212 213 static int vsc8514_config(struct phy_device *phydev) 214 { 215 u32 val; 216 int timeout = 1000000; 217 218 /* configure register to access 19G */ 219 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 220 PHY_EXT_PAGE_ACCESS_GENERAL); 221 222 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL19); 223 if (phydev->interface == PHY_INTERFACE_MODE_QSGMII) { 224 /* set bit 15:14 to '01' for QSGMII mode */ 225 val = (val & 0x3fff) | (1 << 14); 226 phy_write(phydev, MDIO_DEVAD_NONE, 227 MIIM_VSC8514_GENERAL19, val); 228 /* Enable 4 ports MAC QSGMII */ 229 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL18, 230 MIIM_VSC8514_18G_QSGMII); 231 } else { 232 /*TODO Add SGMII functionality once spec sheet 233 * for VSC8514 defines complete functionality 234 */ 235 } 236 237 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL18); 238 /* When bit 15 is cleared the command has completed */ 239 while ((val & MIIM_VSC8514_18G_CMDSTAT) && timeout--) 240 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL18); 241 242 if (0 == timeout) { 243 printf("PHY 8514 config failed\n"); 244 return -1; 245 } 246 247 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); 248 249 /* configure register to access 23 */ 250 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL23); 251 /* set bits 10:8 to '000' */ 252 val = (val & 0xf8ff); 253 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL23, val); 254 255 /* Enable Serdes Auto-negotiation */ 256 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 257 PHY_EXT_PAGE_ACCESS_EXTENDED3); 258 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_MAC_SERDES_CON); 259 val = val | MIIM_VSC8574_MAC_SERDES_ANEG; 260 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_MAC_SERDES_CON, val); 261 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); 262 263 genphy_config_aneg(phydev); 264 265 return 0; 266 } 267 268 static int vsc8664_config(struct phy_device *phydev) 269 { 270 u32 val; 271 272 /* Enable MAC interface auto-negotiation */ 273 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); 274 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_EPHY_CON); 275 val |= (1 << 13); 276 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_EPHY_CON, val); 277 278 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 279 PHY_EXT_PAGE_ACCESS_EXTENDED); 280 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_SERDES_AND_SIGDET); 281 val |= (1 << 11); 282 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_SERDES_AND_SIGDET, val); 283 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); 284 285 /* Enable LED blink */ 286 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_LED_CON); 287 val &= ~(1 << 2); 288 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_LED_CON, val); 289 290 genphy_config_aneg(phydev); 291 292 return 0; 293 } 294 295 static struct phy_driver VSC8211_driver = { 296 .name = "Vitesse VSC8211", 297 .uid = 0xfc4b0, 298 .mask = 0xffff0, 299 .features = PHY_GBIT_FEATURES, 300 .config = &vitesse_config, 301 .startup = &vitesse_startup, 302 .shutdown = &genphy_shutdown, 303 }; 304 305 static struct phy_driver VSC8221_driver = { 306 .name = "Vitesse VSC8221", 307 .uid = 0xfc550, 308 .mask = 0xffff0, 309 .features = PHY_GBIT_FEATURES, 310 .config = &genphy_config_aneg, 311 .startup = &vitesse_startup, 312 .shutdown = &genphy_shutdown, 313 }; 314 315 static struct phy_driver VSC8244_driver = { 316 .name = "Vitesse VSC8244", 317 .uid = 0xfc6c0, 318 .mask = 0xffff0, 319 .features = PHY_GBIT_FEATURES, 320 .config = &genphy_config_aneg, 321 .startup = &vitesse_startup, 322 .shutdown = &genphy_shutdown, 323 }; 324 325 static struct phy_driver VSC8234_driver = { 326 .name = "Vitesse VSC8234", 327 .uid = 0xfc620, 328 .mask = 0xffff0, 329 .features = PHY_GBIT_FEATURES, 330 .config = &genphy_config_aneg, 331 .startup = &vitesse_startup, 332 .shutdown = &genphy_shutdown, 333 }; 334 335 static struct phy_driver VSC8574_driver = { 336 .name = "Vitesse VSC8574", 337 .uid = 0x704a0, 338 .mask = 0xffff0, 339 .features = PHY_GBIT_FEATURES, 340 .config = &vsc8574_config, 341 .startup = &vitesse_startup, 342 .shutdown = &genphy_shutdown, 343 }; 344 345 static struct phy_driver VSC8514_driver = { 346 .name = "Vitesse VSC8514", 347 .uid = 0x70670, 348 .mask = 0xffff0, 349 .features = PHY_GBIT_FEATURES, 350 .config = &vsc8514_config, 351 .startup = &vitesse_startup, 352 .shutdown = &genphy_shutdown, 353 }; 354 355 static struct phy_driver VSC8584_driver = { 356 .name = "Vitesse VSC8584", 357 .uid = 0x707c0, 358 .mask = 0xffff0, 359 .features = PHY_GBIT_FEATURES, 360 .config = &vsc8574_config, 361 .startup = &vitesse_startup, 362 .shutdown = &genphy_shutdown, 363 }; 364 365 static struct phy_driver VSC8601_driver = { 366 .name = "Vitesse VSC8601", 367 .uid = 0x70420, 368 .mask = 0xffff0, 369 .features = PHY_GBIT_FEATURES, 370 .config = &vsc8601_config, 371 .startup = &vitesse_startup, 372 .shutdown = &genphy_shutdown, 373 }; 374 375 static struct phy_driver VSC8641_driver = { 376 .name = "Vitesse VSC8641", 377 .uid = 0x70430, 378 .mask = 0xffff0, 379 .features = PHY_GBIT_FEATURES, 380 .config = &genphy_config_aneg, 381 .startup = &vitesse_startup, 382 .shutdown = &genphy_shutdown, 383 }; 384 385 static struct phy_driver VSC8662_driver = { 386 .name = "Vitesse VSC8662", 387 .uid = 0x70660, 388 .mask = 0xffff0, 389 .features = PHY_GBIT_FEATURES, 390 .config = &genphy_config_aneg, 391 .startup = &vitesse_startup, 392 .shutdown = &genphy_shutdown, 393 }; 394 395 static struct phy_driver VSC8664_driver = { 396 .name = "Vitesse VSC8664", 397 .uid = 0x70660, 398 .mask = 0xffff0, 399 .features = PHY_GBIT_FEATURES, 400 .config = &vsc8664_config, 401 .startup = &vitesse_startup, 402 .shutdown = &genphy_shutdown, 403 }; 404 405 /* Vitesse bought Cicada, so we'll put these here */ 406 static struct phy_driver cis8201_driver = { 407 .name = "CIS8201", 408 .uid = 0xfc410, 409 .mask = 0xffff0, 410 .features = PHY_GBIT_FEATURES, 411 .config = &vitesse_config, 412 .startup = &vitesse_startup, 413 .shutdown = &genphy_shutdown, 414 }; 415 416 static struct phy_driver cis8204_driver = { 417 .name = "Cicada Cis8204", 418 .uid = 0xfc440, 419 .mask = 0xffff0, 420 .features = PHY_GBIT_FEATURES, 421 .config = &cis8204_config, 422 .startup = &vitesse_startup, 423 .shutdown = &genphy_shutdown, 424 }; 425 426 int phy_vitesse_init(void) 427 { 428 phy_register(&VSC8641_driver); 429 phy_register(&VSC8601_driver); 430 phy_register(&VSC8234_driver); 431 phy_register(&VSC8244_driver); 432 phy_register(&VSC8211_driver); 433 phy_register(&VSC8221_driver); 434 phy_register(&VSC8574_driver); 435 phy_register(&VSC8584_driver); 436 phy_register(&VSC8514_driver); 437 phy_register(&VSC8662_driver); 438 phy_register(&VSC8664_driver); 439 phy_register(&cis8201_driver); 440 phy_register(&cis8204_driver); 441 442 return 0; 443 } 444