1 /* 2 * Vitesse PHY drivers 3 * 4 * Copyright 2010-2014 Freescale Semiconductor, Inc. 5 * Original Author: Andy Fleming 6 * Add vsc8662 phy support - Priyanka Jain 7 * SPDX-License-Identifier: GPL-2.0+ 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 ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || 131 (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) || 132 (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)) 133 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8204_EPHY_CON, 134 MIIM_CIS8204_EPHYCON_INIT | 135 MIIM_CIS8204_EPHYCON_RGMII); 136 else 137 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8204_EPHY_CON, 138 MIIM_CIS8204_EPHYCON_INIT); 139 140 return 0; 141 } 142 143 /* Vitesse VSC8601 */ 144 /* This adds a skew for both TX and RX clocks, so the skew should only be 145 * applied to "rgmii-id" interfaces. It may not work as expected 146 * on "rgmii-txid", "rgmii-rxid" or "rgmii" interfaces. */ 147 static int vsc8601_add_skew(struct phy_device *phydev) 148 { 149 int ret; 150 151 ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_VSC8601_EPHY_CTL); 152 if (ret < 0) 153 return ret; 154 155 ret |= MII_VSC8601_EPHY_CTL_RGMII_SKEW; 156 return phy_write(phydev, MDIO_DEVAD_NONE, MII_VSC8601_EPHY_CTL, ret); 157 } 158 159 static int vsc8601_config(struct phy_device *phydev) 160 { 161 int ret = 0; 162 163 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) 164 ret = vsc8601_add_skew(phydev); 165 166 if (ret < 0) 167 return ret; 168 169 return genphy_config_aneg(phydev); 170 } 171 172 static int vsc8574_config(struct phy_device *phydev) 173 { 174 u32 val; 175 /* configure register 19G for MAC */ 176 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 177 PHY_EXT_PAGE_ACCESS_GENERAL); 178 179 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL19); 180 if (phydev->interface == PHY_INTERFACE_MODE_QSGMII) { 181 /* set bit 15:14 to '01' for QSGMII mode */ 182 val = (val & 0x3fff) | (1 << 14); 183 phy_write(phydev, MDIO_DEVAD_NONE, 184 MIIM_VSC8574_GENERAL19, val); 185 /* Enable 4 ports MAC QSGMII */ 186 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18, 187 MIIM_VSC8574_18G_QSGMII); 188 } else { 189 /* set bit 15:14 to '00' for SGMII mode */ 190 val = val & 0x3fff; 191 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL19, val); 192 /* Enable 4 ports MAC SGMII */ 193 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18, 194 MIIM_VSC8574_18G_SGMII); 195 } 196 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18); 197 /* When bit 15 is cleared the command has completed */ 198 while (val & MIIM_VSC8574_18G_CMDSTAT) 199 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18); 200 201 /* Enable Serdes Auto-negotiation */ 202 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 203 PHY_EXT_PAGE_ACCESS_EXTENDED3); 204 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_MAC_SERDES_CON); 205 val = val | MIIM_VSC8574_MAC_SERDES_ANEG; 206 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_MAC_SERDES_CON, val); 207 208 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); 209 210 genphy_config_aneg(phydev); 211 212 return 0; 213 } 214 215 static int vsc8514_config(struct phy_device *phydev) 216 { 217 u32 val; 218 int timeout = 1000000; 219 220 /* configure register to access 19G */ 221 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 222 PHY_EXT_PAGE_ACCESS_GENERAL); 223 224 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL19); 225 if (phydev->interface == PHY_INTERFACE_MODE_QSGMII) { 226 /* set bit 15:14 to '01' for QSGMII mode */ 227 val = (val & 0x3fff) | (1 << 14); 228 phy_write(phydev, MDIO_DEVAD_NONE, 229 MIIM_VSC8514_GENERAL19, val); 230 /* Enable 4 ports MAC QSGMII */ 231 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL18, 232 MIIM_VSC8514_18G_QSGMII); 233 } else { 234 /*TODO Add SGMII functionality once spec sheet 235 * for VSC8514 defines complete functionality 236 */ 237 } 238 239 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL18); 240 /* When bit 15 is cleared the command has completed */ 241 while ((val & MIIM_VSC8514_18G_CMDSTAT) && timeout--) 242 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL18); 243 244 if (0 == timeout) { 245 printf("PHY 8514 config failed\n"); 246 return -1; 247 } 248 249 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); 250 251 /* configure register to access 23 */ 252 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL23); 253 /* set bits 10:8 to '000' */ 254 val = (val & 0xf8ff); 255 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL23, val); 256 257 /* Enable Serdes Auto-negotiation */ 258 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 259 PHY_EXT_PAGE_ACCESS_EXTENDED3); 260 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_MAC_SERDES_CON); 261 val = val | MIIM_VSC8574_MAC_SERDES_ANEG; 262 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_MAC_SERDES_CON, val); 263 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); 264 265 genphy_config_aneg(phydev); 266 267 return 0; 268 } 269 270 static int vsc8664_config(struct phy_device *phydev) 271 { 272 u32 val; 273 274 /* Enable MAC interface auto-negotiation */ 275 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); 276 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_EPHY_CON); 277 val |= (1 << 13); 278 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_EPHY_CON, val); 279 280 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 281 PHY_EXT_PAGE_ACCESS_EXTENDED); 282 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_SERDES_AND_SIGDET); 283 val |= (1 << 11); 284 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_SERDES_AND_SIGDET, val); 285 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); 286 287 /* Enable LED blink */ 288 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_LED_CON); 289 val &= ~(1 << 2); 290 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_LED_CON, val); 291 292 genphy_config_aneg(phydev); 293 294 return 0; 295 } 296 297 static struct phy_driver VSC8211_driver = { 298 .name = "Vitesse VSC8211", 299 .uid = 0xfc4b0, 300 .mask = 0xffff0, 301 .features = PHY_GBIT_FEATURES, 302 .config = &vitesse_config, 303 .startup = &vitesse_startup, 304 .shutdown = &genphy_shutdown, 305 }; 306 307 static struct phy_driver VSC8221_driver = { 308 .name = "Vitesse VSC8221", 309 .uid = 0xfc550, 310 .mask = 0xffff0, 311 .features = PHY_GBIT_FEATURES, 312 .config = &genphy_config_aneg, 313 .startup = &vitesse_startup, 314 .shutdown = &genphy_shutdown, 315 }; 316 317 static struct phy_driver VSC8244_driver = { 318 .name = "Vitesse VSC8244", 319 .uid = 0xfc6c0, 320 .mask = 0xffff0, 321 .features = PHY_GBIT_FEATURES, 322 .config = &genphy_config_aneg, 323 .startup = &vitesse_startup, 324 .shutdown = &genphy_shutdown, 325 }; 326 327 static struct phy_driver VSC8234_driver = { 328 .name = "Vitesse VSC8234", 329 .uid = 0xfc620, 330 .mask = 0xffff0, 331 .features = PHY_GBIT_FEATURES, 332 .config = &genphy_config_aneg, 333 .startup = &vitesse_startup, 334 .shutdown = &genphy_shutdown, 335 }; 336 337 static struct phy_driver VSC8574_driver = { 338 .name = "Vitesse VSC8574", 339 .uid = 0x704a0, 340 .mask = 0xffff0, 341 .features = PHY_GBIT_FEATURES, 342 .config = &vsc8574_config, 343 .startup = &vitesse_startup, 344 .shutdown = &genphy_shutdown, 345 }; 346 347 static struct phy_driver VSC8514_driver = { 348 .name = "Vitesse VSC8514", 349 .uid = 0x70670, 350 .mask = 0xffff0, 351 .features = PHY_GBIT_FEATURES, 352 .config = &vsc8514_config, 353 .startup = &vitesse_startup, 354 .shutdown = &genphy_shutdown, 355 }; 356 357 static struct phy_driver VSC8584_driver = { 358 .name = "Vitesse VSC8584", 359 .uid = 0x707c0, 360 .mask = 0xffff0, 361 .features = PHY_GBIT_FEATURES, 362 .config = &vsc8574_config, 363 .startup = &vitesse_startup, 364 .shutdown = &genphy_shutdown, 365 }; 366 367 static struct phy_driver VSC8601_driver = { 368 .name = "Vitesse VSC8601", 369 .uid = 0x70420, 370 .mask = 0xffff0, 371 .features = PHY_GBIT_FEATURES, 372 .config = &vsc8601_config, 373 .startup = &vitesse_startup, 374 .shutdown = &genphy_shutdown, 375 }; 376 377 static struct phy_driver VSC8641_driver = { 378 .name = "Vitesse VSC8641", 379 .uid = 0x70430, 380 .mask = 0xffff0, 381 .features = PHY_GBIT_FEATURES, 382 .config = &genphy_config_aneg, 383 .startup = &vitesse_startup, 384 .shutdown = &genphy_shutdown, 385 }; 386 387 static struct phy_driver VSC8662_driver = { 388 .name = "Vitesse VSC8662", 389 .uid = 0x70660, 390 .mask = 0xffff0, 391 .features = PHY_GBIT_FEATURES, 392 .config = &genphy_config_aneg, 393 .startup = &vitesse_startup, 394 .shutdown = &genphy_shutdown, 395 }; 396 397 static struct phy_driver VSC8664_driver = { 398 .name = "Vitesse VSC8664", 399 .uid = 0x70660, 400 .mask = 0xffff0, 401 .features = PHY_GBIT_FEATURES, 402 .config = &vsc8664_config, 403 .startup = &vitesse_startup, 404 .shutdown = &genphy_shutdown, 405 }; 406 407 /* Vitesse bought Cicada, so we'll put these here */ 408 static struct phy_driver cis8201_driver = { 409 .name = "CIS8201", 410 .uid = 0xfc410, 411 .mask = 0xffff0, 412 .features = PHY_GBIT_FEATURES, 413 .config = &vitesse_config, 414 .startup = &vitesse_startup, 415 .shutdown = &genphy_shutdown, 416 }; 417 418 static struct phy_driver cis8204_driver = { 419 .name = "Cicada Cis8204", 420 .uid = 0xfc440, 421 .mask = 0xffff0, 422 .features = PHY_GBIT_FEATURES, 423 .config = &cis8204_config, 424 .startup = &vitesse_startup, 425 .shutdown = &genphy_shutdown, 426 }; 427 428 int phy_vitesse_init(void) 429 { 430 phy_register(&VSC8641_driver); 431 phy_register(&VSC8601_driver); 432 phy_register(&VSC8234_driver); 433 phy_register(&VSC8244_driver); 434 phy_register(&VSC8211_driver); 435 phy_register(&VSC8221_driver); 436 phy_register(&VSC8574_driver); 437 phy_register(&VSC8584_driver); 438 phy_register(&VSC8514_driver); 439 phy_register(&VSC8662_driver); 440 phy_register(&VSC8664_driver); 441 phy_register(&cis8201_driver); 442 phy_register(&cis8204_driver); 443 444 return 0; 445 } 446