summaryrefslogtreecommitdiff
path: root/board/xilinx/xilinx_iic
diff options
context:
space:
mode:
authorwdenk <wdenk>2004-09-29 22:43:59 +0000
committerwdenk <wdenk>2004-09-29 22:43:59 +0000
commita06752e36be7fc74b4a928026b63b1bf1764497e (patch)
treeb71ddbcee4e4cc03e8ea98738b605a1c3879a703 /board/xilinx/xilinx_iic
parentda93ed8147a000505ac7b7ed4e2fb50532596a3c (diff)
* 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')
-rw-r--r--board/xilinx/xilinx_iic/iic_adapter.c529
-rw-r--r--board/xilinx/xilinx_iic/xiic_l.c484
-rw-r--r--board/xilinx/xilinx_iic/xiic_l.h150
3 files changed, 1163 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 000000000..8ddba6ade
--- /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
diff --git a/board/xilinx/xilinx_iic/xiic_l.c b/board/xilinx/xilinx_iic/xiic_l.c
new file mode 100644
index 000000000..6b7816373
--- /dev/null
+++ b/board/xilinx/xilinx_iic/xiic_l.c
@@ -0,0 +1,484 @@
+/* $Id: xiic_l.c,v 1.2 2002/12/05 19:32:40 meinelte Exp $ */
+/******************************************************************************
+*
+* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
+* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
+* SOLUTIONS FOR XILINX DEVICES. 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 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.
+*
+* (c) Copyright 2002 Xilinx Inc.
+* All rights reserved.
+*
+******************************************************************************/
+/*****************************************************************************/
+/**
+*
+* @file xiic_l.c
+*
+* This file contains low-level driver functions that can be used to access the
+* device. The user should refer to the hardware device specification for more
+* details of the device operation.
+*
+* <pre>
+* MODIFICATION HISTORY:
+*
+* Ver Who Date Changes
+* ----- --- ------- -----------------------------------------------
+* 1.01b jhl 5/13/02 First release
+* 1.01b jhl 10/14/02 Corrected bug in the receive function, the setup of the
+* interrupt status mask was not being done in the loop such
+* that a read would sometimes fail on the last byte because
+* the transmit error which should have been ignored was
+* being used. This would leave an extra byte in the FIFO
+* and the bus throttled such that the next operation would
+* also fail. Also updated the receive function to not
+* disable the device after the last byte until after the
+* bus transitions to not busy which is more consistent
+* with the expected behavior.
+* 1.01c ecm 12/05/02 new rev
+* </pre>
+*
+****************************************************************************/
+
+/***************************** Include Files *******************************/
+
+#include "xbasic_types.h"
+#include "xio.h"
+#include "xipif_v1_23_b.h"
+#include "xiic_l.h"
+
+/************************** Constant Definitions ***************************/
+
+/**************************** Type Definitions *****************************/
+
+
+/***************** Macros (Inline Functions) Definitions *******************/
+
+
+/******************************************************************************
+*
+* This macro clears the specified interrupt in the IPIF interrupt status
+* register. It is non-destructive in that the register is read and only the
+* interrupt specified is cleared. Clearing an interrupt acknowledges it.
+*
+* @param BaseAddress contains the IPIF registers base address.
+*
+* @param InterruptMask contains the interrupts to be disabled
+*
+* @return
+*
+* None.
+*
+* @note
+*
+* Signature: void XIic_mClearIisr(u32 BaseAddress,
+* u32 InterruptMask);
+*
+******************************************************************************/
+#define XIic_mClearIisr(BaseAddress, InterruptMask) \
+ XIIF_V123B_WRITE_IISR((BaseAddress), \
+ XIIF_V123B_READ_IISR(BaseAddress) & (InterruptMask))
+
+/******************************************************************************
+*
+* This macro sends the address for a 7 bit address during both read and write
+* operations. It takes care of the details to format the address correctly.
+* This macro is designed to be called internally to the drivers.
+*
+* @param SlaveAddress contains the address of the slave to send to.
+*
+* @param Operation indicates XIIC_READ_OPERATION or XIIC_WRITE_OPERATION
+*
+* @return
+*
+* None.
+*
+* @note
+*
+* Signature: void XIic_mSend7BitAddr(u16 SlaveAddress, u8 Operation);
+*
+******************************************************************************/
+#define XIic_mSend7BitAddress(BaseAddress, SlaveAddress, Operation) \
+{ \
+ u8 LocalAddr = (u8)(SlaveAddress << 1); \
+ LocalAddr = (LocalAddr & 0xFE) | (Operation); \
+ XIo_Out8(BaseAddress + XIIC_DTR_REG_OFFSET, LocalAddr); \
+}
+
+/************************** Function Prototypes ****************************/
+
+static unsigned RecvData (u32 BaseAddress, u8 * BufferPtr,
+ unsigned ByteCount);
+static unsigned SendData (u32 BaseAddress, u8 * BufferPtr,
+ unsigned ByteCount);
+
+/************************** Variable Definitions **************************/
+
+
+/****************************************************************************/
+/**
+* Receive data as a master on the IIC bus. This function receives the data
+* using polled I/O and blocks until the data has been received. It only
+* supports 7 bit addressing and non-repeated start modes of operation. The
+* user is responsible for ensuring the bus is not busy if multiple masters
+* are present on the bus.
+*
+* @param BaseAddress contains the base address of the IIC device.
+* @param Address contains the 7 bit IIC address of the device to send the
+* specified data to.
+* @param BufferPtr points to the data to be sent.
+* @param ByteCount is the number of bytes to be sent.
+*
+* @return
+*
+* The number of bytes received.
+*
+* @note
+*
+* None
+*
+******************************************************************************/
+unsigned XIic_Recv (u32 BaseAddress, u8 Address,
+ u8 * BufferPtr, unsigned ByteCount)
+{
+ u8 CntlReg;
+ unsigned RemainingByteCount;
+
+ /* Tx error is enabled incase the address (7 or 10) has no device to answer
+ * with Ack. When only one byte of data, must set NO ACK before address goes
+ * out therefore Tx error must not be enabled as it will go off immediately
+ * and the Rx full interrupt will be checked. If full, then the one byte
+ * was received and the Tx error will be disabled without sending an error
+ * callback msg.
+ */
+ XIic_mClearIisr (BaseAddress,
+ XIIC_INTR_RX_FULL_MASK | XIIC_INTR_TX_ERROR_MASK |
+ XIIC_INTR_ARB_LOST_MASK);
+
+ /* Set receive FIFO occupancy depth for 1 byte (zero based)
+ */
+ XIo_Out8 (BaseAddress + XIIC_RFD_REG_OFFSET, 0);
+
+ /* 7 bit slave address, send the address for a read operation
+ * and set the state to indicate the address has been sent
+ */
+ XIic_mSend7BitAddress (BaseAddress, Address, XIIC_READ_OPERATION);
+
+ /* MSMS gets set after putting data in FIFO. Start the master receive
+ * operation by setting CR Bits MSMS to Master, if the buffer is only one
+ * byte, then it should not be acknowledged to indicate the end of data
+ */
+ CntlReg = XIIC_CR_MSMS_MASK | XIIC_CR_ENABLE_DEVICE_MASK;
+ if (ByteCount == 1) {
+ CntlReg |= XIIC_CR_NO_ACK_MASK;
+ }
+
+ /* Write out the control register to start receiving data and call the
+ * function to receive each byte into the buffer
+ */
+ XIo_Out8 (BaseAddress + XIIC_CR_REG_OFFSET, CntlReg);
+
+ /* Clear the latched interrupt status for the bus not busy bit which must
+ * be done while the bus is busy
+ */
+ XIic_mClearIisr (BaseAddress, XIIC_INTR_BNB_MASK);
+
+ /* Try to receive the data from the IIC bus */
+
+ RemainingByteCount = RecvData (BaseAddress, BufferPtr, ByteCount);
+ /*
+ * The receive is complete, disable the IIC device and return the number of
+ * bytes that was received
+ */
+ XIo_Out8 (BaseAddress + XIIC_CR_REG_OFFSET, 0);
+
+ /* Return the number of bytes that was received */
+
+ return ByteCount - RemainingByteCount;
+}
+
+/******************************************************************************
+*
+* Receive the specified data from the device that has been previously addressed
+* on the IIC bus. This function assumes that the 7 bit address has been sent
+* and it should wait for the transmit of the address to complete.
+*
+* @param BaseAddress contains the base address of the IIC device.
+* @param BufferPtr points to the buffer to hold the data that is received.
+* @param ByteCount is the number of bytes to be received.
+*
+* @return
+*
+* The number of bytes remaining to be received.
+*
+* @note
+*
+* This function does not take advantage of the receive FIFO because it is
+* designed for minimal code space and complexity. It contains loops that
+* that could cause the function not to return if the hardware is not working.
+*
+* This function assumes that the calling function will disable the IIC device
+* after this function returns.
+*
+******************************************************************************/
+static unsigned RecvData (u32 BaseAddress, u8 * BufferPtr, unsigned ByteCount)
+{
+ u8 CntlReg;
+ u32 IntrStatusMask;
+ u32 IntrStatus;
+
+ /* Attempt to receive the specified number of bytes on the IIC bus */
+
+ while (ByteCount > 0) {
+ /* Setup the mask to use for checking errors because when receiving one
+ * byte OR the last byte of a multibyte message an error naturally
+ * occurs when the no ack is done to tell the slave the last byte
+ */
+ if (ByteCount == 1) {
+ IntrStatusMask =
+ XIIC_INTR_ARB_LOST_MASK | XIIC_INTR_BNB_MASK;
+ } else {
+ IntrStatusMask =
+ XIIC_INTR_ARB_LOST_MASK |
+ XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_BNB_MASK;
+ }
+
+ /* Wait for the previous transmit and the 1st receive to complete
+ * by checking the interrupt status register of the IPIF
+ */
+ while (1) {
+ IntrStatus = XIIF_V123B_READ_IISR (BaseAddress);
+ if (IntrStatus & XIIC_INTR_RX_FULL_MASK) {
+ break;
+ }
+ /* Check the transmit error after the receive full because when
+ * sending only one byte transmit error will occur because of the
+ * no ack to indicate the end of the data
+ */
+ if (IntrStatus & IntrStatusMask) {
+ return ByteCount;
+ }
+ }
+
+ CntlReg = XIo_In8 (BaseAddress + XIIC_CR_REG_OFFSET);
+
+ /* Special conditions exist for the last two bytes so check for them
+ * Note that the control register must be setup for these conditions
+ * before the data byte which was already received is read from the
+ * receive FIFO (while the bus is throttled
+ */
+ if (ByteCount == 1) {
+ /* For the last data byte, it has already been read and no ack
+ * has been done, so clear MSMS while leaving the device enabled
+ * so it can get off the IIC bus appropriately with a stop.
+ */
+ XIo_Out8 (BaseAddress + XIIC_CR_REG_OFFSET,
+ XIIC_CR_ENABLE_DEVICE_MASK);
+ }
+
+ /* Before the last byte is received, set NOACK to tell the slave IIC
+ * device that it is the end, this must be done before reading the byte
+ * from the FIFO
+ */
+ if (ByteCount == 2) {
+ /* Write control reg with NO ACK allowing last byte to
+ * have the No ack set to indicate to slave last byte read.
+ */
+ XIo_Out8 (BaseAddress + XIIC_CR_REG_OFFSET,
+ CntlReg | XIIC_CR_NO_ACK_MASK);
+ }
+
+ /* Read in data from the FIFO and unthrottle the bus such that the
+ * next byte is read from the IIC bus
+ */
+ *BufferPtr++ = XIo_In8 (BaseAddress + XIIC_DRR_REG_OFFSET);
+
+ /* Clear the latched interrupt status so that it will be updated with
+ * the new state when it changes, this must be done after the receive
+ * register is read
+ */
+ XIic_mClearIisr (BaseAddress, XIIC_INTR_RX_FULL_MASK |
+ XIIC_INTR_TX_ERROR_MASK |
+ XIIC_INTR_ARB_LOST_MASK);
+ ByteCount--;
+ }
+
+ /* Wait for the bus to transition to not busy before returning, the IIC
+ * device cannot be disabled until this occurs. It should transition as
+ * the MSMS bit of the control register was cleared before the last byte
+ * was read from the FIFO.
+ */
+ while (1) {
+ if (XIIF_V123B_READ_IISR (BaseAddress) & XIIC_INTR_BNB_MASK) {
+ break;
+ }
+ }
+
+ return ByteCount;
+}
+
+/****************************************************************************/
+/**
+* Send data as a master on the IIC bus. This function sends the data
+* using polled I/O and blocks until the data has been sent. It only supports
+* 7 bit addressing and non-repeated start modes of operation. The user is
+* responsible for ensuring the bus is not busy if multiple masters are present
+* on the bus.
+*
+* @param BaseAddress contains the base address of the IIC device.
+* @param Address contains the 7 bit IIC address of the device to send the
+* specified data to.
+* @param BufferPtr points to the data to be sent.
+* @param ByteCount is the number of bytes to be sent.
+*
+* @return
+*
+* The number of bytes sent.
+*
+* @note
+*
+* None
+*
+******************************************************************************/
+unsigned XIic_Send (u32 BaseAddress, u8 Address,
+ u8 * BufferPtr, unsigned ByteCount)
+{
+ unsigned RemainingByteCount;
+
+ /* Put the address into the FIFO to be sent and indicate that the operation
+ * to be performed on the bus is a write operation
+ */
+ XIic_mSend7BitAddress (BaseAddress, Address, XIIC_WRITE_OPERATION);
+
+ /* Clear the latched interrupt status so that it will be updated with the
+ * new state when it changes, this must be done after the address is put
+ * in the FIFO
+ */
+ XIic_mClearIisr (BaseAddress, XIIC_INTR_TX_EMPTY_MASK |
+ XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_ARB_LOST_MASK);
+
+ /* MSMS must be set after putting data into transmit FIFO, indicate the
+ * direction is transmit, this device is master and enable the IIC device
+ */
+ XIo_Out8 (BaseAddress + XIIC_CR_REG_OFFSET,
+ XIIC_CR_MSMS_MASK | XIIC_CR_DIR_IS_TX_MASK |
+ XIIC_CR_ENABLE_DEVICE_MASK);
+
+ /* Clear the latched interrupt
+ * status for the bus not busy bit which must be done while the bus is busy
+ */
+ XIic_mClearIisr (BaseAddress, XIIC_INTR_BNB_MASK);
+
+ /* Send the specified data to the device on the IIC bus specified by the
+ * the address
+ */
+ RemainingByteCount = SendData (BaseAddress, BufferPtr, ByteCount);
+
+ /*
+ * The send is complete, disable the IIC device and return the number of
+ * bytes that was sent
+ */
+ XIo_Out8 (BaseAddress + XIIC_CR_REG_OFFSET, 0);
+
+ return ByteCount - RemainingByteCount;
+}
+
+/******************************************************************************
+*
+* Send the specified buffer to the device that has been previously addressed
+* on the IIC bus. This function assumes that the 7 bit address has been sent
+* and it should wait for the transmit of the address to complete.
+*
+* @param BaseAddress contains the base address of the IIC device.
+* @param BufferPtr points to the data to be sent.
+* @param ByteCount is the number of bytes to be sent.
+*
+* @return
+*
+* The number of bytes remaining to be sent.
+*
+* @note
+*
+* This function does not take advantage of the transmit FIFO because it is
+* designed for minimal code space and complexity. It contains loops that
+* that could cause the function not to return if the hardware is not working.
+*
+******************************************************************************/
+static unsigned SendData (u32 BaseAddress, u8 * BufferPtr, unsigned ByteCount)
+{
+ u32 IntrStatus;
+
+ /* Send the specified number of bytes in the specified buffer by polling
+ * the device registers and blocking until complete
+ */
+ while (ByteCount > 0) {
+ /* Wait for the transmit to be empty before sending any more data
+ * by polling the interrupt status register
+ */
+ while (1) {
+ IntrStatus = XIIF_V123B_READ_IISR (BaseAddress);
+
+ if (IntrStatus & (XIIC_INTR_TX_ERROR_MASK |
+ XIIC_INTR_ARB_LOST_MASK |
+ XIIC_INTR_BNB_MASK)) {
+ return ByteCount;
+ }
+
+ if (IntrStatus & XIIC_INTR_TX_EMPTY_MASK) {
+ break;
+ }
+ }
+ /* If there is more than one byte to send then put the next byte to send
+ * into the transmit FIFO
+ */
+ if (ByteCount > 1) {
+ XIo_Out8 (BaseAddress + XIIC_DTR_REG_OFFSET,
+ *BufferPtr++);
+ } else {
+ /* Set the stop condition before sending the last byte of data so that
+ * the stop condition will be generated immediately following the data
+ * This is done by clearing the MSMS bit in the control register.
+ */
+ XIo_Out8 (BaseAddress + XIIC_CR_REG_OFFSET,
+ XIIC_CR_ENABLE_DEVICE_MASK |
+ XIIC_CR_DIR_IS_TX_MASK);
+
+ /* Put the last byte to send in the transmit FIFO */
+
+ XIo_Out8 (BaseAddress + XIIC_DTR_REG_OFFSET,
+ *BufferPtr++);
+ }
+
+ /* Clear the latched interrupt status register and this must be done after
+ * the transmit FIFO has been written to or it won't clear
+ */
+ XIic_mClearIisr (BaseAddress, XIIC_INTR_TX_EMPTY_MASK);
+
+ /* Update the byte count to reflect the byte sent and clear the latched
+ * interrupt status so it will be updated for the new state
+ */
+ ByteCount--;
+ }
+
+ /* Wait for the bus to transition to not busy before returning, the IIC
+ * device cannot be disabled until this occurs.
+ * Note that this is different from a receive operation because the stop
+ * condition causes the bus to go not busy.
+ */
+ while (1) {
+ if (XIIF_V123B_READ_IISR (BaseAddress) & XIIC_INTR_BNB_MASK) {
+ break;
+ }
+ }
+
+ return ByteCount;
+}
diff --git a/board/xilinx/xilinx_iic/xiic_l.h b/board/xilinx/xilinx_iic/xiic_l.h
new file mode 100644
index 000000000..a2c4c496a
--- /dev/null
+++ b/board/xilinx/xilinx_iic/xiic_l.h
@@ -0,0 +1,150 @@
+/* $Id: xiic_l.h,v 1.2 2002/12/05 19:32:40 meinelte Exp $ */
+/*****************************************************************************
+*
+* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
+* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
+* SOLUTIONS FOR XILINX DEVICES. 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 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.
+*
+* (c) Copyright 2002 Xilinx Inc.
+* All rights reserved.
+*
+*****************************************************************************/
+/****************************************************************************/
+/**
+*
+* @file xiic_l.h
+*
+* This header file contains identifiers and low-level driver functions (or
+* macros) that can be used to access the device. High-level driver functions
+* are defined in xiic.h.
+*
+* <pre>
+* MODIFICATION HISTORY:
+*
+* Ver Who Date Changes
+* ----- ---- -------- -----------------------------------------------
+* 1.00b jhl 05/07/02 First release
+* 1.01c ecm 12/05/02 new rev
+* </pre>
+*
+*****************************************************************************/
+
+#ifndef XIIC_L_H /* prevent circular inclusions */
+#define XIIC_L_H /* by using protection macros */
+
+/***************************** Include Files ********************************/
+
+#include "xbasic_types.h"
+
+/************************** Constant Definitions ****************************/
+
+#define XIIC_MSB_OFFSET 3
+
+#define XIIC_REG_OFFSET 0x100 + XIIC_MSB_OFFSET
+
+/*
+ * Register offsets in bytes from RegisterBase. Three is added to the
+ * base offset to access LSB (IBM style) of the word
+ */
+#define XIIC_CR_REG_OFFSET 0x00+XIIC_REG_OFFSET /* Control Register */
+#define XIIC_SR_REG_OFFSET 0x04+XIIC_REG_OFFSET /* Status Register */
+#define XIIC_DTR_REG_OFFSET 0x08+XIIC_REG_OFFSET /* Data Tx Register */
+#define XIIC_DRR_REG_OFFSET 0x0C+XIIC_REG_OFFSET /* Data Rx Register */
+#define XIIC_ADR_REG_OFFSET 0x10+XIIC_REG_OFFSET /* Address Register */
+#define XIIC_TFO_REG_OFFSET 0x14+XIIC_REG_OFFSET /* Tx FIFO Occupancy */
+#define XIIC_RFO_REG_OFFSET 0x18+XIIC_REG_OFFSET /* Rx FIFO Occupancy */
+#define XIIC_TBA_REG_OFFSET 0x1C+XIIC_REG_OFFSET /* 10 Bit Address reg */
+#define XIIC_RFD_REG_OFFSET 0x20+XIIC_REG_OFFSET /* Rx FIFO Depth reg */
+
+/* Control Register masks */
+
+#define XIIC_CR_ENABLE_DEVICE_MASK 0x01 /* Device enable = 1 */
+#define XIIC_CR_TX_FIFO_RESET_MASK 0x02 /* Transmit FIFO reset=1 */
+#define XIIC_CR_MSMS_MASK 0x04 /* Master starts Txing=1 */
+#define XIIC_CR_DIR_IS_TX_MASK 0x08 /* Dir of tx. Txing=1 */
+#define XIIC_CR_NO_ACK_MASK 0x10 /* Tx Ack. NO ack = 1 */
+#define XIIC_CR_REPEATED_START_MASK 0x20 /* Repeated start = 1 */
+#define XIIC_CR_GENERAL_CALL_MASK 0x40 /* Gen Call enabled = 1 */
+
+/* Status Register masks */
+
+#define XIIC_SR_GEN_CALL_MASK 0x01 /* 1=a mstr issued a GC */
+#define XIIC_SR_ADDR_AS_SLAVE_MASK 0x02 /* 1=when addr as slave */
+#define XIIC_SR_BUS_BUSY_MASK 0x04 /* 1 = bus is busy */
+#define XIIC_SR_MSTR_RDING_SLAVE_MASK 0x08 /* 1=Dir: mstr <-- slave */
+#define XIIC_SR_TX_FIFO_FULL_MASK 0x10 /* 1 = Tx FIFO full */
+#define XIIC_SR_RX_FIFO_FULL_MASK 0x20 /* 1 = Rx FIFO full */
+#define XIIC_SR_RX_FIFO_EMPTY_MASK 0x40 /* 1 = Rx FIFO empty */
+
+/* IPIF Interrupt Status Register masks Interrupt occurs when... */
+
+#define XIIC_INTR_ARB_LOST_MASK 0x01 /* 1 = arbitration lost */
+#define XIIC_INTR_TX_ERROR_MASK 0x02 /* 1=Tx error/msg complete*/
+#define XIIC_INTR_TX_EMPTY_MASK 0x04 /* 1 = Tx FIFO/reg empty */
+#define XIIC_INTR_RX_FULL_MASK 0x08 /* 1=Rx FIFO/reg=OCY level*/
+#define XIIC_INTR_BNB_MASK 0x10 /* 1 = Bus not busy */
+#define XIIC_INTR_AAS_MASK 0x20 /* 1 = when addr as slave */
+#define XIIC_INTR_NAAS_MASK 0x40 /* 1 = not addr as slave */
+#define XIIC_INTR_TX_HALF_MASK 0x80 /* 1 = TX FIFO half empty */
+
+/* IPIF Device Interrupt Register masks */
+
+#define XIIC_IPIF_IIC_MASK 0x00000004UL /* 1=inter enabled */
+#define XIIC_IPIF_ERROR_MASK 0x00000001UL /* 1=inter enabled */
+#define XIIC_IPIF_INTER_ENABLE_MASK (XIIC_IPIF_IIC_MASK | \
+ XIIC_IPIF_ERROR_MASK)
+
+#define XIIC_TX_ADDR_SENT 0x00
+#define XIIC_TX_ADDR_MSTR_RECV_MASK 0x02
+
+/* The following constants specify the depth of the FIFOs */
+
+#define IIC_RX_FIFO_DEPTH 16 /* Rx fifo capacity */
+#define IIC_TX_FIFO_DEPTH 16 /* Tx fifo capacity */
+
+/* The following constants specify groups of interrupts that are typically
+ * enabled or disables at the same time
+ */
+#define XIIC_TX_INTERRUPTS \
+ (XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_TX_EMPTY_MASK | \
+ XIIC_INTR_TX_HALF_MASK)
+
+#define XIIC_TX_RX_INTERRUPTS (XIIC_INTR_RX_FULL_MASK | XIIC_TX_INTERRUPTS)
+
+/* The following constants are used with the following macros to specify the
+ * operation, a read or write operation.
+ */
+#define XIIC_READ_OPERATION 1
+#define XIIC_WRITE_OPERATION 0
+
+/* The following constants are used with the transmit FIFO fill function to
+ * specify the role which the IIC device is acting as, a master or a slave.
+ */
+#define XIIC_MASTER_ROLE 1
+#define XIIC_SLAVE_ROLE 0
+
+/**************************** Type Definitions ******************************/
+
+
+/***************** Macros (Inline Functions) Definitions ********************/
+
+
+/************************** Function Prototypes *****************************/
+
+unsigned XIic_Recv(u32 BaseAddress, u8 Address,
+ u8 *BufferPtr, unsigned ByteCount);
+
+unsigned XIic_Send(u32 BaseAddress, u8 Address,
+ u8 *BufferPtr, unsigned ByteCount);
+
+#endif /* end of protection macro */