Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
buffer_icap.c
Go to the documentation of this file.
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  * (c) Copyright 2003-2008 Xilinx Inc.
25  * All rights reserved.
26  *
27  * You should have received a copy of the GNU General Public License along
28  * with this program; if not, write to the Free Software Foundation, Inc.,
29  * 675 Mass Ave, Cambridge, MA 02139, USA.
30  *
31  *****************************************************************************/
32 
33 #include "buffer_icap.h"
34 
35 /* Indicates how many bytes will fit in a buffer. (1 BRAM) */
36 #define XHI_MAX_BUFFER_BYTES 2048
37 #define XHI_MAX_BUFFER_INTS (XHI_MAX_BUFFER_BYTES >> 2)
38 
39 /* File access and error constants */
40 #define XHI_DEVICE_READ_ERROR -1
41 #define XHI_DEVICE_WRITE_ERROR -2
42 #define XHI_BUFFER_OVERFLOW_ERROR -3
43 
44 #define XHI_DEVICE_READ 0x1
45 #define XHI_DEVICE_WRITE 0x0
46 
47 /* Constants for checking transfer status */
48 #define XHI_CYCLE_DONE 0
49 #define XHI_CYCLE_EXECUTING 1
50 
51 /* buffer_icap register offsets */
52 
53 /* Size of transfer, read & write */
54 #define XHI_SIZE_REG_OFFSET 0x800L
55 /* offset into bram, read & write */
56 #define XHI_BRAM_OFFSET_REG_OFFSET 0x804L
57 /* Read not Configure, direction of transfer. Write only */
58 #define XHI_RNC_REG_OFFSET 0x808L
59 /* Indicates transfer complete. Read only */
60 #define XHI_STATUS_REG_OFFSET 0x80CL
61 
62 /* Constants for setting the RNC register */
63 #define XHI_CONFIGURE 0x0UL
64 #define XHI_READBACK 0x1UL
65 
66 /* Constants for the Done register */
67 #define XHI_NOT_FINISHED 0x0UL
68 #define XHI_FINISHED 0x1UL
69 
70 #define XHI_BUFFER_START 0
71 
89 {
90  return in_be32(drvdata->base_address + XHI_STATUS_REG_OFFSET);
91 }
92 
101 static inline u32 buffer_icap_get_bram(void __iomem *base_address,
102  u32 offset)
103 {
104  return in_be32(base_address + (offset << 2));
105 }
106 
115 static inline bool buffer_icap_busy(void __iomem *base_address)
116 {
117  u32 status = in_be32(base_address + XHI_STATUS_REG_OFFSET);
118  return (status & 1) == XHI_NOT_FINISHED;
119 }
120 
129 static inline void buffer_icap_set_size(void __iomem *base_address,
130  u32 data)
131 {
132  out_be32(base_address + XHI_SIZE_REG_OFFSET, data);
133 }
134 
143 static inline void buffer_icap_set_offset(void __iomem *base_address,
144  u32 data)
145 {
146  out_be32(base_address + XHI_BRAM_OFFSET_REG_OFFSET, data);
147 }
148 
159 static inline void buffer_icap_set_rnc(void __iomem *base_address,
160  u32 data)
161 {
162  out_be32(base_address + XHI_RNC_REG_OFFSET, data);
163 }
164 
174 static inline void buffer_icap_set_bram(void __iomem *base_address,
175  u32 offset, u32 data)
176 {
177  out_be32(base_address + (offset << 2), data);
178 }
179 
187 static int buffer_icap_device_read(struct hwicap_drvdata *drvdata,
188  u32 offset, u32 count)
189 {
190 
191  s32 retries = 0;
192  void __iomem *base_address = drvdata->base_address;
193 
194  if (buffer_icap_busy(base_address))
195  return -EBUSY;
196 
197  if ((offset + count) > XHI_MAX_BUFFER_INTS)
198  return -EINVAL;
199 
200  /* setSize count*4 to get bytes. */
201  buffer_icap_set_size(base_address, (count << 2));
202  buffer_icap_set_offset(base_address, offset);
203  buffer_icap_set_rnc(base_address, XHI_READBACK);
204 
205  while (buffer_icap_busy(base_address)) {
206  retries++;
207  if (retries > XHI_MAX_RETRIES)
208  return -EBUSY;
209  }
210  return 0;
211 
212 };
213 
221 static int buffer_icap_device_write(struct hwicap_drvdata *drvdata,
222  u32 offset, u32 count)
223 {
224 
225  s32 retries = 0;
226  void __iomem *base_address = drvdata->base_address;
227 
228  if (buffer_icap_busy(base_address))
229  return -EBUSY;
230 
231  if ((offset + count) > XHI_MAX_BUFFER_INTS)
232  return -EINVAL;
233 
234  /* setSize count*4 to get bytes. */
235  buffer_icap_set_size(base_address, count << 2);
236  buffer_icap_set_offset(base_address, offset);
237  buffer_icap_set_rnc(base_address, XHI_CONFIGURE);
238 
239  while (buffer_icap_busy(base_address)) {
240  retries++;
241  if (retries > XHI_MAX_RETRIES)
242  return -EBUSY;
243  }
244  return 0;
245 
246 };
247 
256 void buffer_icap_reset(struct hwicap_drvdata *drvdata)
257 {
258  out_be32(drvdata->base_address + XHI_STATUS_REG_OFFSET, 0xFEFE);
259 }
260 
268  u32 size)
269 {
270  int status;
271  s32 buffer_count = 0;
272  s32 num_writes = 0;
273  bool dirty = 0;
274  u32 i;
275  void __iomem *base_address = drvdata->base_address;
276 
277  /* Loop through all the data */
278  for (i = 0, buffer_count = 0; i < size; i++) {
279 
280  /* Copy data to bram */
281  buffer_icap_set_bram(base_address, buffer_count, data[i]);
282  dirty = 1;
283 
284  if (buffer_count < XHI_MAX_BUFFER_INTS - 1) {
285  buffer_count++;
286  continue;
287  }
288 
289  /* Write data to ICAP */
290  status = buffer_icap_device_write(
291  drvdata,
294  if (status != 0) {
295  /* abort. */
296  buffer_icap_reset(drvdata);
297  return status;
298  }
299 
300  buffer_count = 0;
301  num_writes++;
302  dirty = 0;
303  }
304 
305  /* Write unwritten data to ICAP */
306  if (dirty) {
307  /* Write data to ICAP */
308  status = buffer_icap_device_write(drvdata, XHI_BUFFER_START,
309  buffer_count);
310  if (status != 0) {
311  /* abort. */
312  buffer_icap_reset(drvdata);
313  }
314  return status;
315  }
316 
317  return 0;
318 };
319 
327  u32 size)
328 {
329  int status;
330  s32 buffer_count = 0;
331  s32 read_count = 0;
332  u32 i;
333  void __iomem *base_address = drvdata->base_address;
334 
335  /* Loop through all the data */
336  for (i = 0, buffer_count = XHI_MAX_BUFFER_INTS; i < size; i++) {
337  if (buffer_count == XHI_MAX_BUFFER_INTS) {
338  u32 words_remaining = size - i;
339  u32 words_to_read =
340  words_remaining <
341  XHI_MAX_BUFFER_INTS ? words_remaining :
343 
344  /* Read data from ICAP */
345  status = buffer_icap_device_read(
346  drvdata,
348  words_to_read);
349  if (status != 0) {
350  /* abort. */
351  buffer_icap_reset(drvdata);
352  return status;
353  }
354 
355  buffer_count = 0;
356  read_count++;
357  }
358 
359  /* Copy data from bram */
360  data[i] = buffer_icap_get_bram(base_address, buffer_count);
361  buffer_count++;
362  }
363 
364  return 0;
365 };