]>
Commit | Line | Data |
---|---|---|
5d3207da WD |
1 | /* |
2 | * (C) Copyright 2002 | |
3 | * Rich Ireland, Enterasys Networks, rireland@enterasys.com. | |
4 | * Keith Outwater, keith_outwater@mvis.com | |
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, rireland@enterasys.com). | |
12 | */ | |
13 | ||
14 | #include <common.h> | |
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 | |
f8c1be98 | 93 | int virtex2_load(xilinx_desc *desc, const void *buf, size_t bsize) |
5d3207da WD |
94 | { |
95 | int ret_val = FPGA_FAIL; | |
96 | ||
97 | switch (desc->iface) { | |
98 | case slave_serial: | |
99 | PRINTF ("%s: Launching Slave Serial Load\n", __FUNCTION__); | |
d9071ce0 | 100 | ret_val = virtex2_ss_load(desc, buf, bsize); |
5d3207da WD |
101 | break; |
102 | ||
103 | case slave_selectmap: | |
104 | PRINTF ("%s: Launching Slave Parallel Load\n", __FUNCTION__); | |
d9071ce0 | 105 | ret_val = virtex2_ssm_load(desc, buf, bsize); |
5d3207da WD |
106 | break; |
107 | ||
108 | default: | |
109 | printf ("%s: Unsupported interface type, %d\n", | |
110 | __FUNCTION__, desc->iface); | |
111 | } | |
112 | return ret_val; | |
113 | } | |
114 | ||
f8c1be98 | 115 | int virtex2_dump(xilinx_desc *desc, const void *buf, size_t bsize) |
5d3207da WD |
116 | { |
117 | int ret_val = FPGA_FAIL; | |
118 | ||
119 | switch (desc->iface) { | |
120 | case slave_serial: | |
121 | PRINTF ("%s: Launching Slave Serial Dump\n", __FUNCTION__); | |
d9071ce0 | 122 | ret_val = virtex2_ss_dump(desc, buf, bsize); |
5d3207da WD |
123 | break; |
124 | ||
125 | case slave_parallel: | |
126 | PRINTF ("%s: Launching Slave Parallel Dump\n", __FUNCTION__); | |
d9071ce0 | 127 | ret_val = virtex2_ssm_dump(desc, buf, bsize); |
5d3207da WD |
128 | break; |
129 | ||
130 | default: | |
131 | printf ("%s: Unsupported interface type, %d\n", | |
132 | __FUNCTION__, desc->iface); | |
133 | } | |
134 | return ret_val; | |
135 | } | |
136 | ||
f8c1be98 | 137 | int virtex2_info(xilinx_desc *desc) |
5d3207da WD |
138 | { |
139 | return FPGA_SUCCESS; | |
140 | } | |
141 | ||
5d3207da WD |
142 | /* |
143 | * Virtex-II Slave SelectMap configuration loader. Configuration via | |
144 | * SelectMap is as follows: | |
145 | * 1. Set the FPGA's PROG_B line low. | |
146 | * 2. Set the FPGA's PROG_B line high. Wait for INIT_B to go high. | |
147 | * 3. Write data to the SelectMap port. If INIT_B goes low at any time | |
148 | * this process, a configuration error (most likely CRC failure) has | |
149 | * ocurred. At this point a status word may be read from the | |
150 | * SelectMap interface to determine the source of the problem (You | |
9a9200b4 | 151 | * could, for instance, put this in your 'abort' function handler). |
5d3207da WD |
152 | * 4. After all data has been written, test the state of the FPGA |
153 | * INIT_B and DONE lines. If both are high, configuration has | |
154 | * succeeded. Congratulations! | |
155 | */ | |
f8c1be98 | 156 | static int virtex2_ssm_load(xilinx_desc *desc, const void *buf, size_t bsize) |
5d3207da WD |
157 | { |
158 | int ret_val = FPGA_FAIL; | |
d9071ce0 | 159 | xilinx_virtex2_slave_selectmap_fns *fn = desc->iface_fns; |
5d3207da WD |
160 | |
161 | PRINTF ("%s:%d: Start with interface functions @ 0x%p\n", | |
162 | __FUNCTION__, __LINE__, fn); | |
163 | ||
164 | if (fn) { | |
165 | size_t bytecount = 0; | |
166 | unsigned char *data = (unsigned char *) buf; | |
167 | int cookie = desc->cookie; | |
168 | unsigned long ts; | |
169 | ||
170 | /* Gotta split this one up (so the stack won't blow??) */ | |
171 | PRINTF ("%s:%d: Function Table:\n" | |
172 | " base 0x%p\n" | |
173 | " struct 0x%p\n" | |
174 | " pre 0x%p\n" | |
175 | " prog 0x%p\n" | |
176 | " init 0x%p\n" | |
177 | " error 0x%p\n", | |
178 | __FUNCTION__, __LINE__, | |
179 | &fn, fn, fn->pre, fn->pgm, fn->init, fn->err); | |
180 | PRINTF (" clock 0x%p\n" | |
181 | " cs 0x%p\n" | |
182 | " write 0x%p\n" | |
183 | " rdata 0x%p\n" | |
184 | " wdata 0x%p\n" | |
185 | " busy 0x%p\n" | |
186 | " abort 0x%p\n" | |
187 | " post 0x%p\n\n", | |
188 | fn->clk, fn->cs, fn->wr, fn->rdata, fn->wdata, | |
189 | fn->busy, fn->abort, fn->post); | |
190 | ||
6d0f6bcf | 191 | #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK |
5d3207da WD |
192 | printf ("Initializing FPGA Device %d...\n", cookie); |
193 | #endif | |
194 | /* | |
195 | * Run the pre configuration function if there is one. | |
196 | */ | |
197 | if (*fn->pre) { | |
198 | (*fn->pre) (cookie); | |
199 | } | |
200 | ||
201 | /* | |
202 | * Assert the program line. The minimum pulse width for | |
203 | * Virtex II devices is 300 nS (Tprogram parameter in datasheet). | |
204 | * There is no maximum value for the pulse width. Check to make | |
205 | * sure that INIT_B goes low after assertion of PROG_B | |
206 | */ | |
472d5460 | 207 | (*fn->pgm) (true, true, cookie); |
5d3207da WD |
208 | udelay (10); |
209 | ts = get_timer (0); | |
210 | do { | |
6d0f6bcf | 211 | if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT_INIT) { |
9a9200b4 | 212 | printf ("%s:%d: ** Timeout after %d ticks waiting for INIT" |
5d3207da | 213 | " to assert.\n", __FUNCTION__, __LINE__, |
6d0f6bcf | 214 | CONFIG_SYS_FPGA_WAIT_INIT); |
5d3207da WD |
215 | (*fn->abort) (cookie); |
216 | return FPGA_FAIL; | |
217 | } | |
218 | } while (!(*fn->init) (cookie)); | |
219 | ||
472d5460 | 220 | (*fn->pgm) (false, true, cookie); |
5d3207da | 221 | CONFIG_FPGA_DELAY (); |
472d5460 | 222 | (*fn->clk) (true, true, cookie); |
5d3207da WD |
223 | |
224 | /* | |
225 | * Start a timer and wait for INIT_B to go high | |
226 | */ | |
227 | ts = get_timer (0); | |
228 | do { | |
229 | CONFIG_FPGA_DELAY (); | |
6d0f6bcf | 230 | if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT_INIT) { |
9a9200b4 | 231 | printf ("%s:%d: ** Timeout after %d ticks waiting for INIT" |
5d3207da | 232 | " to deassert.\n", __FUNCTION__, __LINE__, |
6d0f6bcf | 233 | CONFIG_SYS_FPGA_WAIT_INIT); |
5d3207da WD |
234 | (*fn->abort) (cookie); |
235 | return FPGA_FAIL; | |
236 | } | |
237 | } while ((*fn->init) (cookie) && (*fn->busy) (cookie)); | |
238 | ||
472d5460 YS |
239 | (*fn->wr) (true, true, cookie); |
240 | (*fn->cs) (true, true, cookie); | |
5d3207da WD |
241 | |
242 | udelay (10000); | |
243 | ||
244 | /* | |
245 | * Load the data byte by byte | |
246 | */ | |
247 | while (bytecount < bsize) { | |
6d0f6bcf | 248 | #ifdef CONFIG_SYS_FPGA_CHECK_CTRLC |
5d3207da WD |
249 | if (ctrlc ()) { |
250 | (*fn->abort) (cookie); | |
251 | return FPGA_FAIL; | |
252 | } | |
253 | #endif | |
9a9200b4 WD |
254 | |
255 | if ((*fn->done) (cookie) == FPGA_SUCCESS) { | |
256 | PRINTF ("%s:%d:done went active early, bytecount = %d\n", | |
257 | __FUNCTION__, __LINE__, bytecount); | |
258 | break; | |
259 | } | |
260 | ||
6d0f6bcf | 261 | #ifdef CONFIG_SYS_FPGA_CHECK_ERROR |
5d3207da | 262 | if ((*fn->init) (cookie)) { |
9a9200b4 | 263 | printf ("\n%s:%d: ** Error: INIT asserted during" |
5d3207da | 264 | " configuration\n", __FUNCTION__, __LINE__); |
9a9200b4 WD |
265 | printf ("%d = buffer offset, %d = buffer size\n", |
266 | bytecount, bsize); | |
5d3207da WD |
267 | (*fn->abort) (cookie); |
268 | return FPGA_FAIL; | |
269 | } | |
270 | #endif | |
9a9200b4 | 271 | |
472d5460 | 272 | (*fn->wdata) (data[bytecount++], true, cookie); |
5d3207da WD |
273 | CONFIG_FPGA_DELAY (); |
274 | ||
275 | /* | |
276 | * Cycle the clock pin | |
277 | */ | |
472d5460 | 278 | (*fn->clk) (false, true, cookie); |
5d3207da | 279 | CONFIG_FPGA_DELAY (); |
472d5460 | 280 | (*fn->clk) (true, true, cookie); |
5d3207da | 281 | |
6d0f6bcf | 282 | #ifdef CONFIG_SYS_FPGA_CHECK_BUSY |
5d3207da WD |
283 | ts = get_timer (0); |
284 | while ((*fn->busy) (cookie)) { | |
6d0f6bcf | 285 | if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT_BUSY) { |
9a9200b4 | 286 | printf ("%s:%d: ** Timeout after %d ticks waiting for" |
5d3207da | 287 | " BUSY to deassert\n", |
6d0f6bcf | 288 | __FUNCTION__, __LINE__, CONFIG_SYS_FPGA_WAIT_BUSY); |
5d3207da WD |
289 | (*fn->abort) (cookie); |
290 | return FPGA_FAIL; | |
291 | } | |
292 | } | |
293 | #endif | |
294 | ||
6d0f6bcf | 295 | #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK |
5d3207da WD |
296 | if (bytecount % (bsize / 40) == 0) |
297 | putc ('.'); | |
298 | #endif | |
299 | } | |
300 | ||
301 | /* | |
302 | * Finished writing the data; deassert FPGA CS_B and WRITE_B signals. | |
303 | */ | |
304 | CONFIG_FPGA_DELAY (); | |
472d5460 YS |
305 | (*fn->cs) (false, true, cookie); |
306 | (*fn->wr) (false, true, cookie); | |
5d3207da | 307 | |
6d0f6bcf | 308 | #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK |
5d3207da WD |
309 | putc ('\n'); |
310 | #endif | |
311 | ||
312 | /* | |
313 | * Check for successful configuration. FPGA INIT_B and DONE should | |
314 | * both be high upon successful configuration. | |
315 | */ | |
316 | ts = get_timer (0); | |
317 | ret_val = FPGA_SUCCESS; | |
318 | while (((*fn->done) (cookie) == FPGA_FAIL) || (*fn->init) (cookie)) { | |
6d0f6bcf | 319 | if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT_CONFIG) { |
9a9200b4 | 320 | printf ("%s:%d: ** Timeout after %d ticks waiting for DONE to" |
5d3207da | 321 | "assert and INIT to deassert\n", |
6d0f6bcf | 322 | __FUNCTION__, __LINE__, CONFIG_SYS_FPGA_WAIT_CONFIG); |
5d3207da WD |
323 | (*fn->abort) (cookie); |
324 | ret_val = FPGA_FAIL; | |
325 | break; | |
326 | } | |
327 | } | |
328 | ||
329 | if (ret_val == FPGA_SUCCESS) { | |
6d0f6bcf | 330 | #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK |
5d3207da WD |
331 | printf ("Initialization of FPGA device %d complete\n", cookie); |
332 | #endif | |
333 | /* | |
334 | * Run the post configuration function if there is one. | |
335 | */ | |
336 | if (*fn->post) { | |
337 | (*fn->post) (cookie); | |
338 | } | |
339 | } else { | |
6d0f6bcf | 340 | #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK |
5d3207da WD |
341 | printf ("** Initialization of FPGA device %d FAILED\n", |
342 | cookie); | |
343 | #endif | |
344 | } | |
345 | } else { | |
346 | printf ("%s:%d: NULL Interface function table!\n", | |
347 | __FUNCTION__, __LINE__); | |
348 | } | |
349 | return ret_val; | |
350 | } | |
351 | ||
352 | /* | |
353 | * Read the FPGA configuration data | |
354 | */ | |
f8c1be98 | 355 | static int virtex2_ssm_dump(xilinx_desc *desc, const void *buf, size_t bsize) |
5d3207da WD |
356 | { |
357 | int ret_val = FPGA_FAIL; | |
d9071ce0 | 358 | xilinx_virtex2_slave_selectmap_fns *fn = desc->iface_fns; |
5d3207da WD |
359 | |
360 | if (fn) { | |
361 | unsigned char *data = (unsigned char *) buf; | |
362 | size_t bytecount = 0; | |
363 | int cookie = desc->cookie; | |
364 | ||
365 | printf ("Starting Dump of FPGA Device %d...\n", cookie); | |
366 | ||
472d5460 YS |
367 | (*fn->cs) (true, true, cookie); |
368 | (*fn->clk) (true, true, cookie); | |
5d3207da WD |
369 | |
370 | while (bytecount < bsize) { | |
6d0f6bcf | 371 | #ifdef CONFIG_SYS_FPGA_CHECK_CTRLC |
5d3207da WD |
372 | if (ctrlc ()) { |
373 | (*fn->abort) (cookie); | |
374 | return FPGA_FAIL; | |
375 | } | |
376 | #endif | |
377 | /* | |
378 | * Cycle the clock and read the data | |
379 | */ | |
472d5460 YS |
380 | (*fn->clk) (false, true, cookie); |
381 | (*fn->clk) (true, true, cookie); | |
5d3207da | 382 | (*fn->rdata) (&(data[bytecount++]), cookie); |
6d0f6bcf | 383 | #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK |
5d3207da WD |
384 | if (bytecount % (bsize / 40) == 0) |
385 | putc ('.'); | |
386 | #endif | |
387 | } | |
388 | ||
389 | /* | |
390 | * Deassert CS_B and cycle the clock to deselect the device. | |
391 | */ | |
472d5460 YS |
392 | (*fn->cs) (false, false, cookie); |
393 | (*fn->clk) (false, true, cookie); | |
394 | (*fn->clk) (true, true, cookie); | |
5d3207da | 395 | |
6d0f6bcf | 396 | #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK |
5d3207da WD |
397 | putc ('\n'); |
398 | #endif | |
399 | puts ("Done.\n"); | |
400 | } else { | |
401 | printf ("%s:%d: NULL Interface function table!\n", | |
402 | __FUNCTION__, __LINE__); | |
403 | } | |
404 | return ret_val; | |
405 | } | |
406 | ||
f8c1be98 | 407 | static int virtex2_ss_load(xilinx_desc *desc, const void *buf, size_t bsize) |
5d3207da WD |
408 | { |
409 | printf ("%s: Slave Serial Loading is unsupported\n", __FUNCTION__); | |
410 | return FPGA_FAIL; | |
411 | } | |
412 | ||
f8c1be98 | 413 | static int virtex2_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize) |
5d3207da WD |
414 | { |
415 | printf ("%s: Slave Serial Dumping is unsupported\n", __FUNCTION__); | |
416 | return FPGA_FAIL; | |
417 | } | |
418 | ||
5d3207da | 419 | /* vim: set ts=4 tw=78: */ |