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 MIIM_VSC8601_EPHY_CON 0x17 34 #define MIIM_VSC8601_EPHY_CON_INIT_SKEW 0x1120 35 #define MIIM_VSC8601_SKEW_CTRL 0x1c 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 genphy_update_link(phydev); 116 vitesse_parse_status(phydev); 117 118 return 0; 119 } 120 121 static int cis8204_config(struct phy_device *phydev) 122 { 123 /* Override PHY config settings */ 124 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT, 125 MIIM_CIS82xx_AUXCONSTAT_INIT); 126 127 genphy_config_aneg(phydev); 128 129 if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || 130 (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) || 131 (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)) 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 static int vsc8601_config(struct phy_device *phydev) 144 { 145 /* Configure some basic stuff */ 146 #ifdef CONFIG_SYS_VSC8601_SKEWFIX 147 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8601_EPHY_CON, 148 MIIM_VSC8601_EPHY_CON_INIT_SKEW); 149 #if defined(CONFIG_SYS_VSC8601_SKEW_TX) && defined(CONFIG_SYS_VSC8601_SKEW_RX) 150 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 1); 151 #define VSC8101_SKEW \ 152 ((CONFIG_SYS_VSC8601_SKEW_TX << 14) \ 153 | (CONFIG_SYS_VSC8601_SKEW_RX << 12)) 154 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8601_SKEW_CTRL, 155 VSC8101_SKEW); 156 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); 157 #endif 158 #endif 159 160 genphy_config_aneg(phydev); 161 162 return 0; 163 } 164 165 static int vsc8574_config(struct phy_device *phydev) 166 { 167 u32 val; 168 /* configure register 19G for MAC */ 169 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 170 PHY_EXT_PAGE_ACCESS_GENERAL); 171 172 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL19); 173 if (phydev->interface == PHY_INTERFACE_MODE_QSGMII) { 174 /* set bit 15:14 to '01' for QSGMII mode */ 175 val = (val & 0x3fff) | (1 << 14); 176 phy_write(phydev, MDIO_DEVAD_NONE, 177 MIIM_VSC8574_GENERAL19, val); 178 /* Enable 4 ports MAC QSGMII */ 179 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18, 180 MIIM_VSC8574_18G_QSGMII); 181 } else { 182 /* set bit 15:14 to '00' for SGMII mode */ 183 val = val & 0x3fff; 184 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL19, val); 185 /* Enable 4 ports MAC SGMII */ 186 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18, 187 MIIM_VSC8574_18G_SGMII); 188 } 189 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18); 190 /* When bit 15 is cleared the command has completed */ 191 while (val & MIIM_VSC8574_18G_CMDSTAT) 192 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18); 193 194 /* Enable Serdes Auto-negotiation */ 195 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 196 PHY_EXT_PAGE_ACCESS_EXTENDED3); 197 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_MAC_SERDES_CON); 198 val = val | MIIM_VSC8574_MAC_SERDES_ANEG; 199 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_MAC_SERDES_CON, val); 200 201 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); 202 203 genphy_config_aneg(phydev); 204 205 return 0; 206 } 207 208 static int vsc8514_config(struct phy_device *phydev) 209 { 210 u32 val; 211 int timeout = 1000000; 212 213 /* configure register to access 19G */ 214 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 215 PHY_EXT_PAGE_ACCESS_GENERAL); 216 217 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL19); 218 if (phydev->interface == PHY_INTERFACE_MODE_QSGMII) { 219 /* set bit 15:14 to '01' for QSGMII mode */ 220 val = (val & 0x3fff) | (1 << 14); 221 phy_write(phydev, MDIO_DEVAD_NONE, 222 MIIM_VSC8514_GENERAL19, val); 223 /* Enable 4 ports MAC QSGMII */ 224 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL18, 225 MIIM_VSC8514_18G_QSGMII); 226 } else { 227 /*TODO Add SGMII functionality once spec sheet 228 * for VSC8514 defines complete functionality 229 */ 230 } 231 232 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL18); 233 /* When bit 15 is cleared the command has completed */ 234 while ((val & MIIM_VSC8514_18G_CMDSTAT) && timeout--) 235 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL18); 236 237 if (0 == timeout) { 238 printf("PHY 8514 config failed\n"); 239 return -1; 240 } 241 242 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); 243 244 /* configure register to access 23 */ 245 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL23); 246 /* set bits 10:8 to '000' */ 247 val = (val & 0xf8ff); 248 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL23, val); 249 250 /* Enable Serdes Auto-negotiation */ 251 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 252 PHY_EXT_PAGE_ACCESS_EXTENDED3); 253 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_MAC_SERDES_CON); 254 val = val | MIIM_VSC8574_MAC_SERDES_ANEG; 255 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_MAC_SERDES_CON, val); 256 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); 257 258 genphy_config_aneg(phydev); 259 260 return 0; 261 } 262 263 static int vsc8664_config(struct phy_device *phydev) 264 { 265 u32 val; 266 267 /* Enable MAC interface auto-negotiation */ 268 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); 269 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_EPHY_CON); 270 val |= (1 << 13); 271 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_EPHY_CON, val); 272 273 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 274 PHY_EXT_PAGE_ACCESS_EXTENDED); 275 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_SERDES_AND_SIGDET); 276 val |= (1 << 11); 277 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_SERDES_AND_SIGDET, val); 278 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); 279 280 /* Enable LED blink */ 281 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_LED_CON); 282 val &= ~(1 << 2); 283 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_LED_CON, val); 284 285 genphy_config_aneg(phydev); 286 287 return 0; 288 } 289 290 static struct phy_driver VSC8211_driver = { 291 .name = "Vitesse VSC8211", 292 .uid = 0xfc4b0, 293 .mask = 0xffff0, 294 .features = PHY_GBIT_FEATURES, 295 .config = &vitesse_config, 296 .startup = &vitesse_startup, 297 .shutdown = &genphy_shutdown, 298 }; 299 300 static struct phy_driver VSC8221_driver = { 301 .name = "Vitesse VSC8221", 302 .uid = 0xfc550, 303 .mask = 0xffff0, 304 .features = PHY_GBIT_FEATURES, 305 .config = &genphy_config_aneg, 306 .startup = &vitesse_startup, 307 .shutdown = &genphy_shutdown, 308 }; 309 310 static struct phy_driver VSC8244_driver = { 311 .name = "Vitesse VSC8244", 312 .uid = 0xfc6c0, 313 .mask = 0xffff0, 314 .features = PHY_GBIT_FEATURES, 315 .config = &genphy_config_aneg, 316 .startup = &vitesse_startup, 317 .shutdown = &genphy_shutdown, 318 }; 319 320 static struct phy_driver VSC8234_driver = { 321 .name = "Vitesse VSC8234", 322 .uid = 0xfc620, 323 .mask = 0xffff0, 324 .features = PHY_GBIT_FEATURES, 325 .config = &genphy_config_aneg, 326 .startup = &vitesse_startup, 327 .shutdown = &genphy_shutdown, 328 }; 329 330 static struct phy_driver VSC8574_driver = { 331 .name = "Vitesse VSC8574", 332 .uid = 0x704a0, 333 .mask = 0xffff0, 334 .features = PHY_GBIT_FEATURES, 335 .config = &vsc8574_config, 336 .startup = &vitesse_startup, 337 .shutdown = &genphy_shutdown, 338 }; 339 340 static struct phy_driver VSC8514_driver = { 341 .name = "Vitesse VSC8514", 342 .uid = 0x70670, 343 .mask = 0xffff0, 344 .features = PHY_GBIT_FEATURES, 345 .config = &vsc8514_config, 346 .startup = &vitesse_startup, 347 .shutdown = &genphy_shutdown, 348 }; 349 350 static struct phy_driver VSC8601_driver = { 351 .name = "Vitesse VSC8601", 352 .uid = 0x70420, 353 .mask = 0xffff0, 354 .features = PHY_GBIT_FEATURES, 355 .config = &vsc8601_config, 356 .startup = &vitesse_startup, 357 .shutdown = &genphy_shutdown, 358 }; 359 360 static struct phy_driver VSC8641_driver = { 361 .name = "Vitesse VSC8641", 362 .uid = 0x70430, 363 .mask = 0xffff0, 364 .features = PHY_GBIT_FEATURES, 365 .config = &genphy_config_aneg, 366 .startup = &vitesse_startup, 367 .shutdown = &genphy_shutdown, 368 }; 369 370 static struct phy_driver VSC8662_driver = { 371 .name = "Vitesse VSC8662", 372 .uid = 0x70660, 373 .mask = 0xffff0, 374 .features = PHY_GBIT_FEATURES, 375 .config = &genphy_config_aneg, 376 .startup = &vitesse_startup, 377 .shutdown = &genphy_shutdown, 378 }; 379 380 static struct phy_driver VSC8664_driver = { 381 .name = "Vitesse VSC8664", 382 .uid = 0x70660, 383 .mask = 0xffff0, 384 .features = PHY_GBIT_FEATURES, 385 .config = &vsc8664_config, 386 .startup = &vitesse_startup, 387 .shutdown = &genphy_shutdown, 388 }; 389 390 /* Vitesse bought Cicada, so we'll put these here */ 391 static struct phy_driver cis8201_driver = { 392 .name = "CIS8201", 393 .uid = 0xfc410, 394 .mask = 0xffff0, 395 .features = PHY_GBIT_FEATURES, 396 .config = &vitesse_config, 397 .startup = &vitesse_startup, 398 .shutdown = &genphy_shutdown, 399 }; 400 401 static struct phy_driver cis8204_driver = { 402 .name = "Cicada Cis8204", 403 .uid = 0xfc440, 404 .mask = 0xffff0, 405 .features = PHY_GBIT_FEATURES, 406 .config = &cis8204_config, 407 .startup = &vitesse_startup, 408 .shutdown = &genphy_shutdown, 409 }; 410 411 int phy_vitesse_init(void) 412 { 413 phy_register(&VSC8641_driver); 414 phy_register(&VSC8601_driver); 415 phy_register(&VSC8234_driver); 416 phy_register(&VSC8244_driver); 417 phy_register(&VSC8211_driver); 418 phy_register(&VSC8221_driver); 419 phy_register(&VSC8574_driver); 420 phy_register(&VSC8514_driver); 421 phy_register(&VSC8662_driver); 422 phy_register(&VSC8664_driver); 423 phy_register(&cis8201_driver); 424 phy_register(&cis8204_driver); 425 426 return 0; 427 } 428