]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/xilinx/xilinx_iic/iic_adapter.c
Merge with /home/m8/git/u-boot
[karo-tx-uboot.git] / board / xilinx / xilinx_iic / iic_adapter.c
1 /******************************************************************************
2 *
3 *     Author: Xilinx, Inc.
4 *
5 *
6 *     This program is free software; you can redistribute it and/or modify it
7 *     under the terms of the GNU General Public License as published by the
8 *     Free Software Foundation; either version 2 of the License, or (at your
9 *     option) any later version.
10 *
11 *
12 *     XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
13 *     COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
14 *     ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR STANDARD,
15 *     XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION IS FREE
16 *     FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE FOR OBTAINING
17 *     ANY THIRD PARTY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
18 *     XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
19 *     THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY
20 *     WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM
21 *     CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND
22 *     FITNESS FOR A PARTICULAR PURPOSE.
23 *
24 *
25 *     Xilinx hardware products are not intended for use in life support
26 *     appliances, devices, or systems. Use in such applications is
27 *     expressly prohibited.
28 *
29 *
30 *     (c) Copyright 2002-2004 Xilinx Inc.
31 *     All rights reserved.
32 *
33 *
34 *     You should have received a copy of the GNU General Public License along
35 *     with this program; if not, write to the Free Software Foundation, Inc.,
36 *     675 Mass Ave, Cambridge, MA 02139, USA.
37 *
38 ******************************************************************************/
39
40 #include <common.h>
41 #include <environment.h>
42 #include <net.h>
43 #include <configs/ml300.h>
44 #include "xparameters.h"
45
46 #ifdef CFG_ENV_IS_IN_EEPROM
47 #include <i2c.h>
48 #include "xiic_l.h"
49
50 #define IIC_DELAY     5000
51
52 static u8 envStep = 0;          /* 0 means crc has not been read */
53 const u8 hex[] = "0123456789ABCDEF"; /* lookup table for ML300 CRC */
54
55 /************************************************************************
56  * Use Xilinx provided driver to send data to EEPROM using iic bus.
57  */
58 static void
59 send(u32 adr, u8 * data, u32 len)
60 {
61         u8 sendBuf[34];         /* first 2-bit is address and others are data */
62         u32 pos, wlen;
63         u32 ret;
64
65         wlen = 32;
66         for (pos = 0; pos < len; pos += 32) {
67                 if ((len - pos) < 32)
68                         wlen = len - pos;
69
70                 /* Put address and data bits together */
71                 sendBuf[0] = (u8) ((adr + pos) >> 8);
72                 sendBuf[1] = (u8) (adr + pos);
73                 memcpy(&sendBuf[2], &data[pos], wlen);
74
75                 /* Send to EEPROM through iic bus */
76                 ret = XIic_Send(XPAR_IIC_0_BASEADDR, CFG_I2C_EEPROM_ADDR >> 1,
77                                 sendBuf, wlen + 2);
78
79                 udelay(IIC_DELAY);
80         }
81 }
82
83 /************************************************************************
84  * Use Xilinx provided driver to read data from EEPROM using the iic bus.
85  */
86 static void
87 receive(u32 adr, u8 * data, u32 len)
88 {
89         u8 address[2];
90         u32 ret;
91
92         address[0] = (u8) (adr >> 8);
93         address[1] = (u8) adr;
94
95         /* Provide EEPROM address */
96         ret =
97             XIic_Send(XPAR_IIC_0_BASEADDR, CFG_I2C_EEPROM_ADDR >> 1, address,
98                       2);
99         /* Receive data from EEPROM */
100         ret =
101             XIic_Recv(XPAR_IIC_0_BASEADDR, CFG_I2C_EEPROM_ADDR >> 1, data, len);
102 }
103
104 /************************************************************************
105  * Convert a hexadecimal string to its equivalent integer value.
106  */
107 static u8
108 axtoi(u8 * hexStg)
109 {
110         u8 n;                   /* position in string */
111         u8 m;                   /* position in digit[] to shift */
112         u8 count;               /* loop index */
113         u8 intValue;            /* integer value of hex string */
114         u8 digit[2];            /* hold values to convert */
115
116         for (n = 0; n < 2; n++) {
117                 if (hexStg[n] == '\0')
118                         break;
119                 if (hexStg[n] > 0x29 && hexStg[n] < 0x40)
120                         digit[n] = hexStg[n] & 0x0f;
121                 else if (hexStg[n] >= 'a' && hexStg[n] <= 'f')
122                         digit[n] = (hexStg[n] & 0x0f) + 9;
123                 else if (hexStg[n] >= 'A' && hexStg[n] <= 'F')
124                         digit[n] = (hexStg[n] & 0x0f) + 9;
125                 else
126                         break;
127         }
128
129         intValue = 0;
130         count = n;
131         m = n - 1;
132         n = 0;
133         while (n < count) {
134                 intValue = intValue | (digit[n] << (m << 2));
135                 m--;            /* adjust the position to set */
136                 n++;            /* next digit to process */
137         }
138
139         return (intValue);
140 }
141
142 /************************************************************************
143  * Convert an integer string to its equivalent value.
144  */
145 static u8
146 atoi(uchar * string)
147 {
148         u8 res = 0;
149         while (*string >= '0' && *string <= '9') {
150                 res *= 10;
151                 res += *string - '0';
152                 string++;
153         }
154
155         return res;
156 }
157
158 /************************************************************************
159  * Key-value pairs are separated by "=" sign.
160  */
161 static void
162 findKey(uchar * buffer, int *loc, u8 len)
163 {
164         u32 i;
165
166         for (i = 0; i < len; i++)
167                 if (buffer[i] == '=') {
168                         *loc = i;
169                         return;
170                 }
171
172         /* return -1 is no "=" sign found */
173         *loc = -1;
174 }
175
176 /************************************************************************
177  * Compute a new ML300 CRC when user calls the saveenv command.
178  * Also update EEPROM with new CRC value.
179  */
180 static u8
181 update_crc(u32 len, uchar * data)
182 {
183         uchar temp[6] = { 'C', '=', 0x00, 0x00, 0x00, 0x00 };
184         u32 crc;                /* new crc value */
185         u32 i;
186
187         crc = 0;
188
189         /* calculate new CRC */
190         for (i = 0; i < len; i++)
191                 crc += data[i];
192
193         /* CRC includes key for check sum */
194         crc += 'C' + '=';
195
196         /* compose new CRC to be updated */
197         temp[2] = hex[(crc >> 4) & 0xf];
198         temp[3] = hex[crc & 0xf];
199
200         /* check to see if env size exceeded */
201         if (len + 6 > ENV_SIZE) {
202                 printf("ERROR: not enough space to store CRC on EEPROM");
203                 return 1;
204         }
205
206         memcpy(data + len, temp, 6);
207         return 0;
208 }
209
210 /************************************************************************
211  * Read out ML300 CRC and compare it with a runtime calculated ML300 CRC.
212  * If equal, then pass back a u-boot CRC value, otherwise pass back
213  * junk to indicate CRC error.
214 */
215 static void
216 read_crc(uchar * buffer, int len)
217 {
218         u32 addr, n;
219         u32 crc;                /* runtime crc */
220         u8 old[2] = { 0xff, 0xff };     /* current CRC in EEPROM */
221         u8 stop;                /* indication of end of env data */
222         u8 pre;                 /* previous EEPROM data bit */
223         int i, loc;
224
225         addr = CFG_ENV_OFFSET;  /* start from first env address */
226         n = 0;
227         pre = 1;
228         stop = 1;
229         crc = 0;
230
231         /* calculate runtime CRC according to ML300 and read back
232            old CRC stored in the EEPROM */
233         while (n < CFG_ENV_SIZE) {
234                 receive(addr, buffer, len);
235
236                 /* found two null chars, end of env */
237                 if ((pre || buffer[0]) == 0)
238                         break;
239
240                 findKey(buffer, &loc, len);
241
242                 /* found old check sum, read and store old CRC */
243                 if ((loc == 0 && pre == 'C')
244                     || (loc > 0 && buffer[loc - 1] == 'C'))
245                         receive(addr + loc + 1, old, 2);
246
247                 pre = buffer[len - 1];
248
249                 /* calculate runtime ML300 CRC */
250                 crc += buffer[0];
251                 i = 1;
252                 do {
253                         crc += buffer[i];
254                         stop = buffer[i] || buffer[i - 1];
255                         i++;
256                 } while (stop && (i < len));
257
258                 if (stop == 0)
259                         break;
260
261                 n += len;
262                 addr += len;
263         }
264
265         /* exclude old CRC from runtime calculation */
266         crc -= (old[0] + old[1]);
267
268         /* match CRC values, send back u-boot CRC */
269         if ((old[0] == hex[(crc >> 4) & 0xf])
270             && (old[1] == hex[crc & 0xf])) {
271                 crc = 0;
272                 n = 0;
273                 addr =
274                     CFG_ENV_OFFSET - offsetof(env_t, crc) + offsetof(env_t,
275                                                                      data);
276                 /* calculate u-boot crc */
277                 while (n < ENV_SIZE) {
278                         receive(addr, buffer, len);
279                         crc = crc32(crc, buffer, len);
280                         n += len;
281                         addr += len;
282                 }
283
284                 memcpy(buffer, &crc, 4);
285         }
286 }
287
288 /************************************************************************
289  * Convert IP address to hexadecimals.
290  */
291 static void
292 ip_ml300(uchar * s, uchar * res)
293 {
294         char temp[2];
295         u8 i;
296
297         res[0] = 0x00;
298
299         for (i = 0; i < 4; i++) {
300                 sprintf(temp, "%02x", atoi(s));
301                 s = (uchar *)strchr((char *)s, '.') + 1;
302                 strcat((char *)res, temp);
303         }
304 }
305
306 /************************************************************************
307  * Change 0xff (255), a dummy null char to 0x00.
308  */
309 static void
310 change_null(uchar * s)
311 {
312         if (s != NULL) {
313                 change_null((uchar *)strchr((char *)s + 1, 255));
314                 *(strchr((char *)s, 255)) = '\0';
315         }
316 }
317
318 /************************************************************************
319  * Update environment variable name and values to u-boot standard.
320  */
321 void
322 convert_env(void)
323 {
324         char *s;                /* pointer to env value */
325         char temp[20];          /* temp storage for addresses */
326
327         /* E -> ethaddr */
328         s = getenv("E");
329         if (s != NULL) {
330                 sprintf(temp, "%c%c.%c%c.%c%c.%c%c.%c%c.%c%c",
331                         s[0], s[1],  s[ 2], s[ 3],
332                         s[4], s[5],  s[ 6], s[ 7],
333                         s[8], s[9],  s[10], s[11] );
334                 setenv("ethaddr", temp);
335                 setenv("E", NULL);
336         }
337
338         /* L -> serial# */
339         s = getenv("L");
340         if (s != NULL) {
341                 setenv("serial#", s);
342                 setenv("L", NULL);
343         }
344
345         /* I -> ipaddr */
346         s = getenv("I");
347         if (s != NULL) {
348                 sprintf(temp, "%d.%d.%d.%d", axtoi((u8 *)s), axtoi((u8 *)(s + 2)),
349                         axtoi((u8 *)(s + 4)), axtoi((u8 *)(s + 6)));
350                 setenv("ipaddr", temp);
351                 setenv("I", NULL);
352         }
353
354         /* S -> serverip */
355         s = getenv("S");
356         if (s != NULL) {
357                 sprintf(temp, "%d.%d.%d.%d", axtoi((u8 *)s), axtoi((u8 *)(s + 2)),
358                         axtoi((u8 *)(s + 4)), axtoi((u8 *)(s + 6)));
359                 setenv("serverip", temp);
360                 setenv("S", NULL);
361         }
362
363         /* A -> bootargs */
364         s = getenv("A");
365         if (s != NULL) {
366                 setenv("bootargs", s);
367                 setenv("A", NULL);
368         }
369
370         /* F -> bootfile */
371         s = getenv("F");
372         if (s != NULL) {
373                 setenv("bootfile", s);
374                 setenv("F", NULL);
375         }
376
377         /* M -> bootcmd */
378         s = getenv("M");
379         if (s != NULL) {
380                 setenv("bootcmd", s);
381                 setenv("M", NULL);
382         }
383
384         /* Don't include C (CRC) */
385         setenv("C", NULL);
386 }
387
388 /************************************************************************
389  * Save user modified environment values back to EEPROM.
390  */
391 static void
392 save_env(void)
393 {
394         char eprom[ENV_SIZE];   /* buffer to be written back to EEPROM */
395         char *s, temp[20];
396         char ff[] = { 0xff, 0x00 };     /* dummy null value */
397         u32 len;                /* length of env to be written to EEPROM */
398
399         eprom[0] = 0x00;
400
401         /* ethaddr -> E */
402         s = getenv("ethaddr");
403         if (s != NULL) {
404                 strcat(eprom, "E=");
405                 sprintf(temp, "%c%c%c%c%c%c%c%c%c%c%c%c",
406                         *s, *(s + 1), *(s + 3), *(s + 4), *(s + 6), *(s + 7),
407                         *(s + 9), *(s + 10), *(s + 12), *(s + 13), *(s + 15),
408                         *(s + 16));
409                 strcat(eprom, temp);
410                 strcat(eprom, ff);
411         }
412
413         /* serial# -> L */
414         s = getenv("serial#");
415         if (s != NULL) {
416                 strcat(eprom, "L=");
417                 strcat(eprom, s);
418                 strcat(eprom, ff);
419         }
420
421         /* ipaddr -> I */
422         s = getenv("ipaddr");
423         if (s != NULL) {
424                 strcat(eprom, "I=");
425                 ip_ml300((uchar *)s, (uchar *)temp);
426                 strcat(eprom, temp);
427                 strcat(eprom, ff);
428         }
429
430         /* serverip -> S */
431         s = getenv("serverip");
432         if (s != NULL) {
433                 strcat(eprom, "S=");
434                 ip_ml300((uchar *)s, (uchar *)temp);
435                 strcat(eprom, temp);
436                 strcat(eprom, ff);
437         }
438
439         /* bootargs -> A */
440         s = getenv("bootargs");
441         if (s != NULL) {
442                 strcat(eprom, "A=");
443                 strcat(eprom, s);
444                 strcat(eprom, ff);
445         }
446
447         /* bootfile -> F */
448         s = getenv("bootfile");
449         if (s != NULL) {
450                 strcat(eprom, "F=");
451                 strcat(eprom, s);
452                 strcat(eprom, ff);
453         }
454
455         /* bootcmd -> M */
456         s = getenv("bootcmd");
457         if (s != NULL) {
458                 strcat(eprom, "M=");
459                 strcat(eprom, s);
460                 strcat(eprom, ff);
461         }
462
463         len = strlen(eprom);    /* find env length without crc */
464         change_null((uchar *)eprom);    /* change 0xff to 0x00 */
465
466         /* update EEPROM env values if there is enough space */
467         if (update_crc(len, (uchar *)eprom) == 0)
468                 send(CFG_ENV_OFFSET, (uchar *)eprom, len + 6);
469 }
470
471 /************************************************************************
472  * U-boot call for EEPROM read associated activities.
473  */
474 int
475 i2c_read(uchar chip, uint addr, int alen, uchar * buffer, int len)
476 {
477
478         if (envStep == 0) {
479                 /* first read call is for crc */
480                 read_crc(buffer, len);
481                 ++envStep;
482                 return 0;
483         } else if (envStep == 1) {
484                 /* then read out EEPROM content for runtime u-boot CRC calculation */
485                 receive(addr, buffer, len);
486
487                 if (addr + len - CFG_ENV_OFFSET == CFG_ENV_SIZE)
488                         /* end of runtime crc read */
489                         ++envStep;
490                 return 0;
491         }
492
493         if (len < 2) {
494                 /* when call getenv_r */
495                 receive(addr, buffer, len);
496         } else if (addr + len < CFG_ENV_OFFSET + CFG_ENV_SIZE) {
497                 /* calling env_relocate(), but don't read out
498                    crc value from EEPROM */
499                 receive(addr, buffer + 4, len);
500         } else {
501                 receive(addr, buffer + 4, len - 4);
502         }
503
504         return 0;
505
506 }
507
508 /************************************************************************
509  * U-boot call for EEPROM write acativities.
510  */
511 int
512 i2c_write(uchar chip, uint addr, int alen, uchar * buffer, int len)
513 {
514         /* save env on last page write called by u-boot */
515         if (addr + len >= CFG_ENV_OFFSET + CFG_ENV_SIZE)
516                 save_env();
517
518         return 0;
519 }
520
521 /************************************************************************
522  * Dummy function.
523  */
524 int
525 i2c_probe(uchar chip)
526 {
527         return 1;
528 }
529
530 #endif