xref: /rk3399_rockchip-uboot/board/keymile/common/common.c (revision f1fef1d8a141e0b4e4520d66e162c06ff047bd16)
1c2485364SHeiko Schocher /*
2c2485364SHeiko Schocher  * (C) Copyright 2008
3c2485364SHeiko Schocher  * Heiko Schocher, DENX Software Engineering, hs@denx.de.
4c2485364SHeiko Schocher  *
5c2485364SHeiko Schocher  * See file CREDITS for list of people who contributed to this
6c2485364SHeiko Schocher  * project.
7c2485364SHeiko Schocher  *
8c2485364SHeiko Schocher  * This program is free software; you can redistribute it and/or
9c2485364SHeiko Schocher  * modify it under the terms of the GNU General Public License as
10c2485364SHeiko Schocher  * published by the Free Software Foundation; either version 2 of
11c2485364SHeiko Schocher  * the License, or (at your option) any later version.
12c2485364SHeiko Schocher  *
13c2485364SHeiko Schocher  * This program is distributed in the hope that it will be useful,
14c2485364SHeiko Schocher  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15c2485364SHeiko Schocher  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16c2485364SHeiko Schocher  * GNU General Public License for more details.
17c2485364SHeiko Schocher  *
18c2485364SHeiko Schocher  * You should have received a copy of the GNU General Public License
19c2485364SHeiko Schocher  * along with this program; if not, write to the Free Software
20c2485364SHeiko Schocher  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21c2485364SHeiko Schocher  * MA 02111-1307 USA
22c2485364SHeiko Schocher  */
23c2485364SHeiko Schocher 
24c2485364SHeiko Schocher #include <common.h>
25af895e45SHeiko Schocher #if defined(CONFIG_MGCOGE) || defined(CONFIG_MGCOGE2NE)
26c2485364SHeiko Schocher #include <mpc8260.h>
27210c8c00SHeiko Schocher #endif
28c2485364SHeiko Schocher #include <ioports.h>
29c2485364SHeiko Schocher #include <malloc.h>
308f64da7fSHeiko Schocher #include <hush.h>
31210c8c00SHeiko Schocher #include <net.h>
3262ddcf05SHeiko Schocher #include <netdev.h>
33210c8c00SHeiko Schocher #include <asm/io.h>
34c2485364SHeiko Schocher 
35c2485364SHeiko Schocher #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT)
36c2485364SHeiko Schocher #include <libfdt.h>
37c2485364SHeiko Schocher #endif
38c2485364SHeiko Schocher 
3967fa8c25SHeiko Schocher #include "../common/common.h"
40c2485364SHeiko Schocher #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
41c2485364SHeiko Schocher #include <i2c.h>
42c2485364SHeiko Schocher 
436c11aeafSHeiko Schocher static void i2c_write_start_seq(void);
446c11aeafSHeiko Schocher static int i2c_make_abort(void);
45*f1fef1d8SHeiko Schocher DECLARE_GLOBAL_DATA_PTR;
466c11aeafSHeiko Schocher 
478f64da7fSHeiko Schocher int ivm_calc_crc(unsigned char *buf, int len)
488f64da7fSHeiko Schocher {
498f64da7fSHeiko Schocher 	const unsigned short crc_tab[16] = {
508f64da7fSHeiko Schocher 		0x0000, 0xCC01, 0xD801, 0x1400,
518f64da7fSHeiko Schocher 		0xF001, 0x3C00, 0x2800, 0xE401,
528f64da7fSHeiko Schocher 		0xA001, 0x6C00, 0x7800, 0xB401,
538f64da7fSHeiko Schocher 		0x5000, 0x9C01, 0x8801, 0x4400};
548f64da7fSHeiko Schocher 
558f64da7fSHeiko Schocher 	unsigned short crc     = 0;   /* final result */
568f64da7fSHeiko Schocher 	unsigned short r1      = 0;   /* temp */
578f64da7fSHeiko Schocher 	unsigned char  byte    = 0;   /* input buffer */
588f64da7fSHeiko Schocher 	int	i;
598f64da7fSHeiko Schocher 
608f64da7fSHeiko Schocher 	/* calculate CRC from array data */
618f64da7fSHeiko Schocher 	for (i = 0; i < len; i++) {
628f64da7fSHeiko Schocher 		byte = buf[i];
638f64da7fSHeiko Schocher 
648f64da7fSHeiko Schocher 		/* lower 4 bits */
658f64da7fSHeiko Schocher 		r1 = crc_tab[crc & 0xF];
668f64da7fSHeiko Schocher 		crc = ((crc) >> 4) & 0x0FFF;
678f64da7fSHeiko Schocher 		crc = crc ^ r1 ^ crc_tab[byte & 0xF];
688f64da7fSHeiko Schocher 
698f64da7fSHeiko Schocher 		/* upper 4 bits */
708f64da7fSHeiko Schocher 		r1 = crc_tab[crc & 0xF];
718f64da7fSHeiko Schocher 		crc = (crc >> 4) & 0x0FFF;
728f64da7fSHeiko Schocher 		crc = crc ^ r1 ^ crc_tab[(byte >> 4) & 0xF];
738f64da7fSHeiko Schocher 	}
748f64da7fSHeiko Schocher 	return crc;
758f64da7fSHeiko Schocher }
768f64da7fSHeiko Schocher 
77*f1fef1d8SHeiko Schocher /*
78*f1fef1d8SHeiko Schocher  * Set Keymile specific environment variables
79*f1fef1d8SHeiko Schocher  * Currently only some memory layout variables are calculated here
80*f1fef1d8SHeiko Schocher  * ... ------------------------------------------------
81*f1fef1d8SHeiko Schocher  * ... |@rootfsaddr |@pnvramaddr |@varaddr |@reserved |@END_OF_RAM
82*f1fef1d8SHeiko Schocher  * ... |<------------------- pram ------------------->|
83*f1fef1d8SHeiko Schocher  * ... ------------------------------------------------
84*f1fef1d8SHeiko Schocher  * @END_OF_RAM: denotes the RAM size
85*f1fef1d8SHeiko Schocher  * @pnvramaddr: Startadress of pseudo non volatile RAM in hex
86*f1fef1d8SHeiko Schocher  * @pram      : preserved ram size in k
87*f1fef1d8SHeiko Schocher  * @varaddr   : startadress for /var mounted into RAM
88*f1fef1d8SHeiko Schocher  */
89*f1fef1d8SHeiko Schocher int set_km_env(void)
90*f1fef1d8SHeiko Schocher {
91*f1fef1d8SHeiko Schocher 	uchar buf[32];
92*f1fef1d8SHeiko Schocher 	unsigned int pnvramaddr;
93*f1fef1d8SHeiko Schocher 	unsigned int pram;
94*f1fef1d8SHeiko Schocher 	unsigned int varaddr;
95*f1fef1d8SHeiko Schocher 
96*f1fef1d8SHeiko Schocher 	pnvramaddr = gd->ram_size - CONFIG_KM_RESERVED_PRAM - CONFIG_KM_PHRAM
97*f1fef1d8SHeiko Schocher 			- CONFIG_KM_PNVRAM;
98*f1fef1d8SHeiko Schocher 	sprintf((char *)buf, "0x%x", pnvramaddr);
99*f1fef1d8SHeiko Schocher 	setenv("pnvramaddr", (char *)buf);
100*f1fef1d8SHeiko Schocher 
101*f1fef1d8SHeiko Schocher 	pram = (CONFIG_KM_RESERVED_PRAM + CONFIG_KM_PHRAM + CONFIG_KM_PNVRAM) /
102*f1fef1d8SHeiko Schocher 		0x400;
103*f1fef1d8SHeiko Schocher 	sprintf((char *)buf, "0x%x", pram);
104*f1fef1d8SHeiko Schocher 	setenv("pram", (char *)buf);
105*f1fef1d8SHeiko Schocher 
106*f1fef1d8SHeiko Schocher 	varaddr = gd->ram_size - CONFIG_KM_RESERVED_PRAM - CONFIG_KM_PHRAM;
107*f1fef1d8SHeiko Schocher 	sprintf((char *)buf, "0x%x", varaddr);
108*f1fef1d8SHeiko Schocher 	setenv("varaddr", (char *)buf);
109*f1fef1d8SHeiko Schocher 	return 0;
110*f1fef1d8SHeiko Schocher }
111*f1fef1d8SHeiko Schocher 
1128f64da7fSHeiko Schocher static int ivm_set_value(char *name, char *value)
1138f64da7fSHeiko Schocher {
1148f64da7fSHeiko Schocher 	char tempbuf[256];
1158f64da7fSHeiko Schocher 
1168f64da7fSHeiko Schocher 	if (value != NULL) {
1178f64da7fSHeiko Schocher 		sprintf(tempbuf, "%s=%s", name, value);
1188f64da7fSHeiko Schocher 		return set_local_var(tempbuf, 0);
1198f64da7fSHeiko Schocher 	} else {
1208f64da7fSHeiko Schocher 		unset_local_var(name);
1218f64da7fSHeiko Schocher 	}
1228f64da7fSHeiko Schocher 	return 0;
1238f64da7fSHeiko Schocher }
1248f64da7fSHeiko Schocher 
1258f64da7fSHeiko Schocher static int ivm_get_value(unsigned char *buf, int len, char *name, int off,
1268f64da7fSHeiko Schocher 				int check)
1278f64da7fSHeiko Schocher {
1288f64da7fSHeiko Schocher 	unsigned short	val;
1298f64da7fSHeiko Schocher 	unsigned char	valbuf[30];
1308f64da7fSHeiko Schocher 
1318f64da7fSHeiko Schocher 	if ((buf[off + 0] != buf[off + 2]) &&
1328f64da7fSHeiko Schocher 	    (buf[off + 2] != buf[off + 4])) {
133b11f53f3SHeiko Schocher 		printf("%s Error corrupted %s\n", __func__, name);
1348f64da7fSHeiko Schocher 		val = -1;
1358f64da7fSHeiko Schocher 	} else {
1368f64da7fSHeiko Schocher 		val = buf[off + 0] + (buf[off + 1] << 8);
1378f64da7fSHeiko Schocher 		if ((val == 0) && (check == 1))
1388f64da7fSHeiko Schocher 			val = -1;
1398f64da7fSHeiko Schocher 	}
1408f64da7fSHeiko Schocher 	sprintf((char *)valbuf, "%x", val);
1418f64da7fSHeiko Schocher 	ivm_set_value(name, (char *)valbuf);
1428f64da7fSHeiko Schocher 	return val;
1438f64da7fSHeiko Schocher }
1448f64da7fSHeiko Schocher 
145b11f53f3SHeiko Schocher #define INV_BLOCKSIZE		0x100
146b11f53f3SHeiko Schocher #define INV_DATAADDRESS		0x21
147b11f53f3SHeiko Schocher #define INVENTORYDATASIZE	(INV_BLOCKSIZE - INV_DATAADDRESS - 3)
1488f64da7fSHeiko Schocher 
1498f64da7fSHeiko Schocher #define IVM_POS_SHORT_TEXT		0
1508f64da7fSHeiko Schocher #define IVM_POS_MANU_ID			1
1518f64da7fSHeiko Schocher #define IVM_POS_MANU_SERIAL		2
1528f64da7fSHeiko Schocher #define IVM_POS_PART_NUMBER		3
1538f64da7fSHeiko Schocher #define IVM_POS_BUILD_STATE		4
1548f64da7fSHeiko Schocher #define IVM_POS_SUPPLIER_PART_NUMBER	5
1558f64da7fSHeiko Schocher #define IVM_POS_DELIVERY_DATE		6
1568f64da7fSHeiko Schocher #define IVM_POS_SUPPLIER_BUILD_STATE	7
1578f64da7fSHeiko Schocher #define IVM_POS_CUSTOMER_ID		8
1588f64da7fSHeiko Schocher #define IVM_POS_CUSTOMER_PROD_ID	9
1598f64da7fSHeiko Schocher #define IVM_POS_HISTORY			10
1608f64da7fSHeiko Schocher #define IVM_POS_SYMBOL_ONLY		11
1618f64da7fSHeiko Schocher 
1628f64da7fSHeiko Schocher static char convert_char(char c)
1638f64da7fSHeiko Schocher {
1648f64da7fSHeiko Schocher 	return (c < ' ' || c > '~') ? '.' : c;
1658f64da7fSHeiko Schocher }
1668f64da7fSHeiko Schocher 
1678f64da7fSHeiko Schocher static int ivm_findinventorystring(int type,
1688f64da7fSHeiko Schocher 					unsigned char* const string,
1698f64da7fSHeiko Schocher 					unsigned long maxlen,
1708f64da7fSHeiko Schocher 					unsigned char *buf)
1718f64da7fSHeiko Schocher {
1728f64da7fSHeiko Schocher 	int xcode = 0;
1738f64da7fSHeiko Schocher 	unsigned long cr = 0;
174b11f53f3SHeiko Schocher 	unsigned long addr = INV_DATAADDRESS;
1758f64da7fSHeiko Schocher 	unsigned long size = 0;
1768f64da7fSHeiko Schocher 	unsigned long nr = type;
1778f64da7fSHeiko Schocher 	int stop = 0; 	/* stop on semicolon */
1788f64da7fSHeiko Schocher 
1798f64da7fSHeiko Schocher 	memset(string, '\0', maxlen);
1808f64da7fSHeiko Schocher 	switch (type) {
1818f64da7fSHeiko Schocher 		case IVM_POS_SYMBOL_ONLY:
1828f64da7fSHeiko Schocher 			nr = 0;
1838f64da7fSHeiko Schocher 			stop= 1;
1848f64da7fSHeiko Schocher 		break;
1858f64da7fSHeiko Schocher 		default:
1868f64da7fSHeiko Schocher 			nr = type;
1878f64da7fSHeiko Schocher 			stop = 0;
1888f64da7fSHeiko Schocher 	}
1898f64da7fSHeiko Schocher 
1908f64da7fSHeiko Schocher 	/* Look for the requested number of CR. */
1918f64da7fSHeiko Schocher 	while ((cr != nr) && (addr < INVENTORYDATASIZE)) {
1928f64da7fSHeiko Schocher 		if ((buf[addr] == '\r')) {
1938f64da7fSHeiko Schocher 			cr++;
1948f64da7fSHeiko Schocher 		}
1958f64da7fSHeiko Schocher 		addr++;
1968f64da7fSHeiko Schocher 	}
1978f64da7fSHeiko Schocher 
198b11f53f3SHeiko Schocher 	/*
199b11f53f3SHeiko Schocher 	 * the expected number of CR was found until the end of the IVM
200b11f53f3SHeiko Schocher 	 *  content --> fill string
201b11f53f3SHeiko Schocher 	 */
2028f64da7fSHeiko Schocher 	if (addr < INVENTORYDATASIZE) {
2038f64da7fSHeiko Schocher 		/* Copy the IVM string in the corresponding string */
2048f64da7fSHeiko Schocher 		for (; (buf[addr] != '\r')			&&
2058f64da7fSHeiko Schocher 			((buf[addr] != ';') ||  (!stop))	&&
2068f64da7fSHeiko Schocher 			(size < (maxlen - 1)			&&
2078f64da7fSHeiko Schocher 			(addr < INVENTORYDATASIZE)); addr++)
2088f64da7fSHeiko Schocher 		{
2098f64da7fSHeiko Schocher 			size += sprintf((char *)string + size, "%c",
2108f64da7fSHeiko Schocher 						convert_char (buf[addr]));
2118f64da7fSHeiko Schocher 		}
2128f64da7fSHeiko Schocher 
213b11f53f3SHeiko Schocher 		/*
214b11f53f3SHeiko Schocher 		 * copy phase is done: check if everything is ok. If not,
2158f64da7fSHeiko Schocher 		 * the inventory data is most probably corrupted: tell
216b11f53f3SHeiko Schocher 		 * the world there is a problem!
217b11f53f3SHeiko Schocher 		 */
2188f64da7fSHeiko Schocher 		if (addr == INVENTORYDATASIZE) {
2198f64da7fSHeiko Schocher 			xcode = -1;
2208f64da7fSHeiko Schocher 			printf("Error end of string not found\n");
2218f64da7fSHeiko Schocher 		} else if ((size >= (maxlen - 1)) &&
2228f64da7fSHeiko Schocher 			   (buf[addr] != '\r')) {
2238f64da7fSHeiko Schocher 			xcode = -1;
2248f64da7fSHeiko Schocher 			printf("string too long till next CR\n");
2258f64da7fSHeiko Schocher 		}
2268f64da7fSHeiko Schocher 	} else {
227b11f53f3SHeiko Schocher 		/*
228b11f53f3SHeiko Schocher 		 * some CR are missing...
229b11f53f3SHeiko Schocher 		 * the inventory data is most probably corrupted
230b11f53f3SHeiko Schocher 		 */
2318f64da7fSHeiko Schocher 		xcode = -1;
2328f64da7fSHeiko Schocher 		printf("not enough cr found\n");
2338f64da7fSHeiko Schocher 	}
2348f64da7fSHeiko Schocher 	return xcode;
2358f64da7fSHeiko Schocher }
2368f64da7fSHeiko Schocher 
2378f64da7fSHeiko Schocher #define GET_STRING(name, which, len) \
2388f64da7fSHeiko Schocher 	if (ivm_findinventorystring(which, valbuf, len, buf) == 0) { \
2398f64da7fSHeiko Schocher 		ivm_set_value(name, (char *)valbuf); \
2408f64da7fSHeiko Schocher 	}
2418f64da7fSHeiko Schocher 
2428f64da7fSHeiko Schocher static int ivm_check_crc(unsigned char *buf, int block)
2438f64da7fSHeiko Schocher {
2448f64da7fSHeiko Schocher 	unsigned long	crc;
2458f64da7fSHeiko Schocher 	unsigned long	crceeprom;
2468f64da7fSHeiko Schocher 
2476d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	crc = ivm_calc_crc(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 2);
2486d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	crceeprom = (buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 1] + \
2496d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 			buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 2] * 256);
2508f64da7fSHeiko Schocher 	if (crc != crceeprom) {
251dc71b248SHeiko Schocher 		if (block == 0)
252dc71b248SHeiko Schocher 			printf("Error CRC Block: %d EEprom: calculated: \
253dc71b248SHeiko Schocher 			%lx EEprom: %lx\n", block, crc, crceeprom);
2548f64da7fSHeiko Schocher 		return -1;
2558f64da7fSHeiko Schocher 	}
2568f64da7fSHeiko Schocher 	return 0;
2578f64da7fSHeiko Schocher }
2588f64da7fSHeiko Schocher 
2598f64da7fSHeiko Schocher static int ivm_analyze_block2(unsigned char *buf, int len)
2608f64da7fSHeiko Schocher {
2616d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	unsigned char	valbuf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN];
2628f64da7fSHeiko Schocher 	unsigned long	count;
2638f64da7fSHeiko Schocher 
2648f64da7fSHeiko Schocher 	/* IVM_MacAddress */
265b11f53f3SHeiko Schocher 	sprintf((char *)valbuf, "%pM", buf);
2668f64da7fSHeiko Schocher 	ivm_set_value("IVM_MacAddress", (char *)valbuf);
2670d015202SHeiko Schocher 	/* if an offset is defined, add it */
2680d015202SHeiko Schocher #if defined(CONFIG_PIGGY_MAC_ADRESS_OFFSET)
2690d015202SHeiko Schocher 	if (CONFIG_PIGGY_MAC_ADRESS_OFFSET > 0) {
2700d015202SHeiko Schocher 		unsigned long val = (buf[4] << 16) + (buf[5] << 8) + buf[6];
2710d015202SHeiko Schocher 
2720d015202SHeiko Schocher 		val += CONFIG_PIGGY_MAC_ADRESS_OFFSET;
2730d015202SHeiko Schocher 		buf[4] = (val >> 16) & 0xff;
2740d015202SHeiko Schocher 		buf[5] = (val >> 8) & 0xff;
2750d015202SHeiko Schocher 		buf[6] = val & 0xff;
2760d015202SHeiko Schocher 		sprintf((char *)valbuf, "%pM", buf);
2770d015202SHeiko Schocher 	}
2780d015202SHeiko Schocher #endif
2798f64da7fSHeiko Schocher 	if (getenv("ethaddr") == NULL)
2808f64da7fSHeiko Schocher 		setenv((char *)"ethaddr", (char *)valbuf);
2810d015202SHeiko Schocher 
2828f64da7fSHeiko Schocher 	/* IVM_MacCount */
2838f64da7fSHeiko Schocher 	count = (buf[10] << 24) +
2848f64da7fSHeiko Schocher 		   (buf[11] << 16) +
2858f64da7fSHeiko Schocher 		   (buf[12] << 8)  +
2868f64da7fSHeiko Schocher 		    buf[13];
2878f64da7fSHeiko Schocher 	if (count == 0xffffffff)
2888f64da7fSHeiko Schocher 		count = 1;
2898f64da7fSHeiko Schocher 	sprintf((char *)valbuf, "%lx", count);
2908f64da7fSHeiko Schocher 	ivm_set_value("IVM_MacCount", (char *)valbuf);
2918f64da7fSHeiko Schocher 	return 0;
2928f64da7fSHeiko Schocher }
2938f64da7fSHeiko Schocher 
2948f64da7fSHeiko Schocher int ivm_analyze_eeprom(unsigned char *buf, int len)
2958f64da7fSHeiko Schocher {
2968f64da7fSHeiko Schocher 	unsigned short	val;
2976d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	unsigned char	valbuf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN];
2988f64da7fSHeiko Schocher 	unsigned char	*tmp;
2998f64da7fSHeiko Schocher 
3008f64da7fSHeiko Schocher 	if (ivm_check_crc(buf, 0) != 0)
3018f64da7fSHeiko Schocher 		return -1;
3028f64da7fSHeiko Schocher 
303b11f53f3SHeiko Schocher 	ivm_get_value(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN,
304b11f53f3SHeiko Schocher 			"IVM_BoardId", 0, 1);
305b11f53f3SHeiko Schocher 	val = ivm_get_value(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN,
306b11f53f3SHeiko Schocher 			"IVM_HWKey", 6, 1);
3078f64da7fSHeiko Schocher 	if (val != 0xffff) {
3088f64da7fSHeiko Schocher 		sprintf((char *)valbuf, "%x", ((val / 100) % 10));
3098f64da7fSHeiko Schocher 		ivm_set_value("IVM_HWVariant", (char *)valbuf);
3108f64da7fSHeiko Schocher 		sprintf((char *)valbuf, "%x", (val % 100));
3118f64da7fSHeiko Schocher 		ivm_set_value("IVM_HWVersion", (char *)valbuf);
3128f64da7fSHeiko Schocher 	}
313b11f53f3SHeiko Schocher 	ivm_get_value(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN,
314b11f53f3SHeiko Schocher 		"IVM_Functions", 12, 0);
3158f64da7fSHeiko Schocher 
3168f64da7fSHeiko Schocher 	GET_STRING("IVM_Symbol", IVM_POS_SYMBOL_ONLY, 8)
3178f64da7fSHeiko Schocher 	GET_STRING("IVM_DeviceName", IVM_POS_SHORT_TEXT, 64)
3188f64da7fSHeiko Schocher 	tmp = (unsigned char *) getenv("IVM_DeviceName");
3198f64da7fSHeiko Schocher 	if (tmp) {
3208f64da7fSHeiko Schocher 		int	len = strlen((char *)tmp);
3218f64da7fSHeiko Schocher 		int	i = 0;
3228f64da7fSHeiko Schocher 
3238f64da7fSHeiko Schocher 		while (i < len) {
3248f64da7fSHeiko Schocher 			if (tmp[i] == ';') {
325b11f53f3SHeiko Schocher 				ivm_set_value("IVM_ShortText",
326b11f53f3SHeiko Schocher 					(char *)&tmp[i + 1]);
3278f64da7fSHeiko Schocher 				break;
3288f64da7fSHeiko Schocher 			}
3298f64da7fSHeiko Schocher 			i++;
3308f64da7fSHeiko Schocher 		}
3318f64da7fSHeiko Schocher 		if (i >= len)
3328f64da7fSHeiko Schocher 			ivm_set_value("IVM_ShortText", NULL);
3338f64da7fSHeiko Schocher 	} else {
3348f64da7fSHeiko Schocher 		ivm_set_value("IVM_ShortText", NULL);
3358f64da7fSHeiko Schocher 	}
3368f64da7fSHeiko Schocher 	GET_STRING("IVM_ManufacturerID", IVM_POS_MANU_ID, 32)
3378f64da7fSHeiko Schocher 	GET_STRING("IVM_ManufacturerSerialNumber", IVM_POS_MANU_SERIAL, 20)
3388f64da7fSHeiko Schocher 	GET_STRING("IVM_ManufacturerPartNumber", IVM_POS_PART_NUMBER, 32)
3398f64da7fSHeiko Schocher 	GET_STRING("IVM_ManufacturerBuildState", IVM_POS_BUILD_STATE, 32)
3408f64da7fSHeiko Schocher 	GET_STRING("IVM_SupplierPartNumber", IVM_POS_SUPPLIER_PART_NUMBER, 32)
3418f64da7fSHeiko Schocher 	GET_STRING("IVM_DelieveryDate", IVM_POS_DELIVERY_DATE, 32)
3428f64da7fSHeiko Schocher 	GET_STRING("IVM_SupplierBuildState", IVM_POS_SUPPLIER_BUILD_STATE, 32)
3438f64da7fSHeiko Schocher 	GET_STRING("IVM_CustomerID", IVM_POS_CUSTOMER_ID, 32)
3448f64da7fSHeiko Schocher 	GET_STRING("IVM_CustomerProductID", IVM_POS_CUSTOMER_PROD_ID, 32)
3458f64da7fSHeiko Schocher 
3466d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	if (ivm_check_crc(&buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN * 2], 2) != 0)
347dc71b248SHeiko Schocher 		return 0;
348b11f53f3SHeiko Schocher 	ivm_analyze_block2(&buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN * 2],
349b11f53f3SHeiko Schocher 		CONFIG_SYS_IVM_EEPROM_PAGE_LEN);
3508f64da7fSHeiko Schocher 
3518f64da7fSHeiko Schocher 	return 0;
3528f64da7fSHeiko Schocher }
3538f64da7fSHeiko Schocher 
3548f64da7fSHeiko Schocher int ivm_read_eeprom(void)
3558f64da7fSHeiko Schocher {
3561b6275dfSHeiko Schocher #if defined(CONFIG_I2C_MUX)
3578f64da7fSHeiko Schocher 	I2C_MUX_DEVICE *dev = NULL;
3581b6275dfSHeiko Schocher #endif
3596d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	uchar i2c_buffer[CONFIG_SYS_IVM_EEPROM_MAX_LEN];
3608f64da7fSHeiko Schocher 	uchar	*buf;
3616d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	unsigned dev_addr = CONFIG_SYS_IVM_EEPROM_ADR;
362b11f53f3SHeiko Schocher 	int ret;
3638f64da7fSHeiko Schocher 
3641b6275dfSHeiko Schocher #if defined(CONFIG_I2C_MUX)
3658f64da7fSHeiko Schocher 	/* First init the Bus, select the Bus */
3666d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_SYS_I2C_IVM_BUS)
3676d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	dev = i2c_mux_ident_muxstring((uchar *)CONFIG_SYS_I2C_IVM_BUS);
3688f64da7fSHeiko Schocher #else
3698f64da7fSHeiko Schocher 	buf = (unsigned char *) getenv("EEprom_ivm");
3708f64da7fSHeiko Schocher 	if (buf != NULL)
3718f64da7fSHeiko Schocher 		dev = i2c_mux_ident_muxstring(buf);
3728f64da7fSHeiko Schocher #endif
3738f64da7fSHeiko Schocher 	if (dev == NULL) {
3748f64da7fSHeiko Schocher 		printf("Error couldnt add Bus for IVM\n");
3758f64da7fSHeiko Schocher 		return -1;
3768f64da7fSHeiko Schocher 	}
3778f64da7fSHeiko Schocher 	i2c_set_bus_num(dev->busid);
3781b6275dfSHeiko Schocher #endif
3798f64da7fSHeiko Schocher 
3808f64da7fSHeiko Schocher 	buf = (unsigned char *) getenv("EEprom_ivm_addr");
3818f64da7fSHeiko Schocher 	if (buf != NULL)
3828f64da7fSHeiko Schocher 		dev_addr = simple_strtoul((char *)buf, NULL, 16);
3838f64da7fSHeiko Schocher 
3846c11aeafSHeiko Schocher 	/* add deblocking here */
3856c11aeafSHeiko Schocher 	i2c_make_abort();
3866c11aeafSHeiko Schocher 
387b11f53f3SHeiko Schocher 	ret = i2c_read(dev_addr, 0, 1, i2c_buffer,
388b11f53f3SHeiko Schocher 		CONFIG_SYS_IVM_EEPROM_MAX_LEN);
389b11f53f3SHeiko Schocher 	if (ret != 0) {
3908f64da7fSHeiko Schocher 		printf ("Error reading EEprom\n");
3918f64da7fSHeiko Schocher 		return -2;
3928f64da7fSHeiko Schocher 	}
3938f64da7fSHeiko Schocher 
3946d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	return ivm_analyze_eeprom(i2c_buffer, CONFIG_SYS_IVM_EEPROM_MAX_LEN);
3958f64da7fSHeiko Schocher }
3968f64da7fSHeiko Schocher 
3976d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_SYS_I2C_INIT_BOARD)
3986c11aeafSHeiko Schocher #define DELAY_ABORT_SEQ		62  /* @200kHz 9 clocks = 44us, 62us is ok */
3996d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #define DELAY_HALF_PERIOD	(500 / (CONFIG_SYS_I2C_SPEED / 1000))
400c2485364SHeiko Schocher 
401af895e45SHeiko Schocher #if defined(CONFIG_MGCOGE) || defined(CONFIG_MGCOGE2NE)
402c2485364SHeiko Schocher #define SDA_MASK	0x00010000
403c2485364SHeiko Schocher #define SCL_MASK	0x00020000
404c2485364SHeiko Schocher static void set_pin(int state, unsigned long mask)
405c2485364SHeiko Schocher {
406b11f53f3SHeiko Schocher 	ioport_t *iop = ioport_addr((immap_t *)CONFIG_SYS_IMMR, 3);
407c2485364SHeiko Schocher 
408c2485364SHeiko Schocher 	if (state)
409b11f53f3SHeiko Schocher 		setbits_be32(&iop->pdat, mask);
410c2485364SHeiko Schocher 	else
411b11f53f3SHeiko Schocher 		clrbits_be32(&iop->pdat, mask);
412c2485364SHeiko Schocher 
413b11f53f3SHeiko Schocher 	setbits_be32(&iop->pdir, mask);
414c2485364SHeiko Schocher }
415c2485364SHeiko Schocher 
416c2485364SHeiko Schocher static int get_pin(unsigned long mask)
417c2485364SHeiko Schocher {
418b11f53f3SHeiko Schocher 	ioport_t *iop = ioport_addr((immap_t *)CONFIG_SYS_IMMR, 3);
419c2485364SHeiko Schocher 
420b11f53f3SHeiko Schocher 	clrbits_be32(&iop->pdir, mask);
421b11f53f3SHeiko Schocher 	return 0 != (in_be32(&iop->pdat) & mask);
422c2485364SHeiko Schocher }
423c2485364SHeiko Schocher 
424c2485364SHeiko Schocher static void set_sda(int state)
425c2485364SHeiko Schocher {
426c2485364SHeiko Schocher 	set_pin(state, SDA_MASK);
427c2485364SHeiko Schocher }
428c2485364SHeiko Schocher 
429c2485364SHeiko Schocher static void set_scl(int state)
430c2485364SHeiko Schocher {
431c2485364SHeiko Schocher 	set_pin(state, SCL_MASK);
432c2485364SHeiko Schocher }
433c2485364SHeiko Schocher 
434c2485364SHeiko Schocher static int get_sda(void)
435c2485364SHeiko Schocher {
436c2485364SHeiko Schocher 	return get_pin(SDA_MASK);
437c2485364SHeiko Schocher }
438c2485364SHeiko Schocher 
439c2485364SHeiko Schocher static int get_scl(void)
440c2485364SHeiko Schocher {
441c2485364SHeiko Schocher 	return get_pin(SCL_MASK);
442c2485364SHeiko Schocher }
443c2485364SHeiko Schocher 
444c2485364SHeiko Schocher #if defined(CONFIG_HARD_I2C)
445c2485364SHeiko Schocher static void setports(int gpio)
446c2485364SHeiko Schocher {
447b11f53f3SHeiko Schocher 	ioport_t *iop = ioport_addr((immap_t *)CONFIG_SYS_IMMR, 3);
448c2485364SHeiko Schocher 
449c2485364SHeiko Schocher 	if (gpio) {
450b11f53f3SHeiko Schocher 		clrbits_be32(&iop->ppar, (SDA_MASK | SCL_MASK));
451b11f53f3SHeiko Schocher 		clrbits_be32(&iop->podr, (SDA_MASK | SCL_MASK));
452c2485364SHeiko Schocher 	} else {
453b11f53f3SHeiko Schocher 		setbits_be32(&iop->ppar, (SDA_MASK | SCL_MASK));
454b11f53f3SHeiko Schocher 		clrbits_be32(&iop->pdir, (SDA_MASK | SCL_MASK));
455b11f53f3SHeiko Schocher 		setbits_be32(&iop->podr, (SDA_MASK | SCL_MASK));
456c2485364SHeiko Schocher 	}
457c2485364SHeiko Schocher }
458c2485364SHeiko Schocher #endif
459c2485364SHeiko Schocher #endif
460c2485364SHeiko Schocher 
46162ddcf05SHeiko Schocher #if !defined(CONFIG_MPC83xx)
4626c11aeafSHeiko Schocher static void i2c_write_start_seq(void)
463c2485364SHeiko Schocher {
464c2485364SHeiko Schocher 	set_sda(1);
465c2485364SHeiko Schocher 	udelay(DELAY_HALF_PERIOD);
466c2485364SHeiko Schocher 	set_scl(1);
467c2485364SHeiko Schocher 	udelay(DELAY_HALF_PERIOD);
468c2485364SHeiko Schocher 	set_sda(0);
469c2485364SHeiko Schocher 	udelay(DELAY_HALF_PERIOD);
470c2485364SHeiko Schocher 	set_scl(0);
471c2485364SHeiko Schocher 	udelay(DELAY_HALF_PERIOD);
472c2485364SHeiko Schocher }
473c2485364SHeiko Schocher 
474b11f53f3SHeiko Schocher /*
475b11f53f3SHeiko Schocher  * I2C is a synchronous protocol and resets of the processor in the middle
476b11f53f3SHeiko Schocher  * of an access can block the I2C Bus until a powerdown of the full unit is
477b11f53f3SHeiko Schocher  * done. This function toggles the SCL until the SCL and SCA line are
478b11f53f3SHeiko Schocher  * released, but max. 16 times, after this a I2C start-sequence is sent.
479b11f53f3SHeiko Schocher  * This I2C Deblocking mechanism was developed by Keymile in association
480b11f53f3SHeiko Schocher  * with Anatech and Atmel in 1998.
481c2485364SHeiko Schocher  */
482c2485364SHeiko Schocher static int i2c_make_abort(void)
483c2485364SHeiko Schocher {
4846c11aeafSHeiko Schocher 
4856c11aeafSHeiko Schocher #if defined(CONFIG_HARD_I2C) && !defined(MACH_TYPE_KM_KIRKWOOD)
4866c11aeafSHeiko Schocher 	immap_t *immap = (immap_t *)CONFIG_SYS_IMMR ;
4876c11aeafSHeiko Schocher 	i2c8260_t *i2c	= (i2c8260_t *)&immap->im_i2c;
4886c11aeafSHeiko Schocher 
4896c11aeafSHeiko Schocher 	/*
4906c11aeafSHeiko Schocher 	 * disable I2C controller first, otherwhise it thinks we want to
4916c11aeafSHeiko Schocher 	 * talk to the slave port...
4926c11aeafSHeiko Schocher 	 */
4936c11aeafSHeiko Schocher 	clrbits_8(&i2c->i2c_i2mod, 0x01);
4946c11aeafSHeiko Schocher 
4956c11aeafSHeiko Schocher 	/* Set the PortPins to GPIO */
4966c11aeafSHeiko Schocher 	setports(1);
4976c11aeafSHeiko Schocher #endif
4986c11aeafSHeiko Schocher 
499c2485364SHeiko Schocher 	int	scl_state = 0;
500c2485364SHeiko Schocher 	int	sda_state = 0;
501c2485364SHeiko Schocher 	int	i = 0;
502c2485364SHeiko Schocher 	int	ret = 0;
503c2485364SHeiko Schocher 
504c2485364SHeiko Schocher 	if (!get_sda()) {
505c2485364SHeiko Schocher 		ret = -1;
506c2485364SHeiko Schocher 		while (i < 16) {
507c2485364SHeiko Schocher 			i++;
508c2485364SHeiko Schocher 			set_scl(0);
509c2485364SHeiko Schocher 			udelay(DELAY_ABORT_SEQ);
510c2485364SHeiko Schocher 			set_scl(1);
511c2485364SHeiko Schocher 			udelay(DELAY_ABORT_SEQ);
512c2485364SHeiko Schocher 			scl_state = get_scl();
513c2485364SHeiko Schocher 			sda_state = get_sda();
514c2485364SHeiko Schocher 			if (scl_state && sda_state) {
515c2485364SHeiko Schocher 				ret = 0;
516c2485364SHeiko Schocher 				break;
517c2485364SHeiko Schocher 			}
518c2485364SHeiko Schocher 		}
519c2485364SHeiko Schocher 	}
520b11f53f3SHeiko Schocher 	if (ret == 0)
521b11f53f3SHeiko Schocher 		for (i = 0; i < 5; i++)
5226c11aeafSHeiko Schocher 			i2c_write_start_seq();
523b11f53f3SHeiko Schocher 
5246c11aeafSHeiko Schocher 	/* respect stop setup time */
5256c11aeafSHeiko Schocher 	udelay(DELAY_ABORT_SEQ);
5266c11aeafSHeiko Schocher 	set_scl(1);
5276c11aeafSHeiko Schocher 	udelay(DELAY_ABORT_SEQ);
5286c11aeafSHeiko Schocher 	set_sda(1);
529c2485364SHeiko Schocher 	get_sda();
530c2485364SHeiko Schocher 
531c2485364SHeiko Schocher #if defined(CONFIG_HARD_I2C)
532c2485364SHeiko Schocher 	/* Set the PortPins back to use for I2C */
533c2485364SHeiko Schocher 	setports(0);
534c2485364SHeiko Schocher #endif
5356c11aeafSHeiko Schocher 	return ret;
5366c11aeafSHeiko Schocher }
53739df00d9SHeiko Schocher #endif
5386c11aeafSHeiko Schocher 
5396c11aeafSHeiko Schocher #if defined(CONFIG_MPC83xx)
5406c11aeafSHeiko Schocher static void i2c_write_start_seq(void)
5416c11aeafSHeiko Schocher {
5426c11aeafSHeiko Schocher 	struct fsl_i2c *dev;
5436c11aeafSHeiko Schocher 	dev = (struct fsl_i2c *) (CONFIG_SYS_IMMR + CONFIG_SYS_I2C_OFFSET);
5446c11aeafSHeiko Schocher 	udelay(DELAY_ABORT_SEQ);
5456c11aeafSHeiko Schocher 	out_8(&dev->cr, (I2C_CR_MEN | I2C_CR_MSTA));
5466c11aeafSHeiko Schocher 	udelay(DELAY_ABORT_SEQ);
5476c11aeafSHeiko Schocher 	out_8(&dev->cr, (I2C_CR_MEN));
5486c11aeafSHeiko Schocher }
5496c11aeafSHeiko Schocher 
5506c11aeafSHeiko Schocher static int i2c_make_abort(void)
5516c11aeafSHeiko Schocher {
5526c11aeafSHeiko Schocher 	struct fsl_i2c *dev;
5536c11aeafSHeiko Schocher 	dev = (struct fsl_i2c *) (CONFIG_SYS_IMMR + CONFIG_SYS_I2C_OFFSET);
5546c11aeafSHeiko Schocher 	uchar	dummy;
5556c11aeafSHeiko Schocher 	uchar   last;
5566c11aeafSHeiko Schocher 	int     nbr_read = 0;
5576c11aeafSHeiko Schocher 	int     i = 0;
5586c11aeafSHeiko Schocher 	int	    ret = 0;
5596c11aeafSHeiko Schocher 
5606c11aeafSHeiko Schocher 	/* wait after each operation to finsh with a delay */
5616c11aeafSHeiko Schocher 	out_8(&dev->cr, (I2C_CR_MSTA));
5626c11aeafSHeiko Schocher 	udelay(DELAY_ABORT_SEQ);
5636c11aeafSHeiko Schocher 	out_8(&dev->cr, (I2C_CR_MEN | I2C_CR_MSTA));
5646c11aeafSHeiko Schocher 	udelay(DELAY_ABORT_SEQ);
5656c11aeafSHeiko Schocher 	dummy = in_8(&dev->dr);
5666c11aeafSHeiko Schocher 	udelay(DELAY_ABORT_SEQ);
5676c11aeafSHeiko Schocher 	last = in_8(&dev->dr);
5686c11aeafSHeiko Schocher 	nbr_read++;
5696c11aeafSHeiko Schocher 
5706c11aeafSHeiko Schocher 	/*
5716c11aeafSHeiko Schocher 	 * do read until the last bit is 1, but stop if the full eeprom is
5726c11aeafSHeiko Schocher 	 * read.
5736c11aeafSHeiko Schocher 	 */
5746c11aeafSHeiko Schocher 	while (((last & 0x01) != 0x01) &&
5756c11aeafSHeiko Schocher 		(nbr_read < CONFIG_SYS_IVM_EEPROM_MAX_LEN)) {
5766c11aeafSHeiko Schocher 		udelay(DELAY_ABORT_SEQ);
5776c11aeafSHeiko Schocher 		last = in_8(&dev->dr);
5786c11aeafSHeiko Schocher 		nbr_read++;
5796c11aeafSHeiko Schocher 	}
5806c11aeafSHeiko Schocher 	if ((last & 0x01) != 0x01)
5816c11aeafSHeiko Schocher 		ret = -2;
5826c11aeafSHeiko Schocher 	if ((last != 0xff) || (nbr_read > 1))
5836c11aeafSHeiko Schocher 		printf("[INFO] i2c abort after %d bytes (0x%02x)\n",
5846c11aeafSHeiko Schocher 			nbr_read, last);
5856c11aeafSHeiko Schocher 	udelay(DELAY_ABORT_SEQ);
5866c11aeafSHeiko Schocher 	out_8(&dev->cr, (I2C_CR_MEN));
5876c11aeafSHeiko Schocher 	udelay(DELAY_ABORT_SEQ);
5886c11aeafSHeiko Schocher 	/* clear status reg */
5896c11aeafSHeiko Schocher 	out_8(&dev->sr, 0);
5906c11aeafSHeiko Schocher 
5916c11aeafSHeiko Schocher 	for (i = 0; i < 5; i++)
5926c11aeafSHeiko Schocher 		i2c_write_start_seq();
5936c11aeafSHeiko Schocher 	if (ret != 0)
5946c11aeafSHeiko Schocher 		printf("[ERROR] i2c abort failed after %d bytes (0x%02x)\n",
5956c11aeafSHeiko Schocher 			nbr_read, last);
5966c11aeafSHeiko Schocher 
5976c11aeafSHeiko Schocher 	return ret;
5986c11aeafSHeiko Schocher }
5996c11aeafSHeiko Schocher #endif
6006c11aeafSHeiko Schocher 
6016c11aeafSHeiko Schocher /**
6026c11aeafSHeiko Schocher  * i2c_init_board - reset i2c bus. When the board is powercycled during a
6036c11aeafSHeiko Schocher  * bus transfer it might hang; for details see doc/I2C_Edge_Conditions.
6046c11aeafSHeiko Schocher  */
6056c11aeafSHeiko Schocher void i2c_init_board(void)
6066c11aeafSHeiko Schocher {
6076c11aeafSHeiko Schocher 	/* Now run the AbortSequence() */
6086c11aeafSHeiko Schocher 	i2c_make_abort();
609c2485364SHeiko Schocher }
610c2485364SHeiko Schocher #endif
611210c8c00SHeiko Schocher #endif
6126250f0f6SHeiko Schocher 
6136250f0f6SHeiko Schocher #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT)
6146250f0f6SHeiko Schocher int fdt_set_node_and_value(void *blob,
6156250f0f6SHeiko Schocher 				char *nodename,
6166250f0f6SHeiko Schocher 				char *regname,
6176250f0f6SHeiko Schocher 				void *var,
6186250f0f6SHeiko Schocher 				int size)
6196250f0f6SHeiko Schocher {
6206250f0f6SHeiko Schocher 	int ret = 0;
6216250f0f6SHeiko Schocher 	int nodeoffset = 0;
6226250f0f6SHeiko Schocher 
6236250f0f6SHeiko Schocher 	nodeoffset = fdt_path_offset(blob, nodename);
6246250f0f6SHeiko Schocher 	if (nodeoffset >= 0) {
6256250f0f6SHeiko Schocher 		ret = fdt_setprop(blob, nodeoffset, regname, var,
6266250f0f6SHeiko Schocher 					size);
6276250f0f6SHeiko Schocher 		if (ret < 0)
6286250f0f6SHeiko Schocher 			printf("ft_blob_update(): cannot set %s/%s "
6296250f0f6SHeiko Schocher 				"property err:%s\n", nodename, regname,
6306250f0f6SHeiko Schocher 				fdt_strerror(ret));
6316250f0f6SHeiko Schocher 	} else {
6326250f0f6SHeiko Schocher 		printf("ft_blob_update(): cannot find %s node "
6336250f0f6SHeiko Schocher 			"err:%s\n", nodename, fdt_strerror(nodeoffset));
6346250f0f6SHeiko Schocher 	}
6356250f0f6SHeiko Schocher 	return ret;
6366250f0f6SHeiko Schocher }
637b11f53f3SHeiko Schocher 
638dc71b248SHeiko Schocher int fdt_get_node_and_value(void *blob,
639dc71b248SHeiko Schocher 				char *nodename,
640dc71b248SHeiko Schocher 				char *propname,
641dc71b248SHeiko Schocher 				void **var)
642dc71b248SHeiko Schocher {
643dc71b248SHeiko Schocher 	int len;
644dc71b248SHeiko Schocher 	int nodeoffset = 0;
645dc71b248SHeiko Schocher 
646dc71b248SHeiko Schocher 	nodeoffset = fdt_path_offset(blob, nodename);
647dc71b248SHeiko Schocher 	if (nodeoffset >= 0) {
648dc71b248SHeiko Schocher 		*var = (void *)fdt_getprop(blob, nodeoffset, propname, &len);
649dc71b248SHeiko Schocher 		if (len == 0) {
650dc71b248SHeiko Schocher 			/* no value */
651b11f53f3SHeiko Schocher 			printf("%s no value\n", __func__);
652dc71b248SHeiko Schocher 			return -1;
653dc71b248SHeiko Schocher 		} else if (len > 0) {
654dc71b248SHeiko Schocher 			return len;
655dc71b248SHeiko Schocher 		} else {
656dc71b248SHeiko Schocher 			printf("libfdt fdt_getprop(): %s\n",
657dc71b248SHeiko Schocher 				fdt_strerror(len));
658dc71b248SHeiko Schocher 			return -2;
659dc71b248SHeiko Schocher 		}
660dc71b248SHeiko Schocher 	} else {
661b11f53f3SHeiko Schocher 		printf("%s: cannot find %s node err:%s\n", __func__,
662dc71b248SHeiko Schocher 			nodename, fdt_strerror(nodeoffset));
663dc71b248SHeiko Schocher 		return -3;
664dc71b248SHeiko Schocher 	}
665dc71b248SHeiko Schocher }
6666250f0f6SHeiko Schocher #endif
667210c8c00SHeiko Schocher 
668802d9963SHolger Brunck #if !defined(MACH_TYPE_KM_KIRKWOOD)
669210c8c00SHeiko Schocher int ethernet_present(void)
670210c8c00SHeiko Schocher {
6718ed74341SHeiko Schocher 	struct km_bec_fpga *base =
6728ed74341SHeiko Schocher 		(struct km_bec_fpga *)CONFIG_SYS_KMBEC_FPGA_BASE;
673b11f53f3SHeiko Schocher 
674b11f53f3SHeiko Schocher 	return in_8(&base->bprth) & PIGGY_PRESENT;
675210c8c00SHeiko Schocher }
67667fa8c25SHeiko Schocher #endif
677210c8c00SHeiko Schocher 
678210c8c00SHeiko Schocher int board_eth_init(bd_t *bis)
679210c8c00SHeiko Schocher {
680210c8c00SHeiko Schocher #ifdef CONFIG_KEYMILE_HDLC_ENET
681210c8c00SHeiko Schocher 	(void)keymile_hdlc_enet_initialize(bis);
682210c8c00SHeiko Schocher #endif
683b11f53f3SHeiko Schocher 	if (ethernet_present())
68462ddcf05SHeiko Schocher 		return cpu_eth_init(bis);
68562ddcf05SHeiko Schocher 
686210c8c00SHeiko Schocher 	return -1;
687210c8c00SHeiko Schocher }
688