]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
5d3207da WD |
2 | /* |
3 | * (C) Copyright 2002 | |
4 | * Rich Ireland, Enterasys Networks, [email protected]. | |
5 | * Keith Outwater, [email protected] | |
5d3207da WD |
6 | */ |
7 | ||
8 | /* | |
9 | * Configuration support for Xilinx Virtex2 devices. Based | |
10 | * on spartan2.c (Rich Ireland, [email protected]). | |
11 | */ | |
12 | ||
13 | #include <common.h> | |
24b852a7 | 14 | #include <console.h> |
5d3207da WD |
15 | #include <virtex2.h> |
16 | ||
9a9200b4 WD |
17 | #if 0 |
18 | #define FPGA_DEBUG | |
265817c7 | 19 | #endif |
9a9200b4 | 20 | |
5d3207da WD |
21 | #ifdef FPGA_DEBUG |
22 | #define PRINTF(fmt,args...) printf (fmt ,##args) | |
23 | #else | |
24 | #define PRINTF(fmt,args...) | |
25 | #endif | |
26 | ||
27 | /* | |
28 | * If the SelectMap interface can be overrun by the processor, define | |
6d0f6bcf | 29 | * CONFIG_SYS_FPGA_CHECK_BUSY and/or CONFIG_FPGA_DELAY in the board configuration |
5d3207da WD |
30 | * file and add board-specific support for checking BUSY status. By default, |
31 | * assume that the SelectMap interface cannot be overrun. | |
32 | */ | |
6d0f6bcf JCPV |
33 | #ifndef CONFIG_SYS_FPGA_CHECK_BUSY |
34 | #undef CONFIG_SYS_FPGA_CHECK_BUSY | |
5d3207da WD |
35 | #endif |
36 | ||
37 | #ifndef CONFIG_FPGA_DELAY | |
38 | #define CONFIG_FPGA_DELAY() | |
39 | #endif | |
40 | ||
6d0f6bcf JCPV |
41 | #ifndef CONFIG_SYS_FPGA_PROG_FEEDBACK |
42 | #define CONFIG_SYS_FPGA_PROG_FEEDBACK | |
5d3207da WD |
43 | #endif |
44 | ||
45 | /* | |
46 | * Don't allow config cycle to be interrupted | |
47 | */ | |
6d0f6bcf JCPV |
48 | #ifndef CONFIG_SYS_FPGA_CHECK_CTRLC |
49 | #undef CONFIG_SYS_FPGA_CHECK_CTRLC | |
5d3207da WD |
50 | #endif |
51 | ||
52 | /* | |
53 | * Check for errors during configuration by default | |
54 | */ | |
6d0f6bcf JCPV |
55 | #ifndef CONFIG_SYS_FPGA_CHECK_ERROR |
56 | #define CONFIG_SYS_FPGA_CHECK_ERROR | |
5d3207da WD |
57 | #endif |
58 | ||
59 | /* | |
60 | * The default timeout in mS for INIT_B to deassert after PROG_B has | |
61 | * been deasserted. Per the latest Virtex II Handbook (page 347), the | |
62 | * max time from PORG_B deassertion to INIT_B deassertion is 4uS per | |
63 | * data frame for the XC2V8000. The XC2V8000 has 2860 data frames | |
64 | * which yields 11.44 mS. So let's make it bigger in order to handle | |
65 | * an XC2V1000, if anyone can ever get ahold of one. | |
66 | */ | |
6d0f6bcf JCPV |
67 | #ifndef CONFIG_SYS_FPGA_WAIT_INIT |
68 | #define CONFIG_SYS_FPGA_WAIT_INIT CONFIG_SYS_HZ/2 /* 500 ms */ | |
5d3207da WD |
69 | #endif |
70 | ||
71 | /* | |
72 | * The default timeout for waiting for BUSY to deassert during configuration. | |
73 | * This is normally not necessary since for most reasonable configuration | |
74 | * clock frequencies (i.e. 66 MHz or less), BUSY monitoring is unnecessary. | |
75 | */ | |
6d0f6bcf JCPV |
76 | #ifndef CONFIG_SYS_FPGA_WAIT_BUSY |
77 | #define CONFIG_SYS_FPGA_WAIT_BUSY CONFIG_SYS_HZ/200 /* 5 ms*/ | |
5d3207da WD |
78 | #endif |
79 | ||
80 | /* Default timeout for waiting for FPGA to enter operational mode after | |
81 | * configuration data has been written. | |
82 | */ | |
6d0f6bcf JCPV |
83 | #ifndef CONFIG_SYS_FPGA_WAIT_CONFIG |
84 | #define CONFIG_SYS_FPGA_WAIT_CONFIG CONFIG_SYS_HZ/5 /* 200 ms */ | |
5d3207da WD |
85 | #endif |
86 | ||
f8c1be98 MS |
87 | static int virtex2_ssm_load(xilinx_desc *desc, const void *buf, size_t bsize); |
88 | static int virtex2_ssm_dump(xilinx_desc *desc, const void *buf, size_t bsize); | |
5d3207da | 89 | |
f8c1be98 MS |
90 | static int virtex2_ss_load(xilinx_desc *desc, const void *buf, size_t bsize); |
91 | static int virtex2_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize); | |
5d3207da | 92 | |
7a78bd26 MS |
93 | static int virtex2_load(xilinx_desc *desc, const void *buf, size_t bsize, |
94 | bitstream_type bstype) | |
5d3207da WD |
95 | { |
96 | int ret_val = FPGA_FAIL; | |
97 | ||
98 | switch (desc->iface) { | |
99 | case slave_serial: | |
100 | PRINTF ("%s: Launching Slave Serial Load\n", __FUNCTION__); | |
d9071ce0 | 101 | ret_val = virtex2_ss_load(desc, buf, bsize); |
5d3207da WD |
102 | break; |
103 | ||
104 | case slave_selectmap: | |
105 | PRINTF ("%s: Launching Slave Parallel Load\n", __FUNCTION__); | |
d9071ce0 | 106 | ret_val = virtex2_ssm_load(desc, buf, bsize); |
5d3207da WD |
107 | break; |
108 | ||
109 | default: | |
110 | printf ("%s: Unsupported interface type, %d\n", | |
111 | __FUNCTION__, desc->iface); | |
112 | } | |
113 | return ret_val; | |
114 | } | |
115 | ||
14cfc4f3 | 116 | static int virtex2_dump(xilinx_desc *desc, const void *buf, size_t bsize) |
5d3207da WD |
117 | { |
118 | int ret_val = FPGA_FAIL; | |
119 | ||
120 | switch (desc->iface) { | |
121 | case slave_serial: | |
122 | PRINTF ("%s: Launching Slave Serial Dump\n", __FUNCTION__); | |
d9071ce0 | 123 | ret_val = virtex2_ss_dump(desc, buf, bsize); |
5d3207da WD |
124 | break; |
125 | ||
126 | case slave_parallel: | |
127 | PRINTF ("%s: Launching Slave Parallel Dump\n", __FUNCTION__); | |
d9071ce0 | 128 | ret_val = virtex2_ssm_dump(desc, buf, bsize); |
5d3207da WD |
129 | break; |
130 | ||
131 | default: | |
132 | printf ("%s: Unsupported interface type, %d\n", | |
133 | __FUNCTION__, desc->iface); | |
134 | } | |
135 | return ret_val; | |
136 | } | |
137 | ||
14cfc4f3 | 138 | static int virtex2_info(xilinx_desc *desc) |
5d3207da WD |
139 | { |
140 | return FPGA_SUCCESS; | |
141 | } | |
142 | ||
5d3207da WD |
143 | /* |
144 | * Virtex-II Slave SelectMap configuration loader. Configuration via | |
145 | * SelectMap is as follows: | |
146 | * 1. Set the FPGA's PROG_B line low. | |
147 | * 2. Set the FPGA's PROG_B line high. Wait for INIT_B to go high. | |
148 | * 3. Write data to the SelectMap port. If INIT_B goes low at any time | |
149 | * this process, a configuration error (most likely CRC failure) has | |
150 | * ocurred. At this point a status word may be read from the | |
151 | * SelectMap interface to determine the source of the problem (You | |
9a9200b4 | 152 | * could, for instance, put this in your 'abort' function handler). |
5d3207da WD |
153 | * 4. After all data has been written, test the state of the FPGA |
154 | * INIT_B and DONE lines. If both are high, configuration has | |
155 | * succeeded. Congratulations! | |
156 | */ | |
f8c1be98 | 157 | static int virtex2_ssm_load(xilinx_desc *desc, const void *buf, size_t bsize) |
5d3207da WD |
158 | { |
159 | int ret_val = FPGA_FAIL; | |
d9071ce0 | 160 | xilinx_virtex2_slave_selectmap_fns *fn = desc->iface_fns; |
5d3207da WD |
161 | |
162 | PRINTF ("%s:%d: Start with interface functions @ 0x%p\n", | |
163 | __FUNCTION__, __LINE__, fn); | |
164 | ||
165 | if (fn) { | |
166 | size_t bytecount = 0; | |
167 | unsigned char *data = (unsigned char *) buf; | |
168 | int cookie = desc->cookie; | |
169 | unsigned long ts; | |
170 | ||
171 | /* Gotta split this one up (so the stack won't blow??) */ | |
172 | PRINTF ("%s:%d: Function Table:\n" | |
173 | " base 0x%p\n" | |
174 | " struct 0x%p\n" | |
175 | " pre 0x%p\n" | |
176 | " prog 0x%p\n" | |
177 | " init 0x%p\n" | |
178 | " error 0x%p\n", | |
179 | __FUNCTION__, __LINE__, | |
180 | &fn, fn, fn->pre, fn->pgm, fn->init, fn->err); | |
181 | PRINTF (" clock 0x%p\n" | |
182 | " cs 0x%p\n" | |
183 | " write 0x%p\n" | |
184 | " rdata 0x%p\n" | |
185 | " wdata 0x%p\n" | |
186 | " busy 0x%p\n" | |
187 | " abort 0x%p\n" | |
188 | " post 0x%p\n\n", | |
189 | fn->clk, fn->cs, fn->wr, fn->rdata, fn->wdata, | |
190 | fn->busy, fn->abort, fn->post); | |
191 | ||
6d0f6bcf | 192 | #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK |
5d3207da WD |
193 | printf ("Initializing FPGA Device %d...\n", cookie); |
194 | #endif | |
195 | /* | |
196 | * Run the pre configuration function if there is one. | |
197 | */ | |
198 | if (*fn->pre) { | |
199 | (*fn->pre) (cookie); | |
200 | } | |
201 | ||
202 | /* | |
203 | * Assert the program line. The minimum pulse width for | |
204 | * Virtex II devices is 300 nS (Tprogram parameter in datasheet). | |
205 | * There is no maximum value for the pulse width. Check to make | |
206 | * sure that INIT_B goes low after assertion of PROG_B | |
207 | */ | |
472d5460 | 208 | (*fn->pgm) (true, true, cookie); |
5d3207da WD |
209 | udelay (10); |
210 | ts = get_timer (0); | |
211 | do { | |
6d0f6bcf | 212 | if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT_INIT) { |
9a9200b4 | 213 | printf ("%s:%d: ** Timeout after %d ticks waiting for INIT" |
5d3207da | 214 | " to assert.\n", __FUNCTION__, __LINE__, |
6d0f6bcf | 215 | CONFIG_SYS_FPGA_WAIT_INIT); |
5d3207da WD |
216 | (*fn->abort) (cookie); |
217 | return FPGA_FAIL; | |
218 | } | |
219 | } while (!(*fn->init) (cookie)); | |
220 | ||
472d5460 | 221 | (*fn->pgm) (false, true, cookie); |
5d3207da | 222 | CONFIG_FPGA_DELAY (); |
472d5460 | 223 | (*fn->clk) (true, true, cookie); |
5d3207da WD |
224 | |
225 | /* | |
226 | * Start a timer and wait for INIT_B to go high | |
227 | */ | |
228 | ts = get_timer (0); | |
229 | do { | |
230 | CONFIG_FPGA_DELAY (); | |
6d0f6bcf | 231 | if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT_INIT) { |
9a9200b4 | 232 | printf ("%s:%d: ** Timeout after %d ticks waiting for INIT" |
5d3207da | 233 | " to deassert.\n", __FUNCTION__, __LINE__, |
6d0f6bcf | 234 | CONFIG_SYS_FPGA_WAIT_INIT); |
5d3207da WD |
235 | (*fn->abort) (cookie); |
236 | return FPGA_FAIL; | |
237 | } | |
238 | } while ((*fn->init) (cookie) && (*fn->busy) (cookie)); | |
239 | ||
472d5460 YS |
240 | (*fn->wr) (true, true, cookie); |
241 | (*fn->cs) (true, true, cookie); | |
5d3207da WD |
242 | |
243 | udelay (10000); | |
244 | ||
245 | /* | |
246 | * Load the data byte by byte | |
247 | */ | |
248 | while (bytecount < bsize) { | |
6d0f6bcf | 249 | #ifdef CONFIG_SYS_FPGA_CHECK_CTRLC |
5d3207da WD |
250 | if (ctrlc ()) { |
251 | (*fn->abort) (cookie); | |
252 | return FPGA_FAIL; | |
253 | } | |
254 | #endif | |
9a9200b4 WD |
255 | |
256 | if ((*fn->done) (cookie) == FPGA_SUCCESS) { | |
257 | PRINTF ("%s:%d:done went active early, bytecount = %d\n", | |
258 | __FUNCTION__, __LINE__, bytecount); | |
259 | break; | |
260 | } | |
261 | ||
6d0f6bcf | 262 | #ifdef CONFIG_SYS_FPGA_CHECK_ERROR |
5d3207da | 263 | if ((*fn->init) (cookie)) { |
9a9200b4 | 264 | printf ("\n%s:%d: ** Error: INIT asserted during" |
5d3207da | 265 | " configuration\n", __FUNCTION__, __LINE__); |
9a9200b4 WD |
266 | printf ("%d = buffer offset, %d = buffer size\n", |
267 | bytecount, bsize); | |
5d3207da WD |
268 | (*fn->abort) (cookie); |
269 | return FPGA_FAIL; | |
270 | } | |
271 | #endif | |
9a9200b4 | 272 | |
472d5460 | 273 | (*fn->wdata) (data[bytecount++], true, cookie); |
5d3207da WD |
274 | CONFIG_FPGA_DELAY (); |
275 | ||
276 | /* | |
277 | * Cycle the clock pin | |
278 | */ | |
472d5460 | 279 | (*fn->clk) (false, true, cookie); |
5d3207da | 280 | CONFIG_FPGA_DELAY (); |
472d5460 | 281 | (*fn->clk) (true, true, cookie); |
5d3207da | 282 | |
6d0f6bcf | 283 | #ifdef CONFIG_SYS_FPGA_CHECK_BUSY |
5d3207da WD |
284 | ts = get_timer (0); |
285 | while ((*fn->busy) (cookie)) { | |
6d0f6bcf | 286 | if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT_BUSY) { |
9a9200b4 | 287 | printf ("%s:%d: ** Timeout after %d ticks waiting for" |
5d3207da | 288 | " BUSY to deassert\n", |
6d0f6bcf | 289 | __FUNCTION__, __LINE__, CONFIG_SYS_FPGA_WAIT_BUSY); |
5d3207da WD |
290 | (*fn->abort) (cookie); |
291 | return FPGA_FAIL; | |
292 | } | |
293 | } | |
294 | #endif | |
295 | ||
6d0f6bcf | 296 | #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK |
5d3207da WD |
297 | if (bytecount % (bsize / 40) == 0) |
298 | putc ('.'); | |
299 | #endif | |
300 | } | |
301 | ||
302 | /* | |
303 | * Finished writing the data; deassert FPGA CS_B and WRITE_B signals. | |
304 | */ | |
305 | CONFIG_FPGA_DELAY (); | |
472d5460 YS |
306 | (*fn->cs) (false, true, cookie); |
307 | (*fn->wr) (false, true, cookie); | |
5d3207da | 308 | |
6d0f6bcf | 309 | #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK |
5d3207da WD |
310 | putc ('\n'); |
311 | #endif | |
312 | ||
313 | /* | |
314 | * Check for successful configuration. FPGA INIT_B and DONE should | |
315 | * both be high upon successful configuration. | |
316 | */ | |
317 | ts = get_timer (0); | |
318 | ret_val = FPGA_SUCCESS; | |
319 | while (((*fn->done) (cookie) == FPGA_FAIL) || (*fn->init) (cookie)) { | |
6d0f6bcf | 320 | if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT_CONFIG) { |
9a9200b4 | 321 | printf ("%s:%d: ** Timeout after %d ticks waiting for DONE to" |
5d3207da | 322 | "assert and INIT to deassert\n", |
6d0f6bcf | 323 | __FUNCTION__, __LINE__, CONFIG_SYS_FPGA_WAIT_CONFIG); |
5d3207da WD |
324 | (*fn->abort) (cookie); |
325 | ret_val = FPGA_FAIL; | |
326 | break; | |
327 | } | |
328 | } | |
329 | ||
330 | if (ret_val == FPGA_SUCCESS) { | |
6d0f6bcf | 331 | #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK |
5d3207da WD |
332 | printf ("Initialization of FPGA device %d complete\n", cookie); |
333 | #endif | |
334 | /* | |
335 | * Run the post configuration function if there is one. | |
336 | */ | |
337 | if (*fn->post) { | |
338 | (*fn->post) (cookie); | |
339 | } | |
340 | } else { | |
6d0f6bcf | 341 | #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK |
5d3207da WD |
342 | printf ("** Initialization of FPGA device %d FAILED\n", |
343 | cookie); | |
344 | #endif | |
345 | } | |
346 | } else { | |
347 | printf ("%s:%d: NULL Interface function table!\n", | |
348 | __FUNCTION__, __LINE__); | |
349 | } | |
350 | return ret_val; | |
351 | } | |
352 | ||
353 | /* | |
354 | * Read the FPGA configuration data | |
355 | */ | |
f8c1be98 | 356 | static int virtex2_ssm_dump(xilinx_desc *desc, const void *buf, size_t bsize) |
5d3207da WD |
357 | { |
358 | int ret_val = FPGA_FAIL; | |
d9071ce0 | 359 | xilinx_virtex2_slave_selectmap_fns *fn = desc->iface_fns; |
5d3207da WD |
360 | |
361 | if (fn) { | |
362 | unsigned char *data = (unsigned char *) buf; | |
363 | size_t bytecount = 0; | |
364 | int cookie = desc->cookie; | |
365 | ||
366 | printf ("Starting Dump of FPGA Device %d...\n", cookie); | |
367 | ||
472d5460 YS |
368 | (*fn->cs) (true, true, cookie); |
369 | (*fn->clk) (true, true, cookie); | |
5d3207da WD |
370 | |
371 | while (bytecount < bsize) { | |
6d0f6bcf | 372 | #ifdef CONFIG_SYS_FPGA_CHECK_CTRLC |
5d3207da WD |
373 | if (ctrlc ()) { |
374 | (*fn->abort) (cookie); | |
375 | return FPGA_FAIL; | |
376 | } | |
377 | #endif | |
378 | /* | |
379 | * Cycle the clock and read the data | |
380 | */ | |
472d5460 YS |
381 | (*fn->clk) (false, true, cookie); |
382 | (*fn->clk) (true, true, cookie); | |
5d3207da | 383 | (*fn->rdata) (&(data[bytecount++]), cookie); |
6d0f6bcf | 384 | #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK |
5d3207da WD |
385 | if (bytecount % (bsize / 40) == 0) |
386 | putc ('.'); | |
387 | #endif | |
388 | } | |
389 | ||
390 | /* | |
391 | * Deassert CS_B and cycle the clock to deselect the device. | |
392 | */ | |
472d5460 YS |
393 | (*fn->cs) (false, false, cookie); |
394 | (*fn->clk) (false, true, cookie); | |
395 | (*fn->clk) (true, true, cookie); | |
5d3207da | 396 | |
6d0f6bcf | 397 | #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK |
5d3207da WD |
398 | putc ('\n'); |
399 | #endif | |
400 | puts ("Done.\n"); | |
401 | } else { | |
402 | printf ("%s:%d: NULL Interface function table!\n", | |
403 | __FUNCTION__, __LINE__); | |
404 | } | |
405 | return ret_val; | |
406 | } | |
407 | ||
f8c1be98 | 408 | static int virtex2_ss_load(xilinx_desc *desc, const void *buf, size_t bsize) |
5d3207da WD |
409 | { |
410 | printf ("%s: Slave Serial Loading is unsupported\n", __FUNCTION__); | |
411 | return FPGA_FAIL; | |
412 | } | |
413 | ||
f8c1be98 | 414 | static int virtex2_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize) |
5d3207da WD |
415 | { |
416 | printf ("%s: Slave Serial Dumping is unsupported\n", __FUNCTION__); | |
417 | return FPGA_FAIL; | |
418 | } | |
419 | ||
5d3207da | 420 | /* vim: set ts=4 tw=78: */ |
14cfc4f3 MS |
421 | |
422 | struct xilinx_fpga_op virtex2_op = { | |
423 | .load = virtex2_load, | |
424 | .dump = virtex2_dump, | |
425 | .info = virtex2_info, | |
426 | }; |