1 /* 2 * Broadcom BCM7xxx internal transceivers support. 3 * 4 * Copyright (C) 2014, Broadcom Corporation 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 */ 11 12 #include <linux/module.h> 13 #include <linux/phy.h> 14 #include <linux/delay.h> 15 #include "bcm-phy-lib.h" 16 #include <linux/bitops.h> 17 #include <linux/brcmphy.h> 18 #include <linux/mdio.h> 19 20 /* Broadcom BCM7xxx internal PHY registers */ 21 22 /* 40nm only register definitions */ 23 #define MII_BCM7XXX_100TX_AUX_CTL 0x10 24 #define MII_BCM7XXX_100TX_FALSE_CAR 0x13 25 #define MII_BCM7XXX_100TX_DISC 0x14 26 #define MII_BCM7XXX_AUX_MODE 0x1d 27 #define MII_BCM7XXX_64CLK_MDIO BIT(12) 28 #define MII_BCM7XXX_TEST 0x1f 29 #define MII_BCM7XXX_SHD_MODE_2 BIT(2) 30 31 /* 28nm only register definitions */ 32 #define MISC_ADDR(base, channel) base, channel 33 34 #define DSP_TAP10 MISC_ADDR(0x0a, 0) 35 #define PLL_PLLCTRL_1 MISC_ADDR(0x32, 1) 36 #define PLL_PLLCTRL_2 MISC_ADDR(0x32, 2) 37 #define PLL_PLLCTRL_4 MISC_ADDR(0x33, 0) 38 39 #define AFE_RXCONFIG_0 MISC_ADDR(0x38, 0) 40 #define AFE_RXCONFIG_1 MISC_ADDR(0x38, 1) 41 #define AFE_RXCONFIG_2 MISC_ADDR(0x38, 2) 42 #define AFE_RX_LP_COUNTER MISC_ADDR(0x38, 3) 43 #define AFE_TX_CONFIG MISC_ADDR(0x39, 0) 44 #define AFE_VDCA_ICTRL_0 MISC_ADDR(0x39, 1) 45 #define AFE_VDAC_OTHERS_0 MISC_ADDR(0x39, 3) 46 #define AFE_HPF_TRIM_OTHERS MISC_ADDR(0x3a, 0) 47 48 struct bcm7xxx_phy_priv { 49 u64 *stats; 50 }; 51 52 static void r_rc_cal_reset(struct phy_device *phydev) 53 { 54 /* Reset R_CAL/RC_CAL Engine */ 55 bcm_phy_write_exp(phydev, 0x00b0, 0x0010); 56 57 /* Disable Reset R_AL/RC_CAL Engine */ 58 bcm_phy_write_exp(phydev, 0x00b0, 0x0000); 59 } 60 61 static int bcm7xxx_28nm_b0_afe_config_init(struct phy_device *phydev) 62 { 63 /* Increase VCO range to prevent unlocking problem of PLL at low 64 * temp 65 */ 66 bcm_phy_write_misc(phydev, PLL_PLLCTRL_1, 0x0048); 67 68 /* Change Ki to 011 */ 69 bcm_phy_write_misc(phydev, PLL_PLLCTRL_2, 0x021b); 70 71 /* Disable loading of TVCO buffer to bandgap, set bandgap trim 72 * to 111 73 */ 74 bcm_phy_write_misc(phydev, PLL_PLLCTRL_4, 0x0e20); 75 76 /* Adjust bias current trim by -3 */ 77 bcm_phy_write_misc(phydev, DSP_TAP10, 0x690b); 78 79 /* Switch to CORE_BASE1E */ 80 phy_write(phydev, MII_BRCM_CORE_BASE1E, 0xd); 81 82 r_rc_cal_reset(phydev); 83 84 /* write AFE_RXCONFIG_0 */ 85 bcm_phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb19); 86 87 /* write AFE_RXCONFIG_1 */ 88 bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9a3f); 89 90 /* write AFE_RX_LP_COUNTER */ 91 bcm_phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0); 92 93 /* write AFE_HPF_TRIM_OTHERS */ 94 bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x000b); 95 96 /* write AFTE_TX_CONFIG */ 97 bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x0800); 98 99 return 0; 100 } 101 102 static int bcm7xxx_28nm_d0_afe_config_init(struct phy_device *phydev) 103 { 104 /* AFE_RXCONFIG_0 */ 105 bcm_phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb15); 106 107 /* AFE_RXCONFIG_1 */ 108 bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f); 109 110 /* AFE_RXCONFIG_2, set rCal offset for HT=0 code and LT=-2 code */ 111 bcm_phy_write_misc(phydev, AFE_RXCONFIG_2, 0x2003); 112 113 /* AFE_RX_LP_COUNTER, set RX bandwidth to maximum */ 114 bcm_phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0); 115 116 /* AFE_TX_CONFIG, set 100BT Cfeed=011 to improve rise/fall time */ 117 bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x431); 118 119 /* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB symmetry */ 120 bcm_phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da); 121 122 /* AFE_VDAC_OTHERS_0, set 1000BT Cidac=010 for all ports */ 123 bcm_phy_write_misc(phydev, AFE_VDAC_OTHERS_0, 0xa020); 124 125 /* AFE_HPF_TRIM_OTHERS, set 100Tx/10BT to -4.5% swing and set rCal 126 * offset for HT=0 code 127 */ 128 bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3); 129 130 /* CORE_BASE1E, force trim to overwrite and set I_ext trim to 0000 */ 131 phy_write(phydev, MII_BRCM_CORE_BASE1E, 0x0010); 132 133 /* DSP_TAP10, adjust bias current trim (+0% swing, +0 tick) */ 134 bcm_phy_write_misc(phydev, DSP_TAP10, 0x011b); 135 136 /* Reset R_CAL/RC_CAL engine */ 137 r_rc_cal_reset(phydev); 138 139 return 0; 140 } 141 142 static int bcm7xxx_28nm_e0_plus_afe_config_init(struct phy_device *phydev) 143 { 144 /* AFE_RXCONFIG_1, provide more margin for INL/DNL measurement */ 145 bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f); 146 147 /* AFE_TX_CONFIG, set 100BT Cfeed=011 to improve rise/fall time */ 148 bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x431); 149 150 /* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB symmetry */ 151 bcm_phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da); 152 153 /* AFE_HPF_TRIM_OTHERS, set 100Tx/10BT to -4.5% swing and set rCal 154 * offset for HT=0 code 155 */ 156 bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3); 157 158 /* CORE_BASE1E, force trim to overwrite and set I_ext trim to 0000 */ 159 phy_write(phydev, MII_BRCM_CORE_BASE1E, 0x0010); 160 161 /* DSP_TAP10, adjust bias current trim (+0% swing, +0 tick) */ 162 bcm_phy_write_misc(phydev, DSP_TAP10, 0x011b); 163 164 /* Reset R_CAL/RC_CAL engine */ 165 r_rc_cal_reset(phydev); 166 167 return 0; 168 } 169 170 static int bcm7xxx_28nm_config_init(struct phy_device *phydev) 171 { 172 u8 rev = PHY_BRCM_7XXX_REV(phydev->dev_flags); 173 u8 patch = PHY_BRCM_7XXX_PATCH(phydev->dev_flags); 174 u8 count; 175 int ret = 0; 176 177 pr_info_once("%s: %s PHY revision: 0x%02x, patch: %d\n", 178 phydev_name(phydev), phydev->drv->name, rev, patch); 179 180 /* Dummy read to a register to workaround an issue upon reset where the 181 * internal inverter may not allow the first MDIO transaction to pass 182 * the MDIO management controller and make us return 0xffff for such 183 * reads. 184 */ 185 phy_read(phydev, MII_BMSR); 186 187 switch (rev) { 188 case 0xb0: 189 ret = bcm7xxx_28nm_b0_afe_config_init(phydev); 190 break; 191 case 0xd0: 192 ret = bcm7xxx_28nm_d0_afe_config_init(phydev); 193 break; 194 case 0xe0: 195 case 0xf0: 196 /* Rev G0 introduces a roll over */ 197 case 0x10: 198 ret = bcm7xxx_28nm_e0_plus_afe_config_init(phydev); 199 break; 200 default: 201 break; 202 } 203 204 if (ret) 205 return ret; 206 207 ret = bcm_phy_downshift_get(phydev, &count); 208 if (ret) 209 return ret; 210 211 /* Only enable EEE if Wirespeed/downshift is disabled */ 212 ret = bcm_phy_set_eee(phydev, count == DOWNSHIFT_DEV_DISABLE); 213 if (ret) 214 return ret; 215 216 return bcm_phy_enable_apd(phydev, true); 217 } 218 219 static int bcm7xxx_28nm_resume(struct phy_device *phydev) 220 { 221 int ret; 222 223 /* Re-apply workarounds coming out suspend/resume */ 224 ret = bcm7xxx_28nm_config_init(phydev); 225 if (ret) 226 return ret; 227 228 /* 28nm Gigabit PHYs come out of reset without any half-duplex 229 * or "hub" compliant advertised mode, fix that. This does not 230 * cause any problems with the PHY library since genphy_config_aneg() 231 * gracefully handles auto-negotiated and forced modes. 232 */ 233 return genphy_config_aneg(phydev); 234 } 235 236 static int phy_set_clr_bits(struct phy_device *dev, int location, 237 int set_mask, int clr_mask) 238 { 239 int v, ret; 240 241 v = phy_read(dev, location); 242 if (v < 0) 243 return v; 244 245 v &= ~clr_mask; 246 v |= set_mask; 247 248 ret = phy_write(dev, location, v); 249 if (ret < 0) 250 return ret; 251 252 return v; 253 } 254 255 static int bcm7xxx_config_init(struct phy_device *phydev) 256 { 257 int ret; 258 259 /* Enable 64 clock MDIO */ 260 phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XXX_64CLK_MDIO); 261 phy_read(phydev, MII_BCM7XXX_AUX_MODE); 262 263 /* set shadow mode 2 */ 264 ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 265 MII_BCM7XXX_SHD_MODE_2, MII_BCM7XXX_SHD_MODE_2); 266 if (ret < 0) 267 return ret; 268 269 /* set iddq_clkbias */ 270 phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0F00); 271 udelay(10); 272 273 /* reset iddq_clkbias */ 274 phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0C00); 275 276 phy_write(phydev, MII_BCM7XXX_100TX_FALSE_CAR, 0x7555); 277 278 /* reset shadow mode 2 */ 279 ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0, MII_BCM7XXX_SHD_MODE_2); 280 if (ret < 0) 281 return ret; 282 283 return 0; 284 } 285 286 /* Workaround for putting the PHY in IDDQ mode, required 287 * for all BCM7XXX 40nm and 65nm PHYs 288 */ 289 static int bcm7xxx_suspend(struct phy_device *phydev) 290 { 291 int ret; 292 const struct bcm7xxx_regs { 293 int reg; 294 u16 value; 295 } bcm7xxx_suspend_cfg[] = { 296 { MII_BCM7XXX_TEST, 0x008b }, 297 { MII_BCM7XXX_100TX_AUX_CTL, 0x01c0 }, 298 { MII_BCM7XXX_100TX_DISC, 0x7000 }, 299 { MII_BCM7XXX_TEST, 0x000f }, 300 { MII_BCM7XXX_100TX_AUX_CTL, 0x20d0 }, 301 { MII_BCM7XXX_TEST, 0x000b }, 302 }; 303 unsigned int i; 304 305 for (i = 0; i < ARRAY_SIZE(bcm7xxx_suspend_cfg); i++) { 306 ret = phy_write(phydev, 307 bcm7xxx_suspend_cfg[i].reg, 308 bcm7xxx_suspend_cfg[i].value); 309 if (ret) 310 return ret; 311 } 312 313 return 0; 314 } 315 316 static int bcm7xxx_28nm_get_tunable(struct phy_device *phydev, 317 struct ethtool_tunable *tuna, 318 void *data) 319 { 320 switch (tuna->id) { 321 case ETHTOOL_PHY_DOWNSHIFT: 322 return bcm_phy_downshift_get(phydev, (u8 *)data); 323 default: 324 return -EOPNOTSUPP; 325 } 326 } 327 328 static int bcm7xxx_28nm_set_tunable(struct phy_device *phydev, 329 struct ethtool_tunable *tuna, 330 const void *data) 331 { 332 u8 count = *(u8 *)data; 333 int ret; 334 335 switch (tuna->id) { 336 case ETHTOOL_PHY_DOWNSHIFT: 337 ret = bcm_phy_downshift_set(phydev, count); 338 break; 339 default: 340 return -EOPNOTSUPP; 341 } 342 343 if (ret) 344 return ret; 345 346 /* Disable EEE advertisment since this prevents the PHY 347 * from successfully linking up, trigger auto-negotiation restart 348 * to let the MAC decide what to do. 349 */ 350 ret = bcm_phy_set_eee(phydev, count == DOWNSHIFT_DEV_DISABLE); 351 if (ret) 352 return ret; 353 354 return genphy_restart_aneg(phydev); 355 } 356 357 static void bcm7xxx_28nm_get_phy_stats(struct phy_device *phydev, 358 struct ethtool_stats *stats, u64 *data) 359 { 360 struct bcm7xxx_phy_priv *priv = phydev->priv; 361 362 bcm_phy_get_stats(phydev, priv->stats, stats, data); 363 } 364 365 static int bcm7xxx_28nm_probe(struct phy_device *phydev) 366 { 367 struct bcm7xxx_phy_priv *priv; 368 369 priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); 370 if (!priv) 371 return -ENOMEM; 372 373 phydev->priv = priv; 374 375 priv->stats = devm_kcalloc(&phydev->mdio.dev, 376 bcm_phy_get_sset_count(phydev), sizeof(u64), 377 GFP_KERNEL); 378 if (!priv->stats) 379 return -ENOMEM; 380 381 return 0; 382 } 383 384 #define BCM7XXX_28NM_GPHY(_oui, _name) \ 385 { \ 386 .phy_id = (_oui), \ 387 .phy_id_mask = 0xfffffff0, \ 388 .name = _name, \ 389 .features = PHY_GBIT_FEATURES, \ 390 .flags = PHY_IS_INTERNAL, \ 391 .config_init = bcm7xxx_28nm_config_init, \ 392 .config_aneg = genphy_config_aneg, \ 393 .read_status = genphy_read_status, \ 394 .resume = bcm7xxx_28nm_resume, \ 395 .get_tunable = bcm7xxx_28nm_get_tunable, \ 396 .set_tunable = bcm7xxx_28nm_set_tunable, \ 397 .get_sset_count = bcm_phy_get_sset_count, \ 398 .get_strings = bcm_phy_get_strings, \ 399 .get_stats = bcm7xxx_28nm_get_phy_stats, \ 400 .probe = bcm7xxx_28nm_probe, \ 401 } 402 403 #define BCM7XXX_40NM_EPHY(_oui, _name) \ 404 { \ 405 .phy_id = (_oui), \ 406 .phy_id_mask = 0xfffffff0, \ 407 .name = _name, \ 408 .features = PHY_BASIC_FEATURES, \ 409 .flags = PHY_IS_INTERNAL, \ 410 .config_init = bcm7xxx_config_init, \ 411 .config_aneg = genphy_config_aneg, \ 412 .read_status = genphy_read_status, \ 413 .suspend = bcm7xxx_suspend, \ 414 .resume = bcm7xxx_config_init, \ 415 } 416 417 static struct phy_driver bcm7xxx_driver[] = { 418 BCM7XXX_28NM_GPHY(PHY_ID_BCM7250, "Broadcom BCM7250"), 419 BCM7XXX_28NM_GPHY(PHY_ID_BCM7364, "Broadcom BCM7364"), 420 BCM7XXX_28NM_GPHY(PHY_ID_BCM7366, "Broadcom BCM7366"), 421 BCM7XXX_28NM_GPHY(PHY_ID_BCM7439, "Broadcom BCM7439"), 422 BCM7XXX_28NM_GPHY(PHY_ID_BCM7439_2, "Broadcom BCM7439 (2)"), 423 BCM7XXX_28NM_GPHY(PHY_ID_BCM7445, "Broadcom BCM7445"), 424 BCM7XXX_40NM_EPHY(PHY_ID_BCM7346, "Broadcom BCM7346"), 425 BCM7XXX_40NM_EPHY(PHY_ID_BCM7362, "Broadcom BCM7362"), 426 BCM7XXX_40NM_EPHY(PHY_ID_BCM7425, "Broadcom BCM7425"), 427 BCM7XXX_40NM_EPHY(PHY_ID_BCM7429, "Broadcom BCM7429"), 428 BCM7XXX_40NM_EPHY(PHY_ID_BCM7435, "Broadcom BCM7435"), 429 }; 430 431 static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = { 432 { PHY_ID_BCM7250, 0xfffffff0, }, 433 { PHY_ID_BCM7364, 0xfffffff0, }, 434 { PHY_ID_BCM7366, 0xfffffff0, }, 435 { PHY_ID_BCM7346, 0xfffffff0, }, 436 { PHY_ID_BCM7362, 0xfffffff0, }, 437 { PHY_ID_BCM7425, 0xfffffff0, }, 438 { PHY_ID_BCM7429, 0xfffffff0, }, 439 { PHY_ID_BCM7439, 0xfffffff0, }, 440 { PHY_ID_BCM7435, 0xfffffff0, }, 441 { PHY_ID_BCM7445, 0xfffffff0, }, 442 { } 443 }; 444 445 module_phy_driver(bcm7xxx_driver); 446 447 MODULE_DEVICE_TABLE(mdio, bcm7xxx_tbl); 448 449 MODULE_DESCRIPTION("Broadcom BCM7xxx internal PHY driver"); 450 MODULE_LICENSE("GPL"); 451 MODULE_AUTHOR("Broadcom Corporation"); 452