aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Carlson <mcarlson@broadcom.com>2007-11-13 00:08:03 -0500
committerDavid S. Miller <davem@davemloft.net>2007-11-13 00:08:03 -0500
commitce057f01956bfcb3cb8588091000ae546be78e00 (patch)
tree6438c33bcdde387ab191912e970b2fb65696b0a0
parentc88864df27590b80fca4a991e0c257d1757cec41 (diff)
[TG3]: 5784 / 5764 GPHY power down fix
5784 and 5764 devices fail to link / pass traffic after one load / unload cycle. This happens because of a hardware bug in the new CPMU. During normal operation, the MAC depends on the PHY clock being available. When the PHY is powered down, the clock the MAC depends on is disabled. The fix is to switch the MAC clock to an alternate source before powering down the PHY, and to restore the MAC clock to the PHY source upon device resume. Signed-off-by: Matt Carlson <mcarlson@broadcom.com> Signed-off-by: Michael Chan <mchan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/tg3.c26
-rw-r--r--drivers/net/tg3.h9
2 files changed, 32 insertions, 3 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index ddeaa0c78305..82b1cf0e2d18 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -1106,6 +1106,19 @@ static int tg3_phy_reset(struct tg3 *tp)
1106 if (err) 1106 if (err)
1107 return err; 1107 return err;
1108 1108
1109 if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0 ||
1110 tp->pci_chip_rev_id == CHIPREV_ID_5761_A0) {
1111 u32 val;
1112
1113 val = tr32(TG3_CPMU_LSPD_1000MB_CLK);
1114 if ((val & CPMU_LSPD_1000MB_MACCLK_MASK) ==
1115 CPMU_LSPD_1000MB_MACCLK_12_5) {
1116 val &= ~CPMU_LSPD_1000MB_MACCLK_MASK;
1117 udelay(40);
1118 tw32_f(TG3_CPMU_LSPD_1000MB_CLK, val);
1119 }
1120 }
1121
1109out: 1122out:
1110 if (tp->tg3_flags2 & TG3_FLG2_PHY_ADC_BUG) { 1123 if (tp->tg3_flags2 & TG3_FLG2_PHY_ADC_BUG) {
1111 tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00); 1124 tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
@@ -1297,6 +1310,8 @@ static void tg3_nvram_unlock(struct tg3 *);
1297 1310
1298static void tg3_power_down_phy(struct tg3 *tp) 1311static void tg3_power_down_phy(struct tg3 *tp)
1299{ 1312{
1313 u32 val;
1314
1300 if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) { 1315 if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
1301 if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) { 1316 if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
1302 u32 sg_dig_ctrl = tr32(SG_DIG_CTRL); 1317 u32 sg_dig_ctrl = tr32(SG_DIG_CTRL);
@@ -1311,8 +1326,6 @@ static void tg3_power_down_phy(struct tg3 *tp)
1311 } 1326 }
1312 1327
1313 if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { 1328 if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
1314 u32 val;
1315
1316 tg3_bmcr_reset(tp); 1329 tg3_bmcr_reset(tp);
1317 val = tr32(GRC_MISC_CFG); 1330 val = tr32(GRC_MISC_CFG);
1318 tw32_f(GRC_MISC_CFG, val | GRC_MISC_CFG_EPHY_IDDQ); 1331 tw32_f(GRC_MISC_CFG, val | GRC_MISC_CFG_EPHY_IDDQ);
@@ -1332,6 +1345,15 @@ static void tg3_power_down_phy(struct tg3 *tp)
1332 (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 && 1345 (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 &&
1333 (tp->tg3_flags2 & TG3_FLG2_MII_SERDES))) 1346 (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)))
1334 return; 1347 return;
1348
1349 if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0 ||
1350 tp->pci_chip_rev_id == CHIPREV_ID_5761_A0) {
1351 val = tr32(TG3_CPMU_LSPD_1000MB_CLK);
1352 val &= ~CPMU_LSPD_1000MB_MACCLK_MASK;
1353 val |= CPMU_LSPD_1000MB_MACCLK_12_5;
1354 tw32_f(TG3_CPMU_LSPD_1000MB_CLK, val);
1355 }
1356
1335 tg3_writephy(tp, MII_BMCR, BMCR_PDOWN); 1357 tg3_writephy(tp, MII_BMCR, BMCR_PDOWN);
1336} 1358}
1337 1359
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index 1d5b2a3dd29d..4659697beb4b 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -109,6 +109,7 @@
109#define CHIPREV_ID_5714_A2 0x9002 109#define CHIPREV_ID_5714_A2 0x9002
110#define CHIPREV_ID_5906_A1 0xc001 110#define CHIPREV_ID_5906_A1 0xc001
111#define CHIPREV_ID_5784_A0 0x5784000 111#define CHIPREV_ID_5784_A0 0x5784000
112#define CHIPREV_ID_5761_A0 0x5761000
112#define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12) 113#define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12)
113#define ASIC_REV_5700 0x07 114#define ASIC_REV_5700 0x07
114#define ASIC_REV_5701 0x00 115#define ASIC_REV_5701 0x00
@@ -856,7 +857,13 @@
856#define CPMU_CTRL_LINK_IDLE_MODE 0x00000200 857#define CPMU_CTRL_LINK_IDLE_MODE 0x00000200
857#define CPMU_CTRL_LINK_AWARE_MODE 0x00000400 858#define CPMU_CTRL_LINK_AWARE_MODE 0x00000400
858#define CPMU_CTRL_LINK_SPEED_MODE 0x00004000 859#define CPMU_CTRL_LINK_SPEED_MODE 0x00004000
859/* 0x3604 --> 0x365c unused */ 860/* 0x3604 --> 0x360c unused */
861
862#define TG3_CPMU_LSPD_1000MB_CLK 0x0000360c
863#define CPMU_LSPD_1000MB_MACCLK_62_5 0x00000000
864#define CPMU_LSPD_1000MB_MACCLK_12_5 0x00110000
865#define CPMU_LSPD_1000MB_MACCLK_MASK 0x001f0000
866/* 0x3610 --> 0x365c unused */
860 867
861#define TG3_CPMU_MUTEX_REQ 0x0000365c 868#define TG3_CPMU_MUTEX_REQ 0x0000365c
862#define CPMU_MUTEX_REQ_DRIVER 0x00001000 869#define CPMU_MUTEX_REQ_DRIVER 0x00001000