diff options
Diffstat (limited to 'drivers/net/atl1c/atl1c_hw.c')
-rw-r--r-- | drivers/net/atl1c/atl1c_hw.c | 107 |
1 files changed, 92 insertions, 15 deletions
diff --git a/drivers/net/atl1c/atl1c_hw.c b/drivers/net/atl1c/atl1c_hw.c index f1389d664a21..d8501f060957 100644 --- a/drivers/net/atl1c/atl1c_hw.c +++ b/drivers/net/atl1c/atl1c_hw.c | |||
@@ -37,6 +37,9 @@ int atl1c_check_eeprom_exist(struct atl1c_hw *hw) | |||
37 | if (data & TWSI_DEBUG_DEV_EXIST) | 37 | if (data & TWSI_DEBUG_DEV_EXIST) |
38 | return 1; | 38 | return 1; |
39 | 39 | ||
40 | AT_READ_REG(hw, REG_MASTER_CTRL, &data); | ||
41 | if (data & MASTER_CTRL_OTP_SEL) | ||
42 | return 1; | ||
40 | return 0; | 43 | return 0; |
41 | } | 44 | } |
42 | 45 | ||
@@ -69,6 +72,8 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw) | |||
69 | u32 i; | 72 | u32 i; |
70 | u32 otp_ctrl_data; | 73 | u32 otp_ctrl_data; |
71 | u32 twsi_ctrl_data; | 74 | u32 twsi_ctrl_data; |
75 | u32 ltssm_ctrl_data; | ||
76 | u32 wol_data; | ||
72 | u8 eth_addr[ETH_ALEN]; | 77 | u8 eth_addr[ETH_ALEN]; |
73 | u16 phy_data; | 78 | u16 phy_data; |
74 | bool raise_vol = false; | 79 | bool raise_vol = false; |
@@ -104,6 +109,15 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw) | |||
104 | udelay(20); | 109 | udelay(20); |
105 | raise_vol = true; | 110 | raise_vol = true; |
106 | } | 111 | } |
112 | /* close open bit of ReadOnly*/ | ||
113 | AT_READ_REG(hw, REG_LTSSM_ID_CTRL, <ssm_ctrl_data); | ||
114 | ltssm_ctrl_data &= ~LTSSM_ID_EN_WRO; | ||
115 | AT_WRITE_REG(hw, REG_LTSSM_ID_CTRL, ltssm_ctrl_data); | ||
116 | |||
117 | /* clear any WOL settings */ | ||
118 | AT_WRITE_REG(hw, REG_WOL_CTRL, 0); | ||
119 | AT_READ_REG(hw, REG_WOL_CTRL, &wol_data); | ||
120 | |||
107 | 121 | ||
108 | AT_READ_REG(hw, REG_TWSI_CTRL, &twsi_ctrl_data); | 122 | AT_READ_REG(hw, REG_TWSI_CTRL, &twsi_ctrl_data); |
109 | twsi_ctrl_data |= TWSI_CTRL_SW_LDSTART; | 123 | twsi_ctrl_data |= TWSI_CTRL_SW_LDSTART; |
@@ -119,17 +133,15 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw) | |||
119 | } | 133 | } |
120 | /* Disable OTP_CLK */ | 134 | /* Disable OTP_CLK */ |
121 | if ((hw->nic_type == athr_l1c || hw->nic_type == athr_l2c)) { | 135 | if ((hw->nic_type == athr_l1c || hw->nic_type == athr_l2c)) { |
122 | if (otp_ctrl_data & OTP_CTRL_CLK_EN) { | 136 | otp_ctrl_data &= ~OTP_CTRL_CLK_EN; |
123 | otp_ctrl_data &= ~OTP_CTRL_CLK_EN; | 137 | AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data); |
124 | AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data); | 138 | msleep(1); |
125 | AT_WRITE_FLUSH(hw); | ||
126 | msleep(1); | ||
127 | } | ||
128 | } | 139 | } |
129 | if (raise_vol) { | 140 | if (raise_vol) { |
130 | if (hw->nic_type == athr_l2c_b || | 141 | if (hw->nic_type == athr_l2c_b || |
131 | hw->nic_type == athr_l2c_b2 || | 142 | hw->nic_type == athr_l2c_b2 || |
132 | hw->nic_type == athr_l1d) { | 143 | hw->nic_type == athr_l1d || |
144 | hw->nic_type == athr_l1d_2) { | ||
133 | atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x00); | 145 | atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x00); |
134 | if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data)) | 146 | if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data)) |
135 | goto out; | 147 | goto out; |
@@ -456,14 +468,22 @@ int atl1c_phy_reset(struct atl1c_hw *hw) | |||
456 | 468 | ||
457 | if (hw->nic_type == athr_l2c_b || | 469 | if (hw->nic_type == athr_l2c_b || |
458 | hw->nic_type == athr_l2c_b2 || | 470 | hw->nic_type == athr_l2c_b2 || |
459 | hw->nic_type == athr_l1d) { | 471 | hw->nic_type == athr_l1d || |
472 | hw->nic_type == athr_l1d_2) { | ||
460 | atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x3B); | 473 | atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x3B); |
461 | atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data); | 474 | atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data); |
462 | atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data & 0xFFF7); | 475 | atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data & 0xFFF7); |
463 | msleep(20); | 476 | msleep(20); |
464 | } | 477 | } |
465 | 478 | if (hw->nic_type == athr_l1d) { | |
466 | /*Enable PHY LinkChange Interrupt */ | 479 | atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29); |
480 | atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x929D); | ||
481 | } | ||
482 | if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c_b2 | ||
483 | || hw->nic_type == athr_l2c || hw->nic_type == athr_l2c) { | ||
484 | atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29); | ||
485 | atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB6DD); | ||
486 | } | ||
467 | err = atl1c_write_phy_reg(hw, MII_IER, mii_ier_data); | 487 | err = atl1c_write_phy_reg(hw, MII_IER, mii_ier_data); |
468 | if (err) { | 488 | if (err) { |
469 | if (netif_msg_hw(adapter)) | 489 | if (netif_msg_hw(adapter)) |
@@ -482,12 +502,10 @@ int atl1c_phy_init(struct atl1c_hw *hw) | |||
482 | struct pci_dev *pdev = adapter->pdev; | 502 | struct pci_dev *pdev = adapter->pdev; |
483 | int ret_val; | 503 | int ret_val; |
484 | u16 mii_bmcr_data = BMCR_RESET; | 504 | u16 mii_bmcr_data = BMCR_RESET; |
485 | u16 phy_id1, phy_id2; | ||
486 | 505 | ||
487 | if ((atl1c_read_phy_reg(hw, MII_PHYSID1, &phy_id1) != 0) || | 506 | if ((atl1c_read_phy_reg(hw, MII_PHYSID1, &hw->phy_id1) != 0) || |
488 | (atl1c_read_phy_reg(hw, MII_PHYSID2, &phy_id2) != 0)) { | 507 | (atl1c_read_phy_reg(hw, MII_PHYSID2, &hw->phy_id2) != 0)) { |
489 | if (netif_msg_link(adapter)) | 508 | dev_err(&pdev->dev, "Error get phy ID\n"); |
490 | dev_err(&pdev->dev, "Error get phy ID\n"); | ||
491 | return -1; | 509 | return -1; |
492 | } | 510 | } |
493 | switch (hw->media_type) { | 511 | switch (hw->media_type) { |
@@ -572,6 +590,65 @@ int atl1c_get_speed_and_duplex(struct atl1c_hw *hw, u16 *speed, u16 *duplex) | |||
572 | return 0; | 590 | return 0; |
573 | } | 591 | } |
574 | 592 | ||
593 | int atl1c_phy_power_saving(struct atl1c_hw *hw) | ||
594 | { | ||
595 | struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter; | ||
596 | struct pci_dev *pdev = adapter->pdev; | ||
597 | int ret = 0; | ||
598 | u16 autoneg_advertised = ADVERTISED_10baseT_Half; | ||
599 | u16 save_autoneg_advertised; | ||
600 | u16 phy_data; | ||
601 | u16 mii_lpa_data; | ||
602 | u16 speed = SPEED_0; | ||
603 | u16 duplex = FULL_DUPLEX; | ||
604 | int i; | ||
605 | |||
606 | atl1c_read_phy_reg(hw, MII_BMSR, &phy_data); | ||
607 | atl1c_read_phy_reg(hw, MII_BMSR, &phy_data); | ||
608 | if (phy_data & BMSR_LSTATUS) { | ||
609 | atl1c_read_phy_reg(hw, MII_LPA, &mii_lpa_data); | ||
610 | if (mii_lpa_data & LPA_10FULL) | ||
611 | autoneg_advertised = ADVERTISED_10baseT_Full; | ||
612 | else if (mii_lpa_data & LPA_10HALF) | ||
613 | autoneg_advertised = ADVERTISED_10baseT_Half; | ||
614 | else if (mii_lpa_data & LPA_100HALF) | ||
615 | autoneg_advertised = ADVERTISED_100baseT_Half; | ||
616 | else if (mii_lpa_data & LPA_100FULL) | ||
617 | autoneg_advertised = ADVERTISED_100baseT_Full; | ||
618 | |||
619 | save_autoneg_advertised = hw->autoneg_advertised; | ||
620 | hw->phy_configured = false; | ||
621 | hw->autoneg_advertised = autoneg_advertised; | ||
622 | if (atl1c_restart_autoneg(hw) != 0) { | ||
623 | dev_dbg(&pdev->dev, "phy autoneg failed\n"); | ||
624 | ret = -1; | ||
625 | } | ||
626 | hw->autoneg_advertised = save_autoneg_advertised; | ||
627 | |||
628 | if (mii_lpa_data) { | ||
629 | for (i = 0; i < AT_SUSPEND_LINK_TIMEOUT; i++) { | ||
630 | mdelay(100); | ||
631 | atl1c_read_phy_reg(hw, MII_BMSR, &phy_data); | ||
632 | atl1c_read_phy_reg(hw, MII_BMSR, &phy_data); | ||
633 | if (phy_data & BMSR_LSTATUS) { | ||
634 | if (atl1c_get_speed_and_duplex(hw, &speed, | ||
635 | &duplex) != 0) | ||
636 | dev_dbg(&pdev->dev, | ||
637 | "get speed and duplex failed\n"); | ||
638 | break; | ||
639 | } | ||
640 | } | ||
641 | } | ||
642 | } else { | ||
643 | speed = SPEED_10; | ||
644 | duplex = HALF_DUPLEX; | ||
645 | } | ||
646 | adapter->link_speed = speed; | ||
647 | adapter->link_duplex = duplex; | ||
648 | |||
649 | return ret; | ||
650 | } | ||
651 | |||
575 | int atl1c_restart_autoneg(struct atl1c_hw *hw) | 652 | int atl1c_restart_autoneg(struct atl1c_hw *hw) |
576 | { | 653 | { |
577 | int err = 0; | 654 | int err = 0; |