xref: /rk3399_rockchip-uboot/board/keymile/common/common.c (revision dc71b248ef0d5e12b19f33c6efb873e31df91fa9)
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>
25210c8c00SHeiko Schocher #if defined(CONFIG_MGCOGE)
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>
32210c8c00SHeiko Schocher #include <asm/io.h>
33c2485364SHeiko Schocher 
34c2485364SHeiko Schocher #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT)
35c2485364SHeiko Schocher #include <libfdt.h>
36c2485364SHeiko Schocher #endif
37c2485364SHeiko Schocher 
38c2485364SHeiko Schocher #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
39c2485364SHeiko Schocher #include <i2c.h>
40c2485364SHeiko Schocher 
41c2485364SHeiko Schocher extern int i2c_soft_read_pin (void);
42c2485364SHeiko Schocher 
438f64da7fSHeiko Schocher int ivm_calc_crc (unsigned char *buf, int len)
448f64da7fSHeiko Schocher {
458f64da7fSHeiko Schocher 	const unsigned short crc_tab[16] = {
468f64da7fSHeiko Schocher 		0x0000, 0xCC01, 0xD801, 0x1400,
478f64da7fSHeiko Schocher 		0xF001, 0x3C00, 0x2800, 0xE401,
488f64da7fSHeiko Schocher 		0xA001, 0x6C00, 0x7800, 0xB401,
498f64da7fSHeiko Schocher 		0x5000, 0x9C01, 0x8801, 0x4400};
508f64da7fSHeiko Schocher 
518f64da7fSHeiko Schocher 	unsigned short crc     = 0;   /* final result */
528f64da7fSHeiko Schocher 	unsigned short r1      = 0;   /* temp */
538f64da7fSHeiko Schocher 	unsigned char  byte    = 0;   /* input buffer */
548f64da7fSHeiko Schocher 	int	i;
558f64da7fSHeiko Schocher 
568f64da7fSHeiko Schocher 	/* calculate CRC from array data */
578f64da7fSHeiko Schocher 	for (i = 0; i < len; i++) {
588f64da7fSHeiko Schocher 		byte = buf[i];
598f64da7fSHeiko Schocher 
608f64da7fSHeiko Schocher 		/* lower 4 bits */
618f64da7fSHeiko Schocher 		r1 = crc_tab[crc & 0xF];
628f64da7fSHeiko Schocher 		crc = ((crc) >> 4) & 0x0FFF;
638f64da7fSHeiko Schocher 		crc = crc ^ r1 ^ crc_tab[byte & 0xF];
648f64da7fSHeiko Schocher 
658f64da7fSHeiko Schocher 		/* upper 4 bits */
668f64da7fSHeiko Schocher 		r1 = crc_tab[crc & 0xF];
678f64da7fSHeiko Schocher 		crc = (crc >> 4) & 0x0FFF;
688f64da7fSHeiko Schocher 		crc = crc ^ r1 ^ crc_tab[(byte >> 4) & 0xF];
698f64da7fSHeiko Schocher 	}
708f64da7fSHeiko Schocher 	return crc;
718f64da7fSHeiko Schocher }
728f64da7fSHeiko Schocher 
738f64da7fSHeiko Schocher static int  ivm_set_value (char *name, char *value)
748f64da7fSHeiko Schocher {
758f64da7fSHeiko Schocher 	char tempbuf[256];
768f64da7fSHeiko Schocher 
778f64da7fSHeiko Schocher 	if (value != NULL) {
788f64da7fSHeiko Schocher 		sprintf (tempbuf, "%s=%s", name, value);
798f64da7fSHeiko Schocher 		return set_local_var (tempbuf, 0);
808f64da7fSHeiko Schocher 	} else {
818f64da7fSHeiko Schocher 		unset_local_var (name);
828f64da7fSHeiko Schocher 	}
838f64da7fSHeiko Schocher 	return 0;
848f64da7fSHeiko Schocher }
858f64da7fSHeiko Schocher 
868f64da7fSHeiko Schocher static int ivm_get_value (unsigned char *buf, int len, char *name, int off,
878f64da7fSHeiko Schocher 				int check)
888f64da7fSHeiko Schocher {
898f64da7fSHeiko Schocher 	unsigned short	val;
908f64da7fSHeiko Schocher 	unsigned char	valbuf[30];
918f64da7fSHeiko Schocher 
928f64da7fSHeiko Schocher 	if ((buf[off + 0] != buf[off + 2]) &&
938f64da7fSHeiko Schocher 	    (buf[off + 2] != buf[off + 4])) {
948f64da7fSHeiko Schocher 		printf ("%s Error corrupted %s\n", __FUNCTION__, name);
958f64da7fSHeiko Schocher 		val = -1;
968f64da7fSHeiko Schocher 	} else {
978f64da7fSHeiko Schocher 		val = buf[off + 0] + (buf[off + 1] << 8);
988f64da7fSHeiko Schocher 		if ((val == 0) && (check == 1))
998f64da7fSHeiko Schocher 			val = -1;
1008f64da7fSHeiko Schocher 	}
1018f64da7fSHeiko Schocher 	sprintf ((char *)valbuf, "%x", val);
1028f64da7fSHeiko Schocher 	ivm_set_value (name, (char *)valbuf);
1038f64da7fSHeiko Schocher 	return val;
1048f64da7fSHeiko Schocher }
1058f64da7fSHeiko Schocher 
1068f64da7fSHeiko Schocher #define INVENTORYBLOCKSIZE	0x100
1078f64da7fSHeiko Schocher #define INVENTORYDATAADDRESS	0x21
1088f64da7fSHeiko Schocher #define INVENTORYDATASIZE	(INVENTORYBLOCKSIZE - INVENTORYDATAADDRESS - 3)
1098f64da7fSHeiko Schocher 
1108f64da7fSHeiko Schocher #define IVM_POS_SHORT_TEXT		0
1118f64da7fSHeiko Schocher #define IVM_POS_MANU_ID			1
1128f64da7fSHeiko Schocher #define IVM_POS_MANU_SERIAL		2
1138f64da7fSHeiko Schocher #define IVM_POS_PART_NUMBER		3
1148f64da7fSHeiko Schocher #define IVM_POS_BUILD_STATE		4
1158f64da7fSHeiko Schocher #define IVM_POS_SUPPLIER_PART_NUMBER	5
1168f64da7fSHeiko Schocher #define IVM_POS_DELIVERY_DATE		6
1178f64da7fSHeiko Schocher #define IVM_POS_SUPPLIER_BUILD_STATE	7
1188f64da7fSHeiko Schocher #define IVM_POS_CUSTOMER_ID		8
1198f64da7fSHeiko Schocher #define IVM_POS_CUSTOMER_PROD_ID	9
1208f64da7fSHeiko Schocher #define IVM_POS_HISTORY			10
1218f64da7fSHeiko Schocher #define IVM_POS_SYMBOL_ONLY		11
1228f64da7fSHeiko Schocher 
1238f64da7fSHeiko Schocher static char convert_char (char c)
1248f64da7fSHeiko Schocher {
1258f64da7fSHeiko Schocher 	return (c < ' ' || c > '~') ? '.' : c;
1268f64da7fSHeiko Schocher }
1278f64da7fSHeiko Schocher 
1288f64da7fSHeiko Schocher static int ivm_findinventorystring (int type,
1298f64da7fSHeiko Schocher 					unsigned char* const string,
1308f64da7fSHeiko Schocher 					unsigned long maxlen,
1318f64da7fSHeiko Schocher 					unsigned char *buf)
1328f64da7fSHeiko Schocher {
1338f64da7fSHeiko Schocher 	int xcode = 0;
1348f64da7fSHeiko Schocher 	unsigned long cr = 0;
1358f64da7fSHeiko Schocher 	unsigned long addr = INVENTORYDATAADDRESS;
1368f64da7fSHeiko Schocher 	unsigned long size = 0;
1378f64da7fSHeiko Schocher 	unsigned long nr = type;
1388f64da7fSHeiko Schocher 	int stop = 0; 	/* stop on semicolon */
1398f64da7fSHeiko Schocher 
1408f64da7fSHeiko Schocher 	memset(string, '\0', maxlen);
1418f64da7fSHeiko Schocher 	switch (type) {
1428f64da7fSHeiko Schocher 		case IVM_POS_SYMBOL_ONLY:
1438f64da7fSHeiko Schocher 			nr = 0;
1448f64da7fSHeiko Schocher 			stop= 1;
1458f64da7fSHeiko Schocher 		break;
1468f64da7fSHeiko Schocher 		default:
1478f64da7fSHeiko Schocher 			nr = type;
1488f64da7fSHeiko Schocher 			stop = 0;
1498f64da7fSHeiko Schocher 	}
1508f64da7fSHeiko Schocher 
1518f64da7fSHeiko Schocher 	/* Look for the requested number of CR. */
1528f64da7fSHeiko Schocher 	while ((cr != nr) && (addr < INVENTORYDATASIZE)) {
1538f64da7fSHeiko Schocher 		if ((buf[addr] == '\r')) {
1548f64da7fSHeiko Schocher 			cr++;
1558f64da7fSHeiko Schocher 		}
1568f64da7fSHeiko Schocher 		addr++;
1578f64da7fSHeiko Schocher 	}
1588f64da7fSHeiko Schocher 
1598f64da7fSHeiko Schocher 	/* the expected number of CR was found until the end of the IVM
1608f64da7fSHeiko Schocher 	 *  content --> fill string */
1618f64da7fSHeiko Schocher 	if (addr < INVENTORYDATASIZE) {
1628f64da7fSHeiko Schocher 		/* Copy the IVM string in the corresponding string */
1638f64da7fSHeiko Schocher 		for (; (buf[addr] != '\r')			&&
1648f64da7fSHeiko Schocher 			((buf[addr] != ';') ||  (!stop))	&&
1658f64da7fSHeiko Schocher 			(size < (maxlen - 1)			&&
1668f64da7fSHeiko Schocher 			(addr < INVENTORYDATASIZE)); addr++)
1678f64da7fSHeiko Schocher 		{
1688f64da7fSHeiko Schocher 			size += sprintf((char *)string + size, "%c",
1698f64da7fSHeiko Schocher 						convert_char (buf[addr]));
1708f64da7fSHeiko Schocher 		}
1718f64da7fSHeiko Schocher 
1728f64da7fSHeiko Schocher 		/* copy phase is done: check if everything is ok. If not,
1738f64da7fSHeiko Schocher 		 * the inventory data is most probably corrupted: tell
1748f64da7fSHeiko Schocher 		 * the world there is a problem! */
1758f64da7fSHeiko Schocher 		if (addr == INVENTORYDATASIZE) {
1768f64da7fSHeiko Schocher 			xcode = -1;
1778f64da7fSHeiko Schocher 			printf ("Error end of string not found\n");
1788f64da7fSHeiko Schocher 		} else if ((size >= (maxlen - 1)) &&
1798f64da7fSHeiko Schocher 			   (buf[addr] != '\r')) {
1808f64da7fSHeiko Schocher 			xcode = -1;
1818f64da7fSHeiko Schocher 			printf ("string too long till next CR\n");
1828f64da7fSHeiko Schocher 		}
1838f64da7fSHeiko Schocher 	} else {
1848f64da7fSHeiko Schocher 		/* some CR are missing...
1858f64da7fSHeiko Schocher 		 * the inventory data is most probably corrupted */
1868f64da7fSHeiko Schocher 		xcode = -1;
1878f64da7fSHeiko Schocher 		printf ("not enough cr found\n");
1888f64da7fSHeiko Schocher 	}
1898f64da7fSHeiko Schocher 	return xcode;
1908f64da7fSHeiko Schocher }
1918f64da7fSHeiko Schocher 
1928f64da7fSHeiko Schocher #define GET_STRING(name, which, len) \
1938f64da7fSHeiko Schocher 	if (ivm_findinventorystring (which, valbuf, len, buf) == 0) { \
1948f64da7fSHeiko Schocher 		ivm_set_value (name, (char *)valbuf); \
1958f64da7fSHeiko Schocher 	}
1968f64da7fSHeiko Schocher 
1978f64da7fSHeiko Schocher static int ivm_check_crc (unsigned char *buf, int block)
1988f64da7fSHeiko Schocher {
1998f64da7fSHeiko Schocher 	unsigned long	crc;
2008f64da7fSHeiko Schocher 	unsigned long	crceeprom;
2018f64da7fSHeiko Schocher 
2026d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	crc = ivm_calc_crc (buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 2);
2036d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	crceeprom = (buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 1] + \
2046d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 			buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 2] * 256);
2058f64da7fSHeiko Schocher 	if (crc != crceeprom) {
206*dc71b248SHeiko Schocher 		if (block == 0)
207*dc71b248SHeiko Schocher 			printf ("Error CRC Block: %d EEprom: calculated: \
208*dc71b248SHeiko Schocher 			%lx EEprom: %lx\n", block, crc, crceeprom);
2098f64da7fSHeiko Schocher 		return -1;
2108f64da7fSHeiko Schocher 	}
2118f64da7fSHeiko Schocher 	return 0;
2128f64da7fSHeiko Schocher }
2138f64da7fSHeiko Schocher 
2148f64da7fSHeiko Schocher static int ivm_analyze_block2 (unsigned char *buf, int len)
2158f64da7fSHeiko Schocher {
2166d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	unsigned char	valbuf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN];
2178f64da7fSHeiko Schocher 	unsigned long	count;
2188f64da7fSHeiko Schocher 
2198f64da7fSHeiko Schocher 	/* IVM_MacAddress */
2208f64da7fSHeiko Schocher 	sprintf ((char *)valbuf, "%02X:%02X:%02X:%02X:%02X:%02X",
2218f64da7fSHeiko Schocher 			buf[1],
2228f64da7fSHeiko Schocher 			buf[2],
2238f64da7fSHeiko Schocher 			buf[3],
2248f64da7fSHeiko Schocher 			buf[4],
2258f64da7fSHeiko Schocher 			buf[5],
2268f64da7fSHeiko Schocher 			buf[6]);
2278f64da7fSHeiko Schocher 	ivm_set_value ("IVM_MacAddress", (char *)valbuf);
2288f64da7fSHeiko Schocher 	if (getenv ("ethaddr") == NULL)
2298f64da7fSHeiko Schocher 		setenv ((char *)"ethaddr", (char *)valbuf);
2308f64da7fSHeiko Schocher 	/* IVM_MacCount */
2318f64da7fSHeiko Schocher 	count = (buf[10] << 24) +
2328f64da7fSHeiko Schocher 		   (buf[11] << 16) +
2338f64da7fSHeiko Schocher 		   (buf[12] << 8)  +
2348f64da7fSHeiko Schocher 		    buf[13];
2358f64da7fSHeiko Schocher 	if (count == 0xffffffff)
2368f64da7fSHeiko Schocher 		count = 1;
2378f64da7fSHeiko Schocher 	sprintf ((char *)valbuf, "%lx", count);
2388f64da7fSHeiko Schocher 	ivm_set_value ("IVM_MacCount", (char *)valbuf);
2398f64da7fSHeiko Schocher 	return 0;
2408f64da7fSHeiko Schocher }
2418f64da7fSHeiko Schocher 
2428f64da7fSHeiko Schocher int ivm_analyze_eeprom (unsigned char *buf, int len)
2438f64da7fSHeiko Schocher {
2448f64da7fSHeiko Schocher 	unsigned short	val;
2456d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	unsigned char	valbuf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN];
2468f64da7fSHeiko Schocher 	unsigned char	*tmp;
2478f64da7fSHeiko Schocher 
2488f64da7fSHeiko Schocher 	if (ivm_check_crc (buf, 0) != 0)
2498f64da7fSHeiko Schocher 		return -1;
2508f64da7fSHeiko Schocher 
2516d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	ivm_get_value (buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN, "IVM_BoardId", 0, 1);
2526d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	val = ivm_get_value (buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN, "IVM_HWKey", 6, 1);
2538f64da7fSHeiko Schocher 	if (val != 0xffff) {
2548f64da7fSHeiko Schocher 		sprintf ((char *)valbuf, "%x", ((val /100) % 10));
2558f64da7fSHeiko Schocher 		ivm_set_value ("IVM_HWVariant", (char *)valbuf);
2568f64da7fSHeiko Schocher 		sprintf ((char *)valbuf, "%x", (val % 100));
2578f64da7fSHeiko Schocher 		ivm_set_value ("IVM_HWVersion", (char *)valbuf);
2588f64da7fSHeiko Schocher 	}
2596d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	ivm_get_value (buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN, "IVM_Functions", 12, 0);
2608f64da7fSHeiko Schocher 
2618f64da7fSHeiko Schocher 	GET_STRING("IVM_Symbol", IVM_POS_SYMBOL_ONLY, 8)
2628f64da7fSHeiko Schocher 	GET_STRING("IVM_DeviceName", IVM_POS_SHORT_TEXT, 64)
2638f64da7fSHeiko Schocher 	tmp = (unsigned char *) getenv("IVM_DeviceName");
2648f64da7fSHeiko Schocher 	if (tmp) {
2658f64da7fSHeiko Schocher 		int	len = strlen ((char *)tmp);
2668f64da7fSHeiko Schocher 		int	i = 0;
2678f64da7fSHeiko Schocher 
2688f64da7fSHeiko Schocher 		while (i < len) {
2698f64da7fSHeiko Schocher 			if (tmp[i] == ';') {
2708f64da7fSHeiko Schocher 				ivm_set_value ("IVM_ShortText", (char *)&tmp[i + 1]);
2718f64da7fSHeiko Schocher 				break;
2728f64da7fSHeiko Schocher 			}
2738f64da7fSHeiko Schocher 			i++;
2748f64da7fSHeiko Schocher 		}
2758f64da7fSHeiko Schocher 		if (i >= len)
2768f64da7fSHeiko Schocher 			ivm_set_value ("IVM_ShortText", NULL);
2778f64da7fSHeiko Schocher 	} else {
2788f64da7fSHeiko Schocher 		ivm_set_value ("IVM_ShortText", NULL);
2798f64da7fSHeiko Schocher 	}
2808f64da7fSHeiko Schocher 	GET_STRING("IVM_ManufacturerID", IVM_POS_MANU_ID, 32)
2818f64da7fSHeiko Schocher 	GET_STRING("IVM_ManufacturerSerialNumber", IVM_POS_MANU_SERIAL, 20)
2828f64da7fSHeiko Schocher 	GET_STRING("IVM_ManufacturerPartNumber", IVM_POS_PART_NUMBER, 32)
2838f64da7fSHeiko Schocher 	GET_STRING("IVM_ManufacturerBuildState", IVM_POS_BUILD_STATE, 32)
2848f64da7fSHeiko Schocher 	GET_STRING("IVM_SupplierPartNumber", IVM_POS_SUPPLIER_PART_NUMBER, 32)
2858f64da7fSHeiko Schocher 	GET_STRING("IVM_DelieveryDate", IVM_POS_DELIVERY_DATE, 32)
2868f64da7fSHeiko Schocher 	GET_STRING("IVM_SupplierBuildState", IVM_POS_SUPPLIER_BUILD_STATE, 32)
2878f64da7fSHeiko Schocher 	GET_STRING("IVM_CustomerID", IVM_POS_CUSTOMER_ID, 32)
2888f64da7fSHeiko Schocher 	GET_STRING("IVM_CustomerProductID", IVM_POS_CUSTOMER_PROD_ID, 32)
2898f64da7fSHeiko Schocher 
2906d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	if (ivm_check_crc (&buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN * 2], 2) != 0)
291*dc71b248SHeiko Schocher 		return 0;
2926d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	ivm_analyze_block2 (&buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN * 2], CONFIG_SYS_IVM_EEPROM_PAGE_LEN);
2938f64da7fSHeiko Schocher 
2948f64da7fSHeiko Schocher 	return 0;
2958f64da7fSHeiko Schocher }
2968f64da7fSHeiko Schocher 
2978f64da7fSHeiko Schocher int ivm_read_eeprom (void)
2988f64da7fSHeiko Schocher {
2991b6275dfSHeiko Schocher #if defined(CONFIG_I2C_MUX)
3008f64da7fSHeiko Schocher 	I2C_MUX_DEVICE *dev = NULL;
3011b6275dfSHeiko Schocher #endif
3026d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	uchar i2c_buffer[CONFIG_SYS_IVM_EEPROM_MAX_LEN];
3038f64da7fSHeiko Schocher 	uchar	*buf;
3046d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	unsigned dev_addr = CONFIG_SYS_IVM_EEPROM_ADR;
3058f64da7fSHeiko Schocher 
3061b6275dfSHeiko Schocher #if defined(CONFIG_I2C_MUX)
3078f64da7fSHeiko Schocher 	/* First init the Bus, select the Bus */
3086d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_SYS_I2C_IVM_BUS)
3096d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	dev = i2c_mux_ident_muxstring ((uchar *)CONFIG_SYS_I2C_IVM_BUS);
3108f64da7fSHeiko Schocher #else
3118f64da7fSHeiko Schocher 	buf = (unsigned char *) getenv ("EEprom_ivm");
3128f64da7fSHeiko Schocher 	if (buf != NULL)
3138f64da7fSHeiko Schocher 		dev = i2c_mux_ident_muxstring (buf);
3148f64da7fSHeiko Schocher #endif
3158f64da7fSHeiko Schocher 	if (dev == NULL) {
3168f64da7fSHeiko Schocher 		printf ("Error couldnt add Bus for IVM\n");
3178f64da7fSHeiko Schocher 		return -1;
3188f64da7fSHeiko Schocher 	}
3198f64da7fSHeiko Schocher 	i2c_set_bus_num (dev->busid);
3201b6275dfSHeiko Schocher #endif
3218f64da7fSHeiko Schocher 
3228f64da7fSHeiko Schocher 	buf = (unsigned char *) getenv ("EEprom_ivm_addr");
3238f64da7fSHeiko Schocher 	if (buf != NULL)
3248f64da7fSHeiko Schocher 		dev_addr = simple_strtoul ((char *)buf, NULL, 16);
3258f64da7fSHeiko Schocher 
32619f0e930SHeiko Schocher 	if (i2c_read(dev_addr, 0, 1, i2c_buffer, CONFIG_SYS_IVM_EEPROM_MAX_LEN) != 0) {
3278f64da7fSHeiko Schocher 		printf ("Error reading EEprom\n");
3288f64da7fSHeiko Schocher 		return -2;
3298f64da7fSHeiko Schocher 	}
3308f64da7fSHeiko Schocher 
3316d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	return ivm_analyze_eeprom (i2c_buffer, CONFIG_SYS_IVM_EEPROM_MAX_LEN);
3328f64da7fSHeiko Schocher }
3338f64da7fSHeiko Schocher 
3346d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_SYS_I2C_INIT_BOARD)
335c2485364SHeiko Schocher #define DELAY_ABORT_SEQ		62
3366d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #define DELAY_HALF_PERIOD	(500 / (CONFIG_SYS_I2C_SPEED / 1000))
337c2485364SHeiko Schocher 
338c2485364SHeiko Schocher #if defined(CONFIG_MGCOGE)
339c2485364SHeiko Schocher #define SDA_MASK	0x00010000
340c2485364SHeiko Schocher #define SCL_MASK	0x00020000
341c2485364SHeiko Schocher static void set_pin (int state, unsigned long mask)
342c2485364SHeiko Schocher {
3436d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	volatile ioport_t *iop = ioport_addr ((immap_t *)CONFIG_SYS_IMMR, 3);
344c2485364SHeiko Schocher 
345c2485364SHeiko Schocher 	if (state)
346c2485364SHeiko Schocher 		iop->pdat |= (mask);
347c2485364SHeiko Schocher 	else
348c2485364SHeiko Schocher 		iop->pdat &= ~(mask);
349c2485364SHeiko Schocher 
350c2485364SHeiko Schocher 	iop->pdir |= (mask);
351c2485364SHeiko Schocher }
352c2485364SHeiko Schocher 
353c2485364SHeiko Schocher static int get_pin (unsigned long mask)
354c2485364SHeiko Schocher {
3556d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	volatile ioport_t *iop = ioport_addr ((immap_t *)CONFIG_SYS_IMMR, 3);
356c2485364SHeiko Schocher 
357c2485364SHeiko Schocher 	iop->pdir &= ~(mask);
358c2485364SHeiko Schocher 	return (0 != (iop->pdat & (mask)));
359c2485364SHeiko Schocher }
360c2485364SHeiko Schocher 
361c2485364SHeiko Schocher static void set_sda (int state)
362c2485364SHeiko Schocher {
363c2485364SHeiko Schocher 	set_pin (state, SDA_MASK);
364c2485364SHeiko Schocher }
365c2485364SHeiko Schocher 
366c2485364SHeiko Schocher static void set_scl (int state)
367c2485364SHeiko Schocher {
368c2485364SHeiko Schocher 	set_pin (state, SCL_MASK);
369c2485364SHeiko Schocher }
370c2485364SHeiko Schocher 
371c2485364SHeiko Schocher static int get_sda (void)
372c2485364SHeiko Schocher {
373c2485364SHeiko Schocher 	return get_pin (SDA_MASK);
374c2485364SHeiko Schocher }
375c2485364SHeiko Schocher 
376c2485364SHeiko Schocher static int get_scl (void)
377c2485364SHeiko Schocher {
378c2485364SHeiko Schocher 	return get_pin (SCL_MASK);
379c2485364SHeiko Schocher }
380c2485364SHeiko Schocher 
381c2485364SHeiko Schocher #if defined(CONFIG_HARD_I2C)
382c2485364SHeiko Schocher static void setports (int gpio)
383c2485364SHeiko Schocher {
3846d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	volatile ioport_t *iop = ioport_addr ((immap_t *)CONFIG_SYS_IMMR, 3);
385c2485364SHeiko Schocher 
386c2485364SHeiko Schocher 	if (gpio) {
387c2485364SHeiko Schocher 		iop->ppar &= ~(SDA_MASK | SCL_MASK);
388c2485364SHeiko Schocher 		iop->podr &= ~(SDA_MASK | SCL_MASK);
389c2485364SHeiko Schocher 	} else {
390c2485364SHeiko Schocher 		iop->ppar |= (SDA_MASK | SCL_MASK);
391c2485364SHeiko Schocher 		iop->pdir &= ~(SDA_MASK | SCL_MASK);
392c2485364SHeiko Schocher 		iop->podr |= (SDA_MASK | SCL_MASK);
393c2485364SHeiko Schocher 	}
394c2485364SHeiko Schocher }
395c2485364SHeiko Schocher #endif
396c2485364SHeiko Schocher #endif
397c2485364SHeiko Schocher 
398d044954fSHeiko Schocher #if defined(CONFIG_KM8XX)
399c2485364SHeiko Schocher static void set_sda (int state)
400c2485364SHeiko Schocher {
401c2485364SHeiko Schocher 	I2C_SDA(state);
402c2485364SHeiko Schocher }
403c2485364SHeiko Schocher 
404c2485364SHeiko Schocher static void set_scl (int state)
405c2485364SHeiko Schocher {
406c2485364SHeiko Schocher 	I2C_SCL(state);
407c2485364SHeiko Schocher }
408c2485364SHeiko Schocher 
409c2485364SHeiko Schocher static int get_sda (void)
410c2485364SHeiko Schocher {
411a21ca95fSHeiko Schocher 	return I2C_READ;
412c2485364SHeiko Schocher }
413c2485364SHeiko Schocher 
414c2485364SHeiko Schocher static int get_scl (void)
415c2485364SHeiko Schocher {
416c2485364SHeiko Schocher 	int	val;
417c2485364SHeiko Schocher 
418c2485364SHeiko Schocher 	*(unsigned short *)(I2C_BASE_DIR) &=  ~SCL_CONF;
419c2485364SHeiko Schocher 	udelay (1);
420c2485364SHeiko Schocher 	val = *(unsigned char *)(I2C_BASE_PORT);
421c2485364SHeiko Schocher 
422c2485364SHeiko Schocher 	return ((val & SCL_BIT) == SCL_BIT);
423c2485364SHeiko Schocher }
424c2485364SHeiko Schocher 
425c2485364SHeiko Schocher #endif
426c2485364SHeiko Schocher 
427c2485364SHeiko Schocher static void writeStartSeq (void)
428c2485364SHeiko Schocher {
429c2485364SHeiko Schocher 	set_sda (1);
430c2485364SHeiko Schocher 	udelay (DELAY_HALF_PERIOD);
431c2485364SHeiko Schocher 	set_scl (1);
432c2485364SHeiko Schocher 	udelay (DELAY_HALF_PERIOD);
433c2485364SHeiko Schocher 	set_sda (0);
434c2485364SHeiko Schocher 	udelay (DELAY_HALF_PERIOD);
435c2485364SHeiko Schocher 	set_scl (0);
436c2485364SHeiko Schocher 	udelay (DELAY_HALF_PERIOD);
437c2485364SHeiko Schocher }
438c2485364SHeiko Schocher 
439c2485364SHeiko Schocher /* I2C is a synchronous protocol and resets of the processor in the middle
440c2485364SHeiko Schocher    of an access can block the I2C Bus until a powerdown of the full unit is
441c2485364SHeiko Schocher    done. This function toggles the SCL until the SCL and SCA line are
442c2485364SHeiko Schocher    released, but max. 16 times, after this a I2C start-sequence is sent.
443c2485364SHeiko Schocher    This I2C Deblocking mechanism was developed by Keymile in association
444c2485364SHeiko Schocher    with Anatech and Atmel in 1998.
445c2485364SHeiko Schocher  */
446c2485364SHeiko Schocher static int i2c_make_abort (void)
447c2485364SHeiko Schocher {
448c2485364SHeiko Schocher 	int	scl_state = 0;
449c2485364SHeiko Schocher 	int	sda_state = 0;
450c2485364SHeiko Schocher 	int	i = 0;
451c2485364SHeiko Schocher 	int	ret = 0;
452c2485364SHeiko Schocher 
453c2485364SHeiko Schocher 	if (!get_sda ()) {
454c2485364SHeiko Schocher 		ret = -1;
455c2485364SHeiko Schocher 		while (i < 16) {
456c2485364SHeiko Schocher 			i++;
457c2485364SHeiko Schocher 			set_scl (0);
458c2485364SHeiko Schocher 			udelay (DELAY_ABORT_SEQ);
459c2485364SHeiko Schocher 			set_scl (1);
460c2485364SHeiko Schocher 			udelay (DELAY_ABORT_SEQ);
461c2485364SHeiko Schocher 			scl_state = get_scl ();
462c2485364SHeiko Schocher 			sda_state = get_sda ();
463c2485364SHeiko Schocher 			if (scl_state && sda_state) {
464c2485364SHeiko Schocher 				ret = 0;
465c2485364SHeiko Schocher 				break;
466c2485364SHeiko Schocher 			}
467c2485364SHeiko Schocher 		}
468c2485364SHeiko Schocher 	}
469c2485364SHeiko Schocher 	if (ret == 0) {
470c2485364SHeiko Schocher 		for (i =0; i < 5; i++) {
471c2485364SHeiko Schocher 			writeStartSeq ();
472c2485364SHeiko Schocher 		}
473c2485364SHeiko Schocher 	}
474c2485364SHeiko Schocher 	get_sda ();
475c2485364SHeiko Schocher 	return ret;
476c2485364SHeiko Schocher }
477c2485364SHeiko Schocher 
478c2485364SHeiko Schocher /**
479c2485364SHeiko Schocher  * i2c_init_board - reset i2c bus. When the board is powercycled during a
480c2485364SHeiko Schocher  * bus transfer it might hang; for details see doc/I2C_Edge_Conditions.
481c2485364SHeiko Schocher  */
482c2485364SHeiko Schocher void i2c_init_board(void)
483c2485364SHeiko Schocher {
484c2485364SHeiko Schocher #if defined(CONFIG_HARD_I2C)
4856d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR ;
486c2485364SHeiko Schocher 	volatile i2c8260_t *i2c	= (i2c8260_t *)&immap->im_i2c;
487c2485364SHeiko Schocher 
488c2485364SHeiko Schocher 	/* disable I2C controller first, otherwhise it thinks we want to    */
489c2485364SHeiko Schocher 	/* talk to the slave port...                                        */
490c2485364SHeiko Schocher 	i2c->i2c_i2mod &= ~0x01;
491c2485364SHeiko Schocher 
492c2485364SHeiko Schocher 	/* Set the PortPins to GPIO */
493c2485364SHeiko Schocher 	setports (1);
494c2485364SHeiko Schocher #endif
495c2485364SHeiko Schocher 
496c2485364SHeiko Schocher 	/* Now run the AbortSequence() */
497c2485364SHeiko Schocher 	i2c_make_abort ();
498c2485364SHeiko Schocher 
499c2485364SHeiko Schocher #if defined(CONFIG_HARD_I2C)
500c2485364SHeiko Schocher 	/* Set the PortPins back to use for I2C */
501c2485364SHeiko Schocher 	setports (0);
502c2485364SHeiko Schocher #endif
503c2485364SHeiko Schocher }
504c2485364SHeiko Schocher #endif
505210c8c00SHeiko Schocher #endif
5066250f0f6SHeiko Schocher 
5076250f0f6SHeiko Schocher #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT)
5086250f0f6SHeiko Schocher int fdt_set_node_and_value (void *blob,
5096250f0f6SHeiko Schocher 				char *nodename,
5106250f0f6SHeiko Schocher 				char *regname,
5116250f0f6SHeiko Schocher 				void *var,
5126250f0f6SHeiko Schocher 				int size)
5136250f0f6SHeiko Schocher {
5146250f0f6SHeiko Schocher 	int ret = 0;
5156250f0f6SHeiko Schocher 	int nodeoffset = 0;
5166250f0f6SHeiko Schocher 
5176250f0f6SHeiko Schocher 	nodeoffset = fdt_path_offset (blob, nodename);
5186250f0f6SHeiko Schocher 	if (nodeoffset >= 0) {
5196250f0f6SHeiko Schocher 		ret = fdt_setprop (blob, nodeoffset, regname, var,
5206250f0f6SHeiko Schocher 					size);
5216250f0f6SHeiko Schocher 		if (ret < 0)
5226250f0f6SHeiko Schocher 			printf("ft_blob_update(): cannot set %s/%s "
5236250f0f6SHeiko Schocher 				"property err:%s\n", nodename, regname,
5246250f0f6SHeiko Schocher 				fdt_strerror (ret));
5256250f0f6SHeiko Schocher 	} else {
5266250f0f6SHeiko Schocher 		printf("ft_blob_update(): cannot find %s node "
5276250f0f6SHeiko Schocher 			"err:%s\n", nodename, fdt_strerror (nodeoffset));
5286250f0f6SHeiko Schocher 	}
5296250f0f6SHeiko Schocher 	return ret;
5306250f0f6SHeiko Schocher }
531*dc71b248SHeiko Schocher int fdt_get_node_and_value (void *blob,
532*dc71b248SHeiko Schocher 				char *nodename,
533*dc71b248SHeiko Schocher 				char *propname,
534*dc71b248SHeiko Schocher 				void **var)
535*dc71b248SHeiko Schocher {
536*dc71b248SHeiko Schocher 	int len;
537*dc71b248SHeiko Schocher 	int nodeoffset = 0;
538*dc71b248SHeiko Schocher 
539*dc71b248SHeiko Schocher 	nodeoffset = fdt_path_offset (blob, nodename);
540*dc71b248SHeiko Schocher 	if (nodeoffset >= 0) {
541*dc71b248SHeiko Schocher 		*var = (void *)fdt_getprop (blob, nodeoffset, propname, &len);
542*dc71b248SHeiko Schocher 		if (len == 0) {
543*dc71b248SHeiko Schocher 			/* no value */
544*dc71b248SHeiko Schocher 			printf ("%s no value\n", __FUNCTION__);
545*dc71b248SHeiko Schocher 			return -1;
546*dc71b248SHeiko Schocher 		} else if (len > 0) {
547*dc71b248SHeiko Schocher 			return len;
548*dc71b248SHeiko Schocher 		} else {
549*dc71b248SHeiko Schocher 			printf ("libfdt fdt_getprop(): %s\n",
550*dc71b248SHeiko Schocher 				fdt_strerror(len));
551*dc71b248SHeiko Schocher 			return -2;
552*dc71b248SHeiko Schocher 		}
553*dc71b248SHeiko Schocher 	} else {
554*dc71b248SHeiko Schocher 		printf("%s: cannot find %s node err:%s\n", __FUNCTION__,
555*dc71b248SHeiko Schocher 			nodename, fdt_strerror (nodeoffset));
556*dc71b248SHeiko Schocher 		return -3;
557*dc71b248SHeiko Schocher 	}
558*dc71b248SHeiko Schocher }
5596250f0f6SHeiko Schocher #endif
560210c8c00SHeiko Schocher 
561210c8c00SHeiko Schocher int ethernet_present (void)
562210c8c00SHeiko Schocher {
563210c8c00SHeiko Schocher 	return (in_8((u8 *)CONFIG_SYS_PIGGY_BASE + CONFIG_SYS_SLOT_ID_OFF) & 0x80);
564210c8c00SHeiko Schocher }
565210c8c00SHeiko Schocher 
566210c8c00SHeiko Schocher int board_eth_init (bd_t *bis)
567210c8c00SHeiko Schocher {
568210c8c00SHeiko Schocher #ifdef CONFIG_KEYMILE_HDLC_ENET
569210c8c00SHeiko Schocher 	(void)keymile_hdlc_enet_initialize (bis);
570210c8c00SHeiko Schocher #endif
571210c8c00SHeiko Schocher 	if (ethernet_present ()) {
572210c8c00SHeiko Schocher 		return -1;
573210c8c00SHeiko Schocher 	}
574210c8c00SHeiko Schocher 	return 0;
575210c8c00SHeiko Schocher }
576