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