[PATCH] [XILINX][HWICAP] Xilinx Internal Configuration Access Port device driver.

Peter Korsgaard jacmet at sunsite.dk
Wed Dec 5 23:20:47 EST 2007


>>>>> "Stephen" == Stephen Neuendorffer <stephen.neuendorffer at xilinx.com> writes:

Hi,

 Stephen> Supports static platform_device and static device tree configuration.
 Stephen> This is a standalone driver that does not depend on EDK generated
 Stephen> files.  However, it is also somewhat different in functionality from
 Stephen> the standard EDK driver.

 Stephen> 1) The EDK driver doesn't support readback, which this driver does.
 Stephen> 2) The EDK driver supports fine granularity reading and writing, which
 Stephen> this driver does not.  The fine granularity support is heavily
 Stephen> architecture independent, which makes it difficult to make the driver
 Stephen> forward compatible.  The fine granularity support is also complex and
 Stephen> probably better handled in user space anyway.

 Stephen> Signed-off-by: Stephen Neuendorffer <stephen.neuendorffer at xilinx.com>
 Stephen> ---

 Stephen> Grant,

 Stephen> No comments last time... It would be nice if this merged
 Stephen> with 2.6.25, I think.

 Stephen> Steve

I never used the icap stuff, but here goes ..

 Stephen>  drivers/char/Kconfig                       |    5 +
 Stephen>  drivers/char/Makefile                      |    1 +
 Stephen>  drivers/char/xilinx_hwicap/Makefile        |    7 +
 Stephen>  drivers/char/xilinx_hwicap/xhwicap_srp.c   |  414 ++++++++++++++++++++
 Stephen>  drivers/char/xilinx_hwicap/xilinx_hwicap.c |  565 ++++++++++++++++++++++++++++
 Stephen>  drivers/char/xilinx_hwicap/xilinx_hwicap.h |  539 ++++++++++++++++++++++++++
 Stephen>  6 files changed, 1531 insertions(+), 0 deletions(-)
 Stephen>  create mode 100644 drivers/char/xilinx_hwicap/Makefile
 Stephen>  create mode 100644 drivers/char/xilinx_hwicap/xhwicap_srp.c
 Stephen>  create mode 100644 drivers/char/xilinx_hwicap/xilinx_hwicap.c
 Stephen>  create mode 100644 drivers/char/xilinx_hwicap/xilinx_hwicap.h

> diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
> index bf18d75..72295cc 100644
> --- a/drivers/char/Kconfig
> +++ b/drivers/char/Kconfig
> @@ -573,6 +573,11 @@ config HVC_DRIVER
>  	  It will automatically be selected if one of the back-end console drivers
>  	  is selected.

Please don't put the HWICAP option in the middle of the HVC options.

> +config XILINX_HWICAP
> +	tristate "Xilinx OPB HWICAP Support"
> +	depends on XILINX_VIRTEX
> +	help
> +	This option enables support for Xilinx Internal Configuration Access Port (ICAP) driver.

Line too long.

>  
>  config HVC_CONSOLE
>  	bool "pSeries Hypervisor Virtual Console support"
> diff --git a/drivers/char/Makefile b/drivers/char/Makefile
> index 07304d5..8cfcbb0 100644
> --- a/drivers/char/Makefile
> +++ b/drivers/char/Makefile
> @@ -76,6 +76,7 @@ obj-$(CONFIG_EFI_RTC)		+= efirtc.o
>  obj-$(CONFIG_SGI_DS1286)	+= ds1286.o
>  obj-$(CONFIG_SGI_IP27_RTC)	+= ip27-rtc.o
>  obj-$(CONFIG_DS1302)		+= ds1302.o
> +obj-$(CONFIG_XILINX_HWICAP)	+= xilinx_hwicap/
>  ifeq ($(CONFIG_GENERIC_NVRAM),y)
>    obj-$(CONFIG_NVRAM)	+= generic_nvram.o
>  else
> diff --git a/drivers/char/xilinx_hwicap/Makefile b/drivers/char/xilinx_hwicap/Makefile
> new file mode 100644
> index 0000000..818f4e1
> --- /dev/null
> +++ b/drivers/char/xilinx_hwicap/Makefile
> @@ -0,0 +1,7 @@
> +#
> +# Makefile for the Xilinx OPB hwicap driver
> +#
> +
> +obj-$(CONFIG_XILINX_HWICAP) += xilinx_hwicap_m.o 
> + 
> +xilinx_hwicap_m-y := xilinx_hwicap.o xhwicap_srp.o

Those files are both quite small, couldn't you merge them and get rid
of the global symbols and the xilinx_hwicap directory?

> diff --git a/drivers/char/xilinx_hwicap/xhwicap_srp.c b/drivers/char/xilinx_hwicap/xhwicap_srp.c
> new file mode 100644
> index 0000000..388eefe
> --- /dev/null
> +++ b/drivers/char/xilinx_hwicap/xhwicap_srp.c
> @@ -0,0 +1,414 @@
> +/*****************************************************************************
> + *
> + *     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, 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.
> + *
> + *     Xilinx products are not intended for use in life support appliances,
> + *     devices, or systems. Use in such applications is expressly prohibited.
> + *
> + *     (c) Copyright 2003-2007 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.
> + *
> + * ****************************************************************************/

Could you please you a smaller / standard GPL header instead?

> +
> +#include "xilinx_hwicap.h"
> +
> +#define XHI_BUFFER_START 0
> +
> +/****************************************************************************/
> +/**
> + *
> + * Stores data in the storage buffer at the specified address.
> + *
> + * @param    InstancePtr - a pointer to the XHwIcap instance to be worked on.
> + *
> + * @param    Address - bram word address
> + *
> + * @param    Data - data to be stored at address
> + *
> + * @return   None.
> + *
> + * @note     None.
> + *
> +*****************************************************************************/

Please use std kerneldoc format.

> +void XHwIcap_StorageBufferWrite(struct xhwicap_drvdata *InstancePtr,
> +				u32 Address, u32 Data)

No CamelCase, Uppercase parameters.

