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) || 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 genphy_config_aneg(phydev); 251 252 return 0; 253 } 254 255 static int vsc8664_config(struct phy_device *phydev) 256 { 257 u32 val; 258 259 /* Enable MAC interface auto-negotiation */ 260 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); 261 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_EPHY_CON); 262 val |= (1 << 13); 263 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_EPHY_CON, val); 264 265 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 266 PHY_EXT_PAGE_ACCESS_EXTENDED); 267 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_SERDES_AND_SIGDET); 268 val |= (1 << 11); 269 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_SERDES_AND_SIGDET, val); 270 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); 271 272 /* Enable LED blink */ 273 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_LED_CON); 274 val &= ~(1 << 2); 275 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_LED_CON, val); 276 277 genphy_config_aneg(phydev); 278 279 return 0; 280 } 281 282 static struct phy_driver VSC8211_driver = { 283 .name = "Vitesse VSC8211", 284 .uid = 0xfc4b0, 285 .mask = 0xffff0, 286 .features = PHY_GBIT_FEATURES, 287 .config = &vitesse_config, 288 .startup = &vitesse_startup, 289 .shutdown = &genphy_shutdown, 290 }; 291 292 static struct phy_driver VSC8221_driver = { 293 .name = "Vitesse VSC8221", 294 .uid = 0xfc550, 295 .mask = 0xffff0, 296 .features = PHY_GBIT_FEATURES, 297 .config = &genphy_config_aneg, 298 .startup = &vitesse_startup, 299 .shutdown = &genphy_shutdown, 300 }; 301 302 static struct phy_driver VSC8244_driver = { 303 .name = "Vitesse VSC8244", 304 .uid = 0xfc6c0, 305 .mask = 0xffff0, 306 .features = PHY_GBIT_FEATURES, 307 .config = &genphy_config_aneg, 308 .startup = &vitesse_startup, 309 .shutdown = &genphy_shutdown, 310 }; 311 312 static struct phy_driver VSC8234_driver = { 313 .name = "Vitesse VSC8234", 314 .uid = 0xfc620, 315 .mask = 0xffff0, 316 .features = PHY_GBIT_FEATURES, 317 .config = &genphy_config_aneg, 318 .startup = &vitesse_startup, 319 .shutdown = &genphy_shutdown, 320 }; 321 322 static struct phy_driver VSC8574_driver = { 323 .name = "Vitesse VSC8574", 324 .uid = 0x704a0, 325 .mask = 0xffff0, 326 .features = PHY_GBIT_FEATURES, 327 .config = &vsc8574_config, 328 .startup = &vitesse_startup, 329 .shutdown = &genphy_shutdown, 330 }; 331 332 static struct phy_driver VSC8514_driver = { 333 .name = "Vitesse VSC8514", 334 .uid = 0x70670, 335 .mask = 0xffff0, 336 .features = PHY_GBIT_FEATURES, 337 .config = &vsc8514_config, 338 .startup = &vitesse_startup, 339 .shutdown = &genphy_shutdown, 340 }; 341 342 static struct phy_driver VSC8601_driver = { 343 .name = "Vitesse VSC8601", 344 .uid = 0x70420, 345 .mask = 0xffff0, 346 .features = PHY_GBIT_FEATURES, 347 .config = &vsc8601_config, 348 .startup = &vitesse_startup, 349 .shutdown = &genphy_shutdown, 350 }; 351 352 static struct phy_driver VSC8641_driver = { 353 .name = "Vitesse VSC8641", 354 .uid = 0x70430, 355 .mask = 0xffff0, 356 .features = PHY_GBIT_FEATURES, 357 .config = &genphy_config_aneg, 358 .startup = &vitesse_startup, 359 .shutdown = &genphy_shutdown, 360 }; 361 362 static struct phy_driver VSC8662_driver = { 363 .name = "Vitesse VSC8662", 364 .uid = 0x70660, 365 .mask = 0xffff0, 366 .features = PHY_GBIT_FEATURES, 367 .config = &genphy_config_aneg, 368 .startup = &vitesse_startup, 369 .shutdown = &genphy_shutdown, 370 }; 371 372 static struct phy_driver VSC8664_driver = { 373 .name = "Vitesse VSC8664", 374 .uid = 0x70660, 375 .mask = 0xffff0, 376 .features = PHY_GBIT_FEATURES, 377 .config = &vsc8664_config, 378 .startup = &vitesse_startup, 379 .shutdown = &genphy_shutdown, 380 }; 381 382 /* Vitesse bought Cicada, so we'll put these here */ 383 static struct phy_driver cis8201_driver = { 384 .name = "CIS8201", 385 .uid = 0xfc410, 386 .mask = 0xffff0, 387 .features = PHY_GBIT_FEATURES, 388 .config = &vitesse_config, 389 .startup = &vitesse_startup, 390 .shutdown = &genphy_shutdown, 391 }; 392 393 static struct phy_driver cis8204_driver = { 394 .name = "Cicada Cis8204", 395 .uid = 0xfc440, 396 .mask = 0xffff0, 397 .features = PHY_GBIT_FEATURES, 398 .config = &cis8204_config, 399 .startup = &vitesse_startup, 400 .shutdown = &genphy_shutdown, 401 }; 402 403 int phy_vitesse_init(void) 404 { 405 phy_register(&VSC8641_driver); 406 phy_register(&VSC8601_driver); 407 phy_register(&VSC8234_driver); 408 phy_register(&VSC8244_driver); 409 phy_register(&VSC8211_driver); 410 phy_register(&VSC8221_driver); 411 phy_register(&VSC8574_driver); 412 phy_register(&VSC8514_driver); 413 phy_register(&VSC8662_driver); 414 phy_register(&VSC8664_driver); 415 phy_register(&cis8201_driver); 416 phy_register(&cis8204_driver); 417 418 return 0; 419 } 420