SYSCONFIG->KICKR[0] = KICK0R_UNLOCK;
SYSCONFIG->KICKR[1] = KICK1R_UNLOCK;
CLRBIT(SYSCONFIG->CFGCHIP[3], 0x00000100); //select mii mode !
//as software reset consideration, do this here
EVMOMAPL138_lpscTransition(PSC1, DOMAIN0, LPSC_EMAC, PSC_ENABLE);
// clear MAC control register, receive control register, transmiter control register
EMAC->MACCONTROL = 0;
EMAC->RXCONTROL = 0;
EMAC->TXCONTROL = 0;
// init header descriptor pointer regs to 0.
for (i = 0; i < 8; i++)
{
EMAC->TXHDP = 0;
EMAC->RXHDP = 0;
}
// clear all statistic register
#ifndef BOOT
memset((uint8_t *)NET_STAT_REG_BASE, 0, NET_STAT_REG_NUM_BYTES);
#endif
// setup local MAC address, only channel 0 is valid.
// program all 8, only need to set MACADDRHI for index = 0.
// use duplicate address for all unused channels.
// TODO: read MAC address from SPI flash.
//写的顺序是MACINDEX, ADDRHI, ADDRLO,由于高40bits是共享的
//只用了通道0,EMAC->MACADDRLO = 0X000000506 |VALID|MATCHFILT
for (i = 1; i < 8; i++)
{
EMAC->MACINDEX = i;
EMAC->MACADDRHI = 0x42020304; //index -> hi -> lo
EMAC->MACADDRLO = 0x00000506;
}
EMAC->MACINDEX = 0;
EMAC->MACADDRHI = 0x42020304;
// channel bit = 0, match mac address = 1
EMAC->MACADDRLO = 0x00000506 | MACADDRLO_VALID | MACADDRLO_MATCHFILT;
// for use tx DMA descriptor configuration:
EMAC->MACSRCADDRHI = 0x42020304;
EMAC->MACSRCADDRLO = 0x00000506;
// initialize receive channel free buffer count regs, if buffer flow
// control is to be enabled.
// NOTE: this example does not use buffer flow control.
// enable unicast chan 0 only.
EMAC->RXUNICASTSET = 0x01;
// no multicast addresses, clear MAC address hash registers.
EMAC->MACHASH1 = 0;
EMAC->MACHASH2 = 0;
// 只允许broadcast的ARP数据包,和发给自己的包,以太网的其他数据不放入Memmory里去.
//但是我单独设置RxBroadEn却没有作用。
EMAC->RXMBPENABLE = 0;
SETBIT(EMAC->RXMBPENABLE, (RXBROADEN|RXCAFEN));
// EMAC->RXMBPENABLE = 0x01E02020; //enable reception of almost all frames inc error
//11. configure MACCONTROL (Don't set GMIIEN Bit)
SETBIT(EMAC->MACCONTROL, (RMIISPEED|FULLDUPLEX|TXPACE)); //RMII_SPEED,为了适应RMII
// 12. Clear all unused channel interrupt bits by writing the receive interrupt mask clear register
//(RXINTMASKCLEAR) and the transmit interrupt mask clear register (TXINTMASKCLEAR).
EMAC->RXINTMASKCLEAR |= 0xFE; //RX channel 0的中断不屏蔽
EMAC->TXINTMASKCLEAR |= 0xFE; //TX CH0 中断屏蔽
//13. Modify RXINTMASKSET, TXINTMASKSET,MACINTMASKSET
EMAC->RXINTMASKSET |= 0x01;
EMAC->TXINTMASKSET |= 0x01;
EMAC->MACINTMASKCLR = 0x03; //disabled host mask , stat interrupt
//14 init receive buffer offset and max length.
EMAC->RXBUFFEROFFSET = 0;
EMAC->RXMAXLEN = MAX_PACKET_SIZE;
// initialize receive/transmit descriptor list queues.
Emac_des_init(); //modify 04/18
//16 enable receive / transmit DMA controllers...set GMIIEN.
EMAC->RXCONTROL = 1;
EMAC->TXCONTROL = 1;
SETBIT(EMAC->MACCONTROL, GMIIEN );
#if 1 //文档说未经测试,删除貌似没效果啊,先不管它
SETBIT(EMAC->EMCONTROL, SOFT);
#endif
// -->& init mdio / phy, 再加上MAC中断
//-----------------
rtn = initMdioPhy();
// if (rtn != ERR_NO_ERROR)
// return (rtn);
SYS_ARCH_UNPROTECT(sr);
//17>Enable the device interrupt in EMAC control module registers CnRXTHRESHEN, CnRXEN, CnTXEN,
//and CnMISCEN. -- LP Add
EMAC_CTRL->C0RXEN = 1; //C0RXPULSE Is Enabled for RX channel 0
EMAC_CTRL->C0TXEN = 1; //C0TXPULSE IS enabled for tx channel 0
return (rtn);
}
//-----------------------------------------------------------------------------
// \brief power on the phy.
//
// \param none.
//
// \return uint32_t
// ERR_NO_ERROR - everything is ok...phy is on.
// ERR_FAIL - something happened and could not power on.
//-----------------------------------------------------------------------------
uint32_t EMAC_phyPowerOn(void)
{
uint32_t rtn;
uint16_t ctrl_reg;
ctrl_reg = phyRegRead(g_active_phy_id, SMSC_REG_BASIC_CTRL);
if (!CHKBIT(ctrl_reg, BASIC_CTRL_POWER_DOWN))
{
// phy is already on...nothing left to do.
#if DEBUG
printf("phy powered, basic ctrl reg: %04x\n", ctrl_reg);
#endif
rtn = ERR_NO_ERROR;
}
else
{
// clear power down bit and write back to phy.
CLRBIT(ctrl_reg, BASIC_CTRL_POWER_DOWN);
phyRegWrite(g_active_phy_id, SMSC_REG_BASIC_CTRL, ctrl_reg);
// short delay, then read the reg back to verify loopback is enabled.
USTIMER_delay(500);
ctrl_reg = phyRegRead(g_active_phy_id, SMSC_REG_BASIC_CTRL);
if (!CHKBIT(ctrl_reg, BASIC_CTRL_POWER_DOWN))
{
// phy is powered...return success.
#if DEBUG
printf("phy powered, basic ctrl reg: %04x\n", ctrl_reg);
#endif
rtn = ERR_NO_ERROR;
}
else
{
// power down bit did not clear...return error.
#if DEBUG
printf("power down did not clear: %04x\n", ctrl_reg);
#endif
rtn = ERR_FAIL;
}
}
return (rtn);
}
//-----------------------------------------------------------------------------
// \brief power down the phy.
//
// \param none.
//
// \return uint32_t
// ERR_NO_ERROR - everything is ok...phy is powered down.
// ERR_FAIL - something happened and could not power down.
//-----------------------------------------------------------------------------
uint32_t EMAC_phyPowerDown(void)
{
uint32_t rtn;
uint16_t ctrl_reg;
ctrl_reg = phyRegRead(g_active_phy_id, SMSC_REG_BASIC_CTRL);
if(CHKBIT(ctrl_reg, BASIC_CTRL_ISOLATE) && CHKBIT(ctrl_reg, BASIC_CTRL_POWER_DOWN))
{
// phy is already powered down...nothing left to do.
#if DEBUG
printf("phy powered down, basic ctrl reg: %04x\n", ctrl_reg);
#endif
rtn = ERR_NO_ERROR;
}
else
{
// set power down bit and write back to phy.
SETBIT(ctrl_reg, BASIC_CTRL_ISOLATE | BASIC_CTRL_POWER_DOWN);
phyRegWrite(g_active_phy_id, SMSC_REG_BASIC_CTRL, ctrl_reg);
// short delay, then read the reg back to verify loopback is disabled.
USTIMER_delay(500);
ctrl_reg = phyRegRead(g_active_phy_id, SMSC_REG_BASIC_CTRL);
if(CHKBIT(ctrl_reg, BASIC_CTRL_ISOLATE) && CHKBIT(ctrl_reg, BASIC_CTRL_POWER_DOWN))
{
// phy is powered down...return success.
#if DEBUG
printf("phy powered down, basic ctrl reg: %04x\n", ctrl_reg);
#endif
rtn = ERR_NO_ERROR;
}
else
{
// power down bit did not set...return error.
#if DEBUG
printf("power down bit did not set: %04x\n", ctrl_reg);
#endif
rtn = ERR_FAIL;
}
}
return (rtn);
}
//-----------------------------------------------------------------------------
// \brief put the phy into loopback mode.
//
// \param none.
//
// \return uint32_t
// ERR_NO_ERROR - everything is ok...phy is in loopback mode.
// ERR_FAIL - something happened and could not enter loopback.
//-----------------------------------------------------------------------------
uint32_t EMAC_phyEnterLoopback(void)
{
uint32_t rtn;
uint16_t ctrl_reg;
ctrl_reg = phyRegRead(g_active_phy_id, SMSC_REG_BASIC_CTRL);
rtn = ERR_NO_ERROR;
if (ctrl_reg & BASIC_CTRL_LOOPBACK)
{
// loopback is already enabled...nothing left to do.
#if DEBUG
printf("loopback enabled, basic ctrl reg: %04x\n", ctrl_reg);
#endif
rtn = ERR_NO_ERROR;
}
else
{
// set loopback bit and write back to phy.
ctrl_reg |= BASIC_CTRL_LOOPBACK;
phyRegWrite(g_active_phy_id, SMSC_REG_BASIC_CTRL, ctrl_reg);
// short delay, then read the reg back to verify loopback is enabled.
USTIMER_delay(500);
ctrl_reg = phyRegRead(g_active_phy_id, SMSC_REG_BASIC_CTRL);
if (ctrl_reg & BASIC_CTRL_LOOPBACK)
{
// loopback is enabled...return success.
#if DEBUG
printf("loopback enabled , basic ctrl reg: %04x\n", ctrl_reg);
#endif
rtn = ERR_NO_ERROR;
}
else
{
// loopback bit did not get set...return error.
#if DEBUG
printf("loopback did not set: %04x\n", ctrl_reg);
#endif
rtn = ERR_FAIL;
}
}
return (rtn);
}
//-----------------------------------------------------------------------------
// \brief remove the phy from loopback mode.
//
// \param none.
//
// \return uint32_t
// ERR_NO_ERROR - everything is ok...phy is out of loopback mode.
// ERR_FAIL - something happened and could not disable loopback.
//-----------------------------------------------------------------------------
uint32_t EMAC_phyExitLoopback(void)
{
uint32_t rtn;
uint16_t ctrl_reg;
ctrl_reg = phyRegRead(g_active_phy_id, SMSC_REG_BASIC_CTRL);
if (!(ctrl_reg & BASIC_CTRL_LOOPBACK))
{
// loopback is already disabled...nothing left to do.
#if DEBUG
printf("loopback disabled, basic ctrl reg: %04x\n", ctrl_reg);
#endif
rtn = ERR_NO_ERROR;
}
else
{
// clear loopback bit and write back to phy.
ctrl_reg &= ~BASIC_CTRL_LOOPBACK;
phyRegWrite(g_active_phy_id, SMSC_REG_BASIC_CTRL, ctrl_reg);
// short delay, then read the reg back to verify loopback is disabled.
USTIMER_delay(5);
ctrl_reg = phyRegRead(g_active_phy_id, SMSC_REG_BASIC_CTRL);
if (!(ctrl_reg & BASIC_CTRL_LOOPBACK))
{
// loopback is disabled...return success.
#if DEBUG
printf("loopback disabled , basic ctrl reg: %04x\n", ctrl_reg);
#endif
rtn = ERR_NO_ERROR;
}
else
{
// loopback bit did not clear...return error.
#if DEBUG
printf("loopback did not clear: %04x\n", ctrl_reg);
#endif
rtn = ERR_FAIL;
}
}
return (rtn);
}
//-----------------------------------------------------------------------------
// Private Function Definitions
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// initialize the mdio module and identify the active phy.
//-----------------------------------------------------------------------------
uint32_t initMdioPhy(void)
{
uint32_t i = 0;
uint16_t phy_reg;
// init the mdio regs.
MDIO->CONTROL = MDIO_CTRL_ENABLE |
MDIO_CTRL_FAULT |
MDIO_CTRL_FAULTENB |
MDIO_CLK_DIVISOR;
while (CHKBIT(MDIO->CONTROL, MDIO_CTRL_IDLE)) {;}
#if DEBUG_MDIO_LINK
// look for an active phy...takes up to 50 us for each phy to be checked.
//以下只是调试时有用,真正烧入程序中去时,是不行的,因为没插上网线,AddISR还要上的。
for (i = 0; i < MAX_POLLING_NUM; i++)
{
if (MDIO->ALIVE)
{
// at least one phy has acknowledged us...break the loop.
break;
}
USTIMER_delay(50); // polling , 采用polling方式,LP- delete
}
while(!(MDIO->ALIVE)); //还是没有找到PHY,它就在此处挂住
#else
while(!(MDIO->ALIVE)) //没有网线连接
{
i++;
if(i >= MAX_POLLING_NUM)
{
break;
}
}//只是为了延时让phy与PC自适应的时涞却??
#endif
//
g_active_phy_id = 0; //确实是个发生错误,现在可以读到PHY。
MDIO->USERPHYSEL0 = 0; //USERPHYSEL0 = 0,表示PHY0被选中监控。
#if DEBUG_MDIO_LINK
phy_reg = phyRegRead(g_active_phy_id,0x02); //phy-id,查看phyRegRead是否正确;
if(phy_reg != 0x0022) //不等则芯片焊错
{
while(1);
}
#endif
return (ERR_NO_ERROR);
}
//-----------------------------------------------------------------------------
// returns if the link is currently active...1 -> active, 0 -> not active.
//-----------------------------------------------------------------------------
uint8_t isLinkActive(uint8_t in_phy)
{
uint16_t status;
status = phyRegRead(in_phy, SMSC_REG_BASIC_STAT);
if (CHKBIT(status, BASIC_STAT_LINK_STAT))
return (1);
else
return (0);
}
//-----------------------------------------------------------------------------
// read a phy register using the MDIO.
//-----------------------------------------------------------------------------
uint16_t phyRegRead(uint8_t in_phy, uint8_t in_reg)
{
// make sure mdio is not busy.
while (CHKBIT(MDIO->USERACCESS0, USERACC_GO)) {}
MDIO->USERACCESS0 = USERACC_GO |
(in_reg << USERACC_SHIFT_REG) |
(in_phy << USERACC_SHIFT_PHY);
while (CHKBIT(MDIO->USERACCESS0, USERACC_GO)) {}
return ((uint16_t)(MDIO->USERACCESS0 & USERACC_MASK_DATA));
}
//-----------------------------------------------------------------------------
// write a phy register using the MDIO.
//-----------------------------------------------------------------------------
void phyRegWrite(uint8_t in_phy, uint8_t in_reg, uint16_t in_data)
{
// make sure mdio is not busy.
while (CHKBIT(MDIO->USERACCESS0, USERACC_GO)) {}
MDIO->USERACCESS0 = USERACC_GO |
USERACC_WRITE |
(in_reg << USERACC_SHIFT_REG) |
(in_phy << USERACC_SHIFT_PHY) |
in_data;
}
/* If the earlier pbuf ended, update the chain */
if(pbuf->next == NULL) {
pbuf->next = (struct pbuf*)(curr_bd->next)->pbuf;
} //if Null
//len_to_alloc , pbuf链中的len的总和
len_to_alloc += pbuf->len;
/* Update the len and tot_len fields for the pbuf in the chain*/
pbuf->len = (curr_bd->bufoff_len) & 0xFFFF; //当前pbuf长度
pbuf->tot_len = tot_len - ex_len ; //当前pbuf后的tot_len长度(含自己)
processed_bd = curr_bd; //处理中的desc
ex_len += pbuf->len;
curr_bd = curr_bd->next;
} while((processed_bd->flags_pktlen & CPDMA_BUF_DESC_EOP)
!= CPDMA_BUF_DESC_EOP);
/**
* Close the chain for this pbuf. A full packet is received in
* this pbuf chain. Now this pbuf can be given to upper layers for
* processing. The start of the pbuf chain is now 'q'.
*/
pbuf->next = (struct pbuf *)NULL;
/**
* The earlier pbuf chain is freed from the upper layer. So, we need to
* allocate a new pbuf chain and update the descriptors with the pbuf info.
* To support chaining, the total length freed by the upper layer is tracked.
* Care should be taken even if the allocation fails.
*/
/**
* now len_to_alloc will contain the length of the pbuf which was freed
* from the upper layer
*/
rxch->freed_pbuf_len += len_to_alloc;
new_pbuf = pbuf_alloc(PBUF_RAW, ((rxch->freed_pbuf_len)+ETH_PAD_SIZE), PBUF_POOL);
/* Write the descriptors with the pbuf info till either of them expires */
if(new_pbuf != NULL) {
#if ETH_PAD_SIZE
pbuf_header((struct pbuf *)new_pbuf, -ETH_PAD_SIZE);
#endif //ETH_PAD_SIZE
curr_bd = rxch->free_head; //free_head,已经被释放的head,需要重新set
//以下循环体添加新的pbuf到curr_bd中去
for(q = new_pbuf; (q != NULL) && (curr_bd != rxch->active_head); q = q->next) {
curr_bd->bufptr = (u32_t)(q->payload);
/* no support for buf_offset. RXBUFFEROFFEST register is 0 */
curr_bd->bufoff_len = (q->len) & 0xFFFF;
curr_bd->flags_pktlen = CPDMA_BUF_DESC_OWNER;
rxch->freed_pbuf_len -= q->len;
/* Save the pbuf */
curr_bd->pbuf = q;
last_bd = curr_bd;
curr_bd = curr_bd->next;
}//for
/**
* At this point either pbuf expired or no rxbd to allocate. If
* there are no, enough rx bds to allocate all pbufs in the chain,
* free the rest of the pbuf
*/
if(q != NULL) {
pbuf_free((struct pbuf *)q);
}
/**
* Check if the reception has ended. If the EOQ flag is set, the NULL
* Pointer is taken by the DMA engine. So we need to write the RX HDP
* with the next descriptor.
*/
if(curr_tail->flags_pktlen & CPDMA_BUF_DESC_EOQ) {
// CPSWCPDMARxHdrDescPtrWrite(sitaraif->cpsw_cpdma_base,
// (u32_t)(rxch->free_head), 0);
EMAC->RXHDP[0] = (u32_t)(rxch->free_head);
}//if EOQ
rxch->free_head = curr_bd;
rxch->active_tail = last_bd;
}//if new_pbuf
}//if OWNER
curr_bd = rxch->active_head;
//以下这句,L138未做要求.
// CPSWCPDMANumFreeBufSet(sitaraif->cpsw_cpdma_base, 0, 1);
// -----------括号不要删-------------------------------
}//While ....
//-------------------------------------------
// 以下在外面写
// CPSWCPDMAEndOfIntVectorWrite(sitaraif->cpsw_cpdma_base, CPSW_EOI_TX_PULSE);
// CPSWCPDMAEndOfIntVectorWrite(sitaraif->cpsw_cpdma_base, CPSW_EOI_RX_PULSE);
}
//---------------------------------------------------------------
//以下是发送部分
//---------------------------------------------------------------
/**
** 这个函数将pbuf链的数据发送给物理层,可能buffer_des连接多处,因为是
** pbuf链连接而成的
* @return None
**/
void Emac_transmit(struct pbuf *pbuf) {
struct pbuf *q;
struct txch *txch;
volatile struct cpdma_tx_bd *curr_bd, *active_head, *bd_end;
// 取地址。
txch = &(emac_trif.txch);
//得到可以使用的空闲head
curr_bd = txch->free_head;
//激活的head
active_head = curr_bd;
//更新该头的packet len 字段
curr_bd->flags_pktlen &= ~0xFFFF;
curr_bd->flags_pktlen |= pbuf->tot_len;
//交给EMAC之前,置位flags, SOP,OWNER
curr_bd->flags_pktlen |= (CPDMA_BUF_DESC_SOP | CPDMA_BUF_DESC_OWNER);
//把pbuf信息构建成buffer desc 链
for(q = pbuf; q != NULL; q = q->next) {
/* Intialize the buffer pointer and length */
curr_bd->bufptr = (u32_t)(q->payload);
curr_bd->bufoff_len = (q->len) & 0xFFFF;
bd_end = curr_bd;
curr_bd->pbuf = pbuf;
curr_bd = curr_bd->next;
}
//将buffer desc结尾
bd_end->next = (volatile struct cpdma_tx_bd *)NULL;
bd_end->flags_pktlen |= CPDMA_BUF_DESC_EOP;
//free_head指向下一个空的buff descriptor 处
txch->free_head = curr_bd;
//经过初始化之后,txch->active_tail指向NULL,但是发送buffer desc是一个
//单向的循环链表。所以这也是上面为什么bd_end->next要赋NULL值
if(txch->active_tail == NULL) {
// 第一次发送active_head
EMAC->TXHDP[0] = (u32_t)active_head;
}
/*
**第1次发送过后,假如发送完了,那么transmiter 将会halt,这样CPU在
**发送之前必须确认EOQ是否set,如果set,那么对于CPU来讲可以写HDP启动
**TXDMA发送了。
*/
else {
curr_bd = txch->active_tail;
curr_bd->next = active_head;
if(curr_bd->flags_pktlen & CPDMA_BUF_DESC_EOQ) {
//假如EOQ被EMAC set之后,就启动tx DMA
EMAC->TXHDP[0] = (u32_t)active_head;
}
}
txch->active_tail = bd_end;
}
/**
* This function will send a packet through the emac if the channel is
* available. Otherwise, the packet will be queued in a pbuf queue.
*
* @param netif the lwip network interface structure for this ethernetif
* @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
* @return ERR_OK if the packet could be sent
* an err_t value if the packet couldn't be sent
*
*/
err_t
OmapEmac_output(struct netif *netif, struct pbuf *p)
{
INT8U os_err = 0;
SYS_ARCH_DECL_PROTECT(lev);
//等待有效的信号量才能发送
// OSSemPend(TxCmpSem, 1000, &os_err); // --LP , 2012/04/28 DLT
/**
* This entire function must run within a "critical section" to preserve
* the integrity of the transmit pbuf queue.
*
*/
SYS_ARCH_PROTECT(lev);
//在选择发送之前,要调整p->payload的两字节,因为它们不能发送出去
#if ETH_PAD_SIZE
pbuf_header(p, -ETH_PAD_SIZE);
#endif
/* adjust the packet length if less than minimum required */
if(p->tot_len < MIN_PKT_LEN) {
p->tot_len = MIN_PKT_LEN;
p->len = MIN_PKT_LEN;
}
/**
* Bump the reference count on the pbuf to prevent it from being
* freed till we are done with it.
*
*/
pbuf_ref(p);
//Emac物理层的发送。DMA 用了TX中断的方式
Emac_transmit(p);
/* Return to prior interrupt state and return. */
SYS_ARCH_UNPROTECT(lev);
/* Check for correct start of packet */
while((curr_bd->flags_pktlen) & CPDMA_BUF_DESC_SOP) {
/* Make sure that the transmission is over */
while((curr_bd->flags_pktlen & CPDMA_BUF_DESC_OWNER)
== CPDMA_BUF_DESC_OWNER);
/* Traverse till the end of packet is reached */
while(((curr_bd->flags_pktlen) & CPDMA_BUF_DESC_EOP) != CPDMA_BUF_DESC_EOP) {
curr_bd = curr_bd->next;
}//while(!EOP)
next_bd_to_process->flags_pktlen &= ~(CPDMA_BUF_DESC_SOP);
curr_bd->flags_pktlen &= ~(CPDMA_BUF_DESC_EOP);
/**
* If there are no more data transmitted, the next interrupt
* shall happen with the pbuf associated with the free_head
*/
if(curr_bd->next == NULL) {
txch->next_bd_to_process = txch->free_head;
}
Adds your network interface to the netif_list. Allocate a struct
netif and pass a pointer to this structure as the first argument.
Give pointers to cleared ip_addr structures when using DHCP,
or fill them with sane numbers otherwise. The state pointer may be NULL.
The init function pointer must point to a initialization function for
your ethernet netif interface. The following code illustrates it's use.*/
netif_add(&main_net, &ipaddr, &netmask, &gw, NULL, ðernetif_init, &tcpip_input);
/* Registers the default network interface.*/
netif_set_default(&main_net); //可以删除 --2012/02/02, netif_default
/* When the netif is fully configured this function must be called.*/
netif_set_up(&main_net); //this functional
}