xref: /rk3399_rockchip-uboot/board/keymile/common/common.c (revision 6c11aeafeff8e0aa0b381baf5bcb1807de77e42e)
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 
43*6c11aeafSHeiko Schocher static void i2c_write_start_seq(void);
44*6c11aeafSHeiko Schocher static int i2c_make_abort(void);
45*6c11aeafSHeiko Schocher 
468f64da7fSHeiko Schocher int ivm_calc_crc(unsigned char *buf, int len)
478f64da7fSHeiko Schocher {
488f64da7fSHeiko Schocher 	const unsigned short crc_tab[16] = {
498f64da7fSHeiko Schocher 		0x0000, 0xCC01, 0xD801, 0x1400,
508f64da7fSHeiko Schocher 		0xF001, 0x3C00, 0x2800, 0xE401,
518f64da7fSHeiko Schocher 		0xA001, 0x6C00, 0x7800, 0xB401,
528f64da7fSHeiko Schocher 		0x5000, 0x9C01, 0x8801, 0x4400};
538f64da7fSHeiko Schocher 
548f64da7fSHeiko Schocher 	unsigned short crc     = 0;   /* final result */
558f64da7fSHeiko Schocher 	unsigned short r1      = 0;   /* temp */
568f64da7fSHeiko Schocher 	unsigned char  byte    = 0;   /* input buffer */
578f64da7fSHeiko Schocher 	int	i;
588f64da7fSHeiko Schocher 
598f64da7fSHeiko Schocher 	/* calculate CRC from array data */
608f64da7fSHeiko Schocher 	for (i = 0; i < len; i++) {
618f64da7fSHeiko Schocher 		byte = buf[i];
628f64da7fSHeiko Schocher 
638f64da7fSHeiko Schocher 		/* lower 4 bits */
648f64da7fSHeiko Schocher 		r1 = crc_tab[crc & 0xF];
658f64da7fSHeiko Schocher 		crc = ((crc) >> 4) & 0x0FFF;
668f64da7fSHeiko Schocher 		crc = crc ^ r1 ^ crc_tab[byte & 0xF];
678f64da7fSHeiko Schocher 
688f64da7fSHeiko Schocher 		/* upper 4 bits */
698f64da7fSHeiko Schocher 		r1 = crc_tab[crc & 0xF];
708f64da7fSHeiko Schocher 		crc = (crc >> 4) & 0x0FFF;
718f64da7fSHeiko Schocher 		crc = crc ^ r1 ^ crc_tab[(byte >> 4) & 0xF];
728f64da7fSHeiko Schocher 	}
738f64da7fSHeiko Schocher 	return crc;
748f64da7fSHeiko Schocher }
758f64da7fSHeiko Schocher 
768f64da7fSHeiko Schocher static int ivm_set_value(char *name, char *value)
778f64da7fSHeiko Schocher {
788f64da7fSHeiko Schocher 	char tempbuf[256];
798f64da7fSHeiko Schocher 
808f64da7fSHeiko Schocher 	if (value != NULL) {
818f64da7fSHeiko Schocher 		sprintf(tempbuf, "%s=%s", name, value);
828f64da7fSHeiko Schocher 		return set_local_var(tempbuf, 0);
838f64da7fSHeiko Schocher 	} else {
848f64da7fSHeiko Schocher 		unset_local_var(name);
858f64da7fSHeiko Schocher 	}
868f64da7fSHeiko Schocher 	return 0;
878f64da7fSHeiko Schocher }
888f64da7fSHeiko Schocher 
898f64da7fSHeiko Schocher static int ivm_get_value(unsigned char *buf, int len, char *name, int off,
908f64da7fSHeiko Schocher 				int check)
918f64da7fSHeiko Schocher {
928f64da7fSHeiko Schocher 	unsigned short	val;
938f64da7fSHeiko Schocher 	unsigned char	valbuf[30];
948f64da7fSHeiko Schocher 
958f64da7fSHeiko Schocher 	if ((buf[off + 0] != buf[off + 2]) &&
968f64da7fSHeiko Schocher 	    (buf[off + 2] != buf[off + 4])) {
97b11f53f3SHeiko Schocher 		printf("%s Error corrupted %s\n", __func__, name);
988f64da7fSHeiko Schocher 		val = -1;
998f64da7fSHeiko Schocher 	} else {
1008f64da7fSHeiko Schocher 		val = buf[off + 0] + (buf[off + 1] << 8);
1018f64da7fSHeiko Schocher 		if ((val == 0) && (check == 1))
1028f64da7fSHeiko Schocher 			val = -1;
1038f64da7fSHeiko Schocher 	}
1048f64da7fSHeiko Schocher 	sprintf((char *)valbuf, "%x", val);
1058f64da7fSHeiko Schocher 	ivm_set_value(name, (char *)valbuf);
1068f64da7fSHeiko Schocher 	return val;
1078f64da7fSHeiko Schocher }
1088f64da7fSHeiko Schocher 
109b11f53f3SHeiko Schocher #define INV_BLOCKSIZE		0x100
110b11f53f3SHeiko Schocher #define INV_DATAADDRESS		0x21
111b11f53f3SHeiko Schocher #define INVENTORYDATASIZE	(INV_BLOCKSIZE - INV_DATAADDRESS - 3)
1128f64da7fSHeiko Schocher 
1138f64da7fSHeiko Schocher #define IVM_POS_SHORT_TEXT		0
1148f64da7fSHeiko Schocher #define IVM_POS_MANU_ID			1
1158f64da7fSHeiko Schocher #define IVM_POS_MANU_SERIAL		2
1168f64da7fSHeiko Schocher #define IVM_POS_PART_NUMBER		3
1178f64da7fSHeiko Schocher #define IVM_POS_BUILD_STATE		4
1188f64da7fSHeiko Schocher #define IVM_POS_SUPPLIER_PART_NUMBER	5
1198f64da7fSHeiko Schocher #define IVM_POS_DELIVERY_DATE		6
1208f64da7fSHeiko Schocher #define IVM_POS_SUPPLIER_BUILD_STATE	7
1218f64da7fSHeiko Schocher #define IVM_POS_CUSTOMER_ID		8
1228f64da7fSHeiko Schocher #define IVM_POS_CUSTOMER_PROD_ID	9
1238f64da7fSHeiko Schocher #define IVM_POS_HISTORY			10
1248f64da7fSHeiko Schocher #define IVM_POS_SYMBOL_ONLY		11
1258f64da7fSHeiko Schocher 
1268f64da7fSHeiko Schocher static char convert_char(char c)
1278f64da7fSHeiko Schocher {
1288f64da7fSHeiko Schocher 	return (c < ' ' || c > '~') ? '.' : c;
1298f64da7fSHeiko Schocher }
1308f64da7fSHeiko Schocher 
1318f64da7fSHeiko Schocher static int ivm_findinventorystring(int type,
1328f64da7fSHeiko Schocher 					unsigned char* const string,
1338f64da7fSHeiko Schocher 					unsigned long maxlen,
1348f64da7fSHeiko Schocher 					unsigned char *buf)
1358f64da7fSHeiko Schocher {
1368f64da7fSHeiko Schocher 	int xcode = 0;
1378f64da7fSHeiko Schocher 	unsigned long cr = 0;
138b11f53f3SHeiko Schocher 	unsigned long addr = INV_DATAADDRESS;
1398f64da7fSHeiko Schocher 	unsigned long size = 0;
1408f64da7fSHeiko Schocher 	unsigned long nr = type;
1418f64da7fSHeiko Schocher 	int stop = 0; 	/* stop on semicolon */
1428f64da7fSHeiko Schocher 
1438f64da7fSHeiko Schocher 	memset(string, '\0', maxlen);
1448f64da7fSHeiko Schocher 	switch (type) {
1458f64da7fSHeiko Schocher 		case IVM_POS_SYMBOL_ONLY:
1468f64da7fSHeiko Schocher 			nr = 0;
1478f64da7fSHeiko Schocher 			stop= 1;
1488f64da7fSHeiko Schocher 		break;
1498f64da7fSHeiko Schocher 		default:
1508f64da7fSHeiko Schocher 			nr = type;
1518f64da7fSHeiko Schocher 			stop = 0;
1528f64da7fSHeiko Schocher 	}
1538f64da7fSHeiko Schocher 
1548f64da7fSHeiko Schocher 	/* Look for the requested number of CR. */
1558f64da7fSHeiko Schocher 	while ((cr != nr) && (addr < INVENTORYDATASIZE)) {
1568f64da7fSHeiko Schocher 		if ((buf[addr] == '\r')) {
1578f64da7fSHeiko Schocher 			cr++;
1588f64da7fSHeiko Schocher 		}
1598f64da7fSHeiko Schocher 		addr++;
1608f64da7fSHeiko Schocher 	}
1618f64da7fSHeiko Schocher 
162b11f53f3SHeiko Schocher 	/*
163b11f53f3SHeiko Schocher 	 * the expected number of CR was found until the end of the IVM
164b11f53f3SHeiko Schocher 	 *  content --> fill string
165b11f53f3SHeiko Schocher 	 */
1668f64da7fSHeiko Schocher 	if (addr < INVENTORYDATASIZE) {
1678f64da7fSHeiko Schocher 		/* Copy the IVM string in the corresponding string */
1688f64da7fSHeiko Schocher 		for (; (buf[addr] != '\r')			&&
1698f64da7fSHeiko Schocher 			((buf[addr] != ';') ||  (!stop))	&&
1708f64da7fSHeiko Schocher 			(size < (maxlen - 1)			&&
1718f64da7fSHeiko Schocher 			(addr < INVENTORYDATASIZE)); addr++)
1728f64da7fSHeiko Schocher 		{
1738f64da7fSHeiko Schocher 			size += sprintf((char *)string + size, "%c",
1748f64da7fSHeiko Schocher 						convert_char (buf[addr]));
1758f64da7fSHeiko Schocher 		}
1768f64da7fSHeiko Schocher 
177b11f53f3SHeiko Schocher 		/*
178b11f53f3SHeiko Schocher 		 * copy phase is done: check if everything is ok. If not,
1798f64da7fSHeiko Schocher 		 * the inventory data is most probably corrupted: tell
180b11f53f3SHeiko Schocher 		 * the world there is a problem!
181b11f53f3SHeiko Schocher 		 */
1828f64da7fSHeiko Schocher 		if (addr == INVENTORYDATASIZE) {
1838f64da7fSHeiko Schocher 			xcode = -1;
1848f64da7fSHeiko Schocher 			printf("Error end of string not found\n");
1858f64da7fSHeiko Schocher 		} else if ((size >= (maxlen - 1)) &&
1868f64da7fSHeiko Schocher 			   (buf[addr] != '\r')) {
1878f64da7fSHeiko Schocher 			xcode = -1;
1888f64da7fSHeiko Schocher 			printf("string too long till next CR\n");
1898f64da7fSHeiko Schocher 		}
1908f64da7fSHeiko Schocher 	} else {
191b11f53f3SHeiko Schocher 		/*
192b11f53f3SHeiko Schocher 		 * some CR are missing...
193b11f53f3SHeiko Schocher 		 * the inventory data is most probably corrupted
194b11f53f3SHeiko Schocher 		 */
1958f64da7fSHeiko Schocher 		xcode = -1;
1968f64da7fSHeiko Schocher 		printf("not enough cr found\n");
1978f64da7fSHeiko Schocher 	}
1988f64da7fSHeiko Schocher 	return xcode;
1998f64da7fSHeiko Schocher }
2008f64da7fSHeiko Schocher 
2018f64da7fSHeiko Schocher #define GET_STRING(name, which, len) \
2028f64da7fSHeiko Schocher 	if (ivm_findinventorystring(which, valbuf, len, buf) == 0) { \
2038f64da7fSHeiko Schocher 		ivm_set_value(name, (char *)valbuf); \
2048f64da7fSHeiko Schocher 	}
2058f64da7fSHeiko Schocher 
2068f64da7fSHeiko Schocher static int ivm_check_crc(unsigned char *buf, int block)
2078f64da7fSHeiko Schocher {
2088f64da7fSHeiko Schocher 	unsigned long	crc;
2098f64da7fSHeiko Schocher 	unsigned long	crceeprom;
2108f64da7fSHeiko Schocher 
2116d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	crc = ivm_calc_crc(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 2);
2126d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	crceeprom = (buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 1] + \
2136d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 			buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 2] * 256);
2148f64da7fSHeiko Schocher 	if (crc != crceeprom) {
215dc71b248SHeiko Schocher 		if (block == 0)
216dc71b248SHeiko Schocher 			printf("Error CRC Block: %d EEprom: calculated: \
217dc71b248SHeiko Schocher 			%lx EEprom: %lx\n", block, crc, crceeprom);
2188f64da7fSHeiko Schocher 		return -1;
2198f64da7fSHeiko Schocher 	}
2208f64da7fSHeiko Schocher 	return 0;
2218f64da7fSHeiko Schocher }
2228f64da7fSHeiko Schocher 
2238f64da7fSHeiko Schocher static int ivm_analyze_block2(unsigned char *buf, int len)
2248f64da7fSHeiko Schocher {
2256d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	unsigned char	valbuf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN];
2268f64da7fSHeiko Schocher 	unsigned long	count;
2278f64da7fSHeiko Schocher 
2288f64da7fSHeiko Schocher 	/* IVM_MacAddress */
229b11f53f3SHeiko Schocher 	sprintf((char *)valbuf, "%pM", buf);
2308f64da7fSHeiko Schocher 	ivm_set_value("IVM_MacAddress", (char *)valbuf);
2318f64da7fSHeiko Schocher 	if (getenv("ethaddr") == NULL)
2328f64da7fSHeiko Schocher 		setenv((char *)"ethaddr", (char *)valbuf);
2338f64da7fSHeiko Schocher 	/* IVM_MacCount */
2348f64da7fSHeiko Schocher 	count = (buf[10] << 24) +
2358f64da7fSHeiko Schocher 		   (buf[11] << 16) +
2368f64da7fSHeiko Schocher 		   (buf[12] << 8)  +
2378f64da7fSHeiko Schocher 		    buf[13];
2388f64da7fSHeiko Schocher 	if (count == 0xffffffff)
2398f64da7fSHeiko Schocher 		count = 1;
2408f64da7fSHeiko Schocher 	sprintf((char *)valbuf, "%lx", count);
2418f64da7fSHeiko Schocher 	ivm_set_value("IVM_MacCount", (char *)valbuf);
2428f64da7fSHeiko Schocher 	return 0;
2438f64da7fSHeiko Schocher }
2448f64da7fSHeiko Schocher 
2458f64da7fSHeiko Schocher int ivm_analyze_eeprom(unsigned char *buf, int len)
2468f64da7fSHeiko Schocher {
2478f64da7fSHeiko Schocher 	unsigned short	val;
2486d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	unsigned char	valbuf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN];
2498f64da7fSHeiko Schocher 	unsigned char	*tmp;
2508f64da7fSHeiko Schocher 
2518f64da7fSHeiko Schocher 	if (ivm_check_crc(buf, 0) != 0)
2528f64da7fSHeiko Schocher 		return -1;
2538f64da7fSHeiko Schocher 
254b11f53f3SHeiko Schocher 	ivm_get_value(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN,
255b11f53f3SHeiko Schocher 			"IVM_BoardId", 0, 1);
256b11f53f3SHeiko Schocher 	val = ivm_get_value(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN,
257b11f53f3SHeiko Schocher 			"IVM_HWKey", 6, 1);
2588f64da7fSHeiko Schocher 	if (val != 0xffff) {
2598f64da7fSHeiko Schocher 		sprintf((char *)valbuf, "%x", ((val / 100) % 10));
2608f64da7fSHeiko Schocher 		ivm_set_value("IVM_HWVariant", (char *)valbuf);
2618f64da7fSHeiko Schocher 		sprintf((char *)valbuf, "%x", (val % 100));
2628f64da7fSHeiko Schocher 		ivm_set_value("IVM_HWVersion", (char *)valbuf);
2638f64da7fSHeiko Schocher 	}
264b11f53f3SHeiko Schocher 	ivm_get_value(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN,
265b11f53f3SHeiko Schocher 		"IVM_Functions", 12, 0);
2668f64da7fSHeiko Schocher 
2678f64da7fSHeiko Schocher 	GET_STRING("IVM_Symbol", IVM_POS_SYMBOL_ONLY, 8)
2688f64da7fSHeiko Schocher 	GET_STRING("IVM_DeviceName", IVM_POS_SHORT_TEXT, 64)
2698f64da7fSHeiko Schocher 	tmp = (unsigned char *) getenv("IVM_DeviceName");
2708f64da7fSHeiko Schocher 	if (tmp) {
2718f64da7fSHeiko Schocher 		int	len = strlen((char *)tmp);
2728f64da7fSHeiko Schocher 		int	i = 0;
2738f64da7fSHeiko Schocher 
2748f64da7fSHeiko Schocher 		while (i < len) {
2758f64da7fSHeiko Schocher 			if (tmp[i] == ';') {
276b11f53f3SHeiko Schocher 				ivm_set_value("IVM_ShortText",
277b11f53f3SHeiko Schocher 					(char *)&tmp[i + 1]);
2788f64da7fSHeiko Schocher 				break;
2798f64da7fSHeiko Schocher 			}
2808f64da7fSHeiko Schocher 			i++;
2818f64da7fSHeiko Schocher 		}
2828f64da7fSHeiko Schocher 		if (i >= len)
2838f64da7fSHeiko Schocher 			ivm_set_value("IVM_ShortText", NULL);
2848f64da7fSHeiko Schocher 	} else {
2858f64da7fSHeiko Schocher 		ivm_set_value("IVM_ShortText", NULL);
2868f64da7fSHeiko Schocher 	}
2878f64da7fSHeiko Schocher 	GET_STRING("IVM_ManufacturerID", IVM_POS_MANU_ID, 32)
2888f64da7fSHeiko Schocher 	GET_STRING("IVM_ManufacturerSerialNumber", IVM_POS_MANU_SERIAL, 20)
2898f64da7fSHeiko Schocher 	GET_STRING("IVM_ManufacturerPartNumber", IVM_POS_PART_NUMBER, 32)
2908f64da7fSHeiko Schocher 	GET_STRING("IVM_ManufacturerBuildState", IVM_POS_BUILD_STATE, 32)
2918f64da7fSHeiko Schocher 	GET_STRING("IVM_SupplierPartNumber", IVM_POS_SUPPLIER_PART_NUMBER, 32)
2928f64da7fSHeiko Schocher 	GET_STRING("IVM_DelieveryDate", IVM_POS_DELIVERY_DATE, 32)
2938f64da7fSHeiko Schocher 	GET_STRING("IVM_SupplierBuildState", IVM_POS_SUPPLIER_BUILD_STATE, 32)
2948f64da7fSHeiko Schocher 	GET_STRING("IVM_CustomerID", IVM_POS_CUSTOMER_ID, 32)
2958f64da7fSHeiko Schocher 	GET_STRING("IVM_CustomerProductID", IVM_POS_CUSTOMER_PROD_ID, 32)
2968f64da7fSHeiko Schocher 
2976d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	if (ivm_check_crc(&buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN * 2], 2) != 0)
298dc71b248SHeiko Schocher 		return 0;
299b11f53f3SHeiko Schocher 	ivm_analyze_block2(&buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN * 2],
300b11f53f3SHeiko Schocher 		CONFIG_SYS_IVM_EEPROM_PAGE_LEN);
3018f64da7fSHeiko Schocher 
3028f64da7fSHeiko Schocher 	return 0;
3038f64da7fSHeiko Schocher }
3048f64da7fSHeiko Schocher 
3058f64da7fSHeiko Schocher int ivm_read_eeprom(void)
3068f64da7fSHeiko Schocher {
3071b6275dfSHeiko Schocher #if defined(CONFIG_I2C_MUX)
3088f64da7fSHeiko Schocher 	I2C_MUX_DEVICE *dev = NULL;
3091b6275dfSHeiko Schocher #endif
3106d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	uchar i2c_buffer[CONFIG_SYS_IVM_EEPROM_MAX_LEN];
3118f64da7fSHeiko Schocher 	uchar	*buf;
3126d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	unsigned dev_addr = CONFIG_SYS_IVM_EEPROM_ADR;
313b11f53f3SHeiko Schocher 	int ret;
3148f64da7fSHeiko Schocher 
3151b6275dfSHeiko Schocher #if defined(CONFIG_I2C_MUX)
3168f64da7fSHeiko Schocher 	/* First init the Bus, select the Bus */
3176d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_SYS_I2C_IVM_BUS)
3186d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	dev = i2c_mux_ident_muxstring((uchar *)CONFIG_SYS_I2C_IVM_BUS);
3198f64da7fSHeiko Schocher #else
3208f64da7fSHeiko Schocher 	buf = (unsigned char *) getenv("EEprom_ivm");
3218f64da7fSHeiko Schocher 	if (buf != NULL)
3228f64da7fSHeiko Schocher 		dev = i2c_mux_ident_muxstring(buf);
3238f64da7fSHeiko Schocher #endif
3248f64da7fSHeiko Schocher 	if (dev == NULL) {
3258f64da7fSHeiko Schocher 		printf("Error couldnt add Bus for IVM\n");
3268f64da7fSHeiko Schocher 		return -1;
3278f64da7fSHeiko Schocher 	}
3288f64da7fSHeiko Schocher 	i2c_set_bus_num(dev->busid);
3291b6275dfSHeiko Schocher #endif
3308f64da7fSHeiko Schocher 
3318f64da7fSHeiko Schocher 	buf = (unsigned char *) getenv("EEprom_ivm_addr");
3328f64da7fSHeiko Schocher 	if (buf != NULL)
3338f64da7fSHeiko Schocher 		dev_addr = simple_strtoul((char *)buf, NULL, 16);
3348f64da7fSHeiko Schocher 
335*6c11aeafSHeiko Schocher 	/* add deblocking here */
336*6c11aeafSHeiko Schocher 	i2c_make_abort();
337*6c11aeafSHeiko Schocher 
338b11f53f3SHeiko Schocher 	ret = i2c_read(dev_addr, 0, 1, i2c_buffer,
339b11f53f3SHeiko Schocher 		CONFIG_SYS_IVM_EEPROM_MAX_LEN);
340b11f53f3SHeiko Schocher 	if (ret != 0) {
3418f64da7fSHeiko Schocher 		printf ("Error reading EEprom\n");
3428f64da7fSHeiko Schocher 		return -2;
3438f64da7fSHeiko Schocher 	}
3448f64da7fSHeiko Schocher 
3456d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	return ivm_analyze_eeprom(i2c_buffer, CONFIG_SYS_IVM_EEPROM_MAX_LEN);
3468f64da7fSHeiko Schocher }
3478f64da7fSHeiko Schocher 
3486d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_SYS_I2C_INIT_BOARD)
349*6c11aeafSHeiko Schocher #define DELAY_ABORT_SEQ		62  /* @200kHz 9 clocks = 44us, 62us is ok */
3506d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #define DELAY_HALF_PERIOD	(500 / (CONFIG_SYS_I2C_SPEED / 1000))
351c2485364SHeiko Schocher 
352af895e45SHeiko Schocher #if defined(CONFIG_MGCOGE) || defined(CONFIG_MGCOGE2NE)
353c2485364SHeiko Schocher #define SDA_MASK	0x00010000
354c2485364SHeiko Schocher #define SCL_MASK	0x00020000
355c2485364SHeiko Schocher static void set_pin(int state, unsigned long mask)
356c2485364SHeiko Schocher {
357b11f53f3SHeiko Schocher 	ioport_t *iop = ioport_addr((immap_t *)CONFIG_SYS_IMMR, 3);
358c2485364SHeiko Schocher 
359c2485364SHeiko Schocher 	if (state)
360b11f53f3SHeiko Schocher 		setbits_be32(&iop->pdat, mask);
361c2485364SHeiko Schocher 	else
362b11f53f3SHeiko Schocher 		clrbits_be32(&iop->pdat, mask);
363c2485364SHeiko Schocher 
364b11f53f3SHeiko Schocher 	setbits_be32(&iop->pdir, mask);
365c2485364SHeiko Schocher }
366c2485364SHeiko Schocher 
367c2485364SHeiko Schocher static int get_pin(unsigned long mask)
368c2485364SHeiko Schocher {
369b11f53f3SHeiko Schocher 	ioport_t *iop = ioport_addr((immap_t *)CONFIG_SYS_IMMR, 3);
370c2485364SHeiko Schocher 
371b11f53f3SHeiko Schocher 	clrbits_be32(&iop->pdir, mask);
372b11f53f3SHeiko Schocher 	return 0 != (in_be32(&iop->pdat) & mask);
373c2485364SHeiko Schocher }
374c2485364SHeiko Schocher 
375c2485364SHeiko Schocher static void set_sda(int state)
376c2485364SHeiko Schocher {
377c2485364SHeiko Schocher 	set_pin(state, SDA_MASK);
378c2485364SHeiko Schocher }
379c2485364SHeiko Schocher 
380c2485364SHeiko Schocher static void set_scl(int state)
381c2485364SHeiko Schocher {
382c2485364SHeiko Schocher 	set_pin(state, SCL_MASK);
383c2485364SHeiko Schocher }
384c2485364SHeiko Schocher 
385c2485364SHeiko Schocher static int get_sda(void)
386c2485364SHeiko Schocher {
387c2485364SHeiko Schocher 	return get_pin(SDA_MASK);
388c2485364SHeiko Schocher }
389c2485364SHeiko Schocher 
390c2485364SHeiko Schocher static int get_scl(void)
391c2485364SHeiko Schocher {
392c2485364SHeiko Schocher 	return get_pin(SCL_MASK);
393c2485364SHeiko Schocher }
394c2485364SHeiko Schocher 
395c2485364SHeiko Schocher #if defined(CONFIG_HARD_I2C)
396c2485364SHeiko Schocher static void setports(int gpio)
397c2485364SHeiko Schocher {
398b11f53f3SHeiko Schocher 	ioport_t *iop = ioport_addr((immap_t *)CONFIG_SYS_IMMR, 3);
399c2485364SHeiko Schocher 
400c2485364SHeiko Schocher 	if (gpio) {
401b11f53f3SHeiko Schocher 		clrbits_be32(&iop->ppar, (SDA_MASK | SCL_MASK));
402b11f53f3SHeiko Schocher 		clrbits_be32(&iop->podr, (SDA_MASK | SCL_MASK));
403c2485364SHeiko Schocher 	} else {
404b11f53f3SHeiko Schocher 		setbits_be32(&iop->ppar, (SDA_MASK | SCL_MASK));
405b11f53f3SHeiko Schocher 		clrbits_be32(&iop->pdir, (SDA_MASK | SCL_MASK));
406b11f53f3SHeiko Schocher 		setbits_be32(&iop->podr, (SDA_MASK | SCL_MASK));
407c2485364SHeiko Schocher 	}
408c2485364SHeiko Schocher }
409c2485364SHeiko Schocher #endif
410c2485364SHeiko Schocher #endif
411c2485364SHeiko Schocher 
41262ddcf05SHeiko Schocher #if !defined(CONFIG_MPC83xx)
413*6c11aeafSHeiko Schocher static void i2c_write_start_seq(void)
414c2485364SHeiko Schocher {
415c2485364SHeiko Schocher 	set_sda(1);
416c2485364SHeiko Schocher 	udelay(DELAY_HALF_PERIOD);
417c2485364SHeiko Schocher 	set_scl(1);
418c2485364SHeiko Schocher 	udelay(DELAY_HALF_PERIOD);
419c2485364SHeiko Schocher 	set_sda(0);
420c2485364SHeiko Schocher 	udelay(DELAY_HALF_PERIOD);
421c2485364SHeiko Schocher 	set_scl(0);
422c2485364SHeiko Schocher 	udelay(DELAY_HALF_PERIOD);
423c2485364SHeiko Schocher }
424c2485364SHeiko Schocher 
425b11f53f3SHeiko Schocher /*
426b11f53f3SHeiko Schocher  * I2C is a synchronous protocol and resets of the processor in the middle
427b11f53f3SHeiko Schocher  * of an access can block the I2C Bus until a powerdown of the full unit is
428b11f53f3SHeiko Schocher  * done. This function toggles the SCL until the SCL and SCA line are
429b11f53f3SHeiko Schocher  * released, but max. 16 times, after this a I2C start-sequence is sent.
430b11f53f3SHeiko Schocher  * This I2C Deblocking mechanism was developed by Keymile in association
431b11f53f3SHeiko Schocher  * with Anatech and Atmel in 1998.
432c2485364SHeiko Schocher  */
433c2485364SHeiko Schocher static int i2c_make_abort(void)
434c2485364SHeiko Schocher {
435*6c11aeafSHeiko Schocher 
436*6c11aeafSHeiko Schocher #if defined(CONFIG_HARD_I2C) && !defined(MACH_TYPE_KM_KIRKWOOD)
437*6c11aeafSHeiko Schocher 	immap_t *immap = (immap_t *)CONFIG_SYS_IMMR ;
438*6c11aeafSHeiko Schocher 	i2c8260_t *i2c	= (i2c8260_t *)&immap->im_i2c;
439*6c11aeafSHeiko Schocher 
440*6c11aeafSHeiko Schocher 	/*
441*6c11aeafSHeiko Schocher 	 * disable I2C controller first, otherwhise it thinks we want to
442*6c11aeafSHeiko Schocher 	 * talk to the slave port...
443*6c11aeafSHeiko Schocher 	 */
444*6c11aeafSHeiko Schocher 	clrbits_8(&i2c->i2c_i2mod, 0x01);
445*6c11aeafSHeiko Schocher 
446*6c11aeafSHeiko Schocher 	/* Set the PortPins to GPIO */
447*6c11aeafSHeiko Schocher 	setports(1);
448*6c11aeafSHeiko Schocher #endif
449*6c11aeafSHeiko Schocher 
450c2485364SHeiko Schocher 	int	scl_state = 0;
451c2485364SHeiko Schocher 	int	sda_state = 0;
452c2485364SHeiko Schocher 	int	i = 0;
453c2485364SHeiko Schocher 	int	ret = 0;
454c2485364SHeiko Schocher 
455c2485364SHeiko Schocher 	if (!get_sda()) {
456c2485364SHeiko Schocher 		ret = -1;
457c2485364SHeiko Schocher 		while (i < 16) {
458c2485364SHeiko Schocher 			i++;
459c2485364SHeiko Schocher 			set_scl(0);
460c2485364SHeiko Schocher 			udelay(DELAY_ABORT_SEQ);
461c2485364SHeiko Schocher 			set_scl(1);
462c2485364SHeiko Schocher 			udelay(DELAY_ABORT_SEQ);
463c2485364SHeiko Schocher 			scl_state = get_scl();
464c2485364SHeiko Schocher 			sda_state = get_sda();
465c2485364SHeiko Schocher 			if (scl_state && sda_state) {
466c2485364SHeiko Schocher 				ret = 0;
467c2485364SHeiko Schocher 				break;
468c2485364SHeiko Schocher 			}
469c2485364SHeiko Schocher 		}
470c2485364SHeiko Schocher 	}
471b11f53f3SHeiko Schocher 	if (ret == 0)
472b11f53f3SHeiko Schocher 		for (i = 0; i < 5; i++)
473*6c11aeafSHeiko Schocher 			i2c_write_start_seq();
474b11f53f3SHeiko Schocher 
475*6c11aeafSHeiko Schocher 	/* respect stop setup time */
476*6c11aeafSHeiko Schocher 	udelay(DELAY_ABORT_SEQ);
477*6c11aeafSHeiko Schocher 	set_scl(1);
478*6c11aeafSHeiko Schocher 	udelay(DELAY_ABORT_SEQ);
479*6c11aeafSHeiko Schocher 	set_sda(1);
480c2485364SHeiko Schocher 	get_sda();
481c2485364SHeiko Schocher 
482c2485364SHeiko Schocher #if defined(CONFIG_HARD_I2C)
483c2485364SHeiko Schocher 	/* Set the PortPins back to use for I2C */
484c2485364SHeiko Schocher 	setports(0);
485c2485364SHeiko Schocher #endif
486*6c11aeafSHeiko Schocher 	return ret;
487*6c11aeafSHeiko Schocher }
48839df00d9SHeiko Schocher #endif
489*6c11aeafSHeiko Schocher 
490*6c11aeafSHeiko Schocher #if defined(CONFIG_MPC83xx)
491*6c11aeafSHeiko Schocher static void i2c_write_start_seq(void)
492*6c11aeafSHeiko Schocher {
493*6c11aeafSHeiko Schocher 	struct fsl_i2c *dev;
494*6c11aeafSHeiko Schocher 	dev = (struct fsl_i2c *) (CONFIG_SYS_IMMR + CONFIG_SYS_I2C_OFFSET);
495*6c11aeafSHeiko Schocher 	udelay(DELAY_ABORT_SEQ);
496*6c11aeafSHeiko Schocher 	out_8(&dev->cr, (I2C_CR_MEN | I2C_CR_MSTA));
497*6c11aeafSHeiko Schocher 	udelay(DELAY_ABORT_SEQ);
498*6c11aeafSHeiko Schocher 	out_8(&dev->cr, (I2C_CR_MEN));
499*6c11aeafSHeiko Schocher }
500*6c11aeafSHeiko Schocher 
501*6c11aeafSHeiko Schocher static int i2c_make_abort(void)
502*6c11aeafSHeiko Schocher {
503*6c11aeafSHeiko Schocher 	struct fsl_i2c *dev;
504*6c11aeafSHeiko Schocher 	dev = (struct fsl_i2c *) (CONFIG_SYS_IMMR + CONFIG_SYS_I2C_OFFSET);
505*6c11aeafSHeiko Schocher 	uchar	dummy;
506*6c11aeafSHeiko Schocher 	uchar   last;
507*6c11aeafSHeiko Schocher 	int     nbr_read = 0;
508*6c11aeafSHeiko Schocher 	int     i = 0;
509*6c11aeafSHeiko Schocher 	int	    ret = 0;
510*6c11aeafSHeiko Schocher 
511*6c11aeafSHeiko Schocher 	/* wait after each operation to finsh with a delay */
512*6c11aeafSHeiko Schocher 	out_8(&dev->cr, (I2C_CR_MSTA));
513*6c11aeafSHeiko Schocher 	udelay(DELAY_ABORT_SEQ);
514*6c11aeafSHeiko Schocher 	out_8(&dev->cr, (I2C_CR_MEN | I2C_CR_MSTA));
515*6c11aeafSHeiko Schocher 	udelay(DELAY_ABORT_SEQ);
516*6c11aeafSHeiko Schocher 	dummy = in_8(&dev->dr);
517*6c11aeafSHeiko Schocher 	udelay(DELAY_ABORT_SEQ);
518*6c11aeafSHeiko Schocher 	last = in_8(&dev->dr);
519*6c11aeafSHeiko Schocher 	nbr_read++;
520*6c11aeafSHeiko Schocher 
521*6c11aeafSHeiko Schocher 	/*
522*6c11aeafSHeiko Schocher 	 * do read until the last bit is 1, but stop if the full eeprom is
523*6c11aeafSHeiko Schocher 	 * read.
524*6c11aeafSHeiko Schocher 	 */
525*6c11aeafSHeiko Schocher 	while (((last & 0x01) != 0x01) &&
526*6c11aeafSHeiko Schocher 		(nbr_read < CONFIG_SYS_IVM_EEPROM_MAX_LEN)) {
527*6c11aeafSHeiko Schocher 		udelay(DELAY_ABORT_SEQ);
528*6c11aeafSHeiko Schocher 		last = in_8(&dev->dr);
529*6c11aeafSHeiko Schocher 		nbr_read++;
530*6c11aeafSHeiko Schocher 	}
531*6c11aeafSHeiko Schocher 	if ((last & 0x01) != 0x01)
532*6c11aeafSHeiko Schocher 		ret = -2;
533*6c11aeafSHeiko Schocher 	if ((last != 0xff) || (nbr_read > 1))
534*6c11aeafSHeiko Schocher 		printf("[INFO] i2c abort after %d bytes (0x%02x)\n",
535*6c11aeafSHeiko Schocher 			nbr_read, last);
536*6c11aeafSHeiko Schocher 	udelay(DELAY_ABORT_SEQ);
537*6c11aeafSHeiko Schocher 	out_8(&dev->cr, (I2C_CR_MEN));
538*6c11aeafSHeiko Schocher 	udelay(DELAY_ABORT_SEQ);
539*6c11aeafSHeiko Schocher 	/* clear status reg */
540*6c11aeafSHeiko Schocher 	out_8(&dev->sr, 0);
541*6c11aeafSHeiko Schocher 
542*6c11aeafSHeiko Schocher 	for (i = 0; i < 5; i++)
543*6c11aeafSHeiko Schocher 		i2c_write_start_seq();
544*6c11aeafSHeiko Schocher 	if (ret != 0)
545*6c11aeafSHeiko Schocher 		printf("[ERROR] i2c abort failed after %d bytes (0x%02x)\n",
546*6c11aeafSHeiko Schocher 			nbr_read, last);
547*6c11aeafSHeiko Schocher 
548*6c11aeafSHeiko Schocher 	return ret;
549*6c11aeafSHeiko Schocher }
550*6c11aeafSHeiko Schocher #endif
551*6c11aeafSHeiko Schocher 
552*6c11aeafSHeiko Schocher /**
553*6c11aeafSHeiko Schocher  * i2c_init_board - reset i2c bus. When the board is powercycled during a
554*6c11aeafSHeiko Schocher  * bus transfer it might hang; for details see doc/I2C_Edge_Conditions.
555*6c11aeafSHeiko Schocher  */
556*6c11aeafSHeiko Schocher void i2c_init_board(void)
557*6c11aeafSHeiko Schocher {
558*6c11aeafSHeiko Schocher 	/* Now run the AbortSequence() */
559*6c11aeafSHeiko Schocher 	i2c_make_abort();
560c2485364SHeiko Schocher }
561c2485364SHeiko Schocher #endif
562210c8c00SHeiko Schocher #endif
5636250f0f6SHeiko Schocher 
5646250f0f6SHeiko Schocher #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT)
5656250f0f6SHeiko Schocher int fdt_set_node_and_value(void *blob,
5666250f0f6SHeiko Schocher 				char *nodename,
5676250f0f6SHeiko Schocher 				char *regname,
5686250f0f6SHeiko Schocher 				void *var,
5696250f0f6SHeiko Schocher 				int size)
5706250f0f6SHeiko Schocher {
5716250f0f6SHeiko Schocher 	int ret = 0;
5726250f0f6SHeiko Schocher 	int nodeoffset = 0;
5736250f0f6SHeiko Schocher 
5746250f0f6SHeiko Schocher 	nodeoffset = fdt_path_offset(blob, nodename);
5756250f0f6SHeiko Schocher 	if (nodeoffset >= 0) {
5766250f0f6SHeiko Schocher 		ret = fdt_setprop(blob, nodeoffset, regname, var,
5776250f0f6SHeiko Schocher 					size);
5786250f0f6SHeiko Schocher 		if (ret < 0)
5796250f0f6SHeiko Schocher 			printf("ft_blob_update(): cannot set %s/%s "
5806250f0f6SHeiko Schocher 				"property err:%s\n", nodename, regname,
5816250f0f6SHeiko Schocher 				fdt_strerror(ret));
5826250f0f6SHeiko Schocher 	} else {
5836250f0f6SHeiko Schocher 		printf("ft_blob_update(): cannot find %s node "
5846250f0f6SHeiko Schocher 			"err:%s\n", nodename, fdt_strerror(nodeoffset));
5856250f0f6SHeiko Schocher 	}
5866250f0f6SHeiko Schocher 	return ret;
5876250f0f6SHeiko Schocher }
588b11f53f3SHeiko Schocher 
589dc71b248SHeiko Schocher int fdt_get_node_and_value(void *blob,
590dc71b248SHeiko Schocher 				char *nodename,
591dc71b248SHeiko Schocher 				char *propname,
592dc71b248SHeiko Schocher 				void **var)
593dc71b248SHeiko Schocher {
594dc71b248SHeiko Schocher 	int len;
595dc71b248SHeiko Schocher 	int nodeoffset = 0;
596dc71b248SHeiko Schocher 
597dc71b248SHeiko Schocher 	nodeoffset = fdt_path_offset(blob, nodename);
598dc71b248SHeiko Schocher 	if (nodeoffset >= 0) {
599dc71b248SHeiko Schocher 		*var = (void *)fdt_getprop(blob, nodeoffset, propname, &len);
600dc71b248SHeiko Schocher 		if (len == 0) {
601dc71b248SHeiko Schocher 			/* no value */
602b11f53f3SHeiko Schocher 			printf("%s no value\n", __func__);
603dc71b248SHeiko Schocher 			return -1;
604dc71b248SHeiko Schocher 		} else if (len > 0) {
605dc71b248SHeiko Schocher 			return len;
606dc71b248SHeiko Schocher 		} else {
607dc71b248SHeiko Schocher 			printf("libfdt fdt_getprop(): %s\n",
608dc71b248SHeiko Schocher 				fdt_strerror(len));
609dc71b248SHeiko Schocher 			return -2;
610dc71b248SHeiko Schocher 		}
611dc71b248SHeiko Schocher 	} else {
612b11f53f3SHeiko Schocher 		printf("%s: cannot find %s node err:%s\n", __func__,
613dc71b248SHeiko Schocher 			nodename, fdt_strerror(nodeoffset));
614dc71b248SHeiko Schocher 		return -3;
615dc71b248SHeiko Schocher 	}
616dc71b248SHeiko Schocher }
6176250f0f6SHeiko Schocher #endif
618210c8c00SHeiko Schocher 
619802d9963SHolger Brunck #if !defined(MACH_TYPE_KM_KIRKWOOD)
620210c8c00SHeiko Schocher int ethernet_present(void)
621210c8c00SHeiko Schocher {
6228ed74341SHeiko Schocher 	struct km_bec_fpga *base =
6238ed74341SHeiko Schocher 		(struct km_bec_fpga *)CONFIG_SYS_KMBEC_FPGA_BASE;
624b11f53f3SHeiko Schocher 
625b11f53f3SHeiko Schocher 	return in_8(&base->bprth) & PIGGY_PRESENT;
626210c8c00SHeiko Schocher }
62767fa8c25SHeiko Schocher #endif
628210c8c00SHeiko Schocher 
629210c8c00SHeiko Schocher int board_eth_init(bd_t *bis)
630210c8c00SHeiko Schocher {
631210c8c00SHeiko Schocher #ifdef CONFIG_KEYMILE_HDLC_ENET
632210c8c00SHeiko Schocher 	(void)keymile_hdlc_enet_initialize(bis);
633210c8c00SHeiko Schocher #endif
634b11f53f3SHeiko Schocher 	if (ethernet_present())
63562ddcf05SHeiko Schocher 		return cpu_eth_init(bis);
63662ddcf05SHeiko Schocher 
637210c8c00SHeiko Schocher 	return -1;
638210c8c00SHeiko Schocher }
639