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 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 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 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 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 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 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 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 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 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 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 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 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 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