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