> +{
> +	/* Write data to storage buffer. */
> +	XHwIcap_mSetBram(InstancePtr->baseAddress, Address, Data);
> +}
> +
> +/****************************************************************************/
> +/**
> + *
> + * Read data from the specified address in the storage buffer..
> + *
> + * @param    InstancePtr - a pointer to the XHwIcap instance to be worked on.
> + *
> + * @param    Address - bram word address
> + *
> + * @return   Data.
> + *
> + * @note     None.
> + *
> +*****************************************************************************/
> +u32 XHwIcap_StorageBufferRead(struct xhwicap_drvdata *InstancePtr, u32 Address)
> +{
> +	u32 Data;
> +
> +	/* Read data from address. Multiply Address by 4 since 4 bytes per
> +	 * word.*/
> +	Data = XHwIcap_mGetBram(InstancePtr->baseAddress, Address);
> +	return Data;
> +
> +}
> +
> +/****************************************************************************/
> +/**
> + *
> + * Reads bytes from the device (ICAP) and puts it in the storage buffer.
> + *
> + * @param    InstancePtr - a pointer to the XHwIcap instance to be worked on.
> + *
> + * @param    Offset - The storage buffer start address.
> + *
> + * @param    NumInts - The number of words (32 bit) to read from the
> + *           device (ICAP).
> + *
> + *@return    int - 0 or -EBUSY or -EINVAL
> + *
> + * @note     None.
> + *
> +*****************************************************************************/
> +int XHwIcap_DeviceRead(struct xhwicap_drvdata *InstancePtr, u32 Offset,
> +		       u32 NumInts)
> +{
> +
> +	s32 Retries = 0;
> +
> +	if (XHwIcap_mGetDoneReg(InstancePtr->baseAddress) == XHI_NOT_FINISHED) {
> +		return -EBUSY;
> +	}

No curly brackets around single statement. In general, please run the
patch through checkpatch.pl and fixup stuff.

> +
> +	if ((Offset + NumInts) <= XHI_MAX_BUFFER_INTS) {
> +		/* setSize NumInts*4 to get bytes. */
> +		XHwIcap_mSetSizeReg((InstancePtr->baseAddress), (NumInts << 2));
> +		XHwIcap_mSetOffsetReg((InstancePtr->baseAddress), Offset);
> +		XHwIcap_mSetRncReg((InstancePtr->baseAddress), XHI_READBACK);
> +
> +		while (XHwIcap_mGetDoneReg(InstancePtr->baseAddress) ==
> +		       XHI_NOT_FINISHED) {
> +			Retries++;
> +			if (Retries > XHI_MAX_RETRIES) {
> +				return -EBUSY;
> +			}
> +		}
> +	} else {
> +		return -EINVAL;
> +	}
> +	return 0;
> +
> +};
> +
> +/****************************************************************************/
> +/**
> + *
> + * Writes bytes from the storage buffer and puts it in the device (ICAP).
> + *
> + * @param    InstancePtr - a pointer to the XHwIcap instance to be worked on.
> + *
> + * @param    Offset - The storage buffer start address.
> + *
> + * @param    NumInts - The number of words (32 bit) to read from the
> + *           device (ICAP).
> + *
> + *@return    int - 0 or -EBUSY or -EINVAL
> + *
> + * @note     None.
> + *
> +*****************************************************************************/
> +int XHwIcap_DeviceWrite(struct xhwicap_drvdata *InstancePtr, u32 Offset,
> +			u32 NumInts)
> +{
> +
> +	s32 Retries = 0;
> +
> +	if (XHwIcap_mGetDoneReg(InstancePtr->baseAddress) == XHI_NOT_FINISHED) {
> +		return -EBUSY;
> +	}
> +
> +	if ((Offset + NumInts) <= XHI_MAX_BUFFER_INTS) {
> +		/* setSize NumInts*4 to get bytes.  */
> +		XHwIcap_mSetSizeReg((InstancePtr->baseAddress), NumInts << 2);
> +		XHwIcap_mSetOffsetReg((InstancePtr->baseAddress), Offset);
> +		XHwIcap_mSetRncReg((InstancePtr->baseAddress), XHI_CONFIGURE);
> +
> +		while (XHwIcap_mGetDoneReg(InstancePtr->baseAddress) ==
> +		       XHI_NOT_FINISHED) {
> +			Retries++;
> +			if (Retries > XHI_MAX_RETRIES) {
> +				return -EBUSY;
> +			}
> +		}
> +	} else {
> +		return -EINVAL;
> +	}
> +	return 0;
> +
> +};
> +
> +/****************************************************************************/
> +/**
> + *
> + * Sends a DESYNC command to the ICAP port.
> + *
> + * @param    InstancePtr - a pointer to the XHwIcap instance to be worked on.
> + *
> + *@return    int - 0 or -EBUSY or -EINVAL
> + *
> + * @note     None.
> + *
> +*****************************************************************************/
> +int XHwIcap_CommandDesync(struct xhwicap_drvdata *InstancePtr)
> +{
> +	int status;
> +
> +	XHwIcap_StorageBufferWrite(InstancePtr, 0,
> +				   (XHwIcap_Type1Write(XHI_CMD) | 1));
> +	XHwIcap_StorageBufferWrite(InstancePtr, 1, XHI_CMD_DESYNCH);
> +	XHwIcap_StorageBufferWrite(InstancePtr, 2, XHI_NOOP_PACKET);
> +	XHwIcap_StorageBufferWrite(InstancePtr, 3, XHI_NOOP_PACKET);
> +
> +	/* send four words */
> +	status = XHwIcap_DeviceWrite(InstancePtr, 0, 4);
> +	if (status) {
> +		return status;
> +	}
> +
> +	return 0;
> +}
> +
> +/****************************************************************************/
> +/**
> + *
> + * Sends a CAPTURE command to the ICAP port.  This command caputres all
> + * of the flip flop states so they will be available during readback.
> + * One can use this command instead of enabling the CAPTURE block in the
> + * design.
> + *
> + * @param    InstancePtr - a pointer to the XHwIcap instance to be worked on.
> + *
> + * @return    int - 0 or -EBUSY or -EINVAL
> + *
> + * @note     None.
> + *
> +*****************************************************************************/
> +int XHwIcap_CommandCapture(struct xhwicap_drvdata *InstancePtr)
> +{
> +	int status;
> +
> +	/* DUMMY and SYNC */
> +	XHwIcap_StorageBufferWrite(InstancePtr, 0, XHI_DUMMY_PACKET);
> +	XHwIcap_StorageBufferWrite(InstancePtr, 1, XHI_SYNC_PACKET);
> +	XHwIcap_StorageBufferWrite(InstancePtr, 2,
> +				   (XHwIcap_Type1Write(XHI_CMD) | 1));
> +	XHwIcap_StorageBufferWrite(InstancePtr, 3, XHI_CMD_GCAPTURE);
> +	XHwIcap_StorageBufferWrite(InstancePtr, 4, XHI_DUMMY_PACKET);
> +	XHwIcap_StorageBufferWrite(InstancePtr, 5, XHI_DUMMY_PACKET);
> +
> +	/* send six words */
> +	status = XHwIcap_DeviceWrite(InstancePtr, 0, 6);
> +	if (status) {		/* send six words */
> +		return status;
> +	}
> +
> +	return 0;
> +}
> +
> +/****************************************************************************/
> +/**
> + *
> + * This function returns the value of the specified configuration
> + * register.
> + *
> + * @param    InstancePtr - a pointer to the XHwIcap instance to be worked
> + * on.
> + *
> + * @param    ConfigReg  - A constant which represents the configuration
> + * register value to be returned. Constants specified in xhwicap_i.h.  Examples:
> + * XHI_IDCODE, XHI_FLR.
> + *
> + * @return   The value of the specified configuration register.
> + *
> + *
> +*****************************************************************************/
> +
> +u32 XHwIcap_GetConfigReg(struct xhwicap_drvdata *InstancePtr, u32 ConfigReg)
> +{
> +	u32 Packet;
> +	int status;
> +
> +	/* Write bitstream to bram */
> +	Packet = XHwIcap_Type1Read(ConfigReg) | 1;
> +	XHwIcap_StorageBufferWrite(InstancePtr, 0, XHI_DUMMY_PACKET);
> +	XHwIcap_StorageBufferWrite(InstancePtr, 1, XHI_SYNC_PACKET);
> +	XHwIcap_StorageBufferWrite(InstancePtr, 2, Packet);
> +	XHwIcap_StorageBufferWrite(InstancePtr, 3, XHI_NOOP_PACKET);
> +	XHwIcap_StorageBufferWrite(InstancePtr, 4, XHI_NOOP_PACKET);
> +
> +	/* Transfer Bitstream from Bram to ICAP */
> +	status = XHwIcap_DeviceWrite(InstancePtr, 0, 5);
> +	if (status) {
> +		return status;
> +	}
> +
> +	/* Now readback one word into bram position
> +	 * XHI_EX_BITSTREAM_LENGTH*/
> +	status = XHwIcap_DeviceRead(InstancePtr, 5, 1);
> +	if (status) {
> +		return status;
> +	}
> +
> +	/* Return the Register value */
> +	return XHwIcap_StorageBufferRead(InstancePtr, 5);
> +}
> +
> +/****************************************************************************
> + *
> + * Loads a partial bitstream from system memory.
> + *
> + * @param    InstancePtr - a pointer to the XHwIcap instance to be worked on.
> + *
> + * @param    Data - Address of the data representing the partial bitstream
> + *
> + * @param    Size - the size of the partial bitstream in 32 bit words.
> + *
> + * @return   0, -EFBIG or -EINVAL.
> + *
> + * @note     None.
> + *
> +*****************************************************************************/
> +int XHwIcap_SetConfiguration(struct xhwicap_drvdata *InstancePtr, u32 *Data,
> +			     u32 Size)
> +{
> +	int status;
> +	s32 BufferCount = 0;
> +	s32 NumWrites = 0;
> +	bool Dirty = 0;
> +	u32 I;
> +
> +	/* Loop through all the data */
> +	for (I = 0, BufferCount = 0; I < Size; I++) {
> +
> +		/* Copy data to bram */
> +		XHwIcap_StorageBufferWrite(InstancePtr, BufferCount, Data[I]);
> +		Dirty = 1;
> +
> +		if (BufferCount == XHI_MAX_BUFFER_INTS - 1) {
> +			/* Write data to ICAP */
> +			status = XHwIcap_DeviceWrite(InstancePtr, XHI_BUFFER_START,
> +						XHI_MAX_BUFFER_INTS);
> +			if (status != 0) {
> +				/* abort. */
> +				XHwIcap_mReset(InstancePtr->baseAddress);					return status;
> +			}
> +
> +			BufferCount = 0;
> +			NumWrites++;
> +			Dirty = 0;
> +		} else {
> +			BufferCount++;
> +		}
> +	}
> +
> +	/* Write unwritten data to ICAP */
> +	if (Dirty) {
> +		/* Write data to ICAP */
> +		status = XHwIcap_DeviceWrite(InstancePtr, XHI_BUFFER_START,
> +					     BufferCount);
> +		if (status != 0) {
> +			/* abort. */
> +			XHwIcap_mReset(InstancePtr->baseAddress);
> +		}
> +		return status;
> +	}
> +
> +	return 0;
> +};
> +
> +/****************************************************************************
> + *
> + * Reads Configuration Data from the device.
> + *
> + * @param    InstancePtr - a pointer to the XHwIcap instance to be worked on.
> + *
> + * @param    Data - Address of the data representing the partial bitstream
> + *
> + * @param    Size - the size of the partial bitstream in 32 bit words.
> + *
> + * @return   0, -EFBIG or -EINVAL.
> + *
> + * @note     None.
> + *
> +*****************************************************************************/
> +int XHwIcap_GetConfiguration(struct xhwicap_drvdata *InstancePtr, u32 *Data,
> +			     u32 Size)
> +{
> +	int status;
> +	s32 BufferCount = 0;
> +	s32 NumReads = 0;
> +	u32 I;
> +
> +	/* Loop through all the data */
> +	for (I = 0, BufferCount = XHI_MAX_BUFFER_INTS; I < Size; I++) {
> +		if (BufferCount == XHI_MAX_BUFFER_INTS) {
> +			u32 intsRemaining = Size - I;
> +			u32 intsToRead =
> +			    intsRemaining <
> +			    XHI_MAX_BUFFER_INTS ? intsRemaining :
> +			    XHI_MAX_BUFFER_INTS;
> +
> +			/* Read data from ICAP */
> +
> +			status =
> +			    XHwIcap_DeviceRead(InstancePtr, XHI_BUFFER_START,
> +					       intsToRead);
> +			if (status != 0) {
> +				/* abort. */
> +				XHwIcap_mReset(InstancePtr->baseAddress);
> +				return status;
> +			}
> +
> +			BufferCount = 0;
> +			NumReads++;
> +		}
> +
> +		/* Copy data from bram */
> +		Data[I] = XHwIcap_StorageBufferRead(InstancePtr, BufferCount);
> +		BufferCount++;
> +	}
> +
> +	return 0;
> +};
> diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
> new file mode 100644
> index 0000000..d42538e
> --- /dev/null
> +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
> @@ -0,0 +1,565 @@
> +/*****************************************************************************
> + *
> + *     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, 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.
> + *
> + *     Xilinx products are not intended for use in life support appliances,
> + *     devices, or systems. Use in such applications is expressly prohibited.
> + *
> + *     (c) Copyright 2002 Xilinx Inc., Systems Engineering Group
> + *     (c) Copyright 2004 Xilinx Inc., Systems Engineering Group
> + *     (c) Copyright 2007 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.
> + *
> + *****************************************************************************/
> +
> +/*
> + * xilinx_hwicap.c
> + *
> + * This is the code behind /dev/xilinx_icap/'x' -- it allows a user-space
> + * application to use the Xilinx ICAP subsystem.
> + *
> + * A /dev/xilinx_icap/'x' device node represents an arbitrary device
> + * on port 'x'.  The following operations are possible:
> + *
> + * open		do nothing, set up default IEEE 1284 protocol to be COMPAT
> + * release	release port and unregister device (if necessary)
> + * write        Write a bitstream to the configuration processor.
> + * read         Read a data stream from the configuration processor.
> + *
> + * Note that in order to use the read interface, it is first necessary
> + * to write a request packet to the write interface.  i.e., it is not
> + * possible to simply readback the bitstream (or any configuration
> + * bits) from a device without specifically requesting them first.
> + * The code to craft such packets is intended to be part of the
> + * user-space application code that uses this device.  The simplest
> + * way to use this interface is simply:
> + *
> + * cp foo.bit /dev/xilinx_icap
> + *
> + * Note that unless foo.bit is an appropriately constructed partial
> + * bitstream, this has a high likelyhood of overwriting the design
> + * currently programmed in the FPGA.
> + */
> +
> +#include <linux/version.h>
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/types.h>
> +#include <linux/ioport.h>
> +#include <linux/interrupt.h>
> +#include <linux/fcntl.h>
> +#include <linux/init.h>
> +#include <linux/poll.h>
> +#include <linux/proc_fs.h>
> +#include <linux/spinlock.h>
> +#include <linux/sysctl.h>
> +#include <linux/version.h>
> +#include <linux/fs.h>
> +#include <linux/cdev.h>
> +#include <linux/platform_device.h>
> +
> +#include <asm/io.h>
> +#include <asm/uaccess.h>
> +#include <asm/system.h>
> +
> +#ifdef CONFIG_OF
> +/* For open firmware. */
> +#include <linux/of_device.h>
> +#include <linux/of_platform.h>
> +#endif
> +
> +#include "xilinx_hwicap.h"
> +
> +#define DRIVER_NAME "xilinx_icap"
> +
> +#define XHWICAP_REGS   (0x10000)
> +
> +/* dynamically allocate device number */
> +static int xhwicap_major = 0;
> +static int xhwicap_minor = 0;
> +static int xhwicap_no_minors = 4;
> +module_param(xhwicap_major, int, S_IRUGO);
> +module_param(xhwicap_minor, int, S_IRUGO);
> +module_param(xhwicap_no_minors, int, S_IRUGO);

Why don't you request official major/minor numbers?
(Documentation/devices.txt)

> +
> +static struct class *icap_class;
> +
> +int xhwicap_initialize_xhwicap(struct xhwicap_drvdata *drvdata)
> +{
> +
> +	u32 DeviceIdCode;
> +	u32 Packet;
> +	int Status;
> +
> +	dev_dbg(drvdata->dev, "Reset...\n");
> +
> +	/* Abort any current transaction, to make sure we have the ICAP in */
> +	/* a good state. */
> +	XHwIcap_mReset(drvdata->baseAddress);
> +
> +	/* Read the IDCODE from ICAP if specified. */
> +	{
> +		dev_dbg(drvdata->dev, "Reading IDCODE...\n");
> +
> +		/* Write bitstream to bram */
> +		Packet = XHwIcap_Type1Read(XHI_IDCODE) | 1;
> +		XHwIcap_StorageBufferWrite(drvdata, 0, XHI_DUMMY_PACKET);
> +		XHwIcap_StorageBufferWrite(drvdata, 1, XHI_SYNC_PACKET);
> +		XHwIcap_StorageBufferWrite(drvdata, 2, Packet);
> +		XHwIcap_StorageBufferWrite(drvdata, 3, XHI_NOOP_PACKET);
> +		XHwIcap_StorageBufferWrite(drvdata, 4, XHI_NOOP_PACKET);
> +
> +		/* Transfer Bitstream from Bram to ICAP */
> +		Status = XHwIcap_DeviceWrite(drvdata, 0, 5);
> +		if (Status) {
> +			return Status;
> +		}
> +
> +		/* Now readback one word into bram position
> +		 * XHI_EX_BITSTREAM_LENGTH*/
> +		Status = XHwIcap_DeviceRead(drvdata, 5, 1);
> +		if (Status) {
> +			return Status;
> +		}
> +
> +		/* Return the Register value */
> +		DeviceIdCode = XHwIcap_StorageBufferRead(drvdata, 5);
> +
> +		/* Mask out the version section of the DeviceIdCode */
> +		DeviceIdCode = DeviceIdCode & 0x0FFFFFFF;
> +
> +		dev_dbg(drvdata->dev, "Desync...\n");
> +		Status = XHwIcap_CommandDesync(drvdata);
> +
> +		if (Status) {
> +			return Status;
> +		}
> +	}
> +
> +	/* Abort any current transaction, to make sure we have the ICAP in */
> +	/* a good state. */
> +	XHwIcap_mReset(drvdata->baseAddress);
> +
> +	dev_info(drvdata->dev, "Device IDCODE = %x\n", DeviceIdCode);
> +
> +	return 0;
> +}
> +
> +static ssize_t
> +xhwicap_read(struct file *file, char *buf, size_t count, loff_t *ppos)
> +{
> +	struct xhwicap_drvdata *drvdata = file->private_data;
> +	ssize_t bytes_to_read = 0;
> +	u32 *kbuf;
> +	u32 words;
> +	u32 bytes_remaining;
> +	int Status;
> +
> +	if (drvdata->read_buffer_in_use) {
> +		/* If there are leftover bytes in the buffer, just */
> +		/* return them and don't try to read more from the */
> +		/* ICAP device. */
> +		bytes_to_read =
> +		    (count <
> +		     drvdata->read_buffer_in_use) ? count : drvdata->
> +		    read_buffer_in_use;
> +
> +		/* Return the data currently in the read buffer. */
> +		if (copy_to_user(buf, drvdata->read_buffer, bytes_to_read)) {
> +			return -EFAULT;
> +		}
> +		drvdata->read_buffer_in_use -= bytes_to_read;
> +		memcpy(drvdata->read_buffer + bytes_to_read,
> +		       drvdata->read_buffer, 4 - bytes_to_read);
> +	} else {
> +		/* Get new data from the ICAP, and return was was requested. */
> +		kbuf = (u32 *) get_zeroed_page(GFP_KERNEL);
> +		if (!kbuf)
> +			return -ENOMEM;
> +
> +		/* The ICAP device is only able to read complete */
> +		/* words.  If a number of bytes that do not correspond */
> +		/* to complete words is requested, then we read enough */
> +		/* words to get the required number of bytes, and then */
> +		/* save the remaining bytes for the next read. */
> +
> +		/* Determine the number of words to read, rounding up */
> +		/* if necessary. */
> +		words = ((count + 3) >> 2);
> +		bytes_to_read = words << 2;
> +
> +		if (bytes_to_read > PAGE_SIZE) {
> +			bytes_to_read = PAGE_SIZE;
> +		}
> +		/* Ensure we only read a complete number of words. */
> +		/* BUG: should be count & 3? */
> +		bytes_remaining = bytes_to_read & 3;
> +		bytes_to_read &= ~3;
> +		words = bytes_to_read >> 2;
> +
> +		Status = XHwIcap_GetConfiguration(drvdata, kbuf, words);
> +		/* If we didn't read correctly, then bail out. */
> +		if (Status) {
> +			free_page((unsigned long)kbuf);
> +			return -EFAULT;
> +		}
> +		/* If we fail to return the data to the user, then bail out. */
> +		if (copy_to_user(buf, kbuf, bytes_to_read)) {
> +			free_page((unsigned long)kbuf);
> +			return -EFAULT;
> +		}
> +		memcpy(kbuf, drvdata->read_buffer, bytes_remaining);
> +		drvdata->read_buffer_in_use = bytes_remaining;
> +		free_page((unsigned long)kbuf);
> +	}
> +	return bytes_to_read;
> +}
> +
> +static ssize_t xhwicap_write(struct file *file, const char *buf,
> +			     size_t count, loff_t *ppos)
> +{
> +	struct xhwicap_drvdata *drvdata = file->private_data;
> +	ssize_t written = 0;
> +	ssize_t left = count;
> +	u32 *kbuf;
> +	int len;
> +	int Status;
> +
> +	left += drvdata->write_buffer_in_use;
> +
> +	/* only write multiples of 4 bytes. */
> +	if (left < 4)
> +		return 0;
> +
> +	kbuf = (u32 *) __get_free_page(GFP_KERNEL);
> +	if (!kbuf)
> +		return -ENOMEM;
> +
> +	while (left > 3) {
> +		/* only write multiples of 4 bytes, so there might */
> +		/* be as many as 3 bytes left (at the end). */
> +		len = left;
> +
> +		if (len > PAGE_SIZE)
> +			len = PAGE_SIZE;
> +		len &= ~3;
> +
> +		if (drvdata->write_buffer_in_use) {
> +			memcpy(kbuf, drvdata->write_buffer,
> +			       drvdata->write_buffer_in_use);
> +			if (copy_from_user
> +			    ((((char *)kbuf) + (drvdata->write_buffer_in_use)),
> +			     buf + written,
> +			     len - (drvdata->write_buffer_in_use))) {
> +				free_page((unsigned long)kbuf);
> +				return -EFAULT;
> +			}
> +		} else {
> +			if (copy_from_user(kbuf, buf + written, len)) {
> +				free_page((unsigned long)kbuf);
> +				return -EFAULT;
> +			}
> +		}
> +
> +		Status = XHwIcap_SetConfiguration(drvdata, kbuf, len >> 2);
> +
> +		if (Status) {
> +			free_page((unsigned long)kbuf);
> +			return -EFAULT;
> +		}
> +		if (drvdata->write_buffer_in_use) {
> +			len -= drvdata->write_buffer_in_use;
> +			left -= drvdata->write_buffer_in_use;
> +			drvdata->write_buffer_in_use = 0;
> +		}
> +		written += len;
> +		left -= len;
> +	}
> +	if ((left > 0) && (left < 4)) {
> +		if (!copy_from_user(drvdata->write_buffer, buf + written, left)) {
> +			drvdata->write_buffer_in_use = left;
> +			written += left;
> +			left = 0;
> +		}
> +	}
> +
> +	free_page((unsigned long)kbuf);
> +	return written;
> +}
> +
> +static int xhwicap_open(struct inode *inode, struct file *file)
> +{
> +	struct xhwicap_drvdata *drvdata;
> +	int status;
> +
> +	drvdata = container_of(inode->i_cdev, struct xhwicap_drvdata, cdev);
> +
> +	status = xhwicap_initialize_xhwicap(drvdata);
> +	if (status) {
> +		dev_err(drvdata->dev, "Failed to open file");
> +		return -status;
> +	}
> +
> +	drvdata->flags = 0;
> +	file->private_data = drvdata;
> +	drvdata->write_buffer_in_use = 0;
> +	drvdata->read_buffer_in_use = 0;
> +
> +	return 0;
> +}
> +
> +static int xhwicap_release(struct inode *inode, struct file *file)
> +{
> +	struct xhwicap_drvdata *drvdata = file->private_data;
> +	int i;
> +	int Status;
> +
> +	if (drvdata->write_buffer_in_use) {
> +		/* Flush write buffer. */
> +		for (i = drvdata->write_buffer_in_use; i < 4; i++) {
> +			drvdata->write_buffer[i] = 0;
> +		}
> +		Status =
> +		    XHwIcap_SetConfiguration(drvdata,
> +					     (u32 *) drvdata->write_buffer, 1);
> +		if (Status) {
> +			return Status;
> +		}
> +	}
> +
> +	Status = XHwIcap_CommandDesync(drvdata);
> +	if (Status) {
> +		return Status;
> +	}
> +
> +	return 0;
> +}
> +
> +static struct file_operations xhwicap_fops = {
> +	.owner = THIS_MODULE,
> +	.write = xhwicap_write,
> +	.read = xhwicap_read,
> +	.open = xhwicap_open,
> +	.release = xhwicap_release,
> +};
> +
> +static int __init xhwicap_drv_probe(struct device *dev)
> +{
> +	dev_t devt;
> +	struct platform_device *pdev = to_platform_device(dev);
> +	struct xhwicap_drvdata *drvdata = NULL;
> +	struct resource *regs_res;
> +	int retval = 0;
> +
> +	if (!dev) {
> +		return -EINVAL;
> +	}
> +
> +	dev_info(dev, "Xilinx icap port driver\n");
> +
> +	devt = MKDEV(xhwicap_major, xhwicap_minor + pdev->id);
> +
> +	drvdata = kmalloc(sizeof(struct xhwicap_drvdata), GFP_KERNEL);
> +	if (!drvdata) {
> +		dev_err(dev, "Couldn't allocate device private record\n");
> +		return -ENOMEM;
> +	}
> +	memset((void *)drvdata, 0, sizeof(struct xhwicap_drvdata));
> +	dev_set_drvdata(dev, (void *)drvdata);
> +
> +	/* Map the control registers in */
> +	regs_res = platform_get_resource(to_platform_device(dev),
> +					 IORESOURCE_MEM, 0);
> +	if (!regs_res) {
> +		dev_err(dev, "Couldn't get registers resource\n");
> +		retval = -EFAULT;
> +		goto failed1;
> +	}
> +
> +	drvdata->mem_start = regs_res->start;
> +	drvdata->mem_end = regs_res->end;
> +	drvdata->mem_size = regs_res->end - regs_res->start + 1;
> +
> +	if (drvdata->mem_size < XHWICAP_REGS) {
> +		dev_err(dev, "Couldn't get registers resource\n");
> +		retval = -EFAULT;
> +		goto failed1;
> +	}
> +
> +	if (!request_mem_region(drvdata->mem_start, drvdata->mem_size, DRIVER_NAME)) {
> +		dev_err(dev, "Couldn't lock memory region at %p\n",
> +			(void *)regs_res->start);
> +		retval = -EBUSY;
> +		goto failed1;
> +	}
> +
> +	drvdata->devt = devt;
> +	drvdata->dev = dev;
> +	drvdata->baseAddress = ioremap(drvdata->mem_start, drvdata->mem_size);
> +	if (!drvdata->baseAddress) {
> +		dev_err(dev, "ioremap() failed\n");
> +		goto failed2;
> +	}
> +
> +	dev_info(dev, "ioremap %lx to %p with size %x\n",
> +		 (unsigned long int)drvdata->mem_start,
> +			drvdata->baseAddress, drvdata->mem_size);
> +
> +	cdev_init(&drvdata->cdev, &xhwicap_fops);
> +	drvdata->cdev.owner = THIS_MODULE;
> +	retval = cdev_add(&drvdata->cdev, devt, 1);
> +	if (retval) {
> +		dev_err(dev, "cdev_add() failed\n");
> +		goto failed3;
> +	}
> +	/*  devfs_mk_cdev(devt, S_IFCHR|S_IRUGO|S_IWUGO, DRIVER_NAME); */
> +	class_device_create(icap_class, NULL, devt, NULL, DRIVER_NAME);
> +	return 0;		/* success */
> +
> + failed3:
> +	iounmap(drvdata->baseAddress);
> +
> + failed2:
> +	release_mem_region(regs_res->start, drvdata->mem_size);
> +
> + failed1:
> +	kfree(drvdata);
> +
> +	return retval;
> +}
> +
> +static int __exit xhwicap_drv_remove(struct device *dev)
> +{
> +	struct xhwicap_drvdata *drvdata;
> +
> +	if (!dev)
> +		return -EINVAL;
> +
> +	drvdata = (struct xhwicap_drvdata *)dev_get_drvdata(dev);
> +
> +	class_device_destroy(icap_class, drvdata->devt);
> +	cdev_del(&drvdata->cdev);
> +	iounmap(drvdata->baseAddress);
> +	release_mem_region(drvdata->mem_start, drvdata->mem_size);
> +	kfree(drvdata);
> +	dev_set_drvdata(dev, NULL);
> +
> +	return 0;		/* success */
> +}
> +
> +static struct device_driver xhwicap_module_driver = {
> +	.name = DRIVER_NAME,
> +	.bus = &platform_bus_type,
> +
> +	.probe = xhwicap_drv_probe,
> +	.remove = xhwicap_drv_remove,
> +};

Please use struct platform_driver instead.
> +
> +static int __init xhwicap_module_init(void)
> +{
> +	dev_t devt;
> +	int retval;
> +
> +	icap_class = class_create(THIS_MODULE, "xilinx_config");

What's that for?

> +
> +	if (xhwicap_major) {
> +		devt = MKDEV(xhwicap_major, xhwicap_minor);
> +		retval = register_chrdev_region(devt, xhwicap_no_minors,
> +						DRIVER_NAME);
> +	} else {
> +		retval =
> +		    alloc_chrdev_region(&devt, xhwicap_minor, xhwicap_no_minors,
> +					DRIVER_NAME);
> +		xhwicap_major = MAJOR(devt);
> +	}
> +	if (retval < 0) {
> +		xhwicap_major = 0;
> +		return retval;
> +	}
> +
> +	retval = driver_register(&xhwicap_module_driver);
> +
> +	if (retval) {
> +		unregister_chrdev_region(devt, xhwicap_no_minors);
> +	}
> +
> +	return retval;
> +}
> +
> +static void __exit xhwicap_module_cleanup(void)
> +{
> +	dev_t devt = MKDEV(xhwicap_major, xhwicap_minor);
> +
> +	class_destroy(icap_class);
> +
> +	driver_unregister(&xhwicap_module_driver);
> +
> +	unregister_chrdev_region(devt, xhwicap_no_minors);
> +}
> +
> +module_init(xhwicap_module_init);
> +module_exit(xhwicap_module_cleanup);
> +
> +#ifdef CONFIG_OF
> +
> +static int __init xilinx_hwicap_of_init(void)
> +{
> +	struct device_node *np;
> +	unsigned int i;
> +	struct platform_device *pdev;
> +	int ret;
> +
> +	for (np = NULL, i = 0;
> +	     (np = of_find_compatible_node(np, NULL, "xlnx,opb-hwicap")) != NULL;
> +	     i++) {
> +		struct resource r;
> +
> +		memset(&r, 0, sizeof(r));
> +
> +		ret = of_address_to_resource(np, 0, &r);
> +		if (ret)
> +			goto err;
> +		pdev =
> +		    platform_device_register_simple(DRIVER_NAME, i, &r, 1);
> +
> +		if (IS_ERR(pdev)) {
> +			ret = PTR_ERR(pdev);
> +			goto err;
> +		}
> +	}
> +
> +	return 0;
> +err:
> +	return ret;
> +}
> +
> +module_init(xilinx_hwicap_of_init);
> +
> +#endif
> +
> +MODULE_AUTHOR("Xilinx, Inc; Xilinx Research Labs Group");
> +MODULE_DESCRIPTION("Xilinx ICAP Port Driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.h b/drivers/char/xilinx_hwicap/xilinx_hwicap.h
> new file mode 100644
> index 0000000..80e3fe0
> --- /dev/null
> +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.h
> @@ -0,0 +1,539 @@
> +/*****************************************************************************
> + *
> + *     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, 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.
> + *
> + *     Xilinx products are not intended for use in life support appliances,
> + *     devices, or systems. Use in such applications is expressly prohibited.
> + *
> + *     (c) Copyright 2003-2007 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.
> + *
> + *****************************************************************************/
> +
> +#ifndef XILINX_HWICAP_H_	/* prevent circular inclusions */
> +#define XILINX_HWICAP_H_	/* by using protection macros */
> +
> +#include <linux/types.h>
> +#include <linux/cdev.h>
> +#include <linux/version.h>
> +#include <linux/platform_device.h>
> +
> +#include <asm/io.h>
> +
> +struct xhwicap_drvdata {
> +	u32 flags;
> +	u32 write_buffer_in_use;  /* Always in [0,3] */
> +	u8 write_buffer[4];
> +	u32 read_buffer_in_use;	  /* Always in [0,3] */
> +	u8 read_buffer[4];
> +	u32 mem_start;		  /* phys. address of the control registers */
> +	u32 mem_end;		  /* phys. address of the control registers */
> +	u32 mem_size;
> +	void __iomem *baseAddress;/* virt. address of the control registers */
> +
> +	struct device *dev;
> +	struct cdev cdev;	/* Char device structure */
> +	dev_t devt;
> +};
> +
> +/***************************** Include Files ********************************/
> +
> +#define virtex2 0
> +#define virtex4 1
> +
> +#ifdef CONFIG_XILINX_VIRTEX_4_FX
> +#define XHI_FAMILY virtex4
> +#else
> +#define XHI_FAMILY virtex2
> +#endif

So having a single kernel with v2p/v4 support is not an option?

> +
> +/************************** Constant Definitions ****************************/
> +
> +#define XHI_PAD_FRAMES              0x1
> +
> +/* Mask for calculating configuration packet headers */
> +#define XHI_WORD_COUNT_MASK_TYPE_1  0x7FFUL
> +#define XHI_WORD_COUNT_MASK_TYPE_2  0x1FFFFFUL
> +#define XHI_TYPE_MASK               0x7
> +#define XHI_REGISTER_MASK           0xF
> +#define XHI_OP_MASK                 0x3
> +
> +#define XHI_TYPE_SHIFT              29
> +#define XHI_REGISTER_SHIFT          13
> +#define XHI_OP_SHIFT                27
> +
> +#define XHI_TYPE_1                  1
> +#define XHI_TYPE_2                  2
> +#define XHI_OP_WRITE                2
> +#define XHI_OP_READ                 1
> +
> +/* Address Block Types */
> +#define XHI_FAR_CLB_BLOCK           0
> +#define XHI_FAR_BRAM_BLOCK          1
> +#define XHI_FAR_BRAM_INT_BLOCK      2
> +
> +/* Addresses of the Configuration Registers */
> +#define XHI_CRC                     0
> +#define XHI_FAR                     1
> +#define XHI_FDRI                    2
> +#define XHI_FDRO                    3
> +#define XHI_CMD                     4
> +#define XHI_CTL                     5
> +#define XHI_MASK                    6
> +#define XHI_STAT                    7
> +#define XHI_LOUT                    8
> +#define XHI_COR                     9
> +#define XHI_MFWR                    10
> +
> +#if XHI_FAMILY == virtex4
> +
> +#define XHI_CBC                     11
> +#define XHI_IDCODE                  12
> +#define XHI_AXSS                    13
> +#define XHI_NUM_REGISTERS           14
> +
> +#else
> +
> +#define XHI_FLR                     11
> +#define XHI_KEY                     12
> +#define XHI_CBC                     13
> +#define XHI_IDCODE                  14
> +#define XHI_NUM_REGISTERS           15
> +
> +#endif
> +
> +/* Configuration Commands */
> +#define XHI_CMD_NULL                0
> +#define XHI_CMD_WCFG                1
> +#define XHI_CMD_MFW                 2
> +#define XHI_CMD_DGHIGH              3
> +#define XHI_CMD_RCFG                4
> +#define XHI_CMD_START               5
> +#define XHI_CMD_RCAP                6
> +#define XHI_CMD_RCRC                7
> +#define XHI_CMD_AGHIGH              8
> +#define XHI_CMD_SWITCH              9
> +#define XHI_CMD_GRESTORE            10
> +#define XHI_CMD_SHUTDOWN            11
> +#define XHI_CMD_GCAPTURE            12
> +#define XHI_CMD_DESYNCH             13
> +
> +/* Packet constants */
> +#define XHI_SYNC_PACKET             0xAA995566UL
> +#define XHI_DUMMY_PACKET            0xFFFFFFFFUL
> +#define XHI_NOOP_PACKET             (XHI_TYPE_1 << XHI_TYPE_SHIFT)
> +#define XHI_TYPE_2_READ ((XHI_TYPE_2 << XHI_TYPE_SHIFT) | \
> +			(XHI_OP_READ << XHI_OP_SHIFT))
> +
> +#define XHI_TYPE_2_WRITE ((XHI_TYPE_2 << XHI_TYPE_SHIFT) | \
> +			(XHI_OP_WRITE << XHI_OP_SHIFT))
> +
> +#define XHI_TYPE2_CNT_MASK          0x07FFFFFF
> +
> +#define XHI_TYPE_1_PACKET_MAX_WORDS 2047UL
> +#define XHI_TYPE_1_HEADER_BYTES     4
> +#define XHI_TYPE_2_HEADER_BYTES     8
> +
> +/* Indicates how many bytes will fit in a buffer. (1 BRAM) */
> +#define XHI_MAX_BUFFER_BYTES        2048
> +#define XHI_MAX_BUFFER_INTS         512
> +
> +/* Number of frames in different tile types */
> +#if XHI_FAMILY == virtex4
> +
> +#define XHI_GCLK_FRAMES             3
> +#define XHI_IOB_FRAMES              30
> +#define XHI_DSP_FRAMES              21
> +#define XHI_CLB_FRAMES              22
> +#define XHI_BRAM_FRAMES             64
> +#define XHI_BRAM_INT_FRAMES         20
> +
> +#else
> +
> +#define XHI_GCLK_FRAMES             4
> +#define XHI_IOB_FRAMES              4
> +#define XHI_IOI_FRAMES              22
> +#define XHI_CLB_FRAMES              22
> +#define XHI_BRAM_FRAMES             64
> +#define XHI_BRAM_INT_FRAMES         22
> +
> +#endif
> +
> +/* Device Resources */
> +#define CLB                         0
> +#define DSP                         1
> +#define BRAM                        2
> +#define BRAM_INT                    3
> +#define IOB                         4
> +#define IOI                         5
> +#define CLK                         6
> +#define MGT                         7
> +
> +#define BLOCKTYPE0                  0
> +#define BLOCKTYPE1                  1
> +#define BLOCKTYPE2                  2
> +
> +/* The number of words reserved for the header in the storage buffer. */
> +/* MAY CHANGE FOR V4 */
> +#define XHI_HEADER_BUFFER_WORDS     20
> +#define XHI_HEADER_BUFFER_BYTES     (XHI_HEADER_BUFFER_WORDS << 2)
> +
> +/* CLB major frames start at 3 for the first column (since we are using
> + * column numbers that start at 1, when the column is added to this offset,
> + * that first one will be 3 as required. */
> +#define XHI_CLB_MAJOR_FRAME_OFFSET  2
> +
> +/* File access and error constants */
> +#define XHI_DEVICE_READ_ERROR       -1
> +#define XHI_DEVICE_WRITE_ERROR      -2
> +#define XHI_BUFFER_OVERFLOW_ERROR   -3
> +
> +#define XHI_DEVICE_READ             0x1
> +#define XHI_DEVICE_WRITE            0x0
> +
> +/* Constants for checking transfer status */
> +#define XHI_CYCLE_DONE              0
> +#define XHI_CYCLE_EXECUTING         1
> +
> +/* Constant to use for CRC check when CRC has been disabled */
> +#define XHI_DISABLED_AUTO_CRC       0x0000DEFCUL
> +
> +/* Major Row Offset */
> +#define XHI_CLB_MAJOR_ROW_OFFSET 96+(32*XHI_HEADER_BUFFER_WORDS)-1
> +
> +/* Number of times to poll the done regsiter */
> +#define XHI_MAX_RETRIES     1000
> +
> +/************************** Constant Definitions ****************************/
> +
> +/* XHwIcap register offsets */
> +
> +/* Size of transfer, read & write */
> +#define XHI_SIZE_REG_OFFSET        0x800L
> +/* Offset into bram, read & write */
> +#define XHI_BRAM_OFFSET_REG_OFFSET 0x804L
> +/* Read not Configure, direction of transfer.  Write only */
> +#define XHI_RNC_REG_OFFSET         0x808L
> +/* Indicates transfer complete. Read only */
> +#define XHI_STATUS_REG_OFFSET      0x80CL
> +
> +/* Constants for setting the RNC register */
> +#define XHI_CONFIGURE              0x0UL
> +#define XHI_READBACK               0x1UL
> +
> +/* Constants for the Done register */
> +#define XHI_NOT_FINISHED           0x0UL
> +#define XHI_FINISHED               0x1UL
> +
> +/**************************** Type Definitions ******************************/
> +
> +/***************** Macros (Inline Functions) Definitions ********************/
> +
> +/****************************************************************************/
> +/**
> +*
> +* Get the contents of the size register.
> +*
> +* The size register holds the number of 32 bit words to transfer between
> +* bram and the icap (or icap to bram).
> +*
> +* @param    BaseAddress is the  base address of the device
> +*
> +* @return   A 32-bit value representing the contents of the size
> +* register.
> +*
> +* @note
> +*
> +* u32 XHwIcap_mGetSizeReg(u32 BaseAddress);
> +*
> +*****************************************************************************/
> +#define XHwIcap_mGetSizeReg(BaseAddress) \
> +    (in_be32((u32 *)((BaseAddress) + XHI_SIZE_REG_OFFSET)))
> +
> +/****************************************************************************/

