<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<META NAME="Generator" CONTENT="MS Exchange Server version 6.5.7652.24">
<TITLE>RE: [PATCH] [POWERPC] Xilinx: hwicap driver</TITLE>
</HEAD>
<BODY>
<!-- Converted from text/plain format -->
<BR>
<P><FONT SIZE=2>Grant,<BR>
<BR>
One of the modifications to the include files got lost, so this won't compile. I also have the corresponding update to booting-without-of.txt queued up. However, webmail won't show me the message id for the thread (grr.), so I'll send it tomorrow when I'm in the office.<BR>
<BR>
Steve<BR>
<BR>
-----Original Message-----<BR>
From: Stephen Neuendorffer [<A HREF="mailto:stephen.neuendorffer@xilinx.com">mailto:stephen.neuendorffer@xilinx.com</A>]<BR>
Sent: Fri 2/1/2008 1:12 PM<BR>
To: linuxppc-dev@ozlabs.org; grant.likely@secretlab.ca; jacmet@sunsite.dk; ntl@pobox.com<BR>
Cc: Stephen Neuendorffer<BR>
Subject: [PATCH] [POWERPC] Xilinx: hwicap driver<BR>
<BR>
This includes code for new fifo-based xps_hwicap in addition to the<BR>
older opb_hwicap, which has a significantly different interface. The<BR>
common code between the two drivers is largely shared.<BR>
<BR>
Significant differences exists between this driver and what is<BR>
supported in the EDK drivers. In particular, most of the<BR>
architecture-specific code for reconfiguring individual FPGA resources<BR>
has been removed. This functionality is likely better provided in a<BR>
user-space support library. In addition, read and write access is<BR>
supported. In addition, although the xps_hwicap cores support<BR>
interrupt-driver mode, this driver only supports polled operation, in<BR>
order to make the code simpler, and since the interrupt processing<BR>
overhead is likely to slow down the throughput under Linux.<BR>
<BR>
Signed-off-by: Stephen Neuendorffer <stephen.neuendorffer@xilinx.com><BR>
<BR>
Fixed to add mutexes, and a few style issues.<BR>
<BR>
Acked-by: Grant Likely <grant.likely@secretlab.ca><BR>
<BR>
---<BR>
<BR>
I will get this right eventually. :)<BR>
---<BR>
drivers/char/Kconfig | 7 +<BR>
drivers/char/Makefile | 1 +<BR>
drivers/char/xilinx_hwicap/Makefile | 7 +<BR>
drivers/char/xilinx_hwicap/buffer_icap.c | 380 ++++++++++++<BR>
drivers/char/xilinx_hwicap/buffer_icap.h | 57 ++<BR>
drivers/char/xilinx_hwicap/fifo_icap.c | 381 ++++++++++++<BR>
drivers/char/xilinx_hwicap/fifo_icap.h | 62 ++<BR>
drivers/char/xilinx_hwicap/xilinx_hwicap.c | 904 ++++++++++++++++++++++++++++<BR>
drivers/char/xilinx_hwicap/xilinx_hwicap.h | 193 ++++++<BR>
9 files changed, 1992 insertions(+), 0 deletions(-)<BR>
create mode 100644 drivers/char/xilinx_hwicap/Makefile<BR>
create mode 100644 drivers/char/xilinx_hwicap/buffer_icap.c<BR>
create mode 100644 drivers/char/xilinx_hwicap/buffer_icap.h<BR>
create mode 100644 drivers/char/xilinx_hwicap/fifo_icap.c<BR>
create mode 100644 drivers/char/xilinx_hwicap/fifo_icap.h<BR>
create mode 100644 drivers/char/xilinx_hwicap/xilinx_hwicap.c<BR>
create mode 100644 drivers/char/xilinx_hwicap/xilinx_hwicap.h<BR>
<BR>
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig<BR>
index ef1ed5d..157ae2a 100644<BR>
--- a/drivers/char/Kconfig<BR>
+++ b/drivers/char/Kconfig<BR>
@@ -831,6 +831,13 @@ config DTLK<BR>
To compile this driver as a module, choose M here: the<BR>
module will be called dtlk.<BR>
<BR>
+config XILINX_HWICAP<BR>
+ tristate "Xilinx HWICAP Support"<BR>
+ depends on XILINX_VIRTEX<BR>
+ help<BR>
+ This option enables support for Xilinx Internal Configuration<BR>
+ Access Port (ICAP) driver.<BR>
+<BR>
config R3964<BR>
tristate "Siemens R3964 line discipline"<BR>
---help---<BR>
diff --git a/drivers/char/Makefile b/drivers/char/Makefile<BR>
index 07304d5..3a278a0 100644<BR>
--- a/drivers/char/Makefile<BR>
+++ b/drivers/char/Makefile<BR>
@@ -76,6 +76,7 @@ obj-$(CONFIG_EFI_RTC) += efirtc.o<BR>
obj-$(CONFIG_SGI_DS1286) += ds1286.o<BR>
obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o<BR>
obj-$(CONFIG_DS1302) += ds1302.o<BR>
+obj-$(CONFIG_XILINX_HWICAP) += xilinx_hwicap/<BR>
ifeq ($(CONFIG_GENERIC_NVRAM),y)<BR>
obj-$(CONFIG_NVRAM) += generic_nvram.o<BR>
else<BR>
diff --git a/drivers/char/xilinx_hwicap/Makefile b/drivers/char/xilinx_hwicap/Makefile<BR>
new file mode 100644<BR>
index 0000000..5491cbc<BR>
--- /dev/null<BR>
+++ b/drivers/char/xilinx_hwicap/Makefile<BR>
@@ -0,0 +1,7 @@<BR>
+#<BR>
+# Makefile for the Xilinx OPB hwicap driver<BR>
+#<BR>
+<BR>
+obj-$(CONFIG_XILINX_HWICAP) += xilinx_hwicap_m.o<BR>
+<BR>
+xilinx_hwicap_m-y := xilinx_hwicap.o fifo_icap.o buffer_icap.o<BR>
diff --git a/drivers/char/xilinx_hwicap/buffer_icap.c b/drivers/char/xilinx_hwicap/buffer_icap.c<BR>
new file mode 100644<BR>
index 0000000..dfea2bd<BR>
--- /dev/null<BR>
+++ b/drivers/char/xilinx_hwicap/buffer_icap.c<BR>
@@ -0,0 +1,380 @@<BR>
+/*****************************************************************************<BR>
+ *<BR>
+ * Author: Xilinx, Inc.<BR>
+ *<BR>
+ * This program is free software; you can redistribute it and/or modify it<BR>
+ * under the terms of the GNU General Public License as published by the<BR>
+ * Free Software Foundation; either version 2 of the License, or (at your<BR>
+ * option) any later version.<BR>
+ *<BR>
+ * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"<BR>
+ * AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND<BR>
+ * SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,<BR>
+ * OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,<BR>
+ * APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION<BR>
+ * THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,<BR>
+ * AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE<BR>
+ * FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY<BR>
+ * WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE<BR>
+ * IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR<BR>
+ * REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF<BR>
+ * INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS<BR>
+ * FOR A PARTICULAR PURPOSE.<BR>
+ *<BR>
+ * Xilinx products are not intended for use in life support appliances,<BR>
+ * devices, or systems. Use in such applications is expressly prohibited.<BR>
+ *<BR>
+ * (c) Copyright 2003-2008 Xilinx Inc.<BR>
+ * All rights reserved.<BR>
+ *<BR>
+ * You should have received a copy of the GNU General Public License along<BR>
+ * with this program; if not, write to the Free Software Foundation, Inc.,<BR>
+ * 675 Mass Ave, Cambridge, MA 02139, USA.<BR>
+ *<BR>
+ *****************************************************************************/<BR>
+<BR>
+#include "buffer_icap.h"<BR>
+<BR>
+/* Indicates how many bytes will fit in a buffer. (1 BRAM) */<BR>
+#define XHI_MAX_BUFFER_BYTES 2048<BR>
+#define XHI_MAX_BUFFER_INTS (XHI_MAX_BUFFER_BYTES >> 2)<BR>
+<BR>
+/* File access and error constants */<BR>
+#define XHI_DEVICE_READ_ERROR -1<BR>
+#define XHI_DEVICE_WRITE_ERROR -2<BR>
+#define XHI_BUFFER_OVERFLOW_ERROR -3<BR>
+<BR>
+#define XHI_DEVICE_READ 0x1<BR>
+#define XHI_DEVICE_WRITE 0x0<BR>
+<BR>
+/* Constants for checking transfer status */<BR>
+#define XHI_CYCLE_DONE 0<BR>
+#define XHI_CYCLE_EXECUTING 1<BR>
+<BR>
+/* buffer_icap register offsets */<BR>
+<BR>
+/* Size of transfer, read & write */<BR>
+#define XHI_SIZE_REG_OFFSET 0x800L<BR>
+/* offset into bram, read & write */<BR>
+#define XHI_BRAM_OFFSET_REG_OFFSET 0x804L<BR>
+/* Read not Configure, direction of transfer. Write only */<BR>
+#define XHI_RNC_REG_OFFSET 0x808L<BR>
+/* Indicates transfer complete. Read only */<BR>
+#define XHI_STATUS_REG_OFFSET 0x80CL<BR>
+<BR>
+/* Constants for setting the RNC register */<BR>
+#define XHI_CONFIGURE 0x0UL<BR>
+#define XHI_READBACK 0x1UL<BR>
+<BR>
+/* Constants for the Done register */<BR>
+#define XHI_NOT_FINISHED 0x0UL<BR>
+#define XHI_FINISHED 0x1UL<BR>
+<BR>
+#define XHI_BUFFER_START 0<BR>
+<BR>
+/**<BR>
+ * buffer_icap_get_status: Get the contents of the status register.<BR>
+ * @parameter base_address: is the base address of the device<BR>
+ *<BR>
+ * The status register contains the ICAP status and the done bit.<BR>
+ *<BR>
+ * D8 - cfgerr<BR>
+ * D7 - dalign<BR>
+ * D6 - rip<BR>
+ * D5 - in_abort_l<BR>
+ * D4 - Always 1<BR>
+ * D3 - Always 1<BR>
+ * D2 - Always 1<BR>
+ * D1 - Always 1<BR>
+ * D0 - Done bit<BR>
+ **/<BR>
+static inline u32 buffer_icap_get_status(void __iomem *base_address)<BR>
+{<BR>
+ return in_be32(base_address + XHI_STATUS_REG_OFFSET);<BR>
+}<BR>
+<BR>
+/**<BR>
+ * buffer_icap_get_bram: Reads data from the storage buffer bram.<BR>
+ * @parameter base_address: contains the base address of the component.<BR>
+ * @parameter offset: The word offset from which the data should be read.<BR>
+ *<BR>
+ * A bram is used as a configuration memory cache. One frame of data can<BR>
+ * be stored in this "storage buffer".<BR>
+ **/<BR>
+static inline u32 buffer_icap_get_bram(void __iomem *base_address,<BR>
+ u32 offset)<BR>
+{<BR>
+ return in_be32(base_address + (offset << 2));<BR>
+}<BR>
+<BR>
+/**<BR>
+ * buffer_icap_busy: Return true if the icap device is busy<BR>
+ * @parameter base_address: is the base address of the device<BR>
+ *<BR>
+ * The queries the low order bit of the status register, which<BR>
+ * indicates whether the current configuration or readback operation<BR>
+ * has completed.<BR>
+ **/<BR>
+static inline bool buffer_icap_busy(void __iomem *base_address)<BR>
+{<BR>
+ return (buffer_icap_get_status(base_address) & 1) == XHI_NOT_FINISHED;<BR>
+}<BR>
+<BR>
+/**<BR>
+ * buffer_icap_busy: Return true if the icap device is not busy<BR>
+ * @parameter base_address: is the base address of the device<BR>
+ *<BR>
+ * The queries the low order bit of the status register, which<BR>
+ * indicates whether the current configuration or readback operation<BR>
+ * has completed.<BR>
+ **/<BR>
+static inline bool buffer_icap_done(void __iomem *base_address)<BR>
+{<BR>
+ return (buffer_icap_get_status(base_address) & 1) == XHI_FINISHED;<BR>
+}<BR>
+<BR>
+/**<BR>
+ * buffer_icap_set_size: Set the size register.<BR>
+ * @parameter base_address: is the base address of the device<BR>
+ * @parameter data: The size in bytes.<BR>
+ *<BR>
+ * The size register holds the number of 8 bit bytes to transfer between<BR>
+ * bram and the icap (or icap to bram).<BR>
+ **/<BR>
+static inline void buffer_icap_set_size(void __iomem *base_address,<BR>
+ u32 data)<BR>
+{<BR>
+ out_be32(base_address + XHI_SIZE_REG_OFFSET, data);<BR>
+}<BR>
+<BR>
+/**<BR>
+ * buffer_icap_mSetoffsetReg: Set the bram offset register.<BR>
+ * @parameter base_address: contains the base address of the device.<BR>
+ * @parameter data: is the value to be written to the data register.<BR>
+ *<BR>
+ * The bram offset register holds the starting bram address to transfer<BR>
+ * data from during configuration or write data to during readback.<BR>
+ **/<BR>
+static inline void buffer_icap_set_offset(void __iomem *base_address,<BR>
+ u32 data)<BR>
+{<BR>
+ out_be32(base_address + XHI_BRAM_OFFSET_REG_OFFSET, data);<BR>
+}<BR>
+<BR>
+/**<BR>
+ * buffer_icap_set_rnc: Set the RNC (Readback not Configure) register.<BR>
+ * @parameter base_address: contains the base address of the device.<BR>
+ * @parameter data: is the value to be written to the data register.<BR>
+ *<BR>
+ * The RNC register determines the direction of the data transfer. It<BR>
+ * controls whether a configuration or readback take place. Writing to<BR>
+ * this register initiates the transfer. A value of 1 initiates a<BR>
+ * readback while writing a value of 0 initiates a configuration.<BR>
+ **/<BR>
+static inline void buffer_icap_set_rnc(void __iomem *base_address,<BR>
+ u32 data)<BR>
+{<BR>
+ out_be32(base_address + XHI_RNC_REG_OFFSET, data);<BR>
+}<BR>
+<BR>
+/**<BR>
+ * buffer_icap_set_bram: Write data to the storage buffer bram.<BR>
+ * @parameter base_address: contains the base address of the component.<BR>
+ * @parameter offset: The word offset at which the data should be written.<BR>
+ * @parameter data: The value to be written to the bram offset.<BR>
+ *<BR>
+ * A bram is used as a configuration memory cache. One frame of data can<BR>
+ * be stored in this "storage buffer".<BR>
+ **/<BR>
+static inline void buffer_icap_set_bram(void __iomem *base_address,<BR>
+ u32 offset, u32 data)<BR>
+{<BR>
+ out_be32(base_address + (offset << 2), data);<BR>
+}<BR>
+<BR>
+/**<BR>
+ * buffer_icap_device_read: Transfer bytes from ICAP to the storage buffer.<BR>
+ * @parameter drvdata: a pointer to the drvdata.<BR>
+ * @parameter offset: The storage buffer start address.<BR>
+ * @parameter count: The number of words (32 bit) to read from the<BR>
+ * device (ICAP).<BR>
+ **/<BR>
+static int buffer_icap_device_read(struct hwicap_drvdata *drvdata,<BR>
+ u32 offset, u32 count)<BR>
+{<BR>
+<BR>
+ s32 retries = 0;<BR>
+ void __iomem *base_address = drvdata->base_address;<BR>
+<BR>
+ if (buffer_icap_busy(base_address))<BR>
+ return -EBUSY;<BR>
+<BR>
+ if ((offset + count) > XHI_MAX_BUFFER_INTS)<BR>
+ return -EINVAL;<BR>
+<BR>
+ /* setSize count*4 to get bytes. */<BR>
+ buffer_icap_set_size(base_address, (count << 2));<BR>
+ buffer_icap_set_offset(base_address, offset);<BR>
+ buffer_icap_set_rnc(base_address, XHI_READBACK);<BR>
+<BR>
+ while (buffer_icap_busy(base_address)) {<BR>
+ retries++;<BR>
+ if (retries > XHI_MAX_RETRIES)<BR>
+ return -EBUSY;<BR>
+ }<BR>
+ return 0;<BR>
+<BR>
+};<BR>
+<BR>
+/**<BR>
+ * buffer_icap_device_write: Transfer bytes from ICAP to the storage buffer.<BR>
+ * @parameter drvdata: a pointer to the drvdata.<BR>
+ * @parameter offset: The storage buffer start address.<BR>
+ * @parameter count: The number of words (32 bit) to read from the<BR>
+ * device (ICAP).<BR>
+ **/<BR>
+static int buffer_icap_device_write(struct hwicap_drvdata *drvdata,<BR>
+ u32 offset, u32 count)<BR>
+{<BR>
+<BR>
+ s32 retries = 0;<BR>
+ void __iomem *base_address = drvdata->base_address;<BR>
+<BR>
+ if (buffer_icap_busy(base_address))<BR>
+ return -EBUSY;<BR>
+<BR>
+ if ((offset + count) > XHI_MAX_BUFFER_INTS)<BR>
+ return -EINVAL;<BR>
+<BR>
+ /* setSize count*4 to get bytes. */<BR>
+ buffer_icap_set_size(base_address, count << 2);<BR>
+ buffer_icap_set_offset(base_address, offset);<BR>
+ buffer_icap_set_rnc(base_address, XHI_CONFIGURE);<BR>
+<BR>
+ while (buffer_icap_busy(base_address)) {<BR>
+ retries++;<BR>
+ if (retries > XHI_MAX_RETRIES)<BR>
+ return -EBUSY;<BR>
+ }<BR>
+ return 0;<BR>
+<BR>
+};<BR>
+<BR>
+/**<BR>
+ * buffer_icap_reset: Reset the logic of the icap device.<BR>
+ * @parameter drvdata: a pointer to the drvdata.<BR>
+ *<BR>
+ * Writing to the status register resets the ICAP logic in an internal<BR>
+ * version of the core. For the version of the core published in EDK,<BR>
+ * this is a noop.<BR>
+ **/<BR>
+void buffer_icap_reset(struct hwicap_drvdata *drvdata)<BR>
+{<BR>
+ out_be32(drvdata->base_address + XHI_STATUS_REG_OFFSET, 0xFEFE);<BR>
+}<BR>
+<BR>
+/**<BR>
+ * buffer_icap_set_configuration: Load a partial bitstream from system memory.<BR>
+ * @parameter drvdata: a pointer to the drvdata.<BR>
+ * @parameter data: Kernel address of the partial bitstream.<BR>
+ * @parameter size: the size of the partial bitstream in 32 bit words.<BR>
+ **/<BR>
+int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data,<BR>
+ u32 size)<BR>
+{<BR>
+ int status;<BR>
+ s32 buffer_count = 0;<BR>
+ s32 num_writes = 0;<BR>
+ bool dirty = 0;<BR>
+ u32 i;<BR>
+ void __iomem *base_address = drvdata->base_address;<BR>
+<BR>
+ /* Loop through all the data */<BR>
+ for (i = 0, buffer_count = 0; i < size; i++) {<BR>
+<BR>
+ /* Copy data to bram */<BR>
+ buffer_icap_set_bram(base_address, buffer_count, data[i]);<BR>
+ dirty = 1;<BR>
+<BR>
+ if (buffer_count < XHI_MAX_BUFFER_INTS - 1) {<BR>
+ buffer_count++;<BR>
+ continue;<BR>
+ }<BR>
+<BR>
+ /* Write data to ICAP */<BR>
+ status = buffer_icap_device_write(<BR>
+ drvdata,<BR>
+ XHI_BUFFER_START,<BR>
+ XHI_MAX_BUFFER_INTS);<BR>
+ if (status != 0) {<BR>
+ /* abort. */<BR>
+ buffer_icap_reset(drvdata);<BR>
+ return status;<BR>
+ }<BR>
+<BR>
+ buffer_count = 0;<BR>
+ num_writes++;<BR>
+ dirty = 0;<BR>
+ }<BR>
+<BR>
+ /* Write unwritten data to ICAP */<BR>
+ if (dirty) {<BR>
+ /* Write data to ICAP */<BR>
+ status = buffer_icap_device_write(drvdata, XHI_BUFFER_START,<BR>
+ buffer_count);<BR>
+ if (status != 0) {<BR>
+ /* abort. */<BR>
+ buffer_icap_reset(drvdata);<BR>
+ }<BR>
+ return status;<BR>
+ }<BR>
+<BR>
+ return 0;<BR>
+};<BR>
+<BR>
+/**<BR>
+ * buffer_icap_get_configuration: Read configuration data from the device.<BR>
+ * @parameter drvdata: a pointer to the drvdata.<BR>
+ * @parameter data: Address of the data representing the partial bitstream<BR>
+ * @parameter size: the size of the partial bitstream in 32 bit words.<BR>
+ **/<BR>
+int buffer_icap_get_configuration(struct hwicap_drvdata *drvdata, u32 *data,<BR>
+ u32 size)<BR>
+{<BR>
+ int status;<BR>
+ s32 buffer_count = 0;<BR>
+ s32 read_count = 0;<BR>
+ u32 i;<BR>
+ void __iomem *base_address = drvdata->base_address;<BR>
+<BR>
+ /* Loop through all the data */<BR>
+ for (i = 0, buffer_count = XHI_MAX_BUFFER_INTS; i < size; i++) {<BR>
+ if (buffer_count == XHI_MAX_BUFFER_INTS) {<BR>
+ u32 words_remaining = size - i;<BR>
+ u32 words_to_read =<BR>
+ words_remaining <<BR>
+ XHI_MAX_BUFFER_INTS ? words_remaining :<BR>
+ XHI_MAX_BUFFER_INTS;<BR>
+<BR>
+ /* Read data from ICAP */<BR>
+ status = buffer_icap_device_read(<BR>
+ drvdata,<BR>
+ XHI_BUFFER_START,<BR>
+ words_to_read);<BR>
+ if (status != 0) {<BR>
+ /* abort. */<BR>
+ buffer_icap_reset(drvdata);<BR>
+ return status;<BR>
+ }<BR>
+<BR>
+ buffer_count = 0;<BR>
+ read_count++;<BR>
+ }<BR>
+<BR>
+ /* Copy data from bram */<BR>
+ data[i] = buffer_icap_get_bram(base_address, buffer_count);<BR>
+ buffer_count++;<BR>
+ }<BR>
+<BR>
+ return 0;<BR>
+};<BR>
diff --git a/drivers/char/xilinx_hwicap/buffer_icap.h b/drivers/char/xilinx_hwicap/buffer_icap.h<BR>
new file mode 100644<BR>
index 0000000..0318495<BR>
--- /dev/null<BR>
+++ b/drivers/char/xilinx_hwicap/buffer_icap.h<BR>
@@ -0,0 +1,57 @@<BR>
+/*****************************************************************************<BR>
+ *<BR>
+ * Author: Xilinx, Inc.<BR>
+ *<BR>
+ * This program is free software; you can redistribute it and/or modify it<BR>
+ * under the terms of the GNU General Public License as published by the<BR>
+ * Free Software Foundation; either version 2 of the License, or (at your<BR>
+ * option) any later version.<BR>
+ *<BR>
+ * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"<BR>
+ * AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND<BR>
+ * SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,<BR>
+ * OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,<BR>
+ * APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION<BR>
+ * THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,<BR>
+ * AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE<BR>
+ * FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY<BR>
+ * WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE<BR>
+ * IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR<BR>
+ * REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF<BR>
+ * INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS<BR>
+ * FOR A PARTICULAR PURPOSE.<BR>
+ *<BR>
+ * Xilinx products are not intended for use in life support appliances,<BR>
+ * devices, or systems. Use in such applications is expressly prohibited.<BR>
+ *<BR>
+ * (c) Copyright 2003-2008 Xilinx Inc.<BR>
+ * All rights reserved.<BR>
+ *<BR>
+ * You should have received a copy of the GNU General Public License along<BR>
+ * with this program; if not, write to the Free Software Foundation, Inc.,<BR>
+ * 675 Mass Ave, Cambridge, MA 02139, USA.<BR>
+ *<BR>
+ *****************************************************************************/<BR>
+<BR>
+#ifndef XILINX_BUFFER_ICAP_H_ /* prevent circular inclusions */<BR>
+#define XILINX_BUFFER_ICAP_H_ /* by using protection macros */<BR>
+<BR>
+#include <linux/types.h><BR>
+#include <linux/cdev.h><BR>
+#include <linux/version.h><BR>
+#include <linux/platform_device.h><BR>
+<BR>
+#include <asm/io.h><BR>
+#include "xilinx_hwicap.h"<BR>
+<BR>
+void buffer_icap_reset(struct hwicap_drvdata *drvdata);<BR>
+<BR>
+/* Loads a partial bitstream from system memory. */<BR>
+int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data,<BR>
+ u32 Size);<BR>
+<BR>
+/* Loads a partial bitstream from system memory. */<BR>
+int buffer_icap_get_configuration(struct hwicap_drvdata *drvdata, u32 *data,<BR>
+ u32 Size);<BR>
+<BR>
+#endif<BR>
diff --git a/drivers/char/xilinx_hwicap/fifo_icap.c b/drivers/char/xilinx_hwicap/fifo_icap.c<BR>
new file mode 100644<BR>
index 0000000..0988314<BR>
--- /dev/null<BR>
+++ b/drivers/char/xilinx_hwicap/fifo_icap.c<BR>
@@ -0,0 +1,381 @@<BR>
+/*****************************************************************************<BR>
+ *<BR>
+ * Author: Xilinx, Inc.<BR>
+ *<BR>
+ * This program is free software; you can redistribute it and/or modify it<BR>
+ * under the terms of the GNU General Public License as published by the<BR>
+ * Free Software Foundation; either version 2 of the License, or (at your<BR>
+ * option) any later version.<BR>
+ *<BR>
+ * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"<BR>
+ * AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND<BR>
+ * SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,<BR>
+ * OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,<BR>
+ * APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION<BR>
+ * THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,<BR>
+ * AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE<BR>
+ * FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY<BR>
+ * WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE<BR>
+ * IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR<BR>
+ * REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF<BR>
+ * INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS<BR>
+ * FOR A PARTICULAR PURPOSE.<BR>
+ *<BR>
+ * Xilinx products are not intended for use in life support appliances,<BR>
+ * devices, or systems. Use in such applications is expressly prohibited.<BR>
+ *<BR>
+ * (c) Copyright 2007-2008 Xilinx Inc.<BR>
+ * All rights reserved.<BR>
+ *<BR>
+ * You should have received a copy of the GNU General Public License along<BR>
+ * with this program; if not, write to the Free Software Foundation, Inc.,<BR>
+ * 675 Mass Ave, Cambridge, MA 02139, USA.<BR>
+ *<BR>
+ *****************************************************************************/<BR>
+<BR>
+#include "fifo_icap.h"<BR>
+<BR>
+/* Register offsets for the XHwIcap device. */<BR>
+#define XHI_GIER_OFFSET 0x1C /* Device Global Interrupt Enable Reg */<BR>
+#define XHI_IPISR_OFFSET 0x20 /* Interrupt Status Register */<BR>
+#define XHI_IPIER_OFFSET 0x28 /* Interrupt Enable Register */<BR>
+#define XHI_WF_OFFSET 0x100 /* Write FIFO */<BR>
+#define XHI_RF_OFFSET 0x104 /* Read FIFO */<BR>
+#define XHI_SZ_OFFSET 0x108 /* Size Register */<BR>
+#define XHI_CR_OFFSET 0x10C /* Control Register */<BR>
+#define XHI_SR_OFFSET 0x110 /* Status Register */<BR>
+#define XHI_WFV_OFFSET 0x114 /* Write FIFO Vacancy Register */<BR>
+#define XHI_RFO_OFFSET 0x118 /* Read FIFO Occupancy Register */<BR>
+<BR>
+/* Device Global Interrupt Enable Register (GIER) bit definitions */<BR>
+<BR>
+#define XHI_GIER_GIE_MASK 0x80000000 /* Global Interrupt enable Mask */<BR>
+<BR>
+/**<BR>
+ * HwIcap Device Interrupt Status/Enable Registers<BR>
+ *<BR>
+ * Interrupt Status Register (IPISR) : This register holds the<BR>
+ * interrupt status flags for the device. These bits are toggle on<BR>
+ * write.<BR>
+ *<BR>
+ * Interrupt Enable Register (IPIER) : This register is used to enable<BR>
+ * interrupt sources for the device.<BR>
+ * Writing a '1' to a bit enables the corresponding interrupt.<BR>
+ * Writing a '0' to a bit disables the corresponding interrupt.<BR>
+ *<BR>
+ * IPISR/IPIER registers have the same bit definitions and are only defined<BR>
+ * once.<BR>
+ */<BR>
+#define XHI_IPIXR_RFULL_MASK 0x00000008 /* Read FIFO Full */<BR>
+#define XHI_IPIXR_WEMPTY_MASK 0x00000004 /* Write FIFO Empty */<BR>
+#define XHI_IPIXR_RDP_MASK 0x00000002 /* Read FIFO half full */<BR>
+#define XHI_IPIXR_WRP_MASK 0x00000001 /* Write FIFO half full */<BR>
+#define XHI_IPIXR_ALL_MASK 0x0000000F /* Mask of all interrupts */<BR>
+<BR>
+/* Control Register (CR) */<BR>
+#define XHI_CR_SW_RESET_MASK 0x00000008 /* SW Reset Mask */<BR>
+#define XHI_CR_FIFO_CLR_MASK 0x00000004 /* FIFO Clear Mask */<BR>
+#define XHI_CR_READ_MASK 0x00000002 /* Read from ICAP to FIFO */<BR>
+#define XHI_CR_WRITE_MASK 0x00000001 /* Write from FIFO to ICAP */<BR>
+<BR>
+/* Status Register (SR) */<BR>
+#define XHI_SR_CFGERR_N_MASK 0x00000100 /* Config Error Mask */<BR>
+#define XHI_SR_DALIGN_MASK 0x00000080 /* Data Alignment Mask */<BR>
+#define XHI_SR_RIP_MASK 0x00000040 /* Read back Mask */<BR>
+#define XHI_SR_IN_ABORT_N_MASK 0x00000020 /* Select Map Abort Mask */<BR>
+#define XHI_SR_DONE_MASK 0x00000001 /* Done bit Mask */<BR>
+<BR>
+<BR>
+#define XHI_WFO_MAX_VACANCY 1024 /* Max Write FIFO Vacancy, in words */<BR>
+#define XHI_RFO_MAX_OCCUPANCY 256 /* Max Read FIFO Occupancy, in words */<BR>
+/* The maximum amount we can request from fifo_icap_get_configuration<BR>
+ at once, in bytes. */<BR>
+#define XHI_MAX_READ_TRANSACTION_WORDS 0xFFF<BR>
+<BR>
+<BR>
+/**<BR>
+ * fifo_icap_fifo_write: Write data to the write FIFO.<BR>
+ * @parameter drvdata: a pointer to the drvdata.<BR>
+ * @parameter data: the 32-bit value to be written to the FIFO.<BR>
+ *<BR>
+ * This function will silently fail if the fifo is full.<BR>
+ **/<BR>
+static inline void fifo_icap_fifo_write(struct hwicap_drvdata *drvdata,<BR>
+ u32 data)<BR>
+{<BR>
+ dev_dbg(drvdata->dev, "fifo_write: %x\n", data);<BR>
+ out_be32(drvdata->base_address + XHI_WF_OFFSET, data);<BR>
+}<BR>
+<BR>
+/**<BR>
+ * fifo_icap_fifo_read: Read data from the Read FIFO.<BR>
+ * @parameter drvdata: a pointer to the drvdata.<BR>
+ *<BR>
+ * This function will silently fail if the fifo is empty.<BR>
+ **/<BR>
+static inline u32 fifo_icap_fifo_read(struct hwicap_drvdata *drvdata)<BR>
+{<BR>
+ u32 data = in_be32(drvdata->base_address + XHI_RF_OFFSET);<BR>
+ dev_dbg(drvdata->dev, "fifo_read: %x\n", data);<BR>
+ return data;<BR>
+}<BR>
+<BR>
+/**<BR>
+ * fifo_icap_set_read_size: Set the the size register.<BR>
+ * @parameter drvdata: a pointer to the drvdata.<BR>
+ * @parameter data: the size of the following read transaction, in words.<BR>
+ **/<BR>
+static inline void fifo_icap_set_read_size(struct hwicap_drvdata *drvdata,<BR>
+ u32 data)<BR>
+{<BR>
+ out_be32(drvdata->base_address + XHI_SZ_OFFSET, data);<BR>
+}<BR>
+<BR>
+/**<BR>
+ * fifo_icap_start_config: Initiate a configuration (write) to the device.<BR>
+ * @parameter drvdata: a pointer to the drvdata.<BR>
+ **/<BR>
+static inline void fifo_icap_start_config(struct hwicap_drvdata *drvdata)<BR>
+{<BR>
+ out_be32(drvdata->base_address + XHI_CR_OFFSET, XHI_CR_WRITE_MASK);<BR>
+ dev_dbg(drvdata->dev, "configuration started\n");<BR>
+}<BR>
+<BR>
+/**<BR>
+ * fifo_icap_start_readback: Initiate a readback from the device.<BR>
+ * @parameter drvdata: a pointer to the drvdata.<BR>
+ **/<BR>
+static inline void fifo_icap_start_readback(struct hwicap_drvdata *drvdata)<BR>
+{<BR>
+ out_be32(drvdata->base_address + XHI_CR_OFFSET, XHI_CR_READ_MASK);<BR>
+ dev_dbg(drvdata->dev, "readback started\n");<BR>
+}<BR>
+<BR>
+/**<BR>
+ * fifo_icap_busy: Return true if the ICAP is still processing a transaction.<BR>
+ * @parameter drvdata: a pointer to the drvdata.<BR>
+ **/<BR>
+static inline u32 fifo_icap_busy(struct hwicap_drvdata *drvdata)<BR>
+{<BR>
+ u32 status = in_be32(drvdata->base_address + XHI_SR_OFFSET);<BR>
+ dev_dbg(drvdata->dev, "Getting status = %x\n", status);<BR>
+ return (status & XHI_SR_DONE_MASK) ? 0 : 1;<BR>
+}<BR>
+<BR>
+/**<BR>
+ * fifo_icap_write_fifo_vacancy: Query the write fifo available space.<BR>
+ * @parameter drvdata: a pointer to the drvdata.<BR>
+ *<BR>
+ * Return the number of words that can be safely pushed into the write fifo.<BR>
+ **/<BR>
+static inline u32 fifo_icap_write_fifo_vacancy(<BR>
+ struct hwicap_drvdata *drvdata)<BR>
+{<BR>
+ return in_be32(drvdata->base_address + XHI_WFV_OFFSET);<BR>
+}<BR>
+<BR>
+/**<BR>
+ * fifo_icap_read_fifo_occupancy: Query the read fifo available data.<BR>
+ * @parameter drvdata: a pointer to the drvdata.<BR>
+ *<BR>
+ * Return the number of words that can be safely read from the read fifo.<BR>
+ **/<BR>
+static inline u32 fifo_icap_read_fifo_occupancy(<BR>
+ struct hwicap_drvdata *drvdata)<BR>
+{<BR>
+ return in_be32(drvdata->base_address + XHI_RFO_OFFSET);<BR>
+}<BR>
+<BR>
+/**<BR>
+ * fifo_icap_set_configuration: Send configuration data to the ICAP.<BR>
+ * @parameter drvdata: a pointer to the drvdata.<BR>
+ * @parameter frame_buffer: a pointer to the data to be written to the<BR>
+ * ICAP device.<BR>
+ * @parameter num_words: the number of words (32 bit) to write to the ICAP<BR>
+ * device.<BR>
+<BR>
+ * This function writes the given user data to the Write FIFO in<BR>
+ * polled mode and starts the transfer of the data to<BR>
+ * the ICAP device.<BR>
+ **/<BR>
+int fifo_icap_set_configuration(struct hwicap_drvdata *drvdata,<BR>
+ u32 *frame_buffer, u32 num_words)<BR>
+{<BR>
+<BR>
+ u32 write_fifo_vacancy = 0;<BR>
+ u32 retries = 0;<BR>
+ u32 remaining_words;<BR>
+<BR>
+ dev_dbg(drvdata->dev, "fifo_set_configuration\n");<BR>
+<BR>
+ /*<BR>
+ * Check if the ICAP device is Busy with the last Read/Write<BR>
+ */<BR>
+ if (fifo_icap_busy(drvdata))<BR>
+ return -EBUSY;<BR>
+<BR>
+ /*<BR>
+ * Set up the buffer pointer and the words to be transferred.<BR>
+ */<BR>
+ remaining_words = num_words;<BR>
+<BR>
+ while (remaining_words > 0) {<BR>
+ /*<BR>
+ * Wait until we have some data in the fifo.<BR>
+ */<BR>
+ while (write_fifo_vacancy == 0) {<BR>
+ write_fifo_vacancy =<BR>
+ fifo_icap_write_fifo_vacancy(drvdata);<BR>
+ retries++;<BR>
+ if (retries > XHI_MAX_RETRIES)<BR>
+ return -EIO;<BR>
+ }<BR>
+<BR>
+ /*<BR>
+ * Write data into the Write FIFO.<BR>
+ */<BR>
+ while ((write_fifo_vacancy != 0) &&<BR>
+ (remaining_words > 0)) {<BR>
+ fifo_icap_fifo_write(drvdata, *frame_buffer);<BR>
+<BR>
+ remaining_words--;<BR>
+ write_fifo_vacancy--;<BR>
+ frame_buffer++;<BR>
+ }<BR>
+ /* Start pushing whatever is in the FIFO into the ICAP. */<BR>
+ fifo_icap_start_config(drvdata);<BR>
+ }<BR>
+<BR>
+ /* Wait until the write has finished. */<BR>
+ while (fifo_icap_busy(drvdata)) {<BR>
+ retries++;<BR>
+ if (retries > XHI_MAX_RETRIES)<BR>
+ break;<BR>
+ }<BR>
+<BR>
+ dev_dbg(drvdata->dev, "done fifo_set_configuration\n");<BR>
+<BR>
+ /*<BR>
+ * If the requested number of words have not been read from<BR>
+ * the device then indicate failure.<BR>
+ */<BR>
+ if (remaining_words != 0)<BR>
+ return -EIO;<BR>
+<BR>
+ return 0;<BR>
+}<BR>
+<BR>
+/**<BR>
+ * fifo_icap_get_configuration: Read configuration data from the device.<BR>
+ * @parameter drvdata: a pointer to the drvdata.<BR>
+ * @parameter data: Address of the data representing the partial bitstream<BR>
+ * @parameter size: the size of the partial bitstream in 32 bit words.<BR>
+ *<BR>
+ * This function reads the specified number of words from the ICAP device in<BR>
+ * the polled mode.<BR>
+ */<BR>
+int fifo_icap_get_configuration(struct hwicap_drvdata *drvdata,<BR>
+ u32 *frame_buffer, u32 num_words)<BR>
+{<BR>
+<BR>
+ u32 read_fifo_occupancy = 0;<BR>
+ u32 retries = 0;<BR>
+ u32 *data = frame_buffer;<BR>
+ u32 remaining_words;<BR>
+ u32 words_to_read;<BR>
+<BR>
+ dev_dbg(drvdata->dev, "fifo_get_configuration\n");<BR>
+<BR>
+ /*<BR>
+ * Check if the ICAP device is Busy with the last Write/Read<BR>
+ */<BR>
+ if (fifo_icap_busy(drvdata))<BR>
+ return -EBUSY;<BR>
+<BR>
+ remaining_words = num_words;<BR>
+<BR>
+ while (remaining_words > 0) {<BR>
+ words_to_read = remaining_words;<BR>
+ /* The hardware has a limit on the number of words<BR>
+ that can be read at one time. */<BR>
+ if (words_to_read > XHI_MAX_READ_TRANSACTION_WORDS)<BR>
+ words_to_read = XHI_MAX_READ_TRANSACTION_WORDS;<BR>
+<BR>
+ remaining_words -= words_to_read;<BR>
+<BR>
+ fifo_icap_set_read_size(drvdata, words_to_read);<BR>
+ fifo_icap_start_readback(drvdata);<BR>
+<BR>
+ while (words_to_read > 0) {<BR>
+ /* Wait until we have some data in the fifo. */<BR>
+ while (read_fifo_occupancy == 0) {<BR>
+ read_fifo_occupancy =<BR>
+ fifo_icap_read_fifo_occupancy(drvdata);<BR>
+ retries++;<BR>
+ if (retries > XHI_MAX_RETRIES)<BR>
+ return -EIO;<BR>
+ }<BR>
+<BR>
+ if (read_fifo_occupancy > words_to_read)<BR>
+ read_fifo_occupancy = words_to_read;<BR>
+<BR>
+ words_to_read -= read_fifo_occupancy;<BR>
+<BR>
+ /* Read the data from the Read FIFO. */<BR>
+ while (read_fifo_occupancy != 0) {<BR>
+ *data++ = fifo_icap_fifo_read(drvdata);<BR>
+ read_fifo_occupancy--;<BR>
+ }<BR>
+ }<BR>
+ }<BR>
+<BR>
+ dev_dbg(drvdata->dev, "done fifo_get_configuration\n");<BR>
+<BR>
+ return 0;<BR>
+}<BR>
+<BR>
+/**<BR>
+ * buffer_icap_reset: Reset the logic of the icap device.<BR>
+ * @parameter drvdata: a pointer to the drvdata.<BR>
+ *<BR>
+ * This function forces the software reset of the complete HWICAP device.<BR>
+ * All the registers will return to the default value and the FIFO is also<BR>
+ * flushed as a part of this software reset.<BR>
+ */<BR>
+void fifo_icap_reset(struct hwicap_drvdata *drvdata)<BR>
+{<BR>
+ u32 reg_data;<BR>
+ /*<BR>
+ * Reset the device by setting/clearing the RESET bit in the<BR>
+ * Control Register.<BR>
+ */<BR>
+ reg_data = in_be32(drvdata->base_address + XHI_CR_OFFSET);<BR>
+<BR>
+ out_be32(drvdata->base_address + XHI_CR_OFFSET,<BR>
+ reg_data | XHI_CR_SW_RESET_MASK);<BR>
+<BR>
+ out_be32(drvdata->base_address + XHI_CR_OFFSET,<BR>
+ reg_data & (~XHI_CR_SW_RESET_MASK));<BR>
+<BR>
+}<BR>
+<BR>
+/**<BR>
+ * fifo_icap_flush_fifo: This function flushes the FIFOs in the device.<BR>
+ * @parameter drvdata: a pointer to the drvdata.<BR>
+ */<BR>
+void fifo_icap_flush_fifo(struct hwicap_drvdata *drvdata)<BR>
+{<BR>
+ u32 reg_data;<BR>
+ /*<BR>
+ * Flush the FIFO by setting/clearing the FIFO Clear bit in the<BR>
+ * Control Register.<BR>
+ */<BR>
+ reg_data = in_be32(drvdata->base_address + XHI_CR_OFFSET);<BR>
+<BR>
+ out_be32(drvdata->base_address + XHI_CR_OFFSET,<BR>
+ reg_data | XHI_CR_FIFO_CLR_MASK);<BR>
+<BR>
+ out_be32(drvdata->base_address + XHI_CR_OFFSET,<BR>
+ reg_data & (~XHI_CR_FIFO_CLR_MASK));<BR>
+}<BR>
+<BR>
diff --git a/drivers/char/xilinx_hwicap/fifo_icap.h b/drivers/char/xilinx_hwicap/fifo_icap.h<BR>
new file mode 100644<BR>
index 0000000..4d3068d<BR>
--- /dev/null<BR>
+++ b/drivers/char/xilinx_hwicap/fifo_icap.h<BR>
@@ -0,0 +1,62 @@<BR>
+/*****************************************************************************<BR>
+ *<BR>
+ * Author: Xilinx, Inc.<BR>
+ *<BR>
+ * This program is free software; you can redistribute it and/or modify it<BR>
+ * under the terms of the GNU General Public License as published by the<BR>
+ * Free Software Foundation; either version 2 of the License, or (at your<BR>
+ * option) any later version.<BR>
+ *<BR>
+ * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"<BR>
+ * AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND<BR>
+ * SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,<BR>
+ * OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,<BR>
+ * APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION<BR>
+ * THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,<BR>
+ * AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE<BR>
+ * FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY<BR>
+ * WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE<BR>
+ * IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR<BR>
+ * REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF<BR>
+ * INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS<BR>
+ * FOR A PARTICULAR PURPOSE.<BR>
+ *<BR>
+ * Xilinx products are not intended for use in life support appliances,<BR>
+ * devices, or systems. Use in such applications is expressly prohibited.<BR>
+ *<BR>
+ * (c) Copyright 2007-2008 Xilinx Inc.<BR>
+ * All rights reserved.<BR>
+ *<BR>
+ * You should have received a copy of the GNU General Public License along<BR>
+ * with this program; if not, write to the Free Software Foundation, Inc.,<BR>
+ * 675 Mass Ave, Cambridge, MA 02139, USA.<BR>
+ *<BR>
+ *****************************************************************************/<BR>
+<BR>
+#ifndef XILINX_FIFO_ICAP_H_ /* prevent circular inclusions */<BR>
+#define XILINX_FIFO_ICAP_H_ /* by using protection macros */<BR>
+<BR>
+#include <linux/types.h><BR>
+#include <linux/cdev.h><BR>
+#include <linux/version.h><BR>
+#include <linux/platform_device.h><BR>
+<BR>
+#include <asm/io.h><BR>
+#include "xilinx_hwicap.h"<BR>
+<BR>
+/* Reads integers from the device into the storage buffer. */<BR>
+int fifo_icap_get_configuration(<BR>
+ struct hwicap_drvdata *drvdata,<BR>
+ u32 *FrameBuffer,<BR>
+ u32 NumWords);<BR>
+<BR>
+/* Writes integers to the device from the storage buffer. */<BR>
+int fifo_icap_set_configuration(<BR>
+ struct hwicap_drvdata *drvdata,<BR>
+ u32 *FrameBuffer,<BR>
+ u32 NumWords);<BR>
+<BR>
+void fifo_icap_reset(struct hwicap_drvdata *drvdata);<BR>
+void fifo_icap_flush_fifo(struct hwicap_drvdata *drvdata);<BR>
+<BR>
+#endif<BR>
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c<BR>
new file mode 100644<BR>
index 0000000..24f6aef<BR>
--- /dev/null<BR>
+++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c<BR>
@@ -0,0 +1,904 @@<BR>
+/*****************************************************************************<BR>
+ *<BR>
+ * Author: Xilinx, Inc.<BR>
+ *<BR>
+ * This program is free software; you can redistribute it and/or modify it<BR>
+ * under the terms of the GNU General Public License as published by the<BR>
+ * Free Software Foundation; either version 2 of the License, or (at your<BR>
+ * option) any later version.<BR>
+ *<BR>
+ * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"<BR>
+ * AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND<BR>
+ * SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,<BR>
+ * OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,<BR>
+ * APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION<BR>
+ * THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,<BR>
+ * AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE<BR>
+ * FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY<BR>
+ * WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE<BR>
+ * IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR<BR>
+ * REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF<BR>
+ * INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS<BR>
+ * FOR A PARTICULAR PURPOSE.<BR>
+ *<BR>
+ * Xilinx products are not intended for use in life support appliances,<BR>
+ * devices, or systems. Use in such applications is expressly prohibited.<BR>
+ *<BR>
+ * (c) Copyright 2002 Xilinx Inc., Systems Engineering Group<BR>
+ * (c) Copyright 2004 Xilinx Inc., Systems Engineering Group<BR>
+ * (c) Copyright 2007-2008 Xilinx Inc.<BR>
+ * All rights reserved.<BR>
+ *<BR>
+ * You should have received a copy of the GNU General Public License along<BR>
+ * with this program; if not, write to the Free Software Foundation, Inc.,<BR>
+ * 675 Mass Ave, Cambridge, MA 02139, USA.<BR>
+ *<BR>
+ *****************************************************************************/<BR>
+<BR>
+/*<BR>
+ * This is the code behind /dev/xilinx_icap -- it allows a user-space<BR>
+ * application to use the Xilinx ICAP subsystem.<BR>
+ *<BR>
+ * The following operations are possible:<BR>
+ *<BR>
+ * open open the port and initialize for access.<BR>
+ * release release port<BR>
+ * write Write a bitstream to the configuration processor.<BR>
+ * read Read a data stream from the configuration processor.<BR>
+ *<BR>
+ * After being opened, the port is initialized and accessed to avoid a<BR>
+ * corrupted first read which may occur with some hardware. The port<BR>
+ * is left in a desynched state, requiring that a synch sequence be<BR>
+ * transmitted before any valid configuration data. A user will have<BR>
+ * exclusive access to the device while it remains open, and the state<BR>
+ * of the ICAP cannot be guaranteed after the device is closed. Note<BR>
+ * that a complete reset of the core and the state of the ICAP cannot<BR>
+ * be performed on many versions of the cores, hence users of this<BR>
+ * device should avoid making inconsistent accesses to the device. In<BR>
+ * particular, accessing the read interface, without first generating<BR>
+ * a write containing a readback packet can leave the ICAP in an<BR>
+ * inaccessible state.<BR>
+ *<BR>
+ * Note that in order to use the read interface, it is first necessary<BR>
+ * to write a request packet to the write interface. i.e., it is not<BR>
+ * possible to simply readback the bitstream (or any configuration<BR>
+ * bits) from a device without specifically requesting them first.<BR>
+ * The code to craft such packets is intended to be part of the<BR>
+ * user-space application code that uses this device. The simplest<BR>
+ * way to use this interface is simply:<BR>
+ *<BR>
+ * cp foo.bit /dev/xilinx_icap<BR>
+ *<BR>
+ * Note that unless foo.bit is an appropriately constructed partial<BR>
+ * bitstream, this has a high likelyhood of overwriting the design<BR>
+ * currently programmed in the FPGA.<BR>
+ */<BR>
+<BR>
+#include <linux/version.h><BR>
+#include <linux/module.h><BR>
+#include <linux/kernel.h><BR>
+#include <linux/types.h><BR>
+#include <linux/ioport.h><BR>
+#include <linux/interrupt.h><BR>
+#include <linux/fcntl.h><BR>
+#include <linux/init.h><BR>
+#include <linux/poll.h><BR>
+#include <linux/proc_fs.h><BR>
+#include <asm/semaphore.h><BR>
+#include <linux/sysctl.h><BR>
+#include <linux/version.h><BR>
+#include <linux/fs.h><BR>
+#include <linux/cdev.h><BR>
+#include <linux/platform_device.h><BR>
+<BR>
+#include <asm/io.h><BR>
+#include <asm/uaccess.h><BR>
+#include <asm/system.h><BR>
+<BR>
+#ifdef CONFIG_OF<BR>
+/* For open firmware. */<BR>
+#include <linux/of_device.h><BR>
+#include <linux/of_platform.h><BR>
+#endif<BR>
+<BR>
+#include "xilinx_hwicap.h"<BR>
+#include "buffer_icap.h"<BR>
+#include "fifo_icap.h"<BR>
+<BR>
+#define DRIVER_NAME "xilinx_icap"<BR>
+<BR>
+#define HWICAP_REGS (0x10000)<BR>
+<BR>
+/* dynamically allocate device number */<BR>
+static int xhwicap_major;<BR>
+static int xhwicap_minor;<BR>
+#define HWICAP_DEVICES 1<BR>
+<BR>
+module_param(xhwicap_major, int, S_IRUGO);<BR>
+module_param(xhwicap_minor, int, S_IRUGO);<BR>
+<BR>
+/* An array, which is set to true when the device is registered. */<BR>
+static bool probed_devices[HWICAP_DEVICES];<BR>
+<BR>
+static struct class *icap_class;<BR>
+<BR>
+#define UNIMPLEMENTED 0xFFFF<BR>
+<BR>
+static const struct config_registers v2_config_registers = {<BR>
+ .CRC = 0,<BR>
+ .FAR = 1,<BR>
+ .FDRI = 2,<BR>
+ .FDRO = 3,<BR>
+ .CMD = 4,<BR>
+ .CTL = 5,<BR>
+ .MASK = 6,<BR>
+ .STAT = 7,<BR>
+ .LOUT = 8,<BR>
+ .COR = 9,<BR>
+ .MFWR = 10,<BR>
+ .FLR = 11,<BR>
+ .KEY = 12,<BR>
+ .CBC = 13,<BR>
+ .IDCODE = 14,<BR>
+ .AXSS = UNIMPLEMENTED,<BR>
+ .C0R_1 = UNIMPLEMENTED,<BR>
+ .CSOB = UNIMPLEMENTED,<BR>
+ .WBSTAR = UNIMPLEMENTED,<BR>
+ .TIMER = UNIMPLEMENTED,<BR>
+ .BOOTSTS = UNIMPLEMENTED,<BR>
+ .CTL_1 = UNIMPLEMENTED,<BR>
+};<BR>
+<BR>
+static const struct config_registers v4_config_registers = {<BR>
+ .CRC = 0,<BR>
+ .FAR = 1,<BR>
+ .FDRI = 2,<BR>
+ .FDRO = 3,<BR>
+ .CMD = 4,<BR>
+ .CTL = 5,<BR>
+ .MASK = 6,<BR>
+ .STAT = 7,<BR>
+ .LOUT = 8,<BR>
+ .COR = 9,<BR>
+ .MFWR = 10,<BR>
+ .FLR = UNIMPLEMENTED,<BR>
+ .KEY = UNIMPLEMENTED,<BR>
+ .CBC = 11,<BR>
+ .IDCODE = 12,<BR>
+ .AXSS = 13,<BR>
+ .C0R_1 = UNIMPLEMENTED,<BR>
+ .CSOB = UNIMPLEMENTED,<BR>
+ .WBSTAR = UNIMPLEMENTED,<BR>
+ .TIMER = UNIMPLEMENTED,<BR>
+ .BOOTSTS = UNIMPLEMENTED,<BR>
+ .CTL_1 = UNIMPLEMENTED,<BR>
+};<BR>
+static const struct config_registers v5_config_registers = {<BR>
+ .CRC = 0,<BR>
+ .FAR = 1,<BR>
+ .FDRI = 2,<BR>
+ .FDRO = 3,<BR>
+ .CMD = 4,<BR>
+ .CTL = 5,<BR>
+ .MASK = 6,<BR>
+ .STAT = 7,<BR>
+ .LOUT = 8,<BR>
+ .COR = 9,<BR>
+ .MFWR = 10,<BR>
+ .FLR = UNIMPLEMENTED,<BR>
+ .KEY = UNIMPLEMENTED,<BR>
+ .CBC = 11,<BR>
+ .IDCODE = 12,<BR>
+ .AXSS = 13,<BR>
+ .C0R_1 = 14,<BR>
+ .CSOB = 15,<BR>
+ .WBSTAR = 16,<BR>
+ .TIMER = 17,<BR>
+ .BOOTSTS = 18,<BR>
+ .CTL_1 = 19,<BR>
+};<BR>
+<BR>
+/**<BR>
+ * hwicap_command_desync: Send a DESYNC command to the ICAP port.<BR>
+ * @parameter drvdata: a pointer to the drvdata.<BR>
+ *<BR>
+ * This command desynchronizes the ICAP After this command, a<BR>
+ * bitstream containing a NULL packet, followed by a SYNCH packet is<BR>
+ * required before the ICAP will recognize commands.<BR>
+ */<BR>
+int hwicap_command_desync(struct hwicap_drvdata *drvdata)<BR>
+{<BR>
+ u32 buffer[4];<BR>
+ u32 index = 0;<BR>
+<BR>
+ /*<BR>
+ * Create the data to be written to the ICAP.<BR>
+ */<BR>
+ buffer[index++] = hwicap_type_1_write(drvdata->config_regs->CMD) | 1;<BR>
+ buffer[index++] = XHI_CMD_DESYNCH;<BR>
+ buffer[index++] = XHI_NOOP_PACKET;<BR>
+ buffer[index++] = XHI_NOOP_PACKET;<BR>
+<BR>
+ /*<BR>
+ * Write the data to the FIFO and intiate the transfer of data present<BR>
+ * in the FIFO to the ICAP device.<BR>
+ */<BR>
+ return drvdata->config->set_configuration(drvdata,<BR>
+ &buffer[0], index);<BR>
+}<BR>
+<BR>
+/**<BR>
+ * hwicap_command_capture: Send a CAPTURE command to the ICAP port.<BR>
+ * @parameter drvdata: a pointer to the drvdata.<BR>
+ *<BR>
+ * This command captures all of the flip flop states so they will be<BR>
+ * available during readback. One can use this command instead of<BR>
+ * enabling the CAPTURE block in the design.<BR>
+ */<BR>
+int hwicap_command_capture(struct hwicap_drvdata *drvdata)<BR>
+{<BR>
+ u32 buffer[7];<BR>
+ u32 index = 0;<BR>
+<BR>
+ /*<BR>
+ * Create the data to be written to the ICAP.<BR>
+ */<BR>
+ buffer[index++] = XHI_DUMMY_PACKET;<BR>
+ buffer[index++] = XHI_SYNC_PACKET;<BR>
+ buffer[index++] = XHI_NOOP_PACKET;<BR>
+ buffer[index++] = hwicap_type_1_write(drvdata->config_regs->CMD) | 1;<BR>
+ buffer[index++] = XHI_CMD_GCAPTURE;<BR>
+ buffer[index++] = XHI_DUMMY_PACKET;<BR>
+ buffer[index++] = XHI_DUMMY_PACKET;<BR>
+<BR>
+ /*<BR>
+ * Write the data to the FIFO and intiate the transfer of data<BR>
+ * present in the FIFO to the ICAP device.<BR>
+ */<BR>
+ return drvdata->config->set_configuration(drvdata,<BR>
+ &buffer[0], index);<BR>
+<BR>
+}<BR>
+<BR>
+/**<BR>
+ * hwicap_get_configuration_register: Query a configuration register.<BR>
+ * @parameter drvdata: a pointer to the drvdata.<BR>
+ * @parameter reg: a constant which represents the configuration<BR>
+ * register value to be returned.<BR>
+ * Examples: XHI_IDCODE, XHI_FLR.<BR>
+ * @parameter RegData: returns the value of the register.<BR>
+ *<BR>
+ * Sends a query packet to the ICAP and then receives the response.<BR>
+ * The icap is left in Synched state.<BR>
+ */<BR>
+int hwicap_get_configuration_register(struct hwicap_drvdata *drvdata,<BR>
+ u32 reg, u32 *RegData)<BR>
+{<BR>
+ int status;<BR>
+ u32 buffer[6];<BR>
+ u32 index = 0;<BR>
+<BR>
+ /*<BR>
+ * Create the data to be written to the ICAP.<BR>
+ */<BR>
+ buffer[index++] = XHI_DUMMY_PACKET;<BR>
+ buffer[index++] = XHI_SYNC_PACKET;<BR>
+ buffer[index++] = XHI_NOOP_PACKET;<BR>
+ buffer[index++] = hwicap_type_1_read(reg) | 1;<BR>
+ buffer[index++] = XHI_NOOP_PACKET;<BR>
+ buffer[index++] = XHI_NOOP_PACKET;<BR>
+<BR>
+ /*<BR>
+ * Write the data to the FIFO and intiate the transfer of data present<BR>
+ * in the FIFO to the ICAP device.<BR>
+ */<BR>
+ status = drvdata->config->set_configuration(drvdata,<BR>
+ &buffer[0], index);<BR>
+ if (status)<BR>
+ return status;<BR>
+<BR>
+ /*<BR>
+ * Read the configuration register<BR>
+ */<BR>
+ status = drvdata->config->get_configuration(drvdata, RegData, 1);<BR>
+ if (status)<BR>
+ return status;<BR>
+<BR>
+ return 0;<BR>
+}<BR>
+<BR>
+int hwicap_initialize_hwicap(struct hwicap_drvdata *drvdata)<BR>
+{<BR>
+ int status;<BR>
+ u32 idcode;<BR>
+<BR>
+ dev_dbg(drvdata->dev, "initializing\n");<BR>
+<BR>
+ /* Abort any current transaction, to make sure we have the<BR>
+ * ICAP in a good state. */<BR>
+ dev_dbg(drvdata->dev, "Reset...\n");<BR>
+ drvdata->config->reset(drvdata);<BR>
+<BR>
+ dev_dbg(drvdata->dev, "Desync...\n");<BR>
+ status = hwicap_command_desync(drvdata);<BR>
+ if (status)<BR>
+ return status;<BR>
+<BR>
+ /* Attempt to read the IDCODE from ICAP. This<BR>
+ * may not be returned correctly, due to the design of the<BR>
+ * hardware.<BR>
+ */<BR>
+ dev_dbg(drvdata->dev, "Reading IDCODE...\n");<BR>
+ status = hwicap_get_configuration_register(<BR>
+ drvdata, drvdata->config_regs->IDCODE, &idcode);<BR>
+ dev_dbg(drvdata->dev, "IDCODE = %x\n", idcode);<BR>
+ if (status)<BR>
+ return status;<BR>
+<BR>
+ dev_dbg(drvdata->dev, "Desync...\n");<BR>
+ status = hwicap_command_desync(drvdata);<BR>
+ if (status)<BR>
+ return status;<BR>
+<BR>
+ return 0;<BR>
+}<BR>
+<BR>
+static ssize_t<BR>
+hwicap_read(struct file *file, char *buf, size_t count, loff_t *ppos)<BR>
+{<BR>
+ struct hwicap_drvdata *drvdata = file->private_data;<BR>
+ ssize_t bytes_to_read = 0;<BR>
+ u32 *kbuf;<BR>
+ u32 words;<BR>
+ u32 bytes_remaining;<BR>
+ int status;<BR>
+<BR>
+ if (down_interruptible(&drvdata->sem))<BR>
+ return -ERESTARTSYS;<BR>
+<BR>
+ if (drvdata->read_buffer_in_use) {<BR>
+ /* If there are leftover bytes in the buffer, just */<BR>
+ /* return them and don't try to read more from the */<BR>
+ /* ICAP device. */<BR>
+ bytes_to_read =<BR>
+ (count < drvdata->read_buffer_in_use) ? count :<BR>
+ drvdata->read_buffer_in_use;<BR>
+<BR>
+ /* Return the data currently in the read buffer. */<BR>
+ if (copy_to_user(buf, drvdata->read_buffer, bytes_to_read)) {<BR>
+ status = -EFAULT;<BR>
+ goto error;<BR>
+ }<BR>
+ drvdata->read_buffer_in_use -= bytes_to_read;<BR>
+ memcpy(drvdata->read_buffer + bytes_to_read,<BR>
+ drvdata->read_buffer, 4 - bytes_to_read);<BR>
+ } else {<BR>
+ /* Get new data from the ICAP, and return was was requested. */<BR>
+ kbuf = (u32 *) get_zeroed_page(GFP_KERNEL);<BR>
+ if (!kbuf) {<BR>
+ status = -ENOMEM;<BR>
+ goto error;<BR>
+ }<BR>
+<BR>
+ /* The ICAP device is only able to read complete */<BR>
+ /* words. If a number of bytes that do not correspond */<BR>
+ /* to complete words is requested, then we read enough */<BR>
+ /* words to get the required number of bytes, and then */<BR>
+ /* save the remaining bytes for the next read. */<BR>
+<BR>
+ /* Determine the number of words to read, rounding up */<BR>
+ /* if necessary. */<BR>
+ words = ((count + 3) >> 2);<BR>
+ bytes_to_read = words << 2;<BR>
+<BR>
+ if (bytes_to_read > PAGE_SIZE)<BR>
+ bytes_to_read = PAGE_SIZE;<BR>
+<BR>
+ /* Ensure we only read a complete number of words. */<BR>
+ bytes_remaining = bytes_to_read & 3;<BR>
+ bytes_to_read &= ~3;<BR>
+ words = bytes_to_read >> 2;<BR>
+<BR>
+ status = drvdata->config->get_configuration(drvdata,<BR>
+ kbuf, words);<BR>
+<BR>
+ /* If we didn't read correctly, then bail out. */<BR>
+ if (status) {<BR>
+ free_page((unsigned long)kbuf);<BR>
+ goto error;<BR>
+ }<BR>
+<BR>
+ /* If we fail to return the data to the user, then bail out. */<BR>
+ if (copy_to_user(buf, kbuf, bytes_to_read)) {<BR>
+ free_page((unsigned long)kbuf);<BR>
+ status = -EFAULT;<BR>
+ goto error;<BR>
+ }<BR>
+ memcpy(kbuf, drvdata->read_buffer, bytes_remaining);<BR>
+ drvdata->read_buffer_in_use = bytes_remaining;<BR>
+ free_page((unsigned long)kbuf);<BR>
+ }<BR>
+ status = bytes_to_read;<BR>
+ error:<BR>
+ up(&drvdata->sem);<BR>
+ return status;<BR>
+}<BR>
+<BR>
+static ssize_t<BR>
+hwicap_write(struct file *file, const char *buf,<BR>
+ size_t count, loff_t *ppos)<BR>
+{<BR>
+ struct hwicap_drvdata *drvdata = file->private_data;<BR>
+ ssize_t written = 0;<BR>
+ ssize_t left = count;<BR>
+ u32 *kbuf;<BR>
+ ssize_t len;<BR>
+ ssize_t status;<BR>
+<BR>
+ if (down_interruptible(&drvdata->sem))<BR>
+ return -ERESTARTSYS;<BR>
+<BR>
+ left += drvdata->write_buffer_in_use;<BR>
+<BR>
+ /* Only write multiples of 4 bytes. */<BR>
+ if (left < 4) {<BR>
+ status = 0;<BR>
+ goto error;<BR>
+ }<BR>
+<BR>
+ kbuf = (u32 *) __get_free_page(GFP_KERNEL);<BR>
+ if (!kbuf) {<BR>
+ status = -ENOMEM;<BR>
+ goto error;<BR>
+ }<BR>
+<BR>
+ while (left > 3) {<BR>
+ /* only write multiples of 4 bytes, so there might */<BR>
+ /* be as many as 3 bytes left (at the end). */<BR>
+ len = left;<BR>
+<BR>
+ if (len > PAGE_SIZE)<BR>
+ len = PAGE_SIZE;<BR>
+ len &= ~3;<BR>
+<BR>
+ if (drvdata->write_buffer_in_use) {<BR>
+ memcpy(kbuf, drvdata->write_buffer,<BR>
+ drvdata->write_buffer_in_use);<BR>
+ if (copy_from_user(<BR>
+ (((char *)kbuf) + (drvdata->write_buffer_in_use)),<BR>
+ buf + written,<BR>
+ len - (drvdata->write_buffer_in_use))) {<BR>
+ free_page((unsigned long)kbuf);<BR>
+ status = -EFAULT;<BR>
+ goto error;<BR>
+ }<BR>
+ } else {<BR>
+ if (copy_from_user(kbuf, buf + written, len)) {<BR>
+ free_page((unsigned long)kbuf);<BR>
+ status = -EFAULT;<BR>
+ goto error;<BR>
+ }<BR>
+ }<BR>
+<BR>
+ status = drvdata->config->set_configuration(drvdata,<BR>
+ kbuf, len >> 2);<BR>
+<BR>
+ if (status) {<BR>
+ free_page((unsigned long)kbuf);<BR>
+ status = -EFAULT;<BR>
+ goto error;<BR>
+ }<BR>
+ if (drvdata->write_buffer_in_use) {<BR>
+ len -= drvdata->write_buffer_in_use;<BR>
+ left -= drvdata->write_buffer_in_use;<BR>
+ drvdata->write_buffer_in_use = 0;<BR>
+ }<BR>
+ written += len;<BR>
+ left -= len;<BR>
+ }<BR>
+ if ((left > 0) && (left < 4)) {<BR>
+ if (!copy_from_user(drvdata->write_buffer,<BR>
+ buf + written, left)) {<BR>
+ drvdata->write_buffer_in_use = left;<BR>
+ written += left;<BR>
+ left = 0;<BR>
+ }<BR>
+ }<BR>
+<BR>
+ free_page((unsigned long)kbuf);<BR>
+ status = written;<BR>
+ error:<BR>
+ up(&drvdata->sem);<BR>
+ return status;<BR>
+}<BR>
+<BR>
+static int hwicap_open(struct inode *inode, struct file *file)<BR>
+{<BR>
+ struct hwicap_drvdata *drvdata;<BR>
+ int status;<BR>
+<BR>
+ drvdata = container_of(inode->i_cdev, struct hwicap_drvdata, cdev);<BR>
+<BR>
+ if (down_interruptible(&drvdata->sem))<BR>
+ return -ERESTARTSYS;<BR>
+<BR>
+ if (drvdata->is_open) {<BR>
+ status = -EBUSY;<BR>
+ goto error;<BR>
+ }<BR>
+<BR>
+ status = hwicap_initialize_hwicap(drvdata);<BR>
+ if (status) {<BR>
+ dev_err(drvdata->dev, "Failed to open file");<BR>
+ goto error;<BR>
+ }<BR>
+<BR>
+ file->private_data = drvdata;<BR>
+ drvdata->write_buffer_in_use = 0;<BR>
+ drvdata->read_buffer_in_use = 0;<BR>
+ drvdata->is_open = 1;<BR>
+<BR>
+ error:<BR>
+ up(&drvdata->sem);<BR>
+ return status;<BR>
+}<BR>
+<BR>
+static int hwicap_release(struct inode *inode, struct file *file)<BR>
+{<BR>
+ struct hwicap_drvdata *drvdata = file->private_data;<BR>
+ int i;<BR>
+ int status = 0;<BR>
+<BR>
+ if (down_interruptible(&drvdata->sem))<BR>
+ return -ERESTARTSYS;<BR>
+<BR>
+ if (drvdata->write_buffer_in_use) {<BR>
+ /* Flush write buffer. */<BR>
+ for (i = drvdata->write_buffer_in_use; i < 4; i++)<BR>
+ drvdata->write_buffer[i] = 0;<BR>
+<BR>
+ status = drvdata->config->set_configuration(drvdata,<BR>
+ (u32 *) drvdata->write_buffer, 1);<BR>
+ if (status)<BR>
+ goto error;<BR>
+ }<BR>
+<BR>
+ status = hwicap_command_desync(drvdata);<BR>
+ if (status)<BR>
+ goto error;<BR>
+<BR>
+ error:<BR>
+ drvdata->is_open = 0;<BR>
+ up(&drvdata->sem);<BR>
+ return status;<BR>
+}<BR>
+<BR>
+static struct file_operations hwicap_fops = {<BR>
+ .owner = THIS_MODULE,<BR>
+ .write = hwicap_write,<BR>
+ .read = hwicap_read,<BR>
+ .open = hwicap_open,<BR>
+ .release = hwicap_release,<BR>
+};<BR>
+<BR>
+static int __devinit hwicap_setup(struct device *dev, int id,<BR>
+ const struct resource *regs_res,<BR>
+ const struct hwicap_driver_config *config,<BR>
+ const struct config_registers *config_regs)<BR>
+{<BR>
+ dev_t devt;<BR>
+ struct hwicap_drvdata *drvdata = NULL;<BR>
+ int retval = 0;<BR>
+<BR>
+ dev_info(dev, "Xilinx icap port driver\n");<BR>
+<BR>
+ if (id < 0) {<BR>
+ for (id = 0; id < HWICAP_DEVICES; id++)<BR>
+ if (!probed_devices[id])<BR>
+ break;<BR>
+ }<BR>
+ if (id < 0 || id >= HWICAP_DEVICES) {<BR>
+ dev_err(dev, "%s%i too large\n", DRIVER_NAME, id);<BR>
+ return -EINVAL;<BR>
+ }<BR>
+ if (probed_devices[id]) {<BR>
+ dev_err(dev, "cannot assign to %s%i; it is already in use\n",<BR>
+ DRIVER_NAME, id);<BR>
+ return -EBUSY;<BR>
+ }<BR>
+<BR>
+ probed_devices[id] = 1;<BR>
+<BR>
+ devt = MKDEV(xhwicap_major, xhwicap_minor + id);<BR>
+<BR>
+ drvdata = kmalloc(sizeof(struct hwicap_drvdata), GFP_KERNEL);<BR>
+ if (!drvdata) {<BR>
+ dev_err(dev, "Couldn't allocate device private record\n");<BR>
+ return -ENOMEM;<BR>
+ }<BR>
+ memset((void *)drvdata, 0, sizeof(struct hwicap_drvdata));<BR>
+ dev_set_drvdata(dev, (void *)drvdata);<BR>
+<BR>
+ if (!regs_res) {<BR>
+ dev_err(dev, "Couldn't get registers resource\n");<BR>
+ retval = -EFAULT;<BR>
+ goto failed1;<BR>
+ }<BR>
+<BR>
+ drvdata->mem_start = regs_res->start;<BR>
+ drvdata->mem_end = regs_res->end;<BR>
+ drvdata->mem_size = regs_res->end - regs_res->start + 1;<BR>
+<BR>
+ if (!request_mem_region(drvdata->mem_start,<BR>
+ drvdata->mem_size, DRIVER_NAME)) {<BR>
+ dev_err(dev, "Couldn't lock memory region at %p\n",<BR>
+ (void *)regs_res->start);<BR>
+ retval = -EBUSY;<BR>
+ goto failed1;<BR>
+ }<BR>
+<BR>
+ drvdata->devt = devt;<BR>
+ drvdata->dev = dev;<BR>
+ drvdata->base_address = ioremap(drvdata->mem_start, drvdata->mem_size);<BR>
+ if (!drvdata->base_address) {<BR>
+ dev_err(dev, "ioremap() failed\n");<BR>
+ goto failed2;<BR>
+ }<BR>
+<BR>
+ drvdata->config = config;<BR>
+ drvdata->config_regs = config_regs;<BR>
+<BR>
+ init_MUTEX(&drvdata->sem);<BR>
+ drvdata->is_open = 0;<BR>
+<BR>
+ dev_info(dev, "ioremap %lx to %p with size %x\n",<BR>
+ (unsigned long int)drvdata->mem_start,<BR>
+ drvdata->base_address, drvdata->mem_size);<BR>
+<BR>
+ cdev_init(&drvdata->cdev, &hwicap_fops);<BR>
+ drvdata->cdev.owner = THIS_MODULE;<BR>
+ retval = cdev_add(&drvdata->cdev, devt, 1);<BR>
+ if (retval) {<BR>
+ dev_err(dev, "cdev_add() failed\n");<BR>
+ goto failed3;<BR>
+ }<BR>
+ /* devfs_mk_cdev(devt, S_IFCHR|S_IRUGO|S_IWUGO, DRIVER_NAME); */<BR>
+ class_device_create(icap_class, NULL, devt, NULL, DRIVER_NAME);<BR>
+ return 0; /* success */<BR>
+<BR>
+ failed3:<BR>
+ iounmap(drvdata->base_address);<BR>
+<BR>
+ failed2:<BR>
+ release_mem_region(regs_res->start, drvdata->mem_size);<BR>
+<BR>
+ failed1:<BR>
+ kfree(drvdata);<BR>
+<BR>
+ return retval;<BR>
+}<BR>
+<BR>
+static struct hwicap_driver_config buffer_icap_config = {<BR>
+ .get_configuration = buffer_icap_get_configuration,<BR>
+ .set_configuration = buffer_icap_set_configuration,<BR>
+ .reset = buffer_icap_reset,<BR>
+};<BR>
+<BR>
+static struct hwicap_driver_config fifo_icap_config = {<BR>
+ .get_configuration = fifo_icap_get_configuration,<BR>
+ .set_configuration = fifo_icap_set_configuration,<BR>
+ .reset = fifo_icap_reset,<BR>
+};<BR>
+<BR>
+static int __devexit hwicap_remove(struct device *dev)<BR>
+{<BR>
+ struct hwicap_drvdata *drvdata;<BR>
+<BR>
+ drvdata = (struct hwicap_drvdata *)dev_get_drvdata(dev);<BR>
+<BR>
+ if (!drvdata)<BR>
+ return 0;<BR>
+<BR>
+ class_device_destroy(icap_class, drvdata->devt);<BR>
+ cdev_del(&drvdata->cdev);<BR>
+ iounmap(drvdata->base_address);<BR>
+ release_mem_region(drvdata->mem_start, drvdata->mem_size);<BR>
+ kfree(drvdata);<BR>
+ dev_set_drvdata(dev, NULL);<BR>
+ probed_devices[MINOR(dev->devt)-xhwicap_minor] = 0;<BR>
+<BR>
+ return 0; /* success */<BR>
+}<BR>
+<BR>
+static int __devinit hwicap_drv_probe(struct platform_device *pdev)<BR>
+{<BR>
+ struct resource *res;<BR>
+ const struct config_registers *regs;<BR>
+ const char *family;<BR>
+<BR>
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);<BR>
+ if (!res)<BR>
+ return -ENODEV;<BR>
+<BR>
+ /* It's most likely that we're using V4, if the family is not<BR>
+ specified */<BR>
+ regs = &v4_config_registers;<BR>
+ family = pdev->dev.platform_data;<BR>
+<BR>
+ if (family) {<BR>
+ if (!strcmp(family, "virtex2p")) {<BR>
+ regs = &v2_config_registers;<BR>
+ } else if (!strcmp(family, "virtex4")) {<BR>
+ regs = &v4_config_registers;<BR>
+ } else if (!strcmp(family, "virtex5")) {<BR>
+ regs = &v5_config_registers;<BR>
+ }<BR>
+ }<BR>
+<BR>
+ return hwicap_setup(&pdev->dev, pdev->id, res,<BR>
+ &buffer_icap_config, regs);<BR>
+}<BR>
+<BR>
+static int __devexit hwicap_drv_remove(struct platform_device *pdev)<BR>
+{<BR>
+ return hwicap_remove(&pdev->dev);<BR>
+}<BR>
+<BR>
+static struct platform_driver hwicap_platform_driver = {<BR>
+ .probe = hwicap_drv_probe,<BR>
+ .remove = hwicap_drv_remove,<BR>
+ .driver = {<BR>
+ .owner = THIS_MODULE,<BR>
+ .name = DRIVER_NAME,<BR>
+ },<BR>
+};<BR>
+<BR>
+/* ---------------------------------------------------------------------<BR>
+ * OF bus binding<BR>
+ */<BR>
+<BR>
+#if defined(CONFIG_OF)<BR>
+static int __devinit<BR>
+hwicap_of_probe(struct of_device *op, const struct of_device_id *match)<BR>
+{<BR>
+ struct resource res;<BR>
+ const unsigned int *id;<BR>
+ const char *family;<BR>
+ int rc;<BR>
+ const struct hwicap_driver_config *config = match->data;<BR>
+ const struct config_registers *regs;<BR>
+<BR>
+ dev_dbg(&op->dev, "hwicap_of_probe(%p, %p)\n", op, match);<BR>
+<BR>
+ rc = of_address_to_resource(op->node, 0, &res);<BR>
+ if (rc) {<BR>
+ dev_err(&op->dev, "invalid address\n");<BR>
+ return rc;<BR>
+ }<BR>
+<BR>
+ id = of_get_property(op->node, "port-number", NULL);<BR>
+<BR>
+ /* It's most likely that we're using V4, if the family is not<BR>
+ specified */<BR>
+ regs = &v4_config_registers;<BR>
+ family = of_get_property(op->node, "xlnx,family", NULL);<BR>
+<BR>
+ if (family) {<BR>
+ if (!strcmp(family, "virtex2p")) {<BR>
+ regs = &v2_config_registers;<BR>
+ } else if (!strcmp(family, "virtex4")) {<BR>
+ regs = &v4_config_registers;<BR>
+ } else if (!strcmp(family, "virtex5")) {<BR>
+ regs = &v5_config_registers;<BR>
+ }<BR>
+ }<BR>
+ return hwicap_setup(&op->dev, id ? *id : -1, &res, config,<BR>
+ regs);<BR>
+}<BR>
+<BR>
+static int __devexit hwicap_of_remove(struct of_device *op)<BR>
+{<BR>
+ return hwicap_remove(&op->dev);<BR>
+}<BR>
+<BR>
+/* Match table for of_platform binding */<BR>
+static const struct of_device_id __devinit hwicap_of_match[] = {<BR>
+ { .compatible = "xlnx,opb-hwicap-1.00.b", .data = &buffer_icap_config},<BR>
+ { .compatible = "xlnx,xps-hwicap-1.00.a", .data = &fifo_icap_config},<BR>
+ {},<BR>
+};<BR>
+MODULE_DEVICE_TABLE(of, hwicap_of_match);<BR>
+<BR>
+static struct of_platform_driver hwicap_of_driver = {<BR>
+ .owner = THIS_MODULE,<BR>
+ .name = DRIVER_NAME,<BR>
+ .match_table = hwicap_of_match,<BR>
+ .probe = hwicap_of_probe,<BR>
+ .remove = __devexit_p(hwicap_of_remove),<BR>
+ .driver = {<BR>
+ .name = DRIVER_NAME,<BR>
+ },<BR>
+};<BR>
+<BR>
+/* Registration helpers to keep the number of #ifdefs to a minimum */<BR>
+static inline int __devinit hwicap_of_register(void)<BR>
+{<BR>
+ pr_debug("hwicap: calling of_register_platform_driver()\n");<BR>
+ return of_register_platform_driver(&hwicap_of_driver);<BR>
+}<BR>
+<BR>
+static inline void __devexit hwicap_of_unregister(void)<BR>
+{<BR>
+ of_unregister_platform_driver(&hwicap_of_driver);<BR>
+}<BR>
+#else /* CONFIG_OF */<BR>
+/* CONFIG_OF not enabled; do nothing helpers */<BR>
+static inline int __devinit hwicap_of_register(void) { return 0; }<BR>
+static inline void __devexit hwicap_of_unregister(void) { }<BR>
+#endif /* CONFIG_OF */<BR>
+<BR>
+static int __devinit hwicap_module_init(void)<BR>
+{<BR>
+ dev_t devt;<BR>
+ int retval;<BR>
+<BR>
+ icap_class = class_create(THIS_MODULE, "xilinx_config");<BR>
+<BR>
+ if (xhwicap_major) {<BR>
+ devt = MKDEV(xhwicap_major, xhwicap_minor);<BR>
+ retval = register_chrdev_region(<BR>
+ devt,<BR>
+ HWICAP_DEVICES,<BR>
+ DRIVER_NAME);<BR>
+ if (retval < 0)<BR>
+ return retval;<BR>
+ } else {<BR>
+ retval = alloc_chrdev_region(&devt,<BR>
+ xhwicap_minor,<BR>
+ HWICAP_DEVICES,<BR>
+ DRIVER_NAME);<BR>
+ if (retval < 0)<BR>
+ return retval;<BR>
+ xhwicap_major = MAJOR(devt);<BR>
+ }<BR>
+<BR>
+ retval = platform_driver_register(&hwicap_platform_driver);<BR>
+<BR>
+ if (retval)<BR>
+ goto failed1;<BR>
+<BR>
+ retval = hwicap_of_register();<BR>
+<BR>
+ if (retval)<BR>
+ goto failed2;<BR>
+<BR>
+ return retval;<BR>
+<BR>
+ failed2:<BR>
+ platform_driver_unregister(&hwicap_platform_driver);<BR>
+<BR>
+ failed1:<BR>
+ unregister_chrdev_region(devt, HWICAP_DEVICES);<BR>
+<BR>
+ return retval;<BR>
+}<BR>
+<BR>
+static void __devexit hwicap_module_cleanup(void)<BR>
+{<BR>
+ dev_t devt = MKDEV(xhwicap_major, xhwicap_minor);<BR>
+<BR>
+ class_destroy(icap_class);<BR>
+<BR>
+ platform_driver_unregister(&hwicap_platform_driver);<BR>
+<BR>
+ hwicap_of_unregister();<BR>
+<BR>
+ unregister_chrdev_region(devt, HWICAP_DEVICES);<BR>
+}<BR>
+<BR>
+module_init(hwicap_module_init);<BR>
+module_exit(hwicap_module_cleanup);<BR>
+<BR>
+MODULE_AUTHOR("Xilinx, Inc; Xilinx Research Labs Group");<BR>
+MODULE_DESCRIPTION("Xilinx ICAP Port Driver");<BR>
+MODULE_LICENSE("GPL");<BR>
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.h b/drivers/char/xilinx_hwicap/xilinx_hwicap.h<BR>
new file mode 100644<BR>
index 0000000..b6b47d0<BR>
--- /dev/null<BR>
+++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.h<BR>
@@ -0,0 +1,193 @@<BR>
+/*****************************************************************************<BR>
+ *<BR>
+ * Author: Xilinx, Inc.<BR>
+ *<BR>
+ * This program is free software; you can redistribute it and/or modify it<BR>
+ * under the terms of the GNU General Public License as published by the<BR>
+ * Free Software Foundation; either version 2 of the License, or (at your<BR>
+ * option) any later version.<BR>
+ *<BR>
+ * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"<BR>
+ * AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND<BR>
+ * SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,<BR>
+ * OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,<BR>
+ * APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION<BR>
+ * THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,<BR>
+ * AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE<BR>
+ * FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY<BR>
+ * WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE<BR>
+ * IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR<BR>
+ * REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF<BR>
+ * INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS<BR>
+ * FOR A PARTICULAR PURPOSE.<BR>
+ *<BR>
+ * Xilinx products are not intended for use in life support appliances,<BR>
+ * devices, or systems. Use in such applications is expressly prohibited.<BR>
+ *<BR>
+ * (c) Copyright 2003-2007 Xilinx Inc.<BR>
+ * All rights reserved.<BR>
+ *<BR>
+ * You should have received a copy of the GNU General Public License along<BR>
+ * with this program; if not, write to the Free Software Foundation, Inc.,<BR>
+ * 675 Mass Ave, Cambridge, MA 02139, USA.<BR>
+ *<BR>
+ *****************************************************************************/<BR>
+<BR>
+#ifndef XILINX_HWICAP_H_ /* prevent circular inclusions */<BR>
+#define XILINX_HWICAP_H_ /* by using protection macros */<BR>
+<BR>
+#include <linux/types.h><BR>
+#include <linux/cdev.h><BR>
+#include <linux/version.h><BR>
+#include <linux/platform_device.h><BR>
+<BR>
+#include <asm/io.h><BR>
+<BR>
+struct hwicap_drvdata {<BR>
+ u32 write_buffer_in_use; /* Always in [0,3] */<BR>
+ u8 write_buffer[4];<BR>
+ u32 read_buffer_in_use; /* Always in [0,3] */<BR>
+ u8 read_buffer[4];<BR>
+ u32 mem_start; /* phys. address of the control registers */<BR>
+ u32 mem_end; /* phys. address of the control registers */<BR>
+ u32 mem_size;<BR>
+ void __iomem *base_address;/* virt. address of the control registers */<BR>
+<BR>
+ struct device *dev;<BR>
+ struct cdev cdev; /* Char device structure */<BR>
+ dev_t devt;<BR>
+<BR>
+ const struct hwicap_driver_config *config;<BR>
+ const struct config_registers *config_regs;<BR>
+ void *private_data;<BR>
+ bool is_open;<BR>
+ bool is_accessing;<BR>
+};<BR>
+<BR>
+struct hwicap_driver_config {<BR>
+ int (*get_configuration)(struct hwicap_drvdata *drvdata, u32 *data,<BR>
+ u32 size);<BR>
+ int (*set_configuration)(struct hwicap_drvdata *drvdata, u32 *data,<BR>
+ u32 size);<BR>
+ void (*reset)(struct hwicap_drvdata *drvdata);<BR>
+};<BR>
+<BR>
+/* Number of times to poll the done regsiter */<BR>
+#define XHI_MAX_RETRIES 10<BR>
+<BR>
+/************ Constant Definitions *************/<BR>
+<BR>
+#define XHI_PAD_FRAMES 0x1<BR>
+<BR>
+/* Mask for calculating configuration packet headers */<BR>
+#define XHI_WORD_COUNT_MASK_TYPE_1 0x7FFUL<BR>
+#define XHI_WORD_COUNT_MASK_TYPE_2 0x1FFFFFUL<BR>
+#define XHI_TYPE_MASK 0x7<BR>
+#define XHI_REGISTER_MASK 0xF<BR>
+#define XHI_OP_MASK 0x3<BR>
+<BR>
+#define XHI_TYPE_SHIFT 29<BR>
+#define XHI_REGISTER_SHIFT 13<BR>
+#define XHI_OP_SHIFT 27<BR>
+<BR>
+#define XHI_TYPE_1 1<BR>
+#define XHI_TYPE_2 2<BR>
+#define XHI_OP_WRITE 2<BR>
+#define XHI_OP_READ 1<BR>
+<BR>
+/* Address Block Types */<BR>
+#define XHI_FAR_CLB_BLOCK 0<BR>
+#define XHI_FAR_BRAM_BLOCK 1<BR>
+#define XHI_FAR_BRAM_INT_BLOCK 2<BR>
+<BR>
+struct config_registers {<BR>
+ u32 CRC;<BR>
+ u32 FAR;<BR>
+ u32 FDRI;<BR>
+ u32 FDRO;<BR>
+ u32 CMD;<BR>
+ u32 CTL;<BR>
+ u32 MASK;<BR>
+ u32 STAT;<BR>
+ u32 LOUT;<BR>
+ u32 COR;<BR>
+ u32 MFWR;<BR>
+ u32 FLR;<BR>
+ u32 KEY;<BR>
+ u32 CBC;<BR>
+ u32 IDCODE;<BR>
+ u32 AXSS;<BR>
+ u32 C0R_1;<BR>
+ u32 CSOB;<BR>
+ u32 WBSTAR;<BR>
+ u32 TIMER;<BR>
+ u32 BOOTSTS;<BR>
+ u32 CTL_1;<BR>
+};<BR>
+<BR>
+/* Configuration Commands */<BR>
+#define XHI_CMD_NULL 0<BR>
+#define XHI_CMD_WCFG 1<BR>
+#define XHI_CMD_MFW 2<BR>
+#define XHI_CMD_DGHIGH 3<BR>
+#define XHI_CMD_RCFG 4<BR>
+#define XHI_CMD_START 5<BR>
+#define XHI_CMD_RCAP 6<BR>
+#define XHI_CMD_RCRC 7<BR>
+#define XHI_CMD_AGHIGH 8<BR>
+#define XHI_CMD_SWITCH 9<BR>
+#define XHI_CMD_GRESTORE 10<BR>
+#define XHI_CMD_SHUTDOWN 11<BR>
+#define XHI_CMD_GCAPTURE 12<BR>
+#define XHI_CMD_DESYNCH 13<BR>
+#define XHI_CMD_IPROG 15 /* Only in Virtex5 */<BR>
+#define XHI_CMD_CRCC 16 /* Only in Virtex5 */<BR>
+#define XHI_CMD_LTIMER 17 /* Only in Virtex5 */<BR>
+<BR>
+/* Packet constants */<BR>
+#define XHI_SYNC_PACKET 0xAA995566UL<BR>
+#define XHI_DUMMY_PACKET 0xFFFFFFFFUL<BR>
+#define XHI_NOOP_PACKET (XHI_TYPE_1 << XHI_TYPE_SHIFT)<BR>
+#define XHI_TYPE_2_READ ((XHI_TYPE_2 << XHI_TYPE_SHIFT) | \<BR>
+ (XHI_OP_READ << XHI_OP_SHIFT))<BR>
+<BR>
+#define XHI_TYPE_2_WRITE ((XHI_TYPE_2 << XHI_TYPE_SHIFT) | \<BR>
+ (XHI_OP_WRITE << XHI_OP_SHIFT))<BR>
+<BR>
+#define XHI_TYPE2_CNT_MASK 0x07FFFFFF<BR>
+<BR>
+#define XHI_TYPE_1_PACKET_MAX_WORDS 2047UL<BR>
+#define XHI_TYPE_1_HEADER_BYTES 4<BR>
+#define XHI_TYPE_2_HEADER_BYTES 8<BR>
+<BR>
+/* Constant to use for CRC check when CRC has been disabled */<BR>
+#define XHI_DISABLED_AUTO_CRC 0x0000DEFCUL<BR>
+<BR>
+/**<BR>
+ * hwicap_type_1_read: Generates a Type 1 read packet header.<BR>
+ * @parameter: Register is the address of the register to be read back.<BR>
+ *<BR>
+ * Generates a Type 1 read packet header, which is used to indirectly<BR>
+ * read registers in the configuration logic. This packet must then<BR>
+ * be sent through the icap device, and a return packet received with<BR>
+ * the information.<BR>
+ **/<BR>
+static inline u32 hwicap_type_1_read(u32 Register)<BR>
+{<BR>
+ return (XHI_TYPE_1 << XHI_TYPE_SHIFT) |<BR>
+ (Register << XHI_REGISTER_SHIFT) |<BR>
+ (XHI_OP_READ << XHI_OP_SHIFT);<BR>
+}<BR>
+<BR>
+/**<BR>
+ * hwicap_type_1_write: Generates a Type 1 write packet header<BR>
+ * @parameter: Register is the address of the register to be read back.<BR>
+ **/<BR>
+static inline u32 hwicap_type_1_write(u32 Register)<BR>
+{<BR>
+ return (XHI_TYPE_1 << XHI_TYPE_SHIFT) |<BR>
+ (Register << XHI_REGISTER_SHIFT) |<BR>
+ (XHI_OP_WRITE << XHI_OP_SHIFT);<BR>
+}<BR>
+<BR>
+#endif<BR>
--<BR>
1.5.3.4-dirty<BR>
<BR>
<BR>
<BR>
</FONT>
</P>
</BODY>
</HTML>