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