Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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