00001 /****************************************************************** 00002 ***** ***** 00003 ***** Name: cs8900.c ***** 00004 ***** Ver.: 1.0 ***** 00005 ***** Date: 07/05/2001 ***** 00006 ***** Auth: Andreas Dannenberg ***** 00007 ***** HTWK Leipzig ***** 00008 ***** university of applied sciences ***** 00009 ***** Germany ***** 00010 ***** Func: ethernet packet-driver for use with LAN- ***** 00011 ***** controller CS8900 from Crystal/Cirrus Logic ***** 00012 ***** ***** 00013 ***** Keil: Module modified for use with Philips ***** 00014 ***** LPC2378 EMAC Ethernet controller ***** 00015 ***** ***** 00016 ******************************************************************/ 00017 00018 #include "emac.h" 00019 #include "../timer/timer.h" 00020 #include "../lpc_config.h" 00021 00022 #include "../uart/uart.h" 00023 #include "../cli/debug.h" 00024 #include "../cli/api.h" 00025 00026 static unsigned short *rptr; 00027 static unsigned short *tptr; 00028 00029 // easyWEB internal function 00030 // help function to swap the byte order of a WORD 00031 00032 static unsigned short SwapBytes(unsigned short Data) 00033 { 00034 return (Data >> 8) | (Data << 8); 00035 } 00036 00037 // Keil: function added to write PHY 00038 void write_PHY (int PhyReg, int Value) 00039 { 00040 unsigned int tout; 00041 00042 MAC_MADR = DP83848C_DEF_ADR | PhyReg; 00043 MAC_MWTD = Value; 00044 00045 /* Wait utill operation completed */ 00046 tout = 0; 00047 for (tout = 0; tout < MII_WR_TOUT; tout++) { 00048 if ((MAC_MIND & MIND_BUSY) == 0) { 00049 break; 00050 } 00051 } 00052 } 00053 00054 00055 // Keil: function added to read PHY 00056 unsigned short read_PHY (unsigned char PhyReg) 00057 { 00058 unsigned int tout; 00059 00060 MAC_MADR = DP83848C_DEF_ADR | PhyReg; 00061 MAC_MCMD = MCMD_READ; 00062 00063 /* Wait until operation completed */ 00064 tout = 0; 00065 for (tout = 0; tout < MII_RD_TOUT; tout++) { 00066 if ((MAC_MIND & MIND_BUSY) == 0) { 00067 break; 00068 } 00069 } 00070 MAC_MCMD = 0; 00071 return (MAC_MRDD); 00072 } 00073 00074 00075 // Keil: function added to initialize Rx Descriptors 00076 void rx_descr_init (void) 00077 { 00078 unsigned int i; 00079 00080 for (i = 0; i < NUM_RX_FRAG; i++) { 00081 RX_DESC_PACKET(i) = RX_BUF(i); 00082 RX_DESC_CTRL(i) = RCTRL_INT | (ETH_FRAG_SIZE-1); 00083 RX_STAT_INFO(i) = 0; 00084 RX_STAT_HASHCRC(i) = 0; 00085 } 00086 00087 /* Set EMAC Receive Descriptor Registers. */ 00088 MAC_RXDESCRIPTOR = RX_DESC_BASE; 00089 MAC_RXSTATUS = RX_STAT_BASE; 00090 MAC_RXDESCRIPTORNUM = NUM_RX_FRAG-1; 00091 00092 /* Rx Descriptors Point to 0 */ 00093 MAC_RXCONSUMEINDEX = 0; 00094 } 00095 00096 00097 // Keil: function added to initialize Tx Descriptors 00098 void tx_descr_init (void) { 00099 unsigned int i; 00100 00101 for (i = 0; i < NUM_TX_FRAG; i++) { 00102 TX_DESC_PACKET(i) = TX_BUF(i); 00103 TX_DESC_CTRL(i) = 0; 00104 TX_STAT_INFO(i) = 0; 00105 } 00106 00107 /* Set EMAC Transmit Descriptor Registers. */ 00108 MAC_TXDESCRIPTOR = TX_DESC_BASE; 00109 MAC_TXSTATUS = TX_STAT_BASE; 00110 MAC_TXDESCRIPTORNUM = NUM_TX_FRAG-1; 00111 00112 /* Tx Descriptors Point to 0 */ 00113 MAC_TXPRODUCEINDEX = 0; 00114 } 00115 00120 int Init_EMAC(void) 00121 { 00122 00123 // Keil: function modified to access the EMAC 00124 // Initializes the EMAC ethernet controller 00125 volatile unsigned int regv,tout,id1,id2; 00126 00127 /* Power Up the EMAC controller. */ 00128 PCONP |= 0x40000000; 00129 delayMs(10); 00130 00131 /* Enable P1 Ethernet Pins. */ 00132 PINSEL2 = 0x50150105; 00133 PINSEL3 = (PINSEL3 & ~0x0000000F) | 0x00000005; 00134 00135 /* Reset all EMAC internal modules. */ 00136 MAC_MAC1 = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX | MAC1_RES_MCS_RX | MAC1_SIM_RES | MAC1_SOFT_RES; 00137 MAC_COMMAND = CR_REG_RES | CR_TX_RES | CR_RX_RES; 00138 00139 /* A short delay after reset. */ 00140 delayMs(10); 00141 00142 /* Initialize MAC control registers. */ 00143 MAC_MAC1 = MAC1_PASS_ALL; 00144 MAC_MAC2 = MAC2_CRC_EN | MAC2_PAD_EN; 00145 MAC_MAXF = ETH_MAX_FLEN; 00146 MAC_CLRT = CLRT_DEF; 00147 MAC_IPGR = IPGR_DEF; 00148 00149 /* Enable Reduced MII interface. */ 00150 MAC_COMMAND = CR_RMII | CR_PASS_RUNT_FRM; 00151 00152 /* Put the DP83848C in reset mode */ 00153 write_PHY (PHY_REG_BMCR, 0x8000); 00154 00155 /* Wait for hardware reset to end. */ 00156 for (tout = 0; tout < 100; tout++) { 00157 delayMs(10); 00158 regv = read_PHY (PHY_REG_BMCR); 00159 if (!(regv & 0x8000)) { 00160 /* Reset complete */ 00161 uart_puts(" PHY-RSTD"); 00162 break; 00163 } 00164 } 00165 00166 /* MII Mgmt Configuration register and MII Mgnt hardware Reset */ 00167 /* host clock divided by 20, no suppress preamble, no scan increment */ 00168 MAC_MCFG = HOST_CLK_BY_20 | MCFG_RES_MII; 00169 delayMs(10); 00170 MAC_MCFG &= (~MCFG_RES_MII); /* Clear the reset */ 00171 MAC_MCMD = 0; 00172 00173 /* Check if this is a DP83848C PHY. */ 00174 id1 = read_PHY (PHY_REG_IDR1); 00175 id2 = read_PHY (PHY_REG_IDR2); 00176 if (((id1 << 16) | (id2 & 0xFFF0)) == DP83848C_ID) { 00177 /* Configure the PHY device */ 00178 // write_PHY(PHY_REG_ANAR,0x3<<5 | 0x1); //Remove 100Mbit from supported options 00179 /* Use autonegotiation about the link speed. */ 00180 write_PHY (PHY_REG_BMCR, PHY_AUTO_NEG); 00181 /* Wait to complete Auto_Negotiation. */ 00182 for (tout = 0; tout < 10; tout++) { 00183 delayMs( 100 ); 00184 regv = read_PHY (PHY_REG_BMSR); 00185 if (regv & 0x0020) { 00186 /* Autonegotiation Complete. */ 00187 uart_puts(" AUTO-NEGD"); 00188 break; 00189 } 00190 } 00191 } 00192 else return FAIL; 00193 00194 /* Check the link status. */ 00195 for (tout = 0; tout < 10; tout++) { 00196 delayMs( 100 ); 00197 regv = read_PHY (PHY_REG_STS); 00198 if (regv & 0x0001) { 00199 /* Link is on. */ 00200 uart_puts(" LINK-ON"); 00201 break; 00202 } 00203 } 00204 /* Configure Full/Half Duplex mode. */ 00205 if (regv & 0x0004) { 00206 /* Full duplex is enabled. */ 00207 MAC_MAC2 |= MAC2_FULL_DUP; 00208 MAC_COMMAND |= CR_FULL_DUP; 00209 MAC_IPGT = IPGT_FULL_DUP; 00210 uart_puts(" FullDuplex"); 00211 } 00212 else { 00213 /* Half duplex mode. */ 00214 MAC_IPGT = IPGT_HALF_DUP; 00215 uart_puts(" HalfDuplex"); 00216 } 00217 00218 /* Configure 100MBit/10MBit mode. */ 00219 if (regv & 0x0002) { 00220 /* 10MBit mode. */ 00221 MAC_SUPP = 0; 00222 uart_puts(" 10Mbps\n"); 00223 } 00224 else { 00225 /* 100MBit mode. */ 00226 MAC_SUPP = SUPP_SPEED; 00227 uart_puts(" 100Mbps\n"); 00228 } 00229 00230 /* Set the Ethernet MAC Address registers */ 00231 MAC_SA0 = (emacETHADDR0 << 8) | emacETHADDR1; 00232 MAC_SA1 = (emacETHADDR2 << 8) | emacETHADDR3; 00233 MAC_SA2 = (emacETHADDR4 << 8) | emacETHADDR5; 00234 00235 /* Initialize Tx and Rx DMA Descriptors */ 00236 rx_descr_init (); 00237 tx_descr_init (); 00238 /* Receive Broadcast and Perfect Match Packets */ 00239 MAC_RXFILTERCTRL = RFC_UCAST_EN | RFC_BCAST_EN | RFC_PERFECT_EN; 00240 00241 /* Reset all interrupts */ 00242 MAC_INTCLEAR = 0xFFFF; 00243 00244 /* Enable receive and transmit mode of MAC Ethernet core */ 00245 MAC_COMMAND |= (CR_RX_EN | CR_TX_EN); 00246 MAC_MAC1 |= MAC1_REC_EN; 00247 00248 return PASS; 00249 } 00250 00251 00252 // reads a word in little-endian byte order from RX_BUFFER 00253 00254 unsigned short ReadFrame_EMAC(void) 00255 { 00256 return (*rptr++); 00257 } 00258 00259 // reads a word in big-endian byte order from RX_FRAME_PORT 00260 // (useful to avoid permanent byte-swapping while reading 00261 // TCP/IP-data) 00262 00263 unsigned short ReadFrameBE_EMAC(void) 00264 { 00265 unsigned short ReturnValue; 00266 00267 ReturnValue = SwapBytes (*rptr++); 00268 return (ReturnValue); 00269 } 00270 00271 00272 // copies bytes from frame port to MCU-memory 00273 // NOTES: * an odd number of byte may only be transfered 00274 // if the frame is read to the end! 00275 // * MCU-memory MUST start at word-boundary 00276 00277 void CopyFromFrame_EMAC(void *Dest, unsigned short Size) 00278 { 00279 unsigned short * piDest; // Keil: Pointer added to correct expression 00280 00281 piDest = Dest; // Keil: Line added 00282 while (Size > 1) { 00283 *piDest++ = ReadFrame_EMAC(); 00284 Size -= 2; 00285 } 00286 00287 if (Size) { // check for leftover byte... 00288 *(unsigned char *)piDest = (char)ReadFrame_EMAC();// the LAN-Controller will return 0 00289 } // for the highbyte 00290 } 00291 00292 // does a dummy read on frame-I/O-port 00293 // NOTE: only an even number of bytes is read! 00294 00295 void DummyReadFrame_EMAC(unsigned short Size) // discards an EVEN number of bytes 00296 { // from RX-fifo 00297 while (Size > 1) { 00298 ReadFrame_EMAC(); 00299 Size -= 2; 00300 } 00301 } 00302 00303 // Reads the length of the received ethernet frame and checks if the 00304 // destination address is a broadcast message or not 00305 // returns the frame length 00306 unsigned short StartReadFrame(void) { 00307 unsigned short RxLen; 00308 unsigned int idx; 00309 00310 idx = MAC_RXCONSUMEINDEX; 00311 RxLen = (RX_STAT_INFO(idx) & RINFO_SIZE) - 3; 00312 rptr = (unsigned short *)RX_DESC_PACKET(idx); 00313 return(RxLen); 00314 } 00315 00316 void EndReadFrame(void) { 00317 unsigned int idx; 00318 00319 /* DMA free packet. */ 00320 idx = MAC_RXCONSUMEINDEX; 00321 00322 if (++idx == NUM_RX_FRAG) 00323 idx = 0; 00324 00325 MAC_RXCONSUMEINDEX = idx; 00326 } 00327 00328 unsigned int CheckFrameReceived(void) { // Packet received ? 00329 00330 if (MAC_RXPRODUCEINDEX != MAC_RXCONSUMEINDEX) // more packets received ? 00331 return(1); 00332 else 00333 return(0); 00334 } 00335 00336 unsigned int uiGetEMACRxData( unsigned char *ucBuffer ) 00337 { 00338 unsigned int uiLen = 0; 00339 00340 if( MAC_RXPRODUCEINDEX != MAC_RXCONSUMEINDEX ) 00341 { 00342 uiLen = StartReadFrame(); 00343 CopyFromFrame_EMAC( ucBuffer, uiLen ); 00344 00345 EndReadFrame(); 00346 } 00347 00348 return uiLen; 00349 } 00350 00351 // requests space in EMAC memory for storing an outgoing frame 00352 00353 void RequestSend(void) 00354 { 00355 unsigned int idx; 00356 00357 idx = MAC_TXPRODUCEINDEX; 00358 tptr = (unsigned short *)TX_DESC_PACKET(idx); 00359 } 00360 00361 // check if ethernet controller is ready to accept the 00362 // frame we want to send 00363 00364 unsigned int Rdy4Tx(void) 00365 { 00366 return (1); // the ethernet controller transmits much faster 00367 } // than the CPU can load its buffers 00368 00369 00370 // writes a word in little-endian byte order to TX_BUFFER 00371 void WriteFrame_EMAC(unsigned short Data) 00372 { 00373 *tptr++ = Data; 00374 } 00375 00376 // copies bytes from MCU-memory to frame port 00377 // NOTES: * an odd number of byte may only be transfered 00378 // if the frame is written to the end! 00379 // * MCU-memory MUST start at word-boundary 00380 00381 void CopyToFrame_EMAC(void *Source, unsigned int Size) 00382 { 00383 unsigned short * piSource; 00384 00385 piSource = Source; 00386 Size = (Size + 1) & 0xFFFE; // round Size up to next even number 00387 while (Size > 0) { 00388 WriteFrame_EMAC(*piSource++); 00389 Size -= 2; 00390 } 00391 } 00392 00393 void DoSend_EMAC(unsigned short FrameSize) 00394 { 00395 unsigned int idx; 00396 00397 idx = MAC_TXPRODUCEINDEX; 00398 TX_DESC_CTRL(idx) = FrameSize | TCTRL_LAST; 00399 if (++idx == NUM_TX_FRAG) idx = 0; 00400 MAC_TXPRODUCEINDEX = idx; 00401 } 00402