at91_emac.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006-2007 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: at91_emac.c,v $
00036  * Revision 1.14  2008/08/28 11:12:15  haraldkipp
00037  * Added interface flags, which will be required to implement Ethernet ioctl
00038  * functions.
00039  *
00040  * Revision 1.13  2008/08/11 06:59:04  haraldkipp
00041  * BSD types replaced by stdint types (feature request #1282721).
00042  *
00043  * Revision 1.12  2008/08/06 12:43:41  haraldkipp
00044  * First EMAC reset failed on power-up. Initialize EMAC clock and MII mode
00045  * earlier.
00046  * Added support for Ethernut 5 (AT91SAM9XE reference design).
00047  *
00048  * Revision 1.11  2007/09/06 20:07:24  olereinhardt
00049  * Changed phy detection and added support for micel phy (SAM7-EX256 Board)
00050  *
00051  * Revision 1.10  2007/08/29 07:43:52  haraldkipp
00052  * Documentation updated and corrected.
00053  *
00054  * Revision 1.9  2007/05/02 11:20:26  haraldkipp
00055  * Pull-up enable/disable simplified.
00056  * Added multicast table entry.
00057  *
00058  * Revision 1.8  2007/04/20 13:06:08  haraldkipp
00059  * Previous change failed on SAM7X-EK. We are now using PHY address 0 by
00060  * default and disable all pull-ups during PHY reset.
00061  *
00062  * Revision 1.7  2007/04/12 09:13:10  haraldkipp
00063  * Bugfix: PHY initialization may fail with pull-ups enabled.
00064  *
00065  * Revision 1.6  2007/02/15 16:00:45  haraldkipp
00066  * Configurable buffer usage and link timeout.
00067  *
00068  * Revision 1.5  2006/10/17 11:06:12  haraldkipp
00069  * Number of loops waiting for links increased to 10000 and NIC resets
00070  * reduced. This will help to link to auto MDIX via direct cable.
00071  *
00072  * Revision 1.4  2006/10/08 16:41:34  haraldkipp
00073  * PHY address and power down bit are now configurable.
00074  *
00075  * Revision 1.3  2006/10/05 17:10:37  haraldkipp
00076  * Link detection was unreliable. This also caused bug #1567785.
00077  * Now NutRegisterDevice will return an error, if there is no
00078  * link available. Applications may then call NutRegisterDevice again.
00079  *
00080  * Revision 1.2  2006/09/29 12:29:16  haraldkipp
00081  * Several fixes to make it running reliably on the AT91SAM9260.
00082  *
00083  * Revision 1.1  2006/08/31 18:58:47  haraldkipp
00084  * More general AT91 MAC driver replaces the SAM7X specific version.
00085  * This had been tested on the SAM9260, but loses Ethernet packets
00086  * for a yet unknown reason.
00087  *
00088  */
00089 
00090 #include <cfg/os.h>
00091 #include <cfg/dev.h>
00092 #include <arch/arm.h>
00093 #include <cfg/arch/gpio.h>
00094 
00095 #include <string.h>
00096 
00097 #include <sys/atom.h>
00098 #include <sys/heap.h>
00099 #include <sys/thread.h>
00100 #include <sys/event.h>
00101 #include <sys/timer.h>
00102 #include <sys/confnet.h>
00103 
00104 #include <netinet/if_ether.h>
00105 #include <net/ether.h>
00106 #include <net/if_var.h>
00107 
00108 #include <dev/irqreg.h>
00109 #include <dev/at91_emac.h>
00110 
00111 #ifdef NUTDEBUG
00112 #include <stdio.h>
00113 #endif
00114 
00115 #ifndef NUT_THREAD_NICRXSTACK
00116 #define NUT_THREAD_NICRXSTACK   768
00117 #endif
00118 
00119 #ifndef EMAC_RX_BUFFERS
00120 #define EMAC_RX_BUFFERS         32
00121 #endif
00122 #define EMAC_RX_BUFSIZ          128
00123 
00124 #define EMAC_TX_BUFFERS         2
00125 #ifndef EMAC_TX_BUFSIZ
00126 #define EMAC_TX_BUFSIZ          1536
00127 #endif
00128 
00129 #ifndef EMAC_LINK_LOOPS
00130 #define EMAC_LINK_LOOPS         1000000
00131 #endif
00132 
00137 #define NIC_PHY_BMCR            0x00    
00138 #define NIC_PHY_BMCR_COLTEST    0x0080  
00139 #define NIC_PHY_BMCR_FDUPLEX    0x0100  
00140 #define NIC_PHY_BMCR_ANEGSTART  0x0200  
00141 #define NIC_PHY_BMCR_ISOLATE    0x0400  
00142 #define NIC_PHY_BMCR_PWRDN      0x0800  
00143 #define NIC_PHY_BMCR_ANEGENA    0x1000  
00144 #define NIC_PHY_BMCR_100MBPS    0x2000  
00145 #define NIC_PHY_BMCR_LOOPBACK   0x4000  
00146 #define NIC_PHY_BMCR_RESET      0x8000  
00148 #define NIC_PHY_BMSR            0x01    
00149 #define NIC_PHY_BMSR_ANCOMPL    0x0020  
00150 #define NIC_PHY_BMSR_LINKSTAT   0x0004  
00152 #define NIC_PHY_ID1             0x02    
00153 #define NIC_PHY_ID2             0x03    
00154 #define NIC_PHY_ANAR            0x04    
00155 #define NIC_PHY_ANLPAR          0x05    
00156 #define NIC_PHY_ANEG_NP         0x8000  
00157 #define NIC_PHY_ANEG_ACK        0x4000  
00158 #define NIC_PHY_ANEG_RF         0x2000  
00159 #define NIC_PHY_ANEG_FCS        0x0400  
00160 #define NIC_PHY_ANEG_T4         0x0200  
00161 #define NIC_PHY_ANEG_TX_FDX     0x0100  
00162 #define NIC_PHY_ANEG_TX_HDX     0x0080  
00163 #define NIC_PHY_ANEG_10_FDX     0x0040  
00164 #define NIC_PHY_ANEG_10_HDX     0x0020  
00165 #define NIC_PHY_ANEG_BINSEL     0x001F  
00167 #define NIC_PHY_ANER            0x06    
00170 
00171 
00177 #ifndef NIC_PHY_ADDR
00178 #define NIC_PHY_ADDR            0
00179 #endif
00180 
00181 
00182 #if defined (MCU_AT91SAM9260) || defined(MCU_AT91SAM9XE512)
00183 
00189 #define PHY_MODE_RMII
00190 
00191 //#define EMAC_PIO_PER            PIOA_PER
00192 //#define EMAC_PIO_OER            PIOA_OER
00193 //#define EMAC_PIO_CODR           PIOA_CODR
00194 #define EMAC_PIO_PUER           PIOA_PUER
00195 #define EMAC_PIO_PUDR           PIOA_PUDR
00196 #define EMAC_PIO_ASR            PIOA_ASR
00197 #define EMAC_PIO_BSR            PIOA_BSR
00198 #define EMAC_PIO_PDR            PIOA_PDR
00199 
00200 #define PHY_TXD0_BIT            PA12_ETX0_A     
00201 #define PHY_TXD1_BIT            PA13_ETX1_A     
00202 #define PHY_RXD0_AD0_BIT        PA14_ERX0_A     
00203 #define PHY_RXD1_AD1_BIT        PA15_ERX1_A     
00204 #define PHY_TXEN_BIT            PA16_ETXEN_A    
00205 #define PHY_RXDV_TESTMODE_BIT   PA17_ERXDV_A    
00206 #define PHY_RXER_RXD4_RPTR_BIT  PA18_ERXER_A    
00207 #define PHY_TXCLK_ISOLATE_BIT   PA19_ETXCK_A    
00208 #define PHY_MDC_BIT             PA20_EMDC_A     
00209 #define PHY_MDIO_BIT            PA21_EMDIO_A    
00211 #ifndef PHY_MODE_RMII
00212 #define PHY_TXD2_BIT            PA10_ETX2_B     
00213 #define PHY_TXD3_BIT            PA11_ETX3_B     
00214 #define PHY_TXER_TXD4_BIT       PA22_ETXER_B    
00215 #define PHY_RXCLK_10BTSER_BIT   PA27_ERXCK_B    
00216 #define PHY_COL_RMII_BIT        PA29_ECOL_B     
00217 #endif
00218 
00219 #define PHY_RXD2_AD2_BIT        PA25_ERX2_B     
00220 #define PHY_RXD3_AD3_BIT        PA26_ERX3_B     
00221 #define PHY_CRS_AD4_BIT         PA28_ECRS_B     
00223 #define PHY_MII_PINS_A 0 \
00224     | _BV(PHY_TXD0_BIT) \
00225     | _BV(PHY_TXD1_BIT) \
00226     | _BV(PHY_RXD0_AD0_BIT) \
00227     | _BV(PHY_RXD1_AD1_BIT) \
00228     | _BV(PHY_TXEN_BIT) \
00229     | _BV(PHY_RXDV_TESTMODE_BIT) \
00230     | _BV(PHY_RXER_RXD4_RPTR_BIT) \
00231     | _BV(PHY_TXCLK_ISOLATE_BIT) \
00232     | _BV(PHY_MDC_BIT) \
00233     | _BV(PHY_MDIO_BIT)
00234 
00235 #ifdef PHY_MODE_RMII
00236 #define PHY_MII_PINS_B 0
00237 #else
00238 #define PHY_MII_PINS_B 0 \
00239     | _BV(PHY_TXD2_BIT) \
00240     | _BV(PHY_TXD3_BIT) \
00241     | _BV(PHY_TXER_TXD4_BIT) \
00242     | _BV(PHY_RXD2_AD2_BIT) \
00243     | _BV(PHY_RXD3_AD3_BIT) \
00244     | _BV(PHY_RXCLK_10BTSER_BIT) \
00245     | _BV(PHY_CRS_AD4_BIT) \
00246     | _BV(PHY_COL_RMII_BIT)
00247 #endif
00248 
00249 #elif defined (MCU_AT91SAM7X256)
00250 
00251 #define EMAC_PIO_PER            PIOB_PER
00252 #define EMAC_PIO_OER            PIOB_OER
00253 #define EMAC_PIO_CODR           PIOB_CODR
00254 #define EMAC_PIO_SODR           PIOB_SODR
00255 #define EMAC_PIO_PUER           PIOB_PUER
00256 #define EMAC_PIO_PUDR           PIOB_PUDR
00257 #define EMAC_PIO_ASR            PIOB_ASR
00258 #define EMAC_PIO_BSR            PIOB_BSR
00259 #define EMAC_PIO_PDR            PIOB_PDR
00260 
00261 #define PHY_TXCLK_ISOLATE_BIT   0
00262 #define PHY_REFCLK_XT2_BIT      0
00263 #define PHY_TXEN_BIT            1
00264 #define PHY_TXD0_BIT            2
00265 #define PHY_TXD1_BIT            3
00266 #define PHY_CRS_AD4_BIT         4
00267 #define PHY_RXD0_AD0_BIT        5
00268 #define PHY_RXD1_AD1_BIT        6
00269 #define PHY_RXER_RXD4_RPTR_BIT  7
00270 #define PHY_MDC_BIT             8
00271 #define PHY_MDIO_BIT            9
00272 #define PHY_TXD2_BIT            10
00273 #define PHY_TXD3_BIT            11
00274 #define PHY_TXER_TXD4_BIT       12
00275 #define PHY_RXD2_AD2_BIT        13
00276 #define PHY_RXD3_AD3_BIT        14
00277 #define PHY_RXDV_TESTMODE_BIT   15
00278 #define PHY_COL_RMII_BIT        16
00279 #define PHY_RXCLK_10BTSER_BIT   17
00280 #ifndef PHY_PWRDN_BIT
00281 #define PHY_PWRDN_BIT           18
00282 #endif
00283 #define PHY_MDINTR_BIT          26
00284 
00285 #define PHY_MII_PINS_A 0 \
00286     | _BV(PHY_REFCLK_XT2_BIT) \
00287     | _BV(PHY_TXEN_BIT) \
00288     | _BV(PHY_TXD0_BIT) \
00289     | _BV(PHY_TXD1_BIT) \
00290     | _BV(PHY_CRS_AD4_BIT) \
00291     | _BV(PHY_RXD0_AD0_BIT) \
00292     | _BV(PHY_RXD1_AD1_BIT) \
00293     | _BV(PHY_RXER_RXD4_RPTR_BIT) \
00294     | _BV(PHY_MDC_BIT) \
00295     | _BV(PHY_MDIO_BIT) \
00296     | _BV(PHY_TXD2_BIT) \
00297     | _BV(PHY_TXD3_BIT) \
00298     | _BV(PHY_TXER_TXD4_BIT) \
00299     | _BV(PHY_RXD2_AD2_BIT) \
00300     | _BV(PHY_RXD3_AD3_BIT) \
00301     | _BV(PHY_RXDV_TESTMODE_BIT) \
00302     | _BV(PHY_COL_RMII_BIT) \
00303     | _BV(PHY_RXCLK_10BTSER_BIT)
00304 
00305 #define PHY_MII_PINS_B 0
00306 
00307 #endif
00308 
00312 struct _EMACINFO {
00313 #ifdef NUT_PERFMON
00314     uint32_t ni_rx_packets;       
00315     uint32_t ni_tx_packets;       
00316     uint32_t ni_overruns;         
00317     uint32_t ni_rx_frame_errors;  
00318     uint32_t ni_rx_crc_errors;    
00319     uint32_t ni_rx_missed_errors; 
00320 #endif
00321     HANDLE volatile ni_rx_rdy;  
00322     HANDLE volatile ni_tx_rdy;  
00323     HANDLE ni_mutex;            
00324     volatile int ni_tx_queued;  
00325     volatile int ni_tx_quelen;  
00326     volatile int ni_insane;     
00327     int ni_iomode;              
00328 };
00329 
00333 typedef struct _EMACINFO EMACINFO;
00334 
00335 /*
00336  * TODO: Buffers and their descriptors should be part of the EMACINFO
00337  * structure. Actually there will be no dual Ethernet chip (sure?),
00338  * but just to keep the code clean.
00339  */
00340 typedef struct _BufDescriptor {
00341     u_int addr;
00342     u_int stat;
00343 } BufDescriptor;
00344 
00345 static volatile BufDescriptor txBufTab[EMAC_TX_BUFFERS];
00346 static volatile uint8_t txBuf[EMAC_TX_BUFFERS * EMAC_TX_BUFSIZ] __attribute__ ((aligned(8)));
00347 static u_int txBufIdx;
00348 
00349 static volatile BufDescriptor rxBufTab[EMAC_RX_BUFFERS];
00350 static volatile uint8_t rxBuf[EMAC_RX_BUFFERS * EMAC_RX_BUFSIZ] __attribute__ ((aligned(8)));
00351 static u_int rxBufIdx;
00352 
00353 #define RXBUF_OWNERSHIP     0x00000001
00354 #define RXBUF_WRAP          0x00000002
00355 #define RXBUF_ADDRMASK      0xFFFFFFFC
00356 
00357 #define RXS_BROADCAST_ADDR  0x80000000  
00358 #define RXS_MULTICAST_HASH  0x40000000  
00359 #define RXS_UNICAST_HASH    0x20000000  
00360 #define RXS_EXTERNAL_ADDR   0x10000000  
00361 #define RXS_SA1_ADDR        0x04000000  
00362 #define RXS_SA2_ADDR        0x02000000  
00363 #define RXS_SA3_ADDR        0x01000000  
00364 #define RXS_SA4_ADDR        0x00800000  
00365 #define RXS_TYPE_ID         0x00400000  
00366 #define RXS_VLAN_TAG        0x00200000  
00367 #define RXS_PRIORITY_TAG    0x00100000  
00368 #define RXS_VLAN_PRIORITY   0x000E0000  
00369 #define RXS_CFI_IND         0x00010000  
00370 #define RXS_EOF             0x00008000  
00371 #define RXS_SOF             0x00004000  
00372 #define RXS_RBF_OFFSET      0x00003000  
00373 #define RXS_LENGTH_FRAME    0x000007FF  
00375 #define TXS_USED            0x80000000  
00376 #define TXS_WRAP            0x40000000  
00377 #define TXS_ERROR           0x20000000  
00378 #define TXS_UNDERRUN        0x10000000  
00379 #define TXS_NO_BUFFER       0x08000000  
00380 #define TXS_NO_CRC          0x00010000  
00381 #define TXS_LAST_BUFF       0x00008000  
00388 
00389 
00396 static uint16_t phy_inw(uint8_t reg)
00397 {
00398     /* PHY read command. */
00399     outr(EMAC_MAN, EMAC_SOF | EMAC_RW_READ | EMAC_CODE | 
00400         (NIC_PHY_ADDR << EMAC_PHYA_LSB) | (reg << EMAC_REGA_LSB));
00401 
00402     /* Wait until PHY logic completed. */
00403     while ((inr(EMAC_NSR) & EMAC_IDLE) == 0);
00404 
00405     /* Get data from PHY maintenance register. */
00406     return (uint16_t) (inr(EMAC_MAN) >> EMAC_DATA_LSB);
00407 }
00408 
00409 #ifndef PHY_MODE_RMII
00410 
00416 static void phy_outw(uint8_t reg, uint16_t val)
00417 {
00418     /* PHY write command. */
00419     outr(EMAC_MAN, EMAC_SOF | EMAC_RW_WRITE | EMAC_CODE | 
00420         (NIC_PHY_ADDR << EMAC_PHYA_LSB) | (reg << EMAC_REGA_LSB) | val);
00421 
00422     /* Wait until PHY logic completed. */
00423     while ((inr(EMAC_NSR) & EMAC_IDLE) == 0);
00424 }
00425 #endif
00426 
00432 static int EmacReset(uint32_t tmo)
00433 {
00434     uint16_t phyval;
00435 
00436     outr(PMC_PCER, _BV(PIOA_ID));
00437     outr(PMC_PCER, _BV(PIOB_ID));
00438     outr(PMC_PCER, _BV(EMAC_ID));
00439 
00440 #if defined (MCU_AT91SAM9260) || defined(MCU_AT91SAM7X256)
00441     /* Disable TESTMODE and set PHY address 0 and by disabling pull-ups. */
00442     outr(EMAC_PIO_PUDR,
00443 #if !defined(PHY_MODE_RMII)
00444         /* Additionally disable RMII, if not configured. */
00445         _BV(PHY_COL_RMII_BIT) | 
00446 #endif
00447         _BV(PHY_RXDV_TESTMODE_BIT) | 
00448         _BV(PHY_RXD0_AD0_BIT) | _BV(PHY_RXD1_AD1_BIT) |
00449         _BV(PHY_RXD2_AD2_BIT) | _BV(PHY_RXD3_AD3_BIT) | _BV(PHY_CRS_AD4_BIT));
00450 
00451 #ifdef PHY_PWRDN_BIT
00452     /* Disable PHY power down. */
00453     outr(EMAC_PIO_PER, _BV(PHY_PWRDN_BIT));
00454     outr(EMAC_PIO_OER, _BV(PHY_PWRDN_BIT));
00455 #ifdef PHY_PWRDN_NEGPOL
00456     outr(EMAC_PIO_SODR, _BV(PHY_PWRDN_BIT));
00457 #else
00458     outr(EMAC_PIO_CODR, _BV(PHY_PWRDN_BIT));
00459 #endif
00460 #endif
00461 
00462     /* Toggle external hardware reset pin. */
00463     outr(RSTC_MR, RSTC_KEY | (2 << RSTC_ERSTL_LSB) | RSTC_URSTEN);
00464     outr(RSTC_CR, RSTC_KEY | RSTC_EXTRST);
00465     while ((inr(RSTC_SR) & RSTC_NRSTL) == 0);
00466 
00467     /* Re-enable pull-ups. */
00468     outr(EMAC_PIO_PUER, _BV(PHY_RXDV_TESTMODE_BIT) | 
00469         _BV(PHY_RXD0_AD0_BIT) | _BV(PHY_RXD1_AD1_BIT) |
00470         _BV(PHY_RXD2_AD2_BIT) | _BV(PHY_RXD3_AD3_BIT) | _BV(PHY_CRS_AD4_BIT));
00471 #endif /* MCU_AT91SAM9XE512 */
00472 
00473     /* Configure MII port. */
00474     outr(EMAC_PIO_ASR, PHY_MII_PINS_A);
00475     outr(EMAC_PIO_BSR, PHY_MII_PINS_B);
00476     outr(EMAC_PIO_PDR, PHY_MII_PINS_A | PHY_MII_PINS_B);
00477 
00478     /* Enable receive and transmit clocks and set MII mode. */
00479 #ifdef PHY_MODE_RMII
00480     outr(EMAC_USRIO, EMAC_RMII | EMAC_CLKEN);
00481 #else
00482     outr(EMAC_USRIO, EMAC_CLKEN);
00483 #endif
00484 
00485     /* Enable management port. */
00486     outr(EMAC_NCR, inr(EMAC_NCR) | EMAC_MPE);
00487     outr(EMAC_NCFGR, inr(EMAC_NCFGR) | EMAC_CLK_HCLK_64);
00488 
00489     /* Wait for PHY ready. */
00490     NutDelay(255);
00491 
00492 #ifndef PHY_MODE_RMII
00493     /* Clear MII isolate. */
00494     phy_inw(NIC_PHY_BMCR);
00495     phy_outw(NIC_PHY_BMCR, phy_inw(NIC_PHY_BMCR) & ~NIC_PHY_BMCR_ISOLATE);
00496 #endif
00497 
00498 //    /* For some unknown reason it seems to be required to read the ID registers first. */
00499 //    if (phy_inw(NIC_PHY_ID1) != 0x0181 || (phy_inw(NIC_PHY_ID2) & 0xFFF0) != 0xB8A0) {
00500 //        outr(EMAC_NCR, inr(EMAC_NCR) & ~EMAC_MPE);
00501 //        return -1;
00502 //    }
00503 
00504 // TODO: Make phy id configurable
00505 /* PHY ID */
00506 #define MII_DM9161_ID_H     0x0181
00507 #define MII_DM9161_ID_L     0xb8a0
00508 
00509 #define MII_AM79C875_ID_H   0x0022
00510 #define MII_AM79C875_ID_L   0x5540      
00511 
00512 #define MII_MICREL_ID_H     0x0022
00513 #define MII_MICREL_ID_L     0x1610
00514 
00515 #define MII_LAN8700_ID_H    0x0007
00516 #define MII_LAN8700_ID_L    0xc0c0
00517 
00518      /* For some unknown reason it seems to be required to read the ID 
00519 registers first. */
00520 
00521      // Check for DM PHY (as used on the ATMEL EK)
00522     if (phy_inw(NIC_PHY_ID1) != MII_DM9161_ID_H ||
00523        (phy_inw(NIC_PHY_ID2) & 0xFFF0) != MII_DM9161_ID_L) {
00524      // Check for MICREL PHY (as used on the Olimex SAM7-EX256)         
00525         if (phy_inw(NIC_PHY_ID1) != MII_MICREL_ID_H ||
00526            (phy_inw(NIC_PHY_ID2) & 0xFFF0) != MII_MICREL_ID_L) {
00527             if (phy_inw(NIC_PHY_ID1) != MII_LAN8700_ID_H ||
00528                (phy_inw(NIC_PHY_ID2) & 0xFFF0) != MII_LAN8700_ID_L) {
00529                 outr(EMAC_NCR, inr(EMAC_NCR) & ~EMAC_MPE);
00530                 return -1;
00531             }
00532         }
00533     }
00534 
00535 
00536 // TODO: END
00537 
00538     /* Handle auto negotiation if configured. */
00539     phyval = phy_inw(NIC_PHY_BMCR);
00540     if (phyval & NIC_PHY_BMCR_ANEGENA) {
00541         /* Wait for auto negotiation completed. */
00542         phy_inw(NIC_PHY_BMSR);  /* Discard previously latched status. */
00543         while (--tmo) {
00544             if (phy_inw(NIC_PHY_BMSR) & NIC_PHY_BMSR_ANCOMPL) {
00545                 break;
00546             }
00547         }
00548         /* Return error on link timeout. */
00549         if (tmo == 0) {
00550             outr(EMAC_NCR, inr(EMAC_NCR) & ~EMAC_MPE);
00551             return -1;
00552         }
00553 
00554         /*
00555          * Read link partner abilities and configure EMAC.
00556          */
00557         phyval = phy_inw(NIC_PHY_ANLPAR);
00558         if (phyval & NIC_PHY_ANEG_TX_FDX) {
00559             /* 100Mb full duplex. */
00560             outr(EMAC_NCFGR, inr(EMAC_NCFGR) | EMAC_SPD | EMAC_FD);
00561         }
00562         else if (phyval & NIC_PHY_ANEG_TX_HDX) {
00563             /* 100Mb half duplex. */
00564             outr(EMAC_NCFGR, (inr(EMAC_NCFGR) & ~EMAC_FD) | EMAC_SPD);
00565         }
00566         else if (phyval & NIC_PHY_ANEG_10_FDX) {
00567             /* 10Mb full duplex. */
00568             outr(EMAC_NCFGR, (inr(EMAC_NCFGR) & ~EMAC_SPD) | EMAC_FD);
00569         }
00570         else {
00571             /* 10Mb half duplex. */
00572             outr(EMAC_NCFGR, inr(EMAC_NCFGR) & ~(EMAC_SPD | EMAC_FD));
00573         }
00574     }
00575 
00576     /* Disable management port. */
00577     outr(EMAC_NCR, inr(EMAC_NCR) & ~EMAC_MPE);
00578 
00579     return 0;
00580 }
00581 
00582 /*
00583  * NIC interrupt entry.
00584  */
00585 static void EmacInterrupt(void *arg)
00586 {
00587     u_int isr;
00588     EMACINFO *ni = (EMACINFO *) ((NUTDEVICE *) arg)->dev_dcb;
00589 
00590     /* Read interrupt status and disable interrupts. */
00591     isr = inr(EMAC_ISR);
00592 
00593     /* Receiver interrupt. */
00594     //if ((isr & EMAC_RCOMP) != 0 || (isr & EMAC_ROVR) != 0 || (inr(EMAC_RSR) & EMAC_REC) != 0) {
00595     if ((isr & (EMAC_RCOMP | EMAC_ROVR | EMAC_RXUBR)) != 0) {
00596         //outr(EMAC_RSR, EMAC_REC);
00597         outr(EMAC_IDR, EMAC_RCOMP | EMAC_ROVR | EMAC_RXUBR);
00598         NutEventPostFromIrq(&ni->ni_rx_rdy);
00599     }
00600 
00601     /* Transmitter interrupt. */
00602     if ((isr & EMAC_TCOMP) != 0 || (inr(EMAC_TSR) & EMAC_COMP) != 0) {
00603         //outr(EMAC_TSR, EMAC_COMP);
00604         NutEventPostFromIrq(&ni->ni_tx_rdy);
00605     }
00606 }
00607 
00613 static int EmacGetPacket(EMACINFO * ni, NETBUF ** nbp)
00614 {
00615     int rc = -1;
00616     u_int fbc = 0;
00617     u_int i;
00618     *nbp = NULL;
00619 
00620     /*
00621      * Search the next frame start. Release any fragment.
00622      */
00623     while ((rxBufTab[rxBufIdx].addr & RXBUF_OWNERSHIP) != 0 && (rxBufTab[rxBufIdx].stat & RXS_SOF) == 0) {
00624         rxBufTab[rxBufIdx].addr &= ~(RXBUF_OWNERSHIP);
00625         rxBufIdx++;
00626         if (rxBufIdx >= EMAC_RX_BUFFERS) {
00627             rxBufIdx = 0;
00628         }
00629     }
00630 
00631     /*
00632      * Determine the size of the next frame.
00633      */
00634     i = rxBufIdx;
00635     while (rxBufTab[i].addr & RXBUF_OWNERSHIP) {
00636         if (i != rxBufIdx && (rxBufTab[i].stat & RXS_SOF) != 0) {
00637             do {
00638                 rxBufTab[rxBufIdx].addr &= ~(RXBUF_OWNERSHIP);
00639                 rxBufIdx++;
00640                 if (rxBufIdx >= EMAC_RX_BUFFERS) {
00641                     rxBufIdx = 0;
00642                 }
00643             } while ((rxBufTab[rxBufIdx].addr & RXBUF_OWNERSHIP) != 0 && (rxBufTab[rxBufIdx].stat & RXS_SOF) == 0);
00644             break;
00645         }
00646         if ((fbc = rxBufTab[i].stat & RXS_LENGTH_FRAME) != 0) {
00647             break;
00648         }
00649         i++;
00650         if (i >= EMAC_RX_BUFFERS) {
00651             i = 0;
00652         }
00653     }
00654 
00655     if (fbc) {
00656         /*
00657          * Receiving long packets is unexpected. Let's declare the 
00658          * chip insane. Short packets will be handled by the caller.
00659          */
00660         if (fbc > 1536) {
00661             ni->ni_insane = 1;
00662         } else {
00663             *nbp = NutNetBufAlloc(0, NBAF_DATALINK, (uint16_t)fbc);
00664             if (*nbp != NULL) {
00665                 uint8_t *bp = (uint8_t *) (* nbp)->nb_dl.vp;
00666                 u_int len;
00667 
00668                 while (fbc) {
00669                     if (fbc > EMAC_RX_BUFSIZ) {
00670                         len = EMAC_RX_BUFSIZ;
00671                     } else {
00672                         len = fbc;
00673                     }
00674                     memcpy(bp, (void *) (rxBufTab[rxBufIdx].addr & RXBUF_ADDRMASK), len);
00675                     rxBufTab[rxBufIdx].addr &= ~RXBUF_OWNERSHIP;
00676                     rxBufIdx++;
00677                     if (rxBufIdx >= EMAC_RX_BUFFERS) {
00678                         rxBufIdx = 0;
00679                     }
00680                     fbc -= len;
00681                     bp += len;
00682                 }
00683                 rc = 0;
00684             }
00685         }
00686     }
00687     return rc;
00688 }
00689 
00704 static int EmacPutPacket(int bufnum, EMACINFO * ni, NETBUF * nb)
00705 {
00706     int rc = -1;
00707     u_int sz;
00708     uint8_t *buf;
00709 
00710     /*
00711      * Calculate the number of bytes to be send. Do not send packets 
00712      * larger than the Ethernet maximum transfer unit. The MTU
00713      * consist of 1500 data bytes plus the 14 byte Ethernet header
00714      * plus 4 bytes CRC. We check the data bytes only.
00715      */
00716     if ((sz = nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz) > ETHERMTU) {
00717         return -1;
00718     }
00719     sz += nb->nb_dl.sz;
00720     if (sz & 1) {
00721         sz++;
00722     }
00723 
00724     /* Disable EMAC interrupts. */
00725     NutIrqDisable(&sig_EMAC);
00726 
00727     /* TODO: Check for link. */
00728     if (ni->ni_insane == 0) {
00729         buf = (uint8_t *) txBufTab[bufnum].addr;
00730         memcpy(buf, nb->nb_dl.vp, nb->nb_dl.sz);
00731         buf += nb->nb_dl.sz;
00732         memcpy(buf, nb->nb_nw.vp, nb->nb_nw.sz);
00733         buf += nb->nb_nw.sz;
00734         memcpy(buf, nb->nb_tp.vp, nb->nb_tp.sz);
00735         buf += nb->nb_tp.sz;
00736         memcpy(buf, nb->nb_ap.vp, nb->nb_ap.sz);
00737         sz |= TXS_LAST_BUFF;
00738         if (bufnum) {
00739             sz |= TXS_WRAP;
00740         }
00741         txBufTab[bufnum].stat = sz;
00742         outr(EMAC_NCR, inr(EMAC_NCR) | EMAC_TSTART);
00743         rc = 0;
00744 #ifdef NUT_PERFMON
00745         ni->ni_tx_packets++;
00746 #endif
00747     }
00748 
00749     /* Enable EMAC interrupts. */
00750     NutIrqEnable(&sig_EMAC);
00751 
00752     return rc;
00753 }
00754 
00755 
00763 static int EmacStart(CONST uint8_t * mac)
00764 {
00765     u_int i;
00766 
00767     /* Set local MAC address. */
00768     outr(EMAC_SA1L, (mac[3] << 24) | (mac[2] << 16) | (mac[1] << 8) | mac[0]);
00769     outr(EMAC_SA1H, (mac[5] << 8) | mac[4]);
00770 
00771     /* Initialize receive buffer descriptors. */
00772     for (i = 0; i < EMAC_RX_BUFFERS - 1; i++) {
00773         rxBufTab[i].addr = (u_int) (&rxBuf[i * EMAC_RX_BUFSIZ]) & RXBUF_ADDRMASK;
00774     }
00775     rxBufTab[i].addr = ((u_int) (&rxBuf[i * EMAC_RX_BUFSIZ]) & RXBUF_ADDRMASK) | RXBUF_WRAP;
00776     outr(EMAC_RBQP, (u_int) rxBufTab);
00777 
00778     /* Initialize transmit buffer descriptors. */
00779     txBufTab[0].addr = (u_int) (&txBuf[0]);
00780     txBufTab[0].stat = TXS_USED;
00781     txBufTab[1].addr = (u_int) (&txBuf[EMAC_TX_BUFSIZ]);
00782     txBufTab[1].stat = TXS_USED | TXS_WRAP;
00783     outr(EMAC_TBQP, (u_int) txBufTab);
00784 
00785     /* Clear receiver status. */
00786     outr(EMAC_RSR, EMAC_OVR | EMAC_REC | EMAC_BNA);
00787 
00788     /* Copy all frames and discard FCS. */
00789     outr(EMAC_NCFGR, inr(EMAC_NCFGR) | EMAC_CAF | EMAC_DRFCS);
00790 
00791     /* Enable receiver, transmitter and statistics. */
00792     outr(EMAC_NCR, inr(EMAC_NCR) | EMAC_TE | EMAC_RE | EMAC_WESTAT);
00793 
00794     return 0;
00795 }
00796 
00801 THREAD(EmacRxThread, arg)
00802 {
00803     NUTDEVICE *dev;
00804     IFNET *ifn;
00805     EMACINFO *ni;
00806     NETBUF *nb;
00807 
00808     dev = arg;
00809     ifn = (IFNET *) dev->dev_icb;
00810     ni = (EMACINFO *) dev->dev_dcb;
00811 
00812     /*
00813      * This is a temporary hack. Due to a change in initialization,
00814      * we may not have got a MAC address yet. Wait until one has been
00815      * set.
00816      */
00817     for (;;) {
00818         int i;
00819 
00820         for (i = 0; i < sizeof(ifn->if_mac); i++) {
00821             if (ifn->if_mac[i] && ifn->if_mac[i] != 0xFF) {
00822                 break;
00823             }
00824         }
00825         if (i < sizeof(ifn->if_mac)) {
00826             break;
00827         }
00828         NutSleep(63);
00829     }
00830 
00831     /*
00832      * Do not continue unless we managed to start the NIC. We are
00833      * trapped here if the Ethernet link cannot be established.
00834      * This happens, for example, if no Ethernet cable is plugged
00835      * in.
00836      */
00837     while (EmacStart(ifn->if_mac)) {
00838         EmacReset(EMAC_LINK_LOOPS);
00839         NutSleep(1000);
00840     }
00841 
00842     /* Initialize the access mutex. */
00843     NutEventPost(&ni->ni_mutex);
00844 
00845     /* Run at high priority. */
00846     NutThreadSetPriority(9);
00847 
00848     /* Enable receive and transmit interrupts. */
00849     outr(EMAC_IER, EMAC_ROVR | EMAC_TCOMP | EMAC_TUND | EMAC_RXUBR | EMAC_RCOMP);
00850     NutIrqEnable(&sig_EMAC);
00851 
00852     for (;;) {
00853         /*
00854          * Wait for the arrival of new packets or poll the receiver every 
00855          * 200 milliseconds. This short timeout helps a bit to deal with
00856          * the SAM9260 Ethernet problem.
00857          */
00858         NutEventWait(&ni->ni_rx_rdy, 200);
00859 
00860         /*
00861          * Fetch all packets from the NIC's internal buffer and pass 
00862          * them to the registered handler.
00863          */
00864         while (EmacGetPacket(ni, &nb) == 0) {
00865             /* Discard short packets. */
00866             if (nb->nb_dl.sz < 60) {
00867                 NutNetBufFree(nb);
00868             } else {
00869                 (*ifn->if_recv) (dev, nb);
00870             }
00871         }
00872         outr(EMAC_IER, EMAC_ROVR | EMAC_RXUBR | EMAC_RCOMP);
00873 
00874         /* We got a weird chip, try to restart it. */
00875         while (ni->ni_insane) {
00876             EmacReset(EMAC_LINK_LOOPS);
00877             if (EmacStart(ifn->if_mac) == 0) {
00878                 ni->ni_insane = 0;
00879                 ni->ni_tx_queued = 0;
00880                 ni->ni_tx_quelen = 0;
00881                 NutIrqEnable(&sig_EMAC);
00882             } else {
00883                 NutSleep(1000);
00884             }
00885         }
00886     }
00887 }
00888 
00899 int EmacOutput(NUTDEVICE * dev, NETBUF * nb)
00900 {
00901     static uint32_t mx_wait = 5000;
00902     int rc = -1;
00903     EMACINFO *ni = (EMACINFO *) dev->dev_dcb;
00904 
00905     /*
00906      * After initialization we are waiting for a long time to give
00907      * the PHY a chance to establish an Ethernet link.
00908      */
00909     while (rc) {
00910         if (ni->ni_insane) {
00911             break;
00912         }
00913         if (NutEventWait(&ni->ni_mutex, mx_wait)) {
00914             break;
00915         }
00916 
00917         /* Check for packet queue space. */
00918         if ((txBufTab[txBufIdx].stat & TXS_USED) == 0) {
00919             if (NutEventWait(&ni->ni_tx_rdy, 500) && (txBufTab[txBufIdx].stat & TXS_USED) == 0) {
00920                 /* No queue space. Release the lock and give up. */
00921                 txBufTab[txBufIdx].stat |= TXS_USED;
00922                 txBufIdx++;
00923                 txBufIdx &= 1;
00924                 NutEventPost(&ni->ni_mutex);
00925                 break;
00926             }
00927         } else {
00928             if (inr(EMAC_TSR) & EMAC_UND) {
00929                 txBufIdx = 0;
00930                 outr(EMAC_TSR, EMAC_UND);
00931             }
00932             if (inr(EMAC_TSR) & EMAC_COMP) {
00933                 outr(EMAC_TSR, EMAC_COMP);
00934             }
00935 
00936             if ((rc = EmacPutPacket(txBufIdx, ni, nb)) == 0) {
00937                 txBufIdx++;
00938                 txBufIdx &= 1;
00939             }
00940         }
00941         NutEventPost(&ni->ni_mutex);
00942     }
00943 
00944     /*
00945      * Probably no Ethernet link. Significantly reduce the waiting
00946      * time, so following transmission will soon return an error.
00947      */
00948     if (rc) {
00949         mx_wait = 500;
00950     } else {
00951         /* Ethernet works. Set a long waiting time in case we
00952            temporarly lose the link next time. */
00953         mx_wait = 5000;
00954     }
00955     return rc;
00956 }
00957 
00967 int EmacInit(NUTDEVICE * dev)
00968 {
00969     EMACINFO *ni = (EMACINFO *) dev->dev_dcb;
00970 
00971     /* Reset the controller. */
00972     if (EmacReset(EMAC_LINK_LOOPS)) {
00973         if (EmacReset(EMAC_LINK_LOOPS)) {
00974             return -1;
00975         }
00976     }
00977 
00978     /* Clear EMACINFO structure. */
00979     memset(ni, 0, sizeof(EMACINFO));
00980 
00981     /* Register interrupt handler. */
00982     if (NutRegisterIrqHandler(&sig_EMAC, EmacInterrupt, dev)) {
00983         return -1;
00984     }
00985 
00986     /* Start the receiver thread. */
00987     if (NutThreadCreate("emacrx", EmacRxThread, dev, NUT_THREAD_NICRXSTACK) == NULL) {
00988         return -1;
00989     }
00990     return 0;
00991 }
00992 
00993 static EMACINFO dcb_eth0;
00994 
01000 static IFNET ifn_eth0 = {
01001     IFT_ETHER,                  
01002     0,                          
01003     {0, 0, 0, 0, 0, 0},         
01004     0,                          
01005     0,                          
01006     0,                          
01007     ETHERMTU,                   
01008     0,                          
01009     0,                          
01010     0,                          
01011     NutEtherInput,              
01012     EmacOutput,                 
01013     NutEtherOutput              
01014 };
01015 
01025 NUTDEVICE devAt91Emac = {
01026     0,                          
01027     {'e', 't', 'h', '0', 0, 0, 0, 0, 0},        
01028     IFTYP_NET,                  
01029     0,                          
01030     0,                          
01031     &ifn_eth0,                  
01032     &dcb_eth0,                  
01033     EmacInit,                   
01034     0,                          
01035     0,                          
01036     0,                          
01037 #ifdef __HARVARD_ARCH__
01038     0,                          
01039 #endif
01040     0,                          
01041     0,                          
01042     0                           
01043 };
01044 

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