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 | |
72 | /** |
73 | * buffer_icap_get_status - Get the contents of the status register. |
74 | * @drvdata: a pointer to the drvdata. |
75 | * |
76 | * The status register contains the ICAP status and the done bit. |
77 | * |
78 | * D8 - cfgerr |
79 | * D7 - dalign |
80 | * D6 - rip |
81 | * D5 - in_abort_l |
82 | * D4 - Always 1 |
83 | * D3 - Always 1 |
84 | * D2 - Always 1 |
85 | * D1 - Always 1 |
86 | * D0 - Done bit |
87 | **/ |
88 | u32 buffer_icap_get_status(struct hwicap_drvdata *drvdata) |
89 | { |
90 | return in_be32(drvdata->base_address + XHI_STATUS_REG_OFFSET); |
91 | } |
92 | |
93 | /** |
94 | * buffer_icap_get_bram - Reads data from the storage buffer bram. |
95 | * @base_address: contains the base address of the component. |
96 | * @offset: The word offset from which the data should be read. |
97 | * |
98 | * A bram is used as a configuration memory cache. One frame of data can |
99 | * be stored in this "storage buffer". |
100 | **/ |
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 | |
107 | /** |
108 | * buffer_icap_busy - Return true if the icap device is busy |
109 | * @base_address: is the base address of the device |
110 | * |
111 | * The queries the low order bit of the status register, which |
112 | * indicates whether the current configuration or readback operation |
113 | * has completed. |
114 | **/ |
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 | |
121 | /** |
122 | * buffer_icap_set_size - Set the size register. |
123 | * @base_address: is the base address of the device |
124 | * @data: The size in bytes. |
125 | * |
126 | * The size register holds the number of 8 bit bytes to transfer between |
127 | * bram and the icap (or icap to bram). |
128 | **/ |
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 | |
135 | /** |
136 | * buffer_icap_set_offset - Set the bram offset register. |
137 | * @base_address: contains the base address of the device. |
138 | * @data: is the value to be written to the data register. |
139 | * |
140 | * The bram offset register holds the starting bram address to transfer |
141 | * data from during configuration or write data to during readback. |
142 | **/ |
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 | |
149 | /** |
150 | * buffer_icap_set_rnc - Set the RNC (Readback not Configure) register. |
151 | * @base_address: contains the base address of the device. |
152 | * @data: is the value to be written to the data register. |
153 | * |
154 | * The RNC register determines the direction of the data transfer. It |
155 | * controls whether a configuration or readback take place. Writing to |
156 | * this register initiates the transfer. A value of 1 initiates a |
157 | * readback while writing a value of 0 initiates a configuration. |
158 | **/ |
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 | |
165 | /** |
166 | * buffer_icap_set_bram - Write data to the storage buffer bram. |
167 | * @base_address: contains the base address of the component. |
168 | * @offset: The word offset at which the data should be written. |
169 | * @data: The value to be written to the bram offset. |
170 | * |
171 | * A bram is used as a configuration memory cache. One frame of data can |
172 | * be stored in this "storage buffer". |
173 | **/ |
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 | |
180 | /** |
181 | * buffer_icap_device_read - Transfer bytes from ICAP to the storage buffer. |
182 | * @drvdata: a pointer to the drvdata. |
183 | * @offset: The storage buffer start address. |
184 | * @count: The number of words (32 bit) to read from the |
185 | * device (ICAP). |
186 | **/ |
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, data: (count << 2)); |
202 | buffer_icap_set_offset(base_address, data: 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 | |
214 | /** |
215 | * buffer_icap_device_write - Transfer bytes from ICAP to the storage buffer. |
216 | * @drvdata: a pointer to the drvdata. |
217 | * @offset: The storage buffer start address. |
218 | * @count: The number of words (32 bit) to read from the |
219 | * device (ICAP). |
220 | **/ |
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, data: count << 2); |
236 | buffer_icap_set_offset(base_address, data: 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 | |
248 | /** |
249 | * buffer_icap_reset - Reset the logic of the icap device. |
250 | * @drvdata: a pointer to the drvdata. |
251 | * |
252 | * Writing to the status register resets the ICAP logic in an internal |
253 | * version of the core. For the version of the core published in EDK, |
254 | * this is a noop. |
255 | **/ |
256 | void buffer_icap_reset(struct hwicap_drvdata *drvdata) |
257 | { |
258 | out_be32(drvdata->base_address + XHI_STATUS_REG_OFFSET, 0xFEFE); |
259 | } |
260 | |
261 | /** |
262 | * buffer_icap_set_configuration - Load a partial bitstream from system memory. |
263 | * @drvdata: a pointer to the drvdata. |
264 | * @data: Kernel address of the partial bitstream. |
265 | * @size: the size of the partial bitstream in 32 bit words. |
266 | **/ |
267 | int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data, |
268 | u32 size) |
269 | { |
270 | int status; |
271 | s32 buffer_count = 0; |
272 | bool dirty = false; |
273 | u32 i; |
274 | void __iomem *base_address = drvdata->base_address; |
275 | |
276 | /* Loop through all the data */ |
277 | for (i = 0, buffer_count = 0; i < size; i++) { |
278 | |
279 | /* Copy data to bram */ |
280 | buffer_icap_set_bram(base_address, offset: buffer_count, data: data[i]); |
281 | dirty = true; |
282 | |
283 | if (buffer_count < XHI_MAX_BUFFER_INTS - 1) { |
284 | buffer_count++; |
285 | continue; |
286 | } |
287 | |
288 | /* Write data to ICAP */ |
289 | status = buffer_icap_device_write( |
290 | drvdata, |
291 | XHI_BUFFER_START, |
292 | XHI_MAX_BUFFER_INTS); |
293 | if (status != 0) { |
294 | /* abort. */ |
295 | buffer_icap_reset(drvdata); |
296 | return status; |
297 | } |
298 | |
299 | buffer_count = 0; |
300 | dirty = false; |
301 | } |
302 | |
303 | /* Write unwritten data to ICAP */ |
304 | if (dirty) { |
305 | /* Write data to ICAP */ |
306 | status = buffer_icap_device_write(drvdata, XHI_BUFFER_START, |
307 | count: buffer_count); |
308 | if (status != 0) { |
309 | /* abort. */ |
310 | buffer_icap_reset(drvdata); |
311 | } |
312 | return status; |
313 | } |
314 | |
315 | return 0; |
316 | }; |
317 | |
318 | /** |
319 | * buffer_icap_get_configuration - Read configuration data from the device. |
320 | * @drvdata: a pointer to the drvdata. |
321 | * @data: Address of the data representing the partial bitstream |
322 | * @size: the size of the partial bitstream in 32 bit words. |
323 | **/ |
324 | int buffer_icap_get_configuration(struct hwicap_drvdata *drvdata, u32 *data, |
325 | u32 size) |
326 | { |
327 | int status; |
328 | s32 buffer_count = 0; |
329 | u32 i; |
330 | void __iomem *base_address = drvdata->base_address; |
331 | |
332 | /* Loop through all the data */ |
333 | for (i = 0, buffer_count = XHI_MAX_BUFFER_INTS; i < size; i++) { |
334 | if (buffer_count == XHI_MAX_BUFFER_INTS) { |
335 | u32 words_remaining = size - i; |
336 | u32 words_to_read = |
337 | words_remaining < |
338 | XHI_MAX_BUFFER_INTS ? words_remaining : |
339 | XHI_MAX_BUFFER_INTS; |
340 | |
341 | /* Read data from ICAP */ |
342 | status = buffer_icap_device_read( |
343 | drvdata, |
344 | XHI_BUFFER_START, |
345 | count: words_to_read); |
346 | if (status != 0) { |
347 | /* abort. */ |
348 | buffer_icap_reset(drvdata); |
349 | return status; |
350 | } |
351 | |
352 | buffer_count = 0; |
353 | } |
354 | |
355 | /* Copy data from bram */ |
356 | data[i] = buffer_icap_get_bram(base_address, offset: buffer_count); |
357 | buffer_count++; |
358 | } |
359 | |
360 | return 0; |
361 | }; |
362 | |