/************************************************************************* * * Used with ICCARM and AARM. * * (c) Copyright IAR Systems 2006 * * File name : LPC23xx_enet.c * Description : MAC/DMA Controller with DMA (ENET) driver * * History : * 1. Date : December 14, 2006 * Author : Stanimir Bonev * Description : Create * * $Revision: 1.1.2.3 $ **************************************************************************/ #define __no_init /* Dummy for __no_init */ #include "LPC23xx.h" #include "types.h" #include "LPC23xx_enet.h" //#pragma segment="EMAC_DMA_RAM" //#pragma location="EMAC_DMA_RAM" //#pragma data_alignment=4 __no_init EnetDmaRxDesc_t EnetDmaRx[ENET_DMA_DESC_NUMB]__attribute__ ((section (".ethram"))) __attribute__((aligned (4))); //#pragma location="EMAC_DMA_RAM" //#pragma data_alignment=8 __no_init EnetDmaRxStatus_t EnetDmaRxSta[ENET_DMA_DESC_NUMB]__attribute__ ((section (".ethram"))) __attribute__((aligned (8))); //#pragma location="EMAC_DMA_RAM" //#pragma data_alignment=4 __no_init Int8U RxBuff0[EMAC_MAX_PACKET_SIZE]__attribute__ ((section (".ethram"))) __attribute__((aligned (4))); //#pragma location="EMAC_DMA_RAM" //#pragma data_alignment=4 __no_init Int8U RxBuff1[EMAC_MAX_PACKET_SIZE]__attribute__ ((section (".ethram"))) __attribute__((aligned (4))); //#pragma location="EMAC_DMA_RAM" //#pragma data_alignment=4 __no_init EnetDmaTxDesc_t EnetDmaTx[ENET_DMA_DESC_NUMB]__attribute__ ((section (".ethram"))) __attribute__((aligned (4))); //#pragma location="EMAC_DMA_RAM" //#pragma data_alignment=4 __no_init EnetDmaTxStatus_t EnetDmaTxSta[ENET_DMA_DESC_NUMB]__attribute__ ((section (".ethram"))) __attribute__((aligned (4))); //#pragma location="EMAC_DMA_RAM" //#pragma data_alignment=4 __no_init Int8U TxBuff0[EMAC_MAX_PACKET_SIZE]__attribute__ ((section (".ethram"))) __attribute__((aligned (4))); //#pragma location="EMAC_DMA_RAM" //#pragma data_alignment=4 __no_init Int8U TxBuff1[EMAC_MAX_PACKET_SIZE]__attribute__ ((section (".ethram"))) __attribute__((aligned (4))); static Int8U PhyAddr; /************************************************************************* * Function Name: * Parameters: None * * Return: Boolean * * Description: Init MAC/DMA Controller * *************************************************************************/ Boolean tapdev_init(void) { Int32U Reg,to,i; // Pins assignment PINMODE2 = 0xA02A220A; // P1[0,1,4,6,8,9,10,14,15] disable pu/pd PINMODE3 = 0x0000000A; // P1[17:16] disable pu/pd PINSEL2 = 0x50151105; // selects P1[0,1,4,6,8,9,10,14,15] PINSEL3 = 0x00000005; // selects P1[17:16] // clk enable // PCONP_bit.PCENET = 1; PCONP |= (1 << 30); /* Set Bit 30 (eth) in PCONP */ // POWERDOWN_bit.POWERDOWN = 0; MAC_POWERDOWN &=~(1 << 31); /* Clear Bit 31(powerdown) */ // Reset entire MAC MAC_MAC1 = 0x0000CF00; /* Reset entire MAC */ MAC_COMMAND = 0x0038; /* Reset all control registers */ MAC_MAC1 = 0; /* Clear entire MAC */ // COMMAND_bit.RMII = 1; MAC_COMMAND |= (1 << 9); /* Set Bit 9 (RMII) in CMD */ MAC_SUPP = 0; /* Clear PHY support register */ MAC_TEST = 0; /* Clear test register */ // write the station address registers MAC_SA0 = (UIP_ETHADDR1<<8) | UIP_ETHADDR0; MAC_SA1 = (UIP_ETHADDR3<<8) | UIP_ETHADDR2; MAC_SA2 = (UIP_ETHADDR5<<8) | UIP_ETHADDR4; MAC_MAXF = 0x600; /* Set maximum Frame */ MAC_MCFG = 0x8018; /* clk/20 */ MAC_MCMD = 0; /* Clear MCommand register */ // MIIM init // MCFG_bit.RSTMIIMGMT = 0; MAC_MCFG &=~(1 << 15); /* Clear RSTMIIMGMT Bit */ // descriptors init // MAC1_bit.RSTMCSTX = 1; MAC_MAC1 |= (1 << 9); /* Set Bit 9 (RSTMCSTX) in MAC1 */ // COMMAND_bit.TXENABLE = 0; MAC_COMMAND &=~(1 << 1); /* Clear Bit 1 (TXENABLE) */ // MAC1_bit.RSTTX = 1; MAC_MAC1 |= (1 << 8); /* Set Bit 8 (RSTTX) in MAC1 */ // COMMAND_bit.TXRESET = 1; MAC_COMMAND |= (1 << 4); /* Set Bit 4 (TXRESET) in MCMD */ // MAC1_bit.RSTMCSTX = 0; MAC_MAC1 &=~(1 << 9); /* Clear Bit 9 (RSTMCSTX) */ // MAC1_bit.RSTTX = 0; MAC_MAC1 &=~(1 << 8); /* Clear Bit 8 (RSTTX) in MAC1 */ // MAC1_bit.RE = 0; MAC_MAC1 &=~(1 << 0); /* Clear Bit 0 (RE) in MAC1 */ // MAC1_bit.RSTMCSRX = 1; MAC_MAC1 |= (1 << 11); /* Set Bit 11 (RSTMCSRX) in MAC1*/ // COMMAND_bit.RXENABLE = 0; MAC_COMMAND &=~(1 << 0); /* Clear Bit 0 (RXENABLE) */ // MAC1_bit.RSTRX = 1; MAC_MAC1 |= (1 << 10); /* Set Bit 10 (RSTRX) in MAC1 */ // COMMAND_bit.RXRESET = 1; MAC_COMMAND |= (1 << 5); /* Set Bit 5 (RXRESET) in MCMD */ // MAC1_bit.RSTMCSRX = 0; MAC_MAC1 &=~(1 << 11); /* Clear Bit 11 (RSTMCSRX) */ // MAC1_bit.RSTRX = 0; MAC_MAC1 &=~(1 << 10); /* Clear Bit 10 (RSTRX) */ MAC_RXDESCRIPTORNUM = ENET_DMA_DESC_NUMB-1; MAC_TXDESCRIPTORNUM = ENET_DMA_DESC_NUMB-1; // COMMAND_bit.PASSRUNTFRAME = 1; MAC_COMMAND |= (1 << 6); /* Set Bit 6 (PASSRUNTFRAME) */ // COMMAND_bit.PASSRXFILTER = 1; MAC_COMMAND |= (1 << 7); /* Set Bit 7 (PASSRXFILTER) */ // MAC1_bit.PARF = 1; MAC_MAC1 |= (1 << 1); /* Set bit 1 (PARF) in MAC1 */ MAC_MAC2 = 0x30; /* Set CRCEN & PADCRCEN in MAC2 */ // CLRT_bit.RM = 0xF; // CLRT_bit.CW = 0x37; MAC_CLRT = 0x0000370F; /* Set RM (0xF) and CW (0x3700) */ // IPGR_bit.IPGR2 = 0x12; // IPGR_bit.IPGR1 = 0x0c; MAC_IPGR = 0x00000C12; /*Set IPGR2(0x12) & IPGR1(0xC00)*/ MAC_IPGT = 0x12; /* Set IPGT register */ // MAC2_bit.FD = COMMAND_bit.FULLDUPLEX = 0; MAC_MAC2 &=~(1 << 0); /* Clear Bit 0 (FD) in MAC2 */ MAC_COMMAND &=~(1 << 10); /* Clear Bit 10 (FULLDUPLEX) */ // SUPP_bit.SPEED = 0; MAC_SUPP &=~(1 << 8); /* Clear Bit 8 (SPEED) in SUPP */ /* find PHY address */ for(PhyAddr = 1; PhyAddr < 32; ++PhyAddr) { /* See Micrel PHY KS8721 Users Manual for more details */ if((ENET_MIIReadRegister(PhyAddr, PHY_PHYIDR1) & 0xFFFF) != 0x0022) { continue; } if ((ENET_MIIReadRegister(PhyAddr, PHY_PHYIDR2) & 0xFFFF) == 0x1619) { break; } } if(PhyAddr == 32) { return(FALSE); } printf("PHY Address - %d\r\n",PhyAddr); ENET_MIIWriteRegister(PhyAddr,PHY_BMCR,BMCR_RESET); to = PHY_TO; while(to) { Reg = ENET_MIIReadRegister(PhyAddr,PHY_BMCR); if(!(Reg & BMCR_RESET)) { break; } } if(!to) { return(FALSE); } #ifdef TRACE_PHY Reg = ENET_MIIReadRegister(PhyAddr,0); printf("PHY_BMCR(0) - 0x%04X\n\r",Reg); Reg = ENET_MIIReadRegister(PhyAddr,1); printf("PHY_BMSR(1) - 0x%04X\n\r",Reg); Reg = ENET_MIIReadRegister(PhyAddr,0x4); printf("PHY_ANAR(4) - 0x%04X\n\r",Reg); Reg = ENET_MIIReadRegister(PhyAddr,0x5); printf("PHY_ANLPAR(5) - 0x%04X\n\r",Reg); Reg = ENET_MIIReadRegister(PhyAddr,0x6); printf("PHY_ANER(6) - 0x%04X\n\r",Reg); Reg = ENET_MIIReadRegister(PhyAddr,0x1f); printf("PHY_100PHY(1F) - 0x%04X\n\r",Reg); #endif // TRACE_PHY if(ENET_MIIReadRegister(PhyAddr,PHY_BMSR ) & BMSR_NOPREAM) { // PHY support preamble suppression MAC_MCFG |= 1 << 1; } #if AUTO_NEGOTIATION_ENA != 0 // PHY interrupt init, clear and enable // Set Auto-Negotiation Advertisement ENET_MIIWriteRegister(PhyAddr,PHY_ANAR, 1 | ANAR_10BT | ANAR_10BT_FULL | ANAR_100BT | ANAR_100BT_FULL); // Enable Auto-Negotiation Reg = BMCR_AN | BMCR_RE_AN; #else Reg = 0; if(FIX_DUPLEX == FULL_DUPLEX) { Reg |= BMCR_DUPLEX; } if(FIX_SPEED == SPEED_100) { Reg |= BMCR_SPEED_100; } #endif ENET_MIIWriteRegister(PhyAddr,PHY_BMCR,Reg); to = PHY_TO; while(to) { --to; if(ENET_MIIReadRegister(PhyAddr,PHY_BMSR) & BMSR_LINK_ESTABLISHED) { break; } } if(!to) { return(FALSE); } #ifdef TRACE_PHY Reg = ENET_MIIReadRegister(PhyAddr,0); printf("PHY_BMCR(0) - 0x%04X\n\r",Reg); Reg = ENET_MIIReadRegister(PhyAddr,1); printf("PHY_BMSR(1) - 0x%04X\n\r",Reg); Reg = ENET_MIIReadRegister(PhyAddr,0x4); printf("PHY_ANAR(4) - 0x%04X\n\r",Reg); Reg = ENET_MIIReadRegister(PhyAddr,0x5); printf("PHY_ANLPAR(5) - 0x%04X\n\r",Reg); Reg = ENET_MIIReadRegister(PhyAddr,0x6); printf("PHY_ANER(6) - 0x%04X\n\r",Reg); Reg = ENET_MIIReadRegister(PhyAddr,0x1f); printf("PHY_100PHY(1F) - 0x%04X\n\r",Reg); #endif // TRACE_PHY Reg = ENET_MIIReadRegister(PhyAddr,PHY_100PHY) & PHYCR_MODE; switch(Reg) { case 0x04: // 10 BASE T Half-duplex printf("10 BASE T Half-duplex\r\n"); Reg = 0; break; case 0x08: // 100 BASE TX Half-duplex printf("100 BASE TX Half-duplex\r\n"); Reg = BMCR_SPEED_100; // SUPP_bit.SPEED = 1; MAC_SUPP |= (1 << 8); /* Set Bit 8 (SPEED) in SUPP */ break; case 0x14: // 10 BASE T Full-duplex printf("10 BASE T Full-duplex\r\n"); Reg = BMCR_DUPLEX; MAC_IPGT = 0x15; // MAC2_bit.FD = COMMAND_bit.FULLDUPLEX = 1; MAC_MAC2 |= (1 << 0); /* Set Bit 0 (FD) in MAC2 */ MAC_COMMAND |= (1 << 10); /* Set Bit 10 (FULLDUPLEX) */ break; case 0x18: // 100 BASE TX Full-duplex printf("100 BASE TX Full-duplex\r\n"); Reg = BMCR_SPEED_100 | BMCR_DUPLEX; MAC_IPGT = 0x15; // MAC2_bit.FD = COMMAND_bit.FULLDUPLEX = 1; MAC_MAC2 |= (1 << 0); /* Set Bit 0 (FD) in MAC2 */ MAC_COMMAND |= (1 << 10); /* Set Bit 10 (FULLDUPLEX) */ // SUPP_bit.SPEED = 1; MAC_SUPP |= (1 << 8); /* Set Bit 8 (SPEED) in SUPP */ break; default: return(FALSE); } // Disable Auto-Negotiation and update speed and duplex settings ENET_MIIWriteRegister(PhyAddr,PHY_BMCR,Reg); to = PHY_TO; while(to) { --to; if(ENET_MIIReadRegister(PhyAddr,PHY_BMSR) & BMSR_LINK_ESTABLISHED) { break; } } if(!to) { return(FALSE); } for( i = 0; i < ENET_DMA_DESC_NUMB; ++i) { EnetDmaRx[i].EnetRxCtrl.Size = EMAC_MAX_PACKET_SIZE-1; EnetDmaRx[i].EnetRxCtrl.Intr = 1; EnetDmaRxSta[i].Data[0] = EnetDmaRxSta[i].Data[1] = 0; EnetDmaTx[i].EnetTxCtrl.Data = (1<<31) | (1<<30) | (1<<29) | (1<<28) | (1<<26) | (EMAC_MAX_PACKET_SIZE-1); EnetDmaTxSta[i].Data = 0; } EnetDmaRx[0].pBuffer = (pInt32U)RxBuff0; EnetDmaRx[1].pBuffer = (pInt32U)RxBuff1; EnetDmaTx[0].pBuffer = (pInt32U)TxBuff0; EnetDmaTx[1].pBuffer = (pInt32U)TxBuff1; MAC_RXCONSUMEINDEX = 0; MAC_TXPRODUCEINDEX = 0; MAC_TXDESCRIPTOR = (Int32U)EnetDmaTx; MAC_TXSTATUS = (Int32U)EnetDmaTxSta; MAC_RXDESCRIPTOR = (Int32U)EnetDmaRx; MAC_RXSTATUS = (Int32U)EnetDmaRxSta; // COMMAND_bit.RXENABLE = 1; MAC_COMMAND |= (1 << 0); /* Set Bit 0 (RXENABLE) in CMD */ // MAC1_bit.RE = 1; MAC_MAC1 |= (1 << 0); /* Set Bit 0 (RE) in MAC1 */ // COMMAND_bit.TXENABLE = 1; MAC_COMMAND |= (1 << 1); /* Set Bit 1 (TXENABLE) in CMD */ return(TRUE); } /************************************************************************* * Function Name: tapdev_read * Parameters: * Return: * * Description: Read data for MAC/DMA Controller * *************************************************************************/ Int32U tapdev_read(void * pPacket) { Int32U Indx = MAC_RXCONSUMEINDEX; Int32U Size = EMAC_MAX_PACKET_SIZE; if(Indx == MAC_RXPRODUCEINDEX) { return(0); } Size = MIN(Size,(EnetDmaRxSta[Indx].RxSize+1)); memcpy(pPacket,EnetDmaRx[Indx].pBuffer,Size); if(++Indx > MAC_RXDESCRIPTORNUM) { Indx = 0; } MAC_RXCONSUMEINDEX = Indx; return(Size); } /************************************************************************* * Function Name: tapdev_send * Parameters: * Return: Boolean * * Description: Send data to MAC/DMA Controller * *************************************************************************/ Boolean tapdev_send(void *pPacket, Int32U size) { Int32U Indx, IndxHold = MAC_TXPRODUCEINDEX + 1; if(size == 0) { return(TRUE); } if(IndxHold > MAC_TXDESCRIPTORNUM) { IndxHold = 0; } if(IndxHold == MAC_TXCONSUMEINDEX) { return(FALSE); } Indx = MAC_TXPRODUCEINDEX; size = MIN(size,EMAC_MAX_PACKET_SIZE); memcpy(EnetDmaTx[Indx].pBuffer,pPacket,size); EnetDmaTx[Indx].EnetTxCtrl.Size = size - 1; MAC_TXPRODUCEINDEX = IndxHold; return(TRUE); } /************************************************************************* * Function Name: ENET_MIIWriteRegister * Parameters: Int8U DevId, Int8U RegAddr, Int32U Value * Return: none * * Description: Writes a value on the PHY registers * *************************************************************************/ static void ENET_MIIWriteRegister (Int8U DevId, Int8U RegAddr, Int32U Value) { MAC_MCMD = 0; /* set read operation */ // MADR_bit.PHY_ADDR = DevId; MAC_MADR = MAC_MADR & 0xFFFFE0E0; /* Reset PHY_ADDR and REG_ADDR */ MAC_MADR |= (DevId << 8) | (RegAddr << 0); /* Set PHY_ADDR and REG_ADDR */ // \TODO is this working?? MAC_MWTD = Value; // while(MIND_bit.BUSY); while (MAC_MIND & (1 << 0)); // \TODO is this working?? } /************************************************************************* * Function Name: ENET_MIIReadRegister * Parameters: Int8U DevId, Int8U RegAddr, Int32U Value * Return: Int32U * * Description: Read a value from the PHY registers * *************************************************************************/ static Int32U ENET_MIIReadRegister (Int8U DevId, Int8U RegAddr) { MAC_MCMD = 0; // MADR_bit.PHY_ADDR = DevId; // set the MII Physical address // MADR_bit.REGADDR = RegAddr; // set the MII register address MAC_MADR = MAC_MADR & 0xFFFFE0E0; /* Reset PHY_ADDR and REG_ADDR */ MAC_MADR |= (DevId << 8) | (RegAddr << 0); /* Set PHY_ADDR and REG_ADDR */ // \TODO is this working?? MAC_MCMD = 1; // set read operation // while(MIND_bit.BUSY | MIND_bit.NOT_VALID); while (MAC_MIND & (5 << 0)); // \TODO is this working?? return(MAC_MRDD); }