xref: /openbmc/u-boot/board/keymile/common/common.c (revision e4430779)
1 /*
2  * (C) Copyright 2008
3  * Heiko Schocher, DENX Software Engineering, hs@denx.de.
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23 
24 #include <common.h>
25 #include <mpc8260.h>
26 #include <ioports.h>
27 #include <malloc.h>
28 #include <hush.h>
29 
30 #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT)
31 #include <libfdt.h>
32 #endif
33 
34 #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
35 #include <i2c.h>
36 #endif
37 #include <asm/io.h>
38 
39 extern int i2c_soft_read_pin (void);
40 
41 int ivm_calc_crc (unsigned char *buf, int len)
42 {
43 	const unsigned short crc_tab[16] = {
44 		0x0000, 0xCC01, 0xD801, 0x1400,
45 		0xF001, 0x3C00, 0x2800, 0xE401,
46 		0xA001, 0x6C00, 0x7800, 0xB401,
47 		0x5000, 0x9C01, 0x8801, 0x4400};
48 
49 	unsigned short crc     = 0;   /* final result */
50 	unsigned short r1      = 0;   /* temp */
51 	unsigned char  byte    = 0;   /* input buffer */
52 	int	i;
53 
54 	/* calculate CRC from array data */
55 	for (i = 0; i < len; i++) {
56 		byte = buf[i];
57 
58 		/* lower 4 bits */
59 		r1 = crc_tab[crc & 0xF];
60 		crc = ((crc) >> 4) & 0x0FFF;
61 		crc = crc ^ r1 ^ crc_tab[byte & 0xF];
62 
63 		/* upper 4 bits */
64 		r1 = crc_tab[crc & 0xF];
65 		crc = (crc >> 4) & 0x0FFF;
66 		crc = crc ^ r1 ^ crc_tab[(byte >> 4) & 0xF];
67 	}
68 	return crc;
69 }
70 
71 static int  ivm_set_value (char *name, char *value)
72 {
73 	char tempbuf[256];
74 
75 	if (value != NULL) {
76 		sprintf (tempbuf, "%s=%s", name, value);
77 		return set_local_var (tempbuf, 0);
78 	} else {
79 		unset_local_var (name);
80 	}
81 	return 0;
82 }
83 
84 static int ivm_get_value (unsigned char *buf, int len, char *name, int off,
85 				int check)
86 {
87 	unsigned short	val;
88 	unsigned char	valbuf[30];
89 
90 	if ((buf[off + 0] != buf[off + 2]) &&
91 	    (buf[off + 2] != buf[off + 4])) {
92 		printf ("%s Error corrupted %s\n", __FUNCTION__, name);
93 		val = -1;
94 	} else {
95 		val = buf[off + 0] + (buf[off + 1] << 8);
96 		if ((val == 0) && (check == 1))
97 			val = -1;
98 	}
99 	sprintf ((char *)valbuf, "%x", val);
100 	ivm_set_value (name, (char *)valbuf);
101 	return val;
102 }
103 
104 #define INVENTORYBLOCKSIZE	0x100
105 #define INVENTORYDATAADDRESS	0x21
106 #define INVENTORYDATASIZE	(INVENTORYBLOCKSIZE - INVENTORYDATAADDRESS - 3)
107 
108 #define IVM_POS_SHORT_TEXT		0
109 #define IVM_POS_MANU_ID			1
110 #define IVM_POS_MANU_SERIAL		2
111 #define IVM_POS_PART_NUMBER		3
112 #define IVM_POS_BUILD_STATE		4
113 #define IVM_POS_SUPPLIER_PART_NUMBER	5
114 #define IVM_POS_DELIVERY_DATE		6
115 #define IVM_POS_SUPPLIER_BUILD_STATE	7
116 #define IVM_POS_CUSTOMER_ID		8
117 #define IVM_POS_CUSTOMER_PROD_ID	9
118 #define IVM_POS_HISTORY			10
119 #define IVM_POS_SYMBOL_ONLY		11
120 
121 static char convert_char (char c)
122 {
123 	return (c < ' ' || c > '~') ? '.' : c;
124 }
125 
126 static int ivm_findinventorystring (int type,
127 					unsigned char* const string,
128 					unsigned long maxlen,
129 					unsigned char *buf)
130 {
131 	int xcode = 0;
132 	unsigned long cr = 0;
133 	unsigned long addr = INVENTORYDATAADDRESS;
134 	unsigned long size = 0;
135 	unsigned long nr = type;
136 	int stop = 0; 	/* stop on semicolon */
137 
138 	memset(string, '\0', maxlen);
139 	switch (type) {
140 		case IVM_POS_SYMBOL_ONLY:
141 			nr = 0;
142 			stop= 1;
143 		break;
144 		default:
145 			nr = type;
146 			stop = 0;
147 	}
148 
149 	/* Look for the requested number of CR. */
150 	while ((cr != nr) && (addr < INVENTORYDATASIZE)) {
151 		if ((buf[addr] == '\r')) {
152 			cr++;
153 		}
154 		addr++;
155 	}
156 
157 	/* the expected number of CR was found until the end of the IVM
158 	 *  content --> fill string */
159 	if (addr < INVENTORYDATASIZE) {
160 		/* Copy the IVM string in the corresponding string */
161 		for (; (buf[addr] != '\r')			&&
162 			((buf[addr] != ';') ||  (!stop))	&&
163 			(size < (maxlen - 1)			&&
164 			(addr < INVENTORYDATASIZE)); addr++)
165 		{
166 			size += sprintf((char *)string + size, "%c",
167 						convert_char (buf[addr]));
168 		}
169 
170 		/* copy phase is done: check if everything is ok. If not,
171 		 * the inventory data is most probably corrupted: tell
172 		 * the world there is a problem! */
173 		if (addr == INVENTORYDATASIZE) {
174 			xcode = -1;
175 			printf ("Error end of string not found\n");
176 		} else if ((size >= (maxlen - 1)) &&
177 			   (buf[addr] != '\r')) {
178 			xcode = -1;
179 			printf ("string too long till next CR\n");
180 		}
181 	} else {
182 		/* some CR are missing...
183 		 * the inventory data is most probably corrupted */
184 		xcode = -1;
185 		printf ("not enough cr found\n");
186 	}
187 	return xcode;
188 }
189 
190 #define GET_STRING(name, which, len) \
191 	if (ivm_findinventorystring (which, valbuf, len, buf) == 0) { \
192 		ivm_set_value (name, (char *)valbuf); \
193 	}
194 
195 static int ivm_check_crc (unsigned char *buf, int block)
196 {
197 	unsigned long	crc;
198 	unsigned long	crceeprom;
199 
200 	crc = ivm_calc_crc (buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 2);
201 	crceeprom = (buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 1] + \
202 			buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 2] * 256);
203 	if (crc != crceeprom) {
204 		printf ("Error CRC Block: %d EEprom: calculated: %lx EEprom: %lx\n",
205 			block, crc, crceeprom);
206 		return -1;
207 	}
208 	return 0;
209 }
210 
211 static int ivm_analyze_block2 (unsigned char *buf, int len)
212 {
213 	unsigned char	valbuf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN];
214 	unsigned long	count;
215 
216 	/* IVM_MacAddress */
217 	sprintf ((char *)valbuf, "%02X:%02X:%02X:%02X:%02X:%02X",
218 			buf[1],
219 			buf[2],
220 			buf[3],
221 			buf[4],
222 			buf[5],
223 			buf[6]);
224 	ivm_set_value ("IVM_MacAddress", (char *)valbuf);
225 	if (getenv ("ethaddr") == NULL)
226 		setenv ((char *)"ethaddr", (char *)valbuf);
227 	/* IVM_MacCount */
228 	count = (buf[10] << 24) +
229 		   (buf[11] << 16) +
230 		   (buf[12] << 8)  +
231 		    buf[13];
232 	if (count == 0xffffffff)
233 		count = 1;
234 	sprintf ((char *)valbuf, "%lx", count);
235 	ivm_set_value ("IVM_MacCount", (char *)valbuf);
236 	return 0;
237 }
238 
239 int ivm_analyze_eeprom (unsigned char *buf, int len)
240 {
241 	unsigned short	val;
242 	unsigned char	valbuf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN];
243 	unsigned char	*tmp;
244 
245 	if (ivm_check_crc (buf, 0) != 0)
246 		return -1;
247 
248 	ivm_get_value (buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN, "IVM_BoardId", 0, 1);
249 	val = ivm_get_value (buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN, "IVM_HWKey", 6, 1);
250 	if (val != 0xffff) {
251 		sprintf ((char *)valbuf, "%x", ((val /100) % 10));
252 		ivm_set_value ("IVM_HWVariant", (char *)valbuf);
253 		sprintf ((char *)valbuf, "%x", (val % 100));
254 		ivm_set_value ("IVM_HWVersion", (char *)valbuf);
255 	}
256 	ivm_get_value (buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN, "IVM_Functions", 12, 0);
257 
258 	GET_STRING("IVM_Symbol", IVM_POS_SYMBOL_ONLY, 8)
259 	GET_STRING("IVM_DeviceName", IVM_POS_SHORT_TEXT, 64)
260 	tmp = (unsigned char *) getenv("IVM_DeviceName");
261 	if (tmp) {
262 		int	len = strlen ((char *)tmp);
263 		int	i = 0;
264 
265 		while (i < len) {
266 			if (tmp[i] == ';') {
267 				ivm_set_value ("IVM_ShortText", (char *)&tmp[i + 1]);
268 				break;
269 			}
270 			i++;
271 		}
272 		if (i >= len)
273 			ivm_set_value ("IVM_ShortText", NULL);
274 	} else {
275 		ivm_set_value ("IVM_ShortText", NULL);
276 	}
277 	GET_STRING("IVM_ManufacturerID", IVM_POS_MANU_ID, 32)
278 	GET_STRING("IVM_ManufacturerSerialNumber", IVM_POS_MANU_SERIAL, 20)
279 	GET_STRING("IVM_ManufacturerPartNumber", IVM_POS_PART_NUMBER, 32)
280 	GET_STRING("IVM_ManufacturerBuildState", IVM_POS_BUILD_STATE, 32)
281 	GET_STRING("IVM_SupplierPartNumber", IVM_POS_SUPPLIER_PART_NUMBER, 32)
282 	GET_STRING("IVM_DelieveryDate", IVM_POS_DELIVERY_DATE, 32)
283 	GET_STRING("IVM_SupplierBuildState", IVM_POS_SUPPLIER_BUILD_STATE, 32)
284 	GET_STRING("IVM_CustomerID", IVM_POS_CUSTOMER_ID, 32)
285 	GET_STRING("IVM_CustomerProductID", IVM_POS_CUSTOMER_PROD_ID, 32)
286 
287 	if (ivm_check_crc (&buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN * 2], 2) != 0)
288 		return -2;
289 	ivm_analyze_block2 (&buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN * 2], CONFIG_SYS_IVM_EEPROM_PAGE_LEN);
290 
291 	return 0;
292 }
293 
294 int ivm_read_eeprom (void)
295 {
296 	I2C_MUX_DEVICE *dev = NULL;
297 	uchar i2c_buffer[CONFIG_SYS_IVM_EEPROM_MAX_LEN];
298 	uchar	*buf;
299 	unsigned dev_addr = CONFIG_SYS_IVM_EEPROM_ADR;
300 
301 	/* First init the Bus, select the Bus */
302 #if defined(CONFIG_SYS_I2C_IVM_BUS)
303 	dev = i2c_mux_ident_muxstring ((uchar *)CONFIG_SYS_I2C_IVM_BUS);
304 #else
305 	buf = (unsigned char *) getenv ("EEprom_ivm");
306 	if (buf != NULL)
307 		dev = i2c_mux_ident_muxstring (buf);
308 #endif
309 	if (dev == NULL) {
310 		printf ("Error couldnt add Bus for IVM\n");
311 		return -1;
312 	}
313 	i2c_set_bus_num (dev->busid);
314 
315 	buf = (unsigned char *) getenv ("EEprom_ivm_addr");
316 	if (buf != NULL)
317 		dev_addr = simple_strtoul ((char *)buf, NULL, 16);
318 
319 	if (eeprom_read (dev_addr, 0, i2c_buffer, CONFIG_SYS_IVM_EEPROM_MAX_LEN) != 0) {
320 		printf ("Error reading EEprom\n");
321 		return -2;
322 	}
323 
324 	return ivm_analyze_eeprom (i2c_buffer, CONFIG_SYS_IVM_EEPROM_MAX_LEN);
325 }
326 
327 #if defined(CONFIG_SYS_I2C_INIT_BOARD)
328 #define DELAY_ABORT_SEQ		62
329 #define DELAY_HALF_PERIOD	(500 / (CONFIG_SYS_I2C_SPEED / 1000))
330 
331 #if defined(CONFIG_MGCOGE)
332 #define SDA_MASK	0x00010000
333 #define SCL_MASK	0x00020000
334 static void set_pin (int state, unsigned long mask)
335 {
336 	volatile ioport_t *iop = ioport_addr ((immap_t *)CONFIG_SYS_IMMR, 3);
337 
338 	if (state)
339 		iop->pdat |= (mask);
340 	else
341 		iop->pdat &= ~(mask);
342 
343 	iop->pdir |= (mask);
344 }
345 
346 static int get_pin (unsigned long mask)
347 {
348 	volatile ioport_t *iop = ioport_addr ((immap_t *)CONFIG_SYS_IMMR, 3);
349 
350 	iop->pdir &= ~(mask);
351 	return (0 != (iop->pdat & (mask)));
352 }
353 
354 static void set_sda (int state)
355 {
356 	set_pin (state, SDA_MASK);
357 }
358 
359 static void set_scl (int state)
360 {
361 	set_pin (state, SCL_MASK);
362 }
363 
364 static int get_sda (void)
365 {
366 	return get_pin (SDA_MASK);
367 }
368 
369 static int get_scl (void)
370 {
371 	return get_pin (SCL_MASK);
372 }
373 
374 #if defined(CONFIG_HARD_I2C)
375 static void setports (int gpio)
376 {
377 	volatile ioport_t *iop = ioport_addr ((immap_t *)CONFIG_SYS_IMMR, 3);
378 
379 	if (gpio) {
380 		iop->ppar &= ~(SDA_MASK | SCL_MASK);
381 		iop->podr &= ~(SDA_MASK | SCL_MASK);
382 	} else {
383 		iop->ppar |= (SDA_MASK | SCL_MASK);
384 		iop->pdir &= ~(SDA_MASK | SCL_MASK);
385 		iop->podr |= (SDA_MASK | SCL_MASK);
386 	}
387 }
388 #endif
389 #endif
390 
391 #if defined(CONFIG_MGSUVD)
392 static void set_sda (int state)
393 {
394 	I2C_SDA(state);
395 }
396 
397 static void set_scl (int state)
398 {
399 	I2C_SCL(state);
400 }
401 
402 static int get_sda (void)
403 {
404 	return I2C_READ;
405 }
406 
407 static int get_scl (void)
408 {
409 	int	val;
410 
411 	*(unsigned short *)(I2C_BASE_DIR) &=  ~SCL_CONF;
412 	udelay (1);
413 	val = *(unsigned char *)(I2C_BASE_PORT);
414 
415 	return ((val & SCL_BIT) == SCL_BIT);
416 }
417 
418 #endif
419 
420 static void writeStartSeq (void)
421 {
422 	set_sda (1);
423 	udelay (DELAY_HALF_PERIOD);
424 	set_scl (1);
425 	udelay (DELAY_HALF_PERIOD);
426 	set_sda (0);
427 	udelay (DELAY_HALF_PERIOD);
428 	set_scl (0);
429 	udelay (DELAY_HALF_PERIOD);
430 }
431 
432 /* I2C is a synchronous protocol and resets of the processor in the middle
433    of an access can block the I2C Bus until a powerdown of the full unit is
434    done. This function toggles the SCL until the SCL and SCA line are
435    released, but max. 16 times, after this a I2C start-sequence is sent.
436    This I2C Deblocking mechanism was developed by Keymile in association
437    with Anatech and Atmel in 1998.
438  */
439 static int i2c_make_abort (void)
440 {
441 	int	scl_state = 0;
442 	int	sda_state = 0;
443 	int	i = 0;
444 	int	ret = 0;
445 
446 	if (!get_sda ()) {
447 		ret = -1;
448 		while (i < 16) {
449 			i++;
450 			set_scl (0);
451 			udelay (DELAY_ABORT_SEQ);
452 			set_scl (1);
453 			udelay (DELAY_ABORT_SEQ);
454 			scl_state = get_scl ();
455 			sda_state = get_sda ();
456 			if (scl_state && sda_state) {
457 				ret = 0;
458 				break;
459 			}
460 		}
461 	}
462 	if (ret == 0) {
463 		for (i =0; i < 5; i++) {
464 			writeStartSeq ();
465 		}
466 	}
467 	get_sda ();
468 	return ret;
469 }
470 
471 /**
472  * i2c_init_board - reset i2c bus. When the board is powercycled during a
473  * bus transfer it might hang; for details see doc/I2C_Edge_Conditions.
474  */
475 void i2c_init_board(void)
476 {
477 #if defined(CONFIG_HARD_I2C)
478 	volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR ;
479 	volatile i2c8260_t *i2c	= (i2c8260_t *)&immap->im_i2c;
480 
481 	/* disable I2C controller first, otherwhise it thinks we want to    */
482 	/* talk to the slave port...                                        */
483 	i2c->i2c_i2mod &= ~0x01;
484 
485 	/* Set the PortPins to GPIO */
486 	setports (1);
487 #endif
488 
489 	/* Now run the AbortSequence() */
490 	i2c_make_abort ();
491 
492 #if defined(CONFIG_HARD_I2C)
493 	/* Set the PortPins back to use for I2C */
494 	setports (0);
495 #endif
496 }
497 #endif
498 
499 #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT)
500 int fdt_set_node_and_value (void *blob,
501 				char *nodename,
502 				char *regname,
503 				void *var,
504 				int size)
505 {
506 	int ret = 0;
507 	int nodeoffset = 0;
508 
509 	nodeoffset = fdt_path_offset (blob, nodename);
510 	if (nodeoffset >= 0) {
511 		ret = fdt_setprop (blob, nodeoffset, regname, var,
512 					size);
513 		if (ret < 0)
514 			printf("ft_blob_update(): cannot set %s/%s "
515 				"property err:%s\n", nodename, regname,
516 				fdt_strerror (ret));
517 	} else {
518 		printf("ft_blob_update(): cannot find %s node "
519 			"err:%s\n", nodename, fdt_strerror (nodeoffset));
520 	}
521 	return ret;
522 }
523 #endif
524