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