atl1c: Add support for Atheros AR8152 and AR8152
authorLuis R. Rodriguez <lrodriguez@atheros.com>
Tue, 16 Feb 2010 23:16:45 +0000 (15:16 -0800)
committerDavid S. Miller <davem@davemloft.net>
Tue, 16 Feb 2010 23:16:45 +0000 (15:16 -0800)
AR8151 is a Gigabit Ethernet device. AR8152 devices are
Fast Ethernet devices, there are two revisions, a 1.0
and a 2.0 revision.

This has been tested against these devices:

Driver Model-name vendor:device Type
atl1c  AR8131 1969:1063 Gigabit Ethernet
atl1c AR8132 1969:1062 Fast Ethernet
atl1c AR8151(v1.0) 1969:1073 Gigabit Ethernet
atl1c AR8152(v1.1) 1969:2060 Fast Ethernet

This device has no hardware available yet so it goes untested,
but it should work:

atl1c AR8152(v2.0) 1969:2062 Fast Ethernet

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/atl1c/atl1c.h
drivers/net/atl1c/atl1c_ethtool.c
drivers/net/atl1c/atl1c_hw.c
drivers/net/atl1c/atl1c_hw.h
drivers/net/atl1c/atl1c_main.c

index efe5435bc3d3f9df920e3e20ea45985bac040a76..84ae905bf732c4ac0e80ec18fbf83825d0b945f3 100644 (file)
@@ -313,6 +313,9 @@ enum atl1c_rss_type {
 enum atl1c_nic_type {
        athr_l1c = 0,
        athr_l2c = 1,
+       athr_l2c_b,
+       athr_l2c_b2,
+       athr_l1d,
 };
 
 enum atl1c_trans_queue {
@@ -426,8 +429,12 @@ struct atl1c_hw {
 #define ATL1C_ASPM_L1_SUPPORT          0x0100
 #define ATL1C_ASPM_CTRL_MON            0x0200
 #define ATL1C_HIB_DISABLE              0x0400
-#define ATL1C_LINK_CAP_1000M           0x0800
-#define ATL1C_FPGA_VERSION             0x8000
+#define ATL1C_APS_MODE_ENABLE           0x0800
+#define ATL1C_LINK_EXT_SYNC             0x1000
+#define ATL1C_CLK_GATING_EN             0x2000
+#define ATL1C_FPGA_VERSION              0x8000
+       u16 link_cap_flags;
+#define ATL1C_LINK_CAP_1000M           0x0001
        u16 cmb_tpd;
        u16 cmb_rrd;
        u16 cmb_rx_timer; /* 2us resolution */
index 9b1e0eaebb5ccd41751538031f2f0e4b485baccf..61a0f2ff11e98437057711aebafea9797a22a93f 100644 (file)
@@ -37,7 +37,7 @@ static int atl1c_get_settings(struct net_device *netdev,
                           SUPPORTED_100baseT_Full |
                           SUPPORTED_Autoneg       |
                           SUPPORTED_TP);
-       if (hw->ctrl_flags & ATL1C_LINK_CAP_1000M)
+       if (hw->link_cap_flags & ATL1C_LINK_CAP_1000M)
                ecmd->supported |= SUPPORTED_1000baseT_Full;
 
        ecmd->advertising = ADVERTISED_TP;
index 3e69b940b8f79d62408640c6c75754b5a9dcbc1c..f1389d664a21b47634f39deebcad13383536b754 100644 (file)
@@ -70,17 +70,39 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
        u32 otp_ctrl_data;
        u32 twsi_ctrl_data;
        u8  eth_addr[ETH_ALEN];
+       u16 phy_data;
+       bool raise_vol = false;
 
        /* init */
        addr[0] = addr[1] = 0;
        AT_READ_REG(hw, REG_OTP_CTRL, &otp_ctrl_data);
        if (atl1c_check_eeprom_exist(hw)) {
-               /* Enable OTP CLK */
-               if (!(otp_ctrl_data & OTP_CTRL_CLK_EN)) {
-                       otp_ctrl_data |= OTP_CTRL_CLK_EN;
-                       AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
-                       AT_WRITE_FLUSH(hw);
-                       msleep(1);
+               if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c_b) {
+                       /* Enable OTP CLK */
+                       if (!(otp_ctrl_data & OTP_CTRL_CLK_EN)) {
+                               otp_ctrl_data |= OTP_CTRL_CLK_EN;
+                               AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
+                               AT_WRITE_FLUSH(hw);
+                               msleep(1);
+                       }
+               }
+
+               if (hw->nic_type == athr_l2c_b ||
+                   hw->nic_type == athr_l2c_b2 ||
+                   hw->nic_type == athr_l1d) {
+                       atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x00);
+                       if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data))
+                               goto out;
+                       phy_data &= 0xFF7F;
+                       atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data);
+
+                       atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x3B);
+                       if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data))
+                               goto out;
+                       phy_data |= 0x8;
+                       atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data);
+                       udelay(20);
+                       raise_vol = true;
                }
 
                AT_READ_REG(hw, REG_TWSI_CTRL, &twsi_ctrl_data);
@@ -96,11 +118,31 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
                        return -1;
        }
        /* Disable OTP_CLK */
-       if (otp_ctrl_data & OTP_CTRL_CLK_EN) {
-               otp_ctrl_data &= ~OTP_CTRL_CLK_EN;
-               AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
-               AT_WRITE_FLUSH(hw);
-               msleep(1);
+       if ((hw->nic_type == athr_l1c || hw->nic_type == athr_l2c)) {
+               if (otp_ctrl_data & OTP_CTRL_CLK_EN) {
+                       otp_ctrl_data &= ~OTP_CTRL_CLK_EN;
+                       AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
+                       AT_WRITE_FLUSH(hw);
+                       msleep(1);
+               }
+       }
+       if (raise_vol) {
+               if (hw->nic_type == athr_l2c_b ||
+                   hw->nic_type == athr_l2c_b2 ||
+                   hw->nic_type == athr_l1d) {
+                       atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x00);
+                       if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data))
+                               goto out;
+                       phy_data |= 0x80;
+                       atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data);
+
+                       atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x3B);
+                       if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data))
+                               goto out;
+                       phy_data &= 0xFFF7;
+                       atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data);
+                       udelay(20);
+               }
        }
 
        /* maybe MAC-address is from BIOS */
@@ -114,6 +156,7 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
                return 0;
        }
 
+out:
        return -1;
 }
 
@@ -307,7 +350,7 @@ static int atl1c_phy_setup_adv(struct atl1c_hw *hw)
                mii_adv_data |= ADVERTISE_10HALF  | ADVERTISE_10FULL |
                                ADVERTISE_100HALF | ADVERTISE_100FULL;
 
-       if (hw->ctrl_flags & ATL1C_LINK_CAP_1000M) {
+       if (hw->link_cap_flags & ATL1C_LINK_CAP_1000M) {
                if (hw->autoneg_advertised & ADVERTISED_1000baseT_Half)
                        mii_giga_ctrl_data |= ADVERTISE_1000HALF;
                if (hw->autoneg_advertised & ADVERTISED_1000baseT_Full)
@@ -389,6 +432,7 @@ int atl1c_phy_reset(struct atl1c_hw *hw)
 {
        struct atl1c_adapter *adapter = hw->adapter;
        struct pci_dev *pdev = adapter->pdev;
+       u16 phy_data;
        u32 phy_ctrl_data = GPHY_CTRL_DEFAULT;
        u32 mii_ier_data = IER_LINK_UP | IER_LINK_DOWN;
        int err;
@@ -404,6 +448,21 @@ int atl1c_phy_reset(struct atl1c_hw *hw)
        AT_WRITE_FLUSH(hw);
        msleep(10);
 
+       if (hw->nic_type == athr_l2c_b) {
+               atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x0A);
+               atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data);
+               atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data & 0xDFFF);
+       }
+
+       if (hw->nic_type == athr_l2c_b ||
+           hw->nic_type == athr_l2c_b2 ||
+           hw->nic_type == athr_l1d) {
+               atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x3B);
+               atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data);
+               atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data & 0xFFF7);
+               msleep(20);
+       }
+
        /*Enable PHY LinkChange Interrupt */
        err = atl1c_write_phy_reg(hw, MII_IER, mii_ier_data);
        if (err) {
index c2c738df5c639e86de1a4ec7899a9e88d9bb3a0b..1eeb3ed9f0cbd10139e1850f13742bce567e6a5c 100644 (file)
@@ -57,6 +57,7 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
 #define REG_LINK_CTRL                  0x68
 #define LINK_CTRL_L0S_EN               0x01
 #define LINK_CTRL_L1_EN                        0x02
+#define LINK_CTRL_EXT_SYNC             0x80
 
 #define REG_VPD_CAP                    0x6C
 #define VPD_CAP_ID_MASK                 0xff
@@ -156,6 +157,8 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
 #define PM_CTRL_PM_REQ_TIMER_SHIFT     20
 #define PM_CTRL_LCKDET_TIMER_MASK      0x3F
 #define PM_CTRL_LCKDET_TIMER_SHIFT     24
+#define PM_CTRL_EN_BUFS_RX_L0S         0x10000000
+#define PM_CTRL_SA_DLY_EN              0x20000000
 #define PM_CTRL_MAC_ASPM_CHK           0x40000000
 #define PM_CTRL_HOTRST                 0x80000000
 
@@ -314,6 +317,8 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
 #define MAC_CTRL_BC_EN                 0x4000000
 #define MAC_CTRL_DBG                   0x8000000
 #define MAC_CTRL_SINGLE_PAUSE_EN       0x10000000
+#define MAC_CTRL_HASH_ALG_CRC32                0x20000000
+#define MAC_CTRL_SPEED_MODE_SW         0x40000000
 
 /* MAC IPG/IFG Control Register  */
 #define REG_MAC_IPG_IFG                0x1484
index d98095df05bec8c316c3ae6dc43d42586d138e64..3d4c0a5a77eb55e2e5d9c2cece9b9a93d5549a97 100644 (file)
 
 #include "atl1c.h"
 
-#define ATL1C_DRV_VERSION "1.0.0.1-NAPI"
+#define ATL1C_DRV_VERSION "1.0.0.2-NAPI"
 char atl1c_driver_name[] = "atl1c";
 char atl1c_driver_version[] = ATL1C_DRV_VERSION;
 #define PCI_DEVICE_ID_ATTANSIC_L2C      0x1062
 #define PCI_DEVICE_ID_ATTANSIC_L1C      0x1063
+#define PCI_DEVICE_ID_ATHEROS_L2C_B    0x2060 /* AR8152 v1.1 Fast 10/100 */
+#define PCI_DEVICE_ID_ATHEROS_L2C_B2   0x2062 /* AR8152 v2.0 Fast 10/100 */
+#define PCI_DEVICE_ID_ATHEROS_L1D      0x1073 /* AR8151 v1.0 Gigabit 1000 */
+
+#define L2CB_V10                       0xc0
+#define L2CB_V11                       0xc1
+
 /*
  * atl1c_pci_tbl - PCI Device ID Table
  *
@@ -38,6 +45,9 @@ char atl1c_driver_version[] = ATL1C_DRV_VERSION;
 static DEFINE_PCI_DEVICE_TABLE(atl1c_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L1C)},
        {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L2C)},
+       {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L2C_B)},
+       {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L2C_B2)},
+       {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L1D)},
        /* required last entry */
        { 0 }
 };
@@ -593,11 +603,18 @@ static void atl1c_set_mac_type(struct atl1c_hw *hw)
        case PCI_DEVICE_ID_ATTANSIC_L2C:
                hw->nic_type = athr_l2c;
                break;
