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

📄 eth_ns9750.c

📁 Hermit-at-1.1.3,一款bootloader
💻 C
字号:
#include <arch/ns9750.h>#include <arch/ns9750_eth.h>#include <arch/eth.h>#include <arch/ioregs.h>#include <target/io.h>#include <target/mem.h>#include <target/net/eth.h>#include <target/net/eth_util.h>#include <target/net/mac.h>#include "board.h"#define NS_ETH_FRAME_LEN	(0x600)#define NS_ETH_PHY_ADDRESS	(0x0000)#define NS_MII_POLE_TIMEOUT	(10000)#ifdef DEBUG_ETH#define DEBUG_FUNC() hprintf("%s()\n", __FUNCTION__)#define DEBUG_INFO(args...) hprintf(args)#else#define DEBUG_FUNC()#define DEBUG_INFO(args...)#endiftypedef struct rx_buffer_desc_t{	unsigned int *src;	unsigned int len;	unsigned int *dest;	union{		unsigned int reg;		struct{			unsigned status : 16;			unsigned res    : 12;			unsigned full   : 1;			unsigned enable : 1;			unsigned intr   : 1;			unsigned wrap   : 1;		}bits;	}s;} rx_buffer_desc_t;typedef struct tx_buffer_desc_t{	unsigned int *src;	unsigned int len;	unsigned int *desc;	union{		unsigned int reg;		struct{			unsigned status : 16;			unsigned res    : 12;			unsigned full   : 1;			unsigned last   : 1;			unsigned intr   : 1;			unsigned wrap   : 1;	      	}bits;	}s;} tx_buffer_desc_t;volatile rx_buffer_desc_t rx_desc[4];volatile tx_buffer_desc_t *tx_desc;unsigned char *txbuf = (unsigned char *)0x02800000;unsigned char *rxbuf = (unsigned char *)0x02000000;static u32ns_mii_poll_busy(void){	u32 timeout = NS_MII_POLE_TIMEOUT;	while((IO_ETH_MIND & NS_ETH_MIND_BUSY) && timeout--);		return timeout;}static u16ns_mii_read(u16 reg){  IO_ETH_MADR = (NS_ETH_PHY_ADDRESS << 8) | reg;	IO_ETH_MCMD = NS_ETH_MCMD_READ;		if(!ns_mii_poll_busy())		hprintf("MII still busy in read\n");		IO_ETH_MCMD = 0;		return (u16)IO_ETH_MRDD;}static voidns_mii_write(u16 reg, u16 data){	IO_ETH_MADR = (NS_ETH_PHY_ADDRESS << 8) | reg;	IO_ETH_MWTD = data;		if(!ns_mii_poll_busy())		hprintf("MII still busy in write\n");}static voidns_link_print_changed(void){	u16 status;	u16 control;	control = ns_mii_read(PHY_COMMON_CTRL);	if((control & PHY_COMMON_CTRL_AUTO_NEG) == PHY_COMMON_CTRL_AUTO_NEG){		/* PHY_COMMON_STAT_LNK_STAT is only set on autonegotiation */		status = ns_mii_read(PHY_COMMON_STAT);		if(status & PHY_COMMON_STAT_LNK_STAT){				status = ns_mii_read(PHY_LXT971_STAT2);				status &= (PHY_LXT971_STAT2_100BTX |					   PHY_LXT971_STAT2_DUPLEX_MODE |					   PHY_LXT971_STAT2_AUTO_NEG);				/* mask out all uninteresting parts */		}	}		/* print new link status */		DEBUG_INFO("link mode %d Mbps %s duplex %s\n",		     (status & PHY_LXT971_STAT2_100BTX) ? 100 : 10,		     (status & PHY_LXT971_STAT2_DUPLEX_MODE) ? "full" : "half",		     (status & PHY_LXT971_STAT2_AUTO_NEG) ? "(auto)" : "");}static voidns_link_update_egcr(void){  u32 status;	u32 egcr;	u32 mac2;	u32 ipgt;	egcr = IO_ETH_EGCR1;	mac2 = IO_ETH_MAC2 & ~NS_ETH_MAC2_FULLD;	ipgt = IO_ETH_IPGT & ~NS_ETH_IPGT_MA;	status = ns_mii_read(PHY_LXT971_STAT2);	if(status & PHY_LXT971_STAT2_DUPLEX_MODE){		mac2 |= NS_ETH_MAC2_FULLD;		ipgt |= 0x15;	/* see [1] p. 339 */	}else{		ipgt |= 0x12;	/* see [1] p. 339 */	}	IO_ETH_MAC2 = mac2;	IO_ETH_EGCR1 = egcr;	IO_ETH_IPGT = ipgt;}static void ns_link_auto_negotiate(void){	u16 status;	DEBUG_FUNC();	status = ns_mii_read(PHY_COMMON_STAT);	if((status & (PHY_COMMON_STAT_AN_COMP | PHY_COMMON_STAT_LNK_STAT)) ==	   (PHY_COMMON_STAT_AN_COMP | PHY_COMMON_STAT_LNK_STAT)){	  ns_link_print_changed();	  ns_link_update_egcr();		return;	}	/* run auto-negotation */	/* define what we are capable of */	ns_mii_write(PHY_COMMON_AUTO_ADV,		     PHY_COMMON_AUTO_ADV_100BTXFD |		     PHY_COMMON_AUTO_ADV_100BTX |		     PHY_COMMON_AUTO_ADV_10BTFD |		     PHY_COMMON_AUTO_ADV_10BT |		     PHY_COMMON_AUTO_ADV_802_3);	/* start auto-negotiation */	ns_mii_write(PHY_COMMON_CTRL,		     PHY_COMMON_CTRL_AUTO_NEG |		     PHY_COMMON_CTRL_RES_AUTO);	/* wait for completion */	while(1){		status = ns_mii_read(PHY_COMMON_STAT);		if((status & 		    (PHY_COMMON_STAT_AN_COMP | PHY_COMMON_STAT_LNK_STAT)) ==		   (PHY_COMMON_STAT_AN_COMP | PHY_COMMON_STAT_LNK_STAT)){			/* lucky we are, auto-negotiation succeeded */		  ns_link_print_changed();		  ns_link_update_egcr();			return;		}	}}static intns_link_init(void){        u16 val;	DEBUG_FUNC();	ns_link_auto_negotiate();        val = ns_mii_read(PHY_COMMON_STAT);        if(val & PHY_COMMON_STAT_LNK_STAT){                return 0;        }	return -1;}static int phy_init(void){  return ns_link_init();}void ns9750_enable_phy_module(void){}void ns9750_disable_phy_module(void){}int ns9750_eth_send(const eth_frame *ethfr,                    const void *pfr, const unsigned int pfrlen){  u32 txlen;  DEBUG_FUNC();  if(pfrlen + ETH_FRAME_LEN < 60){    safe_memset(txbuf, 0, 60);    txlen = 60;  }else{    txlen = pfrlen + ETH_FRAME_LEN;  }  if(txlen > LEN_TxBuf){    return -1;  }  safe_memcpy(&txbuf[0], ethfr, ETH_FRAME_LEN);  safe_memcpy(&txbuf[ETH_FRAME_LEN], pfr, pfrlen);  tx_desc = (tx_buffer_desc_t*)(NS_ETH_TXBD + NS9750_ETH_PHYS_BASE);  tx_desc->src = (unsigned int *)txbuf;  tx_desc->len = txlen;  tx_desc->s.reg = 0x00000000;  tx_desc->s.reg = 0xf0000000;  IO_ETH_TXPTR = 0;  IO_ETH_TXRPTR = 0;  IO_ETH_EGCR1 |= NS_ETH_EGCR1_ETXDMA;  IO_ETH_EGCR2 &= ~NS_ETH_EGCR2_TCLER;  IO_ETH_EGCR2 |= NS_ETH_EGCR2_TCLER;  while(!(tx_desc->s.reg & NS_ETH_ETSR_TXOK));  return 0;}int ns9750_eth_rxbuf_free(const int idx){  DEBUG_FUNC();  DEBUG_INFO("idx: %d\n", idx);  rx_desc[idx].s.bits.full = 0;  rx_desc[idx].s.bits.status = 0;  IO_ETH_RXFREE = (0x1 << idx);  IO_ETH_EINTR = (NS_ETH_EINTR_RXDONEA >> idx);  return 0;}int ns9750_eth_recv(const unsigned char *mac, eth_frame **ethfr,                    void **pbuf, unsigned int *pbuflen, int *timeout){  rx_buffer_desc_t *desc;  int idx;  u32 status;  DEBUG_FUNC();  while(1){    while(1){      status = IO_ETH_EINTR;      if(status & NS_ETH_EINTR_RXDONEA){	idx = 0;	break;      }else if(status & NS_ETH_EINTR_RXDONEB){	idx = 1;	break;      }else if(status & NS_ETH_EINTR_RXDONEC){	idx = 2;	break;      }else if(status & NS_ETH_EINTR_RXDONED){	idx = 3;	break;      }else{	*timeout -= 1;	if(*timeout < 0){ 	  return -1;	}	mdelay(1);      }    }    desc = (rx_buffer_desc_t *)&rx_desc[idx];        *ethfr = (eth_frame *)desc->src;    *pbuf  = (void *)((u32)desc->src + ETH_FRAME_LEN);    *pbuflen = desc->len - ETH_FRAME_LEN - 4;    if(safe_memcmp((*ethfr)->dmac, broadcast_mac, 6) == 0){      //DEBUG_INFO("broadcast packet detect\n");    }else if(safe_memcmp((*ethfr)->dmac, mac, 6) == 0){      //DEBUG_INFO("packet detect\n");    }else{      ns9750_eth_rxbuf_free(idx);      continue;    }    return idx;  }  return 0;}static int eth_indaddr_write(const unsigned char *mac){  	IO_ETH_SA1 = ((mac[5] << 8) | mac[4]);	IO_ETH_SA2 = ((mac[3] << 8) | mac[2]);	IO_ETH_SA3 = ((mac[1] << 8) | mac[0]);	return 0;}static int eth_reset(void){  unsigned long val;  DEBUG_FUNC();	/* Reset MAC */	IO_ETH_EGCR1 |= NS_ETH_EGCR1_MAC_HRST;	udelay(5);	IO_ETH_EGCR1 &= ~NS_ETH_EGCR1_MAC_HRST;	/* Reset and Initialize PHY */	IO_ETH_MAC1 &= ~NS_ETH_MAC1_SRST;		/* Set MDIO Clock */	IO_ETH_MCFG = NS_ETH_MCFG_CLKS_40;		/* Reset PHY */	val = ns_mii_read(PHY_COMMON_CTRL);	ns_mii_write(PHY_COMMON_CTRL, val | PHY_COMMON_CTRL_RESET);	udelay(350);	/* now take the highest MDIO clock possible after detection */	IO_ETH_MCFG = NS_ETH_MCFG_CLKS_40;	val = ns_mii_read(PHY_COMMON_ID1);	DEBUG_INFO("phy id1: %p\n", val);	val = ns_mii_read(PHY_COMMON_ID2);	DEBUG_INFO("phy id2: %p\n", val);	return 0;}static voidns9750_eth_update_rx_desc(void){	int timeout = 20;	IO_ETH_EGCR1 |= NS_ETH_EGCR1_ERXINIT;	/* [1] Tab. 221 states less than 5us */	while(--timeout && !(IO_ETH_EGSR & NS_ETH_EGSR_RXINIT))		/* wait for finish */		udelay(1);	if(!timeout)		hprintf("ethernet descriptor update failed\n");	/* @TODO do we need to clear RXINIT? */	IO_ETH_EGCR1 &= ~NS_ETH_EGCR1_ERXINIT;	/* all 4 descriptors free */	IO_ETH_RXFREE = 0xf;}static int eth_enable(void){	DEBUG_FUNC();	/* enable hardware */	/* enable receive and transmit FIFO, use 10/100 Mbps MII */	IO_ETH_EGCR1 = (		NS_ETH_EGCR1_ETXWM |		NS_ETH_EGCR1_ERX |		NS_ETH_EGCR1_ETX |#ifdef NS9750_RXALIGN		NS_ETH_EGCR1_RXALIGN |#endif		NS_ETH_EGCR1_PHY_MODE_MII |		NS_ETH_EGCR1_ITXA);	/* EINTR can only be reseted with ERX and ETX on */	IO_ETH_EINTR |= 0;	IO_ETH_MAC1 = NS_ETH_MAC1_RXEN;	/* the linux kernel may give packets < 60 bytes, for example arp */	IO_ETH_MAC2 = 		NS_ETH_MAC2_CRCEN | NS_ETH_MAC2_PADEN;	/* program the first descriptors for each ring. */	IO_ETH_RXAPTR = (unsigned long)&rx_desc[0];	IO_ETH_RXBPTR = (unsigned long)&rx_desc[1];	IO_ETH_RXCPTR = (unsigned long)&rx_desc[2];	IO_ETH_RXDPTR = (unsigned long)&rx_desc[3];	ns9750_eth_update_rx_desc();	IO_ETH_EGCR1 |= NS_ETH_EGCR1_ERXDMA;	/* clear statistics */       IO_ETH_EGCR2 = NS_ETH_EGCR2_CLRCNT;	/* enable statistics */	IO_ETH_EGCR2 = NS_ETH_EGCR2_AUTOZ | NS_ETH_EGCR2_STEN;	IO_ETH_SAFR |= NS_ETH_SAFR_BROAD ;  return 0;}static int queue_init(void){  int i;  DEBUG_FUNC();    for(i=0;i<4;i++){  rx_desc[i].s.reg = 0;  rx_desc[i].dest = 0;  rx_desc[i].src = (unsigned int *)&rxbuf[NS_ETH_FRAME_LEN * i];  rx_desc[i].len = NS_ETH_FRAME_LEN;  rx_desc[i].s.bits.wrap = 1;  //!((i + 1) % (NS_RX_DESC_RING)) ? 1 : 0;  rx_desc[i].s.bits.intr = 0;  rx_desc[i].s.bits.enable = 1;  rx_desc[i].s.bits.full = 0;  }  return 0;}int ns9750_eth_init(const unsigned char *ipaddr){  int ret;  hwif_eth hwif;  DEBUG_FUNC();    safe_memset(&hwif, 0, sizeof(hwif_eth));  hwif.enable_phy_module = ns9750_enable_phy_module;  hwif.disable_phy_module = ns9750_disable_phy_module;  hwif.eth_send = ns9750_eth_send;  hwif.eth_recv = ns9750_eth_recv;  hwif.eth_rxbuf_free = ns9750_eth_rxbuf_free;  safe_memcpy(&hwif.eth_ipaddr, ipaddr, 4);  arch_get_mac(hwif.eth_mac);  register_hwif_eth(&hwif);  enable_phy_module();    eth_reset();  ret = phy_init();  if(ret == -1){    hprintf("Link is down\n");    return -1;  }  eth_indaddr_write(hwif.eth_mac);  queue_init();  eth_enable();  return 0;}int ns9750_eth_shutdown(void){  DEBUG_FUNC();	IO_ETH_MAC1 &= ~NS_ETH_MAC1_RXEN;		IO_ETH_EGCR1 &= ~(NS_ETH_EGCR1_ERX |				      NS_ETH_EGCR1_ERXDMA |				      NS_ETH_EGCR1_ETX |				      NS_ETH_EGCR1_ETXDMA);		return 0;}

⌨️ 快捷键说明

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