]>
Commit | Line | Data |
---|---|---|
875c7893 WD |
1 | /* |
2 | * (C) Copyright 2002 | |
3 | * Rich Ireland, Enterasys Networks, [email protected]. | |
4 | * | |
1a459660 | 5 | * SPDX-License-Identifier: GPL-2.0+ |
875c7893 WD |
6 | */ |
7 | ||
8 | /* | |
9 | * Configuration support for Xilinx Spartan3 devices. Based | |
10 | * on spartan2.c (Rich Ireland, [email protected]). | |
11 | */ | |
716c1dcb | 12 | |
875c7893 WD |
13 | #include <common.h> /* core U-Boot definitions */ |
14 | #include <spartan3.h> /* Spartan-II device family */ | |
15 | ||
875c7893 WD |
16 | /* Define FPGA_DEBUG to get debug printf's */ |
17 | #ifdef FPGA_DEBUG | |
18 | #define PRINTF(fmt,args...) printf (fmt ,##args) | |
19 | #else | |
20 | #define PRINTF(fmt,args...) | |
21 | #endif | |
22 | ||
6d0f6bcf | 23 | #undef CONFIG_SYS_FPGA_CHECK_BUSY |
875c7893 WD |
24 | |
25 | /* Note: The assumption is that we cannot possibly run fast enough to | |
26 | * overrun the device (the Slave Parallel mode can free run at 50MHz). | |
27 | * If there is a need to operate slower, define CONFIG_FPGA_DELAY in | |
28 | * the board config file to slow things down. | |
29 | */ | |
30 | #ifndef CONFIG_FPGA_DELAY | |
31 | #define CONFIG_FPGA_DELAY() | |
32 | #endif | |
33 | ||
6d0f6bcf JCPV |
34 | #ifndef CONFIG_SYS_FPGA_WAIT |
35 | #define CONFIG_SYS_FPGA_WAIT CONFIG_SYS_HZ/100 /* 10 ms */ | |
875c7893 WD |
36 | #endif |
37 | ||
f8c1be98 MS |
38 | static int spartan3_sp_load(xilinx_desc *desc, const void *buf, size_t bsize); |
39 | static int spartan3_sp_dump(xilinx_desc *desc, const void *buf, size_t bsize); | |
40 | /* static int spartan3_sp_info(xilinx_desc *desc ); */ | |
875c7893 | 41 | |
f8c1be98 MS |
42 | static int spartan3_ss_load(xilinx_desc *desc, const void *buf, size_t bsize); |
43 | static int spartan3_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize); | |
44 | /* static int spartan3_ss_info(xilinx_desc *desc); */ | |
875c7893 WD |
45 | |
46 | /* ------------------------------------------------------------------------- */ | |
47 | /* Spartan-II Generic Implementation */ | |
7a78bd26 MS |
48 | static int spartan3_load(xilinx_desc *desc, const void *buf, size_t bsize, |
49 | bitstream_type bstype) | |
875c7893 WD |
50 | { |
51 | int ret_val = FPGA_FAIL; | |
52 | ||
53 | switch (desc->iface) { | |
54 | case slave_serial: | |
55 | PRINTF ("%s: Launching Slave Serial Load\n", __FUNCTION__); | |
2a6e3869 | 56 | ret_val = spartan3_ss_load(desc, buf, bsize); |
875c7893 WD |
57 | break; |
58 | ||
59 | case slave_parallel: | |
60 | PRINTF ("%s: Launching Slave Parallel Load\n", __FUNCTION__); | |
2a6e3869 | 61 | ret_val = spartan3_sp_load(desc, buf, bsize); |
875c7893 WD |
62 | break; |
63 | ||
64 | default: | |
65 | printf ("%s: Unsupported interface type, %d\n", | |
66 | __FUNCTION__, desc->iface); | |
67 | } | |
68 | ||
69 | return ret_val; | |
70 | } | |
71 | ||
14cfc4f3 | 72 | static int spartan3_dump(xilinx_desc *desc, const void *buf, size_t bsize) |
875c7893 WD |
73 | { |
74 | int ret_val = FPGA_FAIL; | |
75 | ||
76 | switch (desc->iface) { | |
77 | case slave_serial: | |
78 | PRINTF ("%s: Launching Slave Serial Dump\n", __FUNCTION__); | |
2a6e3869 | 79 | ret_val = spartan3_ss_dump(desc, buf, bsize); |
875c7893 WD |
80 | break; |
81 | ||
82 | case slave_parallel: | |
83 | PRINTF ("%s: Launching Slave Parallel Dump\n", __FUNCTION__); | |
2a6e3869 | 84 | ret_val = spartan3_sp_dump(desc, buf, bsize); |
875c7893 WD |
85 | break; |
86 | ||
87 | default: | |
88 | printf ("%s: Unsupported interface type, %d\n", | |
89 | __FUNCTION__, desc->iface); | |
90 | } | |
91 | ||
92 | return ret_val; | |
93 | } | |
94 | ||
14cfc4f3 | 95 | static int spartan3_info(xilinx_desc *desc) |
875c7893 WD |
96 | { |
97 | return FPGA_SUCCESS; | |
98 | } | |
99 | ||
100 | ||
875c7893 WD |
101 | /* ------------------------------------------------------------------------- */ |
102 | /* Spartan-II Slave Parallel Generic Implementation */ | |
103 | ||
f8c1be98 | 104 | static int spartan3_sp_load(xilinx_desc *desc, const void *buf, size_t bsize) |
875c7893 WD |
105 | { |
106 | int ret_val = FPGA_FAIL; /* assume the worst */ | |
2a6e3869 | 107 | xilinx_spartan3_slave_parallel_fns *fn = desc->iface_fns; |
875c7893 WD |
108 | |
109 | PRINTF ("%s: start with interface functions @ 0x%p\n", | |
110 | __FUNCTION__, fn); | |
111 | ||
112 | if (fn) { | |
113 | size_t bytecount = 0; | |
114 | unsigned char *data = (unsigned char *) buf; | |
115 | int cookie = desc->cookie; /* make a local copy */ | |
116 | unsigned long ts; /* timestamp */ | |
117 | ||
118 | PRINTF ("%s: Function Table:\n" | |
119 | "ptr:\t0x%p\n" | |
120 | "struct: 0x%p\n" | |
121 | "pre: 0x%p\n" | |
122 | "pgm:\t0x%p\n" | |
123 | "init:\t0x%p\n" | |
124 | "err:\t0x%p\n" | |
125 | "clk:\t0x%p\n" | |
126 | "cs:\t0x%p\n" | |
127 | "wr:\t0x%p\n" | |
128 | "read data:\t0x%p\n" | |
129 | "write data:\t0x%p\n" | |
130 | "busy:\t0x%p\n" | |
131 | "abort:\t0x%p\n", | |
132 | "post:\t0x%p\n\n", | |
133 | __FUNCTION__, &fn, fn, fn->pre, fn->pgm, fn->init, fn->err, | |
134 | fn->clk, fn->cs, fn->wr, fn->rdata, fn->wdata, fn->busy, | |
135 | fn->abort, fn->post); | |
136 | ||
137 | /* | |
138 | * This code is designed to emulate the "Express Style" | |
139 | * Continuous Data Loading in Slave Parallel Mode for | |
140 | * the Spartan-II Family. | |
141 | */ | |
6d0f6bcf | 142 | #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK |
875c7893 WD |
143 | printf ("Loading FPGA Device %d...\n", cookie); |
144 | #endif | |
145 | /* | |
146 | * Run the pre configuration function if there is one. | |
147 | */ | |
148 | if (*fn->pre) { | |
149 | (*fn->pre) (cookie); | |
150 | } | |
151 | ||
152 | /* Establish the initial state */ | |
472d5460 | 153 | (*fn->pgm) (true, true, cookie); /* Assert the program, commit */ |
875c7893 WD |
154 | |
155 | /* Get ready for the burn */ | |
156 | CONFIG_FPGA_DELAY (); | |
472d5460 | 157 | (*fn->pgm) (false, true, cookie); /* Deassert the program, commit */ |
875c7893 WD |
158 | |
159 | ts = get_timer (0); /* get current time */ | |
160 | /* Now wait for INIT and BUSY to go high */ | |
161 | do { | |
162 | CONFIG_FPGA_DELAY (); | |
6d0f6bcf | 163 | if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */ |
875c7893 WD |
164 | puts ("** Timeout waiting for INIT to clear.\n"); |
165 | (*fn->abort) (cookie); /* abort the burn */ | |
166 | return FPGA_FAIL; | |
167 | } | |
168 | } while ((*fn->init) (cookie) && (*fn->busy) (cookie)); | |
169 | ||
472d5460 YS |
170 | (*fn->wr) (true, true, cookie); /* Assert write, commit */ |
171 | (*fn->cs) (true, true, cookie); /* Assert chip select, commit */ | |
172 | (*fn->clk) (true, true, cookie); /* Assert the clock pin */ | |
875c7893 WD |
173 | |
174 | /* Load the data */ | |
175 | while (bytecount < bsize) { | |
176 | /* XXX - do we check for an Ctrl-C press in here ??? */ | |
177 | /* XXX - Check the error bit? */ | |
178 | ||
472d5460 | 179 | (*fn->wdata) (data[bytecount++], true, cookie); /* write the data */ |
875c7893 | 180 | CONFIG_FPGA_DELAY (); |
472d5460 | 181 | (*fn->clk) (false, true, cookie); /* Deassert the clock pin */ |
875c7893 | 182 | CONFIG_FPGA_DELAY (); |
472d5460 | 183 | (*fn->clk) (true, true, cookie); /* Assert the clock pin */ |
875c7893 | 184 | |
6d0f6bcf | 185 | #ifdef CONFIG_SYS_FPGA_CHECK_BUSY |
875c7893 WD |
186 | ts = get_timer (0); /* get current time */ |
187 | while ((*fn->busy) (cookie)) { | |
188 | /* XXX - we should have a check in here somewhere to | |
189 | * make sure we aren't busy forever... */ | |
190 | ||
191 | CONFIG_FPGA_DELAY (); | |
472d5460 | 192 | (*fn->clk) (false, true, cookie); /* Deassert the clock pin */ |
875c7893 | 193 | CONFIG_FPGA_DELAY (); |
472d5460 | 194 | (*fn->clk) (true, true, cookie); /* Assert the clock pin */ |
875c7893 | 195 | |
6d0f6bcf | 196 | if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */ |
875c7893 WD |
197 | puts ("** Timeout waiting for BUSY to clear.\n"); |
198 | (*fn->abort) (cookie); /* abort the burn */ | |
199 | return FPGA_FAIL; | |
200 | } | |
201 | } | |
202 | #endif | |
203 | ||
6d0f6bcf | 204 | #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK |
875c7893 WD |
205 | if (bytecount % (bsize / 40) == 0) |
206 | putc ('.'); /* let them know we are alive */ | |
207 | #endif | |
208 | } | |
209 | ||
210 | CONFIG_FPGA_DELAY (); | |
472d5460 YS |
211 | (*fn->cs) (false, true, cookie); /* Deassert the chip select */ |
212 | (*fn->wr) (false, true, cookie); /* Deassert the write pin */ | |
875c7893 | 213 | |
6d0f6bcf | 214 | #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK |
875c7893 WD |
215 | putc ('\n'); /* terminate the dotted line */ |
216 | #endif | |
217 | ||
218 | /* now check for done signal */ | |
219 | ts = get_timer (0); /* get current time */ | |
220 | ret_val = FPGA_SUCCESS; | |
221 | while ((*fn->done) (cookie) == FPGA_FAIL) { | |
222 | /* XXX - we should have a check in here somewhere to | |
223 | * make sure we aren't busy forever... */ | |
224 | ||
225 | CONFIG_FPGA_DELAY (); | |
472d5460 | 226 | (*fn->clk) (false, true, cookie); /* Deassert the clock pin */ |
875c7893 | 227 | CONFIG_FPGA_DELAY (); |
472d5460 | 228 | (*fn->clk) (true, true, cookie); /* Assert the clock pin */ |
875c7893 | 229 | |
6d0f6bcf | 230 | if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */ |
875c7893 WD |
231 | puts ("** Timeout waiting for DONE to clear.\n"); |
232 | (*fn->abort) (cookie); /* abort the burn */ | |
233 | ret_val = FPGA_FAIL; | |
234 | break; | |
235 | } | |
236 | } | |
237 | ||
875c7893 WD |
238 | /* |
239 | * Run the post configuration function if there is one. | |
240 | */ | |
670cbde8 | 241 | if (*fn->post) |
875c7893 | 242 | (*fn->post) (cookie); |
875c7893 | 243 | |
6d0f6bcf | 244 | #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK |
670cbde8 MF |
245 | if (ret_val == FPGA_SUCCESS) |
246 | puts ("Done.\n"); | |
247 | else | |
875c7893 WD |
248 | puts ("Fail.\n"); |
249 | #endif | |
875c7893 WD |
250 | |
251 | } else { | |
252 | printf ("%s: NULL Interface function table!\n", __FUNCTION__); | |
253 | } | |
254 | ||
255 | return ret_val; | |
256 | } | |
257 | ||
f8c1be98 | 258 | static int spartan3_sp_dump(xilinx_desc *desc, const void *buf, size_t bsize) |
875c7893 WD |
259 | { |
260 | int ret_val = FPGA_FAIL; /* assume the worst */ | |
2a6e3869 | 261 | xilinx_spartan3_slave_parallel_fns *fn = desc->iface_fns; |
875c7893 WD |
262 | |
263 | if (fn) { | |
264 | unsigned char *data = (unsigned char *) buf; | |
265 | size_t bytecount = 0; | |
266 | int cookie = desc->cookie; /* make a local copy */ | |
267 | ||
268 | printf ("Starting Dump of FPGA Device %d...\n", cookie); | |
269 | ||
472d5460 YS |
270 | (*fn->cs) (true, true, cookie); /* Assert chip select, commit */ |
271 | (*fn->clk) (true, true, cookie); /* Assert the clock pin */ | |
875c7893 WD |
272 | |
273 | /* dump the data */ | |
274 | while (bytecount < bsize) { | |
275 | /* XXX - do we check for an Ctrl-C press in here ??? */ | |
276 | ||
472d5460 YS |
277 | (*fn->clk) (false, true, cookie); /* Deassert the clock pin */ |
278 | (*fn->clk) (true, true, cookie); /* Assert the clock pin */ | |
875c7893 | 279 | (*fn->rdata) (&(data[bytecount++]), cookie); /* read the data */ |
6d0f6bcf | 280 | #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK |
875c7893 WD |
281 | if (bytecount % (bsize / 40) == 0) |
282 | putc ('.'); /* let them know we are alive */ | |
283 | #endif | |
284 | } | |
285 | ||
472d5460 YS |
286 | (*fn->cs) (false, false, cookie); /* Deassert the chip select */ |
287 | (*fn->clk) (false, true, cookie); /* Deassert the clock pin */ | |
288 | (*fn->clk) (true, true, cookie); /* Assert the clock pin */ | |
875c7893 | 289 | |
6d0f6bcf | 290 | #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK |
875c7893 WD |
291 | putc ('\n'); /* terminate the dotted line */ |
292 | #endif | |
293 | puts ("Done.\n"); | |
294 | ||
295 | /* XXX - checksum the data? */ | |
296 | } else { | |
297 | printf ("%s: NULL Interface function table!\n", __FUNCTION__); | |
298 | } | |
299 | ||
300 | return ret_val; | |
301 | } | |
302 | ||
303 | ||
875c7893 WD |
304 | /* ------------------------------------------------------------------------- */ |
305 | ||
f8c1be98 | 306 | static int spartan3_ss_load(xilinx_desc *desc, const void *buf, size_t bsize) |
875c7893 WD |
307 | { |
308 | int ret_val = FPGA_FAIL; /* assume the worst */ | |
2a6e3869 | 309 | xilinx_spartan3_slave_serial_fns *fn = desc->iface_fns; |
875c7893 | 310 | int i; |
437fc732 | 311 | unsigned char val; |
875c7893 WD |
312 | |
313 | PRINTF ("%s: start with interface functions @ 0x%p\n", | |
314 | __FUNCTION__, fn); | |
315 | ||
316 | if (fn) { | |
317 | size_t bytecount = 0; | |
318 | unsigned char *data = (unsigned char *) buf; | |
319 | int cookie = desc->cookie; /* make a local copy */ | |
320 | unsigned long ts; /* timestamp */ | |
321 | ||
322 | PRINTF ("%s: Function Table:\n" | |
323 | "ptr:\t0x%p\n" | |
324 | "struct: 0x%p\n" | |
325 | "pgm:\t0x%p\n" | |
326 | "init:\t0x%p\n" | |
327 | "clk:\t0x%p\n" | |
328 | "wr:\t0x%p\n" | |
329 | "done:\t0x%p\n\n", | |
330 | __FUNCTION__, &fn, fn, fn->pgm, fn->init, | |
331 | fn->clk, fn->wr, fn->done); | |
6d0f6bcf | 332 | #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK |
875c7893 WD |
333 | printf ("Loading FPGA Device %d...\n", cookie); |
334 | #endif | |
335 | ||
336 | /* | |
337 | * Run the pre configuration function if there is one. | |
338 | */ | |
339 | if (*fn->pre) { | |
340 | (*fn->pre) (cookie); | |
341 | } | |
342 | ||
343 | /* Establish the initial state */ | |
472d5460 | 344 | (*fn->pgm) (true, true, cookie); /* Assert the program, commit */ |
875c7893 WD |
345 | |
346 | /* Wait for INIT state (init low) */ | |
347 | ts = get_timer (0); /* get current time */ | |
348 | do { | |
349 | CONFIG_FPGA_DELAY (); | |
6d0f6bcf | 350 | if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */ |
875c7893 | 351 | puts ("** Timeout waiting for INIT to start.\n"); |
b0bc8b70 WW |
352 | if (*fn->abort) |
353 | (*fn->abort) (cookie); | |
875c7893 WD |
354 | return FPGA_FAIL; |
355 | } | |
356 | } while (!(*fn->init) (cookie)); | |
357 | ||
358 | /* Get ready for the burn */ | |
359 | CONFIG_FPGA_DELAY (); | |
472d5460 | 360 | (*fn->pgm) (false, true, cookie); /* Deassert the program, commit */ |
875c7893 WD |
361 | |
362 | ts = get_timer (0); /* get current time */ | |
363 | /* Now wait for INIT to go high */ | |
364 | do { | |
365 | CONFIG_FPGA_DELAY (); | |
6d0f6bcf | 366 | if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */ |
875c7893 | 367 | puts ("** Timeout waiting for INIT to clear.\n"); |
b0bc8b70 WW |
368 | if (*fn->abort) |
369 | (*fn->abort) (cookie); | |
875c7893 WD |
370 | return FPGA_FAIL; |
371 | } | |
372 | } while ((*fn->init) (cookie)); | |
373 | ||
374 | /* Load the data */ | |
89083346 | 375 | if(*fn->bwr) |
472d5460 | 376 | (*fn->bwr) (data, bsize, true, cookie); |
89083346 WW |
377 | else { |
378 | while (bytecount < bsize) { | |
379 | ||
380 | /* Xilinx detects an error if INIT goes low (active) | |
381 | while DONE is low (inactive) */ | |
382 | if ((*fn->done) (cookie) == 0 && (*fn->init) (cookie)) { | |
383 | puts ("** CRC error during FPGA load.\n"); | |
b0bc8b70 WW |
384 | if (*fn->abort) |
385 | (*fn->abort) (cookie); | |
89083346 WW |
386 | return (FPGA_FAIL); |
387 | } | |
388 | val = data [bytecount ++]; | |
389 | i = 8; | |
390 | do { | |
391 | /* Deassert the clock */ | |
472d5460 | 392 | (*fn->clk) (false, true, cookie); |
89083346 WW |
393 | CONFIG_FPGA_DELAY (); |
394 | /* Write data */ | |
472d5460 | 395 | (*fn->wr) ((val & 0x80), true, cookie); |
89083346 WW |
396 | CONFIG_FPGA_DELAY (); |
397 | /* Assert the clock */ | |
472d5460 | 398 | (*fn->clk) (true, true, cookie); |
89083346 WW |
399 | CONFIG_FPGA_DELAY (); |
400 | val <<= 1; | |
401 | i --; | |
402 | } while (i > 0); | |
875c7893 | 403 | |
6d0f6bcf | 404 | #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK |
89083346 WW |
405 | if (bytecount % (bsize / 40) == 0) |
406 | putc ('.'); /* let them know we are alive */ | |
875c7893 | 407 | #endif |
89083346 | 408 | } |
875c7893 WD |
409 | } |
410 | ||
411 | CONFIG_FPGA_DELAY (); | |
412 | ||
6d0f6bcf | 413 | #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK |
875c7893 WD |
414 | putc ('\n'); /* terminate the dotted line */ |
415 | #endif | |
416 | ||
417 | /* now check for done signal */ | |
418 | ts = get_timer (0); /* get current time */ | |
419 | ret_val = FPGA_SUCCESS; | |
472d5460 | 420 | (*fn->wr) (true, true, cookie); |
875c7893 WD |
421 | |
422 | while (! (*fn->done) (cookie)) { | |
423 | /* XXX - we should have a check in here somewhere to | |
424 | * make sure we aren't busy forever... */ | |
425 | ||
426 | CONFIG_FPGA_DELAY (); | |
472d5460 | 427 | (*fn->clk) (false, true, cookie); /* Deassert the clock pin */ |
875c7893 | 428 | CONFIG_FPGA_DELAY (); |
472d5460 | 429 | (*fn->clk) (true, true, cookie); /* Assert the clock pin */ |
875c7893 WD |
430 | |
431 | putc ('*'); | |
432 | ||
6d0f6bcf | 433 | if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */ |
875c7893 WD |
434 | puts ("** Timeout waiting for DONE to clear.\n"); |
435 | ret_val = FPGA_FAIL; | |
436 | break; | |
437 | } | |
438 | } | |
439 | putc ('\n'); /* terminate the dotted line */ | |
440 | ||
21d39d59 MF |
441 | /* |
442 | * Run the post configuration function if there is one. | |
443 | */ | |
670cbde8 | 444 | if (*fn->post) |
21d39d59 | 445 | (*fn->post) (cookie); |
21d39d59 | 446 | |
6d0f6bcf | 447 | #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK |
670cbde8 | 448 | if (ret_val == FPGA_SUCCESS) |
875c7893 | 449 | puts ("Done.\n"); |
670cbde8 | 450 | else |
875c7893 | 451 | puts ("Fail.\n"); |
875c7893 WD |
452 | #endif |
453 | ||
454 | } else { | |
455 | printf ("%s: NULL Interface function table!\n", __FUNCTION__); | |
456 | } | |
457 | ||
458 | return ret_val; | |
459 | } | |
460 | ||
f8c1be98 | 461 | static int spartan3_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize) |
875c7893 WD |
462 | { |
463 | /* Readback is only available through the Slave Parallel and */ | |
464 | /* boundary-scan interfaces. */ | |
465 | printf ("%s: Slave Serial Dumping is unavailable\n", | |
466 | __FUNCTION__); | |
467 | return FPGA_FAIL; | |
468 | } | |
14cfc4f3 MS |
469 | |
470 | struct xilinx_fpga_op spartan3_op = { | |
471 | .load = spartan3_load, | |
472 | .dump = spartan3_dump, | |
473 | .info = spartan3_info, | |
474 | }; |