|
@@ -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)) {
|