-
        case PCI_DEVICE_ID_ATTANSIC_L1C:
                hw->nic_type = athr_l1c;
                break;
-
+       case PCI_DEVICE_ID_ATHEROS_L2C_B:
+               hw->nic_type = athr_l2c_b;
+               break;
+       case PCI_DEVICE_ID_ATHEROS_L2C_B2:
+               hw->nic_type = athr_l2c_b2;
+               break;
+       case PCI_DEVICE_ID_ATHEROS_L1D:
+               hw->nic_type = athr_l1d;
+               break;
        default:
                break;
        }
@@ -620,10 +637,13 @@ static int atl1c_setup_mac_funcs(struct atl1c_hw *hw)
                hw->ctrl_flags |= ATL1C_ASPM_L0S_SUPPORT;
        if (link_ctrl_data & LINK_CTRL_L1_EN)
                hw->ctrl_flags |= ATL1C_ASPM_L1_SUPPORT;
+       if (link_ctrl_data & LINK_CTRL_EXT_SYNC)
+               hw->ctrl_flags |= ATL1C_LINK_EXT_SYNC;
 
-       if (hw->nic_type == athr_l1c) {
+       if (hw->nic_type == athr_l1c ||
+           hw->nic_type == athr_l1d) {
                hw->ctrl_flags |= ATL1C_ASPM_CTRL_MON;
-               hw->ctrl_flags |= ATL1C_LINK_CAP_1000M;
+               hw->link_cap_flags |= ATL1C_LINK_CAP_1000M;
        }
        return 0;
 }
