Skip to content

Commit

Permalink
Merge branch 'bcm7xxx_apd_eee'
Browse files Browse the repository at this point in the history
Florian Fainelli says:

====================
net: phy: bcm7xxx: APD and EEE support

This patch series enables Auto-power down and EEE for the BCM7xxx integrated
Gigabit PHYs.

I also put a fix for the fixed PHY that would allow clause 45 over clause 22
reads/writes but would return bogus data by using e.g: ethtool --show-eee
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Aug 23, 2014
2 parents 5aa8dbb + b8f9a02 commit 1ad676a
Show file tree
Hide file tree
Showing 6 changed files with 229 additions and 127 deletions.
58 changes: 57 additions & 1 deletion drivers/net/phy/bcm7xxx.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <linux/delay.h>
#include <linux/bitops.h>
#include <linux/brcmphy.h>
#include <linux/mdio.h>

/* Broadcom BCM7xxx internal PHY registers */
#define MII_BCM7XXX_CHANNEL_WIDTH 0x2000
Expand Down Expand Up @@ -146,6 +147,53 @@ static int bcm7xxx_28nm_afe_config_init(struct phy_device *phydev)
return 0;
}

static int bcm7xxx_apd_enable(struct phy_device *phydev)
{
int val;

/* Enable powering down of the DLL during auto-power down */
val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_SCR3);
if (val < 0)
return val;

val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
bcm54xx_shadow_write(phydev, BCM54XX_SHD_SCR3, val);

/* Enable auto-power down */
val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_APD);
if (val < 0)
return val;

val |= BCM54XX_SHD_APD_EN;
return bcm54xx_shadow_write(phydev, BCM54XX_SHD_APD, val);
}

static int bcm7xxx_eee_enable(struct phy_device *phydev)
{
int val;

val = phy_read_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL,
MDIO_MMD_AN, phydev->addr);
if (val < 0)
return val;

/* Enable general EEE feature at the PHY level */
val |= LPI_FEATURE_EN | LPI_FEATURE_EN_DIG1000X;

phy_write_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL,
MDIO_MMD_AN, phydev->addr, val);

/* Advertise supported modes */
val = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_ADV,
MDIO_MMD_AN, phydev->addr);

val |= (MDIO_AN_EEE_ADV_100TX | MDIO_AN_EEE_ADV_1000T);
phy_write_mmd_indirect(phydev, MDIO_AN_EEE_ADV,
MDIO_MMD_AN, phydev->addr, val);

return 0;
}

static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
{
int ret;
Expand All @@ -154,7 +202,15 @@ static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
if (ret)
return ret;

return bcm7xxx_28nm_afe_config_init(phydev);
ret = bcm7xxx_28nm_afe_config_init(phydev);
if (ret)
return ret;

ret = bcm7xxx_eee_enable(phydev);
if (ret)
return ret;

return bcm7xxx_apd_enable(phydev);
}

static int bcm7xxx_28nm_resume(struct phy_device *phydev)
Expand Down
122 changes: 0 additions & 122 deletions drivers/net/phy/broadcom.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,132 +25,10 @@
#define BRCM_PHY_REV(phydev) \
((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask))

/*
* Broadcom LED source encodings. These are used in BCM5461, BCM5481,
* BCM5482, and possibly some others.
*/
#define BCM_LED_SRC_LINKSPD1 0x0
#define BCM_LED_SRC_LINKSPD2 0x1
#define BCM_LED_SRC_XMITLED 0x2
#define BCM_LED_SRC_ACTIVITYLED 0x3
#define BCM_LED_SRC_FDXLED 0x4
#define BCM_LED_SRC_SLAVE 0x5
#define BCM_LED_SRC_INTR 0x6
#define BCM_LED_SRC_QUALITY 0x7
#define BCM_LED_SRC_RCVLED 0x8
#define BCM_LED_SRC_MULTICOLOR1 0xa
#define BCM_LED_SRC_OPENSHORT 0xb
#define BCM_LED_SRC_OFF 0xe /* Tied high */
#define BCM_LED_SRC_ON 0xf /* Tied low */


/*
* BCM5482: Shadow registers
* Shadow values go into bits [14:10] of register 0x1c to select a shadow
* register to access.
*/
/* 00101: Spare Control Register 3 */
#define BCM54XX_SHD_SCR3 0x05
#define BCM54XX_SHD_SCR3_DEF_CLK125 0x0001
#define BCM54XX_SHD_SCR3_DLLAPD_DIS 0x0002
#define BCM54XX_SHD_SCR3_TRDDAPD 0x0004

