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

net: phy: vitesse: Add support for VSC73xx

The VSC7385, VSC7388, VSC7395 and VSC7398 are integrated
switch/router chips for 5+1 or 8-port switches/routers. When
managed directly by Linux using DSA we need to do a special
set-up "dance" on the PHY. Unfortunately these sequences
switches the PHY to undocumented pages named 2a30 and 52b6
and does undocumented things. It is described by these opaque
sequences also in the reference manual. This is a best
effort to integrate it anyways.

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Linus Walleij and committed by
David S. Miller
975ae7c6 1decd2ec

+175
+175
drivers/net/phy/vitesse.c
··· 72 72 #define PHY_ID_VSC8572 0x000704d0 73 73 #define PHY_ID_VSC8574 0x000704a0 74 74 #define PHY_ID_VSC8601 0x00070420 75 + #define PHY_ID_VSC7385 0x00070450 76 + #define PHY_ID_VSC7388 0x00070480 77 + #define PHY_ID_VSC7395 0x00070550 78 + #define PHY_ID_VSC7398 0x00070580 75 79 #define PHY_ID_VSC8662 0x00070660 76 80 #define PHY_ID_VSC8221 0x000fc550 77 81 #define PHY_ID_VSC8211 0x000fc4b0 ··· 118 114 err = vsc824x_add_skew(phydev); 119 115 120 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 genphy_config_init(phydev); 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 genphy_config_init(phydev); 238 + } 239 + 240 + static 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; 121 248 } 122 249 123 250 /* This adds a skew for both TX and RX clocks, so the skew should only be ··· 454 319 .ack_interrupt = &vsc824x_ack_interrupt, 455 320 .config_intr = &vsc82xx_config_intr, 456 321 }, { 322 + .phy_id = PHY_ID_VSC7385, 323 + .name = "Vitesse VSC7385", 324 + .phy_id_mask = 0x000ffff0, 325 + .features = PHY_GBIT_FEATURES, 326 + .config_init = vsc738x_config_init, 327 + .config_aneg = vsc73xx_config_aneg, 328 + .read_page = vsc73xx_read_page, 329 + .write_page = vsc73xx_write_page, 330 + }, { 331 + .phy_id = PHY_ID_VSC7388, 332 + .name = "Vitesse VSC7388", 333 + .phy_id_mask = 0x000ffff0, 334 + .features = PHY_GBIT_FEATURES, 335 + .config_init = vsc738x_config_init, 336 + .config_aneg = vsc73xx_config_aneg, 337 + .read_page = vsc73xx_read_page, 338 + .write_page = vsc73xx_write_page, 339 + }, { 340 + .phy_id = PHY_ID_VSC7395, 341 + .name = "Vitesse VSC7395", 342 + .phy_id_mask = 0x000ffff0, 343 + .features = PHY_GBIT_FEATURES, 344 + .config_init = vsc739x_config_init, 345 + .config_aneg = vsc73xx_config_aneg, 346 + .read_page = vsc73xx_read_page, 347 + .write_page = vsc73xx_write_page, 348 + }, { 349 + .phy_id = PHY_ID_VSC7398, 350 + .name = "Vitesse VSC7398", 351 + .phy_id_mask = 0x000ffff0, 352 + .features = PHY_GBIT_FEATURES, 353 + .config_init = vsc739x_config_init, 354 + .config_aneg = vsc73xx_config_aneg, 355 + .read_page = vsc73xx_read_page, 356 + .write_page = vsc73xx_write_page, 357 + }, { 457 358 .phy_id = PHY_ID_VSC8662, 458 359 .name = "Vitesse VSC8662", 459 360 .phy_id_mask = 0x000ffff0, ··· 529 358 { PHY_ID_VSC8514, 0x000ffff0 }, 530 359 { PHY_ID_VSC8572, 0x000ffff0 }, 531 360 { PHY_ID_VSC8574, 0x000ffff0 }, 361 + { PHY_ID_VSC7385, 0x000ffff0 }, 362 + { PHY_ID_VSC7388, 0x000ffff0 }, 363 + { PHY_ID_VSC7395, 0x000ffff0 }, 364 + { PHY_ID_VSC7398, 0x000ffff0 }, 532 365 { PHY_ID_VSC8662, 0x000ffff0 }, 533 366 { PHY_ID_VSC8221, 0x000ffff0 }, 534 367 { PHY_ID_VSC8211, 0x000ffff0 },