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