]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/fpga/spartan2.c
fpga: Fix Spartan II FPGA booting
[karo-tx-uboot.git] / drivers / fpga / spartan2.c
1 /*
2  * (C) Copyright 2002
3  * Rich Ireland, Enterasys Networks, rireland@enterasys.com.
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  *
23  */
24
25 #include <common.h>             /* core U-Boot definitions */
26 #include <spartan2.h>           /* Spartan-II device family */
27
28 /* Define FPGA_DEBUG to get debug printf's */
29 #ifdef  FPGA_DEBUG
30 #define PRINTF(fmt,args...)     printf (fmt ,##args)
31 #else
32 #define PRINTF(fmt,args...)
33 #endif
34
35 #undef CONFIG_SYS_FPGA_CHECK_BUSY
36 #undef CONFIG_SYS_FPGA_PROG_FEEDBACK
37
38 /* Note: The assumption is that we cannot possibly run fast enough to
39  * overrun the device (the Slave Parallel mode can free run at 50MHz).
40  * If there is a need to operate slower, define CONFIG_FPGA_DELAY in
41  * the board config file to slow things down.
42  */
43 #ifndef CONFIG_FPGA_DELAY
44 #define CONFIG_FPGA_DELAY()
45 #endif
46
47 #ifndef CONFIG_SYS_FPGA_WAIT
48 #define CONFIG_SYS_FPGA_WAIT CONFIG_SYS_HZ/100  /* 10 ms */
49 #endif
50
51 static int Spartan2_sp_load( Xilinx_desc *desc, void *buf, size_t bsize );
52 static int Spartan2_sp_dump( Xilinx_desc *desc, void *buf, size_t bsize );
53 /* static int Spartan2_sp_info( Xilinx_desc *desc ); */
54 static int Spartan2_sp_reloc( Xilinx_desc *desc, ulong reloc_offset );
55
56 static int Spartan2_ss_load( Xilinx_desc *desc, void *buf, size_t bsize );
57 static int Spartan2_ss_dump( Xilinx_desc *desc, void *buf, size_t bsize );
58 /* static int Spartan2_ss_info( Xilinx_desc *desc ); */
59 static int Spartan2_ss_reloc( Xilinx_desc *desc, ulong reloc_offset );
60
61 /* ------------------------------------------------------------------------- */
62 /* Spartan-II Generic Implementation */
63 int Spartan2_load (Xilinx_desc * desc, void *buf, size_t bsize)
64 {
65         int ret_val = FPGA_FAIL;
66
67         switch (desc->iface) {
68         case slave_serial:
69                 PRINTF ("%s: Launching Slave Serial Load\n", __FUNCTION__);
70                 ret_val = Spartan2_ss_load (desc, buf, bsize);
71                 break;
72
73         case slave_parallel:
74                 PRINTF ("%s: Launching Slave Parallel Load\n", __FUNCTION__);
75                 ret_val = Spartan2_sp_load (desc, buf, bsize);
76                 break;
77
78         default:
79                 printf ("%s: Unsupported interface type, %d\n",
80                                 __FUNCTION__, desc->iface);
81         }
82
83         return ret_val;
84 }
85
86 int Spartan2_dump (Xilinx_desc * desc, void *buf, size_t bsize)
87 {
88         int ret_val = FPGA_FAIL;
89
90         switch (desc->iface) {
91         case slave_serial:
92                 PRINTF ("%s: Launching Slave Serial Dump\n", __FUNCTION__);
93                 ret_val = Spartan2_ss_dump (desc, buf, bsize);
94                 break;
95
96         case slave_parallel:
97                 PRINTF ("%s: Launching Slave Parallel Dump\n", __FUNCTION__);
98                 ret_val = Spartan2_sp_dump (desc, buf, bsize);
99                 break;
100
101         default:
102                 printf ("%s: Unsupported interface type, %d\n",
103                                 __FUNCTION__, desc->iface);
104         }
105
106         return ret_val;
107 }
108
109 int Spartan2_info( Xilinx_desc *desc )
110 {
111         return FPGA_SUCCESS;
112 }
113
114
115 int Spartan2_reloc (Xilinx_desc * desc, ulong reloc_offset)
116 {
117         int ret_val = FPGA_FAIL;        /* assume a failure */
118
119         if (desc->family != Xilinx_Spartan2) {
120                 printf ("%s: Unsupported family type, %d\n",
121                                 __FUNCTION__, desc->family);
122                 return FPGA_FAIL;
123         } else
124                 switch (desc->iface) {
125                 case slave_serial:
126                         ret_val = Spartan2_ss_reloc (desc, reloc_offset);
127                         break;
128
129                 case slave_parallel:
130                         ret_val = Spartan2_sp_reloc (desc, reloc_offset);
131                         break;
132
133                 default:
134                         printf ("%s: Unsupported interface type, %d\n",
135                                         __FUNCTION__, desc->iface);
136                 }
137
138         return ret_val;
139 }
140
141
142 /* ------------------------------------------------------------------------- */
143 /* Spartan-II Slave Parallel Generic Implementation */
144
145 static int Spartan2_sp_load (Xilinx_desc * desc, void *buf, size_t bsize)
146 {
147         int ret_val = FPGA_FAIL;        /* assume the worst */
148         Xilinx_Spartan2_Slave_Parallel_fns *fn = desc->iface_fns;
149
150         PRINTF ("%s: start with interface functions @ 0x%p\n",
151                         __FUNCTION__, fn);
152
153         if (fn) {
154                 size_t bytecount = 0;
155                 unsigned char *data = (unsigned char *) buf;
156                 int cookie = desc->cookie;      /* make a local copy */
157                 unsigned long ts;               /* timestamp */
158
159                 PRINTF ("%s: Function Table:\n"
160                                 "ptr:\t0x%p\n"
161                                 "struct: 0x%p\n"
162                                 "pre: 0x%p\n"
163                                 "pgm:\t0x%p\n"
164                                 "init:\t0x%p\n"
165                                 "err:\t0x%p\n"
166                                 "clk:\t0x%p\n"
167                                 "cs:\t0x%p\n"
168                                 "wr:\t0x%p\n"
169                                 "read data:\t0x%p\n"
170                                 "write data:\t0x%p\n"
171                                 "busy:\t0x%p\n"
172                                 "abort:\t0x%p\n",
173                                 "post:\t0x%p\n\n",
174                                 __FUNCTION__, &fn, fn, fn->pre, fn->pgm, fn->init, fn->err,
175                                 fn->clk, fn->cs, fn->wr, fn->rdata, fn->wdata, fn->busy,
176                                 fn->abort, fn->post);
177
178                 /*
179                  * This code is designed to emulate the "Express Style"
180                  * Continuous Data Loading in Slave Parallel Mode for
181                  * the Spartan-II Family.
182                  */
183 #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
184                 printf ("Loading FPGA Device %d...\n", cookie);
185 #endif
186                 /*
187                  * Run the pre configuration function if there is one.
188                  */
189                 if (*fn->pre) {
190                         (*fn->pre) (cookie);
191                 }
192
193                 /* Establish the initial state */
194                 (*fn->pgm) (TRUE, TRUE, cookie);        /* Assert the program, commit */
195
196                 /* Get ready for the burn */
197                 CONFIG_FPGA_DELAY ();
198                 (*fn->pgm) (FALSE, TRUE, cookie);       /* Deassert the program, commit */
199
200                 ts = get_timer (0);             /* get current time */
201                 /* Now wait for INIT and BUSY to go high */
202                 do {
203                         CONFIG_FPGA_DELAY ();
204                         if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) {    /* check the time */
205                                 puts ("** Timeout waiting for INIT to clear.\n");
206                                 (*fn->abort) (cookie);  /* abort the burn */
207                                 return FPGA_FAIL;
208                         }
209                 } while ((*fn->init) (cookie) && (*fn->busy) (cookie));
210
211                 (*fn->wr) (TRUE, TRUE, cookie); /* Assert write, commit */
212                 (*fn->cs) (TRUE, TRUE, cookie); /* Assert chip select, commit */
213                 (*fn->clk) (TRUE, TRUE, cookie);        /* Assert the clock pin */
214
215                 /* Load the data */
216                 while (bytecount < bsize) {
217                         /* XXX - do we check for an Ctrl-C press in here ??? */
218                         /* XXX - Check the error bit? */
219
220                         (*fn->wdata) (data[bytecount++], TRUE, cookie); /* write the data */
221                         CONFIG_FPGA_DELAY ();
222                         (*fn->clk) (FALSE, TRUE, cookie);       /* Deassert the clock pin */
223                         CONFIG_FPGA_DELAY ();
224                         (*fn->clk) (TRUE, TRUE, cookie);        /* Assert the clock pin */
225
226 #ifdef CONFIG_SYS_FPGA_CHECK_BUSY
227                         ts = get_timer (0);     /* get current time */
228                         while ((*fn->busy) (cookie)) {
229                                 /* XXX - we should have a check in here somewhere to
230                                  * make sure we aren't busy forever... */
231
232                                 CONFIG_FPGA_DELAY ();
233                                 (*fn->clk) (FALSE, TRUE, cookie);       /* Deassert the clock pin */
234                                 CONFIG_FPGA_DELAY ();
235                                 (*fn->clk) (TRUE, TRUE, cookie);        /* Assert the clock pin */
236
237                                 if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) {    /* check the time */
238                                         puts ("** Timeout waiting for BUSY to clear.\n");
239                                         (*fn->abort) (cookie);  /* abort the burn */
240                                         return FPGA_FAIL;
241                                 }
242                         }
243 #endif
244
245 #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
246                         if (bytecount % (bsize / 40) == 0)
247                                 putc ('.');             /* let them know we are alive */
248 #endif
249                 }
250
251                 CONFIG_FPGA_DELAY ();
252                 (*fn->cs) (FALSE, TRUE, cookie);        /* Deassert the chip select */
253                 (*fn->wr) (FALSE, TRUE, cookie);        /* Deassert the write pin */
254
255 #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
256                 putc ('\n');                    /* terminate the dotted line */
257 #endif
258
259                 /* now check for done signal */
260                 ts = get_timer (0);             /* get current time */
261                 ret_val = FPGA_SUCCESS;
262                 while ((*fn->done) (cookie) == FPGA_FAIL) {
263
264                         CONFIG_FPGA_DELAY ();
265                         (*fn->clk) (FALSE, TRUE, cookie);       /* Deassert the clock pin */
266                         CONFIG_FPGA_DELAY ();
267                         (*fn->clk) (TRUE, TRUE, cookie);        /* Assert the clock pin */
268
269                         if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) {    /* check the time */
270                                 puts ("** Timeout waiting for DONE to clear.\n");
271                                 (*fn->abort) (cookie);  /* abort the burn */
272                                 ret_val = FPGA_FAIL;
273                                 break;
274                         }
275                 }
276
277                 /*
278                  * Run the post configuration function if there is one.
279                  */
280                 if (*fn->post)
281                         (*fn->post) (cookie);
282
283 #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
284                 if (ret_val == FPGA_SUCCESS)
285                         puts ("Done.\n");
286                 else
287                         puts ("Fail.\n");
288 #endif
289
290         } else {
291                 printf ("%s: NULL Interface function table!\n", __FUNCTION__);
292         }
293
294         return ret_val;
295 }
296
297 static int Spartan2_sp_dump (Xilinx_desc * desc, void *buf, size_t bsize)
298 {
299         int ret_val = FPGA_FAIL;        /* assume the worst */
300         Xilinx_Spartan2_Slave_Parallel_fns *fn = desc->iface_fns;
301
302         if (fn) {
303                 unsigned char *data = (unsigned char *) buf;
304                 size_t bytecount = 0;
305                 int cookie = desc->cookie;      /* make a local copy */
306
307                 printf ("Starting Dump of FPGA Device %d...\n", cookie);
308
309                 (*fn->cs) (TRUE, TRUE, cookie); /* Assert chip select, commit */
310                 (*fn->clk) (TRUE, TRUE, cookie);        /* Assert the clock pin */
311
312                 /* dump the data */
313                 while (bytecount < bsize) {
314                         /* XXX - do we check for an Ctrl-C press in here ??? */
315
316                         (*fn->clk) (FALSE, TRUE, cookie);       /* Deassert the clock pin */
317                         (*fn->clk) (TRUE, TRUE, cookie);        /* Assert the clock pin */
318                         (*fn->rdata) (&(data[bytecount++]), cookie);    /* read the data */
319 #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
320                         if (bytecount % (bsize / 40) == 0)
321                                 putc ('.');             /* let them know we are alive */
322 #endif
323                 }
324
325                 (*fn->cs) (FALSE, FALSE, cookie);       /* Deassert the chip select */
326                 (*fn->clk) (FALSE, TRUE, cookie);       /* Deassert the clock pin */
327                 (*fn->clk) (TRUE, TRUE, cookie);        /* Assert the clock pin */
328
329 #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
330                 putc ('\n');                    /* terminate the dotted line */
331 #endif
332                 puts ("Done.\n");
333
334                 /* XXX - checksum the data? */
335         } else {
336                 printf ("%s: NULL Interface function table!\n", __FUNCTION__);
337         }
338
339         return ret_val;
340 }
341
342
343 static int Spartan2_sp_reloc (Xilinx_desc * desc, ulong reloc_offset)
344 {
345         int ret_val = FPGA_FAIL;        /* assume the worst */
346         Xilinx_Spartan2_Slave_Parallel_fns *fn_r, *fn =
347                         (Xilinx_Spartan2_Slave_Parallel_fns *) (desc->iface_fns);
348
349         if (fn) {
350                 ulong addr;
351
352                 /* Get the relocated table address */
353                 addr = (ulong) fn + reloc_offset;
354                 fn_r = (Xilinx_Spartan2_Slave_Parallel_fns *) addr;
355
356                 if (!fn_r->relocated) {
357
358                         if (memcmp (fn_r, fn,
359                                                 sizeof (Xilinx_Spartan2_Slave_Parallel_fns))
360                                 == 0) {
361                                 /* good copy of the table, fix the descriptor pointer */
362                                 desc->iface_fns = fn_r;
363                         } else {
364                                 PRINTF ("%s: Invalid function table at 0x%p\n",
365                                                 __FUNCTION__, fn_r);
366                                 return FPGA_FAIL;
367                         }
368
369                         PRINTF ("%s: Relocating descriptor at 0x%p\n", __FUNCTION__,
370                                         desc);
371
372                         addr = (ulong) (fn->pre) + reloc_offset;
373                         fn_r->pre = (Xilinx_pre_fn) addr;
374
375                         addr = (ulong) (fn->pgm) + reloc_offset;
376                         fn_r->pgm = (Xilinx_pgm_fn) addr;
377
378                         addr = (ulong) (fn->init) + reloc_offset;
379                         fn_r->init = (Xilinx_init_fn) addr;
380
381                         addr = (ulong) (fn->done) + reloc_offset;
382                         fn_r->done = (Xilinx_done_fn) addr;
383
384                         addr = (ulong) (fn->clk) + reloc_offset;
385                         fn_r->clk = (Xilinx_clk_fn) addr;
386
387                         addr = (ulong) (fn->err) + reloc_offset;
388                         fn_r->err = (Xilinx_err_fn) addr;
389
390                         addr = (ulong) (fn->cs) + reloc_offset;
391                         fn_r->cs = (Xilinx_cs_fn) addr;
392
393                         addr = (ulong) (fn->wr) + reloc_offset;
394                         fn_r->wr = (Xilinx_wr_fn) addr;
395
396                         addr = (ulong) (fn->rdata) + reloc_offset;
397                         fn_r->rdata = (Xilinx_rdata_fn) addr;
398
399                         addr = (ulong) (fn->wdata) + reloc_offset;
400                         fn_r->wdata = (Xilinx_wdata_fn) addr;
401
402                         addr = (ulong) (fn->busy) + reloc_offset;
403                         fn_r->busy = (Xilinx_busy_fn) addr;
404
405                         addr = (ulong) (fn->abort) + reloc_offset;
406                         fn_r->abort = (Xilinx_abort_fn) addr;
407
408                         if (fn->post) {
409                                 addr = (ulong) (fn->post) + reloc_offset;
410                                 fn_r->post = (Xilinx_post_fn) addr;
411                         }
412
413                         fn_r->relocated = TRUE;
414
415                 } else {
416                         /* this table has already been moved */
417                         /* XXX - should check to see if the descriptor is correct */
418                         desc->iface_fns = fn_r;
419                 }
420
421                 ret_val = FPGA_SUCCESS;
422         } else {
423                 printf ("%s: NULL Interface function table!\n", __FUNCTION__);
424         }
425
426         return ret_val;
427
428 }
429
430 /* ------------------------------------------------------------------------- */
431
432 static int Spartan2_ss_load (Xilinx_desc * desc, void *buf, size_t bsize)
433 {
434         int ret_val = FPGA_FAIL;        /* assume the worst */
435         Xilinx_Spartan2_Slave_Serial_fns *fn = desc->iface_fns;
436         int i;
437         unsigned char val;
438
439         PRINTF ("%s: start with interface functions @ 0x%p\n",
440                         __FUNCTION__, fn);
441
442         if (fn) {
443                 size_t bytecount = 0;
444                 unsigned char *data = (unsigned char *) buf;
445                 int cookie = desc->cookie;      /* make a local copy */
446                 unsigned long ts;               /* timestamp */
447
448                 PRINTF ("%s: Function Table:\n"
449                                 "ptr:\t0x%p\n"
450                                 "struct: 0x%p\n"
451                                 "pgm:\t0x%p\n"
452                                 "init:\t0x%p\n"
453                                 "clk:\t0x%p\n"
454                                 "wr:\t0x%p\n"
455                                 "done:\t0x%p\n\n",
456                                 __FUNCTION__, &fn, fn, fn->pgm, fn->init,
457                                 fn->clk, fn->wr, fn->done);
458 #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
459                 printf ("Loading FPGA Device %d...\n", cookie);
460 #endif
461
462                 /*
463                  * Run the pre configuration function if there is one.
464                  */
465                 if (*fn->pre) {
466                         (*fn->pre) (cookie);
467                 }
468
469                 /* Establish the initial state */
470                 (*fn->pgm) (TRUE, TRUE, cookie);        /* Assert the program, commit */
471
472                 /* Wait for INIT state (init low)                            */
473                 ts = get_timer (0);             /* get current time */
474                 do {
475                         CONFIG_FPGA_DELAY ();
476                         if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) {    /* check the time */
477                                 puts ("** Timeout waiting for INIT to start.\n");
478                                 return FPGA_FAIL;
479                         }
480                 } while (!(*fn->init) (cookie));
481
482                 /* Get ready for the burn */
483                 CONFIG_FPGA_DELAY ();
484                 (*fn->pgm) (FALSE, TRUE, cookie);       /* Deassert the program, commit */
485
486                 ts = get_timer (0);             /* get current time */
487                 /* Now wait for INIT to go high */
488                 do {
489                         CONFIG_FPGA_DELAY ();
490                         if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) {    /* check the time */
491                                 puts ("** Timeout waiting for INIT to clear.\n");
492                                 return FPGA_FAIL;
493                         }
494                 } while ((*fn->init) (cookie));
495
496                 /* Load the data */
497                 while (bytecount < bsize) {
498
499                         /* Xilinx detects an error if INIT goes low (active)
500                            while DONE is low (inactive) */
501                         if ((*fn->done) (cookie) == 0 && (*fn->init) (cookie)) {
502                                 puts ("** CRC error during FPGA load.\n");
503                                 return (FPGA_FAIL);
504                         }
505                         val = data [bytecount ++];
506                         i = 8;
507                         do {
508                                 /* Deassert the clock */
509                                 (*fn->clk) (FALSE, TRUE, cookie);
510                                 CONFIG_FPGA_DELAY ();
511                                 /* Write data */
512                                 (*fn->wr) ((val & 0x80), TRUE, cookie);
513                                 CONFIG_FPGA_DELAY ();
514                                 /* Assert the clock */
515                                 (*fn->clk) (TRUE, TRUE, cookie);
516                                 CONFIG_FPGA_DELAY ();
517                                 val <<= 1;
518                                 i --;
519                         } while (i > 0);
520
521 #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
522                         if (bytecount % (bsize / 40) == 0)
523                                 putc ('.');             /* let them know we are alive */
524 #endif
525                 }
526
527                 CONFIG_FPGA_DELAY ();
528
529 #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
530                 putc ('\n');                    /* terminate the dotted line */
531 #endif
532
533                 /* now check for done signal */
534                 ts = get_timer (0);             /* get current time */
535                 ret_val = FPGA_SUCCESS;
536                 (*fn->wr) (TRUE, TRUE, cookie);
537
538                 while (! (*fn->done) (cookie)) {
539
540                         CONFIG_FPGA_DELAY ();
541                         (*fn->clk) (FALSE, TRUE, cookie);       /* Deassert the clock pin */
542                         CONFIG_FPGA_DELAY ();
543                         (*fn->clk) (TRUE, TRUE, cookie);        /* Assert the clock pin */
544
545                         putc ('*');
546
547                         if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) {    /* check the time */
548                                 puts ("** Timeout waiting for DONE to clear.\n");
549                                 ret_val = FPGA_FAIL;
550                                 break;
551                         }
552                 }
553                 putc ('\n');                    /* terminate the dotted line */
554
555                 /*
556                  * Run the post configuration function if there is one.
557                  */
558                 if (*fn->post)
559                         (*fn->post) (cookie);
560
561 #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
562                 if (ret_val == FPGA_SUCCESS)
563                         puts ("Done.\n");
564                 else
565                         puts ("Fail.\n");
566 #endif
567
568         } else {
569                 printf ("%s: NULL Interface function table!\n", __FUNCTION__);
570         }
571
572         return ret_val;
573 }
574
575 static int Spartan2_ss_dump (Xilinx_desc * desc, void *buf, size_t bsize)
576 {
577         /* Readback is only available through the Slave Parallel and         */
578         /* boundary-scan interfaces.                                         */
579         printf ("%s: Slave Serial Dumping is unavailable\n",
580                         __FUNCTION__);
581         return FPGA_FAIL;
582 }
583
584 static int Spartan2_ss_reloc (Xilinx_desc * desc, ulong reloc_offset)
585 {
586         int ret_val = FPGA_FAIL;        /* assume the worst */
587         Xilinx_Spartan2_Slave_Serial_fns *fn_r, *fn =
588                         (Xilinx_Spartan2_Slave_Serial_fns *) (desc->iface_fns);
589
590         if (fn) {
591                 ulong addr;
592
593                 /* Get the relocated table address */
594                 addr = (ulong) fn + reloc_offset;
595                 fn_r = (Xilinx_Spartan2_Slave_Serial_fns *) addr;
596
597                 if (!fn_r->relocated) {
598
599                         if (memcmp (fn_r, fn,
600                                                 sizeof (Xilinx_Spartan2_Slave_Serial_fns))
601                                 == 0) {
602                                 /* good copy of the table, fix the descriptor pointer */
603                                 desc->iface_fns = fn_r;
604                         } else {
605                                 PRINTF ("%s: Invalid function table at 0x%p\n",
606                                                 __FUNCTION__, fn_r);
607                                 return FPGA_FAIL;
608                         }
609
610                         PRINTF ("%s: Relocating descriptor at 0x%p\n", __FUNCTION__,
611                                         desc);
612
613                         if (fn->pre) {
614                                 addr = (ulong) (fn->pre) + reloc_offset;
615                                 fn_r->pre = (Xilinx_pre_fn) addr;
616                         }
617
618                         addr = (ulong) (fn->pgm) + reloc_offset;
619                         fn_r->pgm = (Xilinx_pgm_fn) addr;
620
621                         addr = (ulong) (fn->init) + reloc_offset;
622                         fn_r->init = (Xilinx_init_fn) addr;
623
624                         addr = (ulong) (fn->done) + reloc_offset;
625                         fn_r->done = (Xilinx_done_fn) addr;
626
627                         addr = (ulong) (fn->clk) + reloc_offset;
628                         fn_r->clk = (Xilinx_clk_fn) addr;
629
630                         addr = (ulong) (fn->wr) + reloc_offset;
631                         fn_r->wr = (Xilinx_wr_fn) addr;
632
633                         if (fn->post) {
634                                 addr = (ulong) (fn->post) + reloc_offset;
635                                 fn_r->post = (Xilinx_post_fn) addr;
636                         }
637
638                         fn_r->relocated = TRUE;
639
640                 } else {
641                         /* this table has already been moved */
642                         /* XXX - should check to see if the descriptor is correct */
643                         desc->iface_fns = fn_r;
644                 }
645
646                 ret_val = FPGA_SUCCESS;
647         } else {
648                 printf ("%s: NULL Interface function table!\n", __FUNCTION__);
649         }
650
651         return ret_val;
652
653 }