Patches by Murray Jensen, 17 Jun 2003:
[platform/kernel/u-boot.git] / board / hymod / eeprom.c
1 /*
2  * (C) Copyright 2001
3  * Murray Jensen, CSIRO-MIT, <Murray.Jensen@csiro.au>
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 <mpc8260.h>
26
27 /* imports from fetch.c */
28 extern int fetch_and_parse (char *, ulong, int (*)(uchar *, uchar *));
29
30 /* imports from input.c */
31 extern int hymod_get_serno (const char *);
32
33 /* this is relative to the root of the server's tftp directory */
34 static char *def_bddb_cfgdir = "/hymod/bddb";
35
36 static int
37 hymod_eeprom_load (int which, hymod_eeprom_t *ep)
38 {
39         unsigned dev_addr = CFG_I2C_EEPROM_ADDR | \
40                 (which ? HYMOD_EEOFF_MEZZ : HYMOD_EEOFF_MAIN);
41         unsigned offset = 0;
42         uchar data[HYMOD_EEPROM_SIZE], *dp, *edp;
43         hymod_eehdr_t *hp;
44         ulong len, crc;
45
46         memset (ep, 0, sizeof *ep);
47         memset (data, 0, HYMOD_EEPROM_SIZE);
48         crc = 0;
49
50         hp = (hymod_eehdr_t *)data;
51         eeprom_read (dev_addr, offset, (uchar *)hp, sizeof (*hp));
52         offset += sizeof (*hp);
53
54         if (hp->id != HYMOD_EEPROM_ID || hp->ver > HYMOD_EEPROM_VER ||
55           (len = hp->len) > HYMOD_EEPROM_MAXLEN)
56             return (0);
57
58         dp = (uchar *)(hp + 1); edp = dp + len;
59         eeprom_read (dev_addr, offset, dp, len);
60         offset += len;
61
62         eeprom_read (dev_addr, offset, (uchar *)&crc, sizeof (ulong));
63
64         if (crc32 (0, data, edp - data) != crc)
65                 return (0);
66
67         ep->ver = hp->ver;
68
69         for (;;) {
70                 hymod_eerec_t *rp = (hymod_eerec_t *)dp;
71                 ulong rtyp;
72                 uchar rlen, *rdat;
73                 uint rsiz;
74
75                 if (rp->small.topbit == 0) {
76                     rtyp = rp->small.type;
77                     rlen = rp->small.len;
78                     rdat = rp->small.data;
79                     rsiz = offsetof (hymod_eerec_t, small.data) + rlen;
80                 }
81                 else if (rp->medium.nxtbit == 0) {
82                     rtyp = rp->medium.type;
83                     rlen = rp->medium.len;
84                     rdat = rp->medium.data;
85                     rsiz = offsetof (hymod_eerec_t, medium.data) + rlen;
86                 }
87                 else {
88                     rtyp = rp->large.type;
89                     rlen = rp->large.len;
90                     rdat = rp->large.data;
91                     rsiz = offsetof (hymod_eerec_t, large.data) + rlen;
92                 }
93
94                 if (rtyp == 0)
95                         break;
96
97                 dp += rsiz;
98                 if (dp > edp)   /* error? */
99                         break;
100
101                 switch (rtyp) {
102
103                 case HYMOD_EEREC_SERNO:         /* serial number */
104                         if (rlen == sizeof (ulong))
105                                 memcpy (&ep->serno, rdat, sizeof (ulong));
106                         break;
107
108                 case HYMOD_EEREC_DATE:          /* date */
109                         if (rlen == sizeof (hymod_date_t))
110                                 memcpy (&ep->date, rdat, sizeof (hymod_date_t));
111                         break;
112
113                 case HYMOD_EEREC_BATCH:         /* batch */
114                         if (rlen <= HYMOD_MAX_BATCH)
115                                 memcpy (ep->batch, rdat, ep->batchlen = rlen);
116                         break;
117
118                 case HYMOD_EEREC_TYPE:          /* board type */
119                         if (rlen == 1)
120                                 ep->bdtype = *rdat;
121                         break;
122
123                 case HYMOD_EEREC_REV:           /* board revision */
124                         if (rlen == 1)
125                                 ep->bdrev = *rdat;
126                         break;
127
128                 case HYMOD_EEREC_SDRAM:         /* sdram size(s) */
129                         if (rlen > 0 && rlen <= HYMOD_MAX_SDRAM) {
130                                 int i;
131
132                                 for (i = 0; i < rlen; i++)
133                                         ep->sdramsz[i] = rdat[i];
134                                 ep->nsdram = rlen;
135                         }
136                         break;
137
138                 case HYMOD_EEREC_FLASH:         /* flash size(s) */
139                         if (rlen > 0 && rlen <= HYMOD_MAX_FLASH) {
140                                 int i;
141
142                                 for (i = 0; i < rlen; i++)
143                                         ep->flashsz[i] = rdat[i];
144                                 ep->nflash = rlen;
145                         }
146                         break;
147
148                 case HYMOD_EEREC_ZBT:           /* zbt ram size(s) */
149                         if (rlen > 0 && rlen <= HYMOD_MAX_ZBT) {
150                                 int i;
151
152                                 for (i = 0; i < rlen; i++)
153                                         ep->zbtsz[i] = rdat[i];
154                                 ep->nzbt = rlen;
155                         }
156                         break;
157
158                 case HYMOD_EEREC_XLXTYP:        /* xilinx fpga type(s) */
159                         if (rlen > 0 && rlen <= HYMOD_MAX_XLX) {
160                                 int i;
161
162                                 for (i = 0; i < rlen; i++)
163                                         ep->xlx[i].type = rdat[i];
164                                 ep->nxlx = rlen;
165                         }
166                         break;
167
168                 case HYMOD_EEREC_XLXSPD:        /* xilinx fpga speed(s) */
169                         if (rlen > 0 && rlen <= HYMOD_MAX_XLX) {
170                                 int i;
171
172                                 for (i = 0; i < rlen; i++)
173                                         ep->xlx[i].speed = rdat[i];
174                         }
175                         break;
176
177                 case HYMOD_EEREC_XLXTMP:        /* xilinx fpga temperature(s) */
178                         if (rlen > 0 && rlen <= HYMOD_MAX_XLX) {
179                                 int i;
180
181                                 for (i = 0; i < rlen; i++)
182                                         ep->xlx[i].temp = rdat[i];
183                         }
184                         break;
185
186                 case HYMOD_EEREC_XLXGRD:        /* xilinx fpga grade(s) */
187                         if (rlen > 0 && rlen <= HYMOD_MAX_XLX) {
188                                 int i;
189
190                                 for (i = 0; i < rlen; i++)
191                                         ep->xlx[i].grade = rdat[i];
192                         }
193                         break;
194
195                 case HYMOD_EEREC_CPUTYP:        /* CPU type */
196                         if (rlen == 1)
197                                 ep->mpc.type = *rdat;
198                         break;
199
200                 case HYMOD_EEREC_CPUSPD:        /* CPU speed */
201                         if (rlen == 1)
202                                 ep->mpc.cpuspd = *rdat;
203                         break;
204
205                 case HYMOD_EEREC_CPMSPD:        /* CPM speed */
206                         if (rlen == 1)
207                                 ep->mpc.cpmspd = *rdat;
208                         break;
209
210                 case HYMOD_EEREC_BUSSPD:        /* bus speed */
211                         if (rlen == 1)
212                                 ep->mpc.busspd = *rdat;
213                         break;
214
215                 case HYMOD_EEREC_HSTYPE:        /* hs-serial chip type */
216                         if (rlen == 1)
217                                 ep->hss.type = *rdat;
218                         break;
219
220                 case HYMOD_EEREC_HSCHIN:        /* num hs-serial input chans */
221                         if (rlen == 1)
222                                 ep->hss.nchin = *rdat;
223                         break;
224
225                 case HYMOD_EEREC_HSCHOUT:       /* num hs-serial output chans */
226                         if (rlen == 1)
227                                 ep->hss.nchout = *rdat;
228                         break;
229
230                 default:        /* ignore */
231                         break;
232                 }
233         }
234
235         return (1);
236 }
237
238 /* maps an ascii "name=value" into a binary eeprom data record */
239 typedef
240         struct _eerec_map {
241                 char *name;
242                 uint type;
243                 uchar *(*handler) \
244                         (struct _eerec_map *, uchar *, uchar *, uchar *);
245                 uint length;
246                 uint maxlen;
247         }
248 eerec_map_t;
249
250 static uchar *
251 uint_handler (eerec_map_t *rp, uchar *val, uchar *dp, uchar *edp)
252 {
253         uchar *eval;
254         union {
255                 uchar cval[4];
256                 ushort sval[2];
257                 ulong lval;
258         } rdata;
259
260         rdata.lval = simple_strtol (val, (char **)&eval, 10);
261
262         if (eval == val || *eval != '\0') {
263                 printf ("%s rec (%s) is not a valid uint\n",
264                         rp->name, val);
265                 return (NULL);
266         }
267
268         if (dp + 2 + rp->length > edp) {
269                 printf ("can't fit %s rec into eeprom\n", rp->name);
270                 return (NULL);
271         }
272
273         *dp++ = rp->type;
274         *dp++ = rp->length;
275
276         switch (rp->length) {
277
278         case 1:
279                 if (rdata.lval >= 256) {
280                         printf ("%s rec value (%lu) out of range (0-255)\n",
281                                 rp->name, rdata.lval);
282                         return (NULL);
283                 }
284                 *dp++ = rdata.cval[3];
285                 break;
286
287         case 2:
288                 if (rdata.lval >= 65536) {
289                         printf ("%s rec value (%lu) out of range (0-65535)\n",
290                                 rp->name, rdata.lval);
291                         return (NULL);
292                 }
293                 memcpy (dp, &rdata.sval[1], 2);
294                 dp += 2;
295                 break;
296
297         case 4:
298                 memcpy (dp, &rdata.lval, 4);
299                 dp += 4;
300                 break;
301
302         default:
303                 printf ("huh? rp->length not 1, 2 or 4! (%d)\n", rp->length);
304                 return (NULL);
305         }
306
307         return (dp);
308 }
309
310 static uchar *
311 date_handler (eerec_map_t *rp, uchar *val, uchar *dp, uchar *edp)
312 {
313         hymod_date_t date;
314         uchar *p = val, *ep;
315
316         date.year = simple_strtol (p, (char **)&ep, 10);
317         if (ep == p || *ep++ != '-') {
318 bad_date:
319                 printf ("%s rec (%s) is not a valid date\n", rp->name, val);
320                 return (NULL);
321         }
322
323         date.month = simple_strtol (p = ep, (char **)&ep, 10);
324         if (ep == p || *ep++ != '-' || date.month == 0 || date.month > 12)
325                 goto bad_date;
326
327         date.day = simple_strtol (p = ep, (char **)&ep, 10);
328         if (ep == p || *ep != '\0' || date.day == 0 || date.day > 31)
329                 goto bad_date;
330
331         if (dp + 2 + sizeof (hymod_date_t) > edp) {
332                 printf ("can't fit %s rec into eeprom\n", rp->name);
333                 return (NULL);
334         }
335
336         *dp++ = rp->type;
337         *dp++ = sizeof (hymod_date_t);
338         memcpy (dp, &date, sizeof (hymod_date_t));
339         dp += sizeof (hymod_date_t);
340
341         return (dp);
342 }
343
344 static uchar *
345 string_handler (eerec_map_t *rp, uchar *val, uchar *dp, uchar *edp)
346 {
347         uint len;
348
349         if ((len = strlen (val)) > rp->maxlen) {
350                 printf ("%s rec (%s) string is too long (%d>%d)\n",
351                         rp->name, val, len, rp->maxlen);
352                 return (NULL);
353         }
354
355         if (dp + 2 + len > edp) {
356                 printf ("can't fit %s rec into eeprom\n", rp->name);
357                 return (NULL);
358         }
359
360         *dp++ = rp->type;
361         *dp++ = len;
362         memcpy (dp, val, len);
363         dp += len;
364
365         return (dp);
366 }
367
368 static uchar *
369 bytes_handler (eerec_map_t *rp, uchar *val, uchar *dp, uchar *edp)
370 {
371         uchar bytes[HYMOD_MAX_BYTES], nbytes = 0;
372         uchar *p = val, *ep;
373
374         for (;;) {
375
376                 if (nbytes >= HYMOD_MAX_BYTES) {
377                         printf ("%s rec (%s) byte array too long\n",
378                                 rp->name, val);
379                         return (NULL);
380                 }
381
382                 bytes[nbytes++] = simple_strtol (p, (char **)&ep, 10);
383
384                 if (ep == p || (*ep != '\0' && *ep != ',')) {
385                         printf ("%s rec (%s) byte array has invalid uint\n",
386                                 rp->name, val);
387                         return (NULL);
388                 }
389
390                 if (*ep++ == '\0')
391                         break;
392
393                 p = ep;
394         }
395
396         if (dp + 2 + nbytes > edp) {
397                 printf ("can't fit %s rec into eeprom\n", rp->name);
398                 return (NULL);
399         }
400
401         *dp++ = rp->type;
402         *dp++ = nbytes;
403         memcpy (dp, bytes, nbytes);
404         dp += nbytes;
405
406         return (dp);
407 }
408
409 static eerec_map_t eerec_map[] = {
410         /* name      type                 handler         len max             */
411         { "serno",   HYMOD_EEREC_SERNO,   uint_handler,   4,  0               },
412         { "date",    HYMOD_EEREC_DATE,    date_handler,   4,  0               },
413         { "batch",   HYMOD_EEREC_BATCH,   string_handler, 0,  HYMOD_MAX_BATCH },
414         { "type",    HYMOD_EEREC_TYPE,    uint_handler,   1,  0               },
415         { "rev",     HYMOD_EEREC_REV,     uint_handler,   1,  0               },
416         { "sdram",   HYMOD_EEREC_SDRAM,   bytes_handler,  0,  HYMOD_MAX_SDRAM },
417         { "flash",   HYMOD_EEREC_FLASH,   bytes_handler,  0,  HYMOD_MAX_FLASH },
418         { "zbt",     HYMOD_EEREC_ZBT,     bytes_handler,  0,  HYMOD_MAX_ZBT   },
419         { "xlxtyp",  HYMOD_EEREC_XLXTYP,  bytes_handler,  0,  HYMOD_MAX_XLX   },
420         { "xlxspd",  HYMOD_EEREC_XLXSPD,  bytes_handler,  0,  HYMOD_MAX_XLX   },
421         { "xlxtmp",  HYMOD_EEREC_XLXTMP,  bytes_handler,  0,  HYMOD_MAX_XLX   },
422         { "xlxgrd",  HYMOD_EEREC_XLXGRD,  bytes_handler,  0,  HYMOD_MAX_XLX   },
423         { "cputyp",  HYMOD_EEREC_CPUTYP,  uint_handler,   1,  0               },
424         { "cpuspd",  HYMOD_EEREC_CPUSPD,  uint_handler,   1,  0               },
425         { "cpmspd",  HYMOD_EEREC_CPMSPD,  uint_handler,   1,  0               },
426         { "busspd",  HYMOD_EEREC_BUSSPD,  uint_handler,   1,  0               },
427         { "hstype",  HYMOD_EEREC_HSTYPE,  uint_handler,   1,  0               },
428         { "hschin",  HYMOD_EEREC_HSCHIN,  uint_handler,   1,  0               },
429         { "hschout", HYMOD_EEREC_HSCHOUT, uint_handler,   1,  0               },
430 };
431
432 static int neerecs = sizeof eerec_map / sizeof eerec_map[0];
433
434 static uchar data[HYMOD_EEPROM_SIZE], *sdp, *dp, *edp;
435
436 static int
437 eerec_callback (uchar *name, uchar *val)
438 {
439         eerec_map_t *rp;
440
441         for (rp = eerec_map; rp < &eerec_map[neerecs]; rp++)
442                 if (strcmp (name, rp->name) == 0)
443                         break;
444
445         if (rp >= &eerec_map[neerecs])
446                 return (0);
447
448         if ((dp = (*rp->handler) (rp, val, dp, edp)) == NULL)
449                 return (0);
450
451         return (1);
452 }
453
454 static int
455 hymod_eeprom_fetch(int which, char *filename, ulong addr)
456 {
457         unsigned dev_addr = CFG_I2C_EEPROM_ADDR | \
458                 (which ? HYMOD_EEOFF_MEZZ : HYMOD_EEOFF_MAIN);
459         hymod_eehdr_t *hp = (hymod_eehdr_t *)&data[0];
460         ulong crc;
461
462         hp->id = HYMOD_EEPROM_ID;
463         hp->ver = HYMOD_EEPROM_VER;
464
465         dp = sdp = (uchar *)(hp + 1);
466         edp = dp + HYMOD_EEPROM_MAXLEN;
467
468         if (fetch_and_parse (filename, addr, eerec_callback) == 0)
469                 return (0);
470
471         hp->len = dp - sdp;
472
473         crc = crc32 (0, data, dp - data);
474         memcpy (dp, &crc, sizeof (ulong));
475         dp += sizeof (ulong);
476
477         eeprom_write (dev_addr, 0, data, dp - data);
478
479         return (1);
480 }
481
482 static char *type_vals[] = {
483         "NONE", "IO", "CLP", "DSP", "INPUT", "ALT-INPUT", "DISPLAY"
484 };
485
486 static char *xlxtyp_vals[] = {
487         "NONE", "XCV300E", "XCV400E", "XCV600E"
488 };
489
490 static char *xlxspd_vals[] = {
491         "NONE", "6", "7", "8"
492 };
493
494 static char *xlxtmp_vals[] = {
495         "NONE", "COM", "IND"
496 };
497
498 static char *xlxgrd_vals[] = {
499         "NONE", "NORMAL", "ENGSAMP"
500 };
501
502 static char *cputyp_vals[] = {
503         "NONE", "MPC8260"
504 };
505
506 static char *clk_vals[] = {
507         "NONE", "33", "66", "100", "133", "166", "200"
508 };
509
510 static char *hstype_vals[] = {
511         "NONE", "AMCC-S2064A"
512 };
513
514 static void
515 print_mem (char *l, char *s, uchar n, uchar a[])
516 {
517         if (n > 0) {
518                 if (n == 1)
519                         printf ("%s%dMB %s", s, 1 << (a[0] - 20), l);
520                 else {
521                         ulong t = 0;
522                         int i;
523
524                         for (i = 0; i < n; i++)
525                                 t += 1 << (a[i] - 20);
526
527                         printf ("%s%luMB %s (%d banks:", s, t, l, n);
528
529                         for (i = 0; i < n; i++)
530                                 printf ("%dMB%s",
531                                         1 << (a[i] - 20),
532                                         (i == n - 1) ? ")" : ",");
533                 }
534         }
535         else
536                 printf ("%sNO %s", s, l);
537 }
538
539 void
540 hymod_eeprom_print (hymod_eeprom_t *ep)
541 {
542         int i;
543
544         printf ("         Hymod %s board, rev %03d\n",
545                 type_vals[ep->bdtype], ep->bdrev);
546
547         printf ("         serial #: %010lu, date %04d-%02d-%02d",
548                 ep->serno, ep->date.year, ep->date.month, ep->date.day);
549         if (ep->batchlen > 0)
550                 printf (", batch \"%.*s\"", ep->batchlen, ep->batch);
551         puts ("\n");
552
553         switch (ep->bdtype) {
554
555         case HYMOD_BDTYPE_IO:
556         case HYMOD_BDTYPE_CLP:
557         case HYMOD_BDTYPE_DSP:
558                 printf ("         Motorola %s CPU, speeds: %s/%s/%s",
559                     cputyp_vals[ep->mpc.type], clk_vals[ep->mpc.cpuspd],
560                     clk_vals[ep->mpc.cpmspd], clk_vals[ep->mpc.busspd]);
561
562                 print_mem ("SDRAM", ", ", ep->nsdram, ep->sdramsz);
563
564                 print_mem ("FLASH", ", ", ep->nflash, ep->flashsz);
565
566                 puts ("\n");
567
568                 print_mem ("ZBT", "         ", ep->nzbt, ep->zbtsz);
569
570                 if (ep->nxlx > 0) {
571                         hymod_xlx_t *xp;
572
573                         if (ep->nxlx == 1) {
574                                 xp = &ep->xlx[0];
575                                 printf (", Xilinx %s FPGA (%s/%s/%s)",
576                                         xlxtyp_vals[xp->type],
577                                         xlxspd_vals[xp->speed],
578                                         xlxtmp_vals[xp->temp],
579                                         xlxgrd_vals[xp->grade]);
580                         }
581                         else {
582                                 printf (", %d Xilinx FPGAs (", ep->nxlx);
583                                 for (i = 0; i < ep->nxlx; i++) {
584                                         xp = &ep->xlx[i];
585                                         printf ("%s[%s/%s/%s]%s",
586                                             xlxtyp_vals[xp->type],
587                                             xlxspd_vals[xp->speed],
588                                             xlxtmp_vals[xp->temp],
589                                             xlxgrd_vals[xp->grade],
590                                             (i == ep->nxlx - 1) ? ")" : ", ");
591                                 }
592                         }
593                 }
594                 else
595                         puts(", NO FPGAs");
596
597                 puts ("\n");
598
599                 if (ep->hss.type > 0)
600                         printf ("         High Speed Serial: "
601                                 "%s, %d input%s, %d output%s\n",
602                                 hstype_vals[ep->hss.type],
603                                 ep->hss.nchin,
604                                 (ep->hss.nchin == 1 ? "" : "s"),
605                                 ep->hss.nchout,
606                                 (ep->hss.nchout == 1 ? "" : "s"));
607                 break;
608
609         case HYMOD_BDTYPE_INPUT:
610         case HYMOD_BDTYPE_ALTINPUT:
611         case HYMOD_BDTYPE_DISPLAY:
612                 break;
613
614         default:
615                 /* crap! */
616                 printf ("         UNKNOWN BOARD TYPE: %d\n", ep->bdtype);
617                 break;
618         }
619 }
620
621 int
622 hymod_eeprom_read (int which, hymod_eeprom_t *ep)
623 {
624         char *label = which ? "mezzanine" : "main";
625         unsigned dev_addr = CFG_I2C_EEPROM_ADDR | \
626                 (which ? HYMOD_EEOFF_MEZZ : HYMOD_EEOFF_MAIN);
627         char filename[50], prompt[50], *dir;
628         int serno, count = 0, rc;
629
630         rc = eeprom_probe (dev_addr, 0);
631
632         if (rc > 0) {
633                 printf ("*** probe for eeprom failed with code %d\n", rc);
634                 return (0);
635         }
636
637         if (rc < 0)
638                 return (rc);
639
640         sprintf (prompt, "Enter %s board serial number: ", label);
641
642         if ((dir = getenv ("bddb_cfgdir")) == NULL)
643                 dir = def_bddb_cfgdir;
644
645         for (;;) {
646                 int rc;
647
648                 if (hymod_eeprom_load (which, ep))
649                         return (1);
650
651                 printf ("*** %s board EEPROM contents are %sinvalid\n",
652                         label, count == 0 ? "" : "STILL ");
653
654                 puts ("*** will fetch from server (Ctrl-C to abort)\n");
655
656                 serno = hymod_get_serno (prompt);
657
658                 if (serno < 0) {
659                         if (serno == -1)
660                                 puts ("\n*** interrupted!");
661                         else
662                                 puts ("\n*** timeout!");
663                         puts (" - ignoring eeprom contents\n");
664                         return (0);
665                 }
666
667                 sprintf (filename, "%s/%010d.cfg", dir, serno);
668
669                 printf ("*** fetching %s board EEPROM contents from server\n",
670                         label);
671
672                 rc = hymod_eeprom_fetch (which, filename, CFG_LOAD_ADDR);
673
674                 if (rc == 0) {
675                         puts ("*** fetch failed - ignoring eeprom contents\n");
676                         return (0);
677                 }
678
679                 count++;
680         }
681 }