📄 at_hw.c
字号:
* data - data to write to the PHY
********************************************************************/
s32
at_write_phy_reg(
struct at_hw *hw,
u32 reg_addr,
u16 phy_data)
{
int i;
u32 val;
val = ((u32)(phy_data & MDIO_DATA_MASK)) << MDIO_DATA_SHIFT |
(reg_addr&MDIO_REG_ADDR_MASK) << MDIO_REG_ADDR_SHIFT |
MDIO_SUP_PREAMBLE |
MDIO_START |
MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT;
AT_WRITE_REG(hw, REG_MDIO_CTRL, val);
// DEBUGOUT1("phy write 0x%x <- 0x%x, value = 0x%x", i
// reg_addr,
// phy_data,
// val);
wmb();
for (i=0; i<MDIO_WAIT_TIMES; i++) {
usec_delay(2);
val = AT_READ_REG(hw, REG_MDIO_CTRL);
if (!(val&(MDIO_START|MDIO_BUSY))) {
break;
}
wmb();
}
if (!(val&(MDIO_START|MDIO_BUSY)))
return AT_SUCCESS;
return AT_ERR_PHY;
}
/********************************************************************
* Configures PHY autoneg and flow control advertisement settings
*
* hw - Struct containing variables accessed by shared code
********************************************************************/
s32
at_phy_setup_autoneg_adv(struct at_hw *hw)
{
s32 ret_val;
u16 mii_autoneg_adv_reg;
u16 mii_1000t_ctrl_reg;
DEBUGFUNC("at_phy_setup_autoneg_adv");
if (0 != hw->mii_autoneg_adv_reg)
return AT_SUCCESS;
/* Read the MII Auto-Neg Advertisement Register (Address 4/9). */
mii_autoneg_adv_reg = MII_AR_DEFAULT_CAP_MASK;
mii_1000t_ctrl_reg = MII_AT001_CR_1000T_DEFAULT_CAP_MASK;
/* Need to parse autoneg_advertised and set up
* the appropriate PHY registers. First we will parse for
* autoneg_advertised software override. Since we can advertise
* a plethora of combinations, we need to check each bit
* individually.
*/
/* First we clear all the 10/100 mb speed bits in the Auto-Neg
* Advertisement Register (Address 4) and the 1000 mb speed bits in
* the 1000Base-T Control Register (Address 9).
*/
mii_autoneg_adv_reg &= ~MII_AR_SPEED_MASK;
mii_1000t_ctrl_reg &= ~MII_AT001_CR_1000T_SPEED_MASK;
/* Need to parse MediaType and setup the
* appropriate PHY registers.
*/
switch (hw->MediaType)
{
case MEDIA_TYPE_AUTO_SENSOR:
mii_autoneg_adv_reg |= (MII_AR_10T_HD_CAPS|
MII_AR_10T_FD_CAPS|
MII_AR_100TX_HD_CAPS|
MII_AR_100TX_FD_CAPS);
if (hw->nic_type == athr_l1e) {
mii_1000t_ctrl_reg |= MII_AT001_CR_1000T_FD_CAPS;
}
hw->autoneg_advertised = ADVERTISE_10_HALF|
ADVERTISE_10_FULL |
ADVERTISE_100_HALF|
ADVERTISE_100_FULL;
if (hw->nic_type == athr_l1e) {
hw->autoneg_advertised |= ADVERTISE_1000_FULL;
}
break;
case MEDIA_TYPE_1000M_FULL:
if (hw->nic_type != athr_l1e)
break;
mii_1000t_ctrl_reg |= MII_AT001_CR_1000T_FD_CAPS;
hw->autoneg_advertised |= ADVERTISE_1000_FULL;
break;
case MEDIA_TYPE_100M_FULL:
mii_autoneg_adv_reg |= MII_AR_100TX_FD_CAPS;
hw->autoneg_advertised = ADVERTISE_100_FULL;
break;
case MEDIA_TYPE_100M_HALF:
mii_autoneg_adv_reg |= MII_AR_100TX_HD_CAPS;
hw->autoneg_advertised = ADVERTISE_100_HALF;
break;
case MEDIA_TYPE_10M_FULL:
mii_autoneg_adv_reg |= MII_AR_10T_FD_CAPS;
hw->autoneg_advertised = ADVERTISE_10_FULL;
break;
default:
mii_autoneg_adv_reg |= MII_AR_10T_HD_CAPS;
hw->autoneg_advertised = ADVERTISE_10_HALF;
break;
}
/* flow control fixed to enable all */
mii_autoneg_adv_reg |= (MII_AR_ASM_DIR | MII_AR_PAUSE);
hw->mii_autoneg_adv_reg = mii_autoneg_adv_reg;
hw->mii_1000t_ctrl_reg = mii_1000t_ctrl_reg;
ret_val = at_write_phy_reg(hw,
MII_ADVERTISE,
mii_autoneg_adv_reg);
if(ret_val)
return ret_val;
if (hw->nic_type == athr_l1e ||
hw->nic_type == athr_l2e_revA ) {
ret_val = at_write_phy_reg(hw,
MII_AT001_CR,
mii_1000t_ctrl_reg);
}
if (ret_val)
return ret_val;
return AT_SUCCESS;
}
s32
at_phy_init(struct at_hw* hw)
{
s32 ret_val;
u16 phy_val;
if (hw->phy_configured) {
if (hw->re_autoneg) {
hw->re_autoneg = FALSE;
return at_restart_autoneg(hw);
}
return 0;
}
// RESET GPHY Core
AT_WRITE_REGW(hw, REG_GPHY_CTRL, GPHY_CTRL_DEFAULT);
msec_delay(2);
AT_WRITE_REGW(hw, REG_GPHY_CTRL, GPHY_CTRL_DEFAULT|GPHY_CTRL_EXT_RESET);
msec_delay(2);
/* patches */
/* p1. eable hibernation mode */
ret_val = at_write_phy_reg(hw, MII_DBG_ADDR, 0xB);
if (ret_val) return ret_val;
ret_val = at_write_phy_reg(hw, MII_DBG_DATA, 0xBC00);
if (ret_val) return ret_val;
/* p2. set Class A/B for all modes */
ret_val = at_write_phy_reg(hw, MII_DBG_ADDR, 0);
if (ret_val) return ret_val;
/* remove Class AB, just use ClassA(0x02ef) */
//phy_val = hw->emi_ca ? 0x02ef : 0x02df;
phy_val = 0x02ef; /* ClassA */
ret_val = at_write_phy_reg(hw, MII_DBG_DATA, phy_val);
if (ret_val) return ret_val;
/* p3. 10B ??? */
ret_val = at_write_phy_reg(hw, MII_DBG_ADDR, 0x12);
if (ret_val) return ret_val;
ret_val = at_write_phy_reg(hw, MII_DBG_DATA, 0x4C04);
if (ret_val) return ret_val;
/* p4. 1000T power */
ret_val = at_write_phy_reg(hw, MII_DBG_ADDR, 0x4);
if (ret_val) return ret_val;
ret_val = at_write_phy_reg(hw, MII_DBG_DATA, 0x8BBB);
if (ret_val) return ret_val;
ret_val = at_write_phy_reg(hw, MII_DBG_ADDR, 0x5);
if (ret_val) return ret_val;
ret_val = at_write_phy_reg(hw, MII_DBG_DATA, 0x2C46);
if (ret_val) return ret_val;
msec_delay(1);
/*Enable PHY LinkChange Interrupt */
ret_val = at_write_phy_reg(hw, 18, 0xC00);
if (ret_val)
return ret_val;
/* setup AutoNeg parameters */
ret_val = at_phy_setup_autoneg_adv(hw);
if(ret_val) {
DEBUGOUT("Error Setting up Auto-Negotiation");
return ret_val;
}
/* SW.Reset & En-Auto-Neg to restart Auto-Neg*/
DEBUGOUT("Restarting Auto-Neg");
ret_val = at_phy_commit(hw);
if (ret_val) {
DEBUGOUT("Error Resetting the phy");
return ret_val;
}
hw->phy_configured = TRUE;
return ret_val;
}
/*******************************************************************
* Resets the PHY and make all config validate
*
* hw - Struct containing variables accessed by shared code
*
* Sets bit 15 and 12 of the MII Control regiser (for F001 bug)
*******************************************************************/
s32
at_phy_commit(struct at_hw *hw)
{
s32 ret_val;
u16 phy_data;
DEBUGFUNC("at_phy_commit");
phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG;
ret_val = at_write_phy_reg(hw, MII_BMCR, phy_data);
if (ret_val) { // bug fixed
u32 val;
int i;
/**************************************
* pcie serdes link may be down !
**************************************/
DEBUGOUT("Auto-Neg make pcie phy link down !");
for (i=0; i < 25; i++) {
msec_delay(1);
val = AT_READ_REG(hw, REG_MDIO_CTRL);
if (!(val&(MDIO_START|MDIO_BUSY))) {
break;
}
}
if (0 != (val&(MDIO_START|MDIO_BUSY))) {
AT_ERR("pcie linkdown at least for 25ms !\n");
return ret_val;
DEBUGOUT1("pcie linkup after %dms", i);
}
}
return AT_SUCCESS;
}
void
set_mac_addr(struct at_hw* hw)
{
u32 value;
// 00-0B-6A-F6-00-DC
// 0: 6AF600DC 1: 000B
// low dword
value = (((u32)hw->mac_addr[2]) << 24) |
(((u32)hw->mac_addr[3]) << 16) |
(((u32)hw->mac_addr[4]) << 8 ) |
(((u32)hw->mac_addr[5]) ) ;
AT_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 0, value);
// hight dword
value = (((u32)hw->mac_addr[0]) << 8 ) |
(((u32)hw->mac_addr[1]) ) ;
AT_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 1, value);
}
/*************************************** function about EEPROM **********************************/
/*
* check_eeprom_exist
* return 0 if eeprom exist
*/
int
check_eeprom_exist(struct at_hw* hw)
{
u32 value;
value = AT_READ_REG(hw, REG_SPI_FLASH_CTRL);
if (value & SPI_FLASH_CTRL_EN_VPD)
{
value &= ~SPI_FLASH_CTRL_EN_VPD;
AT_WRITE_REG(hw, REG_SPI_FLASH_CTRL, value);
}
value = AT_READ_REGW(hw, REG_PCIE_CAP_LIST);
return ((value & 0xFF00) == 0x6C00) ? 0 : 1;
}
/*
* get_permanent_address
* return 0 if get valid mac address,
*/
int
get_permanent_address(struct at_hw *hw)
{
#define AT_TWSI_EEPROM_TIMEOUT 10
u32 Addr[2];
u32 i;
u32 twsi_ctrl_data;
u8 EthAddr[NODE_ADDRESS_SIZE];
if (is_valid_ether_addr(hw->perm_mac_addr))
return 0;
// init
Addr[0] = Addr[1] = 0;
if (!check_eeprom_exist(hw)) { // eeprom exist
i = 0;
twsi_ctrl_data = AT_READ_REG(hw, REG_TWSI_CTRL);
twsi_ctrl_data |= TWSI_CTRL_SW_LDSTART;
AT_WRITE_REG(hw, REG_TWSI_CTRL, twsi_ctrl_data);
for (i = 0; i < AT_TWSI_EEPROM_TIMEOUT; i++) {
msec_delay(5);
twsi_ctrl_data = AT_READ_REG(hw, REG_TWSI_CTRL);
if ((twsi_ctrl_data & TWSI_CTRL_SW_LDSTART) == 0) {
break;
}
}
if (i >= AT_TWSI_EEPROM_TIMEOUT)
return -1;
}
Addr[0] = AT_READ_REG(hw,REG_MAC_STA_ADDR);
Addr[1] = AT_READ_REG(hw,REG_MAC_STA_ADDR+4);
*(u32*) &EthAddr[2] = LONGSWAP(Addr[0]);
*(u16*) &EthAddr[0] = SHORTSWAP(*(u16*)&Addr[1]);
if (is_valid_ether_addr(EthAddr)) {
memcpy(hw->perm_mac_addr, EthAddr, NODE_ADDRESS_SIZE);
return 0;
}
return 1;
#undef AT_TWSI_EEPROM_TIMEOUT
}
boolean_t
write_eeprom(struct at_hw* hw, u32 offset, u32 value)
{
return TRUE;
}
boolean_t
read_eeprom(struct at_hw* hw, u32 Offset, u32* pValue)
{
int i;
u32 Control;
if (Offset&3) return FALSE; //address do not align
AT_WRITE_REG(hw, REG_VPD_DATA, 0);
Control = (Offset&VPD_CAP_VPD_ADDR_MASK)<<VPD_CAP_VPD_ADDR_SHIFT;
AT_WRITE_REG(hw, REG_VPD_CAP, Control);
for (i=0; i < 10; i++)
{
msec_delay(2);
Control = AT_READ_REG(hw, REG_VPD_CAP);
if (Control & VPD_CAP_VPD_FLAG)
break;
}
if (Control & VPD_CAP_VPD_FLAG)
{
*pValue = AT_READ_REG(hw, REG_VPD_DATA);
return TRUE;
}
return FALSE; // timeout
}
void at_force_ps(struct at_hw* hw)
{
AT_WRITE_REGW(hw,
REG_GPHY_CTRL,
GPHY_CTRL_PW_WOL_DIS|GPHY_CTRL_EXT_RESET);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -