[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