📄 emac_sl2312.c
字号:
/***************************************************************************** Copyright Storlink Corp 2005. All rights reserved. *--------------------------------------------------------------------------* Name : emac_sl2312.c* Description : * Ethernet device driver for Storlink SL2312 Chip** History** Date Writer Description* ----------- ----------- -------------------------------------------------* 04/25/2005 Gary Chen Create and implement from Jason's Redboot code*****************************************************************************/#include <define.h>#include <board_config.h>#include <sl2312.h>#ifndef MIDWAY#include "emac_sl2312.h"#define diag_printf printf unsigned int FLAG_SWITCH = 0; /* if 1-->switch chip presented. if 0-->switch chip unpresented */int vlan_enabled = 0;/************************************************************* * Global Variable *************************************************************/EMAC_INFO_T emac_private_data;//static unsigned int tx_free_desc = TX_DESC_NUM;static unsigned int flow_control_enable = 0;//static unsigned int tx_desc_virtual_base = 0;//static unsigned int rx_desc_virtual_base = 0;//static unsigned int tx_buf_virtual_base = 0;//static unsigned int rx_buf_virtual_base = 0;unsigned int full_duplex = 1;unsigned int chip_id=0;static unsigned char tx_desc_array[TX_DESC_NUM * sizeof(EMAC_DESCRIPTOR_T)] __attribute__((aligned(32))); static unsigned char rx_desc_array[RX_DESC_NUM * sizeof(EMAC_DESCRIPTOR_T)] __attribute__((aligned(32)));static unsigned char tx_buf_array[TX_BUF_TOT_LEN] __attribute__((aligned(32)));static unsigned char rx_buf_array[RX_BUF_TOT_LEN] __attribute__((aligned(32)));/************************************************//* function declare *//************************************************/void emac_set_mac_addr(unsigned char *mac1, unsigned char *mac2);void emac_enable_tx_rx(void);void emac_disable_tx_rx(void);extern void emac_set_phy_status(void);extern void emac_get_phy_status(void);extern char *sys_get_mac_addr(int index);/****************************************//* SPI Function Declare *//****************************************/extern void SPI_default(int vlan_enabled);extern unsigned int SPI_get_identifier(void);extern void enet_get_mac_addr(unsigned char* mac);/****************************************//* VLAN Function Declare *//****************************************//************************************************//* function body *//************************************************/#define emac_read_reg(offset) REG32(EMAC_BASE_ADDR + offset)#define emac_write_reg(offset, data, mask) REG32(EMAC_BASE_ADDR + offset) = \ (emac_read_reg(offset) & (~mask)) | \ (data & mask) static int emac_init_chip(void){ EMAC_RBNR_T rbnr_val,rbnr_mask; EMAC_CONFIG2_T config2_val; EMAC_CONFIG0_T config0,config0_mask; EMAC_CONFIG1_T config1; UINT32 data; /* chip reset */ /* set RMII mode for testing */ if (full_duplex == 1) { emac_write_reg(EMAC_STATUS,0x00000017,0x0000001f); /* 100M full duplex */ } else { emac_write_reg(EMAC_STATUS,0x00000013,0x0000001f); /* 100M half duplex */ } emac_set_mac_addr(sys_get_mac_addr(0), sys_get_mac_addr(1)); /* set RX_FLTR register to receive all multicast packet */ emac_write_reg(EMAC_RX_FLTR,0x00000005,0x0000001f);// emac_write_reg(EMAC_RX_FLTR,0x00000001,0x0000001f); /* set per packet buffer size */ config1.bits32 = 0; config1.bits.buf_size = 11; /* buffer size = 2048-byte */ emac_write_reg(EMAC_CONFIG1,config1.bits32,0x0000000f); /* set flow control threshold */ config2_val.bits32 = 0; config2_val.bits.set_threshold = RX_DESC_NUM/4; config2_val.bits.rel_threshold = RX_DESC_NUM*3/4; emac_write_reg(EMAC_CONFIG2,config2_val.bits32,0xffffffff); /* init remaining buffer number register */ rbnr_val.bits32 = 0; rbnr_val.bits.buf_remain = RX_DESC_NUM; rbnr_mask.bits32 = 0; rbnr_mask.bits.buf_remain = 0xffff; emac_write_reg(EMAC_RBNR,rbnr_val.bits32,rbnr_mask.bits32); /* disable TX/RX and disable internal loop back */ config0.bits32 = 0; config0_mask.bits32 = 0; config0.bits.max_len = 2; config0.bits.fc_en = 0; /* enable flow control */ config0.bits.dis_rx = 1; /* disable rx */ config0.bits.dis_tx = 1; /* disable tx */ config0.bits.loop_back = 0; /* enable/disable EMAC loopback */ config0_mask.bits.max_len = 3; config0_mask.bits.fc_en = 1; config0_mask.bits.dis_rx = 1; config0_mask.bits.dis_tx = 1; config0_mask.bits.loop_back = 1; emac_write_reg(EMAC_CONFIG0,config0.bits32,config0_mask.bits32); flow_control_enable = 0; /* disable flow control flag */ return (0);}void emac_enable_tx_rx(void){ EMAC_CONFIG0_T config0,config0_mask; /* enable TX/RX */ config0.bits32 = 0; config0_mask.bits32 = 0; config0.bits.dis_rx = 0; /* enable rx */ config0.bits.dis_tx = 0; /* enable tx */ config0_mask.bits.dis_rx = 1; config0_mask.bits.dis_tx = 1; emac_write_reg(EMAC_CONFIG0,config0.bits32,config0_mask.bits32); }void emac_disable_tx_rx(void){ EMAC_CONFIG0_T config0,config0_mask; /* enable TX/RX */ config0.bits32 = 0; config0_mask.bits32 = 0; config0.bits.dis_rx = 1; /* disable rx */ config0.bits.dis_tx = 1; /* disable tx */ config0_mask.bits.dis_rx = 1; config0_mask.bits.dis_tx = 1; emac_write_reg(EMAC_CONFIG0,config0.bits32,config0_mask.bits32); } #if 0static void emac_tx_interrupt(void){ EMAC_INFO_T *tp = (EMAC_INFO_T *)&emac_private_data; EMAC_DESCRIPTOR_T *tx_hw_complete_desc; unsigned int desc_cnt=0; unsigned int i; /* get tx H/W completed descriptor virtual address */ tx_hw_complete_desc = (EMAC_DESCRIPTOR_T *)(emac_read_reg(EMAC_TXDMA_CURR_DESC) & 0xfffffff0); /* check tx status and accumulate tx statistics */ for (;;) { if (tp->tx_finished_desc == tx_hw_complete_desc) /* complete tx processing */ { break; } if (tp->tx_finished_desc->frame_ctrl.bits_tx.own == CPU) { if ( (tp->tx_finished_desc->frame_ctrl.bits_tx.derr) || (tp->tx_finished_desc->frame_ctrl.bits_tx.perr) ) { diag_printf("emac_tx_interrupt::Descriptor Processing Error !!!\n"); } if (tp->tx_finished_desc->frame_ctrl.bits_tx.success_tx == 1) {// tp->stats.tx_bytes += tp->tx_finished_desc->flag_status.bits_tx_flag.frame_count;// tp->stats.tx_packets ++; } else {// tp->stats.tx_errors++; } desc_cnt = tp->tx_finished_desc->frame_ctrl.bits_tx.desc_count; for (i=1; i<desc_cnt; i++) /* multi_descriptor */ { /* release Tx descriptor to CPU */ tp->tx_finished_desc = (EMAC_DESCRIPTOR_T *)((tp->tx_finished_desc->next_desc.next_descriptor & 0xfffffff0)); tp->tx_finished_desc->frame_ctrl.bits_tx.own = CPU; } tp->tx_finished_desc = (EMAC_DESCRIPTOR_T *)((tp->tx_finished_desc->next_desc.next_descriptor & 0xfffffff0)); } }// REG32(SL2312_GLOBAL_BASE+GLOBAL_MISC_CTRL) &= ~GLOBAL_PFLASH_EN_BIT;//~0x00000001; } #endifstatic void emac_weird_interrupt(void){}void sl2312_emac_deliver(void){ EMAC_INFO_T *tp = (EMAC_INFO_T *)&emac_private_data; EMAC_DESCRIPTOR_T *rx_desc; unsigned int pkt_len; unsigned int own; unsigned int desc_count; EMAC_RXDMA_FIRST_DESC_T rxdma_busy; own = tp->rx_cur_desc->frame_ctrl.bits32 >> 31; if (own == CPU) /* check owner bit */ { rx_desc = tp->rx_cur_desc; /* check error interrupt */ if ( (rx_desc->frame_ctrl.bits_rx.derr==1)||(rx_desc->frame_ctrl.bits_rx.perr==1) ) { diag_printf("emac_rx_interrupt::Rx Descriptor Processing Error !!!\n"); } /* get frame information from the first descriptor of the frame */ pkt_len = rx_desc->flag_status.bits_rx_status.frame_count-4; /*total byte count in a frame*/ desc_count = rx_desc->frame_ctrl.bits_rx.desc_count; /* get descriptor count per frame */ if ((pkt_len > 0) && (rx_desc->frame_ctrl.bits_rx.frame_state == 0x000)) /* good frame */ { // (sc->funs->eth_drv->recv)(sc, pkt_len); // queue it tp->rx_pkts++; enet_input(rx_desc->buf_adr, pkt_len); } rx_desc->frame_ctrl.bits_rx.own = DMA; /* release rx descriptor to DMA */ /* point to next rx descriptor */ tp->rx_cur_desc = (EMAC_DESCRIPTOR_T *)(tp->rx_cur_desc->next_desc.next_descriptor & 0xfffffff0); /* release buffer to Remaining Buffer Number Register */ if (flow_control_enable ==1) { emac_write_reg(EMAC_BNCR, desc_count, 0x0000ffff); } } /* if RX DMA process is stoped , restart it */ rxdma_busy.bits.rd_first_des_ptr = emac_read_reg(EMAC_RXDMA_FIRST_DESC); if (rxdma_busy.bits.rd_busy == 0) { EMAC_RXDMA_CTRL_T rxdma_ctrl,rxdma_ctrl_mask; rxdma_ctrl.bits32 = 0; rxdma_ctrl.bits.rd_start = 1; /* start RX DMA transfer */ rxdma_ctrl.bits.rd_continue = 1; /* continue RX DMA operation */ rxdma_ctrl_mask.bits32 = 0; rxdma_ctrl_mask.bits.rd_start = 1; rxdma_ctrl_mask.bits.rd_continue = 1; emac_write_reg(EMAC_RXDMA_CTRL,rxdma_ctrl.bits32,rxdma_ctrl_mask.bits32); }}/* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. *///static void emac_interrupt (int irq, void *dev_instance, struct pt_regs *regs)void emac_sl2312_poll(void){ EMAC_RXDMA_FIRST_DESC_T rxdma_busy; EMAC_TXDMA_FIRST_DESC_T txdma_busy; EMAC_TXDMA_CTRL_T txdma_ctrl,txdma_ctrl_mask; EMAC_RXDMA_CTRL_T rxdma_ctrl,rxdma_ctrl_mask; EMAC_DMA_STATUS_T status; // for (;;) { /* read DMA status */ status.bits32 = emac_read_reg(EMAC_DMA_STATUS); /* clear DMA status */ emac_write_reg(EMAC_DMA_STATUS,status.bits32,status.bits32); if ((status.bits32 & 0xffffc000)==0) { // break; return; } if (status.bits.rx_overrun == 1) { emac_private_data.rx_overrun++; /* if RX DMA process is stoped , restart it */ rxdma_busy.bits32 = emac_read_reg(EMAC_RXDMA_FIRST_DESC) ; if (rxdma_busy.bits.rd_busy == 0) { /* restart Rx DMA process */ rxdma_ctrl.bits32 = 0; rxdma_ctrl.bits.rd_start = 1; /* start RX DMA transfer */ rxdma_ctrl.bits.rd_continue = 1; /* continue RX DMA operation */ rxdma_ctrl_mask.bits32 = 0; rxdma_ctrl_mask.bits.rd_start = 1; rxdma_ctrl_mask.bits.rd_continue = 1; emac_write_reg(EMAC_RXDMA_CTRL,rxdma_ctrl.bits32,rxdma_ctrl_mask.bits32); } } if (status.bits.tx_underrun == 1) { /* if TX DMA process is stoped , restart it */ emac_private_data.tx_underrun++; txdma_busy.bits32 = emac_read_reg(EMAC_TXDMA_FIRST_DESC); if (txdma_busy.bits.td_busy == 0) { /* restart Tx DMA process */ txdma_ctrl.bits32 = 0; txdma_ctrl.bits.td_start = 1; txdma_ctrl.bits.td_continue = 1; txdma_ctrl_mask.bits32 = 0; txdma_ctrl_mask.bits.td_start = 1; txdma_ctrl_mask.bits.td_continue = 1; emac_write_reg(EMAC_TXDMA_CTRL,txdma_ctrl.bits32,txdma_ctrl_mask.bits32); } } /* receive rx interrupt */ if ( ((status.bits.rs_eofi==1)||(status.bits.rs_finish==1))|| ((status.bits.ts_eofi==1)||(status.bits.ts_finish==1)) ) {// emac_rx_interrupt(dev); sl2312_emac_deliver(); } /* receive tx interrupt */// if ( ((status.bits.ts_eofi==1)||(status.bits.ts_finish==1)) )// {// emac_tx_interrupt(dev);// } /* check uncommon events */ if ((status.bits32 & 0x633fc000)!=0) { emac_weird_interrupt(); } } return;}static void emac_hw_start(void){ EMAC_INFO_T *tp = (EMAC_INFO_T *)&emac_private_data; EMAC_TXDMA_CURR_DESC_T tx_desc; EMAC_RXDMA_CURR_DESC_T rx_desc; EMAC_TXDMA_CTRL_T txdma_ctrl,txdma_ctrl_mask; EMAC_RXDMA_CTRL_T rxdma_ctrl,rxdma_ctrl_mask; EMAC_DMA_STATUS_T dma_status,dma_status_mask; /* program TxDMA Current Descriptor Address register for first descriptor */ tx_desc.bits32 = (unsigned int)(tp->tx_desc_dma); tx_desc.bits.eofie = 1; tx_desc.bits.dec = 0; tx_desc.bits.sof_eof = 0x03; emac_write_reg(EMAC_TXDMA_CURR_DESC,tx_desc.bits32,0xffffffff); emac_write_reg(0xff2c,tx_desc.bits32,0xffffffff); /* tx next descriptor address */ /* program RxDMA Current Descriptor Address register for first descriptor */ rx_desc.bits32 = (unsigned int)(tp->rx_desc_dma); rx_desc.bits.eofie = 1; rx_desc.bits.dec = 0; rx_desc.bits.sof_eof = 0x03; emac_write_reg(EMAC_RXDMA_CURR_DESC,rx_desc.bits32,0xffffffff); emac_write_reg(0xff3c,rx_desc.bits32,0xffffffff); /* rx next descriptor address */ /* enable EMAC interrupt & disable loopback */ dma_status.bits32 = 0; dma_status.bits.loop_back = 0; /* disable DMA loop-back mode */ dma_status.bits.m_tx_fail = 1; dma_status.bits.m_cnt_full = 1; dma_status.bits.m_rx_pause_on = 1; dma_status.bits.m_tx_pause_on = 1; dma_status.bits.m_rx_pause_off = 1; dma_status.bits.m_tx_pause_off = 1; dma_status.bits.m_rx_overrun = 1; dma_status.bits.m_tx_underrun = 1; dma_status_mask.bits32 = 0; dma_status_mask.bits.loop_back = 1; dma_status_mask.bits.m_tx_fail = 1; dma_status_mask.bits.m_cnt_full = 1; dma_status_mask.bits.m_rx_pause_on = 1; dma_status_mask.bits.m_tx_pause_on = 1; dma_status_mask.bits.m_rx_pause_off = 1; dma_status_mask.bits.m_tx_pause_off = 1; dma_status_mask.bits.m_rx_overrun = 1; dma_status_mask.bits.m_tx_underrun = 1; emac_write_reg(EMAC_DMA_STATUS,dma_status.bits32,dma_status_mask.bits32); /* program tx dma control register */ txdma_ctrl.bits32 = 0; txdma_ctrl.bits.td_start = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -