blob: 19ead331b878cc2a100e4337ff3530e9f09b828a [file] [log] [blame]
wdenkc6097192002-11-03 00:24:07 +00001/*
2 * (C) Copyright 2001
3 * Denis Peter, MPL AG Switzerland, d.peter@mpl.ch
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
25#include <common.h>
26#include <command.h>
27#include <video_fb.h>
28#include "common_util.h"
29#include <asm/processor.h>
wdenk1cb8e982003-03-06 21:55:29 +000030#include <asm/byteorder.h>
wdenkc6097192002-11-03 00:24:07 +000031#include <i2c.h>
32#include <devices.h>
33#include <pci.h>
34
35extern int gunzip (void *, int, unsigned char *, int *);
36extern int mem_test(unsigned long start, unsigned long ramsize, int quiet);
37
38#define I2C_BACKUP_ADDR 0x7C00 /* 0x200 bytes for backup */
39#define IMAGE_SIZE 0x80000
40
41extern flash_info_t flash_info[]; /* info for FLASH chips */
42
wdenk1cb8e982003-03-06 21:55:29 +000043static image_header_t header;
wdenkc6097192002-11-03 00:24:07 +000044
45
46
47int mpl_prg(unsigned long src,unsigned long size)
48{
49 unsigned long start;
50 flash_info_t *info;
51 int i,rc;
wdenk06d01db2003-03-14 20:47:52 +000052#if defined(CONFIG_PIP405) || defined(CONFIG_MIP405)
wdenkc6097192002-11-03 00:24:07 +000053 unsigned long *magic = (unsigned long *)src;
wdenk06d01db2003-03-14 20:47:52 +000054#endif
wdenkc6097192002-11-03 00:24:07 +000055
56 info = &flash_info[0];
wdenk1cb8e982003-03-06 21:55:29 +000057
58#if defined(CONFIG_PIP405) || defined(CONFIG_MIP405)
59 if(ntohl(magic[0]) != IH_MAGIC) {
60 printf("Bad Magic number\n");
61 return -1;
62 }
63
wdenkc6097192002-11-03 00:24:07 +000064 start = 0 - size;
65 for(i=info->sector_count-1;i>0;i--)
66 {
67 info->protect[i] = 0; /* unprotect this sector */
68 if(start>=info->start[i])
69 break;
70 }
71 /* set-up flash location */
72 /* now erase flash */
wdenkc6097192002-11-03 00:24:07 +000073 printf("Erasing at %lx (sector %d) (start %lx)\n",
74 start,i,info->start[i]);
75 flash_erase (info, i, info->sector_count-1);
wdenk1cb8e982003-03-06 21:55:29 +000076
77#elif defined(CONFIG_VCMA9)
78 start = 0;
79 for (i = 0; i <info->sector_count; i++)
80 {
81 info->protect[i] = 0; /* unprotect this sector */
82 if (size < info->start[i])
83 break;
84 }
85 /* set-up flash location */
86 /* now erase flash */
87 printf("Erasing at %lx (sector %d) (start %lx)\n",
88 start,0,info->start[0]);
89 flash_erase (info, 0, i);
90
91#endif
wdenkc6097192002-11-03 00:24:07 +000092 printf("flash erased, programming from 0x%lx 0x%lx Bytes\n",src,size);
93 if ((rc = flash_write ((uchar *)src, start, size)) != 0) {
94 puts ("ERROR ");
95 flash_perror (rc);
96 return (1);
97 }
98 puts ("OK programming done\n");
99 return 0;
100}
101
102
103int mpl_prg_image(unsigned long ld_addr)
104{
105 unsigned long data,len,checksum;
106 image_header_t *hdr=&header;
107 /* Copy header so we can blank CRC field for re-calculation */
108 memcpy (&header, (char *)ld_addr, sizeof(image_header_t));
wdenk1cb8e982003-03-06 21:55:29 +0000109 if (ntohl(hdr->ih_magic) != IH_MAGIC) {
wdenkc6097192002-11-03 00:24:07 +0000110 printf ("Bad Magic Number\n");
111 return 1;
112 }
113 print_image_hdr(hdr);
114 if (hdr->ih_os != IH_OS_U_BOOT) {
115 printf ("No U-Boot Image\n");
116 return 1;
117 }
118 if (hdr->ih_type != IH_TYPE_FIRMWARE) {
119 printf ("No Firmware Image\n");
120 return 1;
121 }
122 data = (ulong)&header;
123 len = sizeof(image_header_t);
wdenk1cb8e982003-03-06 21:55:29 +0000124 checksum = ntohl(hdr->ih_hcrc);
wdenkc6097192002-11-03 00:24:07 +0000125 hdr->ih_hcrc = 0;
126 if (crc32 (0, (char *)data, len) != checksum) {
127 printf ("Bad Header Checksum\n");
128 return 1;
129 }
130 data = ld_addr + sizeof(image_header_t);
wdenk1cb8e982003-03-06 21:55:29 +0000131 len = ntohl(hdr->ih_size);
wdenkc6097192002-11-03 00:24:07 +0000132 printf ("Verifying Checksum ... ");
wdenk1cb8e982003-03-06 21:55:29 +0000133 if (crc32 (0, (char *)data, len) != ntohl(hdr->ih_dcrc)) {
wdenkc6097192002-11-03 00:24:07 +0000134 printf ("Bad Data CRC\n");
135 return 1;
136 }
137 switch (hdr->ih_comp) {
138 case IH_COMP_NONE:
139 break;
140 case IH_COMP_GZIP:
141 printf (" Uncompressing ... ");
142 if (gunzip ((void *)(data+0x100000), 0x400000,
143 (uchar *)data, (int *)&len) != 0) {
144 printf ("GUNZIP ERROR\n");
145 return 1;
146 }
147 data+=0x100000;
148 break;
149 default:
150 printf (" Unimplemented compression type %d\n", hdr->ih_comp);
151 return 1;
152 }
153
154 printf (" OK\n");
155 return(mpl_prg(data,len));
156}
157
158
159void get_backup_values(backup_t *buf)
160{
161 i2c_read(CFG_DEF_EEPROM_ADDR, I2C_BACKUP_ADDR,2,(void *)buf,sizeof(backup_t));
162}
163
164void set_backup_values(int overwrite)
165{
166 backup_t back;
167 int i;
168
169 get_backup_values(&back);
170 if(!overwrite) {
171 if(strncmp(back.signature,"MPL\0",4)==0) {
172 printf("Not possible to write Backup\n");
173 return;
174 }
175 }
176 memcpy(back.signature,"MPL\0",4);
wdenk1cb8e982003-03-06 21:55:29 +0000177 i = getenv_r("serial#",back.serial_name,16);
178 if(i < 0) {
wdenkc6097192002-11-03 00:24:07 +0000179 printf("Not possible to write Backup\n");
180 return;
181 }
182 back.serial_name[16]=0;
wdenk1cb8e982003-03-06 21:55:29 +0000183 i = getenv_r("ethaddr",back.eth_addr,20);
184 if(i < 0) {
wdenkc6097192002-11-03 00:24:07 +0000185 printf("Not possible to write Backup\n");
186 return;
187 }
188 back.eth_addr[20]=0;
189 i2c_write(CFG_DEF_EEPROM_ADDR, I2C_BACKUP_ADDR,2,(void *)&back,sizeof(backup_t));
190}
191
192void clear_env_values(void)
193{
194 backup_t back;
195 unsigned char env_crc[4];
196
197 memset(&back,0xff,sizeof(backup_t));
198 memset(env_crc,0x00,4);
199 i2c_write(CFG_DEF_EEPROM_ADDR,I2C_BACKUP_ADDR,2,(void *)&back,sizeof(backup_t));
200 i2c_write(CFG_DEF_EEPROM_ADDR,CFG_ENV_OFFSET,2,(void *)env_crc,4);
201}
202
203/*
204 * check crc of "older" environment
205 */
206int check_env_old_size(ulong oldsize)
207{
208 ulong crc, len, new;
209 unsigned off;
210 uchar buf[64];
211
212 /* read old CRC */
213 eeprom_read (CFG_DEF_EEPROM_ADDR,
214 CFG_ENV_OFFSET,
215 (uchar *)&crc, sizeof(ulong));
216
217 new = 0;
218 len = oldsize;
219 off = sizeof(long);
220 len = oldsize-off;
221 while (len > 0) {
222 int n = (len > sizeof(buf)) ? sizeof(buf) : len;
223
224 eeprom_read (CFG_DEF_EEPROM_ADDR, CFG_ENV_OFFSET+off, buf, n);
225 new = crc32 (new, buf, n);
226 len -= n;
227 off += n;
228 }
229
230 return (crc == new);
231}
232
233static ulong oldsizes[] = {
234 0x200,
235 0x800,
236 0
237};
238
239void copy_old_env(ulong size)
240{
241 uchar name_buf[64];
242 uchar value_buf[0x800];
243 uchar c;
244 ulong len;
245 unsigned off;
246 uchar *name, *value;
247
248 name=&name_buf[0];
249 value=&value_buf[0];
250 len=size;
251 off = sizeof(long);
252 while (len > off) {
253 eeprom_read (CFG_DEF_EEPROM_ADDR, CFG_ENV_OFFSET+off, &c, 1);
254 if(c != '=') {
255 *name++=c;
256 off++;
257 }
258 else {
259 *name++='\0';
260 off++;
261 do {
262 eeprom_read (CFG_DEF_EEPROM_ADDR, CFG_ENV_OFFSET+off, &c, 1);
263 *value++=c;
264 off++;
265 if(c == '\0')
266 break;
267 } while(len > off);
268 name=&name_buf[0];
269 value=&value_buf[0];
270 if(strncmp(name,"baudrate",8)!=0) {
271 setenv(name,value);
272 }
273
274 }
275 }
276}
277
278
279void check_env(void)
280{
281 unsigned char *s;
282 int i=0;
283 char buf[32];
284 backup_t back;
285
286 s=getenv("serial#");
287 if(!s) {
288 while(oldsizes[i]) {
289 if(check_env_old_size(oldsizes[i]))
290 break;
291 i++;
292 }
293 if(!oldsizes[i]) {
294 /* no old environment has been found */
295 get_backup_values (&back);
296 if (strncmp (back.signature, "MPL\0", 4) == 0) {
297 sprintf (buf, "%s", back.serial_name);
298 setenv ("serial#", buf);
299 sprintf (buf, "%s", back.eth_addr);
300 setenv ("ethaddr", buf);
301 printf ("INFO: serial# and ethaddr recovered, use saveenv\n");
302 return;
303 }
304 }
305 else {
306 copy_old_env(oldsizes[i]);
307 printf ("INFO: old environment ajusted, use saveenv\n");
308 }
309 }
310 else {
311 /* check if back up is set */
312 get_backup_values(&back);
313 if(strncmp(back.signature,"MPL\0",4)!=0) {
314 set_backup_values(0);
315 }
316 }
317}
318
319
320
321extern device_t *stdio_devices[];
322extern char *stdio_names[];
323
324void show_stdio_dev(void)
325{
wdenk47cd00f2003-03-06 13:39:27 +0000326 /* Print information */
wdenkc6097192002-11-03 00:24:07 +0000327 printf ("In: ");
328 if (stdio_devices[stdin] == NULL) {
329 printf ("No input devices available!\n");
330 } else {
331 printf ("%s\n", stdio_devices[stdin]->name);
332 }
333
334 printf ("Out: ");
335 if (stdio_devices[stdout] == NULL) {
336 printf ("No output devices available!\n");
337 } else {
338 printf ("%s\n", stdio_devices[stdout]->name);
339 }
340
341 printf ("Err: ");
342 if (stdio_devices[stderr] == NULL) {
343 printf ("No error devices available!\n");
344 } else {
345 printf ("%s\n", stdio_devices[stderr]->name);
346 }
347}
348
349/* ------------------------------------------------------------------------- */
350
351 /* switches the cs0 and the cs1 to the locations.
352 When boot is TRUE, the the mapping is switched
353 to the boot configuration, If it is FALSE, the
354 flash will be switched in the boot area */
355
356#undef SW_CS_DBG
357#ifdef SW_CS_DBG
358#define SW_CS_PRINTF(fmt,args...) printf (fmt ,##args)
359#else
360#define SW_CS_PRINTF(fmt,args...)
361#endif
362
wdenk1cb8e982003-03-06 21:55:29 +0000363#if defined(CONFIG_PIP405) || defined(CONFIG_MIP405)
wdenkc6097192002-11-03 00:24:07 +0000364int switch_cs(unsigned char boot)
365{
366 unsigned long pbcr;
367 mtdcr(ebccfga, pb0cr); /* get cs0 config reg */
368 pbcr = mfdcr(ebccfgd);
369 if((pbcr&0x00002000)==0) {
370 /* we need only to switch if boot from MPS */
371 /*printf(" MPS boot mode detected. ");*/
372 /* printf("cs0 cfg: %lx\n",pbcr); */
373 if(boot) {
374 /* switch to boot configuration */
375 /* this is a 8bit boot, switch cs0 to flash location */
376 SW_CS_PRINTF("switch to boot mode (MPS on High address\n");
377 pbcr&=0x000FFFFF; /*mask base address of the cs0 */
378 pbcr|=(FLASH_BASE0_PRELIM & 0xFFF00000);
379 mtdcr(ebccfga, pb0cr);
380 mtdcr(ebccfgd, pbcr);
381 SW_CS_PRINTF(" new cs0 cfg: %lx\n",pbcr);
382 mtdcr(ebccfga, pb1cr); /* get cs1 config reg (flash) */
383 pbcr = mfdcr(ebccfgd);
384 SW_CS_PRINTF(" old cs1 cfg: %lx\n",pbcr);
385 pbcr&=0x000FFFFF; /*mask base address of the cs1 */
386 pbcr|=(MULTI_PURPOSE_SOCKET_ADDR & 0xFFF00000);
387 mtdcr(ebccfga, pb1cr);
388 mtdcr(ebccfgd, pbcr);
389 SW_CS_PRINTF(" new cs1 cfg: %lx, MPS is on High Address\n",pbcr);
390 }
391 else
392 {
393 /* map flash to boot area, */
394 SW_CS_PRINTF("map Flash to boot area\n");
395 pbcr&=0x000FFFFF; /*mask base address of the cs0 */
396 pbcr|=(MULTI_PURPOSE_SOCKET_ADDR & 0xFFF00000);
397 mtdcr(ebccfga, pb0cr);
398 mtdcr(ebccfgd, pbcr);
399 SW_CS_PRINTF(" new cs0 cfg: %lx\n",pbcr);
400 mtdcr(ebccfga, pb1cr); /* get cs1 config reg (flash) */
401 pbcr = mfdcr(ebccfgd);
402 SW_CS_PRINTF(" cs1 cfg: %lx\n",pbcr);
403 pbcr&=0x000FFFFF; /*mask base address of the cs1 */
404 pbcr|=(FLASH_BASE0_PRELIM & 0xFFF00000);
405 mtdcr(ebccfga, pb1cr);
406 mtdcr(ebccfgd, pbcr);
407 SW_CS_PRINTF(" new cs1 cfg: %lx Flash is on High Address\n",pbcr);
408 }
409 return 1;
410 }
411 else {
412 SW_CS_PRINTF("Normal boot, no switching necessary\n");
413 return 0;
414 }
415}
wdenk1cb8e982003-03-06 21:55:29 +0000416#elif defined(CONFIG_VCMA9)
417int switch_cs(unsigned char boot)
418{
419 return 0;
420}
421#endif /* CONFIG_VCMA9 */
wdenkc6097192002-11-03 00:24:07 +0000422
423int do_mplcommon(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
424{
425 ulong size,src,ld_addr;
426 int result;
427 backup_t back;
428 char sw;
429 src = MULTI_PURPOSE_SOCKET_ADDR;
430 size = IMAGE_SIZE;
431
432 if (strcmp(argv[1], "flash") == 0)
433 {
434 sw = switch_cs(0); /* Switch flash to normal location */
435#if (CONFIG_COMMANDS & CFG_CMD_FDC)
436 if (strcmp(argv[2], "floppy") == 0) {
437 char *local_args[3];
438 extern int do_fdcboot (cmd_tbl_t *, int, int, char *[]);
439 printf ("\nupdating bootloader image from floppy\n");
440 local_args[0] = argv[0];
441 if(argc==4) {
442 local_args[1] = argv[3];
443 local_args[2] = NULL;
444 ld_addr=simple_strtoul(argv[3], NULL, 16);
445 result=do_fdcboot(cmdtp, 0, 2, local_args);
446 }
447 else {
448 local_args[1] = NULL;
449 ld_addr=CFG_LOAD_ADDR;
450 result=do_fdcboot(cmdtp, 0, 1, local_args);
451 }
452 result=mpl_prg_image(ld_addr);
453 switch_cs(sw); /* Switch flash back */
454 return result;
455 }
456#endif /* (CONFIG_COMMANDS & CFG_CMD_FDC) */
457 if (strcmp(argv[2], "mem") == 0) {
458 if(argc==4) {
459 ld_addr=simple_strtoul(argv[3], NULL, 16);
460 }
461 else {
462 ld_addr=load_addr;
463 }
464 printf ("\nupdating bootloader image from memory at %lX\n",ld_addr);
465 result=mpl_prg_image(ld_addr);
466 switch_cs(sw); /* Switch flash back */
467 return result;
468 }
469 if (strcmp(argv[2], "mps") == 0) {
470 printf ("\nupdating bootloader image from MSP\n");
471 result=mpl_prg(src,size);
472 switch_cs(sw); /* Switch flash back */
473 return result;
474 }
475 switch_cs(sw); /* Switch flash back */
476
477 }
478 if (strcmp(argv[1], "mem") == 0)
479 {
480 result=0;
481 if(argc==3)
482 {
483 result = (int)simple_strtol(argv[2], NULL, 16);
484 }
485 src=(unsigned long)&result;
486 src-=CFG_MEMTEST_START;
487 src-=(100*1024); /* - 100k */
488 src&=0xfff00000;
489 size=0;
490 do {
491 size++;
492 printf("\n\nPass %ld\n",size);
493 mem_test(CFG_MEMTEST_START,src,1);
494 if(ctrlc())
495 break;
496 if(result>0)
497 result--;
498
499 }while(result);
500 return 0;
501 }
502 if (strcmp(argv[1], "clearenvvalues") == 0)
503 {
504 if (strcmp(argv[2], "yes") == 0)
505 {
506 clear_env_values();
507 return 0;
508 }
509 }
510 if (strcmp(argv[1], "getback") == 0) {
511 get_backup_values(&back);
512 back.signature[3]=0;
513 back.serial_name[16]=0;
514 back.eth_addr[20]=0;
515 printf("GetBackUp: signature: %s\n",back.signature);
516 printf(" serial#: %s\n",back.serial_name);
517 printf(" ethaddr: %s\n",back.eth_addr);
518 return 0;
519 }
520 if (strcmp(argv[1], "setback") == 0) {
521 set_backup_values(1);
522 return 0;
523 }
524 printf("Usage:\n%s\n", cmdtp->usage);
525 return 1;
526}
527
528
529#if (CONFIG_COMMANDS & CFG_CMD_DOC)
530extern void doc_probe(ulong physadr);
531void doc_init (void)
532{
533 doc_probe(MULTI_PURPOSE_SOCKET_ADDR);
534}
535#endif
536
537
538#ifdef CONFIG_VIDEO
539/******************************************************
540 * Routines to display the Board information
541 * to the screen (since the VGA will be initialized as last,
542 * we must resend the infos)
543 */
544
545#ifdef CONFIG_CONSOLE_EXTRA_INFO
546extern GraphicDevice ctfb;
547
548void video_get_info_str (int line_number, char *info)
549{
550 /* init video info strings for graphic console */
551 DECLARE_GLOBAL_DATA_PTR;
552 PPC405_SYS_INFO sys_info;
553 char rev;
554 int i;
555 unsigned long pvr;
556 char buf[64];
557 char tmp[16];
558 unsigned char *s, *e, bc, sw;
559 switch (line_number)
560 {
561 case 2:
562 /* CPU and board infos */
563 pvr=get_pvr();
564 get_sys_info (&sys_info);
565 switch (pvr) {
566 case PVR_405GP_RB: rev='B'; break;
567 case PVR_405GP_RC: rev='C'; break;
568 case PVR_405GP_RD: rev='D'; break;
569 case PVR_405GP_RE: rev='E'; break;
570 default: rev='?'; break;
571 }
572 /* Board info */
573 i=0;
574 s=getenv ("serial#");
575#ifdef CONFIG_PIP405
576 if (!s || strncmp (s, "PIP405", 6)) {
577 sprintf(buf,"### No HW ID - assuming PIP405");
578 }
579#endif
580#ifdef CONFIG_MIP405
581 if (!s || strncmp (s, "MIP405", 6)) {
582 sprintf(buf,"### No HW ID - assuming MIP405");
583 }
584#endif
585 else {
586 for (e = s; *e; ++e) {
587 if (*e == ' ')
588 break;
589 }
590 for (; s < e; ++s) {
591 if (*s == '_') {
592 ++s;
593 break;
594 }
595 buf[i++]=*s;
596 }
597 sprintf(&buf[i]," SN ");
598 i+=4;
599 for (; s < e; ++s) {
600 buf[i++]=*s;
601 }
602 buf[i++]=0;
603 }
604 sprintf (info," %s PPC405GP %c %s MHz (%lu/%lu/%lu MHz)",
605 buf,rev,
606 strmhz (tmp, gd->cpu_clk), sys_info.freqPLB / 1000000,
607 sys_info.freqPLB / sys_info.pllOpbDiv / 1000000,
608 sys_info.freqPLB / sys_info.pllExtBusDiv / 1000000);
609 return;
610 case 3:
611 /* Memory Info */
612 sw = switch_cs (0);
613 switch_cs (sw);
614 bc = in8 (CONFIG_PORT_ADDR);
615 sprintf(info, " %luMB RAM, %luMB Flash Cfg 0x%02X %s %s",
616 gd->bd->bi_memsize / 0x100000,
617 gd->bd->bi_flashsize / 0x100000,
618 bc,
619 sw ? "MPS boot" : "Flash boot",
620 ctfb.modeIdent);
621 return;
622 case 1:
623 sprintf (buf, "%s",CONFIG_IDENT_STRING);
624 sprintf (info, " %s", &buf[1]);
625 return;
626 }
627 /* no more info lines */
628 *info = 0;
629 return;
630}
631#endif /* CONFIG_CONSOLE_EXTRA_INFO */
632
633#endif /* CONFIG_VIDEO */