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 /* CIS8201 */ 62 static int vitesse_config(struct phy_device *phydev) 63 { 64 /* Override PHY config settings */ 65 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT, 66 MIIM_CIS82xx_AUXCONSTAT_INIT); 67 /* Set up the interface mode */ 68 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_EXT_CON1, 69 MIIM_CIS8201_EXTCON1_INIT); 70 71 genphy_config_aneg(phydev); 72 73 return 0; 74 } 75 76 static int vitesse_parse_status(struct phy_device *phydev) 77 { 78 int speed; 79 int mii_reg; 80 81 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT); 82 83 if (mii_reg & MIIM_CIS82xx_AUXCONSTAT_DUPLEX) 84 phydev->duplex = DUPLEX_FULL; 85 else 86 phydev->duplex = DUPLEX_HALF; 87 88 speed = mii_reg & MIIM_CIS82xx_AUXCONSTAT_SPEED; 89 switch (speed) { 90 case MIIM_CIS82xx_AUXCONSTAT_GBIT: 91 phydev->speed = SPEED_1000; 92 break; 93 case MIIM_CIS82xx_AUXCONSTAT_100: 94 phydev->speed = SPEED_100; 95 break; 96 default: 97 phydev->speed = SPEED_10; 98 break; 99 } 100 101 return 0; 102 } 103 104 static int vitesse_startup(struct phy_device *phydev) 105 { 106 genphy_update_link(phydev); 107 vitesse_parse_status(phydev); 108 109 return 0; 110 } 111 112 static int cis8204_config(struct phy_device *phydev) 113 { 114 /* Override PHY config settings */ 115 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT, 116 MIIM_CIS82xx_AUXCONSTAT_INIT); 117 118 genphy_config_aneg(phydev); 119 120 if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || 121 (phydev->interface == PHY_INTERFACE_MODE_RGMII) || 122 (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) || 123 (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)) 124 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8204_EPHY_CON, 125 MIIM_CIS8204_EPHYCON_INIT | 126 MIIM_CIS8204_EPHYCON_RGMII); 127 else 128 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8204_EPHY_CON, 129 MIIM_CIS8204_EPHYCON_INIT); 130 131 return 0; 132 } 133 134 /* Vitesse VSC8601 */ 135 static int vsc8601_config(struct phy_device *phydev) 136 { 137 /* Configure some basic stuff */ 138 #ifdef CONFIG_SYS_VSC8601_SKEWFIX 139 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8601_EPHY_CON, 140 MIIM_VSC8601_EPHY_CON_INIT_SKEW); 141 #if defined(CONFIG_SYS_VSC8601_SKEW_TX) && defined(CONFIG_SYS_VSC8601_SKEW_RX) 142 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 1); 143 #define VSC8101_SKEW \ 144 ((CONFIG_SYS_VSC8601_SKEW_TX << 14) \ 145 | (CONFIG_SYS_VSC8601_SKEW_RX << 12)) 146 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8601_SKEW_CTRL, 147 VSC8101_SKEW); 148 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); 149 #endif 150 #endif 151 152 genphy_config_aneg(phydev); 153 154 return 0; 155 } 156 157 static int vsc8574_config(struct phy_device *phydev) 158 { 159 u32 val; 160 /* configure register 19G for MAC */ 161 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 162 PHY_EXT_PAGE_ACCESS_GENERAL); 163 164 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL19); 165 if (phydev->interface == PHY_INTERFACE_MODE_QSGMII) { 166 /* set bit 15:14 to '01' for QSGMII mode */ 167 val = (val & 0x3fff) | (1 << 14); 168 phy_write(phydev, MDIO_DEVAD_NONE, 169 MIIM_VSC8574_GENERAL19, val); 170 /* Enable 4 ports MAC QSGMII */ 171 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18, 172 MIIM_VSC8574_18G_QSGMII); 173 } else { 174 /* set bit 15:14 to '00' for SGMII mode */ 175 val = val & 0x3fff; 176 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL19, val); 177 /* Enable 4 ports MAC SGMII */ 178 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18, 179 MIIM_VSC8574_18G_SGMII); 180 } 181 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18); 182 /* When bit 15 is cleared the command has completed */ 183 while (val & MIIM_VSC8574_18G_CMDSTAT) 184 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18); 185 186 /* Enable Serdes Auto-negotiation */ 187 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 188 PHY_EXT_PAGE_ACCESS_EXTENDED3); 189 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_MAC_SERDES_CON); 190 val = val | MIIM_VSC8574_MAC_SERDES_ANEG; 191 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_MAC_SERDES_CON, val); 192 193 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); 194 195 genphy_config_aneg(phydev); 196 197 return 0; 198 } 199 200 static int vsc8514_config(struct phy_device *phydev) 201 { 202 u32 val; 203 int timeout = 1000000; 204 205 /* configure register to access 19G */ 206 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 207 PHY_EXT_PAGE_ACCESS_GENERAL); 208 209 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL19); 210 if (phydev->interface == PHY_INTERFACE_MODE_QSGMII) { 211 /* set bit 15:14 to '01' for QSGMII mode */ 212 val = (val & 0x3fff) | (1 << 14); 213 phy_write(phydev, MDIO_DEVAD_NONE, 214 MIIM_VSC8514_GENERAL19, val); 215 /* Enable 4 ports MAC QSGMII */ 216 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL18, 217 MIIM_VSC8514_18G_QSGMII); 218 } else { 219 /*TODO Add SGMII functionality once spec sheet 220 * for VSC8514 defines complete functionality 221 */ 222 } 223 224 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL18); 225 /* When bit 15 is cleared the command has completed */ 226 while ((val & MIIM_VSC8514_18G_CMDSTAT) && timeout--) 227 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL18); 228 229 if (0 == timeout) { 230 printf("PHY 8514 config failed\n"); 231 return -1; 232 } 233 234 phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); 235 236 /* configure register to access 23 */ 237 val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL23); 238 /* set bits 10:8 to '000' */ 239 val = (val & 0xf8ff); 240 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL23, val); 241 242 genphy_config_aneg(phydev); 243 244 return 0; 245 } 246 247 static struct phy_driver VSC8211_driver = { 248 .name = "Vitesse VSC8211", 249 .uid = 0xfc4b0, 250 .mask = 0xffff0, 251 .features = PHY_GBIT_FEATURES, 252 .config = &vitesse_config, 253 .startup = &vitesse_startup, 254 .shutdown = &genphy_shutdown, 255 }; 256 257 static struct phy_driver VSC8221_driver = { 258 .name = "Vitesse VSC8221", 259 .uid = 0xfc550, 260 .mask = 0xffff0, 261 .features = PHY_GBIT_FEATURES, 262 .config = &genphy_config_aneg, 263 .startup = &vitesse_startup, 264 .shutdown = &genphy_shutdown, 265 }; 266 267 static struct phy_driver VSC8244_driver = { 268 .name = "Vitesse VSC8244", 269 .uid = 0xfc6c0, 270 .mask = 0xffff0, 271 .features = PHY_GBIT_FEATURES, 272 .config = &genphy_config_aneg, 273 .startup = &vitesse_startup, 274 .shutdown = &genphy_shutdown, 275 }; 276 277 static struct phy_driver VSC8234_driver = { 278 .name = "Vitesse VSC8234", 279 .uid = 0xfc620, 280 .mask = 0xffff0, 281 .features = PHY_GBIT_FEATURES, 282 .config = &genphy_config_aneg, 283 .startup = &vitesse_startup, 284 .shutdown = &genphy_shutdown, 285 }; 286 287 static struct phy_driver VSC8574_driver = { 288 .name = "Vitesse VSC8574", 289 .uid = 0x704a0, 290 .mask = 0xffff0, 291 .features = PHY_GBIT_FEATURES, 292 .config = &vsc8574_config, 293 .startup = &vitesse_startup, 294 .shutdown = &genphy_shutdown, 295 }; 296 297 static struct phy_driver VSC8514_driver = { 298 .name = "Vitesse VSC8514", 299 .uid = 0x70570, 300 .mask = 0xffff0, 301 .features = PHY_GBIT_FEATURES, 302 .config = &vsc8514_config, 303 .startup = &vitesse_startup, 304 .shutdown = &genphy_shutdown, 305 }; 306 307 static struct phy_driver VSC8601_driver = { 308 .name = "Vitesse VSC8601", 309 .uid = 0x70420, 310 .mask = 0xffff0, 311 .features = PHY_GBIT_FEATURES, 312 .config = &vsc8601_config, 313 .startup = &vitesse_startup, 314 .shutdown = &genphy_shutdown, 315 }; 316 317 static struct phy_driver VSC8641_driver = { 318 .name = "Vitesse VSC8641", 319 .uid = 0x70430, 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 VSC8662_driver = { 328 .name = "Vitesse VSC8662", 329 .uid = 0x70660, 330 .mask = 0xffff0, 331 .features = PHY_GBIT_FEATURES, 332 .config = &genphy_config_aneg, 333 .startup = &vitesse_startup, 334 .shutdown = &genphy_shutdown, 335 }; 336 337 /* Vitesse bought Cicada, so we'll put these here */ 338 static struct phy_driver cis8201_driver = { 339 .name = "CIS8201", 340 .uid = 0xfc410, 341 .mask = 0xffff0, 342 .features = PHY_GBIT_FEATURES, 343 .config = &vitesse_config, 344 .startup = &vitesse_startup, 345 .shutdown = &genphy_shutdown, 346 }; 347 348 static struct phy_driver cis8204_driver = { 349 .name = "Cicada Cis8204", 350 .uid = 0xfc440, 351 .mask = 0xffff0, 352 .features = PHY_GBIT_FEATURES, 353 .config = &cis8204_config, 354 .startup = &vitesse_startup, 355 .shutdown = &genphy_shutdown, 356 }; 357 358 int phy_vitesse_init(void) 359 { 360 phy_register(&VSC8641_driver); 361 phy_register(&VSC8601_driver); 362 phy_register(&VSC8234_driver); 363 phy_register(&VSC8244_driver); 364 phy_register(&VSC8211_driver); 365 phy_register(&VSC8221_driver); 366 phy_register(&VSC8574_driver); 367 phy_register(&VSC8514_driver); 368 phy_register(&VSC8662_driver); 369 phy_register(&cis8201_driver); 370 phy_register(&cis8204_driver); 371 372 return 0; 373 } 374