summaryrefslogtreecommitdiff
path: root/board/xilinx/xilinx_iic/iic_adapter.c
diff options
context:
space:
mode:
authorwdenk <wdenk>2004-09-29 22:43:59 (GMT)
committerwdenk <wdenk>2004-09-29 22:43:59 (GMT)
commita06752e36be7fc74b4a928026b63b1bf1764497e (patch)
treeb71ddbcee4e4cc03e8ea98738b605a1c3879a703 /board/xilinx/xilinx_iic/iic_adapter.c
parentda93ed8147a000505ac7b7ed4e2fb50532596a3c (diff)
downloadu-boot-a06752e36be7fc74b4a928026b63b1bf1764497e.tar.xz
* Patch by Sean Chang, 9 Aug 2004:
- Added I2C support for ML300. - Added support for ML300 to read out its environment information stored on the EEPROM. - Added support to use board specific parameters as part of U-Boot's environment information. - Updated MLD files to support configuration for new features above. * Patches by Travis Sawyer, 5 Aug 2004: - Remove incorrect bridge settings for eth group 6 - Add call to setup bridge in ppc_440x_eth_initialize - Fix ppc_440x_eth_init to reset the phy only if its the first time through, otherwise, just check the phy for the autonegotiated speed/duplex. This allows the use of netconsole - only print the speed/duplex the first time the phy is reset.
Diffstat (limited to 'board/xilinx/xilinx_iic/iic_adapter.c')
-rw-r--r--board/xilinx/xilinx_iic/iic_adapter.c529
1 files changed, 529 insertions, 0 deletions
diff --git a/board/xilinx/xilinx_iic/iic_adapter.c b/board/xilinx/xilinx_iic/iic_adapter.c
new file mode 100644
index 0000000..8ddba6a
--- /dev/null
+++ b/board/xilinx/xilinx_iic/iic_adapter.c
@@ -0,0 +1,529 @@
+/******************************************************************************
+*
+* 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 5000
+
+static 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 void
+send(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 void
+receive(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 u8
+axtoi(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 u8
+atoi(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 void
+findKey(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 u8
+update_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 void
+read_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 void
+ip_ml300(uchar * s, uchar * res)
+{
+ uchar temp[2];
+ u8 i;
+
+ res[0] = 0x00;
+
+ for (i = 0; i < 4; i++) {
+ sprintf(temp, "%02x", atoi(s));
+ s = strchr(s, '.') + 1;
+ strcat(res, temp);
+ }
+}
+
+/************************************************************************
+ * Change 0xff (255), a dummy null char to 0x00.
+ */
+static void
+change_null(uchar * s)
+{
+ if (s != NULL) {
+ change_null(strchr(s + 1, 255));
+ *(strchr(s, 255)) = '\0';
+ }
+}
+
+/************************************************************************
+ * Update environment variable name and values to u-boot standard.
+ */
+void
+convert_env(void)
+{
+ uchar *s; /* pointer to env value */
+ uchar 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++, *s++, *s++, *s++, *s++, *s++,
+ *s++, *s++, *s++, *s++, *s++, *s);
+ 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(s), axtoi(s + 2),
+ axtoi(s + 4), axtoi(s + 6));
+ setenv("ipaddr", temp);
+ setenv("I", NULL);
+ }
+
+ /* S -> serverip */
+ s = getenv("S");
+ if (s != NULL) {
+ sprintf(temp, "%d.%d.%d.%d", axtoi(s), axtoi(s + 2),
+ axtoi(s + 4), axtoi(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 void
+save_env(void)
+{
+ uchar eprom[ENV_SIZE]; /* buffer to be written back to EEPROM */
+ uchar *s, temp[20];
+ uchar 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(s, temp);
+ strcat(eprom, temp);
+ strcat(eprom, ff);
+ }
+
+ /* serverip -> S */
+ s = getenv("serverip");
+ if (s != NULL) {
+ strcat(eprom, "S=");
+ ip_ml300(s, 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(eprom); /* change 0xff to 0x00 */
+
+ /* update EEPROM env values if there is enough space */
+ if (update_crc(len, eprom) == 0)
+ send(CFG_ENV_OFFSET, eprom, len + 6);
+}
+
+/************************************************************************
+ * U-boot call for EEPROM read associated activities.
+ */
+int
+i2c_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.
+ */
+int
+i2c_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.
+ */
+int
+i2c_probe(uchar chip)
+{
+ return 1;
+}
+
+#endif