Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 496c185c authored by Luis R. Rodriguez's avatar Luis R. Rodriguez Committed by David S. Miller
Browse files

atl1c: Add support for Atheros AR8152 and AR8152



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: default avatarLuis R. Rodriguez <lrodriguez@atheros.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d5aa407f
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -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_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 */
+1 −1
Original line number Diff line number Diff line
@@ -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;
+71 −12
Original line number Diff line number Diff line
@@ -70,11 +70,14 @@ 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)) {
		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;
@@ -82,6 +85,25 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
				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);
		twsi_ctrl_data |= TWSI_CTRL_SW_LDSTART;
@@ -96,12 +118,32 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
			return -1;
	}
	/* Disable OTP_CLK */
	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 */
	AT_READ_REG(hw, REG_MAC_STA_ADDR, &addr[0]);
@@ -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) {
+5 −0
Original line number Diff line number Diff line
@@ -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
+105 −10
Original line number Diff line number Diff line
@@ -21,11 +21,18 @@

#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_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);
}