blob: fbcc3944dc5fa71cfe674e34cd07e3e903f4297e [file] [log] [blame]
wdenkc6097192002-11-03 00:24:07 +00001/*
2 * (C) Copyright 2001
3 * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com.
4 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02005 * SPDX-License-Identifier: GPL-2.0+
wdenkc6097192002-11-03 00:24:07 +00006 */
7
8#if defined(VXWORKS)
Wolfgang Denkd58c99f2011-12-07 12:19:27 +00009#include <stdio.h>
10#include <string.h>
11#define CONFIG_SYS_DEF_EEPROM_ADDR 0xa0
12extern char iicReadByte(char, char);
13extern ulong_t crc32(unsigned char *, unsigned long);
wdenkc6097192002-11-03 00:24:07 +000014#else
15#include <common.h>
16#endif
17
18#include "vpd.h"
19
20/*
21 * vpd_reader() - reads VPD data from I2C EEPROMS.
22 * returns pointer to buffer or NULL.
23 */
Wolfgang Denkd58c99f2011-12-07 12:19:27 +000024static unsigned char *vpd_reader(unsigned char *buf, unsigned dev_addr,
25 unsigned off, unsigned count)
wdenkc6097192002-11-03 00:24:07 +000026{
Wolfgang Denkd58c99f2011-12-07 12:19:27 +000027 unsigned offset = off; /* Calculated offset */
wdenkc6097192002-11-03 00:24:07 +000028
Wolfgang Denkd58c99f2011-12-07 12:19:27 +000029 /*
30 * The main board EEPROM contains
31 * SDRAM SPD in the first 128 bytes,
32 * so skew the offset.
33 */
34 if (dev_addr == CONFIG_SYS_DEF_EEPROM_ADDR)
35 offset += SDRAM_SPD_DATA_SIZE;
wdenkc6097192002-11-03 00:24:07 +000036
Wolfgang Denkd58c99f2011-12-07 12:19:27 +000037 /* Try to read the I2C EEPROM */
wdenkc6097192002-11-03 00:24:07 +000038#if defined(VXWORKS)
Wolfgang Denkd58c99f2011-12-07 12:19:27 +000039 {
40 int i;
41
42 for (i = 0; i < count; ++i)
43 buf[i] = iicReadByte(dev_addr, offset + i);
wdenkc6097192002-11-03 00:24:07 +000044 }
wdenkc6097192002-11-03 00:24:07 +000045#else
Wolfgang Denkd58c99f2011-12-07 12:19:27 +000046 if (eeprom_read(dev_addr, offset, buf, count)) {
47 printf("Failed to read %d bytes from VPD EEPROM 0x%x @ 0x%x\n",
48 count, dev_addr, offset);
49 return NULL;
50 }
wdenkc6097192002-11-03 00:24:07 +000051#endif
52
Wolfgang Denkd58c99f2011-12-07 12:19:27 +000053 return buf;
54}
wdenkc6097192002-11-03 00:24:07 +000055
56
57/*
58 * vpd_get_packet() - returns next VPD packet or NULL.
59 */
Wolfgang Denkd58c99f2011-12-07 12:19:27 +000060static vpd_packet_t *vpd_get_packet(vpd_packet_t * vpd_packet)
wdenkc6097192002-11-03 00:24:07 +000061{
Wolfgang Denkd58c99f2011-12-07 12:19:27 +000062 vpd_packet_t *packet = vpd_packet;
wdenkc6097192002-11-03 00:24:07 +000063
Wolfgang Denkd58c99f2011-12-07 12:19:27 +000064 if (packet != NULL) {
65 if (packet->identifier == VPD_PID_TERM)
66 return NULL;
67 else
68 packet = (vpd_packet_t *) ((char *) packet +
69 packet->size + 2);
70 }
wdenkc6097192002-11-03 00:24:07 +000071
Wolfgang Denkd58c99f2011-12-07 12:19:27 +000072 return packet;
73}
wdenkc6097192002-11-03 00:24:07 +000074
75
76/*
77 * vpd_find_packet() - Locates and returns the specified
78 * VPD packet or NULL on error.
79 */
Wolfgang Denkd58c99f2011-12-07 12:19:27 +000080static vpd_packet_t *vpd_find_packet(vpd_t * vpd, unsigned char ident)
wdenkc6097192002-11-03 00:24:07 +000081{
Wolfgang Denkd58c99f2011-12-07 12:19:27 +000082 vpd_packet_t *packet = (vpd_packet_t *) &vpd->packets;
wdenkc6097192002-11-03 00:24:07 +000083
Wolfgang Denkd58c99f2011-12-07 12:19:27 +000084 /* Guaranteed illegal */
85 if (ident == VPD_PID_GI)
86 return NULL;
wdenkc6097192002-11-03 00:24:07 +000087
Wolfgang Denkd58c99f2011-12-07 12:19:27 +000088 /* Scan tuples looking for a match */
89 while ((packet->identifier != ident) &&
90 (packet->identifier != VPD_PID_TERM))
91 packet = vpd_get_packet(packet);
wdenkc6097192002-11-03 00:24:07 +000092
Wolfgang Denkd58c99f2011-12-07 12:19:27 +000093 /* Did we find it? */
94 if ((packet->identifier) && (packet->identifier != ident))
95 return NULL;
96 return packet;
wdenkc6097192002-11-03 00:24:07 +000097}
98
99
100/*
101 * vpd_is_valid() - Validates contents of VPD data
102 * in I2C EEPROM. Returns 1 for
103 * success or 0 for failure.
104 */
105static int vpd_is_valid(unsigned dev_addr, unsigned char *buf)
106{
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000107 unsigned num_bytes;
108 vpd_packet_t *packet;
109 vpd_t *vpd = (vpd_t *) buf;
110 unsigned short stored_crc16, calc_crc16 = 0xffff;
wdenkc6097192002-11-03 00:24:07 +0000111
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000112 /* Check Eyecatcher */
113 if (strncmp
114 ((char *) (vpd->header.eyecatcher), VPD_EYECATCHER,
115 VPD_EYE_SIZE) != 0) {
116 unsigned offset = 0;
wdenkc6097192002-11-03 00:24:07 +0000117
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000118 if (dev_addr == CONFIG_SYS_DEF_EEPROM_ADDR)
119 offset += SDRAM_SPD_DATA_SIZE;
120 printf("Error: VPD EEPROM 0x%x corrupt @ 0x%x\n", dev_addr,
121 offset);
wdenkc6097192002-11-03 00:24:07 +0000122
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000123 return 0;
124 }
wdenkc6097192002-11-03 00:24:07 +0000125
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000126 /* Check Length */
127 if (vpd->header.size > VPD_MAX_EEPROM_SIZE) {
128 printf("Error: VPD EEPROM 0x%x contains bad size 0x%x\n",
129 dev_addr, vpd->header.size);
130 return 0;
131 }
wdenkc6097192002-11-03 00:24:07 +0000132
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000133 /* Now find the termination packet */
134 packet = vpd_find_packet(vpd, VPD_PID_TERM);
135 if (packet == NULL) {
136 printf("Error: VPD EEPROM 0x%x missing termination packet\n",
137 dev_addr);
138 return 0;
139 }
wdenkc6097192002-11-03 00:24:07 +0000140
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000141 /* Calculate data size */
142 num_bytes = (unsigned long) ((unsigned char *) packet -
143 (unsigned char *) vpd +
144 sizeof(vpd_packet_t));
wdenkc6097192002-11-03 00:24:07 +0000145
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000146 /* Find stored CRC and clear it */
147 packet = vpd_find_packet(vpd, VPD_PID_CRC);
148 if (packet == NULL) {
149 printf("Error: VPD EEPROM 0x%x missing CRC\n", dev_addr);
150 return 0;
151 }
Wolfgang Denk4f4b1e62011-12-07 12:19:28 +0000152 memcpy(&stored_crc16, packet->data, sizeof(ushort));
153 memset(packet->data, 0, sizeof(ushort));
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000154
155 /* OK, lets calculate the CRC and check it */
wdenkc6097192002-11-03 00:24:07 +0000156#if defined(VXWORKS)
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000157 calc_crc16 = (0xffff & crc32(buf, num_bytes));
wdenkc6097192002-11-03 00:24:07 +0000158#else
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000159 calc_crc16 = (0xffff & crc32(0, buf, num_bytes));
wdenkc6097192002-11-03 00:24:07 +0000160#endif
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000161 /* Now restore the CRC */
Wolfgang Denk4f4b1e62011-12-07 12:19:28 +0000162 memcpy(packet->data, &stored_crc16, sizeof(ushort));
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000163 if (stored_crc16 != calc_crc16) {
164 printf("Error: VPD EEPROM 0x%x has bad CRC 0x%x\n",
165 dev_addr, stored_crc16);
166 return 0;
167 }
wdenkc6097192002-11-03 00:24:07 +0000168
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000169 return 1;
170}
wdenkc6097192002-11-03 00:24:07 +0000171
172
173/*
174 * size_ok() - Check to see if packet size matches
175 * size of data we want. Returns 1 for
176 * good match or 0 for failure.
177 */
178static int size_ok(vpd_packet_t *packet, unsigned long size)
179{
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000180 if (packet->size != size) {
181 printf("VPD Packet 0x%x corrupt.\n", packet->identifier);
182 return 0;
183 }
184 return 1;
185}
wdenkc6097192002-11-03 00:24:07 +0000186
187
188/*
189 * strlen_ok() - Check to see if packet size matches
190 * strlen of the string we want to populate.
191 * Returns 1 for valid length or 0 for failure.
192 */
193static int strlen_ok(vpd_packet_t *packet, unsigned long length)
194{
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000195 if (packet->size >= length) {
196 printf("VPD Packet 0x%x corrupt.\n", packet->identifier);
197 return 0;
198 }
199 return 1;
200}
wdenkc6097192002-11-03 00:24:07 +0000201
202
203/*
204 * get_vpd_data() - populates the passed VPD structure 'vpdInfo'
205 * with data obtained from the specified
206 * I2C EEPROM 'dev_addr'. Returns 0 for
207 * success or 1 for failure.
208 */
209int vpd_get_data(unsigned char dev_addr, VPD *vpdInfo)
210{
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000211 unsigned char buf[VPD_EEPROM_SIZE];
212 vpd_t *vpd = (vpd_t *) buf;
213 vpd_packet_t *packet;
wdenkc6097192002-11-03 00:24:07 +0000214
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000215 if (vpdInfo == NULL)
216 return 1;
wdenkc6097192002-11-03 00:24:07 +0000217
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000218 /*
219 * Fill vpdInfo with 0s to blank out
220 * unused fields, fill vpdInfo->ethAddrs
221 * with all 0xffs so that other's code can
222 * determine how many real Ethernet addresses
223 * there are. OUIs starting with 0xff are
224 * broadcast addresses, and would never be
225 * permantely stored.
226 */
227 memset((void *) vpdInfo, 0, sizeof(VPD));
228 memset((void *) &vpdInfo->ethAddrs, 0xff, sizeof(vpdInfo->ethAddrs));
229 vpdInfo->_devAddr = dev_addr;
wdenkc6097192002-11-03 00:24:07 +0000230
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000231 /* Read the minimum size first */
232 if (vpd_reader(buf, dev_addr, 0, VPD_EEPROM_SIZE) == NULL)
233 return 1;
wdenkc6097192002-11-03 00:24:07 +0000234
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000235 /* Check validity of VPD data */
236 if (!vpd_is_valid(dev_addr, buf)) {
237 printf("VPD Data is INVALID!\n");
238 return 1;
239 }
wdenkc6097192002-11-03 00:24:07 +0000240
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000241 /*
242 * Walk all the packets and populate
243 * the VPD info structure.
244 */
245 packet = (vpd_packet_t *) &vpd->packets;
246 do {
247 switch (packet->identifier) {
248 case VPD_PID_GI:
249 printf("Error: Illegal VPD value\n");
250 break;
251 case VPD_PID_PID:
252 if (strlen_ok(packet, MAX_PROD_ID)) {
253 strncpy(vpdInfo->productId,
254 (char *) (packet->data),
255 packet->size);
256 }
257 break;
258 case VPD_PID_REV:
259 if (size_ok(packet, sizeof(char)))
260 vpdInfo->revisionId = *packet->data;
261 break;
262 case VPD_PID_SN:
263 if (size_ok(packet, sizeof(unsigned long))) {
Wolfgang Denk4f4b1e62011-12-07 12:19:28 +0000264 memcpy(&vpdInfo->serialNum,
265 packet->data,
266 sizeof(unsigned long));
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000267 }
268 break;
269 case VPD_PID_MANID:
270 if (size_ok(packet, sizeof(unsigned char)))
271 vpdInfo->manuID = *packet->data;
272 break;
273 case VPD_PID_PCO:
274 if (size_ok(packet, sizeof(unsigned long))) {
Wolfgang Denk4f4b1e62011-12-07 12:19:28 +0000275 memcpy(&vpdInfo->configOpt,
276 packet->data,
277 sizeof(unsigned long));
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000278 }
279 break;
280 case VPD_PID_SYSCLK:
281 if (size_ok(packet, sizeof(unsigned long)))
Wolfgang Denk4f4b1e62011-12-07 12:19:28 +0000282 memcpy(&vpdInfo->sysClk,
283 packet->data,
284 sizeof(unsigned long));
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000285 break;
286 case VPD_PID_SERCLK:
287 if (size_ok(packet, sizeof(unsigned long)))
Wolfgang Denk4f4b1e62011-12-07 12:19:28 +0000288 memcpy(&vpdInfo->serClk,
289 packet->data,
290 sizeof(unsigned long));
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000291 break;
292 case VPD_PID_FLASH:
293 if (size_ok(packet, 9)) { /* XXX - hardcoded,
294 padding in struct */
295 memcpy(&vpdInfo->flashCfg, packet->data, 9);
296 }
297 break;
298 case VPD_PID_ETHADDR:
299 memcpy(vpdInfo->ethAddrs, packet->data, packet->size);
300 break;
301 case VPD_PID_POTS:
302 if (size_ok(packet, sizeof(char)))
303 vpdInfo->numPOTS = (unsigned) *packet->data;
304 break;
305 case VPD_PID_DS1:
306 if (size_ok(packet, sizeof(char)))
307 vpdInfo->numDS1 = (unsigned) *packet->data;
308 case VPD_PID_GAL:
309 case VPD_PID_CRC:
310 case VPD_PID_TERM:
311 break;
312 default:
313 printf("Warning: Found unknown VPD packet ID 0x%x\n",
314 packet->identifier);
315 break;
wdenkc6097192002-11-03 00:24:07 +0000316 }
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000317 } while ((packet = vpd_get_packet(packet)));
wdenkc6097192002-11-03 00:24:07 +0000318
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000319 return 0;
320}
wdenkc6097192002-11-03 00:24:07 +0000321
322
323/*
324 * vpd_init() - Initialize default VPD environment
325 */
326int vpd_init(unsigned char dev_addr)
327{
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000328 return 0;
329}
wdenkc6097192002-11-03 00:24:07 +0000330
331
332/*
333 * vpd_print() - Pretty print the VPD data.
334 */
335void vpd_print(VPD *vpdInfo)
336{
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000337 const char *const sp = "";
338 const char *const sfmt = "%4s%-20s: \"%s\"\n";
339 const char *const cfmt = "%4s%-20s: '%c'\n";
340 const char *const dfmt = "%4s%-20s: %ld\n";
341 const char *const hfmt = "%4s%-20s: %08lX\n";
342 const char *const dsfmt = "%4s%-20s: %d\n";
343 const char *const hsfmt = "%4s%-20s: %04X\n";
344 const char *const dhfmt = "%4s%-20s: %ld (%lX)\n";
wdenkc6097192002-11-03 00:24:07 +0000345
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000346 printf("VPD read from I2C device: %02X\n", vpdInfo->_devAddr);
347
348 if (vpdInfo->productId[0])
349 printf(sfmt, sp, "Product ID", vpdInfo->productId);
350 else
351 printf(sfmt, sp, "Product ID", "UNKNOWN");
wdenkc6097192002-11-03 00:24:07 +0000352
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000353 if (vpdInfo->revisionId)
354 printf(cfmt, sp, "Revision ID", vpdInfo->revisionId);
wdenkc6097192002-11-03 00:24:07 +0000355
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000356 if (vpdInfo->serialNum)
357 printf(dfmt, sp, "Serial Number", vpdInfo->serialNum);
wdenkc6097192002-11-03 00:24:07 +0000358
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000359 if (vpdInfo->manuID)
360 printf(dfmt, sp, "Manufacture ID", (long) vpdInfo->manuID);
wdenkc6097192002-11-03 00:24:07 +0000361
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000362 if (vpdInfo->configOpt)
363 printf(hfmt, sp, "Configuration", vpdInfo->configOpt);
wdenkc6097192002-11-03 00:24:07 +0000364
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000365 if (vpdInfo->sysClk)
366 printf(dhfmt, sp, "System Clock", vpdInfo->sysClk,
367 vpdInfo->sysClk);
wdenkc6097192002-11-03 00:24:07 +0000368
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000369 if (vpdInfo->serClk)
370 printf(dhfmt, sp, "Serial Clock", vpdInfo->serClk,
371 vpdInfo->serClk);
wdenkc6097192002-11-03 00:24:07 +0000372
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000373 if (vpdInfo->numPOTS)
374 printf(dfmt, sp, "Number of POTS lines", vpdInfo->numPOTS);
wdenkc6097192002-11-03 00:24:07 +0000375
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000376 if (vpdInfo->numDS1)
377 printf(dfmt, sp, "Number of DS1s", vpdInfo->numDS1);
wdenkc6097192002-11-03 00:24:07 +0000378
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000379 /* Print Ethernet Addresses */
380 if (vpdInfo->ethAddrs[0][0] != 0xff) {
381 int i, j;
wdenkc6097192002-11-03 00:24:07 +0000382
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000383 printf("%4sEtherNet Address(es): ", sp);
384 for (i = 0; i < MAX_ETH_ADDRS; i++) {
385 if (vpdInfo->ethAddrs[i][0] != 0xff) {
386 for (j = 0; j < 6; j++) {
387 printf("%02X",
388 vpdInfo->ethAddrs[i][j]);
389 if (((j + 1) % 6) != 0)
390 printf(":");
391 else
392 printf(" ");
393 }
394 if (((i + 1) % 3) == 0)
395 printf("\n%24s: ", sp);
396 }
wdenkc6097192002-11-03 00:24:07 +0000397 }
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000398 printf("\n");
wdenkc6097192002-11-03 00:24:07 +0000399 }
wdenkc6097192002-11-03 00:24:07 +0000400
Wolfgang Denkd58c99f2011-12-07 12:19:27 +0000401 if (vpdInfo->flashCfg.mfg && vpdInfo->flashCfg.dev) {
402 printf("Main Flash Configuration:\n");
403 printf(hsfmt, sp, "Manufacture ID", vpdInfo->flashCfg.mfg);
404 printf(hsfmt, sp, "Device ID", vpdInfo->flashCfg.dev);
405 printf(dsfmt, sp, "Device Width", vpdInfo->flashCfg.devWidth);
406 printf(dsfmt, sp, "Num. Devices", vpdInfo->flashCfg.numDevs);
407 printf(dsfmt, sp, "Num. Columns", vpdInfo->flashCfg.numCols);
408 printf(dsfmt, sp, "Column Width", vpdInfo->flashCfg.colWidth);
409 printf(dsfmt, sp, "WE Data Width",
410 vpdInfo->flashCfg.weDataWidth);
411 }
412}