cs8900a.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2003-2005 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  *
00032  */
00033 
00034 /*
00035  * $Log: cs8900a.c,v $
00036  * Revision 1.3  2007/05/02 11:22:51  haraldkipp
00037  * Added multicast table entry.
00038  *
00039  * Revision 1.2  2006/05/25 09:09:57  haraldkipp
00040  * API documentation updated and corrected.
00041  *
00042  * Revision 1.1  2006/02/23 15:33:59  haraldkipp
00043  * Support for Philips LPC2xxx Family and LPC-E2294 Board from Olimex added.
00044  * Many thanks to Michael Fischer for this port.
00045  *
00046  * Revision 1.2  2005/08/02 17:46:45  haraldkipp
00047  * Major API documentation update.
00048  *
00049  * Revision 1.1  2005/07/26 18:02:40  haraldkipp
00050  * Moved from dev.
00051  *
00052  * Revision 1.13  2005/04/30 16:42:41  chaac
00053  * Fixed bug in handling of NUTDEBUG. Added include for cfg/os.h. If NUTDEBUG
00054  * is defined in NutConf, it will make effect where it is used.
00055  *
00056  * Revision 1.12  2005/02/02 19:55:34  haraldkipp
00057  * If no Ethernet link was available on the LAN91C111, each outgoing packet
00058  * took 15 seconds and, even worse, the ouput routine doesn't return an error.
00059  * Now the first attempt to send a packet without Ethernet link will wait for
00060  * 5 seconds and subsequent attempts take 0.5 seconds only, always returning
00061  * an error.
00062  *
00063  * Revision 1.11  2005/01/24 21:11:49  freckle
00064  * renamed NutEventPostFromIRQ into NutEventPostFromIrq
00065  *
00066  * Revision 1.10  2005/01/22 19:24:11  haraldkipp
00067  * Changed AVR port configuration names from PORTx to AVRPORTx.
00068  *
00069  * Revision 1.9  2005/01/21 16:49:45  freckle
00070  * Seperated calls to NutEventPostAsync between Threads and IRQs
00071  *
00072  * Revision 1.8  2004/09/22 08:14:48  haraldkipp
00073  * Made configurable
00074  *
00075  * Revision 1.7  2004/03/08 11:14:17  haraldkipp
00076  * Added quick hack for fixed mode.
00077  *
00078  * Revision 1.6  2004/02/25 16:22:33  haraldkipp
00079  * Do not initialize MAC with all zeros
00080  *
00081  * Revision 1.5  2004/01/14 19:31:43  drsung
00082  * Speed improvement to NicWrite applied. Thanks to Kolja Waschk
00083  *
00084  * Revision 1.4  2003/11/06 09:26:50  haraldkipp
00085  * Removed silly line with hardcoded MAC, left over from testing
00086  *
00087  * Revision 1.3  2003/11/04 17:54:47  haraldkipp
00088  * PHY configuration timing changed again for reliable linking
00089  *
00090  * Revision 1.2  2003/11/03 17:12:53  haraldkipp
00091  * Allow linking with RTL8019 driver.
00092  * Links more reliable to 10 MBit networks now.
00093  * Reset MMU on allocation failures.
00094  * Some optimizations.
00095  *
00096  * Revision 1.1  2003/10/13 10:13:49  haraldkipp
00097  * First release
00098  *
00099  */
00100 
00101 #include <cfg/os.h>
00102 #include <cfg/arch/avr.h>
00103 
00104 #include <string.h>
00105 
00106 #include <sys/atom.h>
00107 #include <sys/heap.h>
00108 #include <sys/thread.h>
00109 #include <sys/event.h>
00110 #include <sys/timer.h>
00111 #include <sys/confnet.h>
00112 
00113 #include <netinet/if_ether.h>
00114 #include <net/ether.h>
00115 #include <net/if_var.h>
00116 
00117 #include <dev/irqreg.h>
00118 #include <dev/cs8900a.h>
00119 
00120 #ifdef NUTDEBUG
00121 #include <stdio.h>
00122 #endif
00123 
00124 /*
00125  * This file is for the Olimex LPC-E2294 board @@MF
00126  */
00127 #include <arch/arm/lpc2xxx.h>
00128 #include <__armlib.h>
00129 #define cli()   __ARMLIB_disableIRQ()
00130 #define sei()   __ARMLIB_enableIRQ()   
00131 
00132 /*=========================================================================*/
00133 /*  DEFINE: All Structures and Common Constants                            */
00134 /*=========================================================================*/
00135 
00136 /* 
00137  * Cirrus Logic CS8900a I/O Registers
00138  */
00139 #define CS_DATA_P0    (cs_base + 0x0000UL)
00140 #define CS_DATA_P1      (cs_base + 0x0002UL)
00141 #define CS_TX_CMD_I     (cs_base + 0x0004UL)
00142 #define CS_TX_LEN_I     (cs_base + 0x0006UL)
00143 #define CS_INT_STAT   (cs_base + 0x0008UL)
00144 #define CS_PP_PTR         (cs_base + 0x000AUL)
00145 #define CS_PP_DATA0     (cs_base + 0x000CUL)
00146 #define CS_PP_DATA1     (cs_base + 0x000EUL)
00147 
00148 
00149 // Cirrus Logic CS8900a Packet Page registers
00150 #define CS_PROD_ID      0x0000
00151 #define CS_IO_BASE      0x0020
00152 #define CS_INT_NUM      0x0022
00153 #define CS_DMA_CHAN     0x0024
00154 #define CS_DMA_SOF      0x0026
00155 #define CS_DMA_FCNT     0x0028
00156 #define CS_DMA_RXCNT    0x002A
00157 #define CS_MEM_BASE     0x002C
00158 #define CS_BOOT_BASE    0x0030
00159 #define CS_BOOT_MASK    0x0034
00160 #define CS_EE_CMD         0x0040
00161 #define CS_EE_DATA      0x0042
00162 #define CS_RX_FRM_CNT   0x0050
00163 
00164 #define CS_ISQ            0x0120
00165 #define CS_RX_CFG         0x0102
00166 #define CS_RX_EVENT     0x0124
00167 #define CS_RX_CTL         0x0104
00168 #define CS_TX_CFG         0x0106
00169 #define CS_TX_EVENT     0x0128
00170 #define CS_TX_CMD_P     0x0108
00171 #define CS_BUF_CFG      0x010A
00172 #define CS_BUF_EVENT    0x012C
00173 #define CS_RX_MISS      0x0130
00174 #define CS_TX_COLL      0x0132
00175 #define CS_LINE_CTRL    0x0112
00176 #define CS_LINE_STAT    0x0134
00177 #define CS_SELF_CTRL    0x0114
00178 #define CS_SELF_STAT    0x0136
00179 #define CS_BUS_CTRL     0x0116
00180 #define CS_BUS_STAT     0x0138
00181 #define CS_TEST_CTRL    0x0118
00182 #define CS_AUI_TDR      0x013C
00183 
00184 #define CS_PP_TX_CMD    0x0144
00185 #define CS_PP_TX_LEN    0x0146
00186 
00187 #define CS_IEEE_ADDR    0x0158
00188 
00193 
00198 struct _NICINFO {
00199     u_long ni_rx_packets;       
00200     u_long ni_tx_packets;       
00201 };
00202 
00206 typedef struct _NICINFO NICINFO;
00207 
00208 /*=========================================================================*/
00209 /*  DEFINE: Definition of all local Data                                   */
00210 /*=========================================================================*/
00211 // Ethernet flags byte
00212 // Bit 0 = transmit byte flag
00213 static   u_char cs_flags = 0;
00214 volatile u_long cs_base  = 0x82000000UL;
00215 
00216 
00217 /*=========================================================================*/
00218 /*  DEFINE: Definition of all local Procedures                             */
00219 /*=========================================================================*/
00220 void CSWrite16(u_long addr, u_short data)
00221 {
00222     u_char *p;
00223 
00224     p = (u_char *) addr;
00225     cli();
00226     *p = data;
00227     p++;
00228     *p = data >> 8;    
00229     sei();
00230 }
00231 
00232 void CSWritePP16(u_short addr, u_short data)
00233 {
00234     u_char *p;
00235 
00236     cli();
00237     p = (u_char *) CS_PP_PTR;
00238     *p = addr;
00239     p++;
00240     *p = addr >> 8;
00241 
00242     CSWrite16(CS_PP_DATA0, data);
00243 
00244     return;
00245 }
00246 
00247 u_short CSRead16(u_long addr)
00248 {
00249     u_char *p;
00250     u_short d;
00251 
00252     cli();
00253     p  = (u_char *) addr;
00254     d  = *p;
00255     p++;
00256     d |= (*p << 8); 
00257     sei();
00258 
00259     return d;
00260 }
00261 
00262 u_short CSReadPP16(u_short addr)
00263 {
00264     u_char *p;
00265 
00266     cli();
00267     p = (u_char *) CS_PP_PTR;
00268     *p = addr;
00269     p++;
00270     *p = addr >> 8;
00271 
00272     return CSRead16(CS_PP_DATA0);
00273 }
00274 
00275 void CSBeginFrame(void)
00276 {
00277     cs_flags &= ~1;
00278 }
00279 
00280 void CSEndFrame(void)
00281 {
00282     u_char *p;
00283 
00284     cli();
00285     p = (u_char *) CS_DATA_P0 + 1;
00286     sei();
00287 
00288     // If odd number of bytes in packet pad it out
00289     if (cs_flags & 1)
00290         p = 0;
00291 }
00292 
00293 void CSWriteFrameByte(u_char data)
00294 {
00295     u_char *p;
00296 
00297     if (cs_flags & 1)
00298         p = (u_char *) CS_DATA_P0 + 1;
00299     else
00300         p = (u_char *) CS_DATA_P0;
00301 
00302     *p = data;
00303     cs_flags ^= 1;
00304 }
00305 
00306 static int CSEthPutPacket(NUTDEVICE * dev, NETBUF * nb)
00307 {
00308     u_short i;
00309     u_short sz;
00310     u_char *p;
00311     NICINFO *ni;
00312 
00313     ni = (NICINFO *) dev->dev_dcb;
00314 
00315     //
00316     // Calculate the number of bytes to be send. Do not
00317     // send packets larger than 1536 bytes.
00318     //
00319     sz = nb->nb_dl.sz + nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz;
00320     if (sz >= 0x600) {
00321         NutNetBufFree(nb);
00322         return -1;
00323     }
00324 #if 0
00325     if (tcp_trace) {
00326         NutPrintFormat_P(dev_debug, PSTR("[ETHTX-%u]\r\n"), sz);
00327         NutPrintFlush(dev_debug);
00328     }
00329 #endif
00330 
00331     // Start transmission after entire frame is loaded into CS8900
00332     CSWrite16(CS_TX_CMD_I, 0xC0);
00333     // Set frame size
00334     CSWrite16(CS_TX_LEN_I, sz);
00335 
00336     // Wait for buffer space, but only for a while (200ms)
00337     // If the cable is disconnected this will never become true
00338     // If we don't get the go ahead within 200ms return 0 (Sucess)
00339     // And let the upper layers deal with re-transmission 
00340     // If we return failure TCP sockets will close straight away which probably
00341     // isn't the correct behaviour
00342     i = 0;
00343     while ((CSReadPP16(CS_BUS_STAT) & 0x0100) == 0) {
00344         i++;
00345         if (i > 20)
00346             return 0;
00347         NutSleep(10);
00348     }
00349 
00350     //
00351     // Transfer ethernet physical header.
00352     //
00353     CSBeginFrame();
00354 
00355     p = nb->nb_dl.vp;
00356     for (i = 0; i < nb->nb_dl.sz; i++) {
00357         CSWriteFrameByte(*p++);
00358     }
00359 
00360 
00361     p = nb->nb_nw.vp;
00362     for (i = 0; i < nb->nb_nw.sz; i++) {
00363         CSWriteFrameByte(*p++);
00364     }
00365 
00366     p = nb->nb_tp.vp;
00367     for (i = 0; i < nb->nb_tp.sz; i++) {
00368         CSWriteFrameByte(*p++);
00369     }
00370 
00371     p = nb->nb_ap.vp;
00372     for (i = 0; i < nb->nb_ap.sz; i++) {
00373         CSWriteFrameByte(*p++);
00374     }
00375 
00376     CSEndFrame();
00377 
00378     return 0;
00379 }
00380 
00381 void CSSoftwareWakeup(void)
00382 {
00383     volatile u_char *p;
00384     u_short          data = CS_SELF_CTRL;
00385 
00386     p = (u_char *) CS_PP_PTR;
00387     *p = data;
00388     p++;
00389     *p = data >> 8;
00390 
00391     NutDelay(10);
00392 }
00393 
00394 
00395 void CSSoftwareReset(void)
00396 {
00397     volatile u_char *p;
00398     u_short          data;
00399 
00400     data = CS_SELF_CTRL;
00401     p  = (u_char *) CS_PP_PTR;    
00402     *p = data;
00403     p++;
00404     *p = data >> 8;
00405         
00406     data = 0x0040;
00407     p  = (u_char *) CS_DATA_P0;
00408     *p = data;
00409     p++;
00410     *p = data >> 8;
00411 }
00412 
00413 
00414 THREAD(CSNICrx, arg)
00415 {
00416     NUTDEVICE *dev;
00417     IFNET *ifn;
00418     NICINFO *ni;
00419     NETBUF *nb;
00420     u_char *p;
00421     u_char *q;
00422     u_short i, m;
00423     volatile u_short l;
00424 
00425     dev = arg;
00426     ifn = (IFNET *) dev->dev_icb;
00427     ni = (NICINFO *) dev->dev_dcb;
00428 
00429 #if 0
00430     if (tcp_trace) {
00431         NutPrintFormat_P(dev_debug, PSTR("Enter ETHReceive\r\n"));
00432         NutPrintFlush(dev_debug);
00433     }
00434 #endif
00435 
00436     l = 0;
00437 
00438     NutThreadSetPriority(8);
00439     for (;;) {
00440         while ((CSReadPP16(CS_RX_EVENT) & 0x0100) == 0) {
00441             NutSleep(10);
00442         }
00443 
00444         l = *(u_char *) (CS_DATA_P0 + 1) << 8 | *(u_char *) (CS_DATA_P0);
00445         l = *(u_char *) (CS_DATA_P0 + 1) << 8 | *(u_char *) (CS_DATA_P0);
00446         
00447         //NutPrintFormat_P(dev_debug,PSTR("RxLength = %x \r\n"), l);
00448         //NutPrintFlush(dev_debug);
00449 
00450         // Account for odd length packets
00451         if (l & 1)
00452             m = l - 1;
00453         else
00454             m = l;
00455 
00456 
00457         nb = NutNetBufAlloc(0, NBAF_DATALINK, l);
00458         if (nb) {
00459             q = nb->nb_dl.vp;
00460             for (i = 0; i < m; i += 2) {
00461                 p = (u_char *) CS_DATA_P0;
00462                 *q++ = *p;
00463                 p = (u_char *) CS_DATA_P0 + 1;
00464                 *q++ = *p;
00465             }
00466 
00467             // Odd length packets
00468             if (m != l) {
00469                 p = (u_char *) CS_DATA_P0;
00470                 *q++ = *p;
00471 
00472                 p = (u_char *) CS_DATA_P0 + 1;
00473                 m = *p;
00474             }
00475             ni->ni_rx_packets++;
00476             (*ifn->if_recv) (dev, nb);
00477         }
00478     }
00479 }
00480 
00481 /*=========================================================================*/
00482 /*  DEFINE: All code exported                                              */
00483 /*=========================================================================*/
00484 
00485 
00486 
00497 int cs8900Output(NUTDEVICE * dev, NETBUF * nb)
00498 {
00499     int rc = -1;
00500     NICINFO *ni;
00501 
00502     ni = (NICINFO *) dev->dev_dcb;
00503 
00504 #if 0
00505     if (tcp_trace) {
00506         NutPrintFormat_P(dev_debug, PSTR("Enter EthOutput\r\n"));
00507         NutPrintFlush(dev_debug);
00508     }
00509 #endif
00510 
00511     if ((rc = CSEthPutPacket(dev, nb)) == 0)
00512         ni->ni_tx_packets++;
00513 
00514     return rc;
00515 }
00516 
00534 int cs8900Init(NUTDEVICE * dev)
00535 {
00536     u_short  i;
00537     u_short  j;
00538     IFNET   *ifn;
00539     NICINFO *ni;
00540     
00541 #if 0
00542     if (tcp_trace) {
00543         NutPrintFormat_P(dev_debug, PSTR("Enter NicInit  \r\n"));
00544         NutPrintFlush(dev_debug);
00545     }
00546 #endif
00547 
00548     cs_base = dev->dev_base;
00549     
00550 #if defined(OLIMEX_LPCE2294)
00551     if (cs_base == 0)
00552     {
00553       cs_base = 0x82000000UL;
00554     }
00555 #endif    
00556 
00557 
00558     if (confnet.cd_size == 0)
00559         NutNetLoadConfig(dev->dev_name);
00560 
00561     ifn = dev->dev_icb;
00562 #if 0 /* @@MF */
00563     memcpy(ifn->if_mac, confnet.cdn_mac, 6);
00564 #else
00565     ifn->if_mac[0] = 0x00;
00566     ifn->if_mac[1] = 0x06;
00567     ifn->if_mac[2] = 0x98;
00568     ifn->if_mac[3] = 0x00;
00569     ifn->if_mac[4] = 0x00;
00570     ifn->if_mac[5] = 0x00;
00571 #endif    
00572     memset(dev->dev_dcb, 0, sizeof(NICINFO));
00573     ni = (NICINFO *) dev->dev_dcb;
00574 
00575     // Take CS8900 out of reset and wait for internal reset to complete
00576     CSSoftwareWakeup();
00577     CSSoftwareReset();
00578 
00579     NutDelay(100);
00580 
00581     // Check for presence
00582     if (CSReadPP16(CS_PROD_ID) != 0x630E)
00583         return -1;
00584 
00585     //
00586     //  Copy our MAC address to the NIC
00587     // 
00588     for (i = 0; i < 6; i += 2) {
00589         j = ifn->if_mac[i] << 8;
00590         j |= ifn->if_mac[i + 1];
00591         CSWritePP16(CS_IEEE_ADDR + i, j);
00592         j = CSReadPP16(CS_IEEE_ADDR + i);
00593 #if 0
00594         if (tcp_trace) {
00595             NutPrintFormat_P(dev_debug, PSTR("ADDR = %x\r\n"), j);
00596             NutPrintFlush(dev_debug);
00597         }
00598 #endif
00599     }
00600 
00601     //
00602     // Enable the Transmitter and Receiver
00603     //
00604     CSWritePP16(CS_LINE_CTRL, 0x00C0);
00605     //i = CSReadPP16(CS_LINE_CTRL);
00606     //NutPrintFormat_P(dev_debug,PSTR("CS_LINE_CTRL = %x\r\n"), i);
00607 
00608     CSWritePP16(CS_RX_CTL, 0x0F40);
00609     //i = CSReadPP16(CS_RX_CTL);
00610     //NutPrintFormat_P(dev_debug,PSTR("CS_RX_CTL = %x\r\n"), i);
00611 
00612     // 
00613     // Start receiver thread
00614     //
00615     NutThreadCreate("csnicrx", CSNICrx, dev, 768);
00616 
00617     return 0;
00618 }
00619 
00620 static NICINFO dcb_eth0;
00621 
00627 static IFNET ifn_eth0 = {
00628     IFT_ETHER,                  
00629     {0, 0, 0, 0, 0, 0},         
00630     0,                          
00631     0,                          
00632     0,                          
00633     ETHERMTU,                   
00634     0,                          
00635     0,                          
00636     0,                          
00637     NutEtherInput,              
00638     cs8900Output,               
00639     NutEtherOutput              
00640 };
00641 
00651 NUTDEVICE devCS8900A = {
00652     0,                          /* Pointer to next device. */
00653     {'e', 't', 'h', '0', 0, 0, 0, 0, 0},        /* Unique device name. */
00654     IFTYP_NET,                  /* Type of device. */
00655     0,                          /* Base address. */
00656     0,                          /* First interrupt number. */
00657     &ifn_eth0,                  /* Interface control block. */
00658     &dcb_eth0,                  /* Driver control block. */
00659     cs8900Init,                 /* Driver initialization routine. */
00660     0,                          /* Driver specific control function. */
00661     0,                          /* Read from device. */
00662     0,                          /* Write to device. */
00663     0,                          /* Open a device or file. */
00664     0,                          /* Close a device or file. */
00665     0                           /* Request file size. */
00666 };
00667 

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/