1 | /*****************************************************************************
|
2 | * *
|
3 | * EMAC DRIVER *
|
4 | * *
|
5 | *****************************************************************************/
|
6 |
|
7 | #include "eth.h"
|
8 | #include "endian.h"
|
9 | #include "part.h"
|
10 | #include "main.h"
|
11 | #include "gpio.h"
|
12 | #include <stdio.h>
|
13 | #include <stdlib.h>
|
14 | #include <string.h>
|
15 |
|
16 | /************************************************
|
17 | * VARIABLES AND STRUCTS *
|
18 | ************************************************/
|
19 |
|
20 | /* setting up the buffer descriptor list */
|
21 | unsigned int RxBd[2048]; //1024 buffer descriptors of 2 words
|
22 |
|
23 | /* setting up the receive buffer */
|
24 | unsigned int RxB[1024][32]; //1024 buffer of 128byte
|
25 |
|
26 |
|
27 | /* setting up 128 transmit buffer descriptors, thats enough! */
|
28 | unsigned int TxBd[256]; //128 two word buffer descriptors
|
29 |
|
30 | /* setting up the transmit buffer */
|
31 | unsigned int TxB[128][512]; //128 buffers of 2048 byte
|
32 |
|
33 |
|
34 | /* HEADER DEFINITIONS */
|
35 |
|
36 | /* ethernet encapsulation */
|
37 | struct ethheader {
|
38 | unsigned char destMAC[6];
|
39 | unsigned char srcMAC[6];
|
40 | unsigned char type[2];
|
41 | } __attribute__ ((packed)) *eth;
|
42 |
|
43 | /* ip header */
|
44 | struct ipheader {
|
45 | unsigned char version_header; //4bit version, 4 bit header length in 32bit-words
|
46 | unsigned char TOS; //0x0 for default
|
47 | unsigned short length; //total length of ip datagram
|
48 | unsigned short id; //normally incrementet by every sent packet
|
49 | unsigned short flags_offset; //3bit flags, 13bit offset
|
50 | unsigned char TTL; //time to live, normally 32 or 64
|
51 | unsigned char prot; //17 for UDP
|
52 | unsigned short chksum; //header checksum
|
53 | unsigned int sourceIP;
|
54 | unsigned int destIP;
|
55 | }__attribute__ ((packed)) *ip;
|
56 |
|
57 | /* udp header */
|
58 | struct udpheader {
|
59 | unsigned short srcPort; //source portnumber
|
60 | unsigned short destPort; //destination port number
|
61 | unsigned short length; //total length of udp datagram
|
62 | unsigned short chksum; //checksum (optional) pseudo-header, header and data
|
63 | } __attribute__ ((packed)) *udp;
|
64 |
|
65 |
|
66 | /************************************************
|
67 | * INITIALIZATION *
|
68 | ************************************************/
|
69 |
|
70 | int eth_init ( )
|
71 | {
|
72 | int i;
|
73 |
|
74 | /* enable emac in power management controller PMC */
|
75 | writel( 1 << AT91C_ID_EMAC, AT91C_PMC_PCER);
|
76 |
|
77 | /* disable transmit and receive circuits */
|
78 | writel( 0, AT91C_EMACB_NCR ); //disabling by reset network control register
|
79 |
|
80 | /* disable all interrupts */
|
81 | writel( ~0, AT91C_EMACB_IDR ); //disabling by writing 0xffffffff to the interrupt disable register
|
82 |
|
83 | /* set the MAC address of this device */
|
84 | //necessary to receive packets
|
85 |
|
86 | /* clear statistics register, enable management port, make status registers writable */
|
87 | writel( AT91C_EMAC_CLRSTAT |
|
88 | AT91C_EMAC_MPE |
|
89 | AT91C_EMAC_WESTAT
|
90 | , AT91C_EMACB_NCR );
|
91 |
|
92 | /* configure network */
|
93 | writel( AT91C_EMAC_SPD | //set speed to 100Mbit/s
|
94 | AT91C_EMAC_FD | //set full duplex mode
|
95 | AT91C_EMAC_CLK_HCLK_64 //set clock divider according MCK
|
96 | , AT91C_EMACB_NCFGR );
|
97 |
|
98 | /* enable transreceiver input clock and set to MII mode */
|
99 | writel( AT91C_EMAC_CLKEN, AT91C_EMACB_USRIO );
|
100 |
|
101 |
|
102 | /************************************************
|
103 | * PHY SETUP *
|
104 | ************************************************/
|
105 |
|
106 | /* basic control register 0x0 */
|
107 | writel ( PHY_SOF |
|
108 | PHY_WRITE |
|
109 | PHY_ADDRESS |
|
110 | PHY_BCR |
|
111 | PHY_CODE |
|
112 | PHY_BCR_AUTONEG |
|
113 | PHY_BCR_AUTONEG_RESTART
|
114 | , AT91C_EMACB_MAN );
|
115 | while ( !(readl(AT91C_EMACB_NSR) & AT91C_EMAC_IDLE) ); //wait for transmission completed
|
116 |
|
117 | /* read and verify PHY register entry */
|
118 | /* read PHY identifier, shold be 0x0022 in register 0x2 */
|
119 | writel ( PHY_SOF |
|
120 | PHY_READ |
|
121 | PHY_ADDRESS |
|
122 | PHY_ID1 |
|
123 | PHY_CODE
|
124 | , AT91C_EMACB_MAN );
|
125 | while ( !(readl(AT91C_EMACB_NSR) & AT91C_EMAC_IDLE) ); //wait for transmission completed
|
126 | if ( (readl(AT91C_EMACB_MAN) & PHY_DATA_MASK) != 0x0022 ) //read and verify ID
|
127 | pio_set_value(AT91C_PIN_PA(9), 0); //if doesn't match switch power LED off
|
128 |
|
129 |
|
130 | /************************************************
|
131 | * BUFFER CONFIGURATION *
|
132 | ************************************************/
|
133 |
|
134 | /* RECEIVE BUFFER */
|
135 |
|
136 | /* received frames are written into 128byte long receive buffers. these buffers
|
137 | * are stored in memory. every start location of a buffer is stored in a list.
|
138 | * each entry of this list consists of 2 words and is called buffer desciptor.
|
139 | */
|
140 |
|
141 | /* initialize descriptor list */
|
142 | for (i = 0; i < 1024; i++) {
|
143 | RxBd[i*2] = ((unsigned int) RxB[i]) & ~3; //mask the two least significant bits
|
144 | }
|
145 | RxBd[2047] |= 2; //set wrap bit of the last descriptor
|
146 |
|
147 | /* write start address of descriptor list to receive buffer queue pointer register */
|
148 | writel( (unsigned int) RxBd & ~3, AT91C_EMACB_RBQP ); //mask the two least significant bits of the address
|
149 |
|
150 | /* enable receiver */
|
151 | writel( readl(AT91C_EMACB_NCR) | AT91C_EMAC_RE, AT91C_EMACB_NCR );
|
152 |
|
153 |
|
154 | /* TRANSMIT BUFFER */
|
155 |
|
156 | /* Frames to be transmitted are stored in one or more buffers. the buffer size is
|
157 | * between 0 and 2047 byte. the start location of each transmit buffer is stored
|
158 | * in a tramsmit buffer descriptor list. the transmit buffer queue pointer register
|
159 | * points to one of the descriptors.
|
160 | * each descriptor entry consists of two words. the first word contains the address
|
161 | * and the second control and status information.
|
162 | */
|
163 |
|
164 | /* initialize descriptor list */
|
165 | for (i = 0; i < 128; i++) {
|
166 | TxBd[i*2] = (unsigned int) TxB[i]; //write start address of each buffer to the descriptor
|
167 | TxBd[i*2+1] = TxBd_USED; //set used bit, there's no frame to be sent
|
168 | }
|
169 | TxBd[255] |= TxBd_WRAP; //set wrap bit of the last buffer descriptor
|
170 |
|
171 | /* write start address of descriptor list to transmit buffer queue pointer register */
|
172 | writel( (unsigned int) TxBd, AT91C_EMACB_TBQP );
|
173 |
|
174 | /* enable transmitter */
|
175 | writel( readl(AT91C_EMACB_NCR) | AT91C_EMAC_TE, AT91C_EMACB_NCR );
|
176 |
|
177 | packet_setup();
|
178 |
|
179 | return 0;
|
180 | }
|
181 |
|
182 | /************************************************
|
183 | * PACKET SETUP *
|
184 | ************************************************/
|
185 |
|
186 | void packet_setup () {
|
187 |
|
188 | /* ETHERNET HEADER */
|
189 | /* destination MAC Address */
|
190 | eth->destMAC[0] = 0xff; //MAC: little endian
|
191 | eth->destMAC[1] = 0xff;
|
192 | eth->destMAC[2] = 0xff;
|
193 | eth->destMAC[3] = 0xff;
|
194 | eth->destMAC[4] = 0xff;
|
195 | eth->destMAC[5] = 0xff;
|
196 | /* Source MAC Address */
|
197 | eth->srcMAC[5] = 0x00;
|
198 | eth->srcMAC[4] = 0x2e;
|
199 | eth->srcMAC[3] = 0x44;
|
200 | eth->srcMAC[2] = 0xa2;
|
201 | eth->srcMAC[1] = 0x43;
|
202 | eth->srcMAC[0] = 0x00;
|
203 | /* Type */
|
204 | eth->type[0] = 0x08; //big endian
|
205 | eth->type[1] = 0x00;
|
206 |
|
207 | /* IP HEADER */
|
208 | /* Version and Header length */
|
209 | ip->version_header = 4 << 4; //version on higher-half-byte
|
210 | ip->version_header += 5 << 0; //header length on lower-half-byte
|
211 | /* TOS */
|
212 | ip->TOS = 0x0; //normal service
|
213 | /* total length */
|
214 | ip->length = endians(68);
|
215 | /* identification */
|
216 | ip->id = endians(0);
|
217 | /* flags and offset */
|
218 | ip->flags_offset = endians(0);
|
219 | /* Time To Live */
|
220 | ip->TTL = 32;
|
221 | /* Protocol */
|
222 | ip->prot = 17; //17 means UDP
|
223 | /* source IP */
|
224 | ip->sourceIP = endianl(10 << 0 | 0 << 8 | 168 << 16 | 192 << 24);
|
225 | /* destination IP (broadcast) */
|
226 | ip->destIP = endianl(0xffffffff);
|
227 | /* checksum */
|
228 | ip->chksum = 0; //to calculate chksum, this field has to be zero
|
229 | ip->chksum = endians(ip_chksum(20, (char*)ip)); //calculate IP checksum
|
230 |
|
231 | /* UDP HEADER */
|
232 | /* source port */
|
233 | udp->srcPort = endians(1044);
|
234 | /* destination port */
|
235 | udp->destPort = endians(1044);
|
236 | /* length */
|
237 | udp->length = endians(48);
|
238 | /* checksum */
|
239 | udp->chksum = endians(0); //checksum is not used
|
240 |
|
241 | }
|
242 |
|
243 | /* IP CHECKSUM CALCULATION */
|
244 | short ip_chksum (short header_length, char header[])
|
245 | {
|
246 | short word16;
|
247 | long sum = 0;
|
248 | short i;
|
249 |
|
250 | /* make 16 bit words out of every two adjacent 8 bit words in the packet
|
251 | * and add them up */
|
252 | for (i = 0; i < header_length; i += 2) {
|
253 | word16 = ((header[i] << 8) & 0xFF00) + (header[i+1] & 0xFF);
|
254 | sum = sum + (long) word16;
|
255 | }
|
256 |
|
257 | /* take only 16 bits out of the 32 bit sum and add up the carries */
|
258 | while (sum >> 16)
|
259 | sum = (sum & 0xFFFF) + (sum >> 16);
|
260 |
|
261 | /* one's complement the result */
|
262 | sum = ~sum;
|
263 |
|
264 | return ((short) sum);
|
265 | }
|
266 |
|
267 |
|
268 | /************************************************
|
269 | * TRANSMIT *
|
270 | ************************************************/
|
271 |
|
272 | int eth_send () //(*pBuffer, int length)
|
273 | {
|
274 |
|
275 | if (readl(AT91C_EMACB_FTO) >= 3)
|
276 | return 1;
|
277 | // writel(0, AT91C_EMACB_FTO);
|
278 |
|
279 | if ( TxBd[1] & (TxBd_ERR | TxBd_UNDERRUN | TxBd_BUFFEXH ))
|
280 | return 1;
|
281 | if ( !(TxBd[1] & TxBd_USED) )
|
282 | return 1;
|
283 |
|
284 | writel (AT91C_EMAC_COMP, AT91C_EMACB_TSR); //clear COMPLETE bit of transmit status register
|
285 |
|
286 | char *bptr = (char*) &TxB[0][0];
|
287 | /* copy frame in buffer */
|
288 | memcpy( bptr, eth, 14 );
|
289 | bptr += 14;
|
290 | memcpy( bptr, ip, 20 );
|
291 | bptr += 20;
|
292 | memcpy( bptr, udp, 8 );
|
293 | bptr += 8;
|
294 | memcpy( bptr, "1234567890helloworld1234567890helloworld", 40);
|
295 |
|
296 | /* write status and control information to TxBd */
|
297 | TxBd[1] = TxBd_NOCRC | TxBd_LASTBUF | 82;
|
298 | writel( (unsigned int) &TxBd[0], AT91C_EMACB_TBQP );
|
299 |
|
300 | writel( readl(AT91C_EMACB_NCR) | AT91C_EMAC_TSTART, AT91C_EMACB_NCR );
|
301 |
|
302 | while ( !(readl(AT91C_EMACB_TSR) & AT91C_EMAC_COMP) );
|
303 |
|
304 | /* check for error */
|
305 | return 0;
|
306 | }
|