1b560a58cSFlorian Fainelli /* 2b560a58cSFlorian Fainelli * Broadcom BCM7xxx internal transceivers support. 3b560a58cSFlorian Fainelli * 483ee102aSDoug Berger * Copyright (C) 2014-2017 Broadcom 5b560a58cSFlorian Fainelli * 6b560a58cSFlorian Fainelli * This program is free software; you can redistribute it and/or 7b560a58cSFlorian Fainelli * modify it under the terms of the GNU General Public License 8b560a58cSFlorian Fainelli * as published by the Free Software Foundation; either version 9b560a58cSFlorian Fainelli * 2 of the License, or (at your option) any later version. 10b560a58cSFlorian Fainelli */ 11b560a58cSFlorian Fainelli 12b560a58cSFlorian Fainelli #include <linux/module.h> 13b560a58cSFlorian Fainelli #include <linux/phy.h> 14b560a58cSFlorian Fainelli #include <linux/delay.h> 15a1cba561SArun Parameswaran #include "bcm-phy-lib.h" 16b560a58cSFlorian Fainelli #include <linux/bitops.h> 17b560a58cSFlorian Fainelli #include <linux/brcmphy.h> 18b8f9a029SFlorian Fainelli #include <linux/mdio.h> 19b560a58cSFlorian Fainelli 20b560a58cSFlorian Fainelli /* Broadcom BCM7xxx internal PHY registers */ 21b560a58cSFlorian Fainelli 2283ee102aSDoug Berger /* EPHY only register definitions */ 23b560a58cSFlorian Fainelli #define MII_BCM7XXX_100TX_AUX_CTL 0x10 24b560a58cSFlorian Fainelli #define MII_BCM7XXX_100TX_FALSE_CAR 0x13 25b560a58cSFlorian Fainelli #define MII_BCM7XXX_100TX_DISC 0x14 26b560a58cSFlorian Fainelli #define MII_BCM7XXX_AUX_MODE 0x1d 273ccc3055SFlorian Fainelli #define MII_BCM7XXX_64CLK_MDIO BIT(12) 28b560a58cSFlorian Fainelli #define MII_BCM7XXX_TEST 0x1f 29b560a58cSFlorian Fainelli #define MII_BCM7XXX_SHD_MODE_2 BIT(2) 3083ee102aSDoug Berger #define MII_BCM7XXX_SHD_2_ADDR_CTRL 0xe 3183ee102aSDoug Berger #define MII_BCM7XXX_SHD_2_CTRL_STAT 0xf 3283ee102aSDoug Berger #define MII_BCM7XXX_SHD_2_BIAS_TRIM 0x1a 3383ee102aSDoug Berger #define MII_BCM7XXX_SHD_3_AN_EEE_ADV 0x3 3483ee102aSDoug Berger #define MII_BCM7XXX_SHD_3_PCS_CTRL_2 0x6 3583ee102aSDoug Berger #define MII_BCM7XXX_PCS_CTRL_2_DEF 0x4400 3683ee102aSDoug Berger #define MII_BCM7XXX_SHD_3_AN_STAT 0xb 3783ee102aSDoug Berger #define MII_BCM7XXX_AN_NULL_MSG_EN BIT(0) 3883ee102aSDoug Berger #define MII_BCM7XXX_AN_EEE_EN BIT(1) 3983ee102aSDoug Berger #define MII_BCM7XXX_SHD_3_EEE_THRESH 0xe 4083ee102aSDoug Berger #define MII_BCM7XXX_EEE_THRESH_DEF 0x50 4183ee102aSDoug Berger #define MII_BCM7XXX_SHD_3_TL4 0x23 4283ee102aSDoug Berger #define MII_BCM7XXX_TL4_RST_MSK (BIT(2) | BIT(1)) 43b560a58cSFlorian Fainelli 44a3622f2cSFlorian Fainelli /* 28nm only register definitions */ 45a3622f2cSFlorian Fainelli #define MISC_ADDR(base, channel) base, channel 46a3622f2cSFlorian Fainelli 47a3622f2cSFlorian Fainelli #define DSP_TAP10 MISC_ADDR(0x0a, 0) 48a3622f2cSFlorian Fainelli #define PLL_PLLCTRL_1 MISC_ADDR(0x32, 1) 49a3622f2cSFlorian Fainelli #define PLL_PLLCTRL_2 MISC_ADDR(0x32, 2) 50a3622f2cSFlorian Fainelli #define PLL_PLLCTRL_4 MISC_ADDR(0x33, 0) 51a3622f2cSFlorian Fainelli 52a3622f2cSFlorian Fainelli #define AFE_RXCONFIG_0 MISC_ADDR(0x38, 0) 53a3622f2cSFlorian Fainelli #define AFE_RXCONFIG_1 MISC_ADDR(0x38, 1) 54a490631fSFlorian Fainelli #define AFE_RXCONFIG_2 MISC_ADDR(0x38, 2) 55a3622f2cSFlorian Fainelli #define AFE_RX_LP_COUNTER MISC_ADDR(0x38, 3) 56a3622f2cSFlorian Fainelli #define AFE_TX_CONFIG MISC_ADDR(0x39, 0) 57a490631fSFlorian Fainelli #define AFE_VDCA_ICTRL_0 MISC_ADDR(0x39, 1) 58a490631fSFlorian Fainelli #define AFE_VDAC_OTHERS_0 MISC_ADDR(0x39, 3) 59a3622f2cSFlorian Fainelli #define AFE_HPF_TRIM_OTHERS MISC_ADDR(0x3a, 0) 60a3622f2cSFlorian Fainelli 61b23ce9e8SFlorian Fainelli struct bcm7xxx_phy_priv { 62b23ce9e8SFlorian Fainelli u64 *stats; 63b23ce9e8SFlorian Fainelli }; 64b23ce9e8SFlorian Fainelli 659c41f2baSFlorian Fainelli static void r_rc_cal_reset(struct phy_device *phydev) 669c41f2baSFlorian Fainelli { 679c41f2baSFlorian Fainelli /* Reset R_CAL/RC_CAL Engine */ 68a1cba561SArun Parameswaran bcm_phy_write_exp(phydev, 0x00b0, 0x0010); 699c41f2baSFlorian Fainelli 709c41f2baSFlorian Fainelli /* Disable Reset R_AL/RC_CAL Engine */ 71a1cba561SArun Parameswaran bcm_phy_write_exp(phydev, 0x00b0, 0x0000); 729c41f2baSFlorian Fainelli } 739c41f2baSFlorian Fainelli 742a9df742SFlorian Fainelli static int bcm7xxx_28nm_b0_afe_config_init(struct phy_device *phydev) 75b560a58cSFlorian Fainelli { 76b560a58cSFlorian Fainelli /* Increase VCO range to prevent unlocking problem of PLL at low 77b560a58cSFlorian Fainelli * temp 78b560a58cSFlorian Fainelli */ 79a1cba561SArun Parameswaran bcm_phy_write_misc(phydev, PLL_PLLCTRL_1, 0x0048); 80b560a58cSFlorian Fainelli 81b560a58cSFlorian Fainelli /* Change Ki to 011 */ 82a1cba561SArun Parameswaran bcm_phy_write_misc(phydev, PLL_PLLCTRL_2, 0x021b); 83b560a58cSFlorian Fainelli 84b560a58cSFlorian Fainelli /* Disable loading of TVCO buffer to bandgap, set bandgap trim 85b560a58cSFlorian Fainelli * to 111 86b560a58cSFlorian Fainelli */ 87a1cba561SArun Parameswaran bcm_phy_write_misc(phydev, PLL_PLLCTRL_4, 0x0e20); 88b560a58cSFlorian Fainelli 89b560a58cSFlorian Fainelli /* Adjust bias current trim by -3 */ 90a1cba561SArun Parameswaran bcm_phy_write_misc(phydev, DSP_TAP10, 0x690b); 91b560a58cSFlorian Fainelli 92b560a58cSFlorian Fainelli /* Switch to CORE_BASE1E */ 939200c27aSArun Parameswaran phy_write(phydev, MII_BRCM_CORE_BASE1E, 0xd); 94b560a58cSFlorian Fainelli 959c41f2baSFlorian Fainelli r_rc_cal_reset(phydev); 96b560a58cSFlorian Fainelli 979918542eSFlorian Fainelli /* write AFE_RXCONFIG_0 */ 98a1cba561SArun Parameswaran bcm_phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb19); 999918542eSFlorian Fainelli 1009918542eSFlorian Fainelli /* write AFE_RXCONFIG_1 */ 101a1cba561SArun Parameswaran bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9a3f); 1029918542eSFlorian Fainelli 1039918542eSFlorian Fainelli /* write AFE_RX_LP_COUNTER */ 104a1cba561SArun Parameswaran bcm_phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0); 1059918542eSFlorian Fainelli 1069918542eSFlorian Fainelli /* write AFE_HPF_TRIM_OTHERS */ 107a1cba561SArun Parameswaran bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x000b); 1089918542eSFlorian Fainelli 1099918542eSFlorian Fainelli /* write AFTE_TX_CONFIG */ 110a1cba561SArun Parameswaran bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x0800); 1119918542eSFlorian Fainelli 112b560a58cSFlorian Fainelli return 0; 113b560a58cSFlorian Fainelli } 114b560a58cSFlorian Fainelli 115a490631fSFlorian Fainelli static int bcm7xxx_28nm_d0_afe_config_init(struct phy_device *phydev) 116a490631fSFlorian Fainelli { 117a490631fSFlorian Fainelli /* AFE_RXCONFIG_0 */ 118a1cba561SArun Parameswaran bcm_phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb15); 119a490631fSFlorian Fainelli 120a490631fSFlorian Fainelli /* AFE_RXCONFIG_1 */ 121a1cba561SArun Parameswaran bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f); 122a490631fSFlorian Fainelli 123a490631fSFlorian Fainelli /* AFE_RXCONFIG_2, set rCal offset for HT=0 code and LT=-2 code */ 124a1cba561SArun Parameswaran bcm_phy_write_misc(phydev, AFE_RXCONFIG_2, 0x2003); 125a490631fSFlorian Fainelli 126a490631fSFlorian Fainelli /* AFE_RX_LP_COUNTER, set RX bandwidth to maximum */ 127a1cba561SArun Parameswaran bcm_phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0); 128a490631fSFlorian Fainelli 1296da8253bSFlorian Fainelli /* AFE_TX_CONFIG, set 100BT Cfeed=011 to improve rise/fall time */ 130a1cba561SArun Parameswaran bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x431); 131a490631fSFlorian Fainelli 132a490631fSFlorian Fainelli /* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB symmetry */ 133a1cba561SArun Parameswaran bcm_phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da); 134a490631fSFlorian Fainelli 135a490631fSFlorian Fainelli /* AFE_VDAC_OTHERS_0, set 1000BT Cidac=010 for all ports */ 136a1cba561SArun Parameswaran bcm_phy_write_misc(phydev, AFE_VDAC_OTHERS_0, 0xa020); 137a490631fSFlorian Fainelli 138a490631fSFlorian Fainelli /* AFE_HPF_TRIM_OTHERS, set 100Tx/10BT to -4.5% swing and set rCal 139a490631fSFlorian Fainelli * offset for HT=0 code 140a490631fSFlorian Fainelli */ 141a1cba561SArun Parameswaran bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3); 142a490631fSFlorian Fainelli 143a490631fSFlorian Fainelli /* CORE_BASE1E, force trim to overwrite and set I_ext trim to 0000 */ 1449200c27aSArun Parameswaran phy_write(phydev, MII_BRCM_CORE_BASE1E, 0x0010); 145a490631fSFlorian Fainelli 146a490631fSFlorian Fainelli /* DSP_TAP10, adjust bias current trim (+0% swing, +0 tick) */ 147a1cba561SArun Parameswaran bcm_phy_write_misc(phydev, DSP_TAP10, 0x011b); 148a490631fSFlorian Fainelli 149a490631fSFlorian Fainelli /* Reset R_CAL/RC_CAL engine */ 150a490631fSFlorian Fainelli r_rc_cal_reset(phydev); 151a490631fSFlorian Fainelli 152a490631fSFlorian Fainelli return 0; 153a490631fSFlorian Fainelli } 154a490631fSFlorian Fainelli 1550c2fdc25SFlorian Fainelli static int bcm7xxx_28nm_e0_plus_afe_config_init(struct phy_device *phydev) 1560c2fdc25SFlorian Fainelli { 1570c2fdc25SFlorian Fainelli /* AFE_RXCONFIG_1, provide more margin for INL/DNL measurement */ 158a1cba561SArun Parameswaran bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f); 1590c2fdc25SFlorian Fainelli 1606da8253bSFlorian Fainelli /* AFE_TX_CONFIG, set 100BT Cfeed=011 to improve rise/fall time */ 161a1cba561SArun Parameswaran bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x431); 1626da8253bSFlorian Fainelli 1630c2fdc25SFlorian Fainelli /* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB symmetry */ 164a1cba561SArun Parameswaran bcm_phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da); 1650c2fdc25SFlorian Fainelli 1660c2fdc25SFlorian Fainelli /* AFE_HPF_TRIM_OTHERS, set 100Tx/10BT to -4.5% swing and set rCal 1670c2fdc25SFlorian Fainelli * offset for HT=0 code 1680c2fdc25SFlorian Fainelli */ 169a1cba561SArun Parameswaran bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3); 1700c2fdc25SFlorian Fainelli 1710c2fdc25SFlorian Fainelli /* CORE_BASE1E, force trim to overwrite and set I_ext trim to 0000 */ 1729200c27aSArun Parameswaran phy_write(phydev, MII_BRCM_CORE_BASE1E, 0x0010); 1730c2fdc25SFlorian Fainelli 1740c2fdc25SFlorian Fainelli /* DSP_TAP10, adjust bias current trim (+0% swing, +0 tick) */ 175a1cba561SArun Parameswaran bcm_phy_write_misc(phydev, DSP_TAP10, 0x011b); 1760c2fdc25SFlorian Fainelli 1770c2fdc25SFlorian Fainelli /* Reset R_CAL/RC_CAL engine */ 1780c2fdc25SFlorian Fainelli r_rc_cal_reset(phydev); 1790c2fdc25SFlorian Fainelli 1800c2fdc25SFlorian Fainelli return 0; 1810c2fdc25SFlorian Fainelli } 1820c2fdc25SFlorian Fainelli 183039a7b85SFlorian Fainelli static int bcm7xxx_28nm_a0_patch_afe_config_init(struct phy_device *phydev) 184039a7b85SFlorian Fainelli { 185039a7b85SFlorian Fainelli /* +1 RC_CAL codes for RL centering for both LT and HT conditions */ 186039a7b85SFlorian Fainelli bcm_phy_write_misc(phydev, AFE_RXCONFIG_2, 0xd003); 187039a7b85SFlorian Fainelli 188039a7b85SFlorian Fainelli /* Cut master bias current by 2% to compensate for RC_CAL offset */ 189039a7b85SFlorian Fainelli bcm_phy_write_misc(phydev, DSP_TAP10, 0x791b); 190039a7b85SFlorian Fainelli 191039a7b85SFlorian Fainelli /* Improve hybrid leakage */ 192039a7b85SFlorian Fainelli bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x10e3); 193039a7b85SFlorian Fainelli 194039a7b85SFlorian Fainelli /* Change rx_on_tune 8 to 0xf */ 195039a7b85SFlorian Fainelli bcm_phy_write_misc(phydev, 0x21, 0x2, 0x87f6); 196039a7b85SFlorian Fainelli 197039a7b85SFlorian Fainelli /* Change 100Tx EEE bandwidth */ 198039a7b85SFlorian Fainelli bcm_phy_write_misc(phydev, 0x22, 0x2, 0x017d); 199039a7b85SFlorian Fainelli 200039a7b85SFlorian Fainelli /* Enable ffe zero detection for Vitesse interoperability */ 201039a7b85SFlorian Fainelli bcm_phy_write_misc(phydev, 0x26, 0x2, 0x0015); 202039a7b85SFlorian Fainelli 203039a7b85SFlorian Fainelli r_rc_cal_reset(phydev); 204039a7b85SFlorian Fainelli 205039a7b85SFlorian Fainelli return 0; 206039a7b85SFlorian Fainelli } 207039a7b85SFlorian Fainelli 208b560a58cSFlorian Fainelli static int bcm7xxx_28nm_config_init(struct phy_device *phydev) 209b560a58cSFlorian Fainelli { 210d8ebfed3SFlorian Fainelli u8 rev = PHY_BRCM_7XXX_REV(phydev->dev_flags); 211d8ebfed3SFlorian Fainelli u8 patch = PHY_BRCM_7XXX_PATCH(phydev->dev_flags); 212db88816bSFlorian Fainelli u8 count; 213d8ebfed3SFlorian Fainelli int ret = 0; 214b560a58cSFlorian Fainelli 215039a7b85SFlorian Fainelli /* Newer devices have moved the revision information back into a 216039a7b85SFlorian Fainelli * standard location in MII_PHYS_ID[23] 217039a7b85SFlorian Fainelli */ 218039a7b85SFlorian Fainelli if (rev == 0) 219039a7b85SFlorian Fainelli rev = phydev->phy_id & ~phydev->drv->phy_id_mask; 220039a7b85SFlorian Fainelli 2216ec259c1SFlorian Fainelli pr_info_once("%s: %s PHY revision: 0x%02x, patch: %d\n", 22284eff6d1SAndrew Lunn phydev_name(phydev), phydev->drv->name, rev, patch); 223d8ebfed3SFlorian Fainelli 2248e346e15SFlorian Fainelli /* Dummy read to a register to workaround an issue upon reset where the 2258e346e15SFlorian Fainelli * internal inverter may not allow the first MDIO transaction to pass 2268e346e15SFlorian Fainelli * the MDIO management controller and make us return 0xffff for such 2278e346e15SFlorian Fainelli * reads. 2288e346e15SFlorian Fainelli */ 2298e346e15SFlorian Fainelli phy_read(phydev, MII_BMSR); 2308e346e15SFlorian Fainelli 231d8ebfed3SFlorian Fainelli switch (rev) { 232d8ebfed3SFlorian Fainelli case 0xb0: 2332a9df742SFlorian Fainelli ret = bcm7xxx_28nm_b0_afe_config_init(phydev); 234d8ebfed3SFlorian Fainelli break; 235a490631fSFlorian Fainelli case 0xd0: 236a490631fSFlorian Fainelli ret = bcm7xxx_28nm_d0_afe_config_init(phydev); 237a490631fSFlorian Fainelli break; 2380c2fdc25SFlorian Fainelli case 0xe0: 2390c2fdc25SFlorian Fainelli case 0xf0: 24060efff0cSFlorian Fainelli /* Rev G0 introduces a roll over */ 24160efff0cSFlorian Fainelli case 0x10: 2420c2fdc25SFlorian Fainelli ret = bcm7xxx_28nm_e0_plus_afe_config_init(phydev); 2430c2fdc25SFlorian Fainelli break; 244039a7b85SFlorian Fainelli case 0x01: 245039a7b85SFlorian Fainelli ret = bcm7xxx_28nm_a0_patch_afe_config_init(phydev); 246039a7b85SFlorian Fainelli break; 247d8ebfed3SFlorian Fainelli default: 248d8ebfed3SFlorian Fainelli break; 249d8ebfed3SFlorian Fainelli } 250d8ebfed3SFlorian Fainelli 2519df54ddaSFlorian Fainelli if (ret) 2529df54ddaSFlorian Fainelli return ret; 2539df54ddaSFlorian Fainelli 254db88816bSFlorian Fainelli ret = bcm_phy_downshift_get(phydev, &count); 255db88816bSFlorian Fainelli if (ret) 256db88816bSFlorian Fainelli return ret; 257db88816bSFlorian Fainelli 258db88816bSFlorian Fainelli /* Only enable EEE if Wirespeed/downshift is disabled */ 259db88816bSFlorian Fainelli ret = bcm_phy_set_eee(phydev, count == DOWNSHIFT_DEV_DISABLE); 260b8f9a029SFlorian Fainelli if (ret) 261b8f9a029SFlorian Fainelli return ret; 262b8f9a029SFlorian Fainelli 263a1cba561SArun Parameswaran return bcm_phy_enable_apd(phydev, true); 264b560a58cSFlorian Fainelli } 265b560a58cSFlorian Fainelli 2664fd14e0bSFlorian Fainelli static int bcm7xxx_28nm_resume(struct phy_device *phydev) 2674fd14e0bSFlorian Fainelli { 2684fd14e0bSFlorian Fainelli int ret; 2694fd14e0bSFlorian Fainelli 2704fd14e0bSFlorian Fainelli /* Re-apply workarounds coming out suspend/resume */ 2714fd14e0bSFlorian Fainelli ret = bcm7xxx_28nm_config_init(phydev); 2724fd14e0bSFlorian Fainelli if (ret) 2734fd14e0bSFlorian Fainelli return ret; 2744fd14e0bSFlorian Fainelli 2754fd14e0bSFlorian Fainelli /* 28nm Gigabit PHYs come out of reset without any half-duplex 2764fd14e0bSFlorian Fainelli * or "hub" compliant advertised mode, fix that. This does not 2774fd14e0bSFlorian Fainelli * cause any problems with the PHY library since genphy_config_aneg() 2784fd14e0bSFlorian Fainelli * gracefully handles auto-negotiated and forced modes. 2794fd14e0bSFlorian Fainelli */ 2804fd14e0bSFlorian Fainelli return genphy_config_aneg(phydev); 2814fd14e0bSFlorian Fainelli } 2824fd14e0bSFlorian Fainelli 283b560a58cSFlorian Fainelli static int phy_set_clr_bits(struct phy_device *dev, int location, 284b560a58cSFlorian Fainelli int set_mask, int clr_mask) 285b560a58cSFlorian Fainelli { 286b560a58cSFlorian Fainelli int v, ret; 287b560a58cSFlorian Fainelli 288b560a58cSFlorian Fainelli v = phy_read(dev, location); 289b560a58cSFlorian Fainelli if (v < 0) 290b560a58cSFlorian Fainelli return v; 291b560a58cSFlorian Fainelli 292b560a58cSFlorian Fainelli v &= ~clr_mask; 293b560a58cSFlorian Fainelli v |= set_mask; 294b560a58cSFlorian Fainelli 295b560a58cSFlorian Fainelli ret = phy_write(dev, location, v); 296b560a58cSFlorian Fainelli if (ret < 0) 297b560a58cSFlorian Fainelli return ret; 298b560a58cSFlorian Fainelli 299b560a58cSFlorian Fainelli return v; 300b560a58cSFlorian Fainelli } 301b560a58cSFlorian Fainelli 30283ee102aSDoug Berger static int bcm7xxx_28nm_ephy_01_afe_config_init(struct phy_device *phydev) 30383ee102aSDoug Berger { 30483ee102aSDoug Berger int ret; 30583ee102aSDoug Berger 30683ee102aSDoug Berger /* set shadow mode 2 */ 30783ee102aSDoug Berger ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 30883ee102aSDoug Berger MII_BCM7XXX_SHD_MODE_2, 0); 30983ee102aSDoug Berger if (ret < 0) 31083ee102aSDoug Berger return ret; 31183ee102aSDoug Berger 31283ee102aSDoug Berger /* Set current trim values INT_trim = -1, Ext_trim =0 */ 31383ee102aSDoug Berger ret = phy_write(phydev, MII_BCM7XXX_SHD_2_BIAS_TRIM, 0x3BE0); 31483ee102aSDoug Berger if (ret < 0) 31583ee102aSDoug Berger goto reset_shadow_mode; 31683ee102aSDoug Berger 31783ee102aSDoug Berger /* Cal reset */ 31883ee102aSDoug Berger ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL, 31983ee102aSDoug Berger MII_BCM7XXX_SHD_3_TL4); 32083ee102aSDoug Berger if (ret < 0) 32183ee102aSDoug Berger goto reset_shadow_mode; 32283ee102aSDoug Berger ret = phy_set_clr_bits(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT, 32383ee102aSDoug Berger MII_BCM7XXX_TL4_RST_MSK, 0); 32483ee102aSDoug Berger if (ret < 0) 32583ee102aSDoug Berger goto reset_shadow_mode; 32683ee102aSDoug Berger 32783ee102aSDoug Berger /* Cal reset disable */ 32883ee102aSDoug Berger ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL, 32983ee102aSDoug Berger MII_BCM7XXX_SHD_3_TL4); 33083ee102aSDoug Berger if (ret < 0) 33183ee102aSDoug Berger goto reset_shadow_mode; 33283ee102aSDoug Berger ret = phy_set_clr_bits(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT, 33383ee102aSDoug Berger 0, MII_BCM7XXX_TL4_RST_MSK); 33483ee102aSDoug Berger if (ret < 0) 33583ee102aSDoug Berger goto reset_shadow_mode; 33683ee102aSDoug Berger 33783ee102aSDoug Berger reset_shadow_mode: 33883ee102aSDoug Berger /* reset shadow mode 2 */ 33983ee102aSDoug Berger ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0, 34083ee102aSDoug Berger MII_BCM7XXX_SHD_MODE_2); 34183ee102aSDoug Berger if (ret < 0) 34283ee102aSDoug Berger return ret; 34383ee102aSDoug Berger 34483ee102aSDoug Berger return 0; 34583ee102aSDoug Berger } 34683ee102aSDoug Berger 34783ee102aSDoug Berger /* The 28nm EPHY does not support Clause 45 (MMD) used by bcm-phy-lib */ 34883ee102aSDoug Berger static int bcm7xxx_28nm_ephy_apd_enable(struct phy_device *phydev) 34983ee102aSDoug Berger { 35083ee102aSDoug Berger int ret; 35183ee102aSDoug Berger 35283ee102aSDoug Berger /* set shadow mode 1 */ 35383ee102aSDoug Berger ret = phy_set_clr_bits(phydev, MII_BRCM_FET_BRCMTEST, 35483ee102aSDoug Berger MII_BRCM_FET_BT_SRE, 0); 35583ee102aSDoug Berger if (ret < 0) 35683ee102aSDoug Berger return ret; 35783ee102aSDoug Berger 35883ee102aSDoug Berger /* Enable auto-power down */ 35983ee102aSDoug Berger ret = phy_set_clr_bits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2, 36083ee102aSDoug Berger MII_BRCM_FET_SHDW_AS2_APDE, 0); 36183ee102aSDoug Berger if (ret < 0) 36283ee102aSDoug Berger return ret; 36383ee102aSDoug Berger 36483ee102aSDoug Berger /* reset shadow mode 1 */ 36583ee102aSDoug Berger ret = phy_set_clr_bits(phydev, MII_BRCM_FET_BRCMTEST, 0, 36683ee102aSDoug Berger MII_BRCM_FET_BT_SRE); 36783ee102aSDoug Berger if (ret < 0) 36883ee102aSDoug Berger return ret; 36983ee102aSDoug Berger 37083ee102aSDoug Berger return 0; 37183ee102aSDoug Berger } 37283ee102aSDoug Berger 37383ee102aSDoug Berger static int bcm7xxx_28nm_ephy_eee_enable(struct phy_device *phydev) 37483ee102aSDoug Berger { 37583ee102aSDoug Berger int ret; 37683ee102aSDoug Berger 37783ee102aSDoug Berger /* set shadow mode 2 */ 37883ee102aSDoug Berger ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 37983ee102aSDoug Berger MII_BCM7XXX_SHD_MODE_2, 0); 38083ee102aSDoug Berger if (ret < 0) 38183ee102aSDoug Berger return ret; 38283ee102aSDoug Berger 38383ee102aSDoug Berger /* Advertise supported modes */ 38483ee102aSDoug Berger ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL, 38583ee102aSDoug Berger MII_BCM7XXX_SHD_3_AN_EEE_ADV); 38683ee102aSDoug Berger if (ret < 0) 38783ee102aSDoug Berger goto reset_shadow_mode; 38883ee102aSDoug Berger ret = phy_write(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT, 38983ee102aSDoug Berger MDIO_EEE_100TX); 39083ee102aSDoug Berger if (ret < 0) 39183ee102aSDoug Berger goto reset_shadow_mode; 39283ee102aSDoug Berger 39383ee102aSDoug Berger /* Restore Defaults */ 39483ee102aSDoug Berger ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL, 39583ee102aSDoug Berger MII_BCM7XXX_SHD_3_PCS_CTRL_2); 39683ee102aSDoug Berger if (ret < 0) 39783ee102aSDoug Berger goto reset_shadow_mode; 39883ee102aSDoug Berger ret = phy_write(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT, 39983ee102aSDoug Berger MII_BCM7XXX_PCS_CTRL_2_DEF); 40083ee102aSDoug Berger if (ret < 0) 40183ee102aSDoug Berger goto reset_shadow_mode; 40283ee102aSDoug Berger 40383ee102aSDoug Berger ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL, 40483ee102aSDoug Berger MII_BCM7XXX_SHD_3_EEE_THRESH); 40583ee102aSDoug Berger if (ret < 0) 40683ee102aSDoug Berger goto reset_shadow_mode; 40783ee102aSDoug Berger ret = phy_write(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT, 40883ee102aSDoug Berger MII_BCM7XXX_EEE_THRESH_DEF); 40983ee102aSDoug Berger if (ret < 0) 41083ee102aSDoug Berger goto reset_shadow_mode; 41183ee102aSDoug Berger 41283ee102aSDoug Berger /* Enable EEE autonegotiation */ 41383ee102aSDoug Berger ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL, 41483ee102aSDoug Berger MII_BCM7XXX_SHD_3_AN_STAT); 41583ee102aSDoug Berger if (ret < 0) 41683ee102aSDoug Berger goto reset_shadow_mode; 41783ee102aSDoug Berger ret = phy_write(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT, 41883ee102aSDoug Berger (MII_BCM7XXX_AN_NULL_MSG_EN | MII_BCM7XXX_AN_EEE_EN)); 41983ee102aSDoug Berger if (ret < 0) 42083ee102aSDoug Berger goto reset_shadow_mode; 42183ee102aSDoug Berger 42283ee102aSDoug Berger reset_shadow_mode: 42383ee102aSDoug Berger /* reset shadow mode 2 */ 42483ee102aSDoug Berger ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0, 42583ee102aSDoug Berger MII_BCM7XXX_SHD_MODE_2); 42683ee102aSDoug Berger if (ret < 0) 42783ee102aSDoug Berger return ret; 42883ee102aSDoug Berger 42983ee102aSDoug Berger /* Restart autoneg */ 43083ee102aSDoug Berger phy_write(phydev, MII_BMCR, 43183ee102aSDoug Berger (BMCR_SPEED100 | BMCR_ANENABLE | BMCR_ANRESTART)); 43283ee102aSDoug Berger 43383ee102aSDoug Berger return 0; 43483ee102aSDoug Berger } 43583ee102aSDoug Berger 43683ee102aSDoug Berger static int bcm7xxx_28nm_ephy_config_init(struct phy_device *phydev) 43783ee102aSDoug Berger { 43883ee102aSDoug Berger u8 rev = phydev->phy_id & ~phydev->drv->phy_id_mask; 43983ee102aSDoug Berger int ret = 0; 44083ee102aSDoug Berger 44183ee102aSDoug Berger pr_info_once("%s: %s PHY revision: 0x%02x\n", 44283ee102aSDoug Berger phydev_name(phydev), phydev->drv->name, rev); 44383ee102aSDoug Berger 44483ee102aSDoug Berger /* Dummy read to a register to workaround a possible issue upon reset 44583ee102aSDoug Berger * where the internal inverter may not allow the first MDIO transaction 44683ee102aSDoug Berger * to pass the MDIO management controller and make us return 0xffff for 44783ee102aSDoug Berger * such reads. 44883ee102aSDoug Berger */ 44983ee102aSDoug Berger phy_read(phydev, MII_BMSR); 45083ee102aSDoug Berger 45183ee102aSDoug Berger /* Apply AFE software work-around if necessary */ 45283ee102aSDoug Berger if (rev == 0x01) { 45383ee102aSDoug Berger ret = bcm7xxx_28nm_ephy_01_afe_config_init(phydev); 45483ee102aSDoug Berger if (ret) 45583ee102aSDoug Berger return ret; 45683ee102aSDoug Berger } 45783ee102aSDoug Berger 45883ee102aSDoug Berger ret = bcm7xxx_28nm_ephy_eee_enable(phydev); 45983ee102aSDoug Berger if (ret) 46083ee102aSDoug Berger return ret; 46183ee102aSDoug Berger 46283ee102aSDoug Berger return bcm7xxx_28nm_ephy_apd_enable(phydev); 46383ee102aSDoug Berger } 46483ee102aSDoug Berger 46583ee102aSDoug Berger static int bcm7xxx_28nm_ephy_resume(struct phy_device *phydev) 46683ee102aSDoug Berger { 46783ee102aSDoug Berger int ret; 46883ee102aSDoug Berger 46983ee102aSDoug Berger /* Re-apply workarounds coming out suspend/resume */ 47083ee102aSDoug Berger ret = bcm7xxx_28nm_ephy_config_init(phydev); 47183ee102aSDoug Berger if (ret) 47283ee102aSDoug Berger return ret; 47383ee102aSDoug Berger 47483ee102aSDoug Berger return genphy_config_aneg(phydev); 47583ee102aSDoug Berger } 47683ee102aSDoug Berger 477b560a58cSFlorian Fainelli static int bcm7xxx_config_init(struct phy_device *phydev) 478b560a58cSFlorian Fainelli { 479b560a58cSFlorian Fainelli int ret; 480b560a58cSFlorian Fainelli 481b560a58cSFlorian Fainelli /* Enable 64 clock MDIO */ 4823ccc3055SFlorian Fainelli phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XXX_64CLK_MDIO); 483b560a58cSFlorian Fainelli phy_read(phydev, MII_BCM7XXX_AUX_MODE); 484b560a58cSFlorian Fainelli 485b560a58cSFlorian Fainelli /* set shadow mode 2 */ 486b560a58cSFlorian Fainelli ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 487b560a58cSFlorian Fainelli MII_BCM7XXX_SHD_MODE_2, MII_BCM7XXX_SHD_MODE_2); 488b560a58cSFlorian Fainelli if (ret < 0) 489b560a58cSFlorian Fainelli return ret; 490b560a58cSFlorian Fainelli 491b560a58cSFlorian Fainelli /* set iddq_clkbias */ 492b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0F00); 493b560a58cSFlorian Fainelli udelay(10); 494b560a58cSFlorian Fainelli 495b560a58cSFlorian Fainelli /* reset iddq_clkbias */ 496b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0C00); 497b560a58cSFlorian Fainelli 498b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM7XXX_100TX_FALSE_CAR, 0x7555); 499b560a58cSFlorian Fainelli 500b560a58cSFlorian Fainelli /* reset shadow mode 2 */ 50150d89980SFlorian Fainelli ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0, MII_BCM7XXX_SHD_MODE_2); 502b560a58cSFlorian Fainelli if (ret < 0) 503b560a58cSFlorian Fainelli return ret; 504b560a58cSFlorian Fainelli 505b560a58cSFlorian Fainelli return 0; 506b560a58cSFlorian Fainelli } 507b560a58cSFlorian Fainelli 508b560a58cSFlorian Fainelli /* Workaround for putting the PHY in IDDQ mode, required 50982c084f5SFlorian Fainelli * for all BCM7XXX 40nm and 65nm PHYs 510b560a58cSFlorian Fainelli */ 511b560a58cSFlorian Fainelli static int bcm7xxx_suspend(struct phy_device *phydev) 512b560a58cSFlorian Fainelli { 513b560a58cSFlorian Fainelli int ret; 51433c81821SColin Ian King static const struct bcm7xxx_regs { 515b560a58cSFlorian Fainelli int reg; 516b560a58cSFlorian Fainelli u16 value; 517b560a58cSFlorian Fainelli } bcm7xxx_suspend_cfg[] = { 518b560a58cSFlorian Fainelli { MII_BCM7XXX_TEST, 0x008b }, 519b560a58cSFlorian Fainelli { MII_BCM7XXX_100TX_AUX_CTL, 0x01c0 }, 520b560a58cSFlorian Fainelli { MII_BCM7XXX_100TX_DISC, 0x7000 }, 521b560a58cSFlorian Fainelli { MII_BCM7XXX_TEST, 0x000f }, 522b560a58cSFlorian Fainelli { MII_BCM7XXX_100TX_AUX_CTL, 0x20d0 }, 523b560a58cSFlorian Fainelli { MII_BCM7XXX_TEST, 0x000b }, 524b560a58cSFlorian Fainelli }; 525b560a58cSFlorian Fainelli unsigned int i; 526b560a58cSFlorian Fainelli 527b560a58cSFlorian Fainelli for (i = 0; i < ARRAY_SIZE(bcm7xxx_suspend_cfg); i++) { 528b560a58cSFlorian Fainelli ret = phy_write(phydev, 529b560a58cSFlorian Fainelli bcm7xxx_suspend_cfg[i].reg, 530b560a58cSFlorian Fainelli bcm7xxx_suspend_cfg[i].value); 531b560a58cSFlorian Fainelli if (ret) 532b560a58cSFlorian Fainelli return ret; 533b560a58cSFlorian Fainelli } 534b560a58cSFlorian Fainelli 535b560a58cSFlorian Fainelli return 0; 536b560a58cSFlorian Fainelli } 537b560a58cSFlorian Fainelli 538db88816bSFlorian Fainelli static int bcm7xxx_28nm_get_tunable(struct phy_device *phydev, 539db88816bSFlorian Fainelli struct ethtool_tunable *tuna, 540db88816bSFlorian Fainelli void *data) 541db88816bSFlorian Fainelli { 542db88816bSFlorian Fainelli switch (tuna->id) { 543db88816bSFlorian Fainelli case ETHTOOL_PHY_DOWNSHIFT: 544db88816bSFlorian Fainelli return bcm_phy_downshift_get(phydev, (u8 *)data); 545db88816bSFlorian Fainelli default: 546db88816bSFlorian Fainelli return -EOPNOTSUPP; 547db88816bSFlorian Fainelli } 548db88816bSFlorian Fainelli } 549db88816bSFlorian Fainelli 550db88816bSFlorian Fainelli static int bcm7xxx_28nm_set_tunable(struct phy_device *phydev, 551db88816bSFlorian Fainelli struct ethtool_tunable *tuna, 552db88816bSFlorian Fainelli const void *data) 553db88816bSFlorian Fainelli { 554db88816bSFlorian Fainelli u8 count = *(u8 *)data; 555db88816bSFlorian Fainelli int ret; 556db88816bSFlorian Fainelli 557db88816bSFlorian Fainelli switch (tuna->id) { 558db88816bSFlorian Fainelli case ETHTOOL_PHY_DOWNSHIFT: 559db88816bSFlorian Fainelli ret = bcm_phy_downshift_set(phydev, count); 560db88816bSFlorian Fainelli break; 561db88816bSFlorian Fainelli default: 562db88816bSFlorian Fainelli return -EOPNOTSUPP; 563db88816bSFlorian Fainelli } 564db88816bSFlorian Fainelli 565db88816bSFlorian Fainelli if (ret) 566db88816bSFlorian Fainelli return ret; 567db88816bSFlorian Fainelli 568cc1122b0SColin Ian King /* Disable EEE advertisement since this prevents the PHY 569db88816bSFlorian Fainelli * from successfully linking up, trigger auto-negotiation restart 570db88816bSFlorian Fainelli * to let the MAC decide what to do. 571db88816bSFlorian Fainelli */ 572db88816bSFlorian Fainelli ret = bcm_phy_set_eee(phydev, count == DOWNSHIFT_DEV_DISABLE); 573db88816bSFlorian Fainelli if (ret) 574db88816bSFlorian Fainelli return ret; 575db88816bSFlorian Fainelli 576db88816bSFlorian Fainelli return genphy_restart_aneg(phydev); 577db88816bSFlorian Fainelli } 578db88816bSFlorian Fainelli 579b23ce9e8SFlorian Fainelli static void bcm7xxx_28nm_get_phy_stats(struct phy_device *phydev, 580b23ce9e8SFlorian Fainelli struct ethtool_stats *stats, u64 *data) 581b23ce9e8SFlorian Fainelli { 582b23ce9e8SFlorian Fainelli struct bcm7xxx_phy_priv *priv = phydev->priv; 583b23ce9e8SFlorian Fainelli 584b23ce9e8SFlorian Fainelli bcm_phy_get_stats(phydev, priv->stats, stats, data); 585b23ce9e8SFlorian Fainelli } 586b23ce9e8SFlorian Fainelli 587b23ce9e8SFlorian Fainelli static int bcm7xxx_28nm_probe(struct phy_device *phydev) 588b23ce9e8SFlorian Fainelli { 589b23ce9e8SFlorian Fainelli struct bcm7xxx_phy_priv *priv; 590b23ce9e8SFlorian Fainelli 591b23ce9e8SFlorian Fainelli priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); 592b23ce9e8SFlorian Fainelli if (!priv) 593b23ce9e8SFlorian Fainelli return -ENOMEM; 594b23ce9e8SFlorian Fainelli 595b23ce9e8SFlorian Fainelli phydev->priv = priv; 596b23ce9e8SFlorian Fainelli 597b23ce9e8SFlorian Fainelli priv->stats = devm_kcalloc(&phydev->mdio.dev, 598b23ce9e8SFlorian Fainelli bcm_phy_get_sset_count(phydev), sizeof(u64), 599b23ce9e8SFlorian Fainelli GFP_KERNEL); 600b23ce9e8SFlorian Fainelli if (!priv->stats) 601b23ce9e8SFlorian Fainelli return -ENOMEM; 602b23ce9e8SFlorian Fainelli 603b23ce9e8SFlorian Fainelli return 0; 604b23ce9e8SFlorian Fainelli } 605b23ce9e8SFlorian Fainelli 606153df3c7SFlorian Fainelli #define BCM7XXX_28NM_GPHY(_oui, _name) \ 607153df3c7SFlorian Fainelli { \ 608153df3c7SFlorian Fainelli .phy_id = (_oui), \ 609153df3c7SFlorian Fainelli .phy_id_mask = 0xfffffff0, \ 610153df3c7SFlorian Fainelli .name = _name, \ 611529ed127STimur Tabi .features = PHY_GBIT_FEATURES, \ 612153df3c7SFlorian Fainelli .flags = PHY_IS_INTERNAL, \ 6132a9df742SFlorian Fainelli .config_init = bcm7xxx_28nm_config_init, \ 614153df3c7SFlorian Fainelli .resume = bcm7xxx_28nm_resume, \ 615db88816bSFlorian Fainelli .get_tunable = bcm7xxx_28nm_get_tunable, \ 616db88816bSFlorian Fainelli .set_tunable = bcm7xxx_28nm_set_tunable, \ 617b23ce9e8SFlorian Fainelli .get_sset_count = bcm_phy_get_sset_count, \ 618b23ce9e8SFlorian Fainelli .get_strings = bcm_phy_get_strings, \ 619b23ce9e8SFlorian Fainelli .get_stats = bcm7xxx_28nm_get_phy_stats, \ 620b23ce9e8SFlorian Fainelli .probe = bcm7xxx_28nm_probe, \ 621153df3c7SFlorian Fainelli } 622153df3c7SFlorian Fainelli 62383ee102aSDoug Berger #define BCM7XXX_28NM_EPHY(_oui, _name) \ 62483ee102aSDoug Berger { \ 62583ee102aSDoug Berger .phy_id = (_oui), \ 62683ee102aSDoug Berger .phy_id_mask = 0xfffffff0, \ 62783ee102aSDoug Berger .name = _name, \ 62883ee102aSDoug Berger .features = PHY_BASIC_FEATURES, \ 62983ee102aSDoug Berger .flags = PHY_IS_INTERNAL, \ 63083ee102aSDoug Berger .config_init = bcm7xxx_28nm_ephy_config_init, \ 63183ee102aSDoug Berger .resume = bcm7xxx_28nm_ephy_resume, \ 63283ee102aSDoug Berger .get_sset_count = bcm_phy_get_sset_count, \ 63383ee102aSDoug Berger .get_strings = bcm_phy_get_strings, \ 63483ee102aSDoug Berger .get_stats = bcm7xxx_28nm_get_phy_stats, \ 63583ee102aSDoug Berger .probe = bcm7xxx_28nm_probe, \ 63683ee102aSDoug Berger } 63783ee102aSDoug Berger 6383125c081SFlorian Fainelli #define BCM7XXX_40NM_EPHY(_oui, _name) \ 6393125c081SFlorian Fainelli { \ 6403125c081SFlorian Fainelli .phy_id = (_oui), \ 6413125c081SFlorian Fainelli .phy_id_mask = 0xfffffff0, \ 6423125c081SFlorian Fainelli .name = _name, \ 643529ed127STimur Tabi .features = PHY_BASIC_FEATURES, \ 6443125c081SFlorian Fainelli .flags = PHY_IS_INTERNAL, \ 6453125c081SFlorian Fainelli .config_init = bcm7xxx_config_init, \ 6463125c081SFlorian Fainelli .suspend = bcm7xxx_suspend, \ 6473125c081SFlorian Fainelli .resume = bcm7xxx_config_init, \ 6483125c081SFlorian Fainelli } 6493125c081SFlorian Fainelli 650b560a58cSFlorian Fainelli static struct phy_driver bcm7xxx_driver[] = { 651430ad68fSFlorian Fainelli BCM7XXX_28NM_GPHY(PHY_ID_BCM7250, "Broadcom BCM7250"), 65283ee102aSDoug Berger BCM7XXX_28NM_EPHY(PHY_ID_BCM7260, "Broadcom BCM7260"), 65383ee102aSDoug Berger BCM7XXX_28NM_EPHY(PHY_ID_BCM7268, "Broadcom BCM7268"), 65483ee102aSDoug Berger BCM7XXX_28NM_EPHY(PHY_ID_BCM7271, "Broadcom BCM7271"), 655582d0ac3SFlorian Fainelli BCM7XXX_28NM_GPHY(PHY_ID_BCM7278, "Broadcom BCM7278"), 656430ad68fSFlorian Fainelli BCM7XXX_28NM_GPHY(PHY_ID_BCM7364, "Broadcom BCM7364"), 657153df3c7SFlorian Fainelli BCM7XXX_28NM_GPHY(PHY_ID_BCM7366, "Broadcom BCM7366"), 658b08d46b0SFlorian Fainelli BCM7XXX_28NM_GPHY(PHY_ID_BCM74371, "Broadcom BCM74371"), 659153df3c7SFlorian Fainelli BCM7XXX_28NM_GPHY(PHY_ID_BCM7439, "Broadcom BCM7439"), 66059e33c2bSFlorian Fainelli BCM7XXX_28NM_GPHY(PHY_ID_BCM7439_2, "Broadcom BCM7439 (2)"), 661153df3c7SFlorian Fainelli BCM7XXX_28NM_GPHY(PHY_ID_BCM7445, "Broadcom BCM7445"), 6624cef191dSJaedon Shin BCM7XXX_40NM_EPHY(PHY_ID_BCM7346, "Broadcom BCM7346"), 6634cef191dSJaedon Shin BCM7XXX_40NM_EPHY(PHY_ID_BCM7362, "Broadcom BCM7362"), 6643125c081SFlorian Fainelli BCM7XXX_40NM_EPHY(PHY_ID_BCM7425, "Broadcom BCM7425"), 6653125c081SFlorian Fainelli BCM7XXX_40NM_EPHY(PHY_ID_BCM7429, "Broadcom BCM7429"), 6663125c081SFlorian Fainelli BCM7XXX_40NM_EPHY(PHY_ID_BCM7435, "Broadcom BCM7435"), 667b6333531SDavid S. Miller }; 668b560a58cSFlorian Fainelli 669b560a58cSFlorian Fainelli static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = { 670430ad68fSFlorian Fainelli { PHY_ID_BCM7250, 0xfffffff0, }, 67183ee102aSDoug Berger { PHY_ID_BCM7260, 0xfffffff0, }, 67283ee102aSDoug Berger { PHY_ID_BCM7268, 0xfffffff0, }, 67383ee102aSDoug Berger { PHY_ID_BCM7271, 0xfffffff0, }, 674582d0ac3SFlorian Fainelli { PHY_ID_BCM7278, 0xfffffff0, }, 675430ad68fSFlorian Fainelli { PHY_ID_BCM7364, 0xfffffff0, }, 676b560a58cSFlorian Fainelli { PHY_ID_BCM7366, 0xfffffff0, }, 6774cef191dSJaedon Shin { PHY_ID_BCM7346, 0xfffffff0, }, 6784cef191dSJaedon Shin { PHY_ID_BCM7362, 0xfffffff0, }, 679d068b02cSPetri Gynther { PHY_ID_BCM7425, 0xfffffff0, }, 680d068b02cSPetri Gynther { PHY_ID_BCM7429, 0xfffffff0, }, 681b08d46b0SFlorian Fainelli { PHY_ID_BCM74371, 0xfffffff0, }, 682b560a58cSFlorian Fainelli { PHY_ID_BCM7439, 0xfffffff0, }, 6839458ceabSFlorian Fainelli { PHY_ID_BCM7435, 0xfffffff0, }, 684b560a58cSFlorian Fainelli { PHY_ID_BCM7445, 0xfffffff0, }, 685b560a58cSFlorian Fainelli { } 686b560a58cSFlorian Fainelli }; 687b560a58cSFlorian Fainelli 68850fd7150SJohan Hovold module_phy_driver(bcm7xxx_driver); 689b560a58cSFlorian Fainelli 690b560a58cSFlorian Fainelli MODULE_DEVICE_TABLE(mdio, bcm7xxx_tbl); 691b560a58cSFlorian Fainelli 692b560a58cSFlorian Fainelli MODULE_DESCRIPTION("Broadcom BCM7xxx internal PHY driver"); 693b560a58cSFlorian Fainelli MODULE_LICENSE("GPL"); 694b560a58cSFlorian Fainelli MODULE_AUTHOR("Broadcom Corporation"); 695