vitesse.c (14646B)
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 79MODULE_DESCRIPTION("Vitesse PHY driver"); 80MODULE_AUTHOR("Kriston Carson"); 81MODULE_LICENSE("GPL"); 82 83static 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 104static 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 121static int vsc73xx_read_page(struct phy_device *phydev) 122{ 123 return __phy_read(phydev, VSC73XX_EXT_PAGE_ACCESS); 124} 125 126static int vsc73xx_write_page(struct phy_device *phydev, int page) 127{ 128 return __phy_write(phydev, VSC73XX_EXT_PAGE_ACCESS, page); 129} 130 131static 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 142static 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 208static 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 240static int vsc73xx_config_aneg(struct phy_device *phydev) 241{ 242 /* The VSC73xx switches does not like to be instructed to 243 * do autonegotiation in any way, it prefers that you just go 244 * with the power-on/reset defaults. Writing some registers will 245 * just make autonegotiation permanently fail. 246 */ 247 return 0; 248} 249 250/* This adds a skew for both TX and RX clocks, so the skew should only be 251 * applied to "rgmii-id" interfaces. It may not work as expected 252 * on "rgmii-txid", "rgmii-rxid" or "rgmii" interfaces. 253 */ 254static int vsc8601_add_skew(struct phy_device *phydev) 255{ 256 int ret; 257 258 ret = phy_read(phydev, MII_VSC8601_EPHY_CTL); 259 if (ret < 0) 260 return ret; 261 262 ret |= MII_VSC8601_EPHY_CTL_RGMII_SKEW; 263 return phy_write(phydev, MII_VSC8601_EPHY_CTL, ret); 264} 265 266static int vsc8601_config_init(struct phy_device *phydev) 267{ 268 int ret = 0; 269 270 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) 271 ret = vsc8601_add_skew(phydev); 272 273 if (ret < 0) 274 return ret; 275 276 return 0; 277} 278 279static int vsc82xx_config_intr(struct phy_device *phydev) 280{ 281 int err; 282 283 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) 284 /* Don't bother to ACK the interrupts since the 824x cannot 285 * clear the interrupts if they are disabled. 286 */ 287 err = phy_write(phydev, MII_VSC8244_IMASK, 288 (phydev->drv->phy_id == PHY_ID_VSC8234 || 289 phydev->drv->phy_id == PHY_ID_VSC8244 || 290 phydev->drv->phy_id == PHY_ID_VSC8572 || 291 phydev->drv->phy_id == PHY_ID_VSC8601) ? 292 MII_VSC8244_IMASK_MASK : 293 MII_VSC8221_IMASK_MASK); 294 else { 295 /* The Vitesse PHY cannot clear the interrupt 296 * once it has disabled them, so we clear them first 297 */ 298 err = phy_read(phydev, MII_VSC8244_ISTAT); 299 300 if (err < 0) 301 return err; 302 303 err = phy_write(phydev, MII_VSC8244_IMASK, 0); 304 } 305 306 return err; 307} 308 309static irqreturn_t vsc82xx_handle_interrupt(struct phy_device *phydev) 310{ 311 int irq_status, irq_mask; 312 313 if (phydev->drv->phy_id == PHY_ID_VSC8244 || 314 phydev->drv->phy_id == PHY_ID_VSC8572 || 315 phydev->drv->phy_id == PHY_ID_VSC8601) 316 irq_mask = MII_VSC8244_ISTAT_MASK; 317 else 318 irq_mask = MII_VSC8221_ISTAT_MASK; 319 320 irq_status = phy_read(phydev, MII_VSC8244_ISTAT); 321 if (irq_status < 0) { 322 phy_error(phydev); 323 return IRQ_NONE; 324 } 325 326 if (!(irq_status & irq_mask)) 327 return IRQ_NONE; 328 329 phy_trigger_machine(phydev); 330 331 return IRQ_HANDLED; 332} 333 334static int vsc8221_config_init(struct phy_device *phydev) 335{ 336 int err; 337 338 err = phy_write(phydev, MII_VSC8244_AUX_CONSTAT, 339 MII_VSC8221_AUXCONSTAT_INIT); 340 return err; 341 342 /* Perhaps we should set EXT_CON1 based on the interface? 343 * Options are 802.3Z SerDes or SGMII 344 */ 345} 346 347/* vsc82x4_config_autocross_enable - Enable auto MDI/MDI-X for forced links 348 * @phydev: target phy_device struct 349 * 350 * Enable auto MDI/MDI-X when in 10/100 forced link speeds by writing 351 * special values in the VSC8234/VSC8244 extended reserved registers 352 */ 353static int vsc82x4_config_autocross_enable(struct phy_device *phydev) 354{ 355 int ret; 356 357 if (phydev->autoneg == AUTONEG_ENABLE || phydev->speed > SPEED_100) 358 return 0; 359 360 /* map extended registers set 0x10 - 0x1e */ 361 ret = phy_write(phydev, MII_VSC82X4_EXT_PAGE_ACCESS, 0x52b5); 362 if (ret >= 0) 363 ret = phy_write(phydev, MII_VSC82X4_EXT_PAGE_18E, 0x0012); 364 if (ret >= 0) 365 ret = phy_write(phydev, MII_VSC82X4_EXT_PAGE_17E, 0x2803); 366 if (ret >= 0) 367 ret = phy_write(phydev, MII_VSC82X4_EXT_PAGE_16E, 0x87fa); 368 /* map standard registers set 0x10 - 0x1e */ 369 if (ret >= 0) 370 ret = phy_write(phydev, MII_VSC82X4_EXT_PAGE_ACCESS, 0x0000); 371 else 372 phy_write(phydev, MII_VSC82X4_EXT_PAGE_ACCESS, 0x0000); 373 374 return ret; 375} 376 377/* vsc82x4_config_aneg - restart auto-negotiation or write BMCR 378 * @phydev: target phy_device struct 379 * 380 * Description: If auto-negotiation is enabled, we configure the 381 * advertising, and then restart auto-negotiation. If it is not 382 * enabled, then we write the BMCR and also start the auto 383 * MDI/MDI-X feature 384 */ 385static int vsc82x4_config_aneg(struct phy_device *phydev) 386{ 387 int ret; 388 389 /* Enable auto MDI/MDI-X when in 10/100 forced link speeds by 390 * writing special values in the VSC8234 extended reserved registers 391 */ 392 if (phydev->autoneg != AUTONEG_ENABLE && phydev->speed <= SPEED_100) { 393 ret = genphy_setup_forced(phydev); 394 395 if (ret < 0) /* error */ 396 return ret; 397 398 return vsc82x4_config_autocross_enable(phydev); 399 } 400 401 return genphy_config_aneg(phydev); 402} 403 404/* Vitesse 82xx */ 405static struct phy_driver vsc82xx_driver[] = { 406{ 407 .phy_id = PHY_ID_VSC8234, 408 .name = "Vitesse VSC8234", 409 .phy_id_mask = 0x000ffff0, 410 /* PHY_GBIT_FEATURES */ 411 .config_init = &vsc824x_config_init, 412 .config_aneg = &vsc82x4_config_aneg, 413 .config_intr = &vsc82xx_config_intr, 414 .handle_interrupt = &vsc82xx_handle_interrupt, 415}, { 416 .phy_id = PHY_ID_VSC8244, 417 .name = "Vitesse VSC8244", 418 .phy_id_mask = 0x000fffc0, 419 /* PHY_GBIT_FEATURES */ 420 .config_init = &vsc824x_config_init, 421 .config_aneg = &vsc82x4_config_aneg, 422 .config_intr = &vsc82xx_config_intr, 423 .handle_interrupt = &vsc82xx_handle_interrupt, 424}, { 425 .phy_id = PHY_ID_VSC8572, 426 .name = "Vitesse VSC8572", 427 .phy_id_mask = 0x000ffff0, 428 /* PHY_GBIT_FEATURES */ 429 .config_init = &vsc824x_config_init, 430 .config_aneg = &vsc82x4_config_aneg, 431 .config_intr = &vsc82xx_config_intr, 432 .handle_interrupt = &vsc82xx_handle_interrupt, 433}, { 434 .phy_id = PHY_ID_VSC8601, 435 .name = "Vitesse VSC8601", 436 .phy_id_mask = 0x000ffff0, 437 /* PHY_GBIT_FEATURES */ 438 .config_init = &vsc8601_config_init, 439 .config_intr = &vsc82xx_config_intr, 440 .handle_interrupt = &vsc82xx_handle_interrupt, 441}, { 442 .phy_id = PHY_ID_VSC7385, 443 .name = "Vitesse VSC7385", 444 .phy_id_mask = 0x000ffff0, 445 /* PHY_GBIT_FEATURES */ 446 .config_init = vsc738x_config_init, 447 .config_aneg = vsc73xx_config_aneg, 448 .read_page = vsc73xx_read_page, 449 .write_page = vsc73xx_write_page, 450}, { 451 .phy_id = PHY_ID_VSC7388, 452 .name = "Vitesse VSC7388", 453 .phy_id_mask = 0x000ffff0, 454 /* PHY_GBIT_FEATURES */ 455 .config_init = vsc738x_config_init, 456 .config_aneg = vsc73xx_config_aneg, 457 .read_page = vsc73xx_read_page, 458 .write_page = vsc73xx_write_page, 459}, { 460 .phy_id = PHY_ID_VSC7395, 461 .name = "Vitesse VSC7395", 462 .phy_id_mask = 0x000ffff0, 463 /* PHY_GBIT_FEATURES */ 464 .config_init = vsc739x_config_init, 465 .config_aneg = vsc73xx_config_aneg, 466 .read_page = vsc73xx_read_page, 467 .write_page = vsc73xx_write_page, 468}, { 469 .phy_id = PHY_ID_VSC7398, 470 .name = "Vitesse VSC7398", 471 .phy_id_mask = 0x000ffff0, 472 /* PHY_GBIT_FEATURES */ 473 .config_init = vsc739x_config_init, 474 .config_aneg = vsc73xx_config_aneg, 475 .read_page = vsc73xx_read_page, 476 .write_page = vsc73xx_write_page, 477}, { 478 .phy_id = PHY_ID_VSC8662, 479 .name = "Vitesse VSC8662", 480 .phy_id_mask = 0x000ffff0, 481 /* PHY_GBIT_FEATURES */ 482 .config_init = &vsc824x_config_init, 483 .config_aneg = &vsc82x4_config_aneg, 484 .config_intr = &vsc82xx_config_intr, 485 .handle_interrupt = &vsc82xx_handle_interrupt, 486}, { 487 /* Vitesse 8221 */ 488 .phy_id = PHY_ID_VSC8221, 489 .phy_id_mask = 0x000ffff0, 490 .name = "Vitesse VSC8221", 491 /* PHY_GBIT_FEATURES */ 492 .config_init = &vsc8221_config_init, 493 .config_intr = &vsc82xx_config_intr, 494 .handle_interrupt = &vsc82xx_handle_interrupt, 495}, { 496 /* Vitesse 8211 */ 497 .phy_id = PHY_ID_VSC8211, 498 .phy_id_mask = 0x000ffff0, 499 .name = "Vitesse VSC8211", 500 /* PHY_GBIT_FEATURES */ 501 .config_init = &vsc8221_config_init, 502 .config_intr = &vsc82xx_config_intr, 503 .handle_interrupt = &vsc82xx_handle_interrupt, 504} }; 505 506module_phy_driver(vsc82xx_driver); 507 508static struct mdio_device_id __maybe_unused vitesse_tbl[] = { 509 { PHY_ID_VSC8234, 0x000ffff0 }, 510 { PHY_ID_VSC8244, 0x000fffc0 }, 511 { PHY_ID_VSC8572, 0x000ffff0 }, 512 { PHY_ID_VSC7385, 0x000ffff0 }, 513 { PHY_ID_VSC7388, 0x000ffff0 }, 514 { PHY_ID_VSC7395, 0x000ffff0 }, 515 { PHY_ID_VSC7398, 0x000ffff0 }, 516 { PHY_ID_VSC8662, 0x000ffff0 }, 517 { PHY_ID_VSC8221, 0x000ffff0 }, 518 { PHY_ID_VSC8211, 0x000ffff0 }, 519 { } 520}; 521 522MODULE_DEVICE_TABLE(mdio, vitesse_tbl);