?? iic_adapter.c
字號:
/******************************************************************************** Author: Xilinx, Inc.*** This program is free software; you can redistribute it and/or modify it* under the terms of the GNU General Public License as published by the* Free Software Foundation; either version 2 of the License, or (at your* option) any later version.*** XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A* COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS* ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR STANDARD,* XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION IS FREE* FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE FOR OBTAINING* ANY THIRD PARTY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.* XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO* THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY* WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM* CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND* FITNESS FOR A PARTICULAR PURPOSE.*** Xilinx hardware products are not intended for use in life support* appliances, devices, or systems. Use in such applications is* expressly prohibited.*** (c) Copyright 2002-2004 Xilinx Inc.* All rights reserved.*** You should have received a copy of the GNU General Public License along* with this program; if not, write to the Free Software Foundation, Inc.,* 675 Mass Ave, Cambridge, MA 02139, USA.*******************************************************************************/#include <common.h>#include <environment.h>#include <net.h>#include <configs/ml300.h>#include "xparameters.h"#ifdef CFG_ENV_IS_IN_EEPROM#include <i2c.h>#include "xiic_l.h"#define IIC_DELAY 5000static u8 envStep = 0; /* 0 means crc has not been read */const u8 hex[] = "0123456789ABCDEF"; /* lookup table for ML300 CRC *//************************************************************************ * Use Xilinx provided driver to send data to EEPROM using iic bus. */static voidsend(u32 adr, u8 * data, u32 len){ u8 sendBuf[34]; /* first 2-bit is address and others are data */ u32 pos, wlen; u32 ret; wlen = 32; for (pos = 0; pos < len; pos += 32) { if ((len - pos) < 32) wlen = len - pos; /* Put address and data bits together */ sendBuf[0] = (u8) ((adr + pos) >> 8); sendBuf[1] = (u8) (adr + pos); memcpy(&sendBuf[2], &data[pos], wlen); /* Send to EEPROM through iic bus */ ret = XIic_Send(XPAR_IIC_0_BASEADDR, CFG_I2C_EEPROM_ADDR >> 1, sendBuf, wlen + 2); udelay(IIC_DELAY); }}/************************************************************************ * Use Xilinx provided driver to read data from EEPROM using the iic bus. */static voidreceive(u32 adr, u8 * data, u32 len){ u8 address[2]; u32 ret; address[0] = (u8) (adr >> 8); address[1] = (u8) adr; /* Provide EEPROM address */ ret = XIic_Send(XPAR_IIC_0_BASEADDR, CFG_I2C_EEPROM_ADDR >> 1, address, 2); /* Receive data from EEPROM */ ret = XIic_Recv(XPAR_IIC_0_BASEADDR, CFG_I2C_EEPROM_ADDR >> 1, data, len);}/************************************************************************ * Convert a hexadecimal string to its equivalent integer value. */static u8axtoi(u8 * hexStg){ u8 n; /* position in string */ u8 m; /* position in digit[] to shift */ u8 count; /* loop index */ u8 intValue; /* integer value of hex string */ u8 digit[2]; /* hold values to convert */ for (n = 0; n < 2; n++) { if (hexStg[n] == '\0') break; if (hexStg[n] > 0x29 && hexStg[n] < 0x40) digit[n] = hexStg[n] & 0x0f; else if (hexStg[n] >= 'a' && hexStg[n] <= 'f') digit[n] = (hexStg[n] & 0x0f) + 9; else if (hexStg[n] >= 'A' && hexStg[n] <= 'F') digit[n] = (hexStg[n] & 0x0f) + 9; else break; } intValue = 0; count = n; m = n - 1; n = 0; while (n < count) { intValue = intValue | (digit[n] << (m << 2)); m--; /* adjust the position to set */ n++; /* next digit to process */ } return (intValue);}/************************************************************************ * Convert an integer string to its equivalent value. */static u8atoi(uchar * string){ u8 res = 0; while (*string >= '0' && *string <= '9') { res *= 10; res += *string - '0'; string++; } return res;}/************************************************************************ * Key-value pairs are separated by "=" sign. */static voidfindKey(uchar * buffer, int *loc, u8 len){ u32 i; for (i = 0; i < len; i++) if (buffer[i] == '=') { *loc = i; return; } /* return -1 is no "=" sign found */ *loc = -1;}/************************************************************************ * Compute a new ML300 CRC when user calls the saveenv command. * Also update EEPROM with new CRC value. */static u8update_crc(u32 len, uchar * data){ uchar temp[6] = { 'C', '=', 0x00, 0x00, 0x00, 0x00 }; u32 crc; /* new crc value */ u32 i; crc = 0; /* calculate new CRC */ for (i = 0; i < len; i++) crc += data[i]; /* CRC includes key for check sum */ crc += 'C' + '='; /* compose new CRC to be updated */ temp[2] = hex[(crc >> 4) & 0xf]; temp[3] = hex[crc & 0xf]; /* check to see if env size exceeded */ if (len + 6 > ENV_SIZE) { printf("ERROR: not enough space to store CRC on EEPROM"); return 1; } memcpy(data + len, temp, 6); return 0;}/************************************************************************ * Read out ML300 CRC and compare it with a runtime calculated ML300 CRC. * If equal, then pass back a u-boot CRC value, otherwise pass back * junk to indicate CRC error.*/static voidread_crc(uchar * buffer, int len){ u32 addr, n; u32 crc; /* runtime crc */ u8 old[2] = { 0xff, 0xff }; /* current CRC in EEPROM */ u8 stop; /* indication of end of env data */ u8 pre; /* previous EEPROM data bit */ int i, loc; addr = CFG_ENV_OFFSET; /* start from first env address */ n = 0; pre = 1; stop = 1; crc = 0; /* calculate runtime CRC according to ML300 and read back old CRC stored in the EEPROM */ while (n < CFG_ENV_SIZE) { receive(addr, buffer, len); /* found two null chars, end of env */ if ((pre || buffer[0]) == 0) break; findKey(buffer, &loc, len); /* found old check sum, read and store old CRC */ if ((loc == 0 && pre == 'C') || (loc > 0 && buffer[loc - 1] == 'C')) receive(addr + loc + 1, old, 2); pre = buffer[len - 1]; /* calculate runtime ML300 CRC */ crc += buffer[0]; i = 1; do { crc += buffer[i]; stop = buffer[i] || buffer[i - 1]; i++; } while (stop && (i < len)); if (stop == 0) break; n += len; addr += len; } /* exclude old CRC from runtime calculation */ crc -= (old[0] + old[1]); /* match CRC values, send back u-boot CRC */ if ((old[0] == hex[(crc >> 4) & 0xf]) && (old[1] == hex[crc & 0xf])) { crc = 0; n = 0; addr = CFG_ENV_OFFSET - offsetof(env_t, crc) + offsetof(env_t, data); /* calculate u-boot crc */ while (n < ENV_SIZE) { receive(addr, buffer, len); crc = crc32(crc, buffer, len); n += len; addr += len; } memcpy(buffer, &crc, 4); }}/************************************************************************ * Convert IP address to hexadecimals. */static voidip_ml300(uchar * s, uchar * res){ char temp[2]; u8 i; res[0] = 0x00; for (i = 0; i < 4; i++) { sprintf(temp, "%02x", atoi(s)); s = (uchar *)strchr((char *)s, '.') + 1; strcat((char *)res, temp); }}/************************************************************************ * Change 0xff (255), a dummy null char to 0x00. */static voidchange_null(uchar * s){ if (s != NULL) { change_null((uchar *)strchr((char *)s + 1, 255)); *(strchr((char *)s, 255)) = '\0'; }}/************************************************************************ * Update environment variable name and values to u-boot standard. */voidconvert_env(void){ char *s; /* pointer to env value */ char temp[20]; /* temp storage for addresses */ /* E -> ethaddr */ s = getenv("E"); if (s != NULL) { sprintf(temp, "%c%c.%c%c.%c%c.%c%c.%c%c.%c%c", s[0], s[1], s[ 2], s[ 3], s[4], s[5], s[ 6], s[ 7], s[8], s[9], s[10], s[11] ); setenv("ethaddr", temp); setenv("E", NULL); } /* L -> serial# */ s = getenv("L"); if (s != NULL) { setenv("serial#", s); setenv("L", NULL); } /* I -> ipaddr */ s = getenv("I"); if (s != NULL) { sprintf(temp, "%d.%d.%d.%d", axtoi((u8 *)s), axtoi((u8 *)(s + 2)), axtoi((u8 *)(s + 4)), axtoi((u8 *)(s + 6))); setenv("ipaddr", temp); setenv("I", NULL); } /* S -> serverip */ s = getenv("S"); if (s != NULL) { sprintf(temp, "%d.%d.%d.%d", axtoi((u8 *)s), axtoi((u8 *)(s + 2)), axtoi((u8 *)(s + 4)), axtoi((u8 *)(s + 6))); setenv("serverip", temp); setenv("S", NULL); } /* A -> bootargs */ s = getenv("A"); if (s != NULL) { setenv("bootargs", s); setenv("A", NULL); } /* F -> bootfile */ s = getenv("F"); if (s != NULL) { setenv("bootfile", s); setenv("F", NULL); } /* M -> bootcmd */ s = getenv("M"); if (s != NULL) { setenv("bootcmd", s); setenv("M", NULL); } /* Don't include C (CRC) */ setenv("C", NULL);}/************************************************************************ * Save user modified environment values back to EEPROM. */static voidsave_env(void){ char eprom[ENV_SIZE]; /* buffer to be written back to EEPROM */ char *s, temp[20]; char ff[] = { 0xff, 0x00 }; /* dummy null value */ u32 len; /* length of env to be written to EEPROM */ eprom[0] = 0x00; /* ethaddr -> E */ s = getenv("ethaddr"); if (s != NULL) { strcat(eprom, "E="); sprintf(temp, "%c%c%c%c%c%c%c%c%c%c%c%c", *s, *(s + 1), *(s + 3), *(s + 4), *(s + 6), *(s + 7), *(s + 9), *(s + 10), *(s + 12), *(s + 13), *(s + 15), *(s + 16)); strcat(eprom, temp); strcat(eprom, ff); } /* serial# -> L */ s = getenv("serial#"); if (s != NULL) { strcat(eprom, "L="); strcat(eprom, s); strcat(eprom, ff); } /* ipaddr -> I */ s = getenv("ipaddr"); if (s != NULL) { strcat(eprom, "I="); ip_ml300((uchar *)s, (uchar *)temp); strcat(eprom, temp); strcat(eprom, ff); } /* serverip -> S */ s = getenv("serverip"); if (s != NULL) { strcat(eprom, "S="); ip_ml300((uchar *)s, (uchar *)temp); strcat(eprom, temp); strcat(eprom, ff); } /* bootargs -> A */ s = getenv("bootargs"); if (s != NULL) { strcat(eprom, "A="); strcat(eprom, s); strcat(eprom, ff); } /* bootfile -> F */ s = getenv("bootfile"); if (s != NULL) { strcat(eprom, "F="); strcat(eprom, s); strcat(eprom, ff); } /* bootcmd -> M */ s = getenv("bootcmd"); if (s != NULL) { strcat(eprom, "M="); strcat(eprom, s); strcat(eprom, ff); } len = strlen(eprom); /* find env length without crc */ change_null((uchar *)eprom); /* change 0xff to 0x00 */ /* update EEPROM env values if there is enough space */ if (update_crc(len, (uchar *)eprom) == 0) send(CFG_ENV_OFFSET, (uchar *)eprom, len + 6);}/************************************************************************ * U-boot call for EEPROM read associated activities. */inti2c_read(uchar chip, uint addr, int alen, uchar * buffer, int len){ if (envStep == 0) { /* first read call is for crc */ read_crc(buffer, len); ++envStep; return 0; } else if (envStep == 1) { /* then read out EEPROM content for runtime u-boot CRC calculation */ receive(addr, buffer, len); if (addr + len - CFG_ENV_OFFSET == CFG_ENV_SIZE) /* end of runtime crc read */ ++envStep; return 0; } if (len < 2) { /* when call getenv_r */ receive(addr, buffer, len); } else if (addr + len < CFG_ENV_OFFSET + CFG_ENV_SIZE) { /* calling env_relocate(), but don't read out crc value from EEPROM */ receive(addr, buffer + 4, len); } else { receive(addr, buffer + 4, len - 4); } return 0;}/************************************************************************ * U-boot call for EEPROM write acativities. */inti2c_write(uchar chip, uint addr, int alen, uchar * buffer, int len){ /* save env on last page write called by u-boot */ if (addr + len >= CFG_ENV_OFFSET + CFG_ENV_SIZE) save_env(); return 0;}/************************************************************************ * Dummy function. */inti2c_probe(uchar chip){ return 1;}#endif
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -