⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 at_hw.c

📁 Linux* Base Driver for the Attansic(R) L1 Gigabit Ethernet Adapter
💻 C
📖 第 1 页 / 共 2 页
字号:
    int32_t ret_val;
    int16_t mii_autoneg_adv_reg;
    int16_t mii_1000t_ctrl_reg;    

    DEBUGFUNC("at_phy_setup_autoneg_adv");
    
    /* Read the MII Auto-Neg Advertisement Register (Address 4). */
    mii_autoneg_adv_reg = MII_AR_DEFAULT_CAP_MASK;
    
    /* Read the MII 1000Base-T Control Register (Address 9). */ 
    mii_1000t_ctrl_reg = MII_AT001_CR_1000T_DEFAULT_CAP_MASK;
    
   /* 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 set up
     * 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);
        mii_1000t_ctrl_reg |= MII_AT001_CR_1000T_FD_CAPS;
        break;
        
    case MEDIA_TYPE_1000M_FULL:
        mii_1000t_ctrl_reg |= MII_AT001_CR_1000T_FD_CAPS;
        break;
    
    case MEDIA_TYPE_100M_FULL:
        mii_autoneg_adv_reg |= MII_AR_100TX_FD_CAPS;
        break;
        
    case MEDIA_TYPE_100M_HALF:
        mii_autoneg_adv_reg |= MII_AR_100TX_HD_CAPS;
        break;
        
    case MEDIA_TYPE_10M_FULL:
        mii_autoneg_adv_reg |= MII_AR_10T_FD_CAPS;
        break;
        
    default:
        mii_autoneg_adv_reg |= MII_AR_10T_HD_CAPS;
        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;
    
    ret_val = at_write_phy_reg(hw, MII_AT001_CR, mii_1000t_ctrl_reg);
    if(ret_val)
        return ret_val;
    
    return AT_SUCCESS;
}

/*******************************************************************
* 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)
*******************************************************************/
int32_t
at_phy_reset(struct at_hw *hw)
{
    int32_t ret_val;
    uint16_t phy_data;
    
//    DEBUGFUNC("at_phy_reset");

    if (hw->MediaType == MEDIA_TYPE_AUTO_SENSOR ||
    	hw->MediaType == MEDIA_TYPE_1000M_FULL) {
    	phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN;
    } else {
        switch (hw->MediaType)
    	{
    	case MEDIA_TYPE_100M_FULL:
    		phy_data = MII_CR_FULL_DUPLEX|MII_CR_SPEED_100|MII_CR_RESET;
    		break;
    	case MEDIA_TYPE_100M_HALF:
    		phy_data = MII_CR_SPEED_100|MII_CR_RESET;
    		break;
    	case MEDIA_TYPE_10M_FULL:
    		phy_data = MII_CR_FULL_DUPLEX|MII_CR_SPEED_10|MII_CR_RESET;
    		break;
    	default: // MEDIA_TYPE_10M_HALF:
    		phy_data = MII_CR_SPEED_10|MII_CR_RESET;
    		break;
    	}
    }
    
    ret_val = at_write_phy_reg(hw, MII_BMCR, phy_data);
    if (ret_val) { // bug fixed
        uint32_t 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)
{
    uint32_t value;
    // 00-0B-6A-F6-00-DC
    // 0:  6AF600DC   1: 000B
    //  low dword
    value = (((uint32_t)hw->mac_addr[2]) << 24) |
            (((uint32_t)hw->mac_addr[3]) << 16) |
            (((uint32_t)hw->mac_addr[4]) << 8 ) |
            (((uint32_t)hw->mac_addr[5])      ) ;
    AT_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 0, value);
    // hight dword
    value = (((uint32_t)hw->mac_addr[0]) << 8 ) |
            (((uint32_t)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)
{
    uint32_t 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;
}

inline
boolean_t
EthAddressValid(uint8_t* pAddr)
{
    // Invalid PermanentAddress ? 
    if (    (
            (pAddr[0]==0) &&
            (pAddr[1]==0) &&
            (pAddr[2]==0) &&
            (pAddr[3]==0) &&
            (pAddr[4]==0) &&
            (pAddr[5]==0)
            ) ||
            (pAddr[0] & 1) ) // Multicast address or Broadcast Address
    {
        return FALSE;
    }
    return TRUE;
}

/*
 * get_permanent_address
 * return 0 if get valid mac address, 
 */
int 
get_permanent_address(struct at_hw* hw)
{
    uint32_t Addr[2];
    uint32_t i, Control;
    uint16_t Register;
    uint8_t  EthAddr[NODE_ADDRESS_SIZE];
    boolean_t KeyValid;
    
    if(EthAddressValid(hw->perm_mac_addr))
        return 0;
    
    // init
    Addr[0] = Addr[1] = 0;    
    
    if (!check_eeprom_exist(hw)) { // eeprom exist
    Register = 0;
    KeyValid = FALSE;
    //
    // Read out all EEPROM content
    //
    i = 0;
    while (1) {
        if (read_eeprom(hw, i+0x100, &Control)) {
            if (KeyValid) {
            if (Register == REG_MAC_STA_ADDR)
                    Addr[0] = Control;
            else if (Register == (REG_MAC_STA_ADDR+4)) {
                Addr[1] = Control;
            }
            KeyValid = FALSE;
        } else if ((Control&0xff) == 0x5A) {
            KeyValid = TRUE;
            Register = (uint16_t) (Control >> 16);
        } else {
            break; // assume data end while encount an invalid KEYWORD
            }
        } else {
            break; // read error
        }
        i += 4;
    }
        
    *(uint32_t*) &EthAddr[2] = LONGSWAP(Addr[0]);
    *(uint16_t*) &EthAddr[0] = SHORTSWAP(*(uint16_t*)&Addr[1]); 
    
        if (EthAddressValid(EthAddr)) {
            memcpy(hw->perm_mac_addr, EthAddr, NODE_ADDRESS_SIZE);
            return 0;
        }
        return 1;
    }
    
    // see if SPI FLAHS exist ?
    Addr[0] = Addr[1] = 0 ;
    Register = 0;
    KeyValid = FALSE;
    i = 0;
    while (1) {
        if (spi_read(hw, i+0x1f000, &Control)) {
            if (KeyValid) {
                if (Register == REG_MAC_STA_ADDR)
                    Addr[0] = Control;
                else if (Register == (REG_MAC_STA_ADDR+4)) {
                    Addr[1] = Control;
                }
                KeyValid = FALSE;
            } else if ((Control&0xff) == 0x5A) {
                KeyValid = TRUE;
                Register = (uint16_t) (Control >> 16);
            } else {
                break; // data end
            }
        } else {
            break; // read error
        }
        i += 4;
    }
    
    *(uint32_t*) &EthAddr[2] = LONGSWAP(Addr[0]);
    *(uint16_t*) &EthAddr[0] = SHORTSWAP(*(uint16_t*)&Addr[1]); 
    if (EthAddressValid(EthAddr)) {
        memcpy(hw->perm_mac_addr, EthAddr, NODE_ADDRESS_SIZE);
        return 0;
    }
    return 1;
}

boolean_t
read_eeprom(struct at_hw* hw, uint32_t Offset, uint32_t* pValue)
{
    int i;
    uint32_t    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
}

spi_flash_dev flash_table[] = 
{
//  manu_name   WRSR    READ    PROGRAM WREN    WRDI    RDSR    RDID    SECTOR_ERASE CHIP_ERASE
    {"Atmel",   0x0,    0x03,   0x02,   0x06,   0x04,   0x05,   0x15,   0x52,   0x62 },
    {"SST",     0x01,   0x03,   0x02,   0x06,   0x04,   0x05,   0x90,   0x20,   0x60 },
    {"ST",      0x01,   0x03,   0x02,   0x06,   0x04,   0x05,   0xAB,   0xD8,   0xC7 },
};


#define CUSTOM_SPI_CS_SETUP        2
#define CUSTOM_SPI_CLK_HI          2
#define CUSTOM_SPI_CLK_LO          2
#define CUSTOM_SPI_CS_HOLD         2
#define CUSTOM_SPI_CS_HI           3



void 
init_flash_opcode(struct at_hw* hw)
{
    if (hw->flash_vendor >= sizeof(flash_table)/sizeof(flash_table[0])) {
        hw->flash_vendor = 0; // ATMEL
    }
    // Init OP table
    AT_WRITE_REGB(hw, REG_SPI_FLASH_OP_PROGRAM,     flash_table[hw->flash_vendor].cmdPROGRAM);
    AT_WRITE_REGB(hw, REG_SPI_FLASH_OP_SC_ERASE,    flash_table[hw->flash_vendor].cmdSECTOR_ERASE);
    AT_WRITE_REGB(hw, REG_SPI_FLASH_OP_CHIP_ERASE,  flash_table[hw->flash_vendor].cmdCHIP_ERASE);
    AT_WRITE_REGB(hw, REG_SPI_FLASH_OP_RDID,        flash_table[hw->flash_vendor].cmdRDID);
    AT_WRITE_REGB(hw, REG_SPI_FLASH_OP_WREN,        flash_table[hw->flash_vendor].cmdWREN);
    AT_WRITE_REGB(hw, REG_SPI_FLASH_OP_RDSR,        flash_table[hw->flash_vendor].cmdRDSR);
    AT_WRITE_REGB(hw, REG_SPI_FLASH_OP_WRSR,        flash_table[hw->flash_vendor].cmdWRSR);
    AT_WRITE_REGB(hw, REG_SPI_FLASH_OP_READ,        flash_table[hw->flash_vendor].cmdREAD);
}

boolean_t 
spi_read(struct at_hw* hw, uint32_t addr, uint32_t* buf)
{
    int i;
    uint32_t value;
    
    AT_WRITE_REG(hw, REG_SPI_DATA, 0);
    AT_WRITE_REG(hw, REG_SPI_ADDR, addr);
    
    value = 
        SPI_FLASH_CTRL_WAIT_READY|
        (CUSTOM_SPI_CS_SETUP&SPI_FLASH_CTRL_CS_SETUP_MASK)<<SPI_FLASH_CTRL_CS_SETUP_SHIFT |
        (CUSTOM_SPI_CLK_HI&SPI_FLASH_CTRL_CLK_HI_MASK)<<SPI_FLASH_CTRL_CLK_HI_SHIFT |
        (CUSTOM_SPI_CLK_LO&SPI_FLASH_CTRL_CLK_LO_MASK)<<SPI_FLASH_CTRL_CLK_LO_SHIFT |
        (CUSTOM_SPI_CS_HOLD&SPI_FLASH_CTRL_CS_HOLD_MASK)<<SPI_FLASH_CTRL_CS_HOLD_SHIFT |
        (CUSTOM_SPI_CS_HI&SPI_FLASH_CTRL_CS_HI_MASK)<<SPI_FLASH_CTRL_CS_HI_SHIFT |
        (1&SPI_FLASH_CTRL_INS_MASK)<<SPI_FLASH_CTRL_INS_SHIFT;
        
    AT_WRITE_REG(hw, REG_SPI_FLASH_CTRL, value);
    
    value |= SPI_FLASH_CTRL_START;
    
    AT_WRITE_REG(hw, REG_SPI_FLASH_CTRL, value);

    for (i = 0; i < 10; i++)
    {
        msec_delay(1); // 1ms
        value = AT_READ_REG(hw, REG_SPI_FLASH_CTRL);
        if (!(value & SPI_FLASH_CTRL_START))
            break;        
    }
    
    if (value & SPI_FLASH_CTRL_START)
        return FALSE;    
              
    *buf = AT_READ_REG(hw, REG_SPI_DATA); 
    
    return TRUE; 
}

//michael add 2005-11-17
int32_t
at_set_speed_and_duplex(
        struct at_hw *hw,
        uint16_t speed,
        uint16_t duplex)
{
    int32_t ret_val;
    uint16_t phy_data;

//    DEBUGFUNC("at_get_speed_and_duplex");
   
    if(speed==SPEED_1000)
    {
		hw->MediaType=MEDIA_TYPE_1000M_FULL;
		phy_data=MII_CR_SPEED_1000;
    }
   else if((speed==SPEED_100)&&(duplex==FULL_DUPLEX))
   {
   	      hw->MediaType=MEDIA_TYPE_100M_FULL;
	      phy_data=MII_CR_SPEED_100 | MII_CR_FULL_DUPLEX;
   }
   else if((speed==SPEED_100)&&(duplex==HALF_DUPLEX))
   {
   	     hw->MediaType=MEDIA_TYPE_100M_HALF;
	     phy_data=MII_CR_SPEED_100;
   }		 
   else if((speed==SPEED_10)&&(duplex==FULL_DUPLEX))
   {
   	    hw->MediaType=MEDIA_TYPE_10M_FULL;
	    phy_data=MII_CR_SPEED_10 | MII_CR_FULL_DUPLEX;
   }
   else if((speed==SPEED_10)&&(duplex==HALF_DUPLEX))
   {
   	    hw->MediaType=MEDIA_TYPE_10M_HALF;
	   phy_data=MII_CR_SPEED_10;
   }
   else
   {
   	printk(KERN_WARNING "speed=%d, duplex=%d  not supported\n",speed,duplex);
	return AT_ERR_CONFIG;
   }

   //add reset signal
    phy_data |= MII_CR_RESET;

    if (hw->MediaType == MEDIA_TYPE_AUTO_SENSOR ||
    	hw->MediaType == MEDIA_TYPE_1000M_FULL)
    	phy_data |= MII_CR_AUTO_NEG_EN;
    
    ret_val = at_write_phy_reg(hw, MII_BMCR, phy_data);
    if (ret_val) { // bug fixed
        uint32_t 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;

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -