1040 lines
28 KiB
C
1040 lines
28 KiB
C
#include <config.h>
|
|
#include <common.h>
|
|
#include <malloc.h>
|
|
#include <net.h>
|
|
#include <command.h>
|
|
#include <asm/io.h>
|
|
#include <asm/addrspace.h>
|
|
#include <asm/types.h>
|
|
|
|
#ifdef CONFIG_ATH_NAND_BR
|
|
#include <nand.h>
|
|
#endif
|
|
|
|
#include <atheros.h>
|
|
#include "qca-eth-955x.h"
|
|
#include "qca-eth-955x_phy.h"
|
|
#define SGMII_LINK_WAR_MAX_TRY 10
|
|
|
|
#if defined(CONFIG_CMD_MII)
|
|
#include <miiphy.h>
|
|
#endif
|
|
#define ath_gmac_unit2mac(_unit) ath_gmac_macs[(_unit)]
|
|
#if defined(CFG_ATH_SWAP_ETHACT)
|
|
#define ath_gmac_name2mac(name) is_drqfn() ? ath_gmac_unit2mac(1):strcmp(name,"eth0") ? ath_gmac_unit2mac(0) : ath_gmac_unit2mac(1)
|
|
#else
|
|
#define ath_gmac_name2mac(name) is_drqfn() ? ath_gmac_unit2mac(1):strcmp(name,"eth0") ? ath_gmac_unit2mac(1) : ath_gmac_unit2mac(0)
|
|
#endif
|
|
|
|
uint16_t ath_gmac_miiphy_read(char *devname, uint32_t phaddr, uint8_t reg);
|
|
void ath_gmac_miiphy_write(char *devname, uint32_t phaddr, uint8_t reg, uint16_t data);
|
|
extern void ath_sys_frequency(uint32_t *, uint32_t *, uint32_t *);
|
|
|
|
#ifndef CFG_ATH_GMAC_NMACS
|
|
#define CFG_ATH_GMAC_NMACS 1
|
|
#endif /* CFG_ATH_GMAC_NMACS */
|
|
|
|
//#define ATH_GMAC_DEBUG
|
|
|
|
ath_gmac_mac_t *ath_gmac_macs[CFG_ATH_GMAC_NMACS];
|
|
|
|
|
|
#ifdef CONFIG_VIR_PHY
|
|
extern int athr_vir_phy_setup(int unit);
|
|
extern int athr_vir_phy_is_up(int unit);
|
|
extern int athr_vir_phy_is_fdx(int unit);
|
|
extern int athr_vir_phy_speed(int unit);
|
|
extern void athr_vir_reg_init(void);
|
|
#endif
|
|
|
|
#ifdef CONFIG_ATHRS17_PHY
|
|
extern void athrs17_reg_init(void);
|
|
extern void athrs17_reg_init_wan(void);
|
|
#endif
|
|
|
|
|
|
#ifdef CONFIG_ATHR_8033_PHY
|
|
extern int athrs_ar8033_reg_init(void *arg);
|
|
extern int athrs_ar8033_phy_setup(void *arg);
|
|
extern int athrs_ar8033_phy_is_fdx(int ethUnit);
|
|
extern int athrs_ar8033_phy_is_link_alive(int phyUnit);
|
|
extern int athrs_ar8033_phy_is_up(int ethUnit);
|
|
extern int athrs_ar8033_phy_speed(int ethUnit,int phyUnit);
|
|
#endif
|
|
|
|
#ifdef CONFIG_ATH_NAND_BR
|
|
|
|
#define ATH_ETH_MAC_READ_SIZE 4096
|
|
extern unsigned long long
|
|
ath_nand_get_cal_offset(const char *ba);
|
|
#endif
|
|
|
|
static int
|
|
ath_gmac_send(struct eth_device *dev, volatile void *packet, int length)
|
|
{
|
|
int i;
|
|
|
|
ath_gmac_mac_t *mac = (ath_gmac_mac_t *)dev->priv;
|
|
|
|
ath_gmac_desc_t *f = mac->fifo_tx[mac->next_tx];
|
|
|
|
f->pkt_size = length;
|
|
f->res1 = 0;
|
|
f->pkt_start_addr = virt_to_phys(packet);
|
|
|
|
ath_gmac_tx_give_to_dma(f);
|
|
flush_cache((u32) packet, length);
|
|
ath_gmac_reg_wr(mac, ATH_DMA_TX_DESC, virt_to_phys(f));
|
|
ath_gmac_reg_wr(mac, ATH_DMA_TX_CTRL, ATH_TXE);
|
|
|
|
for (i = 0; i < MAX_WAIT; i++) {
|
|
udelay(10);
|
|
if (!ath_gmac_tx_owned_by_dma(f))
|
|
break;
|
|
}
|
|
#if 0
|
|
if (i == MAX_WAIT)
|
|
printf("Tx Timed out\n");
|
|
#endif
|
|
f->pkt_start_addr = 0;
|
|
f->pkt_size = 0;
|
|
|
|
if (++mac->next_tx >= NO_OF_TX_FIFOS)
|
|
mac->next_tx = 0;
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int ath_gmac_recv(struct eth_device *dev)
|
|
{
|
|
int length;
|
|
ath_gmac_desc_t *f;
|
|
ath_gmac_mac_t *mac;
|
|
volatile int dmaed_pkt=0;
|
|
int count = 0;
|
|
|
|
mac = (ath_gmac_mac_t *)dev->priv;
|
|
|
|
for (;;) {
|
|
f = mac->fifo_rx[mac->next_rx];
|
|
if (ath_gmac_rx_owned_by_dma(f)) {
|
|
/* check if the current Descriptor is_empty is 1,But the DMAed count is not-zero
|
|
then move to desciprot where the packet is available */
|
|
dmaed_pkt = (ath_gmac_reg_rd(mac, 0x194) >> 16);
|
|
if (!dmaed_pkt) {
|
|
break ;
|
|
} else {
|
|
if (f->is_empty == 1) {
|
|
while ( count < NO_OF_RX_FIFOS ) {
|
|
if (++mac->next_rx >= NO_OF_RX_FIFOS) {
|
|
mac->next_rx = 0;
|
|
}
|
|
f = mac->fifo_rx[mac->next_rx];
|
|
/*
|
|
* Break on valid data in the desc by checking
|
|
* empty bit.
|
|
*/
|
|
if (!f->is_empty){
|
|
count = 0;
|
|
break;
|
|
}
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
length = f->pkt_size;
|
|
|
|
NetReceive(NetRxPackets[mac->next_rx] , length - 4);
|
|
flush_cache((u32) NetRxPackets[mac->next_rx] , PKTSIZE_ALIGN);
|
|
|
|
ath_gmac_reg_wr(mac,0x194,1);
|
|
ath_gmac_rx_give_to_dma(f);
|
|
|
|
if (++mac->next_rx >= NO_OF_RX_FIFOS)
|
|
mac->next_rx = 0;
|
|
}
|
|
|
|
if (!(ath_gmac_reg_rd(mac, ATH_DMA_RX_CTRL))) {
|
|
ath_gmac_reg_wr(mac, ATH_DMA_RX_DESC, virt_to_phys(f));
|
|
ath_gmac_reg_wr(mac, ATH_DMA_RX_CTRL, 1);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
void ath_gmac_mii_setup(ath_gmac_mac_t *mac)
|
|
{
|
|
u32 mgmt_cfg_val;
|
|
|
|
ath_reg_wr(SWITCH_CLOCK_SPARE_ADDRESS, 0x520);
|
|
|
|
if ((is_s17() && mac->mac_unit == 0) || is_drqfn()) {
|
|
#ifdef ATH_GMAC_DEBUG
|
|
printf("Scorpion ----> S17 PHY *\n");
|
|
#endif
|
|
mgmt_cfg_val = 7;
|
|
#ifndef ATH_RGMII_CAL
|
|
ath_reg_wr(ATH_ETH_CFG, ETH_CFG_ETH_RXDV_DELAY_SET(3) |
|
|
ETH_CFG_ETH_RXD_DELAY_SET(3)|
|
|
ETH_CFG_RGMII_GE0_SET(1));
|
|
|
|
ath_reg_wr(ETH_XMII_ADDRESS, ETH_XMII_TX_INVERT_SET(1) |
|
|
ETH_XMII_RX_DELAY_SET(2) |
|
|
ETH_XMII_TX_DELAY_SET(1) |
|
|
ETH_XMII_GIGE_SET(1));
|
|
#else
|
|
rgmii_cal_alg()
|
|
#endif
|
|
udelay(1000);
|
|
ath_gmac_reg_wr(mac, ATH_MAC_MII_MGMT_CFG, mgmt_cfg_val | (1 << 31));
|
|
ath_gmac_reg_wr(mac, ATH_MAC_MII_MGMT_CFG, mgmt_cfg_val);
|
|
return;
|
|
}
|
|
#ifdef CONFIG_ATHR_8033_PHY
|
|
if (is_ar8033 () && mac->mac_unit == 1) {
|
|
#ifdef ATH_GMAC_DEBUG
|
|
printf("Scorpion ---->8033 PHY*\n");
|
|
#endif
|
|
mgmt_cfg_val = 7;
|
|
ath_gmac_reg_wr(mac, ATH_MAC_MII_MGMT_CFG, mgmt_cfg_val | (1 << 31));
|
|
ath_gmac_reg_wr(mac, ATH_MAC_MII_MGMT_CFG, mgmt_cfg_val);
|
|
return;
|
|
|
|
|
|
}
|
|
#endif
|
|
#ifdef CONFIG_VIR_PHY
|
|
if (is_vir_phy()) {
|
|
#ifdef ATH_GMAC_DEBUG
|
|
printf("Scorpion ---->VIR PHY*\n");
|
|
#endif
|
|
ath_reg_wr(ATH_ETH_CFG, ETH_CFG_ETH_RXDV_DELAY_SET(3) |
|
|
ETH_CFG_ETH_RXD_DELAY_SET(3)|
|
|
ETH_CFG_RGMII_GE0_SET(1));
|
|
ath_reg_wr(ETH_XMII_ADDRESS, ETH_XMII_TX_INVERT_SET(1) |
|
|
ETH_XMII_RX_DELAY_SET(2) |
|
|
ETH_XMII_TX_DELAY_SET(1) |
|
|
ETH_XMII_GIGE_SET(1));
|
|
udelay(1000);
|
|
ath_gmac_reg_wr(mac, ATH_MAC_MII_MGMT_CFG, mgmt_cfg_val | (1 << 31));
|
|
ath_gmac_reg_wr(mac, ATH_MAC_MII_MGMT_CFG, mgmt_cfg_val);
|
|
|
|
return;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void
|
|
athrs_sgmii_res_cal(void)
|
|
{
|
|
unsigned int read_data, read_data_otp, otp_value, otp_per_val, rbias_per;
|
|
unsigned int read_data_spi;
|
|
unsigned int *address_spi = (unsigned int *)0xbffffffc;
|
|
unsigned int rbias_pos_or_neg, res_cal_val;
|
|
unsigned int sgmii_pos, sgmii_res_cal_value;
|
|
unsigned int reversed_sgmii_value, use_value;
|
|
|
|
ath_reg_wr(OTP_INTF2_ADDRESS, 0x7d);
|
|
ath_reg_wr(OTP_LDO_CONTROL_ADDRESS, 0x0);
|
|
|
|
while (ath_reg_rd(OTP_LDO_STATUS_ADDRESS) & OTP_LDO_STATUS_POWER_ON_MASK);
|
|
|
|
read_data = ath_reg_rd(OTP_MEM_0_ADDRESS + 4);
|
|
|
|
while (!(ath_reg_rd(OTP_STATUS0_ADDRESS) & OTP_STATUS0_EFUSE_READ_DATA_VALID_MASK));
|
|
|
|
read_data_otp = ath_reg_rd(OTP_STATUS1_ADDRESS);
|
|
|
|
if (read_data_otp & 0x1fff) {
|
|
read_data = read_data_otp;
|
|
} else {
|
|
read_data_spi = *(address_spi);
|
|
if ((read_data_spi & 0xffff0000) == 0x5ca10000) {
|
|
read_data = read_data_spi;
|
|
} else {
|
|
read_data = read_data_otp;
|
|
}
|
|
}
|
|
|
|
if (read_data & 0x00001000) {
|
|
otp_value = (read_data & 0xfc0) >> 6;
|
|
} else {
|
|
otp_value = read_data & 0x3f;
|
|
}
|
|
|
|
if (otp_value > 31) {
|
|
otp_per_val = 63 - otp_value;
|
|
rbias_pos_or_neg = 1;
|
|
} else {
|
|
otp_per_val = otp_value;
|
|
rbias_pos_or_neg = 0;
|
|
}
|
|
|
|
rbias_per = otp_per_val * 15;
|
|
|
|
if (rbias_pos_or_neg == 1) {
|
|
res_cal_val = (rbias_per + 34) / 21;
|
|
sgmii_pos = 1;
|
|
} else {
|
|
if (rbias_per > 34) {
|
|
res_cal_val = (rbias_per - 34) / 21;
|
|
sgmii_pos = 0;
|
|
} else {
|
|
res_cal_val = (34 - rbias_per) / 21;
|
|
sgmii_pos = 1;
|
|
}
|
|
}
|
|
|
|
if (sgmii_pos == 1) {
|
|
sgmii_res_cal_value = 8 + res_cal_val;
|
|
} else {
|
|
sgmii_res_cal_value = 8 - res_cal_val;
|
|
}
|
|
|
|
reversed_sgmii_value = 0;
|
|
use_value = 0x8;
|
|
reversed_sgmii_value = reversed_sgmii_value | ((sgmii_res_cal_value & use_value) >> 3);
|
|
use_value = 0x4;
|
|
reversed_sgmii_value = reversed_sgmii_value | ((sgmii_res_cal_value & use_value) >> 1);
|
|
use_value = 0x2;
|
|
reversed_sgmii_value = reversed_sgmii_value | ((sgmii_res_cal_value & use_value) << 1);
|
|
use_value = 0x1;
|
|
reversed_sgmii_value = reversed_sgmii_value | ((sgmii_res_cal_value & use_value) << 3);
|
|
|
|
reversed_sgmii_value &= 0xf;
|
|
#ifdef ATH_GMAC_DEBUG
|
|
printf("%s: cal value = 0x%x\n", __func__, reversed_sgmii_value);
|
|
#endif
|
|
// To Check the locking of the SGMII PLL
|
|
|
|
read_data = (ath_reg_rd(SGMII_SERDES_ADDRESS) &
|
|
~SGMII_SERDES_RES_CALIBRATION_MASK) |
|
|
SGMII_SERDES_RES_CALIBRATION_SET(reversed_sgmii_value);
|
|
|
|
ath_reg_wr(SGMII_SERDES_ADDRESS, read_data);
|
|
|
|
|
|
ath_reg_wr(ETH_SGMII_SERDES_ADDRESS,
|
|
ETH_SGMII_SERDES_EN_LOCK_DETECT_MASK |
|
|
ETH_SGMII_SERDES_PLL_REFCLK_SEL_MASK |
|
|
ETH_SGMII_SERDES_EN_PLL_MASK);
|
|
|
|
ath_reg_rmw_set(SGMII_SERDES_ADDRESS,
|
|
SGMII_SERDES_CDR_BW_SET(3) |
|
|
SGMII_SERDES_TX_DR_CTRL_SET(1) |
|
|
SGMII_SERDES_PLL_BW_SET(1) |
|
|
SGMII_SERDES_EN_SIGNAL_DETECT_SET(1) |
|
|
SGMII_SERDES_FIBER_SDO_SET(1) |
|
|
SGMII_SERDES_VCO_REG_SET(3));
|
|
|
|
ath_reg_rmw_clear(RST_RESET_ADDRESS, RST_RESET_ETH_SGMII_ARESET_MASK);
|
|
udelay(25);
|
|
ath_reg_rmw_clear(RST_RESET_ADDRESS, RST_RESET_ETH_SGMII_RESET_MASK);
|
|
|
|
while (!(ath_reg_rd(SGMII_SERDES_ADDRESS) & SGMII_SERDES_LOCK_DETECT_STATUS_MASK));
|
|
}
|
|
|
|
|
|
static void athr_gmac_sgmii_setup()
|
|
{
|
|
int status = 0, count = 0;
|
|
|
|
#ifdef ATH_SGMII_FORCED_MODE
|
|
ath_reg_wr(MR_AN_CONTROL_ADDRESS, MR_AN_CONTROL_SPEED_SEL1_SET(1) |
|
|
MR_AN_CONTROL_PHY_RESET_SET(1) |
|
|
MR_AN_CONTROL_DUPLEX_MODE_SET(1));
|
|
udelay(10);
|
|
|
|
ath_reg_wr(SGMII_CONFIG_ADDRESS, SGMII_CONFIG_MODE_CTRL_SET(2) |
|
|
SGMII_CONFIG_FORCE_SPEED_SET(1) |
|
|
SGMII_CONFIG_SPEED_SET(2));
|
|
#ifdef ATH_GMAC_DEBUG
|
|
printf ("SGMII in forced mode\n");
|
|
#endif
|
|
#else
|
|
|
|
ath_reg_wr(SGMII_CONFIG_ADDRESS, SGMII_CONFIG_MODE_CTRL_SET(2));
|
|
|
|
ath_reg_wr(MR_AN_CONTROL_ADDRESS, MR_AN_CONTROL_AN_ENABLE_SET(1)
|
|
|MR_AN_CONTROL_PHY_RESET_SET(1));
|
|
|
|
ath_reg_wr(MR_AN_CONTROL_ADDRESS, MR_AN_CONTROL_AN_ENABLE_SET(1));
|
|
#endif
|
|
/*
|
|
* SGMII reset sequence suggested by systems team.
|
|
*/
|
|
|
|
ath_reg_wr(SGMII_RESET_ADDRESS, SGMII_RESET_RX_CLK_N_RESET);
|
|
|
|
ath_reg_wr(SGMII_RESET_ADDRESS, SGMII_RESET_HW_RX_125M_N_SET(1));
|
|
|
|
ath_reg_wr(SGMII_RESET_ADDRESS, SGMII_RESET_HW_RX_125M_N_SET(1)
|
|
|SGMII_RESET_RX_125M_N_SET(1));
|
|
|
|
ath_reg_wr(SGMII_RESET_ADDRESS, SGMII_RESET_HW_RX_125M_N_SET(1)
|
|
|SGMII_RESET_TX_125M_N_SET(1)
|
|
|SGMII_RESET_RX_125M_N_SET(1));
|
|
|
|
ath_reg_wr(SGMII_RESET_ADDRESS, SGMII_RESET_HW_RX_125M_N_SET(1)
|
|
|SGMII_RESET_TX_125M_N_SET(1)
|
|
|SGMII_RESET_RX_125M_N_SET(1)
|
|
|SGMII_RESET_RX_CLK_N_SET(1));
|
|
|
|
ath_reg_wr(SGMII_RESET_ADDRESS, SGMII_RESET_HW_RX_125M_N_SET(1)
|
|
|SGMII_RESET_TX_125M_N_SET(1)
|
|
|SGMII_RESET_RX_125M_N_SET(1)
|
|
|SGMII_RESET_RX_CLK_N_SET(1)
|
|
|SGMII_RESET_TX_CLK_N_SET(1));
|
|
|
|
ath_reg_rmw_clear(MR_AN_CONTROL_ADDRESS, MR_AN_CONTROL_PHY_RESET_SET(1));
|
|
/*
|
|
* WAR::Across resets SGMII link status goes to weird
|
|
* state.
|
|
* if 0xb8070058 (SGMII_DEBUG register) reads other then 0x1f or 0x10
|
|
* for sure we are in bad state.
|
|
* Issue a PHY reset in MR_AN_CONTROL_ADDRESS to keep going.
|
|
*/
|
|
status = (ath_reg_rd(SGMII_DEBUG_ADDRESS) & 0xff);
|
|
while (!(status == 0xf || status == 0x10)) {
|
|
|
|
ath_reg_rmw_set(MR_AN_CONTROL_ADDRESS, MR_AN_CONTROL_PHY_RESET_SET(1));
|
|
udelay(100);
|
|
ath_reg_rmw_clear(MR_AN_CONTROL_ADDRESS, MR_AN_CONTROL_PHY_RESET_SET(1));
|
|
if (count++ == SGMII_LINK_WAR_MAX_TRY) {
|
|
/* hide this message because it always be shown on NBG6716 but it will not cause any error */
|
|
#if !defined(CONFIG_BOARD_NBG6716) && !defined(CONFIG_BOARD_NBG6616)
|
|
printf ("Max resets limit reached exiting...\n");
|
|
#endif
|
|
break;
|
|
}
|
|
status = (ath_reg_rd(SGMII_DEBUG_ADDRESS) & 0xff);
|
|
}
|
|
#ifdef ATH_GMAC_DEBUG
|
|
printf("%s SGMII done\n",__func__);
|
|
#endif
|
|
}
|
|
|
|
static void ath_gmac_hw_start(ath_gmac_mac_t *mac)
|
|
{
|
|
|
|
|
|
#ifndef ATH_RGMII_CAL /* Moved after mii_setup since these registers are touched in RGMII cal code */
|
|
if(mac->mac_unit)
|
|
{
|
|
ath_gmac_reg_rmw_set(mac, ATH_MAC_CFG2, (ATH_MAC_CFG2_PAD_CRC_EN |
|
|
ATH_MAC_CFG2_LEN_CHECK | ATH_MAC_CFG2_IF_1000));
|
|
} else {
|
|
|
|
|
|
ath_gmac_reg_rmw_set(mac, ATH_MAC_CFG2, (ATH_MAC_CFG2_PAD_CRC_EN |
|
|
ATH_MAC_CFG2_LEN_CHECK | ATH_MAC_CFG2_IF_10_100));
|
|
}
|
|
ath_gmac_reg_wr(mac, ATH_MAC_FIFO_CFG_0, 0x1f00);
|
|
#endif
|
|
|
|
|
|
#ifdef ATH_RGMII_CAL
|
|
if(mac->mac_unit)
|
|
{
|
|
ath_gmac_reg_rmw_set(mac, ATH_MAC_CFG2, (ATH_MAC_CFG2_PAD_CRC_EN |
|
|
ATH_MAC_CFG2_LEN_CHECK | ATH_MAC_CFG2_IF_1000));
|
|
} else {
|
|
|
|
|
|
ath_gmac_reg_rmw_set(mac, ATH_MAC_CFG2, (ATH_MAC_CFG2_PAD_CRC_EN |
|
|
ATH_MAC_CFG2_LEN_CHECK | ATH_MAC_CFG2_IF_10_100));
|
|
}
|
|
ath_gmac_reg_wr(mac, ATH_MAC_FIFO_CFG_0, 0x1f00);
|
|
#endif
|
|
|
|
ath_gmac_reg_wr(mac, ATH_MAC_FIFO_CFG_1, 0x10ffff);
|
|
ath_gmac_reg_wr(mac, ATH_MAC_FIFO_CFG_2, 0xAAA0555);
|
|
|
|
ath_gmac_reg_rmw_set(mac, ATH_MAC_FIFO_CFG_4, 0x3ffff);
|
|
/*
|
|
* Setting Drop CRC Errors, Pause Frames,Length Error frames
|
|
* and Multi/Broad cast frames.
|
|
*/
|
|
#ifdef CONFIG_ZYXEL_ZLOADER
|
|
/*
|
|
* The Default setting of driver will ignore multicast patcket,
|
|
* so need to change setting for zloader to using multiboot functionality.
|
|
*/
|
|
ath_gmac_reg_wr(mac, ATH_MAC_FIFO_CFG_5, 0x7edcf);
|
|
#else
|
|
ath_gmac_reg_wr(mac, ATH_MAC_FIFO_CFG_5, 0x7eccf);
|
|
#endif
|
|
ath_gmac_reg_wr(mac, ATH_MAC_FIFO_CFG_3, 0x1f00140);
|
|
#ifdef ATH_GMAC_DEBUG
|
|
printf(": cfg1 %#x cfg2 %#x\n", ath_gmac_reg_rd(mac, ATH_MAC_CFG1),
|
|
ath_gmac_reg_rd(mac, ATH_MAC_CFG2));
|
|
#endif
|
|
}
|
|
|
|
static int ath_gmac_check_link(ath_gmac_mac_t *mac)
|
|
{
|
|
int link, duplex, speed;
|
|
|
|
ath_gmac_phy_link(mac->mac_unit, &link);
|
|
ath_gmac_phy_duplex(mac->mac_unit, &duplex);
|
|
ath_gmac_phy_speed(mac->mac_unit, &speed);
|
|
|
|
mac->link = link;
|
|
|
|
if(!mac->link) {
|
|
//printf("%s link down\n",mac->dev->name);
|
|
return 0;
|
|
}
|
|
|
|
switch (speed)
|
|
{
|
|
case _1000BASET:
|
|
ath_gmac_set_mac_if(mac, 1);
|
|
ath_gmac_reg_rmw_set(mac, ATH_MAC_FIFO_CFG_5, (1 << 19));
|
|
|
|
if (is_ar8033() && mac->mac_unit == 1) {
|
|
ath_reg_wr(ETH_SGMII_ADDRESS, ETH_SGMII_GIGE_SET(1) |
|
|
ETH_SGMII_CLK_SEL_SET(1));
|
|
}
|
|
|
|
break;
|
|
|
|
case _100BASET:
|
|
ath_gmac_set_mac_if(mac, 0);
|
|
ath_gmac_set_mac_speed(mac, 1);
|
|
ath_gmac_reg_rmw_clear(mac, ATH_MAC_FIFO_CFG_5, (1 << 19));
|
|
|
|
if (is_ar8033() && mac->mac_unit == 1) {
|
|
ath_reg_wr(ETH_SGMII_ADDRESS, ETH_SGMII_PHASE0_COUNT_SET(1) |
|
|
ETH_SGMII_PHASE1_COUNT_SET(1));
|
|
}
|
|
|
|
break;
|
|
|
|
case _10BASET:
|
|
ath_gmac_set_mac_if(mac, 0);
|
|
ath_gmac_set_mac_speed(mac, 0);
|
|
ath_gmac_reg_rmw_clear(mac, ATH_MAC_FIFO_CFG_5, (1 << 19));
|
|
|
|
if (is_ar8033() && mac->mac_unit == 1) {
|
|
ath_reg_wr(ETH_SGMII_ADDRESS, ETH_SGMII_PHASE0_COUNT_SET(19) |
|
|
ETH_SGMII_PHASE1_COUNT_SET(19));
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
printf("Invalid speed detected\n");
|
|
return 0;
|
|
}
|
|
|
|
if (mac->link && (duplex == mac->duplex) && (speed == mac->speed))
|
|
return 1;
|
|
|
|
mac->duplex = duplex;
|
|
mac->speed = speed;
|
|
|
|
printf("dup %d speed %d\n", duplex, speed);
|
|
|
|
ath_gmac_set_mac_duplex(mac,duplex);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* For every command we re-setup the ring and start with clean h/w rx state
|
|
*/
|
|
static int ath_gmac_clean_rx(struct eth_device *dev, bd_t * bd)
|
|
{
|
|
|
|
int i;
|
|
ath_gmac_desc_t *fr;
|
|
ath_gmac_mac_t *mac = (ath_gmac_mac_t*)dev->priv;
|
|
|
|
#if 1
|
|
/* Workaround for multiboot!
|
|
* To ensure PHY link-up because eth_init()/ath_gmac_clean_rx() will check link status.
|
|
* if link-down, it will disable RX and not return failed. so it will cause multiboot client
|
|
* can't receive the packet.
|
|
*/
|
|
i=0;
|
|
while (!ath_gmac_check_link(mac)) { /* need to waiting for autonegotiation to complete */
|
|
udelay(1000);
|
|
if (++i >= 3000) {
|
|
printf("could not establish link on %s\n", mac->dev->name);
|
|
return -1;
|
|
}
|
|
}
|
|
#else
|
|
if (!ath_gmac_check_link(mac))
|
|
return 0;
|
|
#endif
|
|
|
|
mac->next_rx = 0;
|
|
|
|
ath_gmac_reg_wr(mac, ATH_MAC_FIFO_CFG_0, 0x1f00);
|
|
ath_gmac_reg_wr(mac, ATH_MAC_CFG1, (ATH_MAC_CFG1_RX_EN | ATH_MAC_CFG1_TX_EN));
|
|
|
|
for (i = 0; i < NO_OF_RX_FIFOS; i++) {
|
|
fr = mac->fifo_rx[i];
|
|
fr->pkt_start_addr = virt_to_phys(NetRxPackets[i]);
|
|
flush_cache((u32) NetRxPackets[i], PKTSIZE_ALIGN);
|
|
ath_gmac_rx_give_to_dma(fr);
|
|
}
|
|
|
|
ath_gmac_reg_wr(mac, ATH_DMA_RX_DESC, virt_to_phys(mac->fifo_rx[0]));
|
|
ath_gmac_reg_wr(mac, ATH_DMA_RX_CTRL, ATH_RXE); /* rx start */
|
|
udelay(1000 * 1000);
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
static int ath_gmac_alloc_fifo(int ndesc, ath_gmac_desc_t ** fifo)
|
|
{
|
|
int i;
|
|
u32 size;
|
|
uchar *p = NULL;
|
|
|
|
size = sizeof(ath_gmac_desc_t) * ndesc;
|
|
size += CONFIG_SYS_CACHELINE_SIZE - 1;
|
|
|
|
if ((p = malloc(size)) == NULL) {
|
|
printf("Cant allocate fifos\n");
|
|
return -1;
|
|
}
|
|
|
|
p = (uchar *) (((u32) p + CONFIG_SYS_CACHELINE_SIZE - 1) &
|
|
~(CONFIG_SYS_CACHELINE_SIZE - 1));
|
|
p = UNCACHED_SDRAM(p);
|
|
|
|
for (i = 0; i < ndesc; i++)
|
|
fifo[i] = (ath_gmac_desc_t *) p + i;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ath_gmac_setup_fifos(ath_gmac_mac_t *mac)
|
|
{
|
|
int i;
|
|
|
|
if (ath_gmac_alloc_fifo(NO_OF_TX_FIFOS, mac->fifo_tx))
|
|
return 1;
|
|
|
|
for (i = 0; i < NO_OF_TX_FIFOS; i++) {
|
|
mac->fifo_tx[i]->next_desc = (i == NO_OF_TX_FIFOS - 1) ?
|
|
virt_to_phys(mac->fifo_tx[0]) : virt_to_phys(mac->fifo_tx[i + 1]);
|
|
ath_gmac_tx_own(mac->fifo_tx[i]);
|
|
}
|
|
|
|
if (ath_gmac_alloc_fifo(NO_OF_RX_FIFOS, mac->fifo_rx))
|
|
return 1;
|
|
|
|
for (i = 0; i < NO_OF_RX_FIFOS; i++) {
|
|
mac->fifo_rx[i]->next_desc = (i == NO_OF_RX_FIFOS - 1) ?
|
|
virt_to_phys(mac->fifo_rx[0]) : virt_to_phys(mac->fifo_rx[i + 1]);
|
|
}
|
|
|
|
return (1);
|
|
}
|
|
|
|
static void ath_gmac_halt(struct eth_device *dev)
|
|
{
|
|
ath_gmac_mac_t *mac = (ath_gmac_mac_t *)dev->priv;
|
|
ath_gmac_reg_rmw_clear(mac, ATH_MAC_CFG1,(ATH_MAC_CFG1_RX_EN | ATH_MAC_CFG1_TX_EN));
|
|
ath_gmac_reg_wr(mac,ATH_MAC_FIFO_CFG_0,0x1f1f);
|
|
ath_gmac_reg_wr(mac,ATH_DMA_RX_CTRL, 0);
|
|
while (ath_gmac_reg_rd(mac, ATH_DMA_RX_CTRL));
|
|
}
|
|
|
|
#if 0
|
|
#ifdef CONFIG_ATH_NAND_BR
|
|
|
|
unsigned char *
|
|
ath_eth_mac_addr(unsigned char *sectorBuff)
|
|
{
|
|
ulong off, size;
|
|
nand_info_t *nand;
|
|
unsigned char ret;
|
|
|
|
/*
|
|
* caldata partition is of 128k
|
|
*/
|
|
nand = &nand_info[nand_curr_device];
|
|
size = ATH_ETH_MAC_READ_SIZE; /* To read 4k setting size as 4k */
|
|
|
|
/*
|
|
* Get the Offset of Caldata partition
|
|
*/
|
|
off = ath_nand_get_cal_offset(getenv("bootargs"));
|
|
if(off == ATH_CAL_OFF_INVAL) {
|
|
printf("Invalid CAL offset \n");
|
|
return NULL;
|
|
}
|
|
/*
|
|
* Get the values from flash, and program into the MAC address
|
|
* registers
|
|
*/
|
|
ret = nand_read(nand, (loff_t)off, &size, (u_char *)sectorBuff);
|
|
printf(" %d bytes %s: %s\n", size,
|
|
"read", ret ? "ERROR" : "OK");
|
|
if(ret != 0 ) {
|
|
return NULL;
|
|
}
|
|
|
|
return sectorBuff;
|
|
}
|
|
|
|
#else /* CONFIG_ATH_NAND_BR */
|
|
|
|
unsigned char *
|
|
ath_gmac_mac_addr_loc(void)
|
|
{
|
|
extern flash_info_t flash_info[];
|
|
|
|
#ifdef BOARDCAL
|
|
/*
|
|
** BOARDCAL environmental variable has the address of the cal sector
|
|
*/
|
|
|
|
return ((unsigned char *)BOARDCAL);
|
|
|
|
#else
|
|
/* MAC address is store in the 2nd 4k of last sector */
|
|
return ((unsigned char *)
|
|
(KSEG1ADDR(ATH_SPI_BASE) + (4 * 1024) +
|
|
flash_info[0].size - (64 * 1024) /* sector_size */ ));
|
|
#endif
|
|
}
|
|
|
|
#endif /* CONFIG_ATH_NAND_BR */
|
|
|
|
static void ath_gmac_get_ethaddr(struct eth_device *dev)
|
|
{
|
|
unsigned char *eeprom;
|
|
unsigned char *mac = dev->enetaddr;
|
|
#ifndef CONFIG_ATH_EMULATION
|
|
|
|
#ifdef CONFIG_ATH_NAND_BR
|
|
unsigned char sectorBuff[ATH_ETH_MAC_READ_SIZE];
|
|
|
|
eeprom = ath_eth_mac_addr(sectorBuff);
|
|
if(eeprom == NULL) {
|
|
/* mac address will be set to default mac address */
|
|
mac[0] = 0xff;
|
|
}
|
|
else {
|
|
#else /* CONFIG_ATH_NAND_BR */
|
|
eeprom = ath_gmac_mac_addr_loc();
|
|
#endif /* CONFIG_ATH_NAND_BR */
|
|
|
|
if (strcmp(dev->name, "eth0") == 0) {
|
|
memcpy(mac, eeprom, 6);
|
|
} else if (strcmp(dev->name, "eth1") == 0) {
|
|
eeprom += 6;
|
|
memcpy(mac, eeprom, 6);
|
|
} else {
|
|
printf("%s: unknown ethernet device %s\n", __func__, dev->name);
|
|
return;
|
|
}
|
|
#ifdef CONFIG_ATH_NAND_BR
|
|
}
|
|
#endif /* CONFIG_ATH_NAND_BR */
|
|
/* Use fixed address if the above address is invalid */
|
|
if (mac[0] != 0x00 || (mac[0] == 0xff && mac[5] == 0xff))
|
|
#else
|
|
if (1)
|
|
#endif
|
|
{
|
|
mac[0] = 0x00;
|
|
mac[1] = 0x03;
|
|
mac[2] = 0x7f;
|
|
mac[3] = 0x09;
|
|
mac[4] = 0x0b;
|
|
mac[5] = 0xad;
|
|
printf("No valid address in Flash. Using fixed address\n");
|
|
} else {
|
|
printf("Fetching MAC Address from 0x%p\n", __func__, eeprom);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_MGMT_INIT) && defined (CONFIG_ATHR_SWITCH_ONLY_MODE) || defined ATH_MDC_GPIO
|
|
void
|
|
athr_mgmt_init(void)
|
|
{
|
|
|
|
#ifdef CONFIG_MGMT_INIT
|
|
uint32_t rddata;
|
|
|
|
rddata = ath_reg_rd(GPIO_IN_ENABLE3_ADDRESS)&
|
|
~GPIO_IN_ENABLE3_MII_GE1_MDI_MASK;
|
|
rddata |= GPIO_IN_ENABLE3_MII_GE1_MDI_SET(19);
|
|
ath_reg_wr(GPIO_IN_ENABLE3_ADDRESS, rddata);
|
|
|
|
ath_reg_rmw_clear(GPIO_OE_ADDRESS, (1 << 19));
|
|
|
|
ath_reg_rmw_clear(GPIO_OE_ADDRESS, (1 << 17));
|
|
|
|
|
|
rddata = ath_reg_rd(GPIO_OUT_FUNCTION4_ADDRESS) &
|
|
~ (GPIO_OUT_FUNCTION4_ENABLE_GPIO_19_MASK |
|
|
GPIO_OUT_FUNCTION4_ENABLE_GPIO_17_MASK);
|
|
|
|
rddata |= GPIO_OUT_FUNCTION4_ENABLE_GPIO_19_SET(0x20) |
|
|
GPIO_OUT_FUNCTION4_ENABLE_GPIO_17_SET(0x21);
|
|
|
|
ath_reg_wr(GPIO_OUT_FUNCTION4_ADDRESS, rddata);
|
|
#endif
|
|
printf ("%s ::done\n",__func__);
|
|
}
|
|
#endif
|
|
|
|
int ath_gmac_enet_initialize(bd_t * bis)
|
|
{
|
|
struct eth_device *dev[CFG_ATH_GMAC_NMACS];
|
|
u32 mask, mac_h, mac_l;
|
|
int i;
|
|
#ifdef ATH_GMAC_DEBUG
|
|
printf("%s...\n", __func__);
|
|
#endif
|
|
athrs_sgmii_res_cal();
|
|
|
|
for (i = 0;i < CFG_ATH_GMAC_NMACS;i++) {
|
|
|
|
if ((dev[i] = (struct eth_device *) malloc(sizeof (struct eth_device))) == NULL) {
|
|
puts("malloc failed\n");
|
|
return 0;
|
|
}
|
|
|
|
if ((ath_gmac_macs[i] = (ath_gmac_mac_t *) malloc(sizeof (ath_gmac_mac_t))) == NULL) {
|
|
puts("malloc failed\n");
|
|
return 0;
|
|
}
|
|
|
|
memset(ath_gmac_macs[i], 0, sizeof(ath_gmac_macs[i]));
|
|
memset(dev[i], 0, sizeof(dev[i]));
|
|
|
|
sprintf(dev[i]->name, "eth%d", i);
|
|
#if 0 /* for zyxel, we get MAC address from u-boot environment */
|
|
ath_gmac_get_ethaddr(dev[i]);
|
|
#else
|
|
#ifdef CFG_ATH_SWAP_ETHACT
|
|
eth_getenv_enetaddr_by_index(CFG_ATH_GMAC_NMACS-1-i, dev[i]->enetaddr);
|
|
#else
|
|
eth_getenv_enetaddr_by_index(i, dev[i]->enetaddr);
|
|
#endif
|
|
#endif
|
|
ath_gmac_macs[i]->mac_unit = i;
|
|
ath_gmac_macs[i]->mac_base = i ? ATH_GE1_BASE : ATH_GE0_BASE ;
|
|
ath_gmac_macs[i]->dev = dev[i];
|
|
|
|
dev[i]->iobase = 0;
|
|
dev[i]->init = ath_gmac_clean_rx;
|
|
dev[i]->halt = ath_gmac_halt;
|
|
dev[i]->send = ath_gmac_send;
|
|
dev[i]->recv = ath_gmac_recv;
|
|
dev[i]->priv = (void *)ath_gmac_macs[i];
|
|
}
|
|
|
|
#if !defined(CONFIG_ATH_NAND_BR)
|
|
ath_reg_rmw_set(RST_RESET_ADDRESS, RST_RESET_ETH_SGMII_ARESET_SET(1));
|
|
udelay(1000 * 100);
|
|
ath_reg_rmw_clear(RST_RESET_ADDRESS, RST_RESET_ETH_SGMII_ARESET_SET(1));
|
|
udelay(100);
|
|
#endif
|
|
ath_reg_rmw_set(RST_RESET_ADDRESS, RST_RESET_ETH_SGMII_RESET_SET(1) | RST_RESET_EXTERNAL_RESET_SET(1));
|
|
udelay(1000 * 100);
|
|
ath_reg_rmw_clear(RST_RESET_ADDRESS, RST_RESET_ETH_SGMII_RESET_SET(1) | RST_RESET_EXTERNAL_RESET_SET(1));
|
|
udelay(1000 * 100);
|
|
|
|
for (i = 0;i < CFG_ATH_GMAC_NMACS;i++) {
|
|
|
|
ath_gmac_reg_rmw_set(ath_gmac_macs[i], ATH_MAC_CFG1, ATH_MAC_CFG1_SOFT_RST
|
|
| ATH_MAC_CFG1_RX_RST | ATH_MAC_CFG1_TX_RST);
|
|
|
|
if(!i) {
|
|
mask = (ATH_RESET_GE0_MAC | ATH_RESET_GE1_MAC);
|
|
|
|
mask = mask | ATH_RESET_GE0_MDIO | ATH_RESET_GE1_MDIO;
|
|
|
|
#ifdef ATH_GMAC_DEBUG
|
|
printf("%s: reset mask:%x \n", __func__, mask);
|
|
#endif
|
|
ath_reg_rmw_set(RST_RESET_ADDRESS, mask);
|
|
udelay(1000 * 100);
|
|
|
|
ath_reg_rmw_clear(RST_RESET_ADDRESS, mask);
|
|
udelay(1000 * 100);
|
|
|
|
udelay(10 * 1000);
|
|
}
|
|
#if defined(CONFIG_MGMT_INIT) && defined (CONFIG_ATHR_SWITCH_ONLY_MODE) || defined ATH_MDC_GPIO
|
|
if (!i)
|
|
athr_mgmt_init();
|
|
|
|
if (ath_gmac_macs[i]->mac_unit == 0)
|
|
continue;
|
|
#endif
|
|
#ifndef CFG_ATH_SWAP_ETHACT
|
|
eth_register(dev[i]);
|
|
#ifdef CONFIG_CMD_MII
|
|
miiphy_register(dev[i]->name, ath_gmac_miiphy_read, ath_gmac_miiphy_write);
|
|
#endif
|
|
#endif
|
|
ath_gmac_mii_setup(ath_gmac_macs[i]);
|
|
|
|
/* if using header for register configuration, we have to */
|
|
/* configure s26 register after frame transmission is enabled */
|
|
|
|
if (ath_gmac_macs[i]->mac_unit == 0) { /* WAN Phy */
|
|
#ifdef CONFIG_ATHRS17_PHY
|
|
athrs17_reg_init();
|
|
#endif
|
|
|
|
#ifdef CONFIG_VIR_PHY
|
|
printf("VIRPhy reg init \n");
|
|
athr_vir_reg_init();
|
|
#endif
|
|
|
|
} else {
|
|
#ifdef CONFIG_ATHR_8033_PHY
|
|
printf("AR8033 PHY init \n");
|
|
athrs_ar8033_reg_init(NULL);
|
|
|
|
#endif
|
|
|
|
#if defined(CONFIG_MGMT_INIT) && defined (CONFIG_ATHR_SWITCH_ONLY_MODE)
|
|
athrs17_reg_init();
|
|
#elif defined (CONFIG_ATHRS17_PHY) && !defined(CFG_DUAL_PHY_SUPPORT)
|
|
athrs17_reg_init_wan();
|
|
#endif
|
|
}
|
|
#ifdef CONFIG_ATHRS_GMAC_SGMII
|
|
/*
|
|
* MAC unit 1 or drqfn package call sgmii setup.
|
|
*/
|
|
if (i == 1 || is_drqfn())
|
|
athr_gmac_sgmii_setup();
|
|
#endif
|
|
ath_gmac_hw_start(ath_gmac_macs[i]);
|
|
ath_gmac_setup_fifos(ath_gmac_macs[i]);
|
|
|
|
udelay(100 * 1000);
|
|
#ifdef ATH_GMAC_DEBUG
|
|
{
|
|
unsigned char *mac = dev[i]->enetaddr;
|
|
|
|
printf("%s: %02x:%02x:%02x:%02x:%02x:%02x\n", dev[i]->name,
|
|
mac[0] & 0xff, mac[1] & 0xff, mac[2] & 0xff,
|
|
mac[3] & 0xff, mac[4] & 0xff, mac[5] & 0xff);
|
|
}
|
|
#endif
|
|
mac_l = (dev[i]->enetaddr[4] << 8) | (dev[i]->enetaddr[5]);
|
|
mac_h = (dev[i]->enetaddr[0] << 24) | (dev[i]->enetaddr[1] << 16) |
|
|
(dev[i]->enetaddr[2] << 8) | (dev[i]->enetaddr[3] << 0);
|
|
|
|
ath_gmac_reg_wr(ath_gmac_macs[i], ATH_GE_MAC_ADDR1, mac_l);
|
|
ath_gmac_reg_wr(ath_gmac_macs[i], ATH_GE_MAC_ADDR2, mac_h);
|
|
|
|
|
|
ath_gmac_phy_setup(ath_gmac_macs[i]->mac_unit);
|
|
#ifdef ATH_GMAC_DEBUG
|
|
printf("%s up\n",dev[i]->name);
|
|
#endif
|
|
}
|
|
|
|
#if defined(CFG_ATH_SWAP_ETHACT)
|
|
strcpy(dev[1]->name, "eth0");
|
|
strcpy(dev[0]->name, "eth1");
|
|
eth_register(dev[1]);
|
|
eth_register(dev[0]);
|
|
#ifdef CONFIG_MII
|
|
miiphy_register(dev[1]->name, ath_gmac_miiphy_read, ath_gmac_miiphy_write);
|
|
miiphy_register(dev[0]->name, ath_gmac_miiphy_read, ath_gmac_miiphy_write);
|
|
#endif
|
|
#endif
|
|
return 1;
|
|
}
|
|
|
|
#if defined(CONFIG_CMD_MII) || defined(CONFIG_ZYXEL_ZLOADER)
|
|
uint16_t
|
|
ath_gmac_miiphy_read(char *devname, uint32_t phy_addr, uint8_t reg)
|
|
{
|
|
ath_gmac_mac_t *mac = ath_gmac_name2mac(devname);
|
|
uint16_t addr = (phy_addr << ATH_ADDR_SHIFT) | reg, val;
|
|
volatile int rddata;
|
|
uint16_t ii = 0xFFFF;
|
|
|
|
|
|
|
|
|
|
/*
|
|
* Check for previous transactions are complete. Added to avoid
|
|
* race condition while running at higher frequencies.
|
|
*/
|
|
do
|
|
{
|
|
udelay(5);
|
|
rddata = ath_gmac_reg_rd(mac, ATH_MII_MGMT_IND) & 0x1;
|
|
}while(rddata && --ii);
|
|
|
|
if (ii == 0)
|
|
printf("ERROR:%s:%d transaction failed\n",__func__,__LINE__);
|
|
|
|
|
|
ath_gmac_reg_wr(mac, ATH_MII_MGMT_CMD, 0x0);
|
|
ath_gmac_reg_wr(mac, ATH_MII_MGMT_ADDRESS, addr);
|
|
ath_gmac_reg_wr(mac, ATH_MII_MGMT_CMD, ATH_MGMT_CMD_READ);
|
|
|
|
do
|
|
{
|
|
udelay(5);
|
|
rddata = ath_gmac_reg_rd(mac, ATH_MII_MGMT_IND) & 0x1;
|
|
}while(rddata && --ii);
|
|
|
|
if(ii==0)
|
|
printf("Error!!! Leave ath_gmac_miiphy_read without polling correct status!\n");
|
|
|
|
val = ath_gmac_reg_rd(mac, ATH_MII_MGMT_STATUS);
|
|
ath_gmac_reg_wr(mac, ATH_MII_MGMT_CMD, 0x0);
|
|
|
|
return val;
|
|
}
|
|
|
|
void
|
|
ath_gmac_miiphy_write(char *devname, uint32_t phy_addr, uint8_t reg, uint16_t data)
|
|
{
|
|
ath_gmac_mac_t *mac = ath_gmac_name2mac(devname);
|
|
uint16_t addr = (phy_addr << ATH_ADDR_SHIFT) | reg;
|
|
volatile int rddata;
|
|
uint16_t ii = 0xFFFF;
|
|
|
|
|
|
/*
|
|
* Check for previous transactions are complete. Added to avoid
|
|
* race condition while running at higher frequencies.
|
|
*/
|
|
do {
|
|
udelay(5);
|
|
rddata = ath_gmac_reg_rd(mac, ATH_MII_MGMT_IND) & 0x1;
|
|
} while (rddata && --ii);
|
|
|
|
if (ii == 0)
|
|
printf("ERROR:%s:%d transaction failed\n",__func__,__LINE__);
|
|
|
|
ath_gmac_reg_wr(mac, ATH_MII_MGMT_ADDRESS, addr);
|
|
ath_gmac_reg_wr(mac, ATH_MII_MGMT_CTRL, data);
|
|
|
|
do {
|
|
rddata = ath_gmac_reg_rd(mac, ATH_MII_MGMT_IND) & 0x1;
|
|
} while (rddata && --ii);
|
|
|
|
if (ii == 0)
|
|
printf("Error!!! Leave ath_gmac_miiphy_write without polling correct status!\n");
|
|
}
|
|
#endif /* defined(CONFIG_CMD_MII) || defined(CONFIG_ZYXEL_ZLOADER) */
|