diff options
Diffstat (limited to 'drivers/char/xilinx_hwicap/fifo_icap.c')
-rw-r--r-- | drivers/char/xilinx_hwicap/fifo_icap.c | 381 |
1 files changed, 381 insertions, 0 deletions
diff --git a/drivers/char/xilinx_hwicap/fifo_icap.c b/drivers/char/xilinx_hwicap/fifo_icap.c new file mode 100644 index 000000000000..0988314694a6 --- /dev/null +++ b/drivers/char/xilinx_hwicap/fifo_icap.c | |||
@@ -0,0 +1,381 @@ | |||
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 2007-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 "fifo_icap.h" | ||
37 | |||
38 | /* Register offsets for the XHwIcap device. */ | ||
39 | #define XHI_GIER_OFFSET 0x1C /* Device Global Interrupt Enable Reg */ | ||
40 | #define XHI_IPISR_OFFSET 0x20 /* Interrupt Status Register */ | ||
41 | #define XHI_IPIER_OFFSET 0x28 /* Interrupt Enable Register */ | ||
42 | #define XHI_WF_OFFSET 0x100 /* Write FIFO */ | ||
43 | #define XHI_RF_OFFSET 0x104 /* Read FIFO */ | ||
44 | #define XHI_SZ_OFFSET 0x108 /* Size Register */ | ||
45 | #define XHI_CR_OFFSET 0x10C /* Control Register */ | ||
46 | #define XHI_SR_OFFSET 0x110 /* Status Register */ | ||
47 | #define XHI_WFV_OFFSET 0x114 /* Write FIFO Vacancy Register */ | ||
48 | #define XHI_RFO_OFFSET 0x118 /* Read FIFO Occupancy Register */ | ||
49 | |||
50 | /* Device Global Interrupt Enable Register (GIER) bit definitions */ | ||
51 | |||
52 | #define XHI_GIER_GIE_MASK 0x80000000 /* Global Interrupt enable Mask */ | ||
53 | |||
54 | /** | ||
55 | * HwIcap Device Interrupt Status/Enable Registers | ||
56 | * | ||
57 | * Interrupt Status Register (IPISR) : This register holds the | ||
58 | * interrupt status flags for the device. These bits are toggle on | ||
59 | * write. | ||
60 | * | ||
61 | * Interrupt Enable Register (IPIER) : This register is used to enable | ||
62 | * interrupt sources for the device. | ||
63 | * Writing a '1' to a bit enables the corresponding interrupt. | ||
64 | * Writing a '0' to a bit disables the corresponding interrupt. | ||
65 | * | ||
66 | * IPISR/IPIER registers have the same bit definitions and are only defined | ||
67 | * once. | ||
68 | */ | ||
69 | #define XHI_IPIXR_RFULL_MASK 0x00000008 /* Read FIFO Full */ | ||
70 | #define XHI_IPIXR_WEMPTY_MASK 0x00000004 /* Write FIFO Empty */ | ||
71 | #define XHI_IPIXR_RDP_MASK 0x00000002 /* Read FIFO half full */ | ||
72 | #define XHI_IPIXR_WRP_MASK 0x00000001 /* Write FIFO half full */ | ||
73 | #define XHI_IPIXR_ALL_MASK 0x0000000F /* Mask of all interrupts */ | ||
74 | |||
75 | /* Control Register (CR) */ | ||
76 | #define XHI_CR_SW_RESET_MASK 0x00000008 /* SW Reset Mask */ | ||
77 | #define XHI_CR_FIFO_CLR_MASK 0x00000004 /* FIFO Clear Mask */ | ||
78 | #define XHI_CR_READ_MASK 0x00000002 /* Read from ICAP to FIFO */ | ||
79 | #define XHI_CR_WRITE_MASK 0x00000001 /* Write from FIFO to ICAP */ | ||
80 | |||
81 | /* Status Register (SR) */ | ||
82 | #define XHI_SR_CFGERR_N_MASK 0x00000100 /* Config Error Mask */ | ||
83 | #define XHI_SR_DALIGN_MASK 0x00000080 /* Data Alignment Mask */ | ||
84 | #define XHI_SR_RIP_MASK 0x00000040 /* Read back Mask */ | ||
85 | #define XHI_SR_IN_ABORT_N_MASK 0x00000020 /* Select Map Abort Mask */ | ||
86 | #define XHI_SR_DONE_MASK 0x00000001 /* Done bit Mask */ | ||
87 | |||
88 | |||
89 | #define XHI_WFO_MAX_VACANCY 1024 /* Max Write FIFO Vacancy, in words */ | ||
90 | #define XHI_RFO_MAX_OCCUPANCY 256 /* Max Read FIFO Occupancy, in words */ | ||
91 | /* The maximum amount we can request from fifo_icap_get_configuration | ||
92 | at once, in bytes. */ | ||
93 | #define XHI_MAX_READ_TRANSACTION_WORDS 0xFFF | ||
94 | |||
95 | |||
96 | /** | ||
97 | * fifo_icap_fifo_write: Write data to the write FIFO. | ||
98 | * @parameter drvdata: a pointer to the drvdata. | ||
99 | * @parameter data: the 32-bit value to be written to the FIFO. | ||
100 | * | ||
101 | * This function will silently fail if the fifo is full. | ||
102 | **/ | ||
103 | static inline void fifo_icap_fifo_write(struct hwicap_drvdata *drvdata, | ||
104 | u32 data) | ||
105 | { | ||
106 | dev_dbg(drvdata->dev, "fifo_write: %x\n", data); | ||
107 | out_be32(drvdata->base_address + XHI_WF_OFFSET, data); | ||
108 | } | ||
109 | |||
110 | /** | ||
111 | * fifo_icap_fifo_read: Read data from the Read FIFO. | ||
112 | * @parameter drvdata: a pointer to the drvdata. | ||
113 | * | ||
114 | * This function will silently fail if the fifo is empty. | ||
115 | **/ | ||
116 | static inline u32 fifo_icap_fifo_read(struct hwicap_drvdata *drvdata) | ||
117 | { | ||
118 | u32 data = in_be32(drvdata->base_address + XHI_RF_OFFSET); | ||
119 | dev_dbg(drvdata->dev, "fifo_read: %x\n", data); | ||
120 | return data; | ||
121 | } | ||
122 | |||
123 | /** | ||
124 | * fifo_icap_set_read_size: Set the the size register. | ||
125 | * @parameter drvdata: a pointer to the drvdata. | ||
126 | * @parameter data: the size of the following read transaction, in words. | ||
127 | **/ | ||
128 | static inline void fifo_icap_set_read_size(struct hwicap_drvdata *drvdata, | ||
129 | u32 data) | ||
130 | { | ||
131 | out_be32(drvdata->base_address + XHI_SZ_OFFSET, data); | ||
132 | } | ||
133 | |||
134 | /** | ||
135 | * fifo_icap_start_config: Initiate a configuration (write) to the device. | ||
136 | * @parameter drvdata: a pointer to the drvdata. | ||
137 | **/ | ||
138 | static inline void fifo_icap_start_config(struct hwicap_drvdata *drvdata) | ||
139 | { | ||
140 | out_be32(drvdata->base_address + XHI_CR_OFFSET, XHI_CR_WRITE_MASK); | ||
141 | dev_dbg(drvdata->dev, "configuration started\n"); | ||
142 | } | ||
143 | |||
144 | /** | ||
145 | * fifo_icap_start_readback: Initiate a readback from the device. | ||
146 | * @parameter drvdata: a pointer to the drvdata. | ||
147 | **/ | ||
148 | static inline void fifo_icap_start_readback(struct hwicap_drvdata *drvdata) | ||
149 | { | ||
150 | out_be32(drvdata->base_address + XHI_CR_OFFSET, XHI_CR_READ_MASK); | ||
151 | dev_dbg(drvdata->dev, "readback started\n"); | ||
152 | } | ||
153 | |||
154 | /** | ||
155 | * fifo_icap_busy: Return true if the ICAP is still processing a transaction. | ||
156 | * @parameter drvdata: a pointer to the drvdata. | ||
157 | **/ | ||
158 | static inline u32 fifo_icap_busy(struct hwicap_drvdata *drvdata) | ||
159 | { | ||
160 | u32 status = in_be32(drvdata->base_address + XHI_SR_OFFSET); | ||
161 | dev_dbg(drvdata->dev, "Getting status = %x\n", status); | ||
162 | return (status & XHI_SR_DONE_MASK) ? 0 : 1; | ||
163 | } | ||
164 | |||
165 | /** | ||
166 | * fifo_icap_write_fifo_vacancy: Query the write fifo available space. | ||
167 | * @parameter drvdata: a pointer to the drvdata. | ||
168 | * | ||
169 | * Return the number of words that can be safely pushed into the write fifo. | ||
170 | **/ | ||
171 | static inline u32 fifo_icap_write_fifo_vacancy( | ||
172 | struct hwicap_drvdata *drvdata) | ||
173 | { | ||
174 | return in_be32(drvdata->base_address + XHI_WFV_OFFSET); | ||
175 | } | ||
176 | |||
177 | /** | ||
178 | * fifo_icap_read_fifo_occupancy: Query the read fifo available data. | ||
179 | * @parameter drvdata: a pointer to the drvdata. | ||
180 | * | ||
181 | * Return the number of words that can be safely read from the read fifo. | ||
182 | **/ | ||
183 | static inline u32 fifo_icap_read_fifo_occupancy( | ||
184 | struct hwicap_drvdata *drvdata) | ||
185 | { | ||
186 | return in_be32(drvdata->base_address + XHI_RFO_OFFSET); | ||
187 | } | ||
188 | |||
189 | /** | ||
190 | * fifo_icap_set_configuration: Send configuration data to the ICAP. | ||
191 | * @parameter drvdata: a pointer to the drvdata. | ||
192 | * @parameter frame_buffer: a pointer to the data to be written to the | ||
193 | * ICAP device. | ||
194 | * @parameter num_words: the number of words (32 bit) to write to the ICAP | ||
195 | * device. | ||
196 | |||
197 | * This function writes the given user data to the Write FIFO in | ||
198 | * polled mode and starts the transfer of the data to | ||
199 | * the ICAP device. | ||
200 | **/ | ||
201 | int fifo_icap_set_configuration(struct hwicap_drvdata *drvdata, | ||
202 | u32 *frame_buffer, u32 num_words) | ||
203 | { | ||
204 | |||
205 | u32 write_fifo_vacancy = 0; | ||
206 | u32 retries = 0; | ||
207 | u32 remaining_words; | ||
208 | |||
209 | dev_dbg(drvdata->dev, "fifo_set_configuration\n"); | ||
210 | |||
211 | /* | ||
212 | * Check if the ICAP device is Busy with the last Read/Write | ||
213 | */ | ||
214 | if (fifo_icap_busy(drvdata)) | ||
215 | return -EBUSY; | ||
216 | |||
217 | /* | ||
218 | * Set up the buffer pointer and the words to be transferred. | ||
219 | */ | ||
220 | remaining_words = num_words; | ||
221 | |||
222 | while (remaining_words > 0) { | ||
223 | /* | ||
224 | * Wait until we have some data in the fifo. | ||
225 | */ | ||
226 | while (write_fifo_vacancy == 0) { | ||
227 | write_fifo_vacancy = | ||
228 | fifo_icap_write_fifo_vacancy(drvdata); | ||
229 | retries++; | ||
230 | if (retries > XHI_MAX_RETRIES) | ||
231 | return -EIO; | ||
232 | } | ||
233 | |||
234 | /* | ||
235 | * Write data into the Write FIFO. | ||
236 | */ | ||
237 | while ((write_fifo_vacancy != 0) && | ||
238 | (remaining_words > 0)) { | ||
239 | fifo_icap_fifo_write(drvdata, *frame_buffer); | ||
240 | |||
241 | remaining_words--; | ||
242 | write_fifo_vacancy--; | ||
243 | frame_buffer++; | ||
244 | } | ||
245 | /* Start pushing whatever is in the FIFO into the ICAP. */ | ||
246 | fifo_icap_start_config(drvdata); | ||
247 | } | ||
248 | |||
249 | /* Wait until the write has finished. */ | ||
250 | while (fifo_icap_busy(drvdata)) { | ||
251 | retries++; | ||
252 | if (retries > XHI_MAX_RETRIES) | ||
253 | break; | ||
254 | } | ||
255 | |||
256 | dev_dbg(drvdata->dev, "done fifo_set_configuration\n"); | ||
257 | |||
258 | /* | ||
259 | * If the requested number of words have not been read from | ||
260 | * the device then indicate failure. | ||
261 | */ | ||
262 | if (remaining_words != 0) | ||
263 | return -EIO; | ||
264 | |||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | /** | ||
269 | * fifo_icap_get_configuration: Read configuration data from the device. | ||
270 | * @parameter drvdata: a pointer to the drvdata. | ||
271 | * @parameter data: Address of the data representing the partial bitstream | ||
272 | * @parameter size: the size of the partial bitstream in 32 bit words. | ||
273 | * | ||
274 | * This function reads the specified number of words from the ICAP device in | ||
275 | * the polled mode. | ||
276 | */ | ||
277 | int fifo_icap_get_configuration(struct hwicap_drvdata *drvdata, | ||
278 | u32 *frame_buffer, u32 num_words) | ||
279 | { | ||
280 | |||
281 | u32 read_fifo_occupancy = 0; | ||
282 | u32 retries = 0; | ||
283 | u32 *data = frame_buffer; | ||
284 | u32 remaining_words; | ||
285 | u32 words_to_read; | ||
286 | |||
287 | dev_dbg(drvdata->dev, "fifo_get_configuration\n"); | ||
288 | |||
289 | /* | ||
290 | * Check if the ICAP device is Busy with the last Write/Read | ||
291 | */ | ||
292 | if (fifo_icap_busy(drvdata)) | ||
293 | return -EBUSY; | ||
294 | |||
295 | remaining_words = num_words; | ||
296 | |||
297 | while (remaining_words > 0) { | ||
298 | words_to_read = remaining_words; | ||
299 | /* The hardware has a limit on the number of words | ||
300 | that can be read at one time. */ | ||
301 | if (words_to_read > XHI_MAX_READ_TRANSACTION_WORDS) | ||
302 | words_to_read = XHI_MAX_READ_TRANSACTION_WORDS; | ||
303 | |||
304 | remaining_words -= words_to_read; | ||
305 | |||
306 | fifo_icap_set_read_size(drvdata, words_to_read); | ||
307 | fifo_icap_start_readback(drvdata); | ||
308 | |||
309 | while (words_to_read > 0) { | ||
310 | /* Wait until we have some data in the fifo. */ | ||
311 | while (read_fifo_occupancy == 0) { | ||
312 | read_fifo_occupancy = | ||
313 | fifo_icap_read_fifo_occupancy(drvdata); | ||
314 | retries++; | ||
315 | if (retries > XHI_MAX_RETRIES) | ||
316 | return -EIO; | ||
317 | } | ||
318 | |||
319 | if (read_fifo_occupancy > words_to_read) | ||
320 | read_fifo_occupancy = words_to_read; | ||
321 | |||
322 | words_to_read -= read_fifo_occupancy; | ||
323 | |||
324 | /* Read the data from the Read FIFO. */ | ||
325 | while (read_fifo_occupancy != 0) { | ||
326 | *data++ = fifo_icap_fifo_read(drvdata); | ||
327 | read_fifo_occupancy--; | ||
328 | } | ||
329 | } | ||
330 | } | ||
331 | |||
332 | dev_dbg(drvdata->dev, "done fifo_get_configuration\n"); | ||
333 | |||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | /** | ||
338 | * buffer_icap_reset: Reset the logic of the icap device. | ||
339 | * @parameter drvdata: a pointer to the drvdata. | ||
340 | * | ||
341 | * This function forces the software reset of the complete HWICAP device. | ||
342 | * All the registers will return to the default value and the FIFO is also | ||
343 | * flushed as a part of this software reset. | ||
344 | */ | ||
345 | void fifo_icap_reset(struct hwicap_drvdata *drvdata) | ||
346 | { | ||
347 | u32 reg_data; | ||
348 | /* | ||
349 | * Reset the device by setting/clearing the RESET bit in the | ||
350 | * Control Register. | ||
351 | */ | ||
352 | reg_data = in_be32(drvdata->base_address + XHI_CR_OFFSET); | ||
353 | |||
354 | out_be32(drvdata->base_address + XHI_CR_OFFSET, | ||
355 | reg_data | XHI_CR_SW_RESET_MASK); | ||
356 | |||
357 | out_be32(drvdata->base_address + XHI_CR_OFFSET, | ||
358 | reg_data & (~XHI_CR_SW_RESET_MASK)); | ||
359 | |||
360 | } | ||
361 | |||
362 | /** | ||
363 | * fifo_icap_flush_fifo: This function flushes the FIFOs in the device. | ||
364 | * @parameter drvdata: a pointer to the drvdata. | ||
365 | */ | ||
366 | void fifo_icap_flush_fifo(struct hwicap_drvdata *drvdata) | ||
367 | { | ||
368 | u32 reg_data; | ||
369 | /* | ||
370 | * Flush the FIFO by setting/clearing the FIFO Clear bit in the | ||
371 | * Control Register. | ||
372 | */ | ||
373 | reg_data = in_be32(drvdata->base_address + XHI_CR_OFFSET); | ||
374 | |||
375 | out_be32(drvdata->base_address + XHI_CR_OFFSET, | ||
376 | reg_data | XHI_CR_FIFO_CLR_MASK); | ||
377 | |||
378 | out_be32(drvdata->base_address + XHI_CR_OFFSET, | ||
379 | reg_data & (~XHI_CR_FIFO_CLR_MASK)); | ||
380 | } | ||
381 | |||