Why not a single getter with a offset/register parameter instead of
all these? And use inline functions instead of macros.

> +/**
> +*
> +* Get the contents of the bram offset register.
> +*
> +* The bram offset register holds the starting bram address to transfer
> +* data from during configuration or write data to during readback.
> +*
> +* @param    BaseAddress is the  base address of the device
> +*
> +* @return   A 32-bit value representing the contents of the bram offset
> +* register.
> +*
> +* @note
> +*
> +* u32 XHwIcap_mGetOffsetReg(u32 BaseAddress);
> +*
> +*****************************************************************************/
> +#define XHwIcap_mGetOffsetReg(BaseAddress) \
> +    (in_be32((u32 *)((BaseAddress + XHI_BRAM_OFFSET_REG_OFFSET))))
> +
> +/****************************************************************************/
> +/**
> +*
> +* Get the contents of the done register.
> +*
> +* The done register is set to zero during configuration or readback.
> +* When the current configuration or readback completes the done register
> +* is set to one.
> +*
> +* @param    BaseAddress is the base address of the device
> +*
> +* @return   A 32-bit value with bit 1 representing done or not
> +*
> +* @note
> +*
> +* u32 XHwIcap_mGetDoneReg(u32 BaseAddress);
> +*
> +*****************************************************************************/
> +
> +#define XHwIcap_mGetDoneReg(BaseAddress) \
> +    (in_be32((u32 *)((BaseAddress + XHI_STATUS_REG_OFFSET))) & 1)
> +
> +/****************************************************************************/
> +/**
> +*
> +* Get the contents of the status register.
> +*
> +* The status register contains the ICAP status and the done bit.
> +*
> +* D8 - cfgerr
> +* D7 - dalign
> +* D6 - rip
> +* D5 - in_abort_l
> +* D4 - Always 1
> +* D3 - Always 1
> +* D2 - Always 1
> +* D1 - Always 1
> +* D0 - Done bit
> +*
> +* @param    BaseAddress is the base address of the device
> +*
> +* @return   A 32-bit value representing the contents of the status register
> +*
> +* @note
> +*
> +* u32 XHwIcap_mGetStatusReg(u32 BaseAddress);
> +*
> +*****************************************************************************/
> +
> +#define XHwIcap_mGetStatusReg(BaseAddress) \
> +    (in_be32((u32 *)((BaseAddress + XHI_STATUS_REG_OFFSET))))
> +
> +#define XHwIcap_mReset(BaseAddress) \
> +    (out_be32((u32 *)((BaseAddress + XHI_STATUS_REG_OFFSET)), 0xFEFE))
> +
> +/****************************************************************************/
> +/**
> +* Reads data from the storage buffer bram.
> +*
> +* A bram is used as a configuration memory cache.  One frame of data can
> +* be stored in this "storage buffer".
> +*
> +* @param    BaseAddress - contains the base address of the component.
> +*
> +* @param    Offset - The offset into which the data should be read.
> +*
> +* @return   The value of the specified offset in the bram.
> +*
> +* @note
> +*
> +* u32 XHwIcap_mGetBram(u32 BaseAddress, u32 Offset);
> +*
> +*****************************************************************************/
> +#define XHwIcap_mGetBram(BaseAddress, Offset) \
> +    (in_be32((u32 *)((BaseAddress+(Offset<<2)))))
> +
> +/****************************************************************************/
> +/**
> +* Set the size register.
> +*
> +* The size register holds the number of 8 bit bytes to transfer between
> +* bram and the icap (or icap to bram).
> +*
> +* @param    BaseAddress - contains the base address of the device.
> +*
> +* @param    Data - The size in bytes.
> +*
> +* @return   None.
> +*
> +* @note
> +*
> +* void XHwIcap_mSetSizeReg(u32 BaseAddress, u32 Data);
> +*
> +*****************************************************************************/
> +#define XHwIcap_mSetSizeReg(BaseAddress, Data) \
> +    (out_be32((u32 *)((BaseAddress) + XHI_SIZE_REG_OFFSET), (Data)))
> +
> +/****************************************************************************/
> +/**
> +* Set the bram offset register.
> +*
> +* The bram offset register holds the starting bram address to transfer
> +* data from during configuration or write data to during readback.
> +*
> +* @param    BaseAddress contains the base address of the device.
> +*
> +* @param    Data is the value to be written to the data register.
> +*
> +* @return   None.
> +*
> +* @note
> +*
> +* void XHwIcap_mSetOffsetReg(u32 BaseAddress, u32 Data);
> +*
> +*****************************************************************************/
> +#define XHwIcap_mSetOffsetReg(BaseAddress, Data) \
> +    (out_be32((u32 *)((BaseAddress) + XHI_BRAM_OFFSET_REG_OFFSET), (Data)))
> +
> +/****************************************************************************/
> +/**
> +* Set the RNC (Readback not Configure) register.
> +*
> +* The RNC register determines the direction of the data transfer.  It
> +* controls whether a configuration or readback take place.  Writing to
> +* this register initiates the transfer.  A value of 1 initiates a
> +* readback while writing a value of 0 initiates a configuration.
> +*
> +* @param    BaseAddress contains the base address of the device.
> +*
> +* @param    Data is the value to be written to the data register.
> +*
> +* @return   None.
> +*
> +* @note
> +*
> +* void XHwIcap_mSetRncReg(u32 BaseAddress, u32 Data);
> +*
> +*****************************************************************************/
> +#define XHwIcap_mSetRncReg(BaseAddress, Data) \
> +    (out_be32((u32 *)((BaseAddress) + XHI_RNC_REG_OFFSET), (Data)))
> +
> +/****************************************************************************/
> +/**
> +* Write data to the storage buffer bram.
> +*
> +* A bram is used as a configuration memory cache.  One frame of data can
> +* be stored in this "storage buffer".
> +*
> +* @param    BaseAddress - contains the base address of the component.
> +*
> +* @param    Offset - The offset into which the data should be written.
> +*
> +* @param    Data - The value to be written to the bram offset.
> +*
> +* @return   None.
> +*
> +* @note
> +*
> +* void XHwIcap_mSetBram(u32 BaseAddress, u32 Offset, u32 Data);
> +*
> +*****************************************************************************/
> +#define XHwIcap_mSetBram(BaseAddress, Offset, Data) \
> +    (out_be32((u32 *)((BaseAddress+(Offset<<2))), (Data)))
> +
> +/****************************************************************************/
> +/**
> +*
> +* Generates a Type 1 packet header that reads back the requested configuration
> +* register.
> +*
> +* @param    Register is the address of the register to be read back.
> +*           Register constants are defined in this file.
> +*
> +* @return   Type 1 packet header to read the specified register
> +*
> +* @note     None.
> +*
> +*****************************************************************************/
> +#define XHwIcap_Type1Read(Register) \
> +    ((XHI_TYPE_1 << XHI_TYPE_SHIFT) | (Register << XHI_REGISTER_SHIFT) | \
> +    (XHI_OP_READ << XHI_OP_SHIFT))
> +
> +/****************************************************************************/
> +/**
> +*
> +* Generates a Type 1 packet header that writes to the requested
> +* configuration register.
> +*
> +* @param    Register is the address of the register to be written to.
> +*           Register constants are defined in this file.
> +*
> +* @return   Type 1 packet header to write the specified register
> +*
> +* @note     None.
> +*
> +*****************************************************************************/
> +#define XHwIcap_Type1Write(Register) \
> +    ((XHI_TYPE_1 << XHI_TYPE_SHIFT) | (Register << XHI_REGISTER_SHIFT) | \
> +    (XHI_OP_WRITE << XHI_OP_SHIFT))
> +
> +/************************** Function Prototypes *****************************/
> +
> +/* These functions are the ones defined in the lower level
> + * Self-Reconfiguration Platform (SRP) API.
> + */
> +
> +/* Initializes a XHwIcap instance.. */
> +int XHwIcap_Initialize(struct xhwicap_drvdata *InstancePtr, u16 DeviceId,
> +		       u32 DeviceIdCode);
> +
> +/* Reads integers from the device into the storage buffer. */
> +int XHwIcap_DeviceRead(struct xhwicap_drvdata *InstancePtr, u32 Offset,
> +		       u32 NumInts);
> +
> +/* Writes integers to the device from the storage buffer. */
> +int XHwIcap_DeviceWrite(struct xhwicap_drvdata *InstancePtr, u32 Offset,
> +			u32 NumInts);
> +
> +/* Writes word to the storage buffer. */
> +void XHwIcap_StorageBufferWrite(struct xhwicap_drvdata *InstancePtr,
> +				u32 Address, u32 Data);
> +
> +/* Reads word from the storage buffer. */
> +u32 XHwIcap_StorageBufferRead(struct xhwicap_drvdata *InstancePtr, u32 Address);
> +
> +/* Loads a partial bitstream from system memory. */
> +int XHwIcap_SetConfiguration(struct xhwicap_drvdata *InstancePtr, u32 *Data,
> +			     u32 Size);
> +
> +/* Loads a partial bitstream from system memory. */
> +int XHwIcap_GetConfiguration(struct xhwicap_drvdata *InstancePtr, u32 *Data,
> +			     u32 Size);
> +
> +/* Sends a DESYNC command to the ICAP */
> +int XHwIcap_CommandDesync(struct xhwicap_drvdata *InstancePtr);
> +
> +/* Sends a CAPTURE command to the ICAP */
> +int XHwIcap_CommandCapture(struct xhwicap_drvdata *InstancePtr);
> +
> +/* Returns the value of the specified configuration register */
> +u32 XHwIcap_GetConfigReg(struct xhwicap_drvdata *InstancePtr, u32 ConfigReg);
> +
> +#endif
> -- 
> 1.5.3.4-dirty
> 
-- 
Bye, Peter Korsgaard



More information about the Linuxppc-dev mailing list