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