aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/xilinx_hwicap/buffer_icap.c
diff options
context:
space:
mode:
authorStephen Neuendorffer <stephen.neuendorffer@xilinx.com>2008-02-05 12:24:09 -0500
committerGrant Likely <grant.likely@secretlab.ca>2008-02-06 12:23:52 -0500
commitef141a0bb0dc6172bb8fe5408cf8adbd5f76ff45 (patch)
tree41bc7cbfa8e8501c510632f8e98b3603c6b3746c /drivers/char/xilinx_hwicap/buffer_icap.c
parent3de66a175d2014246a2e990412e5750922e5c7d8 (diff)
[POWERPC] Xilinx: hwicap driver
This includes code for new fifo-based xps_hwicap in addition to the older opb_hwicap, which has a significantly different interface. The common code between the two drivers is largely shared. Significant differences exists between this driver and what is supported in the EDK drivers. In particular, most of the architecture-specific code for reconfiguring individual FPGA resources has been removed. This functionality is likely better provided in a user-space support library. In addition, read and write access is supported. In addition, although the xps_hwicap cores support interrupt-driver mode, this driver only supports polled operation, in order to make the code simpler, and since the interrupt processing overhead is likely to slow down the throughput under Linux. Signed-off-by: Stephen Neuendorffer <stephen.neuendorffer@xilinx.com> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/char/xilinx_hwicap/buffer_icap.c')
-rw-r--r--drivers/char/xilinx_hwicap/buffer_icap.c380
1 files changed, 380 insertions, 0 deletions
diff --git a/drivers/char/xilinx_hwicap/buffer_icap.c b/drivers/char/xilinx_hwicap/buffer_icap.c
new file mode 100644
index 000000000000..dfea2bde162b
--- /dev/null
+++ b/drivers/char/xilinx_hwicap/buffer_icap.c
@@ -0,0 +1,380 @@
1/*****************************************************************************
2 *
3 * Author: Xilinx, Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
11 * AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
12 * SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,
13 * OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
14 * APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
15 * THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
16 * AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
17 * FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY
18 * WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
19 * IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
20 * REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
21 * INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE.
23 *
24 * Xilinx products are not intended for use in life support appliances,
25 * devices, or systems. Use in such applications is expressly prohibited.
26 *
27 * (c) Copyright 2003-2008 Xilinx Inc.
28 * All rights reserved.
29 *
30 * You should have received a copy of the GNU General Public License along
31 * with this program; if not, write to the Free Software Foundation, Inc.,
32 * 675 Mass Ave, Cambridge, MA 02139, USA.
33 *
34 *****************************************************************************/
35
36#include "buffer_icap.h"
37
38/* Indicates how many bytes will fit in a buffer. (1 BRAM) */
39#define XHI_MAX_BUFFER_BYTES 2048
40#define XHI_MAX_BUFFER_INTS (XHI_MAX_BUFFER_BYTES >> 2)
41
42/* File access and error constants */
43#define XHI_DEVICE_READ_ERROR -1
44#define XHI_DEVICE_WRITE_ERROR -2
45#define XHI_BUFFER_OVERFLOW_ERROR -3
46
47#define XHI_DEVICE_READ 0x1
48#define XHI_DEVICE_WRITE 0x0
49
50/* Constants for checking transfer status */
51#define XHI_CYCLE_DONE 0
52#define XHI_CYCLE_EXECUTING 1
53
54/* buffer_icap register offsets */
55
56/* Size of transfer, read & write */
57#define XHI_SIZE_REG_OFFSET 0x800L
58/* offset into bram, read & write */
59#define XHI_BRAM_OFFSET_REG_OFFSET 0x804L
60/* Read not Configure, direction of transfer. Write only */
61#define XHI_RNC_REG_OFFSET 0x808L
62/* Indicates transfer complete. Read only */
63#define XHI_STATUS_REG_OFFSET 0x80CL
64
65/* Constants for setting the RNC register */
66#define XHI_CONFIGURE 0x0UL
67#define XHI_READBACK 0x1UL
68
69/* Constants for the Done register */
70#define XHI_NOT_FINISHED 0x0UL
71#define XHI_FINISHED 0x1UL
72
73#define XHI_BUFFER_START 0
74
75/**
76 * buffer_icap_get_status: Get the contents of the status register.
77 * @parameter base_address: is the base address of the device
78 *
79 * The status register contains the ICAP status and the done bit.
80 *
81 * D8 - cfgerr
82 * D7 - dalign
83 * D6 - rip
84 * D5 - in_abort_l
85 * D4 - Always 1
86 * D3 - Always 1
87 * D2 - Always 1
88 * D1 - Always 1
89 * D0 - Done bit
90 **/
91static inline u32 buffer_icap_get_status(void __iomem *base_address)
92{
93 return in_be32(base_address + XHI_STATUS_REG_OFFSET);
94}
95
96/**
97 * buffer_icap_get_bram: Reads data from the storage buffer bram.
98 * @parameter base_address: contains the base address of the component.
99 * @parameter offset: The word offset from which the data should be read.
100 *
101 * A bram is used as a configuration memory cache. One frame of data can
102 * be stored in this "storage buffer".
103 **/
104static inline u32 buffer_icap_get_bram(void __iomem *base_address,
105 u32 offset)
106{
107 return in_be32(base_address + (offset << 2));
108}
109
110/**
111 * buffer_icap_busy: Return true if the icap device is busy
112 * @parameter base_address: is the base address of the device
113 *
114 * The queries the low order bit of the status register, which
115 * indicates whether the current configuration or readback operation
116 * has completed.
117 **/
118static inline bool buffer_icap_busy(void __iomem *base_address)
119{
120 return (buffer_icap_get_status(base_address) & 1) == XHI_NOT_FINISHED;
121}
122
123/**
124 * buffer_icap_busy: Return true if the icap device is not busy
125 * @parameter base_address: is the base address of the device
126 *
127 * The queries the low order bit of the status register, which
128 * indicates whether the current configuration or readback operation
129 * has completed.
130 **/
131static inline bool buffer_icap_done(void __iomem *base_address)
132{
133 return (buffer_icap_get_status(base_address) & 1) == XHI_FINISHED;
134}
135
136/**
137 * buffer_icap_set_size: Set the size register.
138 * @parameter base_address: is the base address of the device
139 * @parameter data: The size in bytes.
140 *
141 * The size register holds the number of 8 bit bytes to transfer between
142 * bram and the icap (or icap to bram).
143 **/
144static inline void buffer_icap_set_size(void __iomem *base_address,
145 u32 data)
146{
147 out_be32(base_address + XHI_SIZE_REG_OFFSET, data);
148}
149
150/**
151 * buffer_icap_mSetoffsetReg: Set the bram offset register.
152 * @parameter base_address: contains the base address of the device.
153 * @parameter data: is the value to be written to the data register.
154 *
155 * The bram offset register holds the starting bram address to transfer
156 * data from during configuration or write data to during readback.
157 **/
158static inline void buffer_icap_set_offset(void __iomem *base_address,
159 u32 data)
160{
161 out_be32(base_address + XHI_BRAM_OFFSET_REG_OFFSET, data);
162}
163
164/**
165 * buffer_icap_set_rnc: Set the RNC (Readback not Configure) register.
166 * @parameter base_address: contains the base address of the device.
167 * @parameter data: is the value to be written to the data register.
168 *
169 * The RNC register determines the direction of the data transfer. It
170 * controls whether a configuration or readback take place. Writing to
171 * this register initiates the transfer. A value of 1 initiates a
172 * readback while writing a value of 0 initiates a configuration.
173 **/
174static inline void buffer_icap_set_rnc(void __iomem *base_address,
175 u32 data)
176{
177 out_be32(base_address + XHI_RNC_REG_OFFSET, data);
178}
179
180/**
181 * buffer_icap_set_bram: Write data to the storage buffer bram.
182 * @parameter base_address: contains the base address of the component.
183 * @parameter offset: The word offset at which the data should be written.
184 * @parameter data: The value to be written to the bram offset.
185 *
186 * A bram is used as a configuration memory cache. One frame of data can
187 * be stored in this "storage buffer".
188 **/
189static inline void buffer_icap_set_bram(void __iomem *base_address,
190 u32 offset, u32 data)
191{
192 out_be32(base_address + (offset << 2), data);
193}
194
195/**
196 * buffer_icap_device_read: Transfer bytes from ICAP to the storage buffer.
197 * @parameter drvdata: a pointer to the drvdata.
198 * @parameter offset: The storage buffer start address.
199 * @parameter count: The number of words (32 bit) to read from the
200 * device (ICAP).
201 **/
202static int buffer_icap_device_read(struct hwicap_drvdata *drvdata,
203 u32 offset, u32 count)
204{
205
206 s32 retries = 0;
207 void __iomem *base_address = drvdata->base_address;
208
209 if (buffer_icap_busy(base_address))
210 return -EBUSY;
211
212 if ((offset + count) > XHI_MAX_BUFFER_INTS)
213 return -EINVAL;
214
215 /* setSize count*4 to get bytes. */
216 buffer_icap_set_size(base_address, (count << 2));
217 buffer_icap_set_offset(base_address, offset);
218 buffer_icap_set_rnc(base_address, XHI_READBACK);
219
220 while (buffer_icap_busy(base_address)) {
221 retries++;
222 if (retries > XHI_MAX_RETRIES)
223 return -EBUSY;
224 }
225 return 0;
226
227};
228
229/**
230 * buffer_icap_device_write: Transfer bytes from ICAP to the storage buffer.
231 * @parameter drvdata: a pointer to the drvdata.
232 * @parameter offset: The storage buffer start address.
233 * @parameter count: The number of words (32 bit) to read from the
234 * device (ICAP).
235 **/
236static int buffer_icap_device_write(struct hwicap_drvdata *drvdata,
237 u32 offset, u32 count)
238{
239
240 s32 retries = 0;
241 void __iomem *base_address = drvdata->base_address;
242
243 if (buffer_icap_busy(base_address))
244 return -EBUSY;
245
246 if ((offset + count) > XHI_MAX_BUFFER_INTS)
247 return -EINVAL;
248
249 /* setSize count*4 to get bytes. */
250 buffer_icap_set_size(base_address, count << 2);
251 buffer_icap_set_offset(base_address, offset);
252 buffer_icap_set_rnc(base_address, XHI_CONFIGURE);
253
254 while (buffer_icap_busy(base_address)) {
255 retries++;
256 if (retries > XHI_MAX_RETRIES)
257 return -EBUSY;
258 }
259 return 0;
260
261};
262
263/**
264 * buffer_icap_reset: Reset the logic of the icap device.
265 * @parameter drvdata: a pointer to the drvdata.
266 *
267 * Writing to the status register resets the ICAP logic in an internal
268 * version of the core. For the version of the core published in EDK,
269 * this is a noop.
270 **/
271void buffer_icap_reset(struct hwicap_drvdata *drvdata)
272{
273 out_be32(drvdata->base_address + XHI_STATUS_REG_OFFSET, 0xFEFE);
274}
275
276/**
277 * buffer_icap_set_configuration: Load a partial bitstream from system memory.
278 * @parameter drvdata: a pointer to the drvdata.
279 * @parameter data: Kernel address of the partial bitstream.
280 * @parameter size: the size of the partial bitstream in 32 bit words.
281 **/
282int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data,
283 u32 size)
284{
285 int status;
286 s32 buffer_count = 0;
287 s32 num_writes = 0;
288 bool dirty = 0;
289 u32 i;
290 void __iomem *base_address = drvdata->base_address;
291
292 /* Loop through all the data */
293 for (i = 0, buffer_count = 0; i < size; i++) {
294
295 /* Copy data to bram */
296 buffer_icap_set_bram(base_address, buffer_count, data[i]);
297 dirty = 1;
298
299 if (buffer_count < XHI_MAX_BUFFER_INTS - 1) {
300 buffer_count++;
301 continue;
302 }
303
304 /* Write data to ICAP */
305 status = buffer_icap_device_write(
306 drvdata,
307 XHI_BUFFER_START,
308 XHI_MAX_BUFFER_INTS);
309 if (status != 0) {
310 /* abort. */
311 buffer_icap_reset(drvdata);
312 return status;
313 }
314
315 buffer_count = 0;
316 num_writes++;
317 dirty = 0;
318 }
319
320 /* Write unwritten data to ICAP */
321 if (dirty) {
322 /* Write data to ICAP */
323 status = buffer_icap_device_write(drvdata, XHI_BUFFER_START,
324 buffer_count);
325 if (status != 0) {
326 /* abort. */
327 buffer_icap_reset(drvdata);
328 }
329 return status;
330 }
331
332 return 0;
333};
334
335/**
336 * buffer_icap_get_configuration: Read configuration data from the device.
337 * @parameter drvdata: a pointer to the drvdata.
338 * @parameter data: Address of the data representing the partial bitstream
339 * @parameter size: the size of the partial bitstream in 32 bit words.
340 **/
341int buffer_icap_get_configuration(struct hwicap_drvdata *drvdata, u32 *data,
342 u32 size)
343{
344 int status;
345 s32 buffer_count = 0;
346 s32 read_count = 0;
347 u32 i;
348 void __iomem *base_address = drvdata->base_address;
349
350 /* Loop through all the data */
351 for (i = 0, buffer_count = XHI_MAX_BUFFER_INTS; i < size; i++) {
352 if (buffer_count == XHI_MAX_BUFFER_INTS) {
353 u32 words_remaining = size - i;
354 u32 words_to_read =
355 words_remaining <
356 XHI_MAX_BUFFER_INTS ? words_remaining :
357 XHI_MAX_BUFFER_INTS;
358
359 /* Read data from ICAP */
360 status = buffer_icap_device_read(
361 drvdata,
362 XHI_BUFFER_START,
363 words_to_read);
364 if (status != 0) {
365 /* abort. */
366 buffer_icap_reset(drvdata);
367 return status;
368 }
369
370 buffer_count = 0;
371 read_count++;
372 }
373
374 /* Copy data from bram */
375 data[i] = buffer_icap_get_bram(base_address, buffer_count);
376 buffer_count++;
377 }
378
379 return 0;
380};