#include #include #include #include #include #include #include #include #ifdef CONFIG_ATH_NAND_BR #include #endif #include #include "qca-eth-955x.h" #include "qca-eth-955x_phy.h" #define SGMII_LINK_WAR_MAX_TRY 10 #if defined(CONFIG_CMD_MII) #include #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) */