@@ -1234,21 +1254,92 @@ static void atl1c_disable_l0s_l1(struct atl1c_hw *hw)
 static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup)
 {
        u32 pm_ctrl_data;
+       u32 link_ctrl_data;
 
        AT_READ_REG(hw, REG_PM_CTRL, &pm_ctrl_data);
-
+       AT_READ_REG(hw, REG_LINK_CTRL, &link_ctrl_data);
        pm_ctrl_data &= ~PM_CTRL_SERDES_PD_EX_L1;
+
        pm_ctrl_data &=  ~(PM_CTRL_L1_ENTRY_TIMER_MASK <<
                        PM_CTRL_L1_ENTRY_TIMER_SHIFT);
+       pm_ctrl_data &= ~(PM_CTRL_LCKDET_TIMER_MASK <<
+                         PM_CTRL_LCKDET_TIMER_SHIFT);
 
        pm_ctrl_data |= PM_CTRL_MAC_ASPM_CHK;
+       pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
+       pm_ctrl_data |= PM_CTRL_RBER_EN;
+       pm_ctrl_data |= PM_CTRL_SDES_EN;
+
+       if (hw->nic_type == athr_l2c_b ||
+           hw->nic_type == athr_l1d ||
+           hw->nic_type == athr_l2c_b2) {
+               link_ctrl_data &= ~LINK_CTRL_EXT_SYNC;
+               if (!(hw->ctrl_flags & ATL1C_APS_MODE_ENABLE)) {
+                       if (hw->nic_type == athr_l2c_b &&
+                           hw->revision_id == L2CB_V10)
+                               link_ctrl_data |= LINK_CTRL_EXT_SYNC;
+               }
+
+               AT_WRITE_REG(hw, REG_LINK_CTRL, link_ctrl_data);
+
+               pm_ctrl_data |= PM_CTRL_PCIE_RECV;
+               pm_ctrl_data |= AT_ASPM_L1_TIMER << PM_CTRL_PM_REQ_TIMER_SHIFT;
+               pm_ctrl_data &= ~PM_CTRL_EN_BUFS_RX_L0S;
+               pm_ctrl_data &= ~PM_CTRL_SA_DLY_EN;
+               pm_ctrl_data &= ~PM_CTRL_HOTRST;
+               pm_ctrl_data |= 1 << PM_CTRL_L1_ENTRY_TIMER_SHIFT;
+               pm_ctrl_data |= PM_CTRL_SERDES_PD_EX_L1;
+       }
 
        if (linkup) {
-               pm_ctrl_data |= PM_CTRL_SERDES_PLL_L1_EN;
-               pm_ctrl_data &= ~PM_CTRL_CLK_SWH_L1;
+               pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
+               pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
+               if (hw->ctrl_flags & ATL1C_ASPM_L1_SUPPORT)
+                       pm_ctrl_data |= PM_CTRL_ASPM_L1_EN;
+               if (hw->ctrl_flags & ATL1C_ASPM_L0S_SUPPORT)
+                       pm_ctrl_data |= PM_CTRL_ASPM_L0S_EN;
+
+               if (hw->nic_type == athr_l2c_b ||
+                   hw->nic_type == athr_l1d ||
+                   hw->nic_type == athr_l2c_b2) {
+                       if (hw->nic_type == athr_l2c_b)
+                               if (!(hw->ctrl_flags & ATL1C_APS_MODE_ENABLE))
+                                       pm_ctrl_data &= PM_CTRL_ASPM_L0S_EN;
+                       pm_ctrl_data &= ~PM_CTRL_SERDES_L1_EN;
+                       pm_ctrl_data &= ~PM_CTRL_SERDES_PLL_L1_EN;
+                       pm_ctrl_data &= ~PM_CTRL_SERDES_BUDS_RX_L1_EN;
+                       pm_ctrl_data |= PM_CTRL_CLK_SWH_L1;
+                       if (hw->adapter->link_speed == SPEED_100 ||
+                           hw->adapter->link_speed == SPEED_1000) {
+                               pm_ctrl_data &=
+                                       ~(PM_CTRL_L1_ENTRY_TIMER_MASK <<
+                                         PM_CTRL_L1_ENTRY_TIMER_SHIFT);
+                               if (hw->nic_type == athr_l1d)
+                                       pm_ctrl_data |= 0xF <<
+                                               PM_CTRL_L1_ENTRY_TIMER_SHIFT;
+                               else
+                                       pm_ctrl_data |= 7 <<
+                                               PM_CTRL_L1_ENTRY_TIMER_SHIFT;
+                       }
+               } else {
+                       pm_ctrl_data |= PM_CTRL_SERDES_L1_EN;
+                       pm_ctrl_data |= PM_CTRL_SERDES_PLL_L1_EN;
+                       pm_ctrl_data |= PM_CTRL_SERDES_BUDS_RX_L1_EN;
+                       pm_ctrl_data &= ~PM_CTRL_CLK_SWH_L1;
+                       pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
+                       pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
+               }
+               atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29);
+               if (hw->adapter->link_speed == SPEED_10)
+                       if (hw->nic_type == athr_l1d)
+                               atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0xB69D);
+                       else
+                               atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB6DD);
+               else if (hw->adapter->link_speed == SPEED_100)
+                       atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB2DD);
+               else
+                       atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x96DD);
 
-               pm_ctrl_data |= PM_CTRL_SERDES_BUDS_RX_L1_EN;
-               pm_ctrl_data |= PM_CTRL_SERDES_L1_EN;
        } else {
                pm_ctrl_data &= ~PM_CTRL_SERDES_BUDS_RX_L1_EN;
                pm_ctrl_data &= ~PM_CTRL_SERDES_L1_EN;
@@ -1302,6 +1393,10 @@ static void atl1c_setup_mac_ctrl(struct atl1c_adapter *adapter)
                mac_ctrl_data |= MAC_CTRL_MC_ALL_EN;
 
        mac_ctrl_data |= MAC_CTRL_SINGLE_PAUSE_EN;
+       if (hw->nic_type == athr_l1d || hw->nic_type == athr_l2c_b2) {
+               mac_ctrl_data |= MAC_CTRL_SPEED_MODE_SW;
+               mac_ctrl_data |= MAC_CTRL_HASH_ALG_CRC32;
+       }
        AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data);
 }