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