cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

broadcom.c (29113B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 *	drivers/net/phy/broadcom.c
      4 *
      5 *	Broadcom BCM5411, BCM5421 and BCM5461 Gigabit Ethernet
      6 *	transceivers.
      7 *
      8 *	Copyright (c) 2006  Maciej W. Rozycki
      9 *
     10 *	Inspired by code written by Amy Fong.
     11 */
     12
     13#include "bcm-phy-lib.h"
     14#include <linux/delay.h>
     15#include <linux/module.h>
     16#include <linux/phy.h>
     17#include <linux/brcmphy.h>
     18#include <linux/of.h>
     19
     20#define BRCM_PHY_MODEL(phydev) \
     21	((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask)
     22
     23#define BRCM_PHY_REV(phydev) \
     24	((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask))
     25
     26MODULE_DESCRIPTION("Broadcom PHY driver");
     27MODULE_AUTHOR("Maciej W. Rozycki");
     28MODULE_LICENSE("GPL");
     29
     30static int bcm54xx_config_clock_delay(struct phy_device *phydev)
     31{
     32	int rc, val;
     33
     34	/* handling PHY's internal RX clock delay */
     35	val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
     36	val |= MII_BCM54XX_AUXCTL_MISC_WREN;
     37	if (phydev->interface == PHY_INTERFACE_MODE_RGMII ||
     38	    phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
     39		/* Disable RGMII RXC-RXD skew */
     40		val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
     41	}
     42	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
     43	    phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
     44		/* Enable RGMII RXC-RXD skew */
     45		val |= MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
     46	}
     47	rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
     48				  val);
     49	if (rc < 0)
     50		return rc;
     51
     52	/* handling PHY's internal TX clock delay */
     53	val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL);
     54	if (phydev->interface == PHY_INTERFACE_MODE_RGMII ||
     55	    phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
     56		/* Disable internal TX clock delay */
     57		val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN;
     58	}
     59	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
     60	    phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
     61		/* Enable internal TX clock delay */
     62		val |= BCM54810_SHD_CLK_CTL_GTXCLK_EN;
     63	}
     64	rc = bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val);
     65	if (rc < 0)
     66		return rc;
     67
     68	return 0;
     69}
     70
     71static int bcm54210e_config_init(struct phy_device *phydev)
     72{
     73	int val;
     74
     75	bcm54xx_config_clock_delay(phydev);
     76
     77	if (phydev->dev_flags & PHY_BRCM_EN_MASTER_MODE) {
     78		val = phy_read(phydev, MII_CTRL1000);
     79		val |= CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER;
     80		phy_write(phydev, MII_CTRL1000, val);
     81	}
     82
     83	return 0;
     84}
     85
     86static int bcm54612e_config_init(struct phy_device *phydev)
     87{
     88	int reg;
     89
     90	bcm54xx_config_clock_delay(phydev);
     91
     92	/* Enable CLK125 MUX on LED4 if ref clock is enabled. */
     93	if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) {
     94		int err;
     95
     96		reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0);
     97		err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0,
     98					BCM54612E_LED4_CLK125OUT_EN | reg);
     99
    100		if (err < 0)
    101			return err;
    102	}
    103
    104	return 0;
    105}
    106
    107static int bcm54616s_config_init(struct phy_device *phydev)
    108{
    109	int rc, val;
    110
    111	if (phydev->interface != PHY_INTERFACE_MODE_SGMII &&
    112	    phydev->interface != PHY_INTERFACE_MODE_1000BASEX)
    113		return 0;
    114
    115	/* Ensure proper interface mode is selected. */
    116	/* Disable RGMII mode */
    117	val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
    118	if (val < 0)
    119		return val;
    120	val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_EN;
    121	val |= MII_BCM54XX_AUXCTL_MISC_WREN;
    122	rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
    123				  val);
    124	if (rc < 0)
    125		return rc;
    126
    127	/* Select 1000BASE-X register set (primary SerDes) */
    128	val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE);
    129	if (val < 0)
    130		return val;
    131	val |= BCM54XX_SHD_MODE_1000BX;
    132	rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val);
    133	if (rc < 0)
    134		return rc;
    135
    136	/* Power down SerDes interface */
    137	rc = phy_set_bits(phydev, MII_BMCR, BMCR_PDOWN);
    138	if (rc < 0)
    139		return rc;
    140
    141	/* Select proper interface mode */
    142	val &= ~BCM54XX_SHD_INTF_SEL_MASK;
    143	val |= phydev->interface == PHY_INTERFACE_MODE_SGMII ?
    144		BCM54XX_SHD_INTF_SEL_SGMII :
    145		BCM54XX_SHD_INTF_SEL_GBIC;
    146	rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val);
    147	if (rc < 0)
    148		return rc;
    149
    150	/* Power up SerDes interface */
    151	rc = phy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN);
    152	if (rc < 0)
    153		return rc;
    154
    155	/* Select copper register set */
    156	val &= ~BCM54XX_SHD_MODE_1000BX;
    157	rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val);
    158	if (rc < 0)
    159		return rc;
    160
    161	/* Power up copper interface */
    162	return phy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN);
    163}
    164
    165/* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */
    166static int bcm50610_a0_workaround(struct phy_device *phydev)
    167{
    168	int err;
    169
    170	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH0,
    171				MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN |
    172				MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF);
    173	if (err < 0)
    174		return err;
    175
    176	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH3,
    177				MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ);
    178	if (err < 0)
    179		return err;
    180
    181	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75,
    182				MII_BCM54XX_EXP_EXP75_VDACCTRL);
    183	if (err < 0)
    184		return err;
    185
    186	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP96,
    187				MII_BCM54XX_EXP_EXP96_MYST);
    188	if (err < 0)
    189		return err;
    190
    191	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP97,
    192				MII_BCM54XX_EXP_EXP97_MYST);
    193
    194	return err;
    195}
    196
    197static int bcm54xx_phydsp_config(struct phy_device *phydev)
    198{
    199	int err, err2;
    200
    201	/* Enable the SMDSP clock */
    202	err = bcm54xx_auxctl_write(phydev,
    203				   MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
    204				   MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA |
    205				   MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
    206	if (err < 0)
    207		return err;
    208
    209	if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
    210	    BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) {
    211		/* Clear bit 9 to fix a phy interop issue. */
    212		err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP08,
    213					MII_BCM54XX_EXP_EXP08_RJCT_2MHZ);
    214		if (err < 0)
    215			goto error;
    216
    217		if (phydev->drv->phy_id == PHY_ID_BCM50610) {
    218			err = bcm50610_a0_workaround(phydev);
    219			if (err < 0)
    220				goto error;
    221		}
    222	}
    223
    224	if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) {
    225		int val;
    226
    227		val = bcm_phy_read_exp(phydev, MII_BCM54XX_EXP_EXP75);
    228		if (val < 0)
    229			goto error;
    230
    231		val |= MII_BCM54XX_EXP_EXP75_CM_OSC;
    232		err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75, val);
    233	}
    234
    235error:
    236	/* Disable the SMDSP clock */
    237	err2 = bcm54xx_auxctl_write(phydev,
    238				    MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
    239				    MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
    240
    241	/* Return the first error reported. */
    242	return err ? err : err2;
    243}
    244
    245static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
    246{
    247	u32 orig;
    248	int val;
    249	bool clk125en = true;
    250
    251	/* Abort if we are using an untested phy. */
    252	if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM57780 &&
    253	    BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 &&
    254	    BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M &&
    255	    BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54210E &&
    256	    BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54810 &&
    257	    BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54811)
    258		return;
    259
    260	val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3);
    261	if (val < 0)
    262		return;
    263
    264	orig = val;
    265
    266	if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
    267	     BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
    268	    BRCM_PHY_REV(phydev) >= 0x3) {
    269		/*
    270		 * Here, bit 0 _disables_ CLK125 when set.
    271		 * This bit is set by default.
    272		 */
    273		clk125en = false;
    274	} else {
    275		if (phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) {
    276			if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54811) {
    277				/* Here, bit 0 _enables_ CLK125 when set */
    278				val &= ~BCM54XX_SHD_SCR3_DEF_CLK125;
    279			}
    280			clk125en = false;
    281		}
    282	}
    283
    284	if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
    285		val &= ~BCM54XX_SHD_SCR3_DLLAPD_DIS;
    286	else
    287		val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
    288
    289	if (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) {
    290		if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54210E ||
    291		    BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810 ||
    292		    BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54811)
    293			val |= BCM54XX_SHD_SCR3_RXCTXC_DIS;
    294		else
    295			val |= BCM54XX_SHD_SCR3_TRDDAPD;
    296	}
    297
    298	if (orig != val)
    299		bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val);
    300
    301	val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD);
    302	if (val < 0)
    303		return;
    304
    305	orig = val;
    306
    307	if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
    308		val |= BCM54XX_SHD_APD_EN;
    309	else
    310		val &= ~BCM54XX_SHD_APD_EN;
    311
    312	if (orig != val)
    313		bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val);
    314}
    315
    316static int bcm54xx_config_init(struct phy_device *phydev)
    317{
    318	int reg, err, val;
    319
    320	reg = phy_read(phydev, MII_BCM54XX_ECR);
    321	if (reg < 0)
    322		return reg;
    323
    324	/* Mask interrupts globally.  */
    325	reg |= MII_BCM54XX_ECR_IM;
    326	err = phy_write(phydev, MII_BCM54XX_ECR, reg);
    327	if (err < 0)
    328		return err;
    329
    330	/* Unmask events we are interested in.  */
    331	reg = ~(MII_BCM54XX_INT_DUPLEX |
    332		MII_BCM54XX_INT_SPEED |
    333		MII_BCM54XX_INT_LINK);
    334	err = phy_write(phydev, MII_BCM54XX_IMR, reg);
    335	if (err < 0)
    336		return err;
    337
    338	if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
    339	     BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
    340	    (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE))
    341		bcm_phy_write_shadow(phydev, BCM54XX_SHD_RGMII_MODE, 0);
    342
    343	bcm54xx_adjust_rxrefclk(phydev);
    344
    345	switch (BRCM_PHY_MODEL(phydev)) {
    346	case PHY_ID_BCM50610:
    347	case PHY_ID_BCM50610M:
    348		err = bcm54xx_config_clock_delay(phydev);
    349		break;
    350	case PHY_ID_BCM54210E:
    351		err = bcm54210e_config_init(phydev);
    352		break;
    353	case PHY_ID_BCM54612E:
    354		err = bcm54612e_config_init(phydev);
    355		break;
    356	case PHY_ID_BCM54616S:
    357		err = bcm54616s_config_init(phydev);
    358		break;
    359	case PHY_ID_BCM54810:
    360		/* For BCM54810, we need to disable BroadR-Reach function */
    361		val = bcm_phy_read_exp(phydev,
    362				       BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
    363		val &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
    364		err = bcm_phy_write_exp(phydev,
    365					BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
    366					val);
    367		break;
    368	}
    369	if (err)
    370		return err;
    371
    372	bcm54xx_phydsp_config(phydev);
    373
    374	/* For non-SFP setups, encode link speed into LED1 and LED3 pair
    375	 * (green/amber).
    376	 * Also flash these two LEDs on activity. This means configuring
    377	 * them for MULTICOLOR and encoding link/activity into them.
    378	 * Don't do this for devices on an SFP module, since some of these
    379	 * use the LED outputs to control the SFP LOS signal, and changing
    380	 * these settings will cause LOS to malfunction.
    381	 */
    382	if (!phy_on_sfp(phydev)) {
    383		val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) |
    384			BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1);
    385		bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val);
    386
    387		val = BCM_LED_MULTICOLOR_IN_PHASE |
    388			BCM5482_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) |
    389			BCM5482_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT);
    390		bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val);
    391	}
    392
    393	return 0;
    394}
    395
    396static int bcm54xx_iddq_set(struct phy_device *phydev, bool enable)
    397{
    398	int ret = 0;
    399
    400	if (!(phydev->dev_flags & PHY_BRCM_IDDQ_SUSPEND))
    401		return ret;
    402
    403	ret = bcm_phy_read_exp(phydev, BCM54XX_TOP_MISC_IDDQ_CTRL);
    404	if (ret < 0)
    405		goto out;
    406
    407	if (enable)
    408		ret |= BCM54XX_TOP_MISC_IDDQ_SR | BCM54XX_TOP_MISC_IDDQ_LP;
    409	else
    410		ret &= ~(BCM54XX_TOP_MISC_IDDQ_SR | BCM54XX_TOP_MISC_IDDQ_LP);
    411
    412	ret = bcm_phy_write_exp(phydev, BCM54XX_TOP_MISC_IDDQ_CTRL, ret);
    413out:
    414	return ret;
    415}
    416
    417static int bcm54xx_suspend(struct phy_device *phydev)
    418{
    419	int ret;
    420
    421	/* We cannot use a read/modify/write here otherwise the PHY gets into
    422	 * a bad state where its LEDs keep flashing, thus defeating the purpose
    423	 * of low power mode.
    424	 */
    425	ret = phy_write(phydev, MII_BMCR, BMCR_PDOWN);
    426	if (ret < 0)
    427		return ret;
    428
    429	return bcm54xx_iddq_set(phydev, true);
    430}
    431
    432static int bcm54xx_resume(struct phy_device *phydev)
    433{
    434	int ret;
    435
    436	ret = bcm54xx_iddq_set(phydev, false);
    437	if (ret < 0)
    438		return ret;
    439
    440	/* Writes to register other than BMCR would be ignored
    441	 * unless we clear the PDOWN bit first
    442	 */
    443	ret = genphy_resume(phydev);
    444	if (ret < 0)
    445		return ret;
    446
    447	/* Upon exiting power down, the PHY remains in an internal reset state
    448	 * for 40us
    449	 */
    450	fsleep(40);
    451
    452	/* Issue a soft reset after clearing the power down bit
    453	 * and before doing any other configuration.
    454	 */
    455	if (phydev->dev_flags & PHY_BRCM_IDDQ_SUSPEND) {
    456		ret = genphy_soft_reset(phydev);
    457		if (ret < 0)
    458			return ret;
    459	}
    460
    461	return bcm54xx_config_init(phydev);
    462}
    463
    464static int bcm54811_config_init(struct phy_device *phydev)
    465{
    466	int err, reg;
    467
    468	/* Disable BroadR-Reach function. */
    469	reg = bcm_phy_read_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
    470	reg &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
    471	err = bcm_phy_write_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
    472				reg);
    473	if (err < 0)
    474		return err;
    475
    476	err = bcm54xx_config_init(phydev);
    477
    478	/* Enable CLK125 MUX on LED4 if ref clock is enabled. */
    479	if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) {
    480		reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0);
    481		err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0,
    482					BCM54612E_LED4_CLK125OUT_EN | reg);
    483		if (err < 0)
    484			return err;
    485	}
    486
    487	return err;
    488}
    489
    490static int bcm5481_config_aneg(struct phy_device *phydev)
    491{
    492	struct device_node *np = phydev->mdio.dev.of_node;
    493	int ret;
    494
    495	/* Aneg firstly. */
    496	ret = genphy_config_aneg(phydev);
    497
    498	/* Then we can set up the delay. */
    499	bcm54xx_config_clock_delay(phydev);
    500
    501	if (of_property_read_bool(np, "enet-phy-lane-swap")) {
    502		/* Lane Swap - Undocumented register...magic! */
    503		ret = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_SEL_ER + 0x9,
    504					0x11B);
    505		if (ret < 0)
    506			return ret;
    507	}
    508
    509	return ret;
    510}
    511
    512struct bcm54616s_phy_priv {
    513	bool mode_1000bx_en;
    514};
    515
    516static int bcm54616s_probe(struct phy_device *phydev)
    517{
    518	struct bcm54616s_phy_priv *priv;
    519	int val;
    520
    521	priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
    522	if (!priv)
    523		return -ENOMEM;
    524
    525	phydev->priv = priv;
    526
    527	val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE);
    528	if (val < 0)
    529		return val;
    530
    531	/* The PHY is strapped in RGMII-fiber mode when INTERF_SEL[1:0]
    532	 * is 01b, and the link between PHY and its link partner can be
    533	 * either 1000Base-X or 100Base-FX.
    534	 * RGMII-1000Base-X is properly supported, but RGMII-100Base-FX
    535	 * support is still missing as of now.
    536	 */
    537	if ((val & BCM54XX_SHD_INTF_SEL_MASK) == BCM54XX_SHD_INTF_SEL_RGMII) {
    538		val = bcm_phy_read_shadow(phydev, BCM54616S_SHD_100FX_CTRL);
    539		if (val < 0)
    540			return val;
    541
    542		/* Bit 0 of the SerDes 100-FX Control register, when set
    543		 * to 1, sets the MII/RGMII -> 100BASE-FX configuration.
    544		 * When this bit is set to 0, it sets the GMII/RGMII ->
    545		 * 1000BASE-X configuration.
    546		 */
    547		if (!(val & BCM54616S_100FX_MODE))
    548			priv->mode_1000bx_en = true;
    549
    550		phydev->port = PORT_FIBRE;
    551	}
    552
    553	return 0;
    554}
    555
    556static int bcm54616s_config_aneg(struct phy_device *phydev)
    557{
    558	struct bcm54616s_phy_priv *priv = phydev->priv;
    559	int ret;
    560
    561	/* Aneg firstly. */
    562	if (priv->mode_1000bx_en)
    563		ret = genphy_c37_config_aneg(phydev);
    564	else
    565		ret = genphy_config_aneg(phydev);
    566
    567	/* Then we can set up the delay. */
    568	bcm54xx_config_clock_delay(phydev);
    569
    570	return ret;
    571}
    572
    573static int bcm54616s_read_status(struct phy_device *phydev)
    574{
    575	struct bcm54616s_phy_priv *priv = phydev->priv;
    576	int err;
    577
    578	if (priv->mode_1000bx_en)
    579		err = genphy_c37_read_status(phydev);
    580	else
    581		err = genphy_read_status(phydev);
    582
    583	return err;
    584}
    585
    586static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set)
    587{
    588	int val;
    589
    590	val = phy_read(phydev, reg);
    591	if (val < 0)
    592		return val;
    593
    594	return phy_write(phydev, reg, val | set);
    595}
    596
    597static int brcm_fet_config_init(struct phy_device *phydev)
    598{
    599	int reg, err, err2, brcmtest;
    600
    601	/* Reset the PHY to bring it to a known state. */
    602	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
    603	if (err < 0)
    604		return err;
    605
    606	/* The datasheet indicates the PHY needs up to 1us to complete a reset,
    607	 * build some slack here.
    608	 */
    609	usleep_range(1000, 2000);
    610
    611	/* The PHY requires 65 MDC clock cycles to complete a write operation
    612	 * and turnaround the line properly.
    613	 *
    614	 * We ignore -EIO here as the MDIO controller (e.g.: mdio-bcm-unimac)
    615	 * may flag the lack of turn-around as a read failure. This is
    616	 * particularly true with this combination since the MDIO controller
    617	 * only used 64 MDC cycles. This is not a critical failure in this
    618	 * specific case and it has no functional impact otherwise, so we let
    619	 * that one go through. If there is a genuine bus error, the next read
    620	 * of MII_BRCM_FET_INTREG will error out.
    621	 */
    622	err = phy_read(phydev, MII_BMCR);
    623	if (err < 0 && err != -EIO)
    624		return err;
    625
    626	reg = phy_read(phydev, MII_BRCM_FET_INTREG);
    627	if (reg < 0)
    628		return reg;
    629
    630	/* Unmask events we are interested in and mask interrupts globally. */
    631	reg = MII_BRCM_FET_IR_DUPLEX_EN |
    632	      MII_BRCM_FET_IR_SPEED_EN |
    633	      MII_BRCM_FET_IR_LINK_EN |
    634	      MII_BRCM_FET_IR_ENABLE |
    635	      MII_BRCM_FET_IR_MASK;
    636
    637	err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
    638	if (err < 0)
    639		return err;
    640
    641	/* Enable shadow register access */
    642	brcmtest = phy_read(phydev, MII_BRCM_FET_BRCMTEST);
    643	if (brcmtest < 0)
    644		return brcmtest;
    645
    646	reg = brcmtest | MII_BRCM_FET_BT_SRE;
    647
    648	err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg);
    649	if (err < 0)
    650		return err;
    651
    652	/* Set the LED mode */
    653	reg = phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4);
    654	if (reg < 0) {
    655		err = reg;
    656		goto done;
    657	}
    658
    659	reg &= ~MII_BRCM_FET_SHDW_AM4_LED_MASK;
    660	reg |= MII_BRCM_FET_SHDW_AM4_LED_MODE1;
    661
    662	err = phy_write(phydev, MII_BRCM_FET_SHDW_AUXMODE4, reg);
    663	if (err < 0)
    664		goto done;
    665
    666	/* Enable auto MDIX */
    667	err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_MISCCTRL,
    668				       MII_BRCM_FET_SHDW_MC_FAME);
    669	if (err < 0)
    670		goto done;
    671
    672	if (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE) {
    673		/* Enable auto power down */
    674		err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2,
    675					       MII_BRCM_FET_SHDW_AS2_APDE);
    676	}
    677
    678done:
    679	/* Disable shadow register access */
    680	err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest);
    681	if (!err)
    682		err = err2;
    683
    684	return err;
    685}
    686
    687static int brcm_fet_ack_interrupt(struct phy_device *phydev)
    688{
    689	int reg;
    690
    691	/* Clear pending interrupts.  */
    692	reg = phy_read(phydev, MII_BRCM_FET_INTREG);
    693	if (reg < 0)
    694		return reg;
    695
    696	return 0;
    697}
    698
    699static int brcm_fet_config_intr(struct phy_device *phydev)
    700{
    701	int reg, err;
    702
    703	reg = phy_read(phydev, MII_BRCM_FET_INTREG);
    704	if (reg < 0)
    705		return reg;
    706
    707	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
    708		err = brcm_fet_ack_interrupt(phydev);
    709		if (err)
    710			return err;
    711
    712		reg &= ~MII_BRCM_FET_IR_MASK;
    713		err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
    714	} else {
    715		reg |= MII_BRCM_FET_IR_MASK;
    716		err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
    717		if (err)
    718			return err;
    719
    720		err = brcm_fet_ack_interrupt(phydev);
    721	}
    722
    723	return err;
    724}
    725
    726static irqreturn_t brcm_fet_handle_interrupt(struct phy_device *phydev)
    727{
    728	int irq_status;
    729
    730	irq_status = phy_read(phydev, MII_BRCM_FET_INTREG);
    731	if (irq_status < 0) {
    732		phy_error(phydev);
    733		return IRQ_NONE;
    734	}
    735
    736	if (irq_status == 0)
    737		return IRQ_NONE;
    738
    739	phy_trigger_machine(phydev);
    740
    741	return IRQ_HANDLED;
    742}
    743
    744struct bcm54xx_phy_priv {
    745	u64	*stats;
    746};
    747
    748static int bcm54xx_phy_probe(struct phy_device *phydev)
    749{
    750	struct bcm54xx_phy_priv *priv;
    751
    752	priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
    753	if (!priv)
    754		return -ENOMEM;
    755
    756	phydev->priv = priv;
    757
    758	priv->stats = devm_kcalloc(&phydev->mdio.dev,
    759				   bcm_phy_get_sset_count(phydev), sizeof(u64),
    760				   GFP_KERNEL);
    761	if (!priv->stats)
    762		return -ENOMEM;
    763
    764	return 0;
    765}
    766
    767static void bcm54xx_get_stats(struct phy_device *phydev,
    768			      struct ethtool_stats *stats, u64 *data)
    769{
    770	struct bcm54xx_phy_priv *priv = phydev->priv;
    771
    772	bcm_phy_get_stats(phydev, priv->stats, stats, data);
    773}
    774
    775static void bcm54xx_link_change_notify(struct phy_device *phydev)
    776{
    777	u16 mask = MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE |
    778		   MII_BCM54XX_EXP_EXP08_FORCE_DAC_WAKE;
    779	int ret;
    780
    781	if (phydev->state != PHY_RUNNING)
    782		return;
    783
    784	/* Don't change the DAC wake settings if auto power down
    785	 * is not requested.
    786	 */
    787	if (!(phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
    788		return;
    789
    790	ret = bcm_phy_read_exp(phydev, MII_BCM54XX_EXP_EXP08);
    791	if (ret < 0)
    792		return;
    793
    794	/* Enable/disable 10BaseT auto and forced early DAC wake depending
    795	 * on the negotiated speed, those settings should only be done
    796	 * for 10Mbits/sec.
    797	 */
    798	if (phydev->speed == SPEED_10)
    799		ret |= mask;
    800	else
    801		ret &= ~mask;
    802	bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP08, ret);
    803}
    804
    805static struct phy_driver broadcom_drivers[] = {
    806{
    807	.phy_id		= PHY_ID_BCM5411,
    808	.phy_id_mask	= 0xfffffff0,
    809	.name		= "Broadcom BCM5411",
    810	/* PHY_GBIT_FEATURES */
    811	.get_sset_count	= bcm_phy_get_sset_count,
    812	.get_strings	= bcm_phy_get_strings,
    813	.get_stats	= bcm54xx_get_stats,
    814	.probe		= bcm54xx_phy_probe,
    815	.config_init	= bcm54xx_config_init,
    816	.config_intr	= bcm_phy_config_intr,
    817	.handle_interrupt = bcm_phy_handle_interrupt,
    818	.link_change_notify	= bcm54xx_link_change_notify,
    819}, {
    820	.phy_id		= PHY_ID_BCM5421,
    821	.phy_id_mask	= 0xfffffff0,
    822	.name		= "Broadcom BCM5421",
    823	/* PHY_GBIT_FEATURES */
    824	.get_sset_count	= bcm_phy_get_sset_count,
    825	.get_strings	= bcm_phy_get_strings,
    826	.get_stats	= bcm54xx_get_stats,
    827	.probe		= bcm54xx_phy_probe,
    828	.config_init	= bcm54xx_config_init,
    829	.config_intr	= bcm_phy_config_intr,
    830	.handle_interrupt = bcm_phy_handle_interrupt,
    831	.link_change_notify	= bcm54xx_link_change_notify,
    832}, {
    833	.phy_id		= PHY_ID_BCM54210E,
    834	.phy_id_mask	= 0xfffffff0,
    835	.name		= "Broadcom BCM54210E",
    836	/* PHY_GBIT_FEATURES */
    837	.get_sset_count	= bcm_phy_get_sset_count,
    838	.get_strings	= bcm_phy_get_strings,
    839	.get_stats	= bcm54xx_get_stats,
    840	.probe		= bcm54xx_phy_probe,
    841	.config_init	= bcm54xx_config_init,
    842	.config_intr	= bcm_phy_config_intr,
    843	.handle_interrupt = bcm_phy_handle_interrupt,
    844	.link_change_notify	= bcm54xx_link_change_notify,
    845	.suspend	= bcm54xx_suspend,
    846	.resume		= bcm54xx_resume,
    847}, {
    848	.phy_id		= PHY_ID_BCM5461,
    849	.phy_id_mask	= 0xfffffff0,
    850	.name		= "Broadcom BCM5461",
    851	/* PHY_GBIT_FEATURES */
    852	.get_sset_count	= bcm_phy_get_sset_count,
    853	.get_strings	= bcm_phy_get_strings,
    854	.get_stats	= bcm54xx_get_stats,
    855	.probe		= bcm54xx_phy_probe,
    856	.config_init	= bcm54xx_config_init,
    857	.config_intr	= bcm_phy_config_intr,
    858	.handle_interrupt = bcm_phy_handle_interrupt,
    859	.link_change_notify	= bcm54xx_link_change_notify,
    860}, {
    861	.phy_id		= PHY_ID_BCM54612E,
    862	.phy_id_mask	= 0xfffffff0,
    863	.name		= "Broadcom BCM54612E",
    864	/* PHY_GBIT_FEATURES */
    865	.get_sset_count	= bcm_phy_get_sset_count,
    866	.get_strings	= bcm_phy_get_strings,
    867	.get_stats	= bcm54xx_get_stats,
    868	.probe		= bcm54xx_phy_probe,
    869	.config_init	= bcm54xx_config_init,
    870	.config_intr	= bcm_phy_config_intr,
    871	.handle_interrupt = bcm_phy_handle_interrupt,
    872	.link_change_notify	= bcm54xx_link_change_notify,
    873}, {
    874	.phy_id		= PHY_ID_BCM54616S,
    875	.phy_id_mask	= 0xfffffff0,
    876	.name		= "Broadcom BCM54616S",
    877	/* PHY_GBIT_FEATURES */
    878	.soft_reset     = genphy_soft_reset,
    879	.config_init	= bcm54xx_config_init,
    880	.config_aneg	= bcm54616s_config_aneg,
    881	.config_intr	= bcm_phy_config_intr,
    882	.handle_interrupt = bcm_phy_handle_interrupt,
    883	.read_status	= bcm54616s_read_status,
    884	.probe		= bcm54616s_probe,
    885	.link_change_notify	= bcm54xx_link_change_notify,
    886}, {
    887	.phy_id		= PHY_ID_BCM5464,
    888	.phy_id_mask	= 0xfffffff0,
    889	.name		= "Broadcom BCM5464",
    890	/* PHY_GBIT_FEATURES */
    891	.get_sset_count	= bcm_phy_get_sset_count,
    892	.get_strings	= bcm_phy_get_strings,
    893	.get_stats	= bcm54xx_get_stats,
    894	.probe		= bcm54xx_phy_probe,
    895	.config_init	= bcm54xx_config_init,
    896	.config_intr	= bcm_phy_config_intr,
    897	.handle_interrupt = bcm_phy_handle_interrupt,
    898	.suspend	= genphy_suspend,
    899	.resume		= genphy_resume,
    900	.link_change_notify	= bcm54xx_link_change_notify,
    901}, {
    902	.phy_id		= PHY_ID_BCM5481,
    903	.phy_id_mask	= 0xfffffff0,
    904	.name		= "Broadcom BCM5481",
    905	/* PHY_GBIT_FEATURES */
    906	.get_sset_count	= bcm_phy_get_sset_count,
    907	.get_strings	= bcm_phy_get_strings,
    908	.get_stats	= bcm54xx_get_stats,
    909	.probe		= bcm54xx_phy_probe,
    910	.config_init	= bcm54xx_config_init,
    911	.config_aneg	= bcm5481_config_aneg,
    912	.config_intr	= bcm_phy_config_intr,
    913	.handle_interrupt = bcm_phy_handle_interrupt,
    914	.link_change_notify	= bcm54xx_link_change_notify,
    915}, {
    916	.phy_id         = PHY_ID_BCM54810,
    917	.phy_id_mask    = 0xfffffff0,
    918	.name           = "Broadcom BCM54810",
    919	/* PHY_GBIT_FEATURES */
    920	.get_sset_count	= bcm_phy_get_sset_count,
    921	.get_strings	= bcm_phy_get_strings,
    922	.get_stats	= bcm54xx_get_stats,
    923	.probe		= bcm54xx_phy_probe,
    924	.config_init    = bcm54xx_config_init,
    925	.config_aneg    = bcm5481_config_aneg,
    926	.config_intr    = bcm_phy_config_intr,
    927	.handle_interrupt = bcm_phy_handle_interrupt,
    928	.suspend	= bcm54xx_suspend,
    929	.resume		= bcm54xx_resume,
    930	.link_change_notify	= bcm54xx_link_change_notify,
    931}, {
    932	.phy_id         = PHY_ID_BCM54811,
    933	.phy_id_mask    = 0xfffffff0,
    934	.name           = "Broadcom BCM54811",
    935	/* PHY_GBIT_FEATURES */
    936	.get_sset_count	= bcm_phy_get_sset_count,
    937	.get_strings	= bcm_phy_get_strings,
    938	.get_stats	= bcm54xx_get_stats,
    939	.probe		= bcm54xx_phy_probe,
    940	.config_init    = bcm54811_config_init,
    941	.config_aneg    = bcm5481_config_aneg,
    942	.config_intr    = bcm_phy_config_intr,
    943	.handle_interrupt = bcm_phy_handle_interrupt,
    944	.suspend	= bcm54xx_suspend,
    945	.resume		= bcm54xx_resume,
    946	.link_change_notify	= bcm54xx_link_change_notify,
    947}, {
    948	.phy_id		= PHY_ID_BCM5482,
    949	.phy_id_mask	= 0xfffffff0,
    950	.name		= "Broadcom BCM5482",
    951	/* PHY_GBIT_FEATURES */
    952	.get_sset_count	= bcm_phy_get_sset_count,
    953	.get_strings	= bcm_phy_get_strings,
    954	.get_stats	= bcm54xx_get_stats,
    955	.probe		= bcm54xx_phy_probe,
    956	.config_init	= bcm54xx_config_init,
    957	.config_intr	= bcm_phy_config_intr,
    958	.handle_interrupt = bcm_phy_handle_interrupt,
    959	.link_change_notify	= bcm54xx_link_change_notify,
    960}, {
    961	.phy_id		= PHY_ID_BCM50610,
    962	.phy_id_mask	= 0xfffffff0,
    963	.name		= "Broadcom BCM50610",
    964	/* PHY_GBIT_FEATURES */
    965	.get_sset_count	= bcm_phy_get_sset_count,
    966	.get_strings	= bcm_phy_get_strings,
    967	.get_stats	= bcm54xx_get_stats,
    968	.probe		= bcm54xx_phy_probe,
    969	.config_init	= bcm54xx_config_init,
    970	.config_intr	= bcm_phy_config_intr,
    971	.handle_interrupt = bcm_phy_handle_interrupt,
    972	.link_change_notify	= bcm54xx_link_change_notify,
    973	.suspend	= bcm54xx_suspend,
    974	.resume		= bcm54xx_resume,
    975}, {
    976	.phy_id		= PHY_ID_BCM50610M,
    977	.phy_id_mask	= 0xfffffff0,
    978	.name		= "Broadcom BCM50610M",
    979	/* PHY_GBIT_FEATURES */
    980	.get_sset_count	= bcm_phy_get_sset_count,
    981	.get_strings	= bcm_phy_get_strings,
    982	.get_stats	= bcm54xx_get_stats,
    983	.probe		= bcm54xx_phy_probe,
    984	.config_init	= bcm54xx_config_init,
    985	.config_intr	= bcm_phy_config_intr,
    986	.handle_interrupt = bcm_phy_handle_interrupt,
    987	.link_change_notify	= bcm54xx_link_change_notify,
    988	.suspend	= bcm54xx_suspend,
    989	.resume		= bcm54xx_resume,
    990}, {
    991	.phy_id		= PHY_ID_BCM57780,
    992	.phy_id_mask	= 0xfffffff0,
    993	.name		= "Broadcom BCM57780",
    994	/* PHY_GBIT_FEATURES */
    995	.get_sset_count	= bcm_phy_get_sset_count,
    996	.get_strings	= bcm_phy_get_strings,
    997	.get_stats	= bcm54xx_get_stats,
    998	.probe		= bcm54xx_phy_probe,
    999	.config_init	= bcm54xx_config_init,
   1000	.config_intr	= bcm_phy_config_intr,
   1001	.handle_interrupt = bcm_phy_handle_interrupt,
   1002	.link_change_notify	= bcm54xx_link_change_notify,
   1003}, {
   1004	.phy_id		= PHY_ID_BCMAC131,
   1005	.phy_id_mask	= 0xfffffff0,
   1006	.name		= "Broadcom BCMAC131",
   1007	/* PHY_BASIC_FEATURES */
   1008	.config_init	= brcm_fet_config_init,
   1009	.config_intr	= brcm_fet_config_intr,
   1010	.handle_interrupt = brcm_fet_handle_interrupt,
   1011}, {
   1012	.phy_id		= PHY_ID_BCM5241,
   1013	.phy_id_mask	= 0xfffffff0,
   1014	.name		= "Broadcom BCM5241",
   1015	/* PHY_BASIC_FEATURES */
   1016	.config_init	= brcm_fet_config_init,
   1017	.config_intr	= brcm_fet_config_intr,
   1018	.handle_interrupt = brcm_fet_handle_interrupt,
   1019}, {
   1020	.phy_id		= PHY_ID_BCM5395,
   1021	.phy_id_mask	= 0xfffffff0,
   1022	.name		= "Broadcom BCM5395",
   1023	.flags		= PHY_IS_INTERNAL,
   1024	/* PHY_GBIT_FEATURES */
   1025	.get_sset_count	= bcm_phy_get_sset_count,
   1026	.get_strings	= bcm_phy_get_strings,
   1027	.get_stats	= bcm54xx_get_stats,
   1028	.probe		= bcm54xx_phy_probe,
   1029	.link_change_notify	= bcm54xx_link_change_notify,
   1030}, {
   1031	.phy_id		= PHY_ID_BCM53125,
   1032	.phy_id_mask	= 0xfffffff0,
   1033	.name		= "Broadcom BCM53125",
   1034	.flags		= PHY_IS_INTERNAL,
   1035	/* PHY_GBIT_FEATURES */
   1036	.get_sset_count	= bcm_phy_get_sset_count,
   1037	.get_strings	= bcm_phy_get_strings,
   1038	.get_stats	= bcm54xx_get_stats,
   1039	.probe		= bcm54xx_phy_probe,
   1040	.config_init	= bcm54xx_config_init,
   1041	.config_intr	= bcm_phy_config_intr,
   1042	.handle_interrupt = bcm_phy_handle_interrupt,
   1043	.link_change_notify	= bcm54xx_link_change_notify,
   1044}, {
   1045	.phy_id         = PHY_ID_BCM89610,
   1046	.phy_id_mask    = 0xfffffff0,
   1047	.name           = "Broadcom BCM89610",
   1048	/* PHY_GBIT_FEATURES */
   1049	.get_sset_count	= bcm_phy_get_sset_count,
   1050	.get_strings	= bcm_phy_get_strings,
   1051	.get_stats	= bcm54xx_get_stats,
   1052	.probe		= bcm54xx_phy_probe,
   1053	.config_init    = bcm54xx_config_init,
   1054	.config_intr    = bcm_phy_config_intr,
   1055	.handle_interrupt = bcm_phy_handle_interrupt,
   1056	.link_change_notify	= bcm54xx_link_change_notify,
   1057} };
   1058
   1059module_phy_driver(broadcom_drivers);
   1060
   1061static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
   1062	{ PHY_ID_BCM5411, 0xfffffff0 },
   1063	{ PHY_ID_BCM5421, 0xfffffff0 },
   1064	{ PHY_ID_BCM54210E, 0xfffffff0 },
   1065	{ PHY_ID_BCM5461, 0xfffffff0 },
   1066	{ PHY_ID_BCM54612E, 0xfffffff0 },
   1067	{ PHY_ID_BCM54616S, 0xfffffff0 },
   1068	{ PHY_ID_BCM5464, 0xfffffff0 },
   1069	{ PHY_ID_BCM5481, 0xfffffff0 },
   1070	{ PHY_ID_BCM54810, 0xfffffff0 },
   1071	{ PHY_ID_BCM54811, 0xfffffff0 },
   1072	{ PHY_ID_BCM5482, 0xfffffff0 },
   1073	{ PHY_ID_BCM50610, 0xfffffff0 },
   1074	{ PHY_ID_BCM50610M, 0xfffffff0 },
   1075	{ PHY_ID_BCM57780, 0xfffffff0 },
   1076	{ PHY_ID_BCMAC131, 0xfffffff0 },
   1077	{ PHY_ID_BCM5241, 0xfffffff0 },
   1078	{ PHY_ID_BCM5395, 0xfffffff0 },
   1079	{ PHY_ID_BCM53125, 0xfffffff0 },
   1080	{ PHY_ID_BCM89610, 0xfffffff0 },
   1081	{ }
   1082};
   1083
   1084MODULE_DEVICE_TABLE(mdio, broadcom_tbl);