1 /*******************************************************************************
2 *
3 * Filename: emac.c
4 *
5 * Instantiation of routines for MAC/ethernet functions supporting tftp.
6 *
7 * Revision information:
8 *
9 * 28AUG2004 kb_admin initial creation
10 * 08JAN2005 kb_admin added tftp download
11 * also adapted from external sources
12 *
13 * BEGIN_KBDD_BLOCK
14 * No warranty, expressed or implied, is included with this software. It is
15 * provided "AS IS" and no warranty of any kind including statutory or aspects
16 * relating to merchantability or fitness for any purpose is provided. All
17 * intellectual property rights of others is maintained with the respective
18 * owners. This software is not copyrighted and is intended for reference
19 * only.
20 * END_BLOCK
21 *
22 * $FreeBSD$
23 ******************************************************************************/
24
25 #include "at91rm9200.h"
26 #include "at91rm9200_lowlevel.h"
27 #include "emac.h"
28 #include "lib.h"
29
30 /* ****************************** GLOBALS *************************************/
31
32 /* ********************** PRIVATE FUNCTIONS/DATA ******************************/
33
34 static receive_descriptor_t *p_rxBD;
35 static unsigned short localPort;
36 static unsigned short serverPort;
37 static unsigned serverMACSet;
38 static unsigned localIPSet, serverIPSet;
39 static unsigned lastSize;
40 static unsigned char serverMACAddr[6];
41 static unsigned char localIPAddr[4], serverIPAddr[4];
42 static int ackBlock;
43 static char *dlAddress;
44
45 static unsigned transmitBuffer[1024 / sizeof(unsigned)];
46 static unsigned tftpSendPacket[256 / sizeof(unsigned)];
47
48 /*
49 * .KB_C_FN_DEFINITION_START
50 * unsigned short IP_checksum(unsigned short *p, int len)
51 * This private function calculates the IP checksum for various headers.
52 * .KB_C_FN_DEFINITION_END
53 */
54 static unsigned short
IP_checksum(unsigned short * p,int len)55 IP_checksum(unsigned short *p, int len)
56 {
57 unsigned i, t;
58
59 len &= ~1;
60
61 for (i=0,t=0; i<len; i+=2, ++p)
62 t += SWAP16(*p);
63
64 t = (t & 0xffff) + (t >> 16);
65 return (~t);
66 }
67
68
69 /*
70 * .KB_C_FN_DEFINITION_START
71 * void GetServerAddress(void)
72 * This private function sends an ARP request to determine the server MAC.
73 * .KB_C_FN_DEFINITION_END
74 */
75 static void
GetServerAddress(void)76 GetServerAddress(void)
77 {
78 arp_header_t *p_ARP;
79
80 p_ARP = (arp_header_t*)transmitBuffer;
81
82 p_memset((char*)p_ARP->dest_mac, 0xFF, 6);
83
84 memcpy(p_ARP->src_mac, localMACAddr, 6);
85
86 p_ARP->frame_type = SWAP16(PROTOCOL_ARP);
87 p_ARP->hard_type = SWAP16(1);
88 p_ARP->prot_type = SWAP16(PROTOCOL_IP);
89 p_ARP->hard_size = 6;
90 p_ARP->prot_size = 4;
91 p_ARP->operation = SWAP16(ARP_REQUEST);
92
93 memcpy(p_ARP->sender_mac, localMACAddr, 6);
94 memcpy(p_ARP->sender_ip, localIPAddr, 4);
95 p_memset((char*)p_ARP->target_mac, 0, 6);
96 memcpy(p_ARP->target_ip, serverIPAddr, 4);
97
98 // wait until transmit is available
99 while (!(*AT91C_EMAC_TSR & AT91C_EMAC_BNQ))
100 continue;
101
102 *AT91C_EMAC_TSR |= AT91C_EMAC_COMP;
103 *AT91C_EMAC_TAR = (unsigned)transmitBuffer;
104 *AT91C_EMAC_TCR = 0x40;
105 }
106
107
108 /*
109 * .KB_C_FN_DEFINITION_START
110 * void Send_TFTP_Packet(char *tftpData, unsigned tftpLength)
111 * This private function initializes and send a TFTP packet.
112 * .KB_C_FN_DEFINITION_END
113 */
114 static void
Send_TFTP_Packet(char * tftpData,unsigned tftpLength)115 Send_TFTP_Packet(char *tftpData, unsigned tftpLength)
116 {
117 transmit_header_t *macHdr = (transmit_header_t*)tftpSendPacket;
118 ip_header_t *ipHdr;
119 udp_header_t *udpHdr;
120 unsigned t_checksum;
121
122 memcpy(macHdr->dest_mac, serverMACAddr, 6);
123 memcpy(macHdr->src_mac, localMACAddr, 6);
124 macHdr->proto_mac = SWAP16(PROTOCOL_IP);
125
126 ipHdr = (ip_header_t*)&macHdr->packet_length;
127
128 ipHdr->ip_v_hl = 0x45;
129 ipHdr->ip_tos = 0;
130 ipHdr->ip_len = SWAP16(28 + tftpLength);
131 ipHdr->ip_id = 0;
132 ipHdr->ip_off = SWAP16(0x4000);
133 ipHdr->ip_ttl = 64;
134 ipHdr->ip_p = PROTOCOL_UDP;
135 ipHdr->ip_sum = 0;
136
137 memcpy(ipHdr->ip_src, localIPAddr, 4);
138 memcpy(ipHdr->ip_dst, serverIPAddr, 4);
139
140 ipHdr->ip_sum = SWAP16(IP_checksum((unsigned short*)ipHdr, 20));
141
142 udpHdr = (udp_header_t*)(ipHdr + 1);
143
144 udpHdr->src_port = localPort;
145 udpHdr->dst_port = serverPort;
146 udpHdr->udp_len = SWAP16(8 + tftpLength);
147 udpHdr->udp_cksum = 0;
148
149 memcpy((char *)udpHdr+8, tftpData, tftpLength);
150
151 t_checksum = IP_checksum((unsigned short*)ipHdr + 6, (16 + tftpLength));
152
153 t_checksum = (~t_checksum) & 0xFFFF;
154 t_checksum += 25 + tftpLength;
155
156 t_checksum = (t_checksum & 0xffff) + (t_checksum >> 16);
157 t_checksum = (~t_checksum) & 0xFFFF;
158
159 udpHdr->udp_cksum = SWAP16(t_checksum);
160
161 while (!(*AT91C_EMAC_TSR & AT91C_EMAC_BNQ))
162 continue;
163
164 *AT91C_EMAC_TSR |= AT91C_EMAC_COMP;
165 *AT91C_EMAC_TAR = (unsigned)tftpSendPacket;
166 *AT91C_EMAC_TCR = 42 + tftpLength;
167 }
168
169
170 /*
171 * .KB_C_FN_DEFINITION_START
172 * void TFTP_RequestFile(char *filename)
173 * This private function sends a RRQ packet to the server.
174 * .KB_C_FN_DEFINITION_END
175 */
176 static void
TFTP_RequestFile(char * filename)177 TFTP_RequestFile(char *filename)
178 {
179 tftp_header_t tftpHeader;
180 char *cPtr, *ePtr, *mPtr;
181 unsigned length;
182
183 tftpHeader.opcode = TFTP_RRQ_OPCODE;
184
185 cPtr = (char*)&(tftpHeader.block_num);
186
187 ePtr = strcpy(cPtr, filename);
188 mPtr = strcpy(ePtr, "octet");
189
190 length = mPtr - cPtr;
191 length += 2;
192
193 Send_TFTP_Packet((char*)&tftpHeader, length);
194 }
195
196
197 /*
198 * .KB_C_FN_DEFINITION_START
199 * void TFTP_ACK_Data(char *data, unsigned short block_num, unsigned short len)
200 * This private function sends an ACK packet to the server.
201 * .KB_C_FN_DEFINITION_END
202 */
203 static void
TFTP_ACK_Data(unsigned char * data,unsigned short block_num,unsigned short len)204 TFTP_ACK_Data(unsigned char *data, unsigned short block_num, unsigned short len)
205 {
206 tftp_header_t tftpHeader;
207
208 if (block_num == (ackBlock + 1)) {
209 ++ackBlock;
210 memcpy(dlAddress, data, len);
211 dlAddress += len;
212 lastSize += len;
213 if (ackBlock % 128 == 0)
214 printf("tftp: %u kB\r", lastSize / 1024);
215 }
216 tftpHeader.opcode = TFTP_ACK_OPCODE;
217 tftpHeader.block_num = SWAP16(ackBlock);
218 Send_TFTP_Packet((char*)&tftpHeader, 4);
219 if (len < 512) {
220 ackBlock = -2;
221 printf("tftp: %u byte\n", lastSize);
222 }
223 }
224
225
226 /*
227 * .KB_C_FN_DEFINITION_START
228 * void CheckForNewPacket(ip_header_t *pHeader)
229 * This private function polls for received ethernet packets and handles
230 * any here.
231 * .KB_C_FN_DEFINITION_END
232 */
233 static int
CheckForNewPacket(ip_header_t * pHeader)234 CheckForNewPacket(ip_header_t *pHeader)
235 {
236 unsigned short *pFrameType;
237 unsigned i;
238 char *pData;
239 ip_header_t *pIpHeader;
240 arp_header_t *p_ARP;
241 int process = 0;
242
243 process = 0;
244 for (i = 0; i < MAX_RX_PACKETS; ++i) {
245 if(p_rxBD[i].address & 0x1) {
246 process = 1;
247 (*AT91C_EMAC_RSR) |= (*AT91C_EMAC_RSR);
248 break;
249 }
250 }
251
252 if (!process)
253 return (0);
254 process = i;
255
256 pFrameType = (unsigned short *)((p_rxBD[i].address & 0xFFFFFFFC) + 12);
257 pData = (char *)(p_rxBD[i].address & 0xFFFFFFFC);
258
259 switch (*pFrameType) {
260
261 case SWAP16(PROTOCOL_ARP):
262 p_ARP = (arp_header_t*)pData;
263 if (p_ARP->operation == SWAP16(ARP_REPLY)) {
264 // check if new server info is available
265 if ((!serverMACSet) &&
266 (!(p_memcmp((char*)p_ARP->sender_ip,
267 (char*)serverIPAddr, 4)))) {
268
269 serverMACSet = 1;
270 memcpy(serverMACAddr, p_ARP->sender_mac, 6);
271 }
272 } else if (p_ARP->operation == SWAP16(ARP_REQUEST)) {
273 // ARP REPLY operation
274 p_ARP->operation = SWAP16(ARP_REPLY);
275
276 // Fill the dest address and src address
277 for (i = 0; i <6; i++) {
278 // swap ethernet dest address and ethernet src address
279 pData[i] = pData[i+6];
280 pData[i+6] = localMACAddr[i];
281 // swap sender ethernet address and target ethernet address
282 pData[i+22] = localMACAddr[i];
283 pData[i+32] = pData[i+6];
284 }
285
286 // swap sender IP address and target IP address
287 for (i = 0; i<4; i++) {
288 pData[i+38] = pData[i+28];
289 pData[i+28] = localIPAddr[i];
290 }
291
292 if (!(*AT91C_EMAC_TSR & AT91C_EMAC_BNQ)) break;
293
294 *AT91C_EMAC_TSR |= AT91C_EMAC_COMP;
295 *AT91C_EMAC_TAR = (unsigned)pData;
296 *AT91C_EMAC_TCR = 0x40;
297 }
298 break;
299 case SWAP16(PROTOCOL_IP):
300 pIpHeader = (ip_header_t*)(pData + 14);
301 memcpy(pHeader, pIpHeader, sizeof(ip_header_t));
302
303 if (pIpHeader->ip_p == PROTOCOL_UDP) {
304 udp_header_t *udpHdr;
305 tftp_header_t *tftpHdr;
306
307 udpHdr = (udp_header_t*)((char*)pIpHeader+20);
308 tftpHdr = (tftp_header_t*)((char*)udpHdr + 8);
309
310 if (udpHdr->dst_port != localPort)
311 break;
312
313 if (tftpHdr->opcode != TFTP_DATA_OPCODE)
314 break;
315
316 if (ackBlock == -1) {
317 if (tftpHdr->block_num != SWAP16(1))
318 break;
319 serverPort = udpHdr->src_port;
320 ackBlock = 0;
321 }
322
323 if (serverPort != udpHdr->src_port)
324 break;
325
326 TFTP_ACK_Data(tftpHdr->data,
327 SWAP16(tftpHdr->block_num),
328 SWAP16(udpHdr->udp_len) - 12);
329 }
330 }
331 p_rxBD[process].address &= ~0x01;
332 return (1);
333 }
334
335
336 /*
337 * .KB_C_FN_DEFINITION_START
338 * unsigned short AT91F_MII_ReadPhy (AT91PS_EMAC pEmac, unsigned char addr)
339 * This private function reads the PHY device.
340 * .KB_C_FN_DEFINITION_END
341 */
342 #ifndef BOOT_BWCT
343 static unsigned short
AT91F_MII_ReadPhy(AT91PS_EMAC pEmac,unsigned char addr)344 AT91F_MII_ReadPhy (AT91PS_EMAC pEmac, unsigned char addr)
345 {
346 unsigned value = 0x60020000 | (addr << 18);
347
348 pEmac->EMAC_CTL |= AT91C_EMAC_MPE;
349 pEmac->EMAC_MAN = value;
350 while(!((pEmac->EMAC_SR) & AT91C_EMAC_IDLE));
351 pEmac->EMAC_CTL &= ~AT91C_EMAC_MPE;
352 return (pEmac->EMAC_MAN & 0x0000ffff);
353 }
354 #endif
355
356 /*
357 * .KB_C_FN_DEFINITION_START
358 * unsigned short AT91F_MII_WritePhy (AT91PS_EMAC pEmac, unsigned char addr, unsigned short s)
359 * This private function writes the PHY device.
360 * .KB_C_FN_DEFINITION_END
361 */
362 #ifdef BOOT_TSC
363 static unsigned short
AT91F_MII_WritePhy(AT91PS_EMAC pEmac,unsigned char addr,unsigned short s)364 AT91F_MII_WritePhy (AT91PS_EMAC pEmac, unsigned char addr, unsigned short s)
365 {
366 unsigned value = 0x50020000 | (addr << 18) | s;
367
368 pEmac->EMAC_CTL |= AT91C_EMAC_MPE;
369 pEmac->EMAC_MAN = value;
370 while(!((pEmac->EMAC_SR) & AT91C_EMAC_IDLE));
371 pEmac->EMAC_CTL &= ~AT91C_EMAC_MPE;
372 return (pEmac->EMAC_MAN & 0x0000ffff);
373 }
374 #endif
375
376 /*
377 * .KB_C_FN_DEFINITION_START
378 * void MII_GetLinkSpeed(AT91PS_EMAC pEmac)
379 * This private function determines the link speed set by the PHY.
380 * .KB_C_FN_DEFINITION_END
381 */
382 static void
MII_GetLinkSpeed(AT91PS_EMAC pEmac)383 MII_GetLinkSpeed(AT91PS_EMAC pEmac)
384 {
385 #if defined(BOOT_TSC) || defined(BOOT_KB920X) || defined(BOOT_CENTIPAD)
386 unsigned short stat2;
387 #endif
388 unsigned update;
389 #ifdef BOOT_TSC
390 unsigned sec;
391 int i;
392 #endif
393 #ifdef BOOT_BWCT
394 /* hardcoded link speed since we connect a switch via MII */
395 update = pEmac->EMAC_CFG & ~(AT91C_EMAC_SPD | AT91C_EMAC_FD);
396 update |= AT91C_EMAC_SPD;
397 update |= AT91C_EMAC_FD;
398 #endif
399 #if defined(BOOT_KB920X) || defined(BOOT_CENTIPAD)
400 stat2 = AT91F_MII_ReadPhy(pEmac, MII_STS2_REG);
401 if (!(stat2 & MII_STS2_LINK))
402 return ;
403 update = pEmac->EMAC_CFG & ~(AT91C_EMAC_SPD | AT91C_EMAC_FD);
404 if (stat2 & MII_STS2_100TX)
405 update |= AT91C_EMAC_SPD;
406 if (stat2 & MII_STS2_FDX)
407 update |= AT91C_EMAC_FD;
408 #endif
409 #ifdef BOOT_TSC
410 while (1) {
411 for (i = 0; i < 10; i++) {
412 stat2 = AT91F_MII_ReadPhy(pEmac, MII_STS_REG);
413 if (stat2 & MII_STS_LINK_STAT)
414 break;
415 printf(".");
416 sec = GetSeconds();
417 while (GetSeconds() == sec)
418 continue;
419 }
420 if (stat2 & MII_STS_LINK_STAT)
421 break;
422 printf("Resetting MII...");
423 AT91F_MII_WritePhy(pEmac, 0x0, 0x8000);
424 while (AT91F_MII_ReadPhy(pEmac, 0x0) & 0x8000) continue;
425 }
426 printf("emac: link");
427 stat2 = AT91F_MII_ReadPhy(pEmac, MII_SPEC_STS_REG);
428 update = pEmac->EMAC_CFG & ~(AT91C_EMAC_SPD | AT91C_EMAC_FD);
429 if (stat2 & (MII_SSTS_100FDX | MII_SSTS_100HDX)) {
430 printf(" 100TX");
431 update |= AT91C_EMAC_SPD;
432 }
433 if (stat2 & (MII_SSTS_100FDX | MII_SSTS_10FDX)) {
434 printf(" FDX");
435 update |= AT91C_EMAC_FD;
436 }
437 printf("\n");
438 #endif
439 pEmac->EMAC_CFG = update;
440 }
441
442
443 /*
444 * .KB_C_FN_DEFINITION_START
445 * void AT91F_EmacEntry(void)
446 * This private function initializes the EMAC on the chip.
447 * .KB_C_FN_DEFINITION_END
448 */
449 static void
AT91F_EmacEntry(void)450 AT91F_EmacEntry(void)
451 {
452 unsigned i;
453 char *pRxPacket = (char*)RX_DATA_START;
454 AT91PS_EMAC pEmac = AT91C_BASE_EMAC;
455
456 p_rxBD = (receive_descriptor_t*)RX_BUFFER_START;
457 localPort = SWAP16(0x8002);
458
459 for (i = 0; i < MAX_RX_PACKETS; ++i) {
460
461 p_rxBD[i].address = (unsigned)pRxPacket;
462 p_rxBD[i].size = 0;
463 pRxPacket += RX_PACKET_SIZE;
464 }
465
466 // Set the WRAP bit at the end of the list descriptor
467 p_rxBD[MAX_RX_PACKETS-1].address |= 0x02;
468
469 if (!(pEmac->EMAC_SR & AT91C_EMAC_LINK))
470 MII_GetLinkSpeed(pEmac);
471
472 pEmac->EMAC_RBQP = (unsigned) p_rxBD;
473 pEmac->EMAC_RSR |= (AT91C_EMAC_OVR | AT91C_EMAC_REC | AT91C_EMAC_BNA);
474 pEmac->EMAC_CTL = AT91C_EMAC_TE | AT91C_EMAC_RE;
475
476 pEmac->EMAC_TAR = (unsigned)transmitBuffer;
477 }
478
479
480 /* ************************** GLOBAL FUNCTIONS ********************************/
481
482 /*
483 * .KB_C_FN_DEFINITION_START
484 * void SetServerIPAddress(unsigned address)
485 * This global function sets the IP of the TFTP download server.
486 * .KB_C_FN_DEFINITION_END
487 */
488 void
SetServerIPAddress(unsigned address)489 SetServerIPAddress(unsigned address)
490 {
491 // force update in case the IP has changed
492 serverMACSet = 0;
493
494 serverIPAddr[0] = (address >> 24) & 0xFF;
495 serverIPAddr[1] = (address >> 16) & 0xFF;
496 serverIPAddr[2] = (address >> 8) & 0xFF;
497 serverIPAddr[3] = (address >> 0) & 0xFF;
498
499 serverIPSet = 1;
500 }
501
502
503 /*
504 * .KB_C_FN_DEFINITION_START
505 * void SetLocalIPAddress(unsigned address)
506 * This global function sets the IP of this module.
507 * .KB_C_FN_DEFINITION_END
508 */
509 void
SetLocalIPAddress(unsigned address)510 SetLocalIPAddress(unsigned address)
511 {
512 // force update in case the IP has changed
513 serverMACSet = 0;
514
515 localIPAddr[0] = (address >> 24) & 0xFF;
516 localIPAddr[1] = (address >> 16) & 0xFF;
517 localIPAddr[2] = (address >> 8) & 0xFF;
518 localIPAddr[3] = (address >> 0) & 0xFF;
519
520 localIPSet = 1;
521 }
522
523
524 /*
525 * .KB_C_FN_DEFINITION_START
526 * void TFTP_Download(unsigned address, char *filename)
527 * This global function initiates and processes a tftp download request.
528 * The server IP, local IP, local MAC must be set before this function is
529 * executed.
530 * .KB_C_FN_DEFINITION_END
531 */
532 void
TFTP_Download(unsigned address,char * filename)533 TFTP_Download(unsigned address, char *filename)
534 {
535 ip_header_t IpHeader;
536 unsigned thisSeconds;
537 int timeout;
538
539 if ((!localMACSet) || (!localIPSet) || (!serverIPSet))
540 return ;
541
542 AT91F_EmacEntry();
543 GetServerAddress();
544 dlAddress = (char*)address;
545 lastSize = 0;
546 timeout = 10;
547 thisSeconds = (GetSeconds() + 2) % 32;
548 serverPort = SWAP16(69);
549 ++localPort;
550 ackBlock = -1;
551
552 while (timeout) {
553 if (CheckForNewPacket(&IpHeader)) {
554 if (ackBlock == -2)
555 break;
556 timeout = 10;
557 thisSeconds = (GetSeconds() + 2) % 32;
558 } else if (GetSeconds() == thisSeconds) {
559 --timeout;
560 thisSeconds = (GetSeconds() + 2) % 32;
561 if (!serverMACSet)
562 GetServerAddress();
563 else if (ackBlock == -1)
564 TFTP_RequestFile(filename);
565 else {
566 // Be sure to send a NAK, which is done by
567 // ACKing the last block we got.
568 TFTP_ACK_Data(0, ackBlock, 512);
569 printf("\nNAK %u\n", ackBlock);
570 }
571 }
572 }
573 if (timeout == 0)
574 printf("TFTP TIMEOUT!\n");
575 }
576