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