1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Driver for Vitesse PHYs 4 * 5 * Author: Kriston Carson 6 */ 7 8 #include <linux/kernel.h> 9 #include <linux/module.h> 10 #include <linux/mii.h> 11 #include <linux/ethtool.h> 12 #include <linux/phy.h> 13 14 /* Vitesse Extended Page Magic Register(s) */ 15 #define MII_VSC82X4_EXT_PAGE_16E 0x10 16 #define MII_VSC82X4_EXT_PAGE_17E 0x11 17 #define MII_VSC82X4_EXT_PAGE_18E 0x12 18 19 /* Vitesse Extended Control Register 1 */ 20 #define MII_VSC8244_EXT_CON1 0x17 21 #define MII_VSC8244_EXTCON1_INIT 0x0000 22 #define MII_VSC8244_EXTCON1_TX_SKEW_MASK 0x0c00 23 #define MII_VSC8244_EXTCON1_RX_SKEW_MASK 0x0300 24 #define MII_VSC8244_EXTCON1_TX_SKEW 0x0800 25 #define MII_VSC8244_EXTCON1_RX_SKEW 0x0200 26 27 /* Vitesse Interrupt Mask Register */ 28 #define MII_VSC8244_IMASK 0x19 29 #define MII_VSC8244_IMASK_IEN 0x8000 30 #define MII_VSC8244_IMASK_SPEED 0x4000 31 #define MII_VSC8244_IMASK_LINK 0x2000 32 #define MII_VSC8244_IMASK_DUPLEX 0x1000 33 #define MII_VSC8244_IMASK_MASK 0xf000 34 35 #define MII_VSC8221_IMASK_MASK 0xa000 36 37 /* Vitesse Interrupt Status Register */ 38 #define MII_VSC8244_ISTAT 0x1a 39 #define MII_VSC8244_ISTAT_STATUS 0x8000 40 #define MII_VSC8244_ISTAT_SPEED 0x4000 41 #define MII_VSC8244_ISTAT_LINK 0x2000 42 #define MII_VSC8244_ISTAT_DUPLEX 0x1000 43 #define MII_VSC8244_ISTAT_MASK (MII_VSC8244_ISTAT_SPEED | \ 44 MII_VSC8244_ISTAT_LINK | \ 45 MII_VSC8244_ISTAT_DUPLEX) 46 47 #define MII_VSC8221_ISTAT_MASK MII_VSC8244_ISTAT_LINK 48 49 /* Vitesse Auxiliary Control/Status Register */ 50 #define MII_VSC8244_AUX_CONSTAT 0x1c 51 #define MII_VSC8244_AUXCONSTAT_INIT 0x0000 52 #define MII_VSC8244_AUXCONSTAT_DUPLEX 0x0020 53 #define MII_VSC8244_AUXCONSTAT_SPEED 0x0018 54 #define MII_VSC8244_AUXCONSTAT_GBIT 0x0010 55 #define MII_VSC8244_AUXCONSTAT_100 0x0008 56 57 #define MII_VSC8221_AUXCONSTAT_INIT 0x0004 /* need to set this bit? */ 58 #define MII_VSC8221_AUXCONSTAT_RESERVED 0x0004 59 60 /* Vitesse Extended Page Access Register */ 61 #define MII_VSC82X4_EXT_PAGE_ACCESS 0x1f 62 63 /* Vitesse VSC8601 Extended PHY Control Register 1 */ 64 #define MII_VSC8601_EPHY_CTL 0x17 65 #define MII_VSC8601_EPHY_CTL_RGMII_SKEW (1 << 8) 66 67 #define PHY_ID_VSC8234 0x000fc620 68 #define PHY_ID_VSC8244 0x000fc6c0 69 #define PHY_ID_VSC8572 0x000704d0 70 #define PHY_ID_VSC8601 0x00070420 71 #define PHY_ID_VSC7385 0x00070450 72 #define PHY_ID_VSC7388 0x00070480 73 #define PHY_ID_VSC7395 0x00070550 74 #define PHY_ID_VSC7398 0x00070580 75 #define PHY_ID_VSC8662 0x00070660 76 #define PHY_ID_VSC8221 0x000fc550 77 #define PHY_ID_VSC8211 0x000fc4b0 78 79 MODULE_DESCRIPTION("Vitesse PHY driver"); 80 MODULE_AUTHOR("Kriston Carson"); 81 MODULE_LICENSE("GPL"); 82 83 static int vsc824x_add_skew(struct phy_device *phydev) 84 { 85 int err; 86 int extcon; 87 88 extcon = phy_read(phydev, MII_VSC8244_EXT_CON1); 89 90 if (extcon < 0) 91 return extcon; 92 93 extcon &= ~(MII_VSC8244_EXTCON1_TX_SKEW_MASK | 94 MII_VSC8244_EXTCON1_RX_SKEW_MASK); 95 96 extcon |= (MII_VSC8244_EXTCON1_TX_SKEW | 97 MII_VSC8244_EXTCON1_RX_SKEW); 98 99 err = phy_write(phydev, MII_VSC8244_EXT_CON1, extcon); 100 101 return err; 102 } 103 104 static int vsc824x_config_init(struct phy_device *phydev) 105 { 106 int err; 107 108 err = phy_write(phydev, MII_VSC8244_AUX_CONSTAT, 109 MII_VSC8244_AUXCONSTAT_INIT); 110 if (err < 0) 111 return err; 112 113 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) 114 err = vsc824x_add_skew(phydev); 115 116 return err; 117 } 118 119 #define VSC73XX_EXT_PAGE_ACCESS 0x1f 120 121 static int vsc73xx_read_page(struct phy_device *phydev) 122 { 123 return __phy_read(phydev, VSC73XX_EXT_PAGE_ACCESS); 124 } 125 126 static int vsc73xx_write_page(struct phy_device *phydev, int page) 127 { 128 return __phy_write(phydev, VSC73XX_EXT_PAGE_ACCESS, page); 129 } 130 131 static void vsc73xx_config_init(struct phy_device *phydev) 132 { 133 /* Receiver init */ 134 phy_write(phydev, 0x1f, 0x2a30); 135 phy_modify(phydev, 0x0c, 0x0300, 0x0200); 136 phy_write(phydev, 0x1f, 0x0000); 137 138 /* Config LEDs 0x61 */ 139 phy_modify(phydev, MII_TPISTATUS, 0xff00, 0x0061); 140 } 141 142 static int vsc738x_config_init(struct phy_device *phydev) 143 { 144 u16 rev; 145 /* This magic sequence appear in the application note 146 * "VSC7385/7388 PHY Configuration". 147 * 148 * Maybe one day we will get to know what it all means. 149 */ 150 phy_write(phydev, 0x1f, 0x2a30); 151 phy_modify(phydev, 0x08, 0x0200, 0x0200); 152 phy_write(phydev, 0x1f, 0x52b5); 153 phy_write(phydev, 0x10, 0xb68a); 154 phy_modify(phydev, 0x12, 0xff07, 0x0003); 155 phy_modify(phydev, 0x11, 0x00ff, 0x00a2); 156 phy_write(phydev, 0x10, 0x968a); 157 phy_write(phydev, 0x1f, 0x2a30); 158 phy_modify(phydev, 0x08, 0x0200, 0x0000); 159 phy_write(phydev, 0x1f, 0x0000); 160 161 /* Read revision */ 162 rev = phy_read(phydev, MII_PHYSID2); 163 rev &= 0x0f; 164 165 /* Special quirk for revision 0 */ 166 if (rev == 0) { 167 phy_write(phydev, 0x1f, 0x2a30); 168 phy_modify(phydev, 0x08, 0x0200, 0x0200); 169 phy_write(phydev, 0x1f, 0x52b5); 170 phy_write(phydev, 0x12, 0x0000); 171 phy_write(phydev, 0x11, 0x0689); 172 phy_write(phydev, 0x10, 0x8f92); 173 phy_write(phydev, 0x1f, 0x52b5); 174 phy_write(phydev, 0x12, 0x0000); 175 phy_write(phydev, 0x11, 0x0e35); 176 phy_write(phydev, 0x10, 0x9786); 177 phy_write(phydev, 0x1f, 0x2a30); 178 phy_modify(phydev, 0x08, 0x0200, 0x0000); 179 phy_write(phydev, 0x17, 0xff80); 180 phy_write(phydev, 0x17, 0x0000); 181 } 182 183 phy_write(phydev, 0x1f, 0x0000); 184 phy_write(phydev, 0x12, 0x0048); 185 186 if (rev == 0) { 187 phy_write(phydev, 0x1f, 0x2a30); 188 phy_write(phydev, 0x14, 0x6600); 189 phy_write(phydev, 0x1f, 0x0000); 190 phy_write(phydev, 0x18, 0xa24e); 191 } else { 192 phy_write(phydev, 0x1f, 0x2a30); 193 phy_modify(phydev, 0x16, 0x0fc0, 0x0240); 194 phy_modify(phydev, 0x14, 0x6000, 0x4000); 195 /* bits 14-15 in extended register 0x14 controls DACG amplitude 196 * 6 = -8%, 2 is hardware default 197 */ 198 phy_write(phydev, 0x1f, 0x0001); 199 phy_modify(phydev, 0x14, 0xe000, 0x6000); 200 phy_write(phydev, 0x1f, 0x0000); 201 } 202 203 vsc73xx_config_init(phydev); 204 205 return 0; 206 } 207 208 static int vsc739x_config_init(struct phy_device *phydev) 209 { 210 /* This magic sequence appears in the VSC7395 SparX-G5e application 211 * note "VSC7395/VSC7398 PHY Configuration" 212 * 213 * Maybe one day we will get to know what it all means. 214 */ 215 phy_write(phydev, 0x1f, 0x2a30); 216 phy_modify(phydev, 0x08, 0x0200, 0x0200); 217 phy_write(phydev, 0x1f, 0x52b5); 218 phy_write(phydev, 0x10, 0xb68a); 219 phy_modify(phydev, 0x12, 0xff07, 0x0003); 220 phy_modify(phydev, 0x11, 0x00ff, 0x00a2); 221 phy_write(phydev, 0x10, 0x968a); 222 phy_write(phydev, 0x1f, 0x2a30); 223 phy_modify(phydev, 0x08, 0x0200, 0x0000); 224 phy_write(phydev, 0x1f, 0x0000); 225 226 phy_write(phydev, 0x1f, 0x0000); 227 phy_write(phydev, 0x12, 0x0048); 228 phy_write(phydev, 0x1f, 0x2a30); 229 phy_modify(phydev, 0x16, 0x0fc0, 0x0240); 230 phy_modify(phydev, 0x14, 0x6000, 0x4000); 231 phy_write(phydev, 0x1f, 0x0001); 232 phy_modify(phydev, 0x14, 0xe000, 0x6000); 233 phy_write(phydev, 0x1f, 0x0000); 234 235 vsc73xx_config_init(phydev); 236 237 return 0; 238 } 239 240 /* This adds a skew for both TX and RX clocks, so the skew should only be 241 * applied to "rgmii-id" interfaces. It may not work as expected 242 * on "rgmii-txid", "rgmii-rxid" or "rgmii" interfaces. 243 */ 244 static int vsc8601_add_skew(struct phy_device *phydev) 245 { 246 int ret; 247 248 ret = phy_read(phydev, MII_VSC8601_EPHY_CTL); 249 if (ret < 0) 250 return ret; 251 252 ret |= MII_VSC8601_EPHY_CTL_RGMII_SKEW; 253 return phy_write(phydev, MII_VSC8601_EPHY_CTL, ret); 254 } 255 256 static int vsc8601_config_init(struct phy_device *phydev) 257 { 258 int ret = 0; 259 260 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) 261 ret = vsc8601_add_skew(phydev); 262 263 if (ret < 0) 264 return ret; 265 266 return 0; 267 } 268 269 static int vsc82xx_config_intr(struct phy_device *phydev) 270 { 271 int err; 272 273 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) 274 /* Don't bother to ACK the interrupts since the 824x cannot 275 * clear the interrupts if they are disabled. 276 */ 277 err = phy_write(phydev, MII_VSC8244_IMASK, 278 (phydev->drv->phy_id == PHY_ID_VSC8234 || 279 phydev->drv->phy_id == PHY_ID_VSC8244 || 280 phydev->drv->phy_id == PHY_ID_VSC8572 || 281 phydev->drv->phy_id == PHY_ID_VSC8601) ? 282 MII_VSC8244_IMASK_MASK : 283 MII_VSC8221_IMASK_MASK); 284 else { 285 /* The Vitesse PHY cannot clear the interrupt 286 * once it has disabled them, so we clear them first 287 */ 288 err = phy_read(phydev, MII_VSC8244_ISTAT); 289 290 if (err < 0) 291 return err; 292 293 err = phy_write(phydev, MII_VSC8244_IMASK, 0); 294 } 295 296 return err; 297 } 298 299 static irqreturn_t vsc82xx_handle_interrupt(struct phy_device *phydev) 300 { 301 int irq_status, irq_mask; 302 303 if (phydev->drv->phy_id == PHY_ID_VSC8244 || 304 phydev->drv->phy_id == PHY_ID_VSC8572 || 305 phydev->drv->phy_id == PHY_ID_VSC8601) 306 irq_mask = MII_VSC8244_ISTAT_MASK; 307 else 308 irq_mask = MII_VSC8221_ISTAT_MASK; 309 310 irq_status = phy_read(phydev, MII_VSC8244_ISTAT); 311 if (irq_status < 0) { 312 phy_error(phydev); 313 return IRQ_NONE; 314 } 315 316 if (!(irq_status & irq_mask)) 317 return IRQ_NONE; 318 319 phy_trigger_machine(phydev); 320 321 return IRQ_HANDLED; 322 } 323 324 static int vsc8221_config_init(struct phy_device *phydev) 325 { 326 int err; 327 328 err = phy_write(phydev, MII_VSC8244_AUX_CONSTAT, 329 MII_VSC8221_AUXCONSTAT_INIT); 330 return err; 331 332 /* Perhaps we should set EXT_CON1 based on the interface? 333 * Options are 802.3Z SerDes or SGMII 334 */ 335 } 336 337 /* vsc82x4_config_autocross_enable - Enable auto MDI/MDI-X for forced links 338 * @phydev: target phy_device struct 339 * 340 * Enable auto MDI/MDI-X when in 10/100 forced link speeds by writing 341 * special values in the VSC8234/VSC8244 extended reserved registers 342 */ 343 static int vsc82x4_config_autocross_enable(struct phy_device *phydev) 344 { 345 int ret; 346 347 if (phydev->autoneg == AUTONEG_ENABLE || phydev->speed > SPEED_100) 348 return 0; 349 350 /* map extended registers set 0x10 - 0x1e */ 351 ret = phy_write(phydev, MII_VSC82X4_EXT_PAGE_ACCESS, 0x52b5); 352 if (ret >= 0) 353 ret = phy_write(phydev, MII_VSC82X4_EXT_PAGE_18E, 0x0012); 354 if (ret >= 0) 355 ret = phy_write(phydev, MII_VSC82X4_EXT_PAGE_17E, 0x2803); 356 if (ret >= 0) 357 ret = phy_write(phydev, MII_VSC82X4_EXT_PAGE_16E, 0x87fa); 358 /* map standard registers set 0x10 - 0x1e */ 359 if (ret >= 0) 360 ret = phy_write(phydev, MII_VSC82X4_EXT_PAGE_ACCESS, 0x0000); 361 else 362 phy_write(phydev, MII_VSC82X4_EXT_PAGE_ACCESS, 0x0000); 363 364 return ret; 365 } 366 367 /* vsc82x4_config_aneg - restart auto-negotiation or write BMCR 368 * @phydev: target phy_device struct 369 * 370 * Description: If auto-negotiation is enabled, we configure the 371 * advertising, and then restart auto-negotiation. If it is not 372 * enabled, then we write the BMCR and also start the auto 373 * MDI/MDI-X feature 374 */ 375 static int vsc82x4_config_aneg(struct phy_device *phydev) 376 { 377 int ret; 378 379 /* Enable auto MDI/MDI-X when in 10/100 forced link speeds by 380 * writing special values in the VSC8234 extended reserved registers 381 */ 382 if (phydev->autoneg != AUTONEG_ENABLE && phydev->speed <= SPEED_100) { 383 ret = genphy_setup_forced(phydev); 384 385 if (ret < 0) /* error */ 386 return ret; 387 388 return vsc82x4_config_autocross_enable(phydev); 389 } 390 391 return genphy_config_aneg(phydev); 392 } 393 394 /* Vitesse 82xx */ 395 static struct phy_driver vsc82xx_driver[] = { 396 { 397 .phy_id = PHY_ID_VSC8234, 398 .name = "Vitesse VSC8234", 399 .phy_id_mask = 0x000ffff0, 400 /* PHY_GBIT_FEATURES */ 401 .config_init = &vsc824x_config_init, 402 .config_aneg = &vsc82x4_config_aneg, 403 .config_intr = &vsc82xx_config_intr, 404 .handle_interrupt = &vsc82xx_handle_interrupt, 405 }, { 406 .phy_id = PHY_ID_VSC8244, 407 .name = "Vitesse VSC8244", 408 .phy_id_mask = 0x000fffc0, 409 /* PHY_GBIT_FEATURES */ 410 .config_init = &vsc824x_config_init, 411 .config_aneg = &vsc82x4_config_aneg, 412 .config_intr = &vsc82xx_config_intr, 413 .handle_interrupt = &vsc82xx_handle_interrupt, 414 }, { 415 .phy_id = PHY_ID_VSC8572, 416 .name = "Vitesse VSC8572", 417 .phy_id_mask = 0x000ffff0, 418 /* PHY_GBIT_FEATURES */ 419 .config_init = &vsc824x_config_init, 420 .config_aneg = &vsc82x4_config_aneg, 421 .config_intr = &vsc82xx_config_intr, 422 .handle_interrupt = &vsc82xx_handle_interrupt, 423 }, { 424 .phy_id = PHY_ID_VSC8601, 425 .name = "Vitesse VSC8601", 426 .phy_id_mask = 0x000ffff0, 427 /* PHY_GBIT_FEATURES */ 428 .config_init = &vsc8601_config_init, 429 .config_intr = &vsc82xx_config_intr, 430 .handle_interrupt = &vsc82xx_handle_interrupt, 431 }, { 432 .phy_id = PHY_ID_VSC7385, 433 .name = "Vitesse VSC7385", 434 .phy_id_mask = 0x000ffff0, 435 /* PHY_GBIT_FEATURES */ 436 .config_init = vsc738x_config_init, 437 .read_page = vsc73xx_read_page, 438 .write_page = vsc73xx_write_page, 439 }, { 440 .phy_id = PHY_ID_VSC7388, 441 .name = "Vitesse VSC7388", 442 .phy_id_mask = 0x000ffff0, 443 /* PHY_GBIT_FEATURES */ 444 .config_init = vsc738x_config_init, 445 .read_page = vsc73xx_read_page, 446 .write_page = vsc73xx_write_page, 447 }, { 448 .phy_id = PHY_ID_VSC7395, 449 .name = "Vitesse VSC7395", 450 .phy_id_mask = 0x000ffff0, 451 /* PHY_GBIT_FEATURES */ 452 .config_init = vsc739x_config_init, 453 .read_page = vsc73xx_read_page, 454 .write_page = vsc73xx_write_page, 455 }, { 456 .phy_id = PHY_ID_VSC7398, 457 .name = "Vitesse VSC7398", 458 .phy_id_mask = 0x000ffff0, 459 /* PHY_GBIT_FEATURES */ 460 .config_init = vsc739x_config_init, 461 .read_page = vsc73xx_read_page, 462 .write_page = vsc73xx_write_page, 463 }, { 464 .phy_id = PHY_ID_VSC8662, 465 .name = "Vitesse VSC8662", 466 .phy_id_mask = 0x000ffff0, 467 /* PHY_GBIT_FEATURES */ 468 .config_init = &vsc824x_config_init, 469 .config_aneg = &vsc82x4_config_aneg, 470 .config_intr = &vsc82xx_config_intr, 471 .handle_interrupt = &vsc82xx_handle_interrupt, 472 }, { 473 /* Vitesse 8221 */ 474 .phy_id = PHY_ID_VSC8221, 475 .phy_id_mask = 0x000ffff0, 476 .name = "Vitesse VSC8221", 477 /* PHY_GBIT_FEATURES */ 478 .config_init = &vsc8221_config_init, 479 .config_intr = &vsc82xx_config_intr, 480 .handle_interrupt = &vsc82xx_handle_interrupt, 481 }, { 482 /* Vitesse 8211 */ 483 .phy_id = PHY_ID_VSC8211, 484 .phy_id_mask = 0x000ffff0, 485 .name = "Vitesse VSC8211", 486 /* PHY_GBIT_FEATURES */ 487 .config_init = &vsc8221_config_init, 488 .config_intr = &vsc82xx_config_intr, 489 .handle_interrupt = &vsc82xx_handle_interrupt, 490 } }; 491 492 module_phy_driver(vsc82xx_driver); 493 494 static struct mdio_device_id __maybe_unused vitesse_tbl[] = { 495 { PHY_ID_VSC8234, 0x000ffff0 }, 496 { PHY_ID_VSC8244, 0x000fffc0 }, 497 { PHY_ID_VSC8572, 0x000ffff0 }, 498 { PHY_ID_VSC7385, 0x000ffff0 }, 499 { PHY_ID_VSC7388, 0x000ffff0 }, 500 { PHY_ID_VSC7395, 0x000ffff0 }, 501 { PHY_ID_VSC7398, 0x000ffff0 }, 502 { PHY_ID_VSC8662, 0x000ffff0 }, 503 { PHY_ID_VSC8221, 0x000ffff0 }, 504 { PHY_ID_VSC8211, 0x000ffff0 }, 505 { } 506 }; 507 508 MODULE_DEVICE_TABLE(mdio, vitesse_tbl); 509