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 */ 71static 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 85static 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 113static 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 123static 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. */ 146static 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 158static 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 171static 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 214static 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 269static 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 296U_BOOT_PHY_DRIVER(vsc8211) = { 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 306U_BOOT_PHY_DRIVER(vsc8221) = { 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 316U_BOOT_PHY_DRIVER(vsc8244) = { 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 326U_BOOT_PHY_DRIVER(vsc8234) = { 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 336U_BOOT_PHY_DRIVER(vsc8574) = { 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 346U_BOOT_PHY_DRIVER(vsc8514) = { 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 356U_BOOT_PHY_DRIVER(vsc8584) = { 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 366U_BOOT_PHY_DRIVER(vsc8601) = { 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 376U_BOOT_PHY_DRIVER(vsc8641) = { 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 386U_BOOT_PHY_DRIVER(vsc8662) = { 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 396U_BOOT_PHY_DRIVER(vsc8664) = { 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 */ 407U_BOOT_PHY_DRIVER(cis8201) = { 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 417U_BOOT_PHY_DRIVER(cis8204) = { 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