xref: /openbmc/u-boot/board/keymile/common/common.c (revision 5c8404af)
1 /*
2  * (C) Copyright 2008
3  * Heiko Schocher, DENX Software Engineering, hs@denx.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 #if defined(CONFIG_KM82XX)
26 #include <mpc8260.h>
27 #endif
28 #include <ioports.h>
29 #include <command.h>
30 #include <malloc.h>
31 #include <hush.h>
32 #include <net.h>
33 #include <netdev.h>
34 #include <asm/io.h>
35 #include <linux/ctype.h>
36 
37 #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT)
38 #include <libfdt.h>
39 #endif
40 
41 #include "../common/common.h"
42 #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
43 #include <i2c.h>
44 
45 static void i2c_write_start_seq(void);
46 static int i2c_make_abort(void);
47 DECLARE_GLOBAL_DATA_PTR;
48 
49 int ivm_calc_crc(unsigned char *buf, int len)
50 {
51 	const unsigned short crc_tab[16] = {
52 		0x0000, 0xCC01, 0xD801, 0x1400,
53 		0xF001, 0x3C00, 0x2800, 0xE401,
54 		0xA001, 0x6C00, 0x7800, 0xB401,
55 		0x5000, 0x9C01, 0x8801, 0x4400};
56 
57 	unsigned short crc     = 0;   /* final result */
58 	unsigned short r1      = 0;   /* temp */
59 	unsigned char  byte    = 0;   /* input buffer */
60 	int	i;
61 
62 	/* calculate CRC from array data */
63 	for (i = 0; i < len; i++) {
64 		byte = buf[i];
65 
66 		/* lower 4 bits */
67 		r1 = crc_tab[crc & 0xF];
68 		crc = ((crc) >> 4) & 0x0FFF;
69 		crc = crc ^ r1 ^ crc_tab[byte & 0xF];
70 
71 		/* upper 4 bits */
72 		r1 = crc_tab[crc & 0xF];
73 		crc = (crc >> 4) & 0x0FFF;
74 		crc = crc ^ r1 ^ crc_tab[(byte >> 4) & 0xF];
75 	}
76 	return crc;
77 }
78 
79 /*
80  * Set Keymile specific environment variables
81  * Currently only some memory layout variables are calculated here
82  * ... ------------------------------------------------
83  * ... |@rootfsaddr |@pnvramaddr |@varaddr |@reserved |@END_OF_RAM
84  * ... |<------------------- pram ------------------->|
85  * ... ------------------------------------------------
86  * @END_OF_RAM: denotes the RAM size
87  * @pnvramaddr: Startadress of pseudo non volatile RAM in hex
88  * @pram      : preserved ram size in k
89  * @varaddr   : startadress for /var mounted into RAM
90  */
91 int set_km_env(void)
92 {
93 	uchar buf[32];
94 	unsigned int pnvramaddr;
95 	unsigned int pram;
96 	unsigned int varaddr;
97 
98 	pnvramaddr = gd->ram_size - CONFIG_KM_RESERVED_PRAM - CONFIG_KM_PHRAM
99 			- CONFIG_KM_PNVRAM;
100 	sprintf((char *)buf, "0x%x", pnvramaddr);
101 	setenv("pnvramaddr", (char *)buf);
102 
103 	pram = (CONFIG_KM_RESERVED_PRAM + CONFIG_KM_PHRAM + CONFIG_KM_PNVRAM) /
104 		0x400;
105 	sprintf((char *)buf, "0x%x", pram);
106 	setenv("pram", (char *)buf);
107 
108 	varaddr = gd->ram_size - CONFIG_KM_RESERVED_PRAM - CONFIG_KM_PHRAM;
109 	sprintf((char *)buf, "0x%x", varaddr);
110 	setenv("varaddr", (char *)buf);
111 	return 0;
112 }
113 
114 static int ivm_set_value(char *name, char *value)
115 {
116 	char tempbuf[256];
117 
118 	if (value != NULL) {
119 		sprintf(tempbuf, "%s=%s", name, value);
120 		return set_local_var(tempbuf, 0);
121 	} else {
122 		unset_local_var(name);
123 	}
124 	return 0;
125 }
126 
127 static int ivm_get_value(unsigned char *buf, int len, char *name, int off,
128 				int check)
129 {
130 	unsigned short	val;
131 	unsigned char	valbuf[30];
132 
133 	if ((buf[off + 0] != buf[off + 2]) &&
134 	    (buf[off + 2] != buf[off + 4])) {
135 		printf("%s Error corrupted %s\n", __func__, name);
136 		val = -1;
137 	} else {
138 		val = buf[off + 0] + (buf[off + 1] << 8);
139 		if ((val == 0) && (check == 1))
140 			val = -1;
141 	}
142 	sprintf((char *)valbuf, "%x", val);
143 	ivm_set_value(name, (char *)valbuf);
144 	return val;
145 }
146 
147 #define INV_BLOCKSIZE		0x100
148 #define INV_DATAADDRESS		0x21
149 #define INVENTORYDATASIZE	(INV_BLOCKSIZE - INV_DATAADDRESS - 3)
150 
151 #define IVM_POS_SHORT_TEXT		0
152 #define IVM_POS_MANU_ID			1
153 #define IVM_POS_MANU_SERIAL		2
154 #define IVM_POS_PART_NUMBER		3
155 #define IVM_POS_BUILD_STATE		4
156 #define IVM_POS_SUPPLIER_PART_NUMBER	5
157 #define IVM_POS_DELIVERY_DATE		6
158 #define IVM_POS_SUPPLIER_BUILD_STATE	7
159 #define IVM_POS_CUSTOMER_ID		8
160 #define IVM_POS_CUSTOMER_PROD_ID	9
161 #define IVM_POS_HISTORY			10
162 #define IVM_POS_SYMBOL_ONLY		11
163 
164 static char convert_char(char c)
165 {
166 	return (c < ' ' || c > '~') ? '.' : c;
167 }
168 
169 static int ivm_findinventorystring(int type,
170 					unsigned char* const string,
171 					unsigned long maxlen,
172 					unsigned char *buf)
173 {
174 	int xcode = 0;
175 	unsigned long cr = 0;
176 	unsigned long addr = INV_DATAADDRESS;
177 	unsigned long size = 0;
178 	unsigned long nr = type;
179 	int stop = 0; 	/* stop on semicolon */
180 
181 	memset(string, '\0', maxlen);
182 	switch (type) {
183 		case IVM_POS_SYMBOL_ONLY:
184 			nr = 0;
185 			stop= 1;
186 		break;
187 		default:
188 			nr = type;
189 			stop = 0;
190 	}
191 
192 	/* Look for the requested number of CR. */
193 	while ((cr != nr) && (addr < INVENTORYDATASIZE)) {
194 		if ((buf[addr] == '\r')) {
195 			cr++;
196 		}
197 		addr++;
198 	}
199 
200 	/*
201 	 * the expected number of CR was found until the end of the IVM
202 	 *  content --> fill string
203 	 */
204 	if (addr < INVENTORYDATASIZE) {
205 		/* Copy the IVM string in the corresponding string */
206 		for (; (buf[addr] != '\r')			&&
207 			((buf[addr] != ';') ||  (!stop))	&&
208 			(size < (maxlen - 1)			&&
209 			(addr < INVENTORYDATASIZE)); addr++)
210 		{
211 			size += sprintf((char *)string + size, "%c",
212 						convert_char (buf[addr]));
213 		}
214 
215 		/*
216 		 * copy phase is done: check if everything is ok. If not,
217 		 * the inventory data is most probably corrupted: tell
218 		 * the world there is a problem!
219 		 */
220 		if (addr == INVENTORYDATASIZE) {
221 			xcode = -1;
222 			printf("Error end of string not found\n");
223 		} else if ((size >= (maxlen - 1)) &&
224 			   (buf[addr] != '\r')) {
225 			xcode = -1;
226 			printf("string too long till next CR\n");
227 		}
228 	} else {
229 		/*
230 		 * some CR are missing...
231 		 * the inventory data is most probably corrupted
232 		 */
233 		xcode = -1;
234 		printf("not enough cr found\n");
235 	}
236 	return xcode;
237 }
238 
239 #define GET_STRING(name, which, len) \
240 	if (ivm_findinventorystring(which, valbuf, len, buf) == 0) { \
241 		ivm_set_value(name, (char *)valbuf); \
242 	}
243 
244 static int ivm_check_crc(unsigned char *buf, int block)
245 {
246 	unsigned long	crc;
247 	unsigned long	crceeprom;
248 
249 	crc = ivm_calc_crc(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 2);
250 	crceeprom = (buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 1] + \
251 			buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 2] * 256);
252 	if (crc != crceeprom) {
253 		if (block == 0)
254 			printf("Error CRC Block: %d EEprom: calculated: \
255 			%lx EEprom: %lx\n", block, crc, crceeprom);
256 		return -1;
257 	}
258 	return 0;
259 }
260 
261 static int ivm_analyze_block2(unsigned char *buf, int len)
262 {
263 	unsigned char	valbuf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN];
264 	unsigned long	count;
265 
266 	/* IVM_MacAddress */
267 	sprintf((char *)valbuf, "%pM", buf);
268 	ivm_set_value("IVM_MacAddress", (char *)valbuf);
269 	/* if an offset is defined, add it */
270 #if defined(CONFIG_PIGGY_MAC_ADRESS_OFFSET)
271 	if (CONFIG_PIGGY_MAC_ADRESS_OFFSET > 0) {
272 		unsigned long val = (buf[4] << 16) + (buf[5] << 8) + buf[6];
273 
274 		val += CONFIG_PIGGY_MAC_ADRESS_OFFSET;
275 		buf[4] = (val >> 16) & 0xff;
276 		buf[5] = (val >> 8) & 0xff;
277 		buf[6] = val & 0xff;
278 		sprintf((char *)valbuf, "%pM", buf);
279 	}
280 #endif
281 	if (getenv("ethaddr") == NULL)
282 		setenv((char *)"ethaddr", (char *)valbuf);
283 
284 	/* IVM_MacCount */
285 	count = (buf[10] << 24) +
286 		   (buf[11] << 16) +
287 		   (buf[12] << 8)  +
288 		    buf[13];
289 	if (count == 0xffffffff)
290 		count = 1;
291 	sprintf((char *)valbuf, "%lx", count);
292 	ivm_set_value("IVM_MacCount", (char *)valbuf);
293 	return 0;
294 }
295 
296 int ivm_analyze_eeprom(unsigned char *buf, int len)
297 {
298 	unsigned short	val;
299 	unsigned char	valbuf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN];
300 	unsigned char	*tmp;
301 
302 	if (ivm_check_crc(buf, 0) != 0)
303 		return -1;
304 
305 	ivm_get_value(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN,
306 			"IVM_BoardId", 0, 1);
307 	val = ivm_get_value(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN,
308 			"IVM_HWKey", 6, 1);
309 	if (val != 0xffff) {
310 		sprintf((char *)valbuf, "%x", ((val / 100) % 10));
311 		ivm_set_value("IVM_HWVariant", (char *)valbuf);
312 		sprintf((char *)valbuf, "%x", (val % 100));
313 		ivm_set_value("IVM_HWVersion", (char *)valbuf);
314 	}
315 	ivm_get_value(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN,
316 		"IVM_Functions", 12, 0);
317 
318 	GET_STRING("IVM_Symbol", IVM_POS_SYMBOL_ONLY, 8)
319 	GET_STRING("IVM_DeviceName", IVM_POS_SHORT_TEXT, 64)
320 	tmp = (unsigned char *) getenv("IVM_DeviceName");
321 	if (tmp) {
322 		int	len = strlen((char *)tmp);
323 		int	i = 0;
324 
325 		while (i < len) {
326 			if (tmp[i] == ';') {
327 				ivm_set_value("IVM_ShortText",
328 					(char *)&tmp[i + 1]);
329 				break;
330 			}
331 			i++;
332 		}
333 		if (i >= len)
334 			ivm_set_value("IVM_ShortText", NULL);
335 	} else {
336 		ivm_set_value("IVM_ShortText", NULL);
337 	}
338 	GET_STRING("IVM_ManufacturerID", IVM_POS_MANU_ID, 32)
339 	GET_STRING("IVM_ManufacturerSerialNumber", IVM_POS_MANU_SERIAL, 20)
340 	GET_STRING("IVM_ManufacturerPartNumber", IVM_POS_PART_NUMBER, 32)
341 	GET_STRING("IVM_ManufacturerBuildState", IVM_POS_BUILD_STATE, 32)
342 	GET_STRING("IVM_SupplierPartNumber", IVM_POS_SUPPLIER_PART_NUMBER, 32)
343 	GET_STRING("IVM_DelieveryDate", IVM_POS_DELIVERY_DATE, 32)
344 	GET_STRING("IVM_SupplierBuildState", IVM_POS_SUPPLIER_BUILD_STATE, 32)
345 	GET_STRING("IVM_CustomerID", IVM_POS_CUSTOMER_ID, 32)
346 	GET_STRING("IVM_CustomerProductID", IVM_POS_CUSTOMER_PROD_ID, 32)
347 
348 	if (ivm_check_crc(&buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN * 2], 2) != 0)
349 		return 0;
350 	ivm_analyze_block2(&buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN * 2],
351 		CONFIG_SYS_IVM_EEPROM_PAGE_LEN);
352 
353 	return 0;
354 }
355 
356 int ivm_read_eeprom(void)
357 {
358 #if defined(CONFIG_I2C_MUX)
359 	I2C_MUX_DEVICE *dev = NULL;
360 #endif
361 	uchar i2c_buffer[CONFIG_SYS_IVM_EEPROM_MAX_LEN];
362 	uchar	*buf;
363 	unsigned dev_addr = CONFIG_SYS_IVM_EEPROM_ADR;
364 	int ret;
365 
366 #if defined(CONFIG_I2C_MUX)
367 	/* First init the Bus, select the Bus */
368 #if defined(CONFIG_SYS_I2C_IVM_BUS)
369 	dev = i2c_mux_ident_muxstring((uchar *)CONFIG_SYS_I2C_IVM_BUS);
370 #else
371 	buf = (unsigned char *) getenv("EEprom_ivm");
372 	if (buf != NULL)
373 		dev = i2c_mux_ident_muxstring(buf);
374 #endif
375 	if (dev == NULL) {
376 		printf("Error couldnt add Bus for IVM\n");
377 		return -1;
378 	}
379 	i2c_set_bus_num(dev->busid);
380 #endif
381 
382 	buf = (unsigned char *) getenv("EEprom_ivm_addr");
383 	if (buf != NULL)
384 		dev_addr = simple_strtoul((char *)buf, NULL, 16);
385 
386 	/* add deblocking here */
387 	i2c_make_abort();
388 
389 	ret = i2c_read(dev_addr, 0, 1, i2c_buffer,
390 		CONFIG_SYS_IVM_EEPROM_MAX_LEN);
391 	if (ret != 0) {
392 		printf ("Error reading EEprom\n");
393 		return -2;
394 	}
395 
396 	return ivm_analyze_eeprom(i2c_buffer, CONFIG_SYS_IVM_EEPROM_MAX_LEN);
397 }
398 
399 #if defined(CONFIG_SYS_I2C_INIT_BOARD)
400 #define DELAY_ABORT_SEQ		62  /* @200kHz 9 clocks = 44us, 62us is ok */
401 #define DELAY_HALF_PERIOD	(500 / (CONFIG_SYS_I2C_SPEED / 1000))
402 
403 #if defined(CONFIG_KM_82XX)
404 #define SDA_MASK	0x00010000
405 #define SCL_MASK	0x00020000
406 void set_pin(int state, unsigned long mask)
407 {
408 	ioport_t *iop = ioport_addr((immap_t *)CONFIG_SYS_IMMR, 3);
409 
410 	if (state)
411 		setbits_be32(&iop->pdat, mask);
412 	else
413 		clrbits_be32(&iop->pdat, mask);
414 
415 	setbits_be32(&iop->pdir, mask);
416 }
417 
418 static int get_pin(unsigned long mask)
419 {
420 	ioport_t *iop = ioport_addr((immap_t *)CONFIG_SYS_IMMR, 3);
421 
422 	clrbits_be32(&iop->pdir, mask);
423 	return 0 != (in_be32(&iop->pdat) & mask);
424 }
425 
426 static void set_sda(int state)
427 {
428 	set_pin(state, SDA_MASK);
429 }
430 
431 static void set_scl(int state)
432 {
433 	set_pin(state, SCL_MASK);
434 }
435 
436 static int get_sda(void)
437 {
438 	return get_pin(SDA_MASK);
439 }
440 
441 static int get_scl(void)
442 {
443 	return get_pin(SCL_MASK);
444 }
445 
446 #if defined(CONFIG_HARD_I2C)
447 static void setports(int gpio)
448 {
449 	ioport_t *iop = ioport_addr((immap_t *)CONFIG_SYS_IMMR, 3);
450 
451 	if (gpio) {
452 		clrbits_be32(&iop->ppar, (SDA_MASK | SCL_MASK));
453 		clrbits_be32(&iop->podr, (SDA_MASK | SCL_MASK));
454 	} else {
455 		setbits_be32(&iop->ppar, (SDA_MASK | SCL_MASK));
456 		clrbits_be32(&iop->pdir, (SDA_MASK | SCL_MASK));
457 		setbits_be32(&iop->podr, (SDA_MASK | SCL_MASK));
458 	}
459 }
460 #endif
461 #endif
462 
463 #if !defined(CONFIG_MPC83xx)
464 static void i2c_write_start_seq(void)
465 {
466 	set_sda(1);
467 	udelay(DELAY_HALF_PERIOD);
468 	set_scl(1);
469 	udelay(DELAY_HALF_PERIOD);
470 	set_sda(0);
471 	udelay(DELAY_HALF_PERIOD);
472 	set_scl(0);
473 	udelay(DELAY_HALF_PERIOD);
474 }
475 
476 /*
477  * I2C is a synchronous protocol and resets of the processor in the middle
478  * of an access can block the I2C Bus until a powerdown of the full unit is
479  * done. This function toggles the SCL until the SCL and SCA line are
480  * released, but max. 16 times, after this a I2C start-sequence is sent.
481  * This I2C Deblocking mechanism was developed by Keymile in association
482  * with Anatech and Atmel in 1998.
483  */
484 static int i2c_make_abort(void)
485 {
486 
487 #if defined(CONFIG_HARD_I2C) && !defined(MACH_TYPE_KM_KIRKWOOD)
488 	immap_t *immap = (immap_t *)CONFIG_SYS_IMMR ;
489 	i2c8260_t *i2c	= (i2c8260_t *)&immap->im_i2c;
490 
491 	/*
492 	 * disable I2C controller first, otherwhise it thinks we want to
493 	 * talk to the slave port...
494 	 */
495 	clrbits_8(&i2c->i2c_i2mod, 0x01);
496 
497 	/* Set the PortPins to GPIO */
498 	setports(1);
499 #endif
500 
501 	int	scl_state = 0;
502 	int	sda_state = 0;
503 	int	i = 0;
504 	int	ret = 0;
505 
506 	if (!get_sda()) {
507 		ret = -1;
508 		while (i < 16) {
509 			i++;
510 			set_scl(0);
511 			udelay(DELAY_ABORT_SEQ);
512 			set_scl(1);
513 			udelay(DELAY_ABORT_SEQ);
514 			scl_state = get_scl();
515 			sda_state = get_sda();
516 			if (scl_state && sda_state) {
517 				ret = 0;
518 				break;
519 			}
520 		}
521 	}
522 	if (ret == 0)
523 		for (i = 0; i < 5; i++)
524 			i2c_write_start_seq();
525 
526 	/* respect stop setup time */
527 	udelay(DELAY_ABORT_SEQ);
528 	set_scl(1);
529 	udelay(DELAY_ABORT_SEQ);
530 	set_sda(1);
531 	get_sda();
532 
533 #if defined(CONFIG_HARD_I2C)
534 	/* Set the PortPins back to use for I2C */
535 	setports(0);
536 #endif
537 	return ret;
538 }
539 #endif
540 
541 #if defined(CONFIG_MPC83xx)
542 static void i2c_write_start_seq(void)
543 {
544 	struct fsl_i2c *dev;
545 	dev = (struct fsl_i2c *) (CONFIG_SYS_IMMR + CONFIG_SYS_I2C_OFFSET);
546 	udelay(DELAY_ABORT_SEQ);
547 	out_8(&dev->cr, (I2C_CR_MEN | I2C_CR_MSTA));
548 	udelay(DELAY_ABORT_SEQ);
549 	out_8(&dev->cr, (I2C_CR_MEN));
550 }
551 
552 static int i2c_make_abort(void)
553 {
554 	struct fsl_i2c *dev;
555 	dev = (struct fsl_i2c *) (CONFIG_SYS_IMMR + CONFIG_SYS_I2C_OFFSET);
556 	uchar	dummy;
557 	uchar   last;
558 	int     nbr_read = 0;
559 	int     i = 0;
560 	int	    ret = 0;
561 
562 	/* wait after each operation to finsh with a delay */
563 	out_8(&dev->cr, (I2C_CR_MSTA));
564 	udelay(DELAY_ABORT_SEQ);
565 	out_8(&dev->cr, (I2C_CR_MEN | I2C_CR_MSTA));
566 	udelay(DELAY_ABORT_SEQ);
567 	dummy = in_8(&dev->dr);
568 	udelay(DELAY_ABORT_SEQ);
569 	last = in_8(&dev->dr);
570 	nbr_read++;
571 
572 	/*
573 	 * do read until the last bit is 1, but stop if the full eeprom is
574 	 * read.
575 	 */
576 	while (((last & 0x01) != 0x01) &&
577 		(nbr_read < CONFIG_SYS_IVM_EEPROM_MAX_LEN)) {
578 		udelay(DELAY_ABORT_SEQ);
579 		last = in_8(&dev->dr);
580 		nbr_read++;
581 	}
582 	if ((last & 0x01) != 0x01)
583 		ret = -2;
584 	if ((last != 0xff) || (nbr_read > 1))
585 		printf("[INFO] i2c abort after %d bytes (0x%02x)\n",
586 			nbr_read, last);
587 	udelay(DELAY_ABORT_SEQ);
588 	out_8(&dev->cr, (I2C_CR_MEN));
589 	udelay(DELAY_ABORT_SEQ);
590 	/* clear status reg */
591 	out_8(&dev->sr, 0);
592 
593 	for (i = 0; i < 5; i++)
594 		i2c_write_start_seq();
595 	if (ret != 0)
596 		printf("[ERROR] i2c abort failed after %d bytes (0x%02x)\n",
597 			nbr_read, last);
598 
599 	return ret;
600 }
601 #endif
602 
603 /**
604  * i2c_init_board - reset i2c bus. When the board is powercycled during a
605  * bus transfer it might hang; for details see doc/I2C_Edge_Conditions.
606  */
607 void i2c_init_board(void)
608 {
609 	/* Now run the AbortSequence() */
610 	i2c_make_abort();
611 }
612 #endif
613 #endif
614 
615 #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT)
616 int fdt_set_node_and_value(void *blob,
617 				char *nodename,
618 				char *regname,
619 				void *var,
620 				int size)
621 {
622 	int ret = 0;
623 	int nodeoffset = 0;
624 
625 	nodeoffset = fdt_path_offset(blob, nodename);
626 	if (nodeoffset >= 0) {
627 		ret = fdt_setprop(blob, nodeoffset, regname, var,
628 					size);
629 		if (ret < 0)
630 			printf("ft_blob_update(): cannot set %s/%s "
631 				"property err:%s\n", nodename, regname,
632 				fdt_strerror(ret));
633 	} else {
634 		printf("ft_blob_update(): cannot find %s node "
635 			"err:%s\n", nodename, fdt_strerror(nodeoffset));
636 	}
637 	return ret;
638 }
639 
640 int fdt_get_node_and_value(void *blob,
641 				char *nodename,
642 				char *propname,
643 				void **var)
644 {
645 	int len;
646 	int nodeoffset = 0;
647 
648 	nodeoffset = fdt_path_offset(blob, nodename);
649 	if (nodeoffset >= 0) {
650 		*var = (void *)fdt_getprop(blob, nodeoffset, propname, &len);
651 		if (len == 0) {
652 			/* no value */
653 			printf("%s no value\n", __func__);
654 			return -1;
655 		} else if (len > 0) {
656 			return len;
657 		} else {
658 			printf("libfdt fdt_getprop(): %s\n",
659 				fdt_strerror(len));
660 			return -2;
661 		}
662 	} else {
663 		printf("%s: cannot find %s node err:%s\n", __func__,
664 			nodename, fdt_strerror(nodeoffset));
665 		return -3;
666 	}
667 }
668 #endif
669 
670 #if !defined(MACH_TYPE_KM_KIRKWOOD)
671 int ethernet_present(void)
672 {
673 	struct km_bec_fpga *base =
674 		(struct km_bec_fpga *)CONFIG_SYS_KMBEC_FPGA_BASE;
675 
676 	return in_8(&base->bprth) & PIGGY_PRESENT;
677 }
678 #endif
679 
680 int board_eth_init(bd_t *bis)
681 {
682 	if (ethernet_present())
683 		return cpu_eth_init(bis);
684 
685 	return -1;
686 }
687 
688 /*
689  * do_setboardid command
690  * read out the board id and the hw key from the intventory EEPROM and set
691  * this values as environment variables.
692  */
693 static int do_setboardid(cmd_tbl_t *cmdtp, int flag, int argc,
694 				char *const argv[])
695 {
696 	unsigned char buf[32];
697 	char *p;
698 
699 	p = get_local_var("IVM_BoardId");
700 	if (p == NULL) {
701 		printf("can't get the IVM_Boardid\n");
702 		return 1;
703 	}
704 	sprintf((char *)buf, "%s", p);
705 	setenv("boardid", (char *)buf);
706 
707 	p = get_local_var("IVM_HWKey");
708 	if (p == NULL) {
709 		printf("can't get the IVM_HWKey\n");
710 		return 1;
711 	}
712 	sprintf((char *)buf, "%s", p);
713 	setenv("hwkey", (char *)buf);
714 
715 	return 0;
716 }
717 
718 U_BOOT_CMD(km_setboardid, 1, 0, do_setboardid, "setboardid", "read out bid and "
719 				 "hwkey from IVM and set in environment");
720 
721 /*
722  * command km_checkbidhwk
723  *	if "boardid" and "hwkey" are not already set in the environment, do:
724  *		if a "boardIdListHex" exists in the environment:
725  *			- read ivm data for boardid and hwkey
726  *			- compare each entry of the boardIdListHex with the
727  *				IVM data:
728  *			if match:
729  *				set environment variables boardid, boardId,
730  *				hwkey, hwKey to	the found values
731  *				both (boardid and boardId) are set because
732  *				they might be used differently in the
733  *				application and in the init scripts (?)
734  *	return 0 in case of match, 1 if not match or error
735  */
736 int do_checkboardidhwk(cmd_tbl_t *cmdtp, int flag, int argc,
737 			char *const argv[])
738 {
739 	unsigned long ivmbid = 0, ivmhwkey = 0;
740 	unsigned long envbid = 0, envhwkey = 0;
741 	char *p;
742 	int verbose = argc > 1 && *argv[1] == 'v';
743 	int rc = 0;
744 
745 	/*
746 	 * first read out the real inventory values, these values are
747 	 * already stored in the local hush variables
748 	 */
749 	p = get_local_var("IVM_BoardId");
750 	if (p == NULL) {
751 		printf("can't get the IVM_Boardid\n");
752 		return 1;
753 	}
754 	rc = strict_strtoul(p, 16, &ivmbid);
755 
756 	p = get_local_var("IVM_HWKey");
757 	if (p == NULL) {
758 		printf("can't get the IVM_HWKey\n");
759 		return 1;
760 	}
761 	rc = strict_strtoul(p, 16, &ivmhwkey);
762 
763 	if (!ivmbid || !ivmhwkey) {
764 		printf("Error: IVM_BoardId and/or IVM_HWKey not set!\n");
765 		return rc;
766 	}
767 
768 	/* now try to read values from environment if available */
769 	p = getenv("boardid");
770 	if (p != NULL)
771 		rc = strict_strtoul(p, 16, &envbid);
772 	p = getenv("hwkey");
773 	if (p != NULL)
774 		rc = strict_strtoul(p, 16, &envhwkey);
775 
776 	if (rc != 0) {
777 		printf("strict_strtoul returns error: %d", rc);
778 		return rc;
779 	}
780 
781 	if (!envbid || !envhwkey) {
782 		/*
783 		 * BoardId/HWkey not available in the environment, so try the
784 		 * environment variable for BoardId/HWkey list
785 		 */
786 		char *bidhwklist = getenv("boardIdListHex");
787 
788 		if (bidhwklist) {
789 			int found = 0;
790 			char *rest = bidhwklist;
791 			char *endp;
792 
793 			if (verbose) {
794 				printf("IVM_BoardId: %ld, IVM_HWKey=%ld\n",
795 					ivmbid, ivmhwkey);
796 				printf("boardIdHwKeyList: %s\n",
797 					bidhwklist);
798 			}
799 			while (!found) {
800 				/* loop over each bid/hwkey pair in the list */
801 				unsigned long bid   = 0;
802 				unsigned long hwkey = 0;
803 
804 				while (*rest && !isxdigit(*rest))
805 					rest++;
806 				/*
807 				 * use simple_strtoul because we need &end and
808 				 * we know we got non numeric char at the end
809 				 */
810 				bid = simple_strtoul(rest, &endp, 16);
811 				/* BoardId and HWkey are separated with a "_" */
812 				if (*endp == '_') {
813 					rest  = endp + 1;
814 					/*
815 					 * use simple_strtoul because we need
816 					 * &end
817 					 */
818 					hwkey = simple_strtoul(rest, &endp, 16);
819 					rest  = endp;
820 					while (*rest && !isxdigit(*rest))
821 						rest++;
822 				}
823 				if ((!bid) || (!hwkey)) {
824 					/* end of list */
825 					break;
826 				}
827 				if (verbose) {
828 					printf("trying bid=0x%lX, hwkey=%ld\n",
829 						bid, hwkey);
830 				}
831 				/*
832 				 * Compare the values of the found entry in the
833 				 * list with the valid values which are stored
834 				 * in the inventory eeprom. If they are equal
835 				 * store the values in environment variables
836 				 * and save the environment.
837 				 * This can only happen once for the lifetime
838 				 * of a board, because once saved the function
839 				 * will never reach the while loop.
840 				 */
841 				if ((bid == ivmbid) && (hwkey == ivmhwkey)) {
842 					char buf[10];
843 
844 					found = 1;
845 					envbid   = bid;
846 					envhwkey = hwkey;
847 					sprintf(buf, "%lx", bid);
848 					setenv("boardid", buf);
849 					sprintf(buf, "%lx", hwkey);
850 					setenv("hwkey", buf);
851 					saveenv();
852 				}
853 			} /* end while( ! found ) */
854 		}
855 	}
856 
857 	/* compare now the values */
858 	if ((ivmbid == envbid) && (ivmhwkey == envhwkey)) {
859 		printf("boardid=0x%3lX, hwkey=%ld\n", envbid, envhwkey);
860 		rc = 0; /* match */
861 	} else {
862 		printf("Error: env bId=0x%3lX, hwKey=%ld\n", envbid, envhwkey);
863 		printf("       IVM bId=0x%3lX, hwKey=%ld\n", ivmbid, ivmhwkey);
864 		rc = 1; /* don't match */
865 	}
866 	return rc;
867 }
868 
869 U_BOOT_CMD(km_checkbidhwk, 2, 0, do_checkboardidhwk,
870 		"check boardid and hwkey",
871 		"[v]\n  - check environment parameter "\
872 		"\"boardIdListHex\" against stored boardid and hwkey "\
873 		"from the IVM\n    v: verbose output"
874 );
875