/* 01010: Auto Power-Down */
#define BCM54XX_SHD_APD 0x0a
#define BCM54XX_SHD_APD_EN 0x0020

#define BCM5482_SHD_LEDS1 0x0d /* 01101: LED Selector 1 */
/* LED3 / ~LINKSPD[2] selector */
#define BCM5482_SHD_LEDS1_LED3(src) ((src & 0xf) << 4)
/* LED1 / ~LINKSPD[1] selector */
#define BCM5482_SHD_LEDS1_LED1(src) ((src & 0xf) << 0)
#define BCM54XX_SHD_RGMII_MODE 0x0b /* 01011: RGMII Mode Selector */
#define BCM5482_SHD_SSD 0x14 /* 10100: Secondary SerDes control */
#define BCM5482_SHD_SSD_LEDM 0x0008 /* SSD LED Mode enable */
#define BCM5482_SHD_SSD_EN 0x0001 /* SSD enable */
#define BCM5482_SHD_MODE 0x1f /* 11111: Mode Control Register */
#define BCM5482_SHD_MODE_1000BX 0x0001 /* Enable 1000BASE-X registers */


/*
* EXPANSION SHADOW ACCESS REGISTERS. (PHY REG 0x15, 0x16, and 0x17)
*/
#define MII_BCM54XX_EXP_AADJ1CH0 0x001f
#define MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN 0x0200
#define MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF 0x0100
#define MII_BCM54XX_EXP_AADJ1CH3 0x601f
#define MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ 0x0002
#define MII_BCM54XX_EXP_EXP08 0x0F08
#define MII_BCM54XX_EXP_EXP08_RJCT_2MHZ 0x0001
#define MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE 0x0200
#define MII_BCM54XX_EXP_EXP75 0x0f75
#define MII_BCM54XX_EXP_EXP75_VDACCTRL 0x003c
#define MII_BCM54XX_EXP_EXP75_CM_OSC 0x0001
#define MII_BCM54XX_EXP_EXP96 0x0f96
#define MII_BCM54XX_EXP_EXP96_MYST 0x0010
#define MII_BCM54XX_EXP_EXP97 0x0f97
#define MII_BCM54XX_EXP_EXP97_MYST 0x0c0c

/*
* BCM5482: Secondary SerDes registers
*/
#define BCM5482_SSD_1000BX_CTL 0x00 /* 1000BASE-X Control */
#define BCM5482_SSD_1000BX_CTL_PWRDOWN 0x0800 /* Power-down SSD */
#define BCM5482_SSD_SGMII_SLAVE 0x15 /* SGMII Slave Register */
#define BCM5482_SSD_SGMII_SLAVE_EN 0x0002 /* Slave mode enable */
#define BCM5482_SSD_SGMII_SLAVE_AD 0x0001 /* Slave auto-detection */


/*****************************************************************************/
/* Fast Ethernet Transceiver definitions. */
/*****************************************************************************/

#define MII_BRCM_FET_INTREG 0x1a /* Interrupt register */
#define MII_BRCM_FET_IR_MASK 0x0100 /* Mask all interrupts */
#define MII_BRCM_FET_IR_LINK_EN 0x0200 /* Link status change enable */
#define MII_BRCM_FET_IR_SPEED_EN 0x0400 /* Link speed change enable */
#define MII_BRCM_FET_IR_DUPLEX_EN 0x0800 /* Duplex mode change enable */
#define MII_BRCM_FET_IR_ENABLE 0x4000 /* Interrupt enable */

#define MII_BRCM_FET_BRCMTEST 0x1f /* Brcm test register */
#define MII_BRCM_FET_BT_SRE 0x0080 /* Shadow register enable */


/*** Shadow register definitions ***/

#define MII_BRCM_FET_SHDW_MISCCTRL 0x10 /* Shadow misc ctrl */
#define MII_BRCM_FET_SHDW_MC_FAME 0x4000 /* Force Auto MDIX enable */

#define MII_BRCM_FET_SHDW_AUXMODE4 0x1a /* Auxiliary mode 4 */
#define MII_BRCM_FET_SHDW_AM4_LED_MASK 0x0003
#define MII_BRCM_FET_SHDW_AM4_LED_MODE1 0x0001

#define MII_BRCM_FET_SHDW_AUXSTAT2 0x1b /* Auxiliary status 2 */
#define MII_BRCM_FET_SHDW_AS2_APDE 0x0020 /* Auto power down enable */


MODULE_DESCRIPTION("Broadcom PHY driver");
MODULE_AUTHOR("Maciej W. Rozycki");
MODULE_LICENSE("GPL");

/*
* Indirect register access functions for the 1000BASE-T/100BASE-TX/10BASE-T
* 0x1c shadow registers.
*/
static int bcm54xx_shadow_read(struct phy_device *phydev, u16 shadow)
{
phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow));
return MII_BCM54XX_SHD_DATA(phy_read(phydev, MII_BCM54XX_SHD));
}

static int bcm54xx_shadow_write(struct phy_device *phydev, u16 shadow, u16 val)
{
return phy_write(phydev, MII_BCM54XX_SHD,
MII_BCM54XX_SHD_WRITE |
MII_BCM54XX_SHD_VAL(shadow) |
MII_BCM54XX_SHD_DATA(val));
}

/* Indirect register access functions for the Expansion Registers */
static int bcm54xx_exp_read(struct phy_device *phydev, u16 regnum)
{
Expand Down
11 changes: 11 additions & 0 deletions drivers/net/phy/fixed.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,17 @@ static int fixed_mdio_read(struct mii_bus *bus, int phy_addr, int reg_num)
if (reg_num >= MII_REGS_NUM)
return -1;

/* We do not support emulating Clause 45 over Clause 22 register reads
* return an error instead of bogus data.
*/
switch (reg_num) {
case MII_MMD_CTRL:
case MII_MMD_DATA:
return -1;
default:
break;
}

list_for_each_entry(fp, &fmb->phys, node) {
if (fp->addr == phy_addr) {
/* Issue callback if user registered it. */
Expand Down
12 changes: 8 additions & 4 deletions drivers/net/phy/phy.c
Original file line number Diff line number Diff line change
Expand Up @@ -955,7 +955,7 @@ static inline void mmd_phy_indirect(struct mii_bus *bus, int prtad, int devad,
* 3) Write reg 13 // MMD Data Command for MMD DEVAD
* 3) Read reg 14 // Read MMD data
*/
static int phy_read_mmd_indirect(struct phy_device *phydev, int prtad,
int phy_read_mmd_indirect(struct phy_device *phydev, int prtad,
int devad, int addr)
{
struct phy_driver *phydrv = phydev->drv;
Expand All @@ -971,6 +971,7 @@ static int phy_read_mmd_indirect(struct phy_device *phydev, int prtad,
}
return value;
}
EXPORT_SYMBOL(phy_read_mmd_indirect);

/**
* phy_write_mmd_indirect - writes data to the MMD registers
Expand All @@ -988,7 +989,7 @@ static int phy_read_mmd_indirect(struct phy_device *phydev, int prtad,
* 3) Write reg 13 // MMD Data Command for MMD DEVAD
* 3) Write reg 14 // Write MMD data
*/
static void phy_write_mmd_indirect(struct phy_device *phydev, int prtad,
void phy_write_mmd_indirect(struct phy_device *phydev, int prtad,
int devad, int addr, u32 data)
{
struct phy_driver *phydrv = phydev->drv;
Expand All @@ -1002,6 +1003,7 @@ static void phy_write_mmd_indirect(struct phy_device *phydev, int prtad,
phydrv->write_mmd_indirect(phydev, prtad, devad, addr, data);
}
}
EXPORT_SYMBOL(phy_write_mmd_indirect);

/**
* phy_init_eee - init and check the EEE feature
Expand All @@ -1017,12 +1019,14 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
{
/* According to 802.3az,the EEE is supported only in full duplex-mode.
* Also EEE feature is active when core is operating with MII, GMII
* or RGMII.
* or RGMII. Internal PHYs are also allowed to proceed and should
* return an error if they do not support EEE.
*/
if ((phydev->duplex == DUPLEX_FULL) &&
((phydev->interface == PHY_INTERFACE_MODE_MII) ||
(phydev->interface == PHY_INTERFACE_MODE_GMII) ||
(phydev->interface == PHY_INTERFACE_MODE_RGMII))) {
(phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
phy_is_internal(phydev))) {
int eee_lp, eee_cap, eee_adv;
u32 lp, cap, adv;
int status;
Expand Down
Loading

0 comments on commit 1ad676a

Please sign in to comment.