/***************************************************************************** * * 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. * * (c) Copyright 2002 Xilinx Inc., Systems Engineering Group * (c) Copyright 2004 Xilinx Inc., Systems Engineering Group * (c) Copyright 2007-2008 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. *
*****************************************************************************/
/* * This is the code behind /dev/icap* -- it allows a user-space * application to use the Xilinx ICAP subsystem. * * The following operations are possible: * * open open the port and initialize for access. * release release port * write Write a bitstream to the configuration processor. * read Read a data stream from the configuration processor. * * After being opened, the port is initialized and accessed to avoid a * corrupted first read which may occur with some hardware. The port * is left in a desynched state, requiring that a synch sequence be * transmitted before any valid configuration data. A user will have * exclusive access to the device while it remains open, and the state * of the ICAP cannot be guaranteed after the device is closed. Note * that a complete reset of the core and the state of the ICAP cannot * be performed on many versions of the cores, hence users of this * device should avoid making inconsistent accesses to the device. In * particular, accessing the read interface, without first generating * a write containing a readback packet can leave the ICAP in an * inaccessible state. * * 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/icap0 * * Note that unless foo.bit is an appropriately constructed partial * bitstream, this has a high likelihood of overwriting the design * currently programmed in the FPGA.
*/
/* An array, which is set to true when the device is registered. */ static DEFINE_MUTEX(hwicap_mutex); staticbool probed_devices[HWICAP_DEVICES]; staticstruct mutex icap_sem;
/** * hwicap_command_desync - Send a DESYNC command to the ICAP port. * @drvdata: a pointer to the drvdata. * * Returns: '0' on success and failure value on error * * This command desynchronizes the ICAP After this command, a * bitstream containing a NULL packet, followed by a SYNCH packet is * required before the ICAP will recognize commands.
*/ staticint hwicap_command_desync(struct hwicap_drvdata *drvdata)
{
u32 buffer[4];
u32 index = 0;
/* * Create the data to be written to the ICAP.
*/
buffer[index++] = hwicap_type_1_write(drvdata->config_regs->CMD) | 1;
buffer[index++] = XHI_CMD_DESYNCH;
buffer[index++] = XHI_NOOP_PACKET;
buffer[index++] = XHI_NOOP_PACKET;
/* * Write the data to the FIFO and initiate the transfer of data present * in the FIFO to the ICAP device.
*/ return drvdata->config->set_configuration(drvdata,
&buffer[0], index);
}
/** * hwicap_get_configuration_register - Query a configuration register. * @drvdata: a pointer to the drvdata. * @reg: a constant which represents the configuration * register value to be returned. * Examples: XHI_IDCODE, XHI_FLR. * @reg_data: returns the value of the register. * * Returns: '0' on success and failure value on error * * Sends a query packet to the ICAP and then receives the response. * The icap is left in Synched state.
*/ staticint hwicap_get_configuration_register(struct hwicap_drvdata *drvdata,
u32 reg, u32 *reg_data)
{ int status;
u32 buffer[6];
u32 index = 0;
/* * Create the data to be written to the ICAP.
*/
buffer[index++] = XHI_DUMMY_PACKET;
buffer[index++] = XHI_NOOP_PACKET;
buffer[index++] = XHI_SYNC_PACKET;
buffer[index++] = XHI_NOOP_PACKET;
buffer[index++] = XHI_NOOP_PACKET;
/* * Write the data to the FIFO and initiate the transfer of data present * in the FIFO to the ICAP device.
*/
status = drvdata->config->set_configuration(drvdata,
&buffer[0], index); if (status) return status;
/* If the syncword was not found, then we need to start over. */
status = drvdata->config->get_status(drvdata); if ((status & XHI_SR_DALIGN_MASK) != XHI_SR_DALIGN_MASK) return -EIO;
/* * Write the data to the FIFO and initiate the transfer of data present * in the FIFO to the ICAP device.
*/
status = drvdata->config->set_configuration(drvdata,
&buffer[0], index); if (status) return status;
/* * Read the configuration register
*/
status = drvdata->config->get_configuration(drvdata, reg_data, 1); if (status) return status;
return 0;
}
staticint hwicap_initialize_hwicap(struct hwicap_drvdata *drvdata)
{ int status;
u32 idcode;
dev_dbg(drvdata->dev, "initializing\n");
/* Abort any current transaction, to make sure we have the * ICAP in a good state.
*/
dev_dbg(drvdata->dev, "Reset...\n");
drvdata->config->reset(drvdata);
dev_dbg(drvdata->dev, "Desync...\n");
status = hwicap_command_desync(drvdata); if (status) return status;
/* Attempt to read the IDCODE from ICAP. This * may not be returned correctly, due to the design of the * hardware.
*/
dev_dbg(drvdata->dev, "Reading IDCODE...\n");
status = hwicap_get_configuration_register(
drvdata, drvdata->config_regs->IDCODE, &idcode);
dev_dbg(drvdata->dev, "IDCODE = %x\n", idcode); if (status) return status;
dev_dbg(drvdata->dev, "Desync...\n");
status = hwicap_command_desync(drvdata); if (status) return status;
status = mutex_lock_interruptible(&drvdata->sem); if (status) return 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)) {
status = -EFAULT; goto error;
}
drvdata->read_buffer_in_use -= bytes_to_read;
memmove(drvdata->read_buffer,
drvdata->read_buffer + bytes_to_read,
4 - bytes_to_read);
} else { /* Get new data from the ICAP, and return what was requested. */
kbuf = (u32 *) get_zeroed_page(GFP_KERNEL); if (!kbuf) {
status = -ENOMEM; goto error;
}
/* 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. */
bytes_remaining = bytes_to_read & 3;
bytes_to_read &= ~3;
words = bytes_to_read >> 2;
status = drvdata->config->get_configuration(drvdata,
kbuf, words);
/* If we didn't read correctly, then bail out. */ if (status) {
free_page((unsignedlong)kbuf); goto error;
}
/* If we fail to return the data to the user, then bail out. */ if (copy_to_user(buf, kbuf, bytes_to_read)) {
free_page((unsignedlong)kbuf);
status = -EFAULT; goto error;
}
memcpy(drvdata->read_buffer,
kbuf,
bytes_remaining);
drvdata->read_buffer_in_use = bytes_remaining;
free_page((unsignedlong)kbuf);
}
status = bytes_to_read;
error:
mutex_unlock(&drvdata->sem); return status;
}
if (id < 0) { for (id = 0; id < HWICAP_DEVICES; id++) if (!probed_devices[id]) break;
} if (id < 0 || id >= HWICAP_DEVICES) {
mutex_unlock(&icap_sem);
dev_err(dev, "%s%i too large\n", DRIVER_NAME, id); return -EINVAL;
} if (probed_devices[id]) {
mutex_unlock(&icap_sem);
dev_err(dev, "cannot assign to %s%i; it is already in use\n",
DRIVER_NAME, id); return -EBUSY;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.