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