📄 at_hw.c
字号:
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 + -