diff options
Diffstat (limited to 'hw/bsp/ea4357/emac.c')
| -rw-r--r-- | hw/bsp/ea4357/emac.c | 480 |
1 files changed, 480 insertions, 0 deletions
diff --git a/hw/bsp/ea4357/emac.c b/hw/bsp/ea4357/emac.c new file mode 100644 index 000000000..fce042259 --- /dev/null +++ b/hw/bsp/ea4357/emac.c @@ -0,0 +1,480 @@ +/****************************************************************** + ***** ***** + ***** Name: cs8900.c ***** + ***** Ver.: 1.0 ***** + ***** Date: 07/05/2001 ***** + ***** Auth: Andreas Dannenberg ***** + ***** HTWK Leipzig ***** + ***** university of applied sciences ***** + ***** Germany ***** + ***** Func: ethernet packet-driver for use with LAN- ***** + ***** controller CS8900 from Crystal/Cirrus Logic ***** + ***** ***** + ***** NXP: Module modified for use with NXP ***** + ***** lpc43xx EMAC Ethernet controller ***** + ***** ***** + ******************************************************************/ + +#include "../board.h" + +#if BOARD == BOARD_EA4357 + +#include "emac.h" +//#include "tcpip.h" +#include "LPC43xx.h" +#include "lpc43xx_scu.h" +#include "lpc43xx_rgu.h" + +#define TIMEOUT 100000 + +static unsigned short *rptr; +static unsigned short *tptr; + +static unsigned int TxDescIndex = 0; +static unsigned int RxDescIndex = 0; + +// Keil: function added to write PHY +static void write_PHY (unsigned int PhyReg, unsigned short Value) { + + unsigned int tout; + + /* Write a data 'Value' to PHY register 'PhyReg'. */ + while(LPC_ETHERNET->MAC_MII_ADDR & GMII_BUSY); // Check GMII busy bit + LPC_ETHERNET->MAC_MII_ADDR = (DP83848C_DEF_ADR<<11) | (PhyReg<<6) | GMII_WRITE; + LPC_ETHERNET->MAC_MII_DATA = Value; + LPC_ETHERNET->MAC_MII_ADDR |= GMII_BUSY; // Start PHY Write Cycle + + /* Wait utill operation completed */ + for (tout = 0; tout < MII_WR_TOUT; tout++) { + if ((LPC_ETHERNET->MAC_MII_ADDR & GMII_BUSY) == 0) { + break; + } + } + if (tout == MII_WR_TOUT) // Trap the timeout + while(1); +} + + +// Keil: function added to read PHY +static unsigned short read_PHY (unsigned int PhyReg) { + + unsigned int tout, val; + + /* Read a PHY register 'PhyReg'. */ + while(LPC_ETHERNET->MAC_MII_ADDR & GMII_BUSY); // Check GMII busy bit + LPC_ETHERNET->MAC_MII_ADDR = (DP83848C_DEF_ADR<<11) | (PhyReg<<6) | GMII_READ; + LPC_ETHERNET->MAC_MII_ADDR |= GMII_BUSY; // Start PHY Read Cycle + + /* Wait until operation completed */ + for (tout = 0; tout < MII_RD_TOUT; tout++) { + if ((LPC_ETHERNET->MAC_MII_ADDR & GMII_BUSY) == 0) { + break; + } + } + if (tout == MII_RD_TOUT) // Trap the timeout + while(1); + val = LPC_ETHERNET->MAC_MII_DATA; + return (val); +} + + +// Keil: function added to initialize Rx Descriptors +void rx_descr_init (void) +{ + unsigned int i; + + for (i = 0; i < NUM_RX_DESC; i++) { + RX_DESC_STAT(i) = OWN_BIT; + RX_DESC_CTRL(i) = ETH_FRAG_SIZE; + RX_BUFADDR(i) = RX_BUF(i); + if (i == (NUM_RX_DESC-1)) // Last Descriptor? + RX_DESC_CTRL(i) |= RX_END_RING; + } + + /* Set Starting address of RX Descriptor list */ + LPC_ETHERNET->DMA_REC_DES_ADDR = RX_DESC_BASE; +} + + +// Keil: function added to initialize Tx Descriptors +void tx_descr_init (void) +{ + unsigned int i; + + for (i = 0; i < NUM_TX_DESC; i++) { // Take it out!!!! + TX_DESC_STAT(i) = 0; + TX_DESC_CTRL(i) = 0; + TX_BUFADDR(i) = 0; + } + + for (i = 0; i < NUM_TX_DESC; i++) { + TX_DESC_STAT(i) = TX_LAST_SEGM | TX_FIRST_SEGM; + TX_DESC_CTRL(i) = 0; + TX_BUFADDR(i) = TX_BUF(i); + if (i == (NUM_TX_DESC-1)) // Last Descriptor? + TX_DESC_STAT(i) |= TX_END_RING; + } + + /* Set Starting address of RX Descriptor list */ + LPC_ETHERNET->DMA_TRANS_DES_ADDR = TX_DESC_BASE; +} + + + +// configure port-pins for use with LAN-controller, +// reset it and send the configuration-sequence + +void Init_EMAC(void) +{ + int id1, id2, tout, regv; + unsigned phy_in_use = 0; + + /* Ethernet pins configuration */ +#if MII + scu_pinmux(0xC ,1 , (MD_PLN | MD_EZI | MD_ZI), FUNC3); // ENET_MDC: PC_1 -> FUNC3 + scu_pinmux(0x1 ,17 , (MD_PLN | MD_EZI | MD_ZI), FUNC3); // ENET_MDIO: P1_17 -> FUNC3 + scu_pinmux(0x1 ,18 , (MD_PLN | MD_EZI | MD_ZI), FUNC3); // ENET_TXD0: P1_18 -> FUNC3 + scu_pinmux(0x1 ,20 , (MD_PLN | MD_EZI | MD_ZI), FUNC3); // ENET_TXD1: P1_20 -> FUNC3 + scu_pinmux(0x1 ,19 , (MD_PLN | MD_EZI | MD_ZI), FUNC0); // ENET_REF: P1_19 -> FUNC0 (default) + +// scu_pinmux(0xC ,4 , (MD_PLN | MD_EZI | MD_ZI), FUNC3); // ENET_TX_EN: PC_4 -> FUNC3 + scu_pinmux(0x0 ,1 , (MD_PLN | MD_EZI | MD_ZI), FUNC6); // ENET_TX_EN: P0_1 -> FUNC6 + + scu_pinmux(0x1 ,15 , (MD_PLN | MD_EZI | MD_ZI), FUNC3); // ENET_RXD0: P1_15 -> FUNC3 + scu_pinmux(0x0 ,0 , (MD_PLN | MD_EZI | MD_ZI), FUNC2); // ENET_RXD1: P0_0 -> FUNC2 + +// scu_pinmux(0x1 ,16 , (MD_PLN | MD_EZI | MD_ZI), FUNC3); // ENET_CRS: P1_16 -> FUNC3 + scu_pinmux(0x9 ,0 , (MD_PLN | MD_EZI | MD_ZI), FUNC5); // ENET_CRS: P9_0 -> FUNC5 + +// scu_pinmux(0xC ,9 , (MD_PLN | MD_EZI | MD_ZI), FUNC3); // ENET_RX_ER: PC_9 -> FUNC3 + scu_pinmux(0x9 ,1 , (MD_PLN | MD_EZI | MD_ZI), FUNC5); // ENET_RX_ER: P9_1 -> FUNC5 + +// scu_pinmux(0xC ,8 , (MD_PLN | MD_EZI | MD_ZI), FUNC3); // ENET_RXDV: PC_8 -> FUNC3 + scu_pinmux(0x1 ,16 , (MD_PLN | MD_EZI | MD_ZI), FUNC7); // ENET_RXDV: P1_16 -> FUNC7 + +#else + scu_pinmux(0xC ,1 , (MD_EHS | MD_PLN | MD_EZI | MD_ZI), FUNC3); // ENET_MDC: PC_1 -> FUNC3 + scu_pinmux(0x1 ,17 , (MD_EHS | MD_PLN | MD_EZI | MD_ZI), FUNC3); // ENET_MDIO: P1_17 -> FUNC3 + scu_pinmux(0x1 ,18 , (MD_EHS | MD_PLN | MD_EZI | MD_ZI), FUNC3); // ENET_TXD0: P1_18 -> FUNC3 + scu_pinmux(0x1 ,20 , (MD_EHS | MD_PLN | MD_EZI | MD_ZI), FUNC3); // ENET_TXD1: P1_20 -> FUNC3 + scu_pinmux(0x1 ,19 , (MD_EHS | MD_PLN | MD_EZI | MD_ZI), FUNC0); // ENET_REF: P1_19 -> FUNC0 (default) +// scu_pinmux(0xC ,4 , (MD_EHS | MD_PLN | MD_EZI | MD_ZI), FUNC3); // ENET_TX_EN: PC_4 -> FUNC3 + scu_pinmux(0x0 ,1 , (MD_PLN | MD_EZI | MD_ZI), FUNC6); // ENET_TX_EN: P0_1 -> FUNC6 + scu_pinmux(0x1 ,15 , (MD_EHS | MD_PLN | MD_EZI | MD_ZI), FUNC3); // ENET_RXD0: P1_15 -> FUNC3 + scu_pinmux(0x0 ,0 , (MD_EHS | MD_PLN | MD_EZI | MD_ZI), FUNC2); // ENET_RXD1: P0_0 -> FUNC2 +// scu_pinmux(0x1 ,16 , (MD_EHS | MD_PLN | MD_EZI | MD_ZI), FUNC3); // ENET_CRS: P1_16 -> FUNC3 +// scu_pinmux(0x9 ,0 , (MD_PLN | MD_EZI | MD_ZI), FUNC5); // ENET_CRS: P9_0 -> FUNC5 +// scu_pinmux(0xC ,9 , (MD_EHS | MD_PLN | MD_EZI | MD_ZI), FUNC3); // ENET_RX_ER: PC_9 -> FUNC3 +// scu_pinmux(0x9 ,1 , (MD_PLN | MD_EZI | MD_ZI), FUNC5); // ENET_RX_ER: P9_1 -> FUNC5 +// scu_pinmux(0xC ,8 , (MD_EHS | MD_PLN | MD_EZI | MD_ZI), FUNC3); // ENET_RXDV: PC_8 -> FUNC3 + scu_pinmux(0x1 ,16 , (MD_PLN | MD_EZI | MD_ZI), FUNC7); // ENET_RXDV: P1_16 -> FUNC7 +#endif + + +#if MII /* Select MII interface */ // check MUXING for new Eagle... +// scu_pinmux(0xC ,6 , (MD_PLN | MD_EZI | MD_ZI), FUNC3); // ENET_RXD2: PC_6 -> FUNC3 + scu_pinmux(0x9 ,3 , (MD_PLN | MD_EZI | MD_ZI), FUNC5); // ENET_RXD2: P9_3 -> FUNC5 + +// scu_pinmux(0xC ,7 , (MD_PLN | MD_EZI | MD_ZI), FUNC3); // ENET_RXD3: PC_7 -> FUNC3 + scu_pinmux(0x9 ,2 , (MD_PLN | MD_EZI | MD_ZI), FUNC5); // ENET_RXD3: P9_2 -> FUNC5 + + scu_pinmux(0xC ,0 , (MD_PLN | MD_EZI | MD_ZI), FUNC3); // ENET_RXLK: PC_0 -> FUNC3 + +// scu_pinmux(0xC ,2 , (MD_PLN | MD_EZI | MD_ZI), FUNC3); // ENET_TXD2: PC_2 -> FUNC3 + scu_pinmux(0x9 ,4 , (MD_PLN | MD_EZI | MD_ZI), FUNC5); // ENET_TXD2: P9_4 -> FUNC5 + +// scu_pinmux(0xC ,3 , (MD_PLN | MD_EZI | MD_ZI), FUNC3); // ENET_TXD3: PC_3 -> FUNC3 + scu_pinmux(0x9 ,5 , (MD_PLN | MD_EZI | MD_ZI), FUNC5); // ENET_TXD3: P9_5 -> FUNC5 + +// scu_pinmux(0xC ,5 , (MD_PLN | MD_EZI | MD_ZI), FUNC3); // ENET_TX_ER: PC_5 -> FUNC3 + scu_pinmux(0xC ,5 , (MD_PLN | MD_EZI | MD_ZI), FUNC3); // ENET_TX_ER: PC_5 -> FUNC3 + +// scu_pinmux(0x0 ,1 , (MD_PLN | MD_EZI | MD_ZI), FUNC2); // ENET_COL: P0_1 -> FUNC2 + scu_pinmux(0x9 ,6 , (MD_PLN | MD_EZI | MD_ZI), FUNC5); // ENET_COL: P9_6 -> FUNC5 +#else /* Select RMII interface */ + LPC_CREG->CREG6 |= RMII_SELECT; +#endif + + + RGU_SoftReset(RGU_SIG_ETHERNET); + while(1){ // Confirm the reset happened + if (LPC_RGU->RESET_ACTIVE_STATUS0 & (1<<ETHERNET_RST)) + break; + } + + LPC_ETHERNET->DMA_BUS_MODE |= DMA_SOFT_RESET; // Reset all GMAC Subsystem internal registers and logic + while(LPC_ETHERNET->DMA_BUS_MODE & DMA_SOFT_RESET); // Wait for software reset completion + + /* Put the DP83848C in reset mode */ + write_PHY (PHY_REG_BMCR, PHY_BMCR_RESET); + + /* Wait for hardware reset to end. */ + for (tout = 0; tout < TIMEOUT; tout++) { + regv = read_PHY (PHY_REG_BMCR); + if (!(regv & PHY_BMCR_RESET)) { + /* Reset complete */ + break; + } + } + + /* Check if this is a DP83848C PHY. */ + id1 = read_PHY (PHY_REG_IDR1); + id2 = read_PHY (PHY_REG_IDR2); + if (((id1 << 16) | (id2 & 0xFFF0)) == DP83848C_ID) { + phy_in_use = DP83848C_ID; + } + else if (((id1 << 16) | (id2 & 0xFFF0)) == LAN8720_ID) { + phy_in_use = LAN8720_ID; + } + + if (phy_in_use != 0) { + /* Configure the PHY device */ +#if !MII + write_PHY (PHY_REG_RBR, 0x20); +#endif + + /* Use autonegotiation about the link speed. */ + write_PHY (PHY_REG_BMCR, PHY_AUTO_NEG); + /* Wait to complete Auto_Negotiation. */ + for (tout = 0; tout < TIMEOUT; tout++) { + regv = read_PHY (PHY_REG_BMSR); + if (regv & PHY_AUTO_NEG_DONE) { + /* Autonegotiation Complete. */ + break; + } + } + } + + + + /* Check the link status. */ + for (tout = 0; tout < TIMEOUT; tout++) { + regv = read_PHY (PHY_REG_STS); + if (regv & LINK_VALID_STS) { + /* Link is on. */ + break; + } + } + + // Configure the EMAC with the established parameters + switch (phy_in_use) { + case DP83848C_ID: + + /* Configure Full/Half Duplex mode. */ + if (regv & FULL_DUP_STS) { + /* Full duplex is enabled. */ + LPC_ETHERNET->MAC_CONFIG |= MAC_DUPMODE; + } + + /* Configure 100MBit/10MBit mode. */ + if (~(regv & SPEED_10M_STS)) { + /* 100MBit mode. */ + LPC_ETHERNET->MAC_CONFIG |= MAC_100MPS; + } + +// value = ReadFromPHY (PHY_REG_STS); /* PHY Extended Status Register */ +// // Now configure for full/half duplex mode +// if (value & 0x0004) { +// // We are in full duplex is enabled mode +// LPC_ETHERNET->MAC2 |= MAC2_FULL_DUP; +// LPC_ETHERNET->Command |= CR_FULL_DUP; +// LPC_ETHERNET->IPGT = IPGT_FULL_DUP; +// } +// else { +// // Otherwise we are in half duplex mode +// LPC_ETHERNET->IPGT = IPGT_HALF_DUP; +// } + +// // Now configure 100MBit or 10MBit mode +// if (value & 0x0002) { +// // 10MBit mode +// LPC_ETHERNET->SUPP = 0; +// } +// else { +// // 100MBit mode +// LPC_ETHERNET->SUPP = SUPP_SPEED; +// } + break; + + case LAN8720_ID: + + regv = read_PHY (PHY_REG_SCSR); /* PHY Extended Status Register */ + // Now configure for full/half duplex mode + if (regv & (1<<4)) { /* bit 4: 1 = Full Duplex, 0 = Half Duplex */ + // We are in full duplex is enabled mode + LPC_ETHERNET->MAC_CONFIG |= MAC_DUPMODE; + } + + // Now configure 100MBit or 10MBit mode + if (regv & (1<<3)) { /* bit 3: 1 = 100Mbps, 0 = 10Mbps */ + // 100MBit mode + LPC_ETHERNET->MAC_CONFIG |= MAC_100MPS; + } + + + break; + + } + + /* Set the Ethernet MAC Address registers */ + LPC_ETHERNET->MAC_ADDR0_HIGH = (MYMAC_6 << 8) | MYMAC_5; + LPC_ETHERNET->MAC_ADDR0_LOW = (MYMAC_4 << 24) | (MYMAC_3 << 16) | (MYMAC_2 << 8) | MYMAC_1; + + /* Initialize Descriptor Lists */ + rx_descr_init(); + tx_descr_init(); + + /* Configure Filter */ + LPC_ETHERNET->MAC_FRAME_FILTER = MAC_PROMISCUOUS | MAC_RECEIVEALL; + + /* Enable Receiver and Transmitter */ + LPC_ETHERNET->MAC_CONFIG |= (MAC_TX_ENABLE | MAC_RX_ENABLE); + + /* Enable interrupts */ + //LPC_ETHERNET->DMA_INT_EN = DMA_INT_NOR_SUM | DMA_INT_RECEIVE | DMA_INT_TRANSMIT; + + /* Start Transmission & Receive processes */ + LPC_ETHERNET->DMA_OP_MODE |= (DMA_SS_TRANSMIT | DMA_SS_RECEIVE ); + +} + + +// reads a word in little-endian byte order from RX_BUFFER + +unsigned short ReadFrame_EMAC(void) +{ + return (*rptr++); +} + + +// easyWEB internal function +// help function to swap the byte order of a WORD + +unsigned short SwapBytes(unsigned short Data) +{ + return (Data >> 8) | (Data << 8); +} + +// reads a word in big-endian byte order from RX_FRAME_PORT +// (useful to avoid permanent byte-swapping while reading +// TCP/IP-data) + +unsigned short ReadFrameBE_EMAC(void) +{ + unsigned short ReturnValue; + + ReturnValue = SwapBytes (*rptr++); + 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 + +void CopyFromFrame_EMAC(void *Dest, unsigned short Size) +{ + unsigned short * piDest; // Keil: Pointer added to correct expression + + piDest = Dest; // Keil: Line added + while (Size > 1) { + *piDest++ = ReadFrame_EMAC(); + Size -= 2; + } + + if (Size) { // check for leftover byte... + *(unsigned char *)piDest = (char)ReadFrame_EMAC();// 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! + +void DummyReadFrame_EMAC(unsigned short Size) // discards an EVEN number of bytes +{ // from RX-fifo + while (Size > 1) { + ReadFrame_EMAC(); + Size -= 2; + } +} + +// Reads the length of the received ethernet frame and checks if the +// destination address is a broadcast message or not +// returns the frame length +unsigned short StartReadFrame(void) { + unsigned short RxLen; + + if ((RX_DESC_STAT(RxDescIndex) & OWN_BIT) == 0) { + RxLen = (RX_DESC_STAT(RxDescIndex) >> 16) & 0x03FFF; + rptr = (unsigned short *)RX_BUFADDR(RxDescIndex); + return(RxLen); + } + return 0; + +} + +void EndReadFrame(void) { + + RX_DESC_STAT(RxDescIndex) = OWN_BIT; + RxDescIndex++; + if (RxDescIndex == NUM_RX_DESC) + RxDescIndex = 0; +} + +unsigned int CheckFrameReceived(void) { // Packet received ? + + if ((RX_DESC_STAT(RxDescIndex) & OWN_BIT) == 0) + return(1); + else + return(0); +} + +// requests space in EMAC memory for storing an outgoing frame + +void RequestSend(unsigned short FrameSize) +{ + tptr = (unsigned short *)TX_BUFADDR(TxDescIndex); + TX_DESC_CTRL(TxDescIndex) = FrameSize; +} + +// check if ethernet controller is ready to accept the +// frame we want to send + +unsigned int Rdy4Tx(void) +{ + return (1); // the ethernet controller transmits much faster +} // than the CPU can load its buffers + + +// writes a word in little-endian byte order to TX_BUFFER +void WriteFrame_EMAC(unsigned short Data) +{ + *tptr++ = 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 + +void CopyToFrame_EMAC(void *Source, unsigned int Size) +{ + unsigned short * piSource; +// unsigned int idx; + + piSource = Source; + Size = (Size + 1) & 0xFFFE; // round Size up to next even number + while (Size > 0) { + WriteFrame_EMAC(*piSource++); + Size -= 2; + } + TX_DESC_STAT(TxDescIndex) |= OWN_BIT; + LPC_ETHERNET->DMA_TRANS_POLL_DEMAND = 1; // Wake Up the DMA if it's in Suspended Mode + TxDescIndex++; + if (TxDescIndex == NUM_TX_DESC) + TxDescIndex = 0; +} + +#endif + |
