aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/tg3.c
diff options
context:
space:
mode:
authorMatt Carlson <mcarlson@broadcom.com>2010-10-14 10:37:41 +0000
committerDavid S. Miller <davem@davemloft.net>2010-10-17 13:57:44 -0700
commit52b02d04c801fff51ca49ad033210846d1713253 (patch)
tree719c03990321d703b192caf38186e30bb999885e /drivers/net/tg3.c
parenttg3: Add clause 45 register accessor methods (diff)
downloadlinux-dev-52b02d04c801fff51ca49ad033210846d1713253.tar.xz
linux-dev-52b02d04c801fff51ca49ad033210846d1713253.zip
tg3: Add EEE support
This patch adds Energy Efficient Ethernet (EEE) support for the 5718 device ID and the 57765 B0 asic revision. Signed-off-by: Matt Carlson <mcarlson@broadcom.com> Reviewed-by: Michael Chan <mchan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/tg3.c')
-rw-r--r--drivers/net/tg3.c114
1 files changed, 114 insertions, 0 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index afcc593108ce..f2d96ddd464e 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -1584,6 +1584,17 @@ static void tg3_phy_fini(struct tg3 *tp)
}
}
+static int tg3_phydsp_read(struct tg3 *tp, u32 reg, u32 *val)
+{
+ int err;
+
+ err = tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg);
+ if (!err)
+ err = tg3_readphy(tp, MII_TG3_DSP_RW_PORT, val);
+
+ return err;
+}
+
static int tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val)
{
int err;
@@ -1747,6 +1758,42 @@ static void tg3_phy_apply_otp(struct tg3 *tp)
tg3_writephy(tp, MII_TG3_AUX_CTRL, phy);
}
+static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up)
+{
+ u32 val;
+
+ if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP))
+ return;
+
+ tp->setlpicnt = 0;
+
+ if (tp->link_config.autoneg == AUTONEG_ENABLE &&
+ current_link_up == 1 &&
+ (tp->link_config.active_speed == SPEED_1000 ||
+ (tp->link_config.active_speed == SPEED_100 &&
+ tp->link_config.active_duplex == DUPLEX_FULL))) {
+ u32 eeectl;
+
+ if (tp->link_config.active_speed == SPEED_1000)
+ eeectl = TG3_CPMU_EEE_CTRL_EXIT_16_5_US;
+ else
+ eeectl = TG3_CPMU_EEE_CTRL_EXIT_36_US;
+
+ tw32(TG3_CPMU_EEE_CTRL, eeectl);
+
+ tg3_phy_cl45_read(tp, 0x7, TG3_CL45_D7_EEERES_STAT, &val);
+
+ if (val == TG3_CL45_D7_EEERES_STAT_LP_1000T ||
+ val == TG3_CL45_D7_EEERES_STAT_LP_100TX)
+ tp->setlpicnt = 2;
+ }
+
+ if (!tp->setlpicnt) {
+ val = tr32(TG3_CPMU_EEE_MODE);
+ tw32(TG3_CPMU_EEE_MODE, val & ~TG3_CPMU_EEEMD_LPI_ENABLE);
+ }
+}
+
static int tg3_wait_macro_done(struct tg3 *tp)
{
int limit = 100;
@@ -2921,6 +2968,44 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
tg3_writephy(tp, MII_TG3_CTRL, new_adv);
}
+ if (tp->phy_flags & TG3_PHYFLG_EEE_CAP) {
+ u32 val = 0;
+
+ tw32(TG3_CPMU_EEE_MODE,
+ tr32(TG3_CPMU_EEE_MODE) & ~TG3_CPMU_EEEMD_LPI_ENABLE);
+
+ /* Enable SM_DSP clock and tx 6dB coding. */
+ val = MII_TG3_AUXCTL_SHDWSEL_AUXCTL |
+ MII_TG3_AUXCTL_ACTL_SMDSP_ENA |
+ MII_TG3_AUXCTL_ACTL_TX_6DB;
+ tg3_writephy(tp, MII_TG3_AUX_CTRL, val);
+
+ if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) &&
+ !tg3_phydsp_read(tp, MII_TG3_DSP_CH34TP2, &val))
+ tg3_phydsp_write(tp, MII_TG3_DSP_CH34TP2,
+ val | MII_TG3_DSP_CH34TP2_HIBW01);
+
+ if (tp->link_config.autoneg == AUTONEG_ENABLE) {
+ /* Advertise 100-BaseTX EEE ability */
+ if (tp->link_config.advertising &
+ (ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full))
+ val |= TG3_CL45_D7_EEEADV_CAP_100TX;
+ /* Advertise 1000-BaseT EEE ability */
+ if (tp->link_config.advertising &
+ (ADVERTISED_1000baseT_Half |
+ ADVERTISED_1000baseT_Full))
+ val |= TG3_CL45_D7_EEEADV_CAP_1000T;
+ }
+ tg3_phy_cl45_write(tp, 0x7, TG3_CL45_D7_EEEADV_CAP, val);
+
+ /* Turn off SM_DSP clock. */
+ val = MII_TG3_AUXCTL_SHDWSEL_AUXCTL |
+ MII_TG3_AUXCTL_ACTL_TX_6DB;
+ tg3_writephy(tp, MII_TG3_AUX_CTRL, val);
+ }
+
if (tp->link_config.autoneg == AUTONEG_DISABLE &&
tp->link_config.speed != SPEED_INVALID) {
u32 bmcr, orig_bmcr;
@@ -3282,6 +3367,8 @@ relink:
tw32_f(MAC_MODE, tp->mac_mode);
udelay(40);
+ tg3_phy_eee_adjust(tp, current_link_up);
+
if (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) {
/* Polled via timer. */
tw32_f(MAC_EVENT, 0);
@@ -7790,6 +7877,22 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(TG3_CPMU_LSPD_10MB_CLK, val);
}
+ /* Enable MAC control of LPI */
+ if (tp->phy_flags & TG3_PHYFLG_EEE_CAP) {
+ tw32_f(TG3_CPMU_EEE_LNKIDL_CTRL,
+ TG3_CPMU_EEE_LNKIDL_PCIE_NL0 |
+ TG3_CPMU_EEE_LNKIDL_UART_IDL);
+
+ tw32_f(TG3_CPMU_EEE_CTRL,
+ TG3_CPMU_EEE_CTRL_EXIT_20_1_US);
+
+ tw32_f(TG3_CPMU_EEE_MODE,
+ TG3_CPMU_EEEMD_ERLY_L1_XIT_DET |
+ TG3_CPMU_EEEMD_LPI_IN_TX |
+ TG3_CPMU_EEEMD_LPI_IN_RX |
+ TG3_CPMU_EEEMD_EEE_ENABLE);
+ }
+
/* This works around an issue with Athlon chipsets on
* B3 tigon3 silicon. This bit has no effect on any
* other revision. But do not set this on PCI Express
@@ -8598,6 +8701,12 @@ static void tg3_timer(unsigned long __opaque)
if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
tg3_periodic_fetch_stats(tp);
+ if (tp->setlpicnt && !--tp->setlpicnt) {
+ u32 val = tr32(TG3_CPMU_EEE_MODE);
+ tw32(TG3_CPMU_EEE_MODE,
+ val | TG3_CPMU_EEEMD_LPI_ENABLE);
+ }
+
if (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) {
u32 mac_stat;
int phy_event;
@@ -12432,6 +12541,11 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
}
}
+ if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 ||
+ (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 &&
+ tp->pci_chip_rev_id != CHIPREV_ID_57765_A0))
+ tp->phy_flags |= TG3_PHYFLG_EEE_CAP;
+
if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES) &&
!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) &&
!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {