]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - common/cmd_bootce.c
general cleanup
[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                 ((int)(~0U >> 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 static IPaddr_t server_ip;
56
57 static void ce_init_bin(ce_bin *bin, unsigned char *dataBuffer)
58 {
59         memset(bin, 0, sizeof(*bin));
60
61         bin->data = dataBuffer;
62         bin->parseState = CE_PS_RTI_ADDR;
63         bin->parsePtr = (unsigned char *)bin;
64 }
65
66 static int ce_is_bin_image(void *image, int imglen)
67 {
68         if (imglen < CE_BIN_SIGN_LEN) {
69                 return 0;
70         }
71
72         return memcmp(image, CE_BIN_SIGN, CE_BIN_SIGN_LEN) == 0;
73 }
74
75 static const struct ce_magic {
76         char magic[8];
77         size_t size;
78         ce_std_driver_globals drv_glb;
79 } ce_magic_template = {
80         .magic = "KARO_CE6",
81         .size = sizeof(ce_std_driver_globals),
82         .drv_glb = {
83                 .header = {
84                         .signature = STD_DRV_GLB_SIGNATURE,
85                         .oalVersion = 1,
86                         .bspVersion = 2,
87                 },
88         },
89 };
90
91 #ifdef DEBUG
92 static void __attribute__((unused)) ce_dump_block(void *ptr, int length)
93 {
94         char *p = ptr;
95         int i;
96         int j;
97
98         for (i = 0; i < length; i++) {
99                 if (!(i % 16)) {
100                         printf("\n%p: ", ptr + i);
101                 }
102
103                 printf("%02x ", p[i]);
104                 if (!((i + 1) % 16)){
105                         printf("      ");
106                         for (j = i - 15; j <= i; j++){
107                                 if((p[j] > 0x1f) && (p[j] < 0x7f)) {
108                                         printf("%c", p[j]);
109                                 } else {
110                                         printf(".");
111                                 }
112                         }
113                 }
114         }
115         printf("\n");
116 }
117 #else
118 static inline void ce_dump_block(void *ptr, int length)
119 {
120 }
121 #endif
122
123 static void ce_setup_std_drv_globals(ce_std_driver_globals *std_drv_glb)
124 {
125         char *mtdparts = getenv("mtdparts");
126         size_t max_len = ALIGN((unsigned long)std_drv_glb, SZ_4K) -
127                 (unsigned long)&std_drv_glb->mtdparts;
128
129         if (eth_get_dev()) {
130                 memcpy(&std_drv_glb->kitl.mac, eth_get_dev()->enetaddr,
131                         sizeof(std_drv_glb->kitl.mac));
132         }
133         snprintf(std_drv_glb->deviceId, sizeof(std_drv_glb->deviceId),
134                 "Triton%02X", eth_get_dev()->enetaddr[5]);
135
136         NetCopyIP(&std_drv_glb->kitl.ipAddress, &NetOurIP);
137         std_drv_glb->kitl.ipMask = getenv_IPaddr("netmask");
138         std_drv_glb->kitl.ipRoute = getenv_IPaddr("gatewayip");
139
140         if (mtdparts) {
141                 strncpy(std_drv_glb->mtdparts, mtdparts, max_len);
142                 std_drv_glb->mtdparts[max_len - 1] = '\0';
143         } else {
144                 printf("Failed to get mtdparts environment variable\n");
145         }
146 }
147
148 static void ce_prepare_run_bin(ce_bin *bin)
149 {
150         ce_driver_globals *drv_glb;
151         struct ce_magic *ce_magic = (void *)CONFIG_SYS_SDRAM_BASE + 0x160;
152         ce_std_driver_globals *std_drv_glb = &ce_magic->drv_glb;
153
154         /* Clear os RAM area (if needed) */
155         if (bin->edbgConfig.flags & EDBG_FL_CLEANBOOT) {
156                 debug("cleaning memory from %p to %p\n",
157                         bin->eRamStart, bin->eRamStart + bin->eRamLen);
158
159                 printf("Preparing clean boot ... ");
160                 memset(bin->eRamStart, 0, bin->eRamLen);
161                 printf("ok\n");
162         }
163
164         /* Prepare driver globals (if needed) */
165         if (bin->eDrvGlb) {
166                 debug("Copying CE MAGIC from %p to %p..%p\n",
167                         &ce_magic_template, ce_magic,
168                         (void *)ce_magic + sizeof(*ce_magic) - 1);
169                 memcpy(ce_magic, &ce_magic_template, sizeof(*ce_magic));
170
171                 ce_setup_std_drv_globals(std_drv_glb);
172                 ce_magic->size = sizeof(*std_drv_glb) +
173                         strlen(std_drv_glb->mtdparts) + 1;
174                 ce_dump_block(ce_magic, offsetof(struct ce_magic, drv_glb) +
175                         ce_magic->size);
176
177                 drv_glb = bin->eDrvGlb;
178                 memset(drv_glb, 0, sizeof(*drv_glb));
179
180                 drv_glb->signature = DRV_GLB_SIGNATURE;
181
182                 /* Local ethernet MAC address */
183                 memcpy(drv_glb->macAddr, std_drv_glb->kitl.mac,
184                         sizeof(drv_glb->macAddr));
185                 debug("got MAC address %02x:%02x:%02x:%02x:%02x:%02x from environment\n",
186                         drv_glb->macAddr[0], drv_glb->macAddr[1],
187                         drv_glb->macAddr[2], drv_glb->macAddr[3],
188                         drv_glb->macAddr[4], drv_glb->macAddr[5]);
189
190                 /* Local IP address */
191                 drv_glb->ipAddr = getenv_IPaddr("ipaddr");
192
193                 /* Subnet mask */
194                 drv_glb->ipMask = getenv_IPaddr("netmask");
195
196                 /* Gateway config */
197                 drv_glb->ipGate = getenv_IPaddr("gatewayip");
198 #ifdef DEBUG
199                 debug("got IP address %pI4 from environment\n", &drv_glb->ipAddr);
200                 debug("got IP mask %pI4 from environment\n", &drv_glb->ipMask);
201                 debug("got gateway address %pI4 from environment\n", &drv_glb->ipGate);
202 #endif
203                 /* EDBG services config */
204                 memcpy(&drv_glb->edbgConfig, &bin->edbgConfig,
205                         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                                 debug("ePhysAddr=%p physlen=%08x parselen=%08x\n",
330                                         bin->ePhysAddr, bin->ePhysLen, bin->parseLen);
331                                 if (bin->ePhysAddr) {
332                                         copyLen = CE_MIN(bin->ePhysLen - bin->parseLen, len);
333                                         bin->parseLen += copyLen;
334                                         len -= copyLen;
335
336                                         while (copyLen--) {
337                                                 bin->parseChkSum += *pbData;
338                                                 *bin->parsePtr++ = *pbData++;
339                                         }
340
341                                         if (bin->parseLen == bin->ePhysLen) {
342                                                 printf("Section [%02d]: address %p, size 0x%08X, checksum %s\n",
343                                                         bin->section,
344                                                         bin->ePhysAddr,
345                                                         bin->ePhysLen,
346                                                         (bin->eChkSum == bin->parseChkSum) ? "ok" : "fail");
347
348                                                 if (bin->eChkSum != bin->parseChkSum) {
349                                                         printf("Error: Checksum error, corrupted .BIN file!\n");
350                                                         printf("checksum calculated: 0x%08x from file: 0x%08x\n",
351                                                                 bin->parseChkSum, bin->eChkSum);
352                                                         bin->binLen = 0;
353                                                         return CE_PR_ERROR;
354                                                 }
355
356                                                 bin->section++;
357                                                 bin->parseState = CE_PS_E_ADDR;
358                                                 bin->parseLen = 0;
359                                                 bin->parsePtr = (unsigned char *)&bin->ePhysAddr;
360                                         }
361                                 } else {
362                                         bin->parseLen = 0;
363                                         bin->endOfBin = 1;
364                                         len = 0;
365                                 }
366                                 break;
367                         }
368                 }
369         }
370
371         if (bin->endOfBin) {
372                 if (!ce_lookup_ep_bin(bin)) {
373                         printf("Error: entry point not found!\n");
374                         bin->binLen = 0;
375                         return CE_PR_ERROR;
376                 }
377
378                 printf("Entry point: %p, address range: %p-%p\n",
379                         bin->eEntryPoint,
380                         bin->rtiPhysAddr,
381                         bin->rtiPhysAddr + bin->rtiPhysLen);
382
383                 return CE_PR_EOF;
384         }
385
386         /* Need more data */
387         bin->binLen += bin->dataLen;
388         return CE_PR_MORE;
389 }
390
391 static int ce_bin_load(void *image, int imglen)
392 {
393         ce_init_bin(&g_bin, image);
394         g_bin.dataLen = imglen;
395         if (ce_parse_bin(&g_bin) == CE_PR_EOF) {
396                 ce_prepare_run_bin(&g_bin);
397                 return 1;
398         }
399
400         return 0;
401 }
402
403 static void ce_run_bin(void (*entry)(void))
404 {
405         printf("Launching Windows CE ...\n");
406 #ifdef TEST_LAUNCH
407 return;
408 #endif
409         entry();
410 }
411
412 static int do_bootce(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
413 {
414         void *addr;
415         size_t image_size;
416
417         if (argc > 1) {
418                 addr = (void *)simple_strtoul(argv[1], NULL, 16);
419                 image_size = INT_MAX;           /* actually we do not know the image size */
420         } else if (getenv("fileaddr") != NULL) {
421                 addr = (void *)getenv_ulong("fileaddr", 16, 0);
422                 image_size = getenv_ulong("filesize", 16, INT_MAX);
423         } else {
424                 return CMD_RET_USAGE;
425         }
426
427         printf ("## Booting Windows CE Image from address %p ...\n", addr);
428
429         /* check if there is a valid windows CE image */
430         if (ce_is_bin_image(addr, image_size)) {
431                 if (!ce_bin_load(addr, image_size)) {
432                         /* Ops! Corrupted .BIN image! */
433                         /* Handle error here ...      */
434                         printf("corrupted .BIN image !!!\n");
435                         return CMD_RET_FAILURE;
436                 }
437                 if (getenv_yesno("autostart") != 1) {
438                         /*
439                          * just use bootce to load the image to SDRAM;
440                          * Do not start it automatically.
441                          */
442                         setenv_addr("fileaddr", g_bin.eEntryPoint);
443                         return CMD_RET_SUCCESS;
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 CMD_RET_FAILURE;
449         }
450         return CMD_RET_FAILURE; /* never reached - just to keep compiler happy */
451 }
452 U_BOOT_CMD(
453         bootce, 2, 0, do_bootce,
454         "bootce [addr]\t- Boot a Windows CE image from memory\n",
455         "[args..]\n"
456         "\taddr\t\t-boot image from address addr\n"
457 );
458
459 static int ce_send_write_ack(ce_net *net)
460 {
461         int ret;
462         unsigned short wdata[2];
463         int retries = 0;
464
465         wdata[0] = htons(EDBG_CMD_WRITE_ACK);
466         wdata[1] = htons(net->blockNum);
467         net->dataLen = sizeof(wdata);
468         memcpy(net->data, wdata, net->dataLen);
469
470         do {
471                 ret = bootme_send_frame(net->data, net->dataLen);
472                 if (ret) {
473                         printf("Failed to send write ack %d; retries=%d\n",
474                                 ret, retries);
475                 }
476         } while (ret != 0 && retries-- > 0);
477         return ret;
478 }
479
480 static enum bootme_state ce_process_download(ce_net *net, ce_bin *bin)
481 {
482         int ret = net->state;
483
484         if (net->dataLen >= 4) {
485                 unsigned short command;
486                 unsigned short blknum;
487
488                 memcpy(&command, net->data, sizeof(command));
489                 command = ntohs(command);
490                 debug("command found: 0x%04X\n", command);
491
492                 if (net->state == BOOTME_DOWNLOAD) {
493                         unsigned short nxt = net->blockNum + 1;
494
495                         memcpy(&blknum, &net->data[2], sizeof(blknum));
496                         blknum = ntohs(blknum);
497                         if (blknum == nxt) {
498                                 net->blockNum = blknum;
499                         } else {
500                                 int rc = ce_send_write_ack(net);
501
502                                 printf("Dropping out of sequence packet with ID %d (expected %d)\n",
503                                         blknum, nxt);
504                                 if (rc != 0)
505                                         return rc;
506
507                                 return ret;
508                         }
509                 }
510
511                 switch (command) {
512                 case EDBG_CMD_WRITE_REQ:
513                         if (net->state == BOOTME_INIT) {
514                                 // Check file name for WRITE request
515                                 // CE EShell uses "boot.bin" file name
516                                 if (strncmp((char *)&net->data[2],
517                                                 "boot.bin", 8) == 0) {
518                                         // Some diag output
519                                         if (net->verbose) {
520                                                 printf("Locked Down download link, IP: %pI4\n",
521                                                         &NetServerIP);
522                                                 printf("Sending BOOTME request [%d] to %pI4\n",
523                                                         net->seqNum, &NetServerIP);
524                                         }
525
526                                         // Lock down EShell download link
527                                         ret = BOOTME_DOWNLOAD;
528                                 } else {
529                                         // Unknown link
530                                         printf("Unknown link\n");
531                                 }
532
533                                 if (ret == BOOTME_DOWNLOAD) {
534                                         int rc = ce_send_write_ack(net);
535                                         if (rc != 0)
536                                                 return rc;
537                                 }
538                         }
539                         break;
540
541                 case EDBG_CMD_WRITE:
542                         /* Fixup data len */
543                         bin->data = &net->data[4];
544                         bin->dataLen = net->dataLen - 4;
545                         ret = ce_parse_bin(bin);
546                         if (ret != CE_PR_ERROR) {
547                                 int rc = ce_send_write_ack(net);
548                                 if (rc)
549                                         return rc;
550                                 if (ret == CE_PR_EOF)
551                                         ret = BOOTME_DONE;
552                         } else {
553                                 ret = BOOTME_ERROR;
554                         }
555                         break;
556
557                 case EDBG_CMD_READ_REQ:
558                         printf("Ignoring EDBG_CMD_READ_REQ\n");
559                         /* Read requests are not supported
560                          * Do nothing ...
561                          */
562                         break;
563
564                 case EDBG_CMD_ERROR:
565                         printf("Error: unknown error on the host side\n");
566
567                         bin->binLen = 0;
568                         ret = BOOTME_ERROR;
569                         break;
570
571                 default:
572                         printf("unknown command 0x%04X\n", command);
573                         net->state = BOOTME_ERROR;
574                 }
575         }
576         return ret;
577 }
578
579 static enum bootme_state ce_process_edbg(ce_net *net, ce_bin *bin)
580 {
581         enum bootme_state ret = net->state;
582         eth_dbg_hdr header;
583
584         if (net->dataLen < sizeof(header)) {
585                 /* Bad packet */
586                 printf("Invalid packet size %u\n", net->dataLen);
587                 net->dataLen = 0;
588                 return ret;
589         }
590         memcpy(&header, net->data, sizeof(header));
591         if (header.id != EDBG_ID) {
592                 /* Bad packet */
593                 printf("Bad EDBG ID %08x\n", header.id);
594                 net->dataLen = 0;
595                 return ret;
596         }
597
598         if (header.service != EDBG_SVC_ADMIN) {
599                 /* Unknown service */
600                 printf("Bad EDBG service %02x\n", header.service);
601                 net->dataLen = 0;
602                 return ret;
603         }
604
605         if (net->state == BOOTME_INIT) {
606                 /* Some diag output */
607                 if (net->verbose) {
608                         printf("Locked Down EDBG service link, IP: %pI4\n",
609                                 &NetServerIP);
610                 }
611
612                 /* Lock down EDBG link */
613                 net->state = BOOTME_DEBUG;
614         }
615
616 debug("%s@%d\n", __func__, __LINE__);
617         switch (header.cmd) {
618         case EDBG_CMD_JUMPIMG:
619 debug("%s@%d\n", __func__, __LINE__);
620                 net->gotJumpingRequest = 1;
621
622                 if (net->verbose) {
623                         printf("Received JUMPING command\n");
624                 }
625                 /* Just pass through and copy CONFIG structure */
626         case EDBG_CMD_OS_CONFIG:
627 debug("%s@%d\n", __func__, __LINE__);
628                 /* Copy config structure */
629                 memcpy(&bin->edbgConfig, header.data,
630                         sizeof(edbg_os_config_data));
631                 if (net->verbose) {
632                         printf("Received CONFIG command\n");
633                         if (bin->edbgConfig.flags & EDBG_FL_DBGMSG) {
634                                 printf("--> Enabling DBGMSG service, IP: %d.%d.%d.%d, port: %d\n",
635                                         (bin->edbgConfig.dbgMsgIPAddr >> 0) & 0xFF,
636                                         (bin->edbgConfig.dbgMsgIPAddr >> 8) & 0xFF,
637                                         (bin->edbgConfig.dbgMsgIPAddr >> 16) & 0xFF,
638                                         (bin->edbgConfig.dbgMsgIPAddr >> 24) & 0xFF,
639                                         ntohs(bin->edbgConfig.dbgMsgPort));
640                         }
641
642                         if (bin->edbgConfig.flags & EDBG_FL_PPSH) {
643                                 printf("--> Enabling PPSH service, IP: %d.%d.%d.%d, port: %d\n",
644                                         (bin->edbgConfig.ppshIPAddr >> 0) & 0xFF,
645                                         (bin->edbgConfig.ppshIPAddr >> 8) & 0xFF,
646                                         (bin->edbgConfig.ppshIPAddr >> 16) & 0xFF,
647                                         (bin->edbgConfig.ppshIPAddr >> 24) & 0xFF,
648                                         ntohs(bin->edbgConfig.ppshPort));
649                         }
650
651                         if (bin->edbgConfig.flags & EDBG_FL_KDBG) {
652                                 printf("--> Enabling KDBG service, IP: %d.%d.%d.%d, port: %d\n",
653                                         (bin->edbgConfig.kdbgIPAddr >> 0) & 0xFF,
654                                         (bin->edbgConfig.kdbgIPAddr >> 8) & 0xFF,
655                                         (bin->edbgConfig.kdbgIPAddr >> 16) & 0xFF,
656                                         (bin->edbgConfig.kdbgIPAddr >> 24) & 0xFF,
657                                         ntohs(bin->edbgConfig.kdbgPort));
658                         }
659
660                         if (bin->edbgConfig.flags & EDBG_FL_CLEANBOOT) {
661                                 printf("--> Force clean boot\n");
662                         }
663                 }
664                 ret = BOOTME_DEBUG;
665                 break;
666
667         default:
668                 if (net->verbose) {
669                         printf("Received unknown command: %08X\n", header.cmd);
670                 }
671                 return BOOTME_ERROR;
672         }
673
674         /* Respond with ack */
675         header.flags = EDBG_FL_FROM_DEV | EDBG_FL_ACK;
676         net->dataLen = EDBG_DATA_OFFSET;
677 debug("%s@%d: sending packet %p len %u\n", __func__, __LINE__,
678         net->data, net->dataLen);
679         bootme_send_frame(net->data, net->dataLen);
680         return ret;
681 }
682
683 static enum bootme_state ce_edbg_handler(const void *buf, size_t len)
684 {
685         if (len == 0)
686                 return BOOTME_DONE;
687
688         g_net.data = (void *)buf;
689         g_net.dataLen = len;
690
691         return ce_process_edbg(&g_net, &g_bin);
692 }
693
694 static void ce_init_edbg_link(ce_net *net)
695 {
696         /* Initialize EDBG link for commands */
697         net->state = BOOTME_INIT;
698 }
699
700 static enum bootme_state ce_download_handler(const void *buf, size_t len)
701 {
702         g_net.data = (void *)buf;
703         g_net.dataLen = len;
704
705         g_net.state = ce_process_download(&g_net, &g_bin);
706         return g_net.state;
707 }
708
709 static int ce_send_bootme(ce_net *net)
710 {
711         eth_dbg_hdr *header;
712         edbg_bootme_data *data;
713         unsigned char txbuf[PKTSIZE_ALIGN];
714 #ifdef DEBUG
715         int     i;
716         unsigned char   *pkt;
717 #endif
718         /* Fill out BOOTME packet */
719         net->data = txbuf;
720
721         memset(net->data, 0, PKTSIZE);
722         header = (eth_dbg_hdr *)net->data;
723         data = (edbg_bootme_data *)header->data;
724
725         header->id = EDBG_ID;
726         header->service = EDBG_SVC_ADMIN;
727         header->flags = EDBG_FL_FROM_DEV;
728         header->seqNum = net->seqNum++;
729         header->cmd = EDBG_CMD_BOOTME;
730
731         data->versionMajor = 0;
732         data->versionMinor = 0;
733         data->cpuId = EDBG_CPU_TYPE_ARM;
734         data->bootmeVer = EDBG_CURRENT_BOOTME_VERSION;
735         data->bootFlags = 0;
736         data->downloadPort = 0;
737         data->svcPort = 0;
738
739         /* MAC address from environment*/
740         if (!eth_getenv_enetaddr("ethaddr", data->macAddr)) {
741                 printf("'ethaddr' is not set or invalid\n");
742                 memset(data->macAddr, 0, sizeof(data->macAddr));
743         }
744
745         /* IP address from active config */
746         NetCopyIP(&data->ipAddr, &NetOurIP);
747
748         // Device name string (NULL terminated). Should include
749         // platform and number based on Ether address (e.g. Odo42, CEPCLS2346, etc)
750
751         // We will use lower MAC address segment to create device name
752         // eg. MAC '00-0C-C6-69-09-05', device name 'Triton05'
753
754         strncpy(data->platformId, "Triton", sizeof(data->platformId));
755         snprintf(data->deviceName, sizeof(data->deviceName), "%s%02X",
756                 data->platformId, data->macAddr[5]);
757
758 #ifdef DEBUG
759         printf("header->id: %08X\r\n", header->id);
760         printf("header->service: %08X\r\n", header->service);
761         printf("header->flags: %08X\r\n", header->flags);
762         printf("header->seqNum: %08X\r\n", header->seqNum);
763         printf("header->cmd: %08X\r\n\r\n", header->cmd);
764
765         printf("data->versionMajor: %08X\r\n", data->versionMajor);
766         printf("data->versionMinor: %08X\r\n", data->versionMinor);
767         printf("data->cpuId: %08X\r\n", data->cpuId);
768         printf("data->bootmeVer: %08X\r\n", data->bootmeVer);
769         printf("data->bootFlags: %08X\r\n", data->bootFlags);
770         printf("data->svcPort: %08X\r\n\r\n", ntohs(data->svcPort));
771
772         printf("data->macAddr: %02X-%02X-%02X-%02X-%02X-%02X\r\n",
773                 data->macAddr[0], data->macAddr[1],
774                 data->macAddr[2], data->macAddr[3],
775                 data->macAddr[4], data->macAddr[5]);
776
777         printf("data->ipAddr: %d.%d.%d.%d\r\n",
778                 (data->ipAddr >> 0) & 0xFF,
779                 (data->ipAddr >> 8) & 0xFF,
780                 (data->ipAddr >> 16) & 0xFF,
781                 (data->ipAddr >> 24) & 0xFF);
782
783         printf("data->platformId: %s\r\n", data->platformId);
784
785         printf("data->deviceName: %s\r\n", data->deviceName);
786 #endif
787         // Some diag output ...
788         if (net->verbose) {
789                 printf("Sending BOOTME request [%d] to %pI4\n", net->seqNum,
790                         &server_ip);
791         }
792
793         net->dataLen = BOOTME_PKT_SIZE;
794 //      net->status = CE_PR_MORE;
795         net->state = BOOTME_INIT;
796 #ifdef DEBUG
797         debug("Start of buffer:      %p\n", net->data);
798         debug("Start of ethernet buffer:   %p\n", net->data);
799         debug("Start of CE header:         %p\n", header);
800         debug("Start of CE data:           %p\n", data);
801
802         pkt = net->data;
803         debug("packet to send (ceconnect): \n");
804         for (i = 0; i < net->dataLen; i++) {
805                 debug("0x%02X ", pkt[i]);
806                 if (!((i + 1) % 16))
807                         debug("\n");
808         }
809         debug("\n");
810 #endif
811         return BootMeRequest(server_ip, net->data, net->dataLen, 1);
812 }
813
814 static inline int ce_init_download_link(ce_net *net, ce_bin *bin, int verbose)
815 {
816         if (!eth_get_dev()) {
817                 printf("No network interface available\n");
818                 return -ENODEV;
819         }
820         printf("Using device '%s'\n", eth_get_name());
821
822         /* Initialize EDBG link for download */
823         memset(net, 0, sizeof(*net));
824
825         net->verbose = verbose;
826
827         /* buffer will be dynamically assigned in ce_download_handler() */
828         ce_init_bin(bin, NULL);
829         return 0;
830 }
831
832 #define UINT_MAX ~0UL
833
834 static inline int ce_download_file(ce_net *net, ulong timeout)
835 {
836         ulong start = get_timer_masked();
837
838         while (net->state == BOOTME_INIT) {
839                 int ret;
840
841                 if (timeout && get_timer(start) > timeout) {
842                         printf("CELOAD - Canceled, timeout\n");
843                         return 1;
844                 }
845
846                 if (ctrlc()) {
847                         printf("CELOAD - canceled by user\n");
848                         return 1;
849                 }
850
851                 if (ce_send_bootme(&g_net)) {
852                         printf("CELOAD - error while sending BOOTME request\n");
853                         return 1;
854                 }
855                 if (net->verbose) {
856                         if (timeout) {
857                                 printf("Waiting for connection, timeout %lu sec\n",
858                                         DIV_ROUND_UP(timeout - get_timer(start),
859                                                 CONFIG_SYS_HZ));
860                         } else {
861                                 printf("Waiting for connection, enter ^C to abort\n");
862                         }
863                 }
864
865                 ret = BootMeDownload(ce_download_handler);
866                 if (ret == BOOTME_ERROR) {
867                         printf("CELOAD - aborted\n");
868                         return 1;
869                 }
870         }
871         return 0;
872 }
873
874 static void ce_disconnect(void)
875 {
876         net_set_udp_handler(NULL);
877         eth_halt();
878 }
879
880 static int do_ceconnect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
881 {
882         int verbose = 0;
883         ulong timeout = 0;
884         int ret = 1;
885         int i;
886
887         server_ip = 0;
888
889         for (i = 1; i < argc; i++){
890                 if (*argv[i] != '-')
891                         break;
892                 if (argv[i][1] == 'v') {
893                         verbose = 1;
894                 } else if (argv[i][1] == 't') {
895                         i++;
896                         if (argc > i) {
897                                 timeout = simple_strtoul(argv[i],
898                                                         NULL, 10);
899                                 if (timeout >= UINT_MAX / CONFIG_SYS_HZ) {
900                                         printf("Timeout value %lu out of range (max.: %lu)\n",
901                                                 timeout, UINT_MAX / CONFIG_SYS_HZ - 1);
902                                         return CMD_RET_USAGE;
903                                 }
904                                 timeout *= CONFIG_SYS_HZ;
905                         } else {
906                                 printf("Option requires an argument - t\n");
907                                 return CMD_RET_USAGE;
908                         }
909                 } else if (argv[i][1] == 'h') {
910                         i++;
911                         if (argc > i) {
912                                 server_ip = string_to_ip(argv[i]);
913                                 printf("Using server %pI4\n", &server_ip);
914                         } else {
915                                 printf("Option requires an argument - t\n");
916                                 return CMD_RET_USAGE;
917                         }
918                 }
919         }
920
921         if (ce_init_download_link(&g_net, &g_bin, verbose) != 0)
922                 goto err;
923
924         if (ce_download_file(&g_net, timeout))
925                 goto err;
926
927         if (g_bin.binLen) {
928                 // Try to receive edbg commands from host
929                 ce_init_edbg_link(&g_net);
930                 if (verbose)
931                         printf("Waiting for EDBG commands ...\n");
932
933                 ret = BootMeDebugStart(ce_edbg_handler);
934                 if (ret != BOOTME_DONE)
935                         goto err;
936
937                 // Prepare WinCE image for execution
938                 ce_prepare_run_bin(&g_bin);
939
940                 // Launch WinCE, if necessary
941                 if (g_net.gotJumpingRequest)
942                         ce_run_bin(g_bin.eEntryPoint);
943         }
944         ret = 0;
945 err:
946         ce_disconnect();
947         return ret == 0 ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
948 }
949 U_BOOT_CMD(
950         ceconnect, 6, 1, do_ceconnect,
951         "Set up a connection to the CE host PC over TCP/IP and download the run-time image\n",
952         "[-v] [-t <timeout>] [-h host]\n"
953         "  -v            - verbose operation\n"
954         "  -t <timeout>  - max wait time (#sec) for the connection\n"
955         "  -h <host>     - send BOOTME requests to <host> (default: broadcast address 255.255.255.255)"
956 );