]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - common/cmd_bootce.c
Remove unused definition IOMUX_SION
[karo-tx-uboot.git] / common / cmd_bootce.c
1 /*
2  * Copyright (C) 2012 Lothar Waßmann <LW@KARO-electronics.de>
3  * based on: code from RedBoot (C) Uwe Steinkohl <US@KARO-electronics.de>
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 #include <common.h>
25 #include <command.h>
26 #include <net.h>
27 #include <wince.h>
28 #include <asm/errno.h>
29
30 DECLARE_GLOBAL_DATA_PTR;
31
32 #define WINCE_VRAM_BASE         0x80000000
33 #define CE_FIX_ADDRESS(a)       ((void *)((a) - WINCE_VRAM_BASE + CONFIG_SYS_SDRAM_BASE))
34
35 #ifndef INT_MAX
36 #define INT_MAX                 ((1U << (sizeof(int) * 8 - 1)) - 1)
37 #endif
38
39 /* Bin image parse states */
40 #define CE_PS_RTI_ADDR          0
41 #define CE_PS_RTI_LEN           1
42 #define CE_PS_E_ADDR            2
43 #define CE_PS_E_LEN             3
44 #define CE_PS_E_CHKSUM          4
45 #define CE_PS_E_DATA            5
46
47 #define CE_MIN(a, b)            (((a) < (b)) ? (a) : (b))
48 #define CE_MAX(a, b)            (((a) > (b)) ? (a) : (b))
49
50 #define _STRMAC(s)              #s
51 #define STRMAC(s)               _STRMAC(s)
52
53 static ce_bin __attribute__ ((aligned (32))) g_bin;
54 static ce_net __attribute__ ((aligned (32))) g_net;
55
56 static inline void print_IPaddr(IPaddr_t ip)
57 {
58         printf("%d.%d.%d.%d",
59                 ip & 0xff,
60                 (ip >> 8) & 0xff,
61                 (ip >> 16) & 0xff,
62                 (ip >> 24) & 0xff);
63 }
64
65 static void ce_init_bin(ce_bin *bin, unsigned char *dataBuffer)
66 {
67         memset(bin, 0, sizeof(*bin));
68
69         bin->data = dataBuffer;
70         bin->parseState = CE_PS_RTI_ADDR;
71         bin->parsePtr = (unsigned char *)bin;
72 }
73
74 static int ce_is_bin_image(void *image, int imglen)
75 {
76         if (imglen < CE_BIN_SIGN_LEN) {
77                 return 0;
78         }
79
80         return memcmp(image, CE_BIN_SIGN, CE_BIN_SIGN_LEN) == 0;
81 }
82
83 static const struct ce_magic {
84         char magic[8];
85         size_t size;
86         ce_std_driver_globals drv_glb;
87 } ce_magic_template = {
88         .magic = "KARO_CE6",
89         .size = sizeof(ce_std_driver_globals),
90         .drv_glb = {
91                 .header = {
92                         .signature = STD_DRV_GLB_SIGNATURE,
93                         .oalVersion = 1,
94                         .bspVersion = 1,
95                 },
96         },
97 };
98
99 #ifdef DEBUG
100 static void __attribute__((unused)) ce_dump_block(void *ptr, int length)
101 {
102         char *p = ptr;
103         int i;
104         int j;
105
106         for (i = 0; i < length; i++) {
107                 if (!(i % 16)) {
108                         printf("\n%p: ", ptr + i);
109                 }
110
111                 printf("%02x ", p[i]);
112                 if (!((i + 1) % 16)){
113                         printf("      ");
114                         for (j = i - 15; j <= i; j++){
115                                 if((p[j] > 0x1f) && (p[j] < 0x7f)) {
116                                         printf("%c", p[j]);
117                                 } else {
118                                         printf(".");
119                                 }
120                         }
121                 }
122         }
123         printf("\n");
124 }
125 #else
126 static inline void ce_dump_block(void *ptr, int length)
127 {
128 }
129 #endif
130
131 static void ce_setup_std_drv_globals(ce_std_driver_globals *std_drv_glb,
132                                 ce_bin *bin)
133 {
134         if (eth_get_dev()) {
135                 memcpy(&std_drv_glb->kitl.mac, eth_get_dev()->enetaddr,
136                         sizeof(std_drv_glb->kitl.mac));
137         }
138         snprintf(std_drv_glb->deviceId, sizeof(std_drv_glb->deviceId),
139                 "Triton%02X", eth_get_dev()->enetaddr[5]);
140
141         std_drv_glb->kitl.ipAddress = gd->bd->bi_ip_addr;
142         std_drv_glb->kitl.ipMask = getenv_IPaddr("netmask");
143         std_drv_glb->kitl.ipRoute = getenv_IPaddr("gatewayip");
144         std_drv_glb->mtdparts = getenv("mtdparts");
145 }
146
147 static void ce_prepare_run_bin(ce_bin *bin)
148 {
149         ce_driver_globals *drv_glb;
150         struct ce_magic *ce_magic = (void *)CONFIG_SYS_SDRAM_BASE + 0x160;
151         ce_std_driver_globals *std_drv_glb = &ce_magic->drv_glb;
152
153         /* Clear os RAM area (if needed) */
154         if (bin->edbgConfig.flags & EDBG_FL_CLEANBOOT) {
155                 debug("cleaning memory from %p to %p\n",
156                         bin->eRamStart, bin->eRamStart + bin->eRamLen);
157
158                 printf("Preparing clean boot ... ");
159                 memset(bin->eRamStart, 0, bin->eRamLen);
160                 printf("ok\n");
161         }
162
163         /* Prepare driver globals (if needed) */
164         if (bin->eDrvGlb) {
165                 debug("Copying CE MAGIC from %p to %p..%p\n",
166                         &ce_magic_template, ce_magic, (void *)ce_magic + sizeof(*ce_magic));
167                 memcpy(ce_magic, &ce_magic_template, sizeof(*ce_magic));
168
169                 ce_setup_std_drv_globals(std_drv_glb, bin);
170                 ce_dump_block(ce_magic, sizeof(*ce_magic));
171
172                 drv_glb = bin->eDrvGlb;
173                 memset(drv_glb, 0, sizeof(*drv_glb));
174
175                 drv_glb->signature = DRV_GLB_SIGNATURE;
176
177                 /* Local ethernet MAC address */
178                 memcpy(drv_glb->macAddr, std_drv_glb->kitl.mac,
179                         sizeof(drv_glb->macAddr));
180                 debug("got MAC address %02x:%02x:%02x:%02x:%02x:%02x from environment\n",
181                         drv_glb->macAddr[0], drv_glb->macAddr[1],
182                         drv_glb->macAddr[2], drv_glb->macAddr[3],
183                         drv_glb->macAddr[4], drv_glb->macAddr[5]);
184
185                 /* Local IP address */
186                 drv_glb->ipAddr = getenv_IPaddr("ipaddr");
187
188                 /* Subnet mask */
189                 drv_glb->ipMask = getenv_IPaddr("netmask");
190
191                 /* Gateway config */
192                 drv_glb->ipGate = getenv_IPaddr("gatewayip");
193 #ifdef DEBUG
194                 debug("got IP address ");
195                 print_IPaddr(drv_glb->ipAddr);
196                 debug(" from environment\n");
197                 debug("got IP mask ");
198                 print_IPaddr(drv_glb->ipMask);
199                 debug(" from environment\n");
200                 debug("got gateway address ");
201                 print_IPaddr(drv_glb->ipGate);
202                 debug(" from environment\n");
203 #endif
204                 /* EDBG services config */
205                 memcpy(&drv_glb->edbgConfig, &bin->edbgConfig, sizeof(bin->edbgConfig));
206         }
207
208         /*
209          * Make sure, all the above makes it into SDRAM because
210          * WinCE switches the cache & MMU off, obviously without
211          * flushing it first!
212          */
213         flush_dcache_all();
214 }
215
216 static int ce_lookup_ep_bin(ce_bin *bin)
217 {
218         ce_rom_hdr *header;
219         ce_toc_entry *tentry;
220         e32_rom *e32;
221         unsigned int i;
222         uint32_t *sig = (uint32_t *)(bin->rtiPhysAddr + ROM_SIGNATURE_OFFSET);
223
224         debug("Looking for TOC signature at %p\n", sig);
225
226         /* Check image Table Of Contents (TOC) signature */
227         if (*sig != ROM_SIGNATURE) {
228                 printf("Error: Did not find image TOC signature!\n");
229                 printf("Expected %08x at address %p; found %08x instead\n",
230                         ROM_SIGNATURE, sig, *sig);
231                 return 0;
232         }
233
234         /* Lookup entry point */
235         header = CE_FIX_ADDRESS(*(unsigned int *)(bin->rtiPhysAddr +
236                                                 ROM_SIGNATURE_OFFSET +
237                                                 sizeof(unsigned int)));
238         tentry = (ce_toc_entry *)(header + 1);
239
240         for (i = 0; i < header->nummods; i++) {
241                 // Look for 'nk.exe' module
242                 if (strcmp(CE_FIX_ADDRESS(tentry[i].fileName), "nk.exe") == 0) {
243                         // Save entry point and RAM addresses
244
245                         e32 = CE_FIX_ADDRESS(tentry[i].e32Offset);
246
247                         bin->eEntryPoint = CE_FIX_ADDRESS(tentry[i].loadOffset) +
248                                 e32->e32_entryrva;
249                         bin->eRamStart = CE_FIX_ADDRESS(header->ramStart);
250                         bin->eRamLen = header->ramEnd - header->ramStart;
251                         // Save driver_globals address
252                         // Must follow RAM section in CE config.bib file
253                         //
254                         // eg.
255                         //
256                         // RAM          80900000        03200000        RAM
257                         // DRV_GLB      83B00000        00001000        RESERVED
258                         //
259                         bin->eDrvGlb = CE_FIX_ADDRESS(header->ramEnd);
260                         return 1;
261                 }
262         }
263
264         // Error: Did not find 'nk.exe' module
265         return 0;
266 }
267
268 static int ce_parse_bin(ce_bin *bin)
269 {
270         unsigned char *pbData = bin->data;
271         int len = bin->dataLen;
272         int copyLen;
273
274         debug("starting ce image parsing:\n\tbin->binLen: 0x%08X\n", bin->binLen);
275
276         if (len) {
277                 if (bin->binLen == 0) {
278                         // Check for the .BIN signature first
279                         if (!ce_is_bin_image(pbData, len)) {
280                                 printf("Error: Invalid or corrupted .BIN image!\n");
281                                 return CE_PR_ERROR;
282                         }
283
284                         printf("Loading Windows CE .BIN image ...\n");
285                         // Skip signature
286                         len -= CE_BIN_SIGN_LEN;
287                         pbData += CE_BIN_SIGN_LEN;
288                 }
289
290                 while (len) {
291                         switch (bin->parseState) {
292                         case CE_PS_RTI_ADDR:
293                         case CE_PS_RTI_LEN:
294                         case CE_PS_E_ADDR:
295                         case CE_PS_E_LEN:
296                         case CE_PS_E_CHKSUM:
297                                 copyLen = CE_MIN(sizeof(unsigned int) - bin->parseLen, len);
298                                 memcpy(&bin->parsePtr[bin->parseLen], pbData, copyLen);
299
300                                 bin->parseLen += copyLen;
301                                 len -= copyLen;
302                                 pbData += copyLen;
303
304                                 if (bin->parseLen == sizeof(unsigned int)) {
305                                         if (bin->parseState == CE_PS_RTI_ADDR)
306                                                 bin->rtiPhysAddr = CE_FIX_ADDRESS(bin->rtiPhysAddr);
307                                         else if (bin->parseState == CE_PS_E_ADDR &&
308                                                 bin->ePhysAddr)
309                                                 bin->ePhysAddr = CE_FIX_ADDRESS(bin->ePhysAddr);
310
311                                         bin->parseState++;
312                                         bin->parseLen = 0;
313                                         bin->parsePtr += sizeof(unsigned int);
314
315                                         if (bin->parseState == CE_PS_E_DATA) {
316                                                 if (bin->ePhysAddr) {
317                                                         bin->parsePtr = bin->ePhysAddr;
318                                                         bin->parseChkSum = 0;
319                                                 } else {
320                                                         /* EOF */
321                                                         len = 0;
322                                                         bin->endOfBin = 1;
323                                                 }
324                                         }
325                                 }
326                                 break;
327
328                         case CE_PS_E_DATA:
329                                 if (bin->ePhysAddr) {
330                                         copyLen = CE_MIN(bin->ePhysLen - bin->parseLen, len);
331                                         bin->parseLen += copyLen;
332                                         len -= copyLen;
333
334                                         while (copyLen--) {
335                                                 bin->parseChkSum += *pbData;
336                                                 *bin->parsePtr++ = *pbData++;
337                                         }
338
339                                         if (bin->parseLen == bin->ePhysLen) {
340                                                 printf("Section [%02d]: address %p, size 0x%08X, checksum %s\n",
341                                                         bin->section,
342                                                         bin->ePhysAddr,
343                                                         bin->ePhysLen,
344                                                         (bin->eChkSum == bin->parseChkSum) ? "ok" : "fail");
345
346                                                 if (bin->eChkSum != bin->parseChkSum) {
347                                                         printf("Error: Checksum error, corrupted .BIN file!\n");
348                                                         printf("checksum calculated: 0x%08x from file: 0x%08x\n",
349                                                                 bin->parseChkSum, bin->eChkSum);
350                                                         bin->binLen = 0;
351                                                         return CE_PR_ERROR;
352                                                 }
353
354                                                 bin->section++;
355                                                 bin->parseState = CE_PS_E_ADDR;
356                                                 bin->parseLen = 0;
357                                                 bin->parsePtr = (unsigned char *)&bin->ePhysAddr;
358                                         }
359                                 } else {
360                                         bin->parseLen = 0;
361                                         bin->endOfBin = 1;
362                                         len = 0;
363                                 }
364                                 break;
365                         }
366                 }
367         }
368
369         if (bin->endOfBin) {
370                 if (!ce_lookup_ep_bin(bin)) {
371                         printf("Error: entry point not found!\n");
372                         bin->binLen = 0;
373                         return CE_PR_ERROR;
374                 }
375
376                 printf("Entry point: %p, address range: %p-%p\n",
377                         bin->eEntryPoint,
378                         bin->rtiPhysAddr,
379                         bin->rtiPhysAddr + bin->rtiPhysLen);
380
381                 return CE_PR_EOF;
382         }
383
384         /* Need more data */
385         bin->binLen += bin->dataLen;
386         return CE_PR_MORE;
387 }
388
389 static int ce_bin_load(void *image, int imglen)
390 {
391         ce_init_bin(&g_bin, image);
392         g_bin.dataLen = imglen;
393         if (ce_parse_bin(&g_bin) == CE_PR_EOF) {
394                 ce_prepare_run_bin(&g_bin);
395                 return 1;
396         }
397
398         return 0;
399 }
400
401 static void ce_run_bin(void (*entry)(void))
402 {
403         printf("Launching Windows CE ...\n");
404         entry();
405 }
406
407 static int do_bootce(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
408 {
409         void *addr;
410         size_t image_size;
411         char *s;
412
413         if (argc > 1) {
414                 addr = (void *)simple_strtoul(argv[1], NULL, 16);
415                 image_size = INT_MAX;           /* actually we do not know the image size */
416         } else if (getenv("fileaddr") != NULL) {
417                 addr = (void *)getenv_ulong("fileaddr", 16, 0);
418                 image_size = getenv_ulong("filesize", 16, INT_MAX);
419         } else {
420                 printf ("Usage:\n%s\n", cmdtp->usage);
421                 return 1;
422         }
423
424         printf ("## Booting Windows CE Image from address %p ...\n", addr);
425
426         /* check if there is a valid windows CE image */
427         if (ce_is_bin_image(addr, image_size)) {
428                 if (!ce_bin_load(addr, image_size)) {
429                         /* Ops! Corrupted .BIN image! */
430                         /* Handle error here ...      */
431                         printf("corrupted .BIN image !!!\n");
432                         return 1;
433                 }
434                 if ((s = getenv("autostart")) != NULL) {
435                         if (*s != 'y') {
436                                 /*
437                                  * just use bootce to load the image to SDRAM;
438                                  * Do not start it automatically.
439                                  */
440                                 setenv_addr("fileaddr",
441                                         g_bin.eEntryPoint);
442                                 return 0;
443                         }
444                 }
445                 ce_run_bin(g_bin.eEntryPoint);          /* start the image */
446         } else {
447                 printf("Image does not seem to be a valid Windows CE image!\n");
448                 return 1;
449         }
450         return 1;       /* never reached - just to keep compiler happy */
451 }
452
453 U_BOOT_CMD(
454         bootce, 2,      0,      do_bootce,
455         "bootce\t- Boot a Windows CE image from memory \n",
456         "[args..]\n"
457         "\taddr\t\t-boot image from address addr\n"
458 );
459
460 static void wince_handler(uchar *pkt, unsigned dport, IPaddr_t sip,
461                         unsigned sport, unsigned len)
462 {
463         void *eth_pkt = pkt - IP_HDR_SIZE - ETHER_HDR_SIZE;
464         unsigned eth_len = len + IP_HDR_SIZE + ETHER_HDR_SIZE;
465
466         NetState = NETLOOP_SUCCESS;     /* got input - quit net loop */
467
468         if (memcmp(eth_pkt, eth_get_dev()->enetaddr, ETH_ALEN) != 0) {
469                 g_net.got_packet_4me = 0;
470                 return;
471         }
472         memcpy(&g_net.data[g_net.align_offset],
473                 eth_pkt, eth_len);
474
475         g_net.dataLen = len;
476         g_net.got_packet_4me = 1;
477
478         g_net.srvAddrRecv.sin_port = *((unsigned short *)(&g_net.data[
479                         ETHER_HDR_SIZE + IP_HDR_SIZE_NO_UDP + g_net.align_offset]));
480         NetCopyIP(&g_net.srvAddrRecv.sin_addr, &g_net.data[ETHER_HDR_SIZE +
481                 g_net.align_offset + 12]);
482         memcpy(NetServerEther, &g_net.data[g_net.align_offset + 6], ETH_ALEN);
483 #if 0
484         printf("received packet:   buffer %p   Laenge %d \n", pkt, len);
485         printf("from ");
486         print_IPaddr(g_net.srvAddrRecv.sin_addr);
487         printf(", port: %d\n", ntohs(g_net.srvAddrRecv.sin_port));
488
489         ce_dump_block(pkt, len);
490
491         printf("Headers:\n");
492         ce_dump_block(eth_pkt, ETHER_HDR_SIZE + IP_HDR_SIZE);
493         printf("my port should be: %d\n",
494                 ntohs(*((unsigned short *)(&g_net.data[ETHER_HDR_SIZE +
495                                                         IP_HDR_SIZE_NO_UDP +
496                                                         g_net.align_offset + 2]))));
497 #endif
498 }
499
500 /* returns packet length if successfull */
501 static int ce_recv_packet(uchar *buf, int len, struct sockaddr_in *from,
502                 struct sockaddr_in *local, struct timeval *timeout)
503 {
504         int rxlength;
505         ulong time_started;
506
507         g_net.got_packet_4me = 0;
508         time_started = get_timer(0);
509         NetSetHandler(wince_handler);
510
511         while (1) {
512                 rxlength = eth_rx();
513                 if (g_net.got_packet_4me)
514                         return g_net.dataLen;
515                 /* check for timeout */
516                 if (get_timer(time_started) > timeout->tv_sec * CONFIG_SYS_HZ) {
517                         return -ETIMEDOUT;
518                 }
519         }
520 }
521
522 static int ce_recv_frame(ce_net *net, int timeout)
523 {
524         struct timeval timeo;
525
526         timeo.tv_sec = timeout;
527         timeo.tv_usec = 0;
528
529         net->dataLen = ce_recv_packet(&net->data[net->align_offset],
530                                 sizeof(net->data) - net->align_offset,
531                                 &net->srvAddrRecv, &net->locAddr, &timeo);
532
533         if (net->dataLen < 0 || net->dataLen > sizeof(net->data)) {
534                 /* Error! No data available */
535                 net->dataLen = 0;
536         }
537
538         return net->dataLen;
539 }
540
541 static int ce_send_frame(ce_net *net)
542 {
543         uchar *pkt = (uchar *)NetTxPacket + ETHER_HDR_SIZE + IP_HDR_SIZE;
544
545         memcpy(pkt, &net->data[net->align_offset + ETHER_HDR_SIZE + IP_HDR_SIZE],
546                 net->dataLen);
547         return NetSendUDPPacket(NetServerEther, net->srvAddrSend.sin_addr,
548                                 ntohs(net->srvAddrSend.sin_port),
549                                 ntohs(net->locAddr.sin_port), net->dataLen);
550 }
551
552 static int ce_send_write_ack(ce_net *net)
553 {
554         unsigned short *wdata;
555         unsigned long aligned_address;
556
557         aligned_address = (unsigned long)&net->data[ETHER_HDR_SIZE + IP_HDR_SIZE + net->align_offset];
558
559         wdata = (unsigned short *)aligned_address;
560         wdata[0] = htons(EDBG_CMD_WRITE_ACK);
561         wdata[1] = htons(net->blockNum);
562
563         net->dataLen = 4;
564
565         return ce_send_frame(net);
566 }
567
568 static int ce_process_download(ce_net *net, ce_bin *bin)
569 {
570         int ret = CE_PR_MORE;
571
572         if (net->dataLen >= 2) {
573                 unsigned short command;
574
575                 command = ntohs(*(unsigned short *)&net->data[CE_DOFFSET]);
576                 debug("command found: 0x%04X\n", command);
577
578                 switch (command) {
579                 case EDBG_CMD_WRITE_REQ:
580                         if (!net->link) {
581                                 // Check file name for WRITE request
582                                 // CE EShell uses "boot.bin" file name
583 #if 0
584                                 printf(">>>>>>>> First Frame, IP: %s, port: %d\n",
585                                         inet_ntoa((in_addr_t *)&net->srvAddrRecv),
586                                         ntohs(net->srvAddrRecv.sin_port));
587 #endif
588                                 if (strncmp((char *)&net->data[CE_DOFFSET + 2],
589                                                 "boot.bin", 8) == 0) {
590                                         // Some diag output
591                                         if (net->verbose) {
592                                                 printf("Locked Down download link, IP: ");
593                                                 print_IPaddr(net->srvAddrRecv.sin_addr);
594                                                 printf(", port: %d\n", ntohs(net->srvAddrRecv.sin_port));
595
596                                                 printf("Sending BOOTME request [%d] to ",
597                                                         net->seqNum);
598                                                 print_IPaddr(net->srvAddrSend.sin_addr);
599                                                 printf("\n");
600                                         }
601
602                                         // Lock down EShell download link
603                                         net->locAddr.sin_port = htons(EDBG_DOWNLOAD_PORT + 1);
604                                         net->srvAddrSend.sin_port = net->srvAddrRecv.sin_port;
605                                         net->srvAddrSend.sin_addr = net->srvAddrRecv.sin_addr;
606                                         net->link = 1;
607                                 } else {
608                                         // Unknown link
609                                         net->srvAddrRecv.sin_port = 0;
610                                 }
611
612                                 if (net->link) {
613                                         ce_send_write_ack(net);
614                                 }
615                         }
616                         break;
617
618                 case EDBG_CMD_WRITE:
619                         /* Fix data len */
620                         bin->dataLen = net->dataLen - 4;
621
622                         ret = ce_parse_bin(bin);
623                         if (ret != CE_PR_ERROR) {
624                                 net->blockNum++;
625                                 ce_send_write_ack(net);
626                         }
627                         break;
628
629                 case EDBG_CMD_READ_REQ:
630                         /* Read requests are not supported
631                          * Do nothing ...
632                          */
633                         break;
634
635                 case EDBG_CMD_ERROR:
636                         printf("Error: unknown error on the host side\n");
637
638                         bin->binLen = 0;
639                         ret = CE_PR_ERROR;
640                         break;
641
642                 default:
643                         printf("unknown command 0x%04X\n", command);
644                         return -EINVAL;
645                 }
646         }
647         return ret;
648 }
649
650 static void ce_init_edbg_link(ce_net *net)
651 {
652         /* Initialize EDBG link for commands */
653
654         net->locAddr.sin_port = htons(EDBG_DOWNLOAD_PORT);
655         net->srvAddrSend.sin_port = htons(EDBG_DOWNLOAD_PORT);
656         net->srvAddrRecv.sin_port = 0;
657         net->link = 0;
658 }
659
660 static void ce_process_edbg(ce_net *net, ce_bin *bin)
661 {
662         eth_dbg_hdr *header;
663
664         if (net->dataLen < sizeof(eth_dbg_hdr)) {
665                 /* Bad packet */
666
667                 net->srvAddrRecv.sin_port = 0;
668                 return;
669         }
670
671         header = (eth_dbg_hdr *)&net->data[net->align_offset + ETHER_HDR_SIZE + IP_HDR_SIZE];
672
673         if (header->id != EDBG_ID) {
674                 /* Bad packet */
675
676                 net->srvAddrRecv.sin_port = 0;
677                 return;
678         }
679
680         if (header->service != EDBG_SVC_ADMIN) {
681                 /* Unknown service */
682                 return;
683         }
684
685         if (!net->link) {
686                 /* Some diag output */
687                 if (net->verbose) {
688                         printf("Locked Down EDBG service link, IP: ");
689                         print_IPaddr(net->srvAddrRecv.sin_addr);
690                         printf(", port: %d\n", ntohs(net->srvAddrRecv.sin_port));
691                 }
692
693                 /* Lock down EDBG link */
694                 net->srvAddrSend.sin_port = net->srvAddrRecv.sin_port;
695                 net->link = 1;
696         }
697
698         switch (header->cmd) {
699         case EDBG_CMD_JUMPIMG:
700                 net->gotJumpingRequest = 1;
701
702                 if (net->verbose) {
703                         printf("Received JUMPING command\n");
704                 }
705                 /* Just pass through and copy CONFIG structure */
706         case EDBG_CMD_OS_CONFIG:
707                 /* Copy config structure */
708                 memcpy(&bin->edbgConfig, header->data,
709                         sizeof(edbg_os_config_data));
710                 if (net->verbose) {
711                         printf("Received CONFIG command\n");
712                         if (bin->edbgConfig.flags & EDBG_FL_DBGMSG) {
713                                 printf("--> Enabling DBGMSG service, IP: %d.%d.%d.%d, port: %d\n",
714                                         (bin->edbgConfig.dbgMsgIPAddr >> 0) & 0xFF,
715                                         (bin->edbgConfig.dbgMsgIPAddr >> 8) & 0xFF,
716                                         (bin->edbgConfig.dbgMsgIPAddr >> 16) & 0xFF,
717                                         (bin->edbgConfig.dbgMsgIPAddr >> 24) & 0xFF,
718                                         ntohs(bin->edbgConfig.dbgMsgPort));
719                         }
720
721                         if (bin->edbgConfig.flags & EDBG_FL_PPSH) {
722                                 printf("--> Enabling PPSH service, IP: %d.%d.%d.%d, port: %d\n",
723                                         (bin->edbgConfig.ppshIPAddr >> 0) & 0xFF,
724                                         (bin->edbgConfig.ppshIPAddr >> 8) & 0xFF,
725                                         (bin->edbgConfig.ppshIPAddr >> 16) & 0xFF,
726                                         (bin->edbgConfig.ppshIPAddr >> 24) & 0xFF,
727                                         ntohs(bin->edbgConfig.ppshPort));
728                         }
729
730                         if (bin->edbgConfig.flags & EDBG_FL_KDBG) {
731                                 printf("--> Enabling KDBG service, IP: %d.%d.%d.%d, port: %d\n",
732                                         (bin->edbgConfig.kdbgIPAddr >> 0) & 0xFF,
733                                         (bin->edbgConfig.kdbgIPAddr >> 8) & 0xFF,
734                                         (bin->edbgConfig.kdbgIPAddr >> 16) & 0xFF,
735                                         (bin->edbgConfig.kdbgIPAddr >> 24) & 0xFF,
736                                         ntohs(bin->edbgConfig.kdbgPort));
737                         }
738
739                         if (bin->edbgConfig.flags & EDBG_FL_CLEANBOOT) {
740                                 printf("--> Force clean boot\n");
741                         }
742                 }
743                 break;
744
745         default:
746                 if (net->verbose) {
747                         printf("Received unknown command: %08X\n", header->cmd);
748                 }
749                 return;
750         }
751
752         /* Respond with ack */
753         header->flags = EDBG_FL_FROM_DEV | EDBG_FL_ACK;
754         net->dataLen = EDBG_DATA_OFFSET;
755         ce_send_frame(net);
756 }
757
758 static int ce_send_bootme(ce_net *net)
759 {
760         eth_dbg_hdr *header;
761         edbg_bootme_data *data;
762 #ifdef DEBUG
763         int     i;
764         unsigned char   *pkt;
765 #endif
766         /* Fill out BOOTME packet */
767         memset(net->data, 0, PKTSIZE);
768         header = (eth_dbg_hdr *)&net->data[CE_DOFFSET];
769         data = (edbg_bootme_data *)header->data;
770
771         header->id = EDBG_ID;
772         header->service = EDBG_SVC_ADMIN;
773         header->flags = EDBG_FL_FROM_DEV;
774         header->seqNum = net->seqNum++;
775         header->cmd = EDBG_CMD_BOOTME;
776
777         data->versionMajor = 0;
778         data->versionMinor = 0;
779         data->cpuId = EDBG_CPU_TYPE_ARM;
780         data->bootmeVer = EDBG_CURRENT_BOOTME_VERSION;
781         data->bootFlags = 0;
782         data->downloadPort = 0;
783         data->svcPort = 0;
784
785         /* MAC address from environment*/
786         if (!eth_getenv_enetaddr("ethaddr", data->macAddr)) {
787                 printf("'ethaddr' is not set or invalid\n");
788                 memset(data->macAddr, 0, sizeof(data->macAddr));
789         }
790
791         /* IP address from environment */
792         data->ipAddr = getenv_IPaddr("ipaddr");
793
794         // Device name string (NULL terminated). Should include
795         // platform and number based on Ether address (e.g. Odo42, CEPCLS2346, etc)
796
797         // We will use lower MAC address segment to create device name
798         // eg. MAC '00-0C-C6-69-09-05', device name 'Triton05'
799
800         strncpy(data->platformId, "Triton", sizeof(data->platformId));
801         snprintf(data->deviceName, sizeof(data->deviceName), "%s%02X",
802                 data->platformId, data->macAddr[5]);
803
804 #ifdef DEBUG
805         printf("header->id: %08X\r\n", header->id);
806         printf("header->service: %08X\r\n", header->service);
807         printf("header->flags: %08X\r\n", header->flags);
808         printf("header->seqNum: %08X\r\n", header->seqNum);
809         printf("header->cmd: %08X\r\n\r\n", header->cmd);
810
811         printf("data->versionMajor: %08X\r\n", data->versionMajor);
812         printf("data->versionMinor: %08X\r\n", data->versionMinor);
813         printf("data->cpuId: %08X\r\n", data->cpuId);
814         printf("data->bootmeVer: %08X\r\n", data->bootmeVer);
815         printf("data->bootFlags: %08X\r\n", data->bootFlags);
816         printf("data->svcPort: %08X\r\n\r\n", ntohs(data->svcPort));
817
818         printf("data->macAddr: %02X-%02X-%02X-%02X-%02X-%02X\r\n",
819                 data->macAddr[0], data->macAddr[1],
820                 data->macAddr[2], data->macAddr[3],
821                 data->macAddr[4], data->macAddr[5]);
822
823         printf("data->ipAddr: %d.%d.%d.%d\r\n",
824                 (data->ipAddr >> 0) & 0xFF,
825                 (data->ipAddr >> 8) & 0xFF,
826                 (data->ipAddr >> 16) & 0xFF,
827                 (data->ipAddr >> 24) & 0xFF);
828
829         printf("data->platformId: %s\r\n", data->platformId);
830
831         printf("data->deviceName: %s\r\n", data->deviceName);
832 #endif
833         // Some diag output ...
834         if (net->verbose) {
835                 printf("Sending BOOTME request [%d] to ", net->seqNum);
836                 print_IPaddr(net->srvAddrSend.sin_addr);
837                 printf("\n");
838         }
839
840         net->dataLen = BOOTME_PKT_SIZE;
841 #ifdef DEBUG
842         debug("Start of buffer:      %p\n", net->data);
843         debug("Start of ethernet buffer:   %p\n", &net->data[net->align_offset]);
844         debug("Start of CE header:         %p\n", header);
845         debug("Start of CE data:           %p\n", data);
846
847         pkt = &net->data[net->align_offset];
848         debug("packet to send (ceconnect): \n");
849         for (i = 0; i < net->dataLen + ETHER_HDR_SIZE + IP_HDR_SIZE; i++) {
850                 debug("0x%02X ", pkt[i]);
851                 if (!((i + 1) % 16))
852                         debug("\n");
853         }
854         debug("\n");
855 #endif
856         memcpy(NetServerEther, NetBcastAddr, 6);
857         return ce_send_frame(net);
858 }
859
860 static void ce_init_download_link(ce_net *net, ce_bin *bin,
861                                 struct sockaddr_in *host_addr, int verbose)
862 {
863         unsigned long aligned_address;
864
865         /* Initialize EDBG link for download */
866         memset(net, 0, sizeof(*net));
867
868         /* our buffer contains space for ethernet- ip- and udp- headers */
869         /* calculate an offset so that our ce field is aligned to 4 bytes */
870         aligned_address = (unsigned long)net->data;
871         /* we need 42 bytes room for headers (14 Ethernet , 20 IPv4, 8 UDP) */
872         aligned_address += ETHER_HDR_SIZE + IP_HDR_SIZE;
873         /* want CE header aligned to 4 Byte boundary */
874         net->align_offset = (4 - (aligned_address % 4)) % 4;
875
876         net->locAddr.sin_family = AF_INET;
877         net->locAddr.sin_addr = getenv_IPaddr("ipaddr");
878         net->locAddr.sin_port = htons(EDBG_DOWNLOAD_PORT);
879
880         net->srvAddrSend.sin_family = AF_INET;
881         net->srvAddrSend.sin_port = htons(EDBG_DOWNLOAD_PORT);
882
883         net->srvAddrRecv.sin_family = AF_INET;
884         net->srvAddrRecv.sin_port = 0;
885
886         if (host_addr->sin_addr) {
887                 /* Use specified host address ... */
888                 net->srvAddrSend.sin_addr = host_addr->sin_addr;
889                 net->srvAddrRecv.sin_addr = host_addr->sin_addr;
890         } else {
891                 /* ... or default server address */
892                 net->srvAddrSend.sin_addr = getenv_IPaddr("serverip");
893                 net->srvAddrRecv.sin_addr = getenv_IPaddr("serverip");
894         }
895
896         net->verbose = verbose;
897
898         ce_init_bin(bin, &net->data[CE_DOFFSET + 4]);
899
900         eth_halt();
901
902 #ifdef CONFIG_NET_MULTI
903         eth_set_current();
904 #endif
905         if (eth_init(gd->bd) < 0) {
906 #ifdef ET_DEBUG
907                 puts("ceconnect: failed to init ethernet !\n");
908 #endif
909                 eth_halt();
910                 return;
911         }
912 #ifdef ET_DEBUG
913         puts("ceconnect: init ethernet done!\n");
914 #endif
915         memcpy(NetOurEther, eth_get_dev()->enetaddr, ETH_ALEN);
916         NetCopyIP(&NetOurIP, &gd->bd->bi_ip_addr);
917         NetOurGatewayIP = getenv_IPaddr("gatewayip");
918         NetOurSubnetMask = getenv_IPaddr("netmask");
919         NetServerIP = getenv_IPaddr("serverip");
920 }
921
922 static int do_ceconnect(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
923 {
924         int i;
925         int verbose = 0, use_timeout = 0;
926         int timeout = 0, recv_timeout, ret;
927         struct sockaddr_in host_ip_addr;
928
929         for (i = 1; i < argc; i++){
930                 if (*argv[i] != '-')
931                         break;
932                 if (argv[i][1] == 'v') {
933                         verbose = 1;
934                 } else if (argv[i][1] == 't') {
935                         i++;
936                         if (argc > i) {
937                                 timeout = simple_strtoul(argv[i],
938                                                         NULL, 10);
939                                 use_timeout = 1;
940                         } else {
941                                 printf("Option requires an argument - t\n");
942                                 return 1;
943                         }
944                 }
945         }
946
947         memset(&host_ip_addr, 0xff, sizeof(host_ip_addr));
948
949         ce_init_download_link(&g_net, &g_bin, &host_ip_addr, verbose);
950         while (1) {
951                 if (g_net.link) {
952                         recv_timeout = 3;
953                 } else {
954                         recv_timeout = 1;
955
956                         if (use_timeout && timeout <= 0) {
957                                 printf("CELOAD - Canceled, timeout\n");
958                                 eth_halt();
959                                 return 1;
960                         }
961                         if (ctrlc()) {
962                                 printf("CELOAD - canceled by user\n");
963                                 eth_halt();
964                                 return 1;
965                         }
966
967                         debug("sending broadcast frame bootme\n");
968
969                         if (ce_send_bootme(&g_net)) {
970                                 printf("CELOAD - error while sending BOOTME request\n");
971                                 eth_halt();
972                                 return 1;
973                         }
974                         debug("net state is: %d\n", NetState);
975                         if (verbose) {
976                                 if (use_timeout) {
977                                         printf("Waiting for connection, timeout %d sec\n", timeout);
978                                 } else {
979                                         printf("Waiting for connection, enter ^C to abort\n");
980                                 }
981                         }
982                 }
983
984                 if (ce_recv_frame(&g_net, recv_timeout)) {
985                         ret = ce_process_download(&g_net, &g_bin);
986                         if (ret != CE_PR_MORE)
987                                 break;
988                 } else if (use_timeout) {
989                         timeout -= recv_timeout;
990                 }
991         }
992
993         if (g_bin.binLen) {
994                 // Try to receive edbg commands from host
995                 ce_init_edbg_link(&g_net);
996                 if (verbose)
997                         printf("Waiting for EDBG commands ...\n");
998
999                 while (ce_recv_frame(&g_net, 3))
1000                         ce_process_edbg(&g_net, &g_bin);
1001
1002                 // Prepare WinCE image for execution
1003                 ce_prepare_run_bin(&g_bin);
1004
1005                 // Launch WinCE, if necessary
1006                 if (g_net.gotJumpingRequest)
1007                         ce_run_bin(g_bin.eEntryPoint);
1008         }
1009         eth_halt();
1010         return 0;
1011 }
1012
1013 U_BOOT_CMD(
1014         ceconnect,      4,      1,      do_ceconnect,
1015         "ceconnect    - Set up a connection to the CE host PC over TCP/IP and download the run-time image\n",
1016         "ceconnect [-v] [-t <timeout>]\n"
1017         "  -v verbose operation\n"
1018         "  -t <timeout> - max wait time (#sec) for the connection\n"
1019 );