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