1 /*******************************************************************************
5 * Instantiation of routines for MAC/ethernet functions supporting tftp.
7 * Revision information:
9 * 28AUG2004 kb_admin initial creation
10 * 08JAN2005 kb_admin added tftp download
11 * also adapted from external sources
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
23 ******************************************************************************/
25 #include "at91rm9200.h"
26 #include "at91rm9200_lowlevel.h"
30 /* ****************************** GLOBALS *************************************/
32 /* ********************** PRIVATE FUNCTIONS/DATA ******************************/
34 static char serverMACAddr[6];
35 static unsigned char localIPAddr[4], serverIPAddr[4];
37 static char *dlAddress;
39 static unsigned transmitBuffer[1024 / sizeof(unsigned)];
40 static unsigned tftpSendPacket[256 / sizeof(unsigned)];
43 * .KB_C_FN_DEFINITION_START
44 * unsigned short IP_checksum(unsigned short *p, int len)
45 * This private function calculates the IP checksum for various headers.
46 * .KB_C_FN_DEFINITION_END
49 IP_checksum(unsigned short *p, int len)
55 for (i=0,t=0; i<len; i+=2, ++p)
58 t = (t & 0xffff) + (t >> 16);
64 * .KB_C_FN_DEFINITION_START
65 * void GetServerAddress(void)
66 * This private function sends an ARP request to determine the server MAC.
67 * .KB_C_FN_DEFINITION_END
70 GetServerAddress(void)
74 p_ARP = (arp_header_t*)transmitBuffer;
76 p_memset((char*)p_ARP->dest_mac, 0xFF, 6);
78 p_memcpy((char*)p_ARP->src_mac, (char*)localMACAddr, 6);
80 p_ARP->frame_type = SWAP16(PROTOCOL_ARP);
81 p_ARP->hard_type = SWAP16(1);
82 p_ARP->prot_type = SWAP16(PROTOCOL_IP);
85 p_ARP->operation = SWAP16(ARP_REQUEST);
87 p_memcpy((char*)p_ARP->sender_mac, (char*)localMACAddr, 6);
89 p_memcpy((char*)p_ARP->sender_ip, (char*)localIPAddr, 4);
91 p_memset((char*)p_ARP->target_mac, 0, 6);
93 p_memcpy((char*)p_ARP->target_ip, (char*)serverIPAddr, 4);
95 // wait until transmit is available
96 while (!(*AT91C_EMAC_TSR & AT91C_EMAC_BNQ)) ;
98 *AT91C_EMAC_TSR |= AT91C_EMAC_COMP;
99 *AT91C_EMAC_TAR = (unsigned)transmitBuffer;
100 *AT91C_EMAC_TCR = 0x40;
105 * .KB_C_FN_DEFINITION_START
106 * void Send_TFTP_Packet(char *tftpData, unsigned tftpLength)
107 * This private function initializes and send a TFTP packet.
108 * .KB_C_FN_DEFINITION_END
111 Send_TFTP_Packet(char *tftpData, unsigned tftpLength)
113 transmit_header_t *macHdr = (transmit_header_t*)tftpSendPacket;
115 udp_header_t *udpHdr;
118 p_memcpy((char*)macHdr->dest_mac, (char*)serverMACAddr, 6);
120 p_memcpy((char*)macHdr->src_mac, (char*)localMACAddr, 6);
122 macHdr->proto_mac = SWAP16(PROTOCOL_IP);
124 ipHdr = (ip_header_t*)&macHdr->packet_length;
126 ipHdr->ip_v_hl = 0x45;
128 ipHdr->ip_len = SWAP16(28 + tftpLength);
130 ipHdr->ip_off = SWAP16(0x4000);
132 ipHdr->ip_p = PROTOCOL_UDP;
135 p_memcpy((char*)ipHdr->ip_src, (char*)localIPAddr, 4);
137 p_memcpy((char*)ipHdr->ip_dst, (char*)serverIPAddr, 4);
139 ipHdr->ip_sum = SWAP16(IP_checksum((unsigned short*)ipHdr, 20));
141 udpHdr = (udp_header_t*)(ipHdr + 1);
143 udpHdr->src_port = localPort;
144 udpHdr->dst_port = serverPort;
145 udpHdr->udp_len = SWAP16(8 + tftpLength);
146 udpHdr->udp_cksum = 0;
148 p_memcpy((char*)udpHdr+8, tftpData, tftpLength);
150 t_checksum = IP_checksum((unsigned short*)ipHdr + 6, (16 + tftpLength));
152 t_checksum = (~t_checksum) & 0xFFFF;
153 t_checksum += 25 + tftpLength;
155 t_checksum = (t_checksum & 0xffff) + (t_checksum >> 16);
156 t_checksum = (~t_checksum) & 0xFFFF;
158 udpHdr->udp_cksum = SWAP16(t_checksum);
160 while (!(*AT91C_EMAC_TSR & AT91C_EMAC_BNQ)) ;
162 *AT91C_EMAC_TSR |= AT91C_EMAC_COMP;
163 *AT91C_EMAC_TAR = (unsigned)tftpSendPacket;
164 *AT91C_EMAC_TCR = 42 + tftpLength;
169 * .KB_C_FN_DEFINITION_START
170 * void TFTP_RequestFile(char *filename)
171 * This private function sends a RRQ packet to the server.
172 * .KB_C_FN_DEFINITION_END
175 TFTP_RequestFile(char *filename)
177 tftp_header_t tftpHeader;
178 char *cPtr, *ePtr, *mPtr;
181 tftpHeader.opcode = TFTP_RRQ_OPCODE;
183 cPtr = (char*)&(tftpHeader.block_num);
185 ePtr = p_strcpy(cPtr, filename);
186 mPtr = p_strcpy(ePtr, "octet");
188 length = mPtr - cPtr;
191 Send_TFTP_Packet((char*)&tftpHeader, length);
196 * .KB_C_FN_DEFINITION_START
197 * void TFTP_ACK_Data(char *data, unsigned short block_num, unsigned short len)
198 * This private function sends an ACK packet to the server.
199 * .KB_C_FN_DEFINITION_END
202 TFTP_ACK_Data(char *data, unsigned short block_num, unsigned short len)
204 tftp_header_t tftpHeader;
206 if (block_num == (ackBlock + 1)) {
208 p_memcpy(dlAddress, data, len);
211 if (ackBlock % 128 == 0)
212 printf("tftp: %u kB\r", lastSize / 1024);
214 tftpHeader.opcode = TFTP_ACK_OPCODE;
215 tftpHeader.block_num = SWAP16(ackBlock);
216 Send_TFTP_Packet((char*)&tftpHeader, 4);
219 printf("tftp: %u byte\r\n", lastSize);
225 * .KB_C_FN_DEFINITION_START
226 * void CheckForNewPacket(ip_header_t *pHeader)
227 * This private function polls for received ethernet packets and handles
229 * .KB_C_FN_DEFINITION_END
232 CheckForNewPacket(ip_header_t *pHeader)
234 unsigned short *pFrameType;
237 ip_header_t *pIpHeader;
242 for (i = 0; i < MAX_RX_PACKETS; ++i) {
243 if(p_rxBD[i].address & 0x1) {
245 (*AT91C_EMAC_RSR) |= (*AT91C_EMAC_RSR);
255 pFrameType = (unsigned short *)((p_rxBD[i].address & 0xFFFFFFFC) + 12);
256 pData = (char *)(p_rxBD[i].address & 0xFFFFFFFC);
258 switch (*pFrameType) {
260 case SWAP16(PROTOCOL_ARP):
261 p_ARP = (arp_header_t*)pData;
262 if (p_ARP->operation == SWAP16(ARP_REPLY)) {
263 // check if new server info is available
264 if ((!serverMACSet) &&
265 (!(p_memcmp((char*)p_ARP->sender_ip,
266 (char*)serverIPAddr, 4)))) {
270 p_memcpy((char*)serverMACAddr,
271 (char*)p_ARP->sender_mac, 6);
273 } else if (p_ARP->operation == SWAP16(ARP_REQUEST)) {
274 // ARP REPLY operation
275 p_ARP->operation = SWAP16(ARP_REPLY);
277 // Fill the dest address and src address
278 for (i = 0; i <6; i++) {
279 // swap ethernet dest address and ethernet src address
280 pData[i] = pData[i+6];
281 pData[i+6] = localMACAddr[i];
282 // swap sender ethernet address and target ethernet address
283 pData[i+22] = localMACAddr[i];
284 pData[i+32] = pData[i+6];
287 // swap sender IP address and target IP address
288 for (i = 0; i<4; i++) {
289 pData[i+38] = pData[i+28];
290 pData[i+28] = localIPAddr[i];
293 if (!(*AT91C_EMAC_TSR & AT91C_EMAC_BNQ)) break;
295 *AT91C_EMAC_TSR |= AT91C_EMAC_COMP;
296 *AT91C_EMAC_TAR = (unsigned)pData;
297 *AT91C_EMAC_TCR = 0x40;
300 case SWAP16(PROTOCOL_IP):
301 pIpHeader = (ip_header_t*)(pData + 14);
302 p_memcpy((char*)pHeader, (char*)pIpHeader,sizeof(ip_header_t));
304 if (pIpHeader->ip_p == PROTOCOL_UDP) {
305 udp_header_t *udpHdr;
306 tftp_header_t *tftpHdr;
308 udpHdr = (udp_header_t*)((char*)pIpHeader+20);
309 tftpHdr = (tftp_header_t*)((char*)udpHdr + 8);
311 if (udpHdr->dst_port != localPort)
314 if (tftpHdr->opcode != TFTP_DATA_OPCODE)
317 if (ackBlock == -1) {
318 if (tftpHdr->block_num != SWAP16(1))
320 serverPort = udpHdr->src_port;
324 if (serverPort != udpHdr->src_port)
327 TFTP_ACK_Data(tftpHdr->data,
328 SWAP16(tftpHdr->block_num),
329 SWAP16(udpHdr->udp_len) - 12);
332 p_rxBD[process].address &= ~0x01;
338 * .KB_C_FN_DEFINITION_START
339 * unsigned short AT91F_MII_ReadPhy (AT91PS_EMAC pEmac, unsigned char addr)
340 * This private function reads the PHY device.
341 * .KB_C_FN_DEFINITION_END
343 static unsigned short
344 AT91F_MII_ReadPhy (AT91PS_EMAC pEmac, unsigned char addr)
346 unsigned value = 0x60020000 | (addr << 18);
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);
356 * .KB_C_FN_DEFINITION_START
357 * unsigned short AT91F_MII_ReadPhy (AT91PS_EMAC pEmac, unsigned char addr)
358 * This private function reads the PHY device.
359 * .KB_C_FN_DEFINITION_END
362 static unsigned short
363 AT91F_MII_WritePhy (AT91PS_EMAC pEmac, unsigned char addr, unsigned short s)
365 unsigned value = 0x50020000 | (addr << 18) | s;
367 pEmac->EMAC_CTL |= AT91C_EMAC_MPE;
368 pEmac->EMAC_MAN = value;
369 while(!((pEmac->EMAC_SR) & AT91C_EMAC_IDLE));
370 pEmac->EMAC_CTL &= ~AT91C_EMAC_MPE;
371 return (pEmac->EMAC_MAN & 0x0000ffff);
376 * .KB_C_FN_DEFINITION_START
377 * void MII_GetLinkSpeed(AT91PS_EMAC pEmac)
378 * This private function determines the link speed set by the PHY.
379 * .KB_C_FN_DEFINITION_END
382 MII_GetLinkSpeed(AT91PS_EMAC pEmac)
384 unsigned short stat2;
391 stat2 = AT91F_MII_ReadPhy(pEmac, MII_STS2_REG);
392 if (!(stat2 & MII_STS2_LINK))
394 update = pEmac->EMAC_CFG & ~(AT91C_EMAC_SPD | AT91C_EMAC_FD);
395 if (stat2 & MII_STS2_100TX)
396 update |= AT91C_EMAC_SPD;
397 if (stat2 & MII_STS2_FDX)
398 update |= AT91C_EMAC_FD;
402 for (i = 0; i < 10; i++) {
403 stat2 = AT91F_MII_ReadPhy(pEmac, MII_STS_REG);
404 if (stat2 & MII_STS_LINK_STAT)
408 while (GetSeconds() <= sec) continue;
410 if (stat2 & MII_STS_LINK_STAT)
412 printf("Resetting MII...");
413 AT91F_MII_WritePhy(pEmac, 0x0, 0x8000);
414 while (AT91F_MII_ReadPhy(pEmac, 0x0) & 0x8000) continue;
416 printf("emac: link");
417 stat2 = AT91F_MII_ReadPhy(pEmac, MII_SPEC_STS_REG);
418 update = pEmac->EMAC_CFG & ~(AT91C_EMAC_SPD | AT91C_EMAC_FD);
419 if (stat2 & (MII_SSTS_100FDX | MII_SSTS_100HDX)) {
421 update |= AT91C_EMAC_SPD;
423 if (stat2 & (MII_SSTS_100FDX | MII_SSTS_10FDX)) {
425 update |= AT91C_EMAC_FD;
429 pEmac->EMAC_CFG = update;
434 * .KB_C_FN_DEFINITION_START
435 * void AT91F_EmacEntry(void)
436 * This private function initializes the EMAC on the chip.
437 * .KB_C_FN_DEFINITION_END
440 AT91F_EmacEntry(void)
443 char *pRxPacket = (char*)RX_DATA_START;
444 AT91PS_EMAC pEmac = AT91C_BASE_EMAC;
446 for (i = 0; i < MAX_RX_PACKETS; ++i) {
448 p_rxBD[i].address = (unsigned)pRxPacket;
450 pRxPacket += RX_PACKET_SIZE;
453 // Set the WRAP bit at the end of the list descriptor
454 p_rxBD[MAX_RX_PACKETS-1].address |= 0x02;
456 if (!(pEmac->EMAC_SR & AT91C_EMAC_LINK))
457 MII_GetLinkSpeed(pEmac);
459 pEmac->EMAC_RBQP = (unsigned) p_rxBD;
460 pEmac->EMAC_RSR |= (AT91C_EMAC_OVR | AT91C_EMAC_REC | AT91C_EMAC_BNA);
461 pEmac->EMAC_CTL = AT91C_EMAC_TE | AT91C_EMAC_RE;
463 pEmac->EMAC_TAR = (unsigned)transmitBuffer;
467 /* ************************** GLOBAL FUNCTIONS ********************************/
470 * .KB_C_FN_DEFINITION_START
471 * void SetServerIPAddress(unsigned address)
472 * This global function sets the IP of the TFTP download server.
473 * .KB_C_FN_DEFINITION_END
476 SetServerIPAddress(unsigned address)
478 // force update in case the IP has changed
481 serverIPAddr[0] = (address >> 24) & 0xFF;
482 serverIPAddr[1] = (address >> 16) & 0xFF;
483 serverIPAddr[2] = (address >> 8) & 0xFF;
484 serverIPAddr[3] = (address >> 0) & 0xFF;
491 * .KB_C_FN_DEFINITION_START
492 * void SetLocalIPAddress(unsigned address)
493 * This global function sets the IP of this module.
494 * .KB_C_FN_DEFINITION_END
497 SetLocalIPAddress(unsigned address)
499 // force update in case the IP has changed
502 localIPAddr[0] = (address >> 24) & 0xFF;
503 localIPAddr[1] = (address >> 16) & 0xFF;
504 localIPAddr[2] = (address >> 8) & 0xFF;
505 localIPAddr[3] = (address >> 0) & 0xFF;
512 * .KB_C_FN_DEFINITION_START
513 * void TFTP_Download(unsigned address, char *filename)
514 * This global function initiates and processes a tftp download request.
515 * The server IP, local IP, local MAC must be set before this function is
517 * .KB_C_FN_DEFINITION_END
520 TFTP_Download(unsigned address, char *filename)
522 ip_header_t IpHeader;
523 unsigned thisSeconds;
526 if ((!localMACSet) || (!localIPSet) || (!serverIPSet))
531 dlAddress = (char*)address;
534 thisSeconds = GetSeconds() + 1;
535 serverPort = SWAP16(69);
540 if (CheckForNewPacket(&IpHeader)) {
544 thisSeconds = GetSeconds() + 1;
545 } else if (GetSeconds() > thisSeconds) {
547 thisSeconds = GetSeconds() + 1;
550 else if (ackBlock == -1)
551 TFTP_RequestFile(filename);
553 // Be sure to send a NAK, which is done by
554 // ACKing the last block we got.
555 TFTP_ACK_Data(0, ackBlock, 512);
556 printf("\nNAK %u\r\n", ackBlock);
561 printf("TFTP TIMEOUT!\r\n");