1b560a58cSFlorian Fainelli /* 2b560a58cSFlorian Fainelli * Broadcom BCM7xxx internal transceivers support. 3b560a58cSFlorian Fainelli * 4b560a58cSFlorian Fainelli * Copyright (C) 2014, Broadcom Corporation 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> 15b560a58cSFlorian Fainelli #include <linux/bitops.h> 16b560a58cSFlorian Fainelli #include <linux/brcmphy.h> 17b8f9a029SFlorian Fainelli #include <linux/mdio.h> 18b560a58cSFlorian Fainelli 19b560a58cSFlorian Fainelli /* Broadcom BCM7xxx internal PHY registers */ 20b560a58cSFlorian Fainelli #define MII_BCM7XXX_CHANNEL_WIDTH 0x2000 21b560a58cSFlorian Fainelli 22b560a58cSFlorian Fainelli /* 40nm 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 27b560a58cSFlorian Fainelli #define MII_BCM7XX_64CLK_MDIO BIT(12) 28b560a58cSFlorian Fainelli #define MII_BCM7XXX_CORE_BASE1E 0x1e 29b560a58cSFlorian Fainelli #define MII_BCM7XXX_TEST 0x1f 30b560a58cSFlorian Fainelli #define MII_BCM7XXX_SHD_MODE_2 BIT(2) 31b560a58cSFlorian Fainelli 32a3622f2cSFlorian Fainelli /* 28nm only register definitions */ 33a3622f2cSFlorian Fainelli #define MISC_ADDR(base, channel) base, channel 34a3622f2cSFlorian Fainelli 35a3622f2cSFlorian Fainelli #define DSP_TAP10 MISC_ADDR(0x0a, 0) 36a3622f2cSFlorian Fainelli #define PLL_PLLCTRL_1 MISC_ADDR(0x32, 1) 37a3622f2cSFlorian Fainelli #define PLL_PLLCTRL_2 MISC_ADDR(0x32, 2) 38a3622f2cSFlorian Fainelli #define PLL_PLLCTRL_4 MISC_ADDR(0x33, 0) 39a3622f2cSFlorian Fainelli 40a3622f2cSFlorian Fainelli #define AFE_RXCONFIG_0 MISC_ADDR(0x38, 0) 41a3622f2cSFlorian Fainelli #define AFE_RXCONFIG_1 MISC_ADDR(0x38, 1) 42a3622f2cSFlorian Fainelli #define AFE_RX_LP_COUNTER MISC_ADDR(0x38, 3) 43a3622f2cSFlorian Fainelli #define AFE_TX_CONFIG MISC_ADDR(0x39, 0) 44a3622f2cSFlorian Fainelli #define AFE_HPF_TRIM_OTHERS MISC_ADDR(0x3a, 0) 45a3622f2cSFlorian Fainelli 46a3622f2cSFlorian Fainelli #define CORE_EXPB0 0xb0 47a3622f2cSFlorian Fainelli 48b560a58cSFlorian Fainelli static int bcm7445_config_init(struct phy_device *phydev) 49b560a58cSFlorian Fainelli { 50b560a58cSFlorian Fainelli int ret; 51b560a58cSFlorian Fainelli const struct bcm7445_regs { 52b560a58cSFlorian Fainelli int reg; 53b560a58cSFlorian Fainelli u16 value; 54b560a58cSFlorian Fainelli } bcm7445_regs_cfg[] = { 55b560a58cSFlorian Fainelli /* increases ADC latency by 24ns */ 56b560a58cSFlorian Fainelli { MII_BCM54XX_EXP_SEL, 0x0038 }, 57b560a58cSFlorian Fainelli { MII_BCM54XX_EXP_DATA, 0xAB95 }, 58b560a58cSFlorian Fainelli /* increases internal 1V LDO voltage by 5% */ 59b560a58cSFlorian Fainelli { MII_BCM54XX_EXP_SEL, 0x2038 }, 60b560a58cSFlorian Fainelli { MII_BCM54XX_EXP_DATA, 0xBB22 }, 61b560a58cSFlorian Fainelli /* reduce RX low pass filter corner frequency */ 62b560a58cSFlorian Fainelli { MII_BCM54XX_EXP_SEL, 0x6038 }, 63b560a58cSFlorian Fainelli { MII_BCM54XX_EXP_DATA, 0xFFC5 }, 64b560a58cSFlorian Fainelli /* reduce RX high pass filter corner frequency */ 65b560a58cSFlorian Fainelli { MII_BCM54XX_EXP_SEL, 0x003a }, 66b560a58cSFlorian Fainelli { MII_BCM54XX_EXP_DATA, 0x2002 }, 67b560a58cSFlorian Fainelli }; 68b560a58cSFlorian Fainelli unsigned int i; 69b560a58cSFlorian Fainelli 70b560a58cSFlorian Fainelli for (i = 0; i < ARRAY_SIZE(bcm7445_regs_cfg); i++) { 71b560a58cSFlorian Fainelli ret = phy_write(phydev, 72b560a58cSFlorian Fainelli bcm7445_regs_cfg[i].reg, 73b560a58cSFlorian Fainelli bcm7445_regs_cfg[i].value); 74b560a58cSFlorian Fainelli if (ret) 75b560a58cSFlorian Fainelli return ret; 76b560a58cSFlorian Fainelli } 77b560a58cSFlorian Fainelli 78b560a58cSFlorian Fainelli return 0; 79b560a58cSFlorian Fainelli } 80b560a58cSFlorian Fainelli 81b560a58cSFlorian Fainelli static void phy_write_exp(struct phy_device *phydev, 82b560a58cSFlorian Fainelli u16 reg, u16 value) 83b560a58cSFlorian Fainelli { 84b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM54XX_EXP_SEL, MII_BCM54XX_EXP_SEL_ER | reg); 85b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM54XX_EXP_DATA, value); 86b560a58cSFlorian Fainelli } 87b560a58cSFlorian Fainelli 88b560a58cSFlorian Fainelli static void phy_write_misc(struct phy_device *phydev, 89b560a58cSFlorian Fainelli u16 reg, u16 chl, u16 value) 90b560a58cSFlorian Fainelli { 91b560a58cSFlorian Fainelli int tmp; 92b560a58cSFlorian Fainelli 93b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM54XX_AUX_CTL, MII_BCM54XX_AUXCTL_SHDWSEL_MISC); 94b560a58cSFlorian Fainelli 95b560a58cSFlorian Fainelli tmp = phy_read(phydev, MII_BCM54XX_AUX_CTL); 96b560a58cSFlorian Fainelli tmp |= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA; 97b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM54XX_AUX_CTL, tmp); 98b560a58cSFlorian Fainelli 99b560a58cSFlorian Fainelli tmp = (chl * MII_BCM7XXX_CHANNEL_WIDTH) | reg; 100b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM54XX_EXP_SEL, tmp); 101b560a58cSFlorian Fainelli 102b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM54XX_EXP_DATA, value); 103b560a58cSFlorian Fainelli } 104b560a58cSFlorian Fainelli 105b560a58cSFlorian Fainelli static int bcm7xxx_28nm_afe_config_init(struct phy_device *phydev) 106b560a58cSFlorian Fainelli { 107b560a58cSFlorian Fainelli /* Increase VCO range to prevent unlocking problem of PLL at low 108b560a58cSFlorian Fainelli * temp 109b560a58cSFlorian Fainelli */ 110a3622f2cSFlorian Fainelli phy_write_misc(phydev, PLL_PLLCTRL_1, 0x0048); 111b560a58cSFlorian Fainelli 112b560a58cSFlorian Fainelli /* Change Ki to 011 */ 113a3622f2cSFlorian Fainelli phy_write_misc(phydev, PLL_PLLCTRL_2, 0x021b); 114b560a58cSFlorian Fainelli 115b560a58cSFlorian Fainelli /* Disable loading of TVCO buffer to bandgap, set bandgap trim 116b560a58cSFlorian Fainelli * to 111 117b560a58cSFlorian Fainelli */ 118a3622f2cSFlorian Fainelli phy_write_misc(phydev, PLL_PLLCTRL_4, 0x0e20); 119b560a58cSFlorian Fainelli 120b560a58cSFlorian Fainelli /* Adjust bias current trim by -3 */ 121a3622f2cSFlorian Fainelli phy_write_misc(phydev, DSP_TAP10, 0x690b); 122b560a58cSFlorian Fainelli 123b560a58cSFlorian Fainelli /* Switch to CORE_BASE1E */ 124b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM7XXX_CORE_BASE1E, 0xd); 125b560a58cSFlorian Fainelli 126b560a58cSFlorian Fainelli /* Reset R_CAL/RC_CAL Engine */ 127a3622f2cSFlorian Fainelli phy_write_exp(phydev, CORE_EXPB0, 0x0010); 128b560a58cSFlorian Fainelli 129b560a58cSFlorian Fainelli /* Disable Reset R_CAL/RC_CAL Engine */ 130a3622f2cSFlorian Fainelli phy_write_exp(phydev, CORE_EXPB0, 0x0000); 131b560a58cSFlorian Fainelli 1329918542eSFlorian Fainelli /* write AFE_RXCONFIG_0 */ 1339918542eSFlorian Fainelli phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb19); 1349918542eSFlorian Fainelli 1359918542eSFlorian Fainelli /* write AFE_RXCONFIG_1 */ 1369918542eSFlorian Fainelli phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9a3f); 1379918542eSFlorian Fainelli 1389918542eSFlorian Fainelli /* write AFE_RX_LP_COUNTER */ 139a62ea5a7SFlorian Fainelli phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0); 1409918542eSFlorian Fainelli 1419918542eSFlorian Fainelli /* write AFE_HPF_TRIM_OTHERS */ 1429918542eSFlorian Fainelli phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x000b); 1439918542eSFlorian Fainelli 1449918542eSFlorian Fainelli /* write AFTE_TX_CONFIG */ 1459918542eSFlorian Fainelli phy_write_misc(phydev, AFE_TX_CONFIG, 0x0800); 1469918542eSFlorian Fainelli 147b560a58cSFlorian Fainelli return 0; 148b560a58cSFlorian Fainelli } 149b560a58cSFlorian Fainelli 1509df54ddaSFlorian Fainelli static int bcm7xxx_apd_enable(struct phy_device *phydev) 1519df54ddaSFlorian Fainelli { 1529df54ddaSFlorian Fainelli int val; 1539df54ddaSFlorian Fainelli 1549df54ddaSFlorian Fainelli /* Enable powering down of the DLL during auto-power down */ 1559df54ddaSFlorian Fainelli val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_SCR3); 1569df54ddaSFlorian Fainelli if (val < 0) 1579df54ddaSFlorian Fainelli return val; 1589df54ddaSFlorian Fainelli 1599df54ddaSFlorian Fainelli val |= BCM54XX_SHD_SCR3_DLLAPD_DIS; 1609df54ddaSFlorian Fainelli bcm54xx_shadow_write(phydev, BCM54XX_SHD_SCR3, val); 1619df54ddaSFlorian Fainelli 1629df54ddaSFlorian Fainelli /* Enable auto-power down */ 1639df54ddaSFlorian Fainelli val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_APD); 1649df54ddaSFlorian Fainelli if (val < 0) 1659df54ddaSFlorian Fainelli return val; 1669df54ddaSFlorian Fainelli 1679df54ddaSFlorian Fainelli val |= BCM54XX_SHD_APD_EN; 1689df54ddaSFlorian Fainelli return bcm54xx_shadow_write(phydev, BCM54XX_SHD_APD, val); 1699df54ddaSFlorian Fainelli } 1709df54ddaSFlorian Fainelli 171b8f9a029SFlorian Fainelli static int bcm7xxx_eee_enable(struct phy_device *phydev) 172b8f9a029SFlorian Fainelli { 173b8f9a029SFlorian Fainelli int val; 174b8f9a029SFlorian Fainelli 175b8f9a029SFlorian Fainelli val = phy_read_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL, 176b8f9a029SFlorian Fainelli MDIO_MMD_AN, phydev->addr); 177b8f9a029SFlorian Fainelli if (val < 0) 178b8f9a029SFlorian Fainelli return val; 179b8f9a029SFlorian Fainelli 180b8f9a029SFlorian Fainelli /* Enable general EEE feature at the PHY level */ 181b8f9a029SFlorian Fainelli val |= LPI_FEATURE_EN | LPI_FEATURE_EN_DIG1000X; 182b8f9a029SFlorian Fainelli 183b8f9a029SFlorian Fainelli phy_write_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL, 184b8f9a029SFlorian Fainelli MDIO_MMD_AN, phydev->addr, val); 185b8f9a029SFlorian Fainelli 186b8f9a029SFlorian Fainelli /* Advertise supported modes */ 187b8f9a029SFlorian Fainelli val = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_ADV, 188b8f9a029SFlorian Fainelli MDIO_MMD_AN, phydev->addr); 189b8f9a029SFlorian Fainelli 190b8f9a029SFlorian Fainelli val |= (MDIO_AN_EEE_ADV_100TX | MDIO_AN_EEE_ADV_1000T); 191b8f9a029SFlorian Fainelli phy_write_mmd_indirect(phydev, MDIO_AN_EEE_ADV, 192b8f9a029SFlorian Fainelli MDIO_MMD_AN, phydev->addr, val); 193b8f9a029SFlorian Fainelli 194b8f9a029SFlorian Fainelli return 0; 195b8f9a029SFlorian Fainelli } 196b8f9a029SFlorian Fainelli 197b560a58cSFlorian Fainelli static int bcm7xxx_28nm_config_init(struct phy_device *phydev) 198b560a58cSFlorian Fainelli { 199b560a58cSFlorian Fainelli int ret; 200b560a58cSFlorian Fainelli 201b560a58cSFlorian Fainelli ret = bcm7445_config_init(phydev); 202b560a58cSFlorian Fainelli if (ret) 203b560a58cSFlorian Fainelli return ret; 204b560a58cSFlorian Fainelli 2059df54ddaSFlorian Fainelli ret = bcm7xxx_28nm_afe_config_init(phydev); 2069df54ddaSFlorian Fainelli if (ret) 2079df54ddaSFlorian Fainelli return ret; 2089df54ddaSFlorian Fainelli 209b8f9a029SFlorian Fainelli ret = bcm7xxx_eee_enable(phydev); 210b8f9a029SFlorian Fainelli if (ret) 211b8f9a029SFlorian Fainelli return ret; 212b8f9a029SFlorian Fainelli 2139df54ddaSFlorian Fainelli return bcm7xxx_apd_enable(phydev); 214b560a58cSFlorian Fainelli } 215b560a58cSFlorian Fainelli 2164fd14e0bSFlorian Fainelli static int bcm7xxx_28nm_resume(struct phy_device *phydev) 2174fd14e0bSFlorian Fainelli { 2184fd14e0bSFlorian Fainelli int ret; 2194fd14e0bSFlorian Fainelli 2204fd14e0bSFlorian Fainelli /* Re-apply workarounds coming out suspend/resume */ 2214fd14e0bSFlorian Fainelli ret = bcm7xxx_28nm_config_init(phydev); 2224fd14e0bSFlorian Fainelli if (ret) 2234fd14e0bSFlorian Fainelli return ret; 2244fd14e0bSFlorian Fainelli 2254fd14e0bSFlorian Fainelli /* 28nm Gigabit PHYs come out of reset without any half-duplex 2264fd14e0bSFlorian Fainelli * or "hub" compliant advertised mode, fix that. This does not 2274fd14e0bSFlorian Fainelli * cause any problems with the PHY library since genphy_config_aneg() 2284fd14e0bSFlorian Fainelli * gracefully handles auto-negotiated and forced modes. 2294fd14e0bSFlorian Fainelli */ 2304fd14e0bSFlorian Fainelli return genphy_config_aneg(phydev); 2314fd14e0bSFlorian Fainelli } 2324fd14e0bSFlorian Fainelli 233b560a58cSFlorian Fainelli static int phy_set_clr_bits(struct phy_device *dev, int location, 234b560a58cSFlorian Fainelli int set_mask, int clr_mask) 235b560a58cSFlorian Fainelli { 236b560a58cSFlorian Fainelli int v, ret; 237b560a58cSFlorian Fainelli 238b560a58cSFlorian Fainelli v = phy_read(dev, location); 239b560a58cSFlorian Fainelli if (v < 0) 240b560a58cSFlorian Fainelli return v; 241b560a58cSFlorian Fainelli 242b560a58cSFlorian Fainelli v &= ~clr_mask; 243b560a58cSFlorian Fainelli v |= set_mask; 244b560a58cSFlorian Fainelli 245b560a58cSFlorian Fainelli ret = phy_write(dev, location, v); 246b560a58cSFlorian Fainelli if (ret < 0) 247b560a58cSFlorian Fainelli return ret; 248b560a58cSFlorian Fainelli 249b560a58cSFlorian Fainelli return v; 250b560a58cSFlorian Fainelli } 251b560a58cSFlorian Fainelli 252b560a58cSFlorian Fainelli static int bcm7xxx_config_init(struct phy_device *phydev) 253b560a58cSFlorian Fainelli { 254b560a58cSFlorian Fainelli int ret; 255b560a58cSFlorian Fainelli 256b560a58cSFlorian Fainelli /* Enable 64 clock MDIO */ 257b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XX_64CLK_MDIO); 258b560a58cSFlorian Fainelli phy_read(phydev, MII_BCM7XXX_AUX_MODE); 259b560a58cSFlorian Fainelli 260b560a58cSFlorian Fainelli /* Workaround only required for 100Mbits/sec */ 261b560a58cSFlorian Fainelli if (!(phydev->dev_flags & PHY_BRCM_100MBPS_WAR)) 262b560a58cSFlorian Fainelli return 0; 263b560a58cSFlorian Fainelli 264b560a58cSFlorian Fainelli /* set shadow mode 2 */ 265b560a58cSFlorian Fainelli ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 266b560a58cSFlorian Fainelli MII_BCM7XXX_SHD_MODE_2, MII_BCM7XXX_SHD_MODE_2); 267b560a58cSFlorian Fainelli if (ret < 0) 268b560a58cSFlorian Fainelli return ret; 269b560a58cSFlorian Fainelli 270b560a58cSFlorian Fainelli /* set iddq_clkbias */ 271b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0F00); 272b560a58cSFlorian Fainelli udelay(10); 273b560a58cSFlorian Fainelli 274b560a58cSFlorian Fainelli /* reset iddq_clkbias */ 275b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0C00); 276b560a58cSFlorian Fainelli 277b560a58cSFlorian Fainelli phy_write(phydev, MII_BCM7XXX_100TX_FALSE_CAR, 0x7555); 278b560a58cSFlorian Fainelli 279b560a58cSFlorian Fainelli /* reset shadow mode 2 */ 280b560a58cSFlorian Fainelli ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, MII_BCM7XXX_SHD_MODE_2, 0); 281b560a58cSFlorian Fainelli if (ret < 0) 282b560a58cSFlorian Fainelli return ret; 283b560a58cSFlorian Fainelli 284b560a58cSFlorian Fainelli return 0; 285b560a58cSFlorian Fainelli } 286b560a58cSFlorian Fainelli 287b560a58cSFlorian Fainelli /* Workaround for putting the PHY in IDDQ mode, required 28882c084f5SFlorian Fainelli * for all BCM7XXX 40nm and 65nm PHYs 289b560a58cSFlorian Fainelli */ 290b560a58cSFlorian Fainelli static int bcm7xxx_suspend(struct phy_device *phydev) 291b560a58cSFlorian Fainelli { 292b560a58cSFlorian Fainelli int ret; 293b560a58cSFlorian Fainelli const struct bcm7xxx_regs { 294b560a58cSFlorian Fainelli int reg; 295b560a58cSFlorian Fainelli u16 value; 296b560a58cSFlorian Fainelli } bcm7xxx_suspend_cfg[] = { 297b560a58cSFlorian Fainelli { MII_BCM7XXX_TEST, 0x008b }, 298b560a58cSFlorian Fainelli { MII_BCM7XXX_100TX_AUX_CTL, 0x01c0 }, 299b560a58cSFlorian Fainelli { MII_BCM7XXX_100TX_DISC, 0x7000 }, 300b560a58cSFlorian Fainelli { MII_BCM7XXX_TEST, 0x000f }, 301b560a58cSFlorian Fainelli { MII_BCM7XXX_100TX_AUX_CTL, 0x20d0 }, 302b560a58cSFlorian Fainelli { MII_BCM7XXX_TEST, 0x000b }, 303b560a58cSFlorian Fainelli }; 304b560a58cSFlorian Fainelli unsigned int i; 305b560a58cSFlorian Fainelli 306b560a58cSFlorian Fainelli for (i = 0; i < ARRAY_SIZE(bcm7xxx_suspend_cfg); i++) { 307b560a58cSFlorian Fainelli ret = phy_write(phydev, 308b560a58cSFlorian Fainelli bcm7xxx_suspend_cfg[i].reg, 309b560a58cSFlorian Fainelli bcm7xxx_suspend_cfg[i].value); 310b560a58cSFlorian Fainelli if (ret) 311b560a58cSFlorian Fainelli return ret; 312b560a58cSFlorian Fainelli } 313b560a58cSFlorian Fainelli 314b560a58cSFlorian Fainelli return 0; 315b560a58cSFlorian Fainelli } 316b560a58cSFlorian Fainelli 317b560a58cSFlorian Fainelli static int bcm7xxx_dummy_config_init(struct phy_device *phydev) 318b560a58cSFlorian Fainelli { 319b560a58cSFlorian Fainelli return 0; 320b560a58cSFlorian Fainelli } 321b560a58cSFlorian Fainelli 322153df3c7SFlorian Fainelli #define BCM7XXX_28NM_GPHY(_oui, _name) \ 323153df3c7SFlorian Fainelli { \ 324153df3c7SFlorian Fainelli .phy_id = (_oui), \ 325153df3c7SFlorian Fainelli .phy_id_mask = 0xfffffff0, \ 326153df3c7SFlorian Fainelli .name = _name, \ 327153df3c7SFlorian Fainelli .features = PHY_GBIT_FEATURES | \ 328153df3c7SFlorian Fainelli SUPPORTED_Pause | SUPPORTED_Asym_Pause, \ 329153df3c7SFlorian Fainelli .flags = PHY_IS_INTERNAL, \ 330153df3c7SFlorian Fainelli .config_init = bcm7xxx_28nm_afe_config_init, \ 331153df3c7SFlorian Fainelli .config_aneg = genphy_config_aneg, \ 332153df3c7SFlorian Fainelli .read_status = genphy_read_status, \ 333153df3c7SFlorian Fainelli .resume = bcm7xxx_28nm_resume, \ 334153df3c7SFlorian Fainelli .driver = { .owner = THIS_MODULE }, \ 335153df3c7SFlorian Fainelli } 336153df3c7SFlorian Fainelli 337b560a58cSFlorian Fainelli static struct phy_driver bcm7xxx_driver[] = { 338430ad68fSFlorian Fainelli BCM7XXX_28NM_GPHY(PHY_ID_BCM7250, "Broadcom BCM7250"), 339430ad68fSFlorian Fainelli BCM7XXX_28NM_GPHY(PHY_ID_BCM7364, "Broadcom BCM7364"), 340153df3c7SFlorian Fainelli BCM7XXX_28NM_GPHY(PHY_ID_BCM7366, "Broadcom BCM7366"), 341153df3c7SFlorian Fainelli BCM7XXX_28NM_GPHY(PHY_ID_BCM7439, "Broadcom BCM7439"), 342153df3c7SFlorian Fainelli BCM7XXX_28NM_GPHY(PHY_ID_BCM7445, "Broadcom BCM7445"), 343b560a58cSFlorian Fainelli { 344b560a58cSFlorian Fainelli .phy_id = PHY_BCM_OUI_4, 345b560a58cSFlorian Fainelli .phy_id_mask = 0xffff0000, 346b560a58cSFlorian Fainelli .name = "Broadcom BCM7XXX 40nm", 347b560a58cSFlorian Fainelli .features = PHY_GBIT_FEATURES | 348b560a58cSFlorian Fainelli SUPPORTED_Pause | SUPPORTED_Asym_Pause, 349b560a58cSFlorian Fainelli .flags = PHY_IS_INTERNAL, 350b560a58cSFlorian Fainelli .config_init = bcm7xxx_config_init, 351b560a58cSFlorian Fainelli .config_aneg = genphy_config_aneg, 352b560a58cSFlorian Fainelli .read_status = genphy_read_status, 353b560a58cSFlorian Fainelli .suspend = bcm7xxx_suspend, 354b560a58cSFlorian Fainelli .resume = bcm7xxx_config_init, 355b560a58cSFlorian Fainelli .driver = { .owner = THIS_MODULE }, 356b560a58cSFlorian Fainelli }, { 357b560a58cSFlorian Fainelli .phy_id = PHY_BCM_OUI_5, 358b560a58cSFlorian Fainelli .phy_id_mask = 0xffffff00, 359b560a58cSFlorian Fainelli .name = "Broadcom BCM7XXX 65nm", 360b560a58cSFlorian Fainelli .features = PHY_BASIC_FEATURES | 361b560a58cSFlorian Fainelli SUPPORTED_Pause | SUPPORTED_Asym_Pause, 362b560a58cSFlorian Fainelli .flags = PHY_IS_INTERNAL, 363b560a58cSFlorian Fainelli .config_init = bcm7xxx_dummy_config_init, 364b560a58cSFlorian Fainelli .config_aneg = genphy_config_aneg, 365b560a58cSFlorian Fainelli .read_status = genphy_read_status, 366b560a58cSFlorian Fainelli .suspend = bcm7xxx_suspend, 367b560a58cSFlorian Fainelli .resume = bcm7xxx_config_init, 368b560a58cSFlorian Fainelli .driver = { .owner = THIS_MODULE }, 369b560a58cSFlorian Fainelli } }; 370b560a58cSFlorian Fainelli 371b560a58cSFlorian Fainelli static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = { 372430ad68fSFlorian Fainelli { PHY_ID_BCM7250, 0xfffffff0, }, 373430ad68fSFlorian Fainelli { PHY_ID_BCM7364, 0xfffffff0, }, 374b560a58cSFlorian Fainelli { PHY_ID_BCM7366, 0xfffffff0, }, 375b560a58cSFlorian Fainelli { PHY_ID_BCM7439, 0xfffffff0, }, 376b560a58cSFlorian Fainelli { PHY_ID_BCM7445, 0xfffffff0, }, 377b560a58cSFlorian Fainelli { PHY_BCM_OUI_4, 0xffff0000 }, 378b560a58cSFlorian Fainelli { PHY_BCM_OUI_5, 0xffffff00 }, 379b560a58cSFlorian Fainelli { } 380b560a58cSFlorian Fainelli }; 381b560a58cSFlorian Fainelli 382b560a58cSFlorian Fainelli static int __init bcm7xxx_phy_init(void) 383b560a58cSFlorian Fainelli { 384b560a58cSFlorian Fainelli return phy_drivers_register(bcm7xxx_driver, 385b560a58cSFlorian Fainelli ARRAY_SIZE(bcm7xxx_driver)); 386b560a58cSFlorian Fainelli } 387b560a58cSFlorian Fainelli 388b560a58cSFlorian Fainelli static void __exit bcm7xxx_phy_exit(void) 389b560a58cSFlorian Fainelli { 390b560a58cSFlorian Fainelli phy_drivers_unregister(bcm7xxx_driver, 391b560a58cSFlorian Fainelli ARRAY_SIZE(bcm7xxx_driver)); 392b560a58cSFlorian Fainelli } 393b560a58cSFlorian Fainelli 394b560a58cSFlorian Fainelli module_init(bcm7xxx_phy_init); 395b560a58cSFlorian Fainelli module_exit(bcm7xxx_phy_exit); 396b560a58cSFlorian Fainelli 397b560a58cSFlorian Fainelli MODULE_DEVICE_TABLE(mdio, bcm7xxx_tbl); 398b560a58cSFlorian Fainelli 399b560a58cSFlorian Fainelli MODULE_DESCRIPTION("Broadcom BCM7xxx internal PHY driver"); 400b560a58cSFlorian Fainelli MODULE_LICENSE("GPL"); 401b560a58cSFlorian Fainelli MODULE_AUTHOR("Broadcom Corporation"); 402