Igor Skochinsky
/
EasyWebCR
code_red's port of EasyWeb server for LPC1768, made to compile with mbed's online compiler.
ethmac.c
- Committer:
- igorsk
- Date:
- 2010-01-29
- Revision:
- 0:12b53511e212
File content as of revision 0:12b53511e212:
/****************************************************************** ***** ***** ***** Name: cs8900.c ***** ***** Ver.: 1.0 ***** ***** Date: 07/05/2001 ***** ***** Auth: Andreas Dannenberg ***** ***** HTWK Leipzig ***** ***** university of applied sciences ***** ***** Germany ***** ***** adannenb@et.htwk-leipzig.de ***** ***** Func: ethernet packet-driver for use with LAN- ***** ***** controller CS8900 from Crystal/Cirrus Logic ***** ***** ***** ******************************************************************/ // Modifications by Code Red Technologies for NXP LPC1776 // Filename changed to ethmac.c as no longer for cs8900 // CodeRed - updated include to match new filename #include "mbed.h" #include "ethmac.h" // CodeRed - add additional includes #include "tcpip.h" // CodeRed - new static pointers for receive and transmit static unsigned short *rxptr; static unsigned short *txptr; // CodeRed - function added to write to external ethernet PHY chip void WriteToPHY (int reg, int writeval) { unsigned int loop; // Set up address to access in MII Mgmt Address Register LPC_EMAC->MADR = DP83848C_DEF_ADR | reg; // Write value into MII Mgmt Write Data Register LPC_EMAC->MWTD = writeval; // Loop whilst write to PHY completes for (loop = 0; loop < MII_WR_TOUT; loop++) { if ((LPC_EMAC->MIND & MIND_BUSY) == 0) { break; } } } // CodeRed - function added to read from external ethernet PHY chip unsigned short ReadFromPHY (unsigned char reg) { unsigned int loop; // Set up address to access in MII Mgmt Address Register LPC_EMAC->MADR = DP83848C_DEF_ADR | reg; // Trigger a PHY read via MII Mgmt Command Register LPC_EMAC->MCMD = MCMD_READ; // Loop whilst read from PHY completes for (loop = 0; loop < MII_RD_TOUT; loop++) { if ((LPC_EMAC->MIND & MIND_BUSY) == 0) { break; } } LPC_EMAC->MCMD = 0; // Cancel read // Returned value is in MII Mgmt Read Data Register return (LPC_EMAC->MRDD); } // CodeRed - Init8900() replaced by Init_EthMAC() /* // configure port-pins for use with LAN-controller, // reset it and send the configuration-sequence // (InitSeq[]) void Init8900(void) { unsigned int i; P3SEL = 0x30; // reserve P3.4 and P3.5 for rs232 P3OUT = IOR | IOW; // reset outputs, control lines high P3DIR = 0xFF; // port 3 as output (all pins but rs232) P5SEL = 0; // select standard port functions P5OUT = 0; // reset outputs P5DIR = 0xFF; // switch data port to output Write8900(ADD_PORT, PP_SelfCTL); Write8900(DATA_PORT, POWER_ON_RESET); // Reset the Ethernet-Controller Write8900(ADD_PORT, PP_SelfST); while (!(Read8900(DATA_PORT) & INIT_DONE)); // wait until chip-reset is done for (i = 0; i < sizeof InitSeq / sizeof (TInitSeq); i++) // configure the CS8900 { Write8900(ADD_PORT, InitSeq[i].Addr); Write8900(DATA_PORT, InitSeq[i].Data); } } */ // Ethernet power/clock control bit in PCONP register #define PCENET 0x40000000 // Ethernet configuration for PINSEL2, as per user guide section 5.3 #define ENET_PINSEL2_CONFIG 0x50150105 // Ethernet configuration for PINSEL3, as per user guide section 5.4 #define ENET_PINSEL3_CONFIG 0x00000005 // Only bottom byte of PINSEL3 relevant to Ethernet #define ENET_PINSEL3_MASK 0x0000000F void Init_EthMAC(void) { unsigned int loop, value, phyid1, phyid2; unsigned phy_in_use = 0; unsigned phy_linkstatus_reg; unsigned phy_linkstatus_mask; // Set Ethernet power/clock control bit LPC_SC->PCONP |= PCENET; //Enable Ethernet pins through PINSEL registers LPC_PINCON->PINSEL2 = ENET_PINSEL2_CONFIG; LPC_PINCON->PINSEL3 = (LPC_PINCON->PINSEL3 & ~(ENET_PINSEL3_MASK)) | ENET_PINSEL3_CONFIG; // Set up MAC Configuration Register 1 LPC_EMAC->MAC1 = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX | MAC1_RES_MCS_RX |MAC1_SIM_RES | MAC1_SOFT_RES; // Set up MAC Command Register LPC_EMAC->Command = CR_REG_RES | CR_TX_RES | CR_RX_RES | CR_PASS_RUNT_FRM; // Short delay for (loop = 100; loop; loop--); // Set up MAC Configuration Register 1 to pass all receive frames LPC_EMAC->MAC1 = MAC1_PASS_ALL; // Set up MAC Configuration Register 2 to append CRC and pad out frames LPC_EMAC->MAC2 = MAC2_CRC_EN | MAC2_PAD_EN; // Set Ethernet Maximum Frame Register LPC_EMAC->MAXF = ETH_MAX_FLEN; // Set Collision Window / Retry Register LPC_EMAC->CLRT = CLRT_DEF; // Set Non Back-to-Back Inter-Packet-Gap Register LPC_EMAC->IPGR = IPGR_DEF; // Set MAC Command Register to enable Reduced MII interface // and prevent runt frames being filtered out LPC_EMAC->Command = CR_RMII | CR_PASS_RUNT_FRM; // Put DP83848C PHY into reset mode WriteToPHY (PHY_REG_BMCR, 0x8000); // Loop until hardware reset completes for (loop = 0; loop < 0x100000; loop++) { value = ReadFromPHY (PHY_REG_BMCR); if (!(value & 0x8000)) { // Reset has completed break; } } // Just check this actually is a DP83848C PHY phyid1 = ReadFromPHY (PHY_REG_IDR1); phyid2 = ReadFromPHY (PHY_REG_IDR2); if (((phyid1 << 16) | (phyid2 & 0xFFF0)) == DP83848C_ID) { phy_in_use = DP83848C_ID; } else if (((phyid1 << 16) | (phyid2 & 0xFFF0)) == LAN8720_ID) { phy_in_use = LAN8720_ID; } if (phy_in_use != 0) { // Safe to configure the PHY device // Set PHY to autonegotiation link speed WriteToPHY (PHY_REG_BMCR, PHY_AUTO_NEG); // loop until autonegotiation completes for (loop = 0; loop < 0x100000; loop++) { value = ReadFromPHY (PHY_REG_BMSR); if (value & 0x0020) { // Autonegotiation has completed break; } } } phy_linkstatus_reg = PHY_REG_STS; // Default to DP83848C phy_linkstatus_mask = 0x0001; if (phy_in_use == LAN8720_ID) { phy_linkstatus_reg = PHY_REG_BMSR; phy_linkstatus_mask = 0x0002; } // Now check the link status for (loop = 0; loop < 0x10000; loop++) { value = ReadFromPHY (phy_linkstatus_reg); if (value & phy_linkstatus_mask) { // The link is on break; } } // Now configure for full/half duplex mode if (value & 0x0004) { // We are in full duplex is enabled mode LPC_EMAC->MAC2 |= MAC2_FULL_DUP; LPC_EMAC->Command |= CR_FULL_DUP; LPC_EMAC->IPGT = IPGT_FULL_DUP; } else { // Otherwise we are in half duplex mode LPC_EMAC->IPGT = IPGT_HALF_DUP; } // Now configure 100MBit or 10MBit mode if (value & 0x0002) { // 10MBit mode LPC_EMAC->SUPP = 0; } else { // 100MBit mode LPC_EMAC->SUPP = SUPP_SPEED; } // Now set the Ethernet MAC Address registers // NOTE - MAC address must be unique on the network! LPC_EMAC->SA0 = (MYMAC_1 << 8) | MYMAC_2; // Station address 0 Reg LPC_EMAC->SA1 = (MYMAC_3 << 8) | MYMAC_4; // Station address 1 Reg LPC_EMAC->SA2 = (MYMAC_5 << 8) | MYMAC_6; // Station address 2 Reg // Now initialise the Rx descriptors for (loop = 0; loop < NUM_RX_FRAG; loop++) { RX_DESC_PACKET(loop) = RX_BUF(loop); RX_DESC_CTRL(loop) = RCTRL_INT | (ETH_FRAG_SIZE-1); RX_STAT_INFO(loop) = 0; RX_STAT_HASHCRC(loop) = 0; } // Set up the Receive Descriptor Base address register LPC_EMAC->RxDescriptor = RX_DESC_BASE; // Set up the Receive Status Base address register LPC_EMAC->RxStatus = RX_STAT_BASE; // Setup the Receive Number of Descriptor register LPC_EMAC->RxDescriptorNumber = NUM_RX_FRAG-1; // Set Receive Consume Index register to 0 LPC_EMAC->RxConsumeIndex = 0; // Now initialise the Tx descriptors for (loop = 0; loop < NUM_TX_FRAG; loop++) { TX_DESC_PACKET(loop) = TX_BUF(loop); TX_DESC_CTRL(loop) = 0; TX_STAT_INFO(loop) = 0; } // Set up the Transmit Descriptor Base address register LPC_EMAC->TxDescriptor = TX_DESC_BASE; // Set up the Transmit Status Base address register LPC_EMAC->TxStatus = TX_STAT_BASE; // Setup the Transmit Number of Descriptor register LPC_EMAC->TxDescriptorNumber = NUM_TX_FRAG-1; // Set Transmit Consume Index register to 0 LPC_EMAC->TxProduceIndex = 0; // Receive Broadcast and Perfect Match Packets LPC_EMAC->RxFilterCtrl = RFC_BCAST_EN | RFC_PERFECT_EN; // Enable interrupts MAC Module Control Interrupt Enable Register LPC_EMAC->IntEnable = INT_RX_DONE | INT_TX_DONE; // Reset all ethernet interrupts in MAC module LPC_EMAC->IntClear = 0xFFFF; // Finally enable receive and transmit mode in ethernet core LPC_EMAC->Command |= (CR_RX_EN | CR_TX_EN); LPC_EMAC->MAC1 |= MAC1_REC_EN; } // CodeRed - Write8900() not needed // for RDB1768 port /* // writes a word in little-endian byte order to // a specified port-address void Write8900(unsigned char Address, unsigned int Data) { P5DIR = 0xFF; // data port to output P3OUT = IOR | IOW | Address; // put address on bus P5OUT = Data; // write low order byte to data bus P3OUT &= ~IOW; // toggle IOW-signal P3OUT = IOR | IOW | (Address + 1); // and put next address on bus P5OUT = Data >> 8; // write high order byte to data bus P3OUT &= ~IOW; // toggle IOW-signal P3OUT |= IOW; } */ // Code Red - updated for LPC1776 port /* // writes a word in little-endian byte order to TX_FRAME_PORT void WriteFrame8900(unsigned int Data) { P5DIR = 0xFF; // data port to output P3OUT = IOR | IOW | TX_FRAME_PORT; // put address on bus P5OUT = Data; // write low order byte to data bus P3OUT &= ~IOW; // toggle IOW-signal P3OUT = IOR | IOW | (TX_FRAME_PORT + 1); // and put next address on bus P5OUT = Data >> 8; // write high order byte to data bus P3OUT &= ~IOW; // toggle IOW-signal P3OUT |= IOW; } */ // writes a word in little-endian byte order to TX_BUFFER void WriteFrame_EthMAC(unsigned short Data) { *txptr++ = Data; } // copies bytes from MCU-memory to frame port // NOTES: * an odd number of byte may only be transfered // if the frame is written to the end! // * MCU-memory MUST start at word-boundary // Code Red - rewritten for LPC1776 /* void CopyToFrame8900(void *Source, unsigned int Size) { P5DIR = 0xFF; // data port to output while (Size > 1) { WriteFrame8900(*((unsigned int *)Source)++); Size -= 2; } if (Size) // if odd num. of bytes... WriteFrame8900(*(unsigned char *)Source); // write leftover byte (the LAN-controller } // ignores the highbyte) */ void CopyToFrame_EthMAC(void *Source, unsigned int Size) { unsigned int index; unsigned short *pSource; pSource = (unsigned short *)Source; Size = (Size + 1) & 0xFFFE; // round up Size to next even number while (Size > 0) { WriteFrame_EthMAC(*pSource++); Size -= 2; } index = LPC_EMAC->TxProduceIndex; if (++index == NUM_TX_FRAG) index = 0; LPC_EMAC->TxProduceIndex = index; } // CodeRed - Read8900() not needed // for LPC1768 port /* // reads a word in little-endian byte order from // a specified port-address unsigned int Read8900(unsigned char Address) { unsigned int ReturnValue; P5DIR = 0x00; // data port to input P3OUT = IOR | IOW | Address; // put address on bus P3OUT &= ~IOR; // IOR-signal low ReturnValue = P5IN; // get low order byte from data bus P3OUT = IOR | IOW | (Address + 1); // IOR high and put next address on bus P3OUT &= ~IOR; // IOR-signal low ReturnValue |= P5IN << 8; // get high order byte from data bus P3OUT |= IOR; return ReturnValue; } */ // reads a word in little-endian byte order from RX_FRAME_PORT // Code Red - ReadFrame8900 rewritten for RDB1768 port /* unsigned int ReadFrame8900(void) { unsigned int ReturnValue; P5DIR = 0x00; // data port to input P3OUT = IOR | IOW | RX_FRAME_PORT; // access to RX_FRAME_PORT P3OUT &= ~IOR; // IOR-signal low ReturnValue = P5IN; // get 1st byte from data bus (low-byte) P3OUT = IOR | IOW | (RX_FRAME_PORT + 1); // IOR high and put next address on bus P3OUT &= ~IOR; // IOR-signal low ReturnValue |= P5IN << 8; // get 2nd byte from data bus (high-byte) P3OUT |= IOR; return ReturnValue; } */ // reads a word in little-endian byte order from RX_BUFFER unsigned short ReadFrame_EthMAC(void) { return (*rxptr++); } // reads a word in big-endian byte order from RX_FRAME_PORT // (useful to avoid permanent byte-swapping while reading // TCP/IP-data) // CodeRed - rewritten for LPC1768 /* unsigned int ReadFrameBE8900(void) { unsigned int ReturnValue; P5DIR = 0x00; // data port to input P3OUT = IOR | IOW | RX_FRAME_PORT; // access to RX_FRAME_PORT P3OUT &= ~IOR; // IOR-signal low ReturnValue = P5IN << 8; // get 1st byte from data bus (high-byte) P3OUT = IOR | IOW | (RX_FRAME_PORT + 1); // IOR high and put next address on bus P3OUT &= ~IOR; // IOR-signal low ReturnValue |= P5IN; // get 2nd byte from data bus (low-byte) P3OUT |= IOR; return ReturnValue; } */ unsigned short ReadFrameBE_EthMAC(void) { unsigned short ReturnValue; ReturnValue = SwapBytes (*rxptr++); return (ReturnValue); } // CodeRed - not required for RDB1768 port /* // reads a word in little-endian byte order from // a specified port-address // NOTE: this func. xfers the high-byte 1st, must be used to // access some special registers (e.g. RxStatus) unsigned int ReadHB1ST8900(unsigned char Address) { unsigned int ReturnValue; P5DIR = 0x00; // data port to input P3OUT = IOR | IOW | (Address + 1); // put address on bus P3OUT &= ~IOR; // IOR-signal low ReturnValue = P5IN << 8; // get high order byte from data bus P3OUT = IOR | IOW | Address; // IOR high and put next address on bus P3OUT &= ~IOR; // IOR-signal low ReturnValue |= P5IN; // get low order byte from data bus P3OUT |= IOR; return ReturnValue; } */ // copies bytes from frame port to MCU-memory // NOTES: * an odd number of byte may only be transfered // if the frame is read to the end! // * MCU-memory MUST start at word-boundary // Code Red - rewritten for LPC1776 port /* void CopyFromFrame8900(void *Dest, unsigned int Size) { while (Size > 1) { *((unsigned int *)Dest)++ = ReadFrame8900(); Size -= 2; } if (Size) // check for leftover byte... *(unsigned char *)Dest = ReadFrame8900(); // the LAN-Controller will return 0 } // for the highbyte */ void CopyFromFrame_EthMAC(void *Dest, unsigned short Size) { unsigned short *pDest; pDest = (unsigned short *)Dest; while (Size > 1) { *pDest++ = ReadFrame_EthMAC(); Size -= 2; } if (Size) { // check for leftover byte... *(unsigned char *)pDest = (char)ReadFrame_EthMAC();// the LAN-Controller will return 0 } // for the highbyte } // does a dummy read on frame-I/O-port // NOTE: only an even number of bytes is read! // Code Red - updated for LPC1776 //void DummyReadFrame8900(unsigned int Size) // discards an EVEN number of bytes void DummyReadFrame_EthMAC(unsigned short Size) // discards an EVEN number of bytes { // from RX-fifo while (Size > 1) { // Code Red - updated for LPC1776 // ReadFrame8900(); ReadFrame_EthMAC(); Size -= 2; } } // requests space in CS8900's on-chip memory for // storing an outgoing frame // CodeRed - updated for LPC1768 port /* void RequestSend(unsigned int FrameSize) { Write8900(TX_CMD_PORT, TX_START_ALL_BYTES); Write8900(TX_LEN_PORT, FrameSize); } */ void RequestSend(unsigned short FrameSize) { unsigned int index; index = LPC_EMAC->TxProduceIndex; txptr = (unsigned short *)TX_DESC_PACKET(index); TX_DESC_CTRL(index) = FrameSize | TCTRL_LAST; } // check if CS8900 is ready to accept the // frame we want to send unsigned int Rdy4Tx(void) { // Code Red - updated for LPC1768 // Write8900(ADD_PORT, PP_BusST); // return (Read8900(DATA_PORT) & READY_FOR_TX_NOW); // One the LPC the ethernet controller transmits // much faster than the CPU can load its buffers // so will always be ready to accept frame return (1); // } // CodeRed - New function // Reads length of received ethernet frame and checks // if destination address is a broadcast message or not. // Then returns the frame length unsigned short StartReadingFrame(void) { unsigned short ReceiveLength; unsigned int index; index = LPC_EMAC->RxConsumeIndex; ReceiveLength = (RX_STAT_INFO(index) & RINFO_SIZE) - 3; rxptr = (unsigned short *)RX_DESC_PACKET(index); return(ReceiveLength); } // CodeRed - new function void StopReadingFrame(void) { unsigned int index; index = LPC_EMAC->RxConsumeIndex; if (++index == NUM_RX_FRAG) index = 0; LPC_EMAC->RxConsumeIndex = index; } // CodeRed - new function to check if frame has been received unsigned int CheckIfFrameReceived(void) { if (LPC_EMAC->RxProduceIndex != LPC_EMAC->RxConsumeIndex) return(1); // Yes, packet received else return(0); }