]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/fpga/spartan2.c
f5ba7fc041e61684bb7d7784d4f206f37b6ac91c
[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                         /* XXX - we should have a check in here somewhere to
264                          * make sure we aren't busy forever... */
265
266                         CONFIG_FPGA_DELAY ();
267                         (*fn->clk) (FALSE, TRUE, cookie);       /* Deassert the clock pin */
268                         CONFIG_FPGA_DELAY ();
269                         (*fn->clk) (TRUE, TRUE, cookie);        /* Assert the clock pin */
270
271                         if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) {    /* check the time */
272                                 puts ("** Timeout waiting for DONE to clear.\n");
273                                 (*fn->abort) (cookie);  /* abort the burn */
274                                 ret_val = FPGA_FAIL;
275                                 break;
276                         }
277                 }
278
279                 if (ret_val == FPGA_SUCCESS) {
280 #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
281                         puts ("Done.\n");
282 #endif
283                 }
284                 /*
285                  * Run the post configuration function if there is one.
286                  */
287                 if (*fn->post) {
288                         (*fn->post) (cookie);
289                 }
290
291                 else {
292 #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
293                         puts ("Fail.\n");
294 #endif
295                 }
296
297         } else {
298                 printf ("%s: NULL Interface function table!\n", __FUNCTION__);
299         }
300
301         return ret_val;
302 }
303
304 static int Spartan2_sp_dump (Xilinx_desc * desc, void *buf, size_t bsize)
305 {
306         int ret_val = FPGA_FAIL;        /* assume the worst */
307         Xilinx_Spartan2_Slave_Parallel_fns *fn = desc->iface_fns;
308
309         if (fn) {
310                 unsigned char *data = (unsigned char *) buf;
311                 size_t bytecount = 0;
312                 int cookie = desc->cookie;      /* make a local copy */
313
314                 printf ("Starting Dump of FPGA Device %d...\n", cookie);
315
316                 (*fn->cs) (TRUE, TRUE, cookie); /* Assert chip select, commit */
317                 (*fn->clk) (TRUE, TRUE, cookie);        /* Assert the clock pin */
318
319                 /* dump the data */
320                 while (bytecount < bsize) {
321                         /* XXX - do we check for an Ctrl-C press in here ??? */
322
323                         (*fn->clk) (FALSE, TRUE, cookie);       /* Deassert the clock pin */
324                         (*fn->clk) (TRUE, TRUE, cookie);        /* Assert the clock pin */
325                         (*fn->rdata) (&(data[bytecount++]), cookie);    /* read the data */
326 #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
327                         if (bytecount % (bsize / 40) == 0)
328                                 putc ('.');             /* let them know we are alive */
329 #endif
330                 }
331
332                 (*fn->cs) (FALSE, FALSE, cookie);       /* Deassert the chip select */
333                 (*fn->clk) (FALSE, TRUE, cookie);       /* Deassert the clock pin */
334                 (*fn->clk) (TRUE, TRUE, cookie);        /* Assert the clock pin */
335
336 #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
337                 putc ('\n');                    /* terminate the dotted line */
338 #endif
339                 puts ("Done.\n");
340
341                 /* XXX - checksum the data? */
342         } else {
343                 printf ("%s: NULL Interface function table!\n", __FUNCTION__);
344         }
345
346         return ret_val;
347 }
348
349
350 static int Spartan2_sp_reloc (Xilinx_desc * desc, ulong reloc_offset)
351 {
352         int ret_val = FPGA_FAIL;        /* assume the worst */
353         Xilinx_Spartan2_Slave_Parallel_fns *fn_r, *fn =
354                         (Xilinx_Spartan2_Slave_Parallel_fns *) (desc->iface_fns);
355
356         if (fn) {
357                 ulong addr;
358
359                 /* Get the relocated table address */
360                 addr = (ulong) fn + reloc_offset;
361                 fn_r = (Xilinx_Spartan2_Slave_Parallel_fns *) addr;
362
363                 if (!fn_r->relocated) {
364
365                         if (memcmp (fn_r, fn,
366                                                 sizeof (Xilinx_Spartan2_Slave_Parallel_fns))
367                                 == 0) {
368                                 /* good copy of the table, fix the descriptor pointer */
369                                 desc->iface_fns = fn_r;
370                         } else {
371                                 PRINTF ("%s: Invalid function table at 0x%p\n",
372                                                 __FUNCTION__, fn_r);
373                                 return FPGA_FAIL;
374                         }
375
376                         PRINTF ("%s: Relocating descriptor at 0x%p\n", __FUNCTION__,
377                                         desc);
378
379                         addr = (ulong) (fn->pre) + reloc_offset;
380                         fn_r->pre = (Xilinx_pre_fn) addr;
381
382                         addr = (ulong) (fn->pgm) + reloc_offset;
383                         fn_r->pgm = (Xilinx_pgm_fn) addr;
384
385                         addr = (ulong) (fn->init) + reloc_offset;
386                         fn_r->init = (Xilinx_init_fn) addr;
387
388                         addr = (ulong) (fn->done) + reloc_offset;
389                         fn_r->done = (Xilinx_done_fn) addr;
390
391                         addr = (ulong) (fn->clk) + reloc_offset;
392                         fn_r->clk = (Xilinx_clk_fn) addr;
393
394                         addr = (ulong) (fn->err) + reloc_offset;
395                         fn_r->err = (Xilinx_err_fn) addr;
396
397                         addr = (ulong) (fn->cs) + reloc_offset;
398                         fn_r->cs = (Xilinx_cs_fn) addr;
399
400                         addr = (ulong) (fn->wr) + reloc_offset;
401                         fn_r->wr = (Xilinx_wr_fn) addr;
402
403                         addr = (ulong) (fn->rdata) + reloc_offset;
404                         fn_r->rdata = (Xilinx_rdata_fn) addr;
405
406                         addr = (ulong) (fn->wdata) + reloc_offset;
407                         fn_r->wdata = (Xilinx_wdata_fn) addr;
408
409                         addr = (ulong) (fn->busy) + reloc_offset;
410                         fn_r->busy = (Xilinx_busy_fn) addr;
411
412                         addr = (ulong) (fn->abort) + reloc_offset;
413                         fn_r->abort = (Xilinx_abort_fn) addr;
414
415                         addr = (ulong) (fn->post) + reloc_offset;
416                         fn_r->post = (Xilinx_post_fn) addr;
417
418                         fn_r->relocated = TRUE;
419
420                 } else {
421                         /* this table has already been moved */
422                         /* XXX - should check to see if the descriptor is correct */
423                         desc->iface_fns = fn_r;
424                 }
425
426                 ret_val = FPGA_SUCCESS;
427         } else {
428                 printf ("%s: NULL Interface function table!\n", __FUNCTION__);
429         }
430
431         return ret_val;
432
433 }
434
435 /* ------------------------------------------------------------------------- */
436
437 static int Spartan2_ss_load (Xilinx_desc * desc, void *buf, size_t bsize)
438 {
439         int ret_val = FPGA_FAIL;        /* assume the worst */
440         Xilinx_Spartan2_Slave_Serial_fns *fn = desc->iface_fns;
441         int i;
442         unsigned char val;
443
444         PRINTF ("%s: start with interface functions @ 0x%p\n",
445                         __FUNCTION__, fn);
446
447         if (fn) {
448                 size_t bytecount = 0;
449                 unsigned char *data = (unsigned char *) buf;
450                 int cookie = desc->cookie;      /* make a local copy */
451                 unsigned long ts;               /* timestamp */
452
453                 PRINTF ("%s: Function Table:\n"
454                                 "ptr:\t0x%p\n"
455                                 "struct: 0x%p\n"
456                                 "pgm:\t0x%p\n"
457                                 "init:\t0x%p\n"
458                                 "clk:\t0x%p\n"
459                                 "wr:\t0x%p\n"
460                                 "done:\t0x%p\n\n",
461                                 __FUNCTION__, &fn, fn, fn->pgm, fn->init,
462                                 fn->clk, fn->wr, fn->done);
463 #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
464                 printf ("Loading FPGA Device %d...\n", cookie);
465 #endif
466
467                 /*
468                  * Run the pre configuration function if there is one.
469                  */
470                 if (*fn->pre) {
471                         (*fn->pre) (cookie);
472                 }
473
474                 /* Establish the initial state */
475                 (*fn->pgm) (TRUE, TRUE, cookie);        /* Assert the program, commit */
476
477                 /* Wait for INIT state (init low)                            */
478                 ts = get_timer (0);             /* get current time */
479                 do {
480                         CONFIG_FPGA_DELAY ();
481                         if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) {    /* check the time */
482                                 puts ("** Timeout waiting for INIT to start.\n");
483                                 return FPGA_FAIL;
484                         }
485                 } while (!(*fn->init) (cookie));
486
487                 /* Get ready for the burn */
488                 CONFIG_FPGA_DELAY ();
489                 (*fn->pgm) (FALSE, TRUE, cookie);       /* Deassert the program, commit */
490
491                 ts = get_timer (0);             /* get current time */
492                 /* Now wait for INIT to go high */
493                 do {
494                         CONFIG_FPGA_DELAY ();
495                         if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) {    /* check the time */
496                                 puts ("** Timeout waiting for INIT to clear.\n");
497                                 return FPGA_FAIL;
498                         }
499                 } while ((*fn->init) (cookie));
500
501                 /* Load the data */
502                 while (bytecount < bsize) {
503
504                         /* Xilinx detects an error if INIT goes low (active)
505                            while DONE is low (inactive) */
506                         if ((*fn->done) (cookie) == 0 && (*fn->init) (cookie)) {
507                                 puts ("** CRC error during FPGA load.\n");
508                                 return (FPGA_FAIL);
509                         }
510                         val = data [bytecount ++];
511                         i = 8;
512                         do {
513                                 /* Deassert the clock */
514                                 (*fn->clk) (FALSE, TRUE, cookie);
515                                 CONFIG_FPGA_DELAY ();
516                                 /* Write data */
517                                 (*fn->wr) ((val & 0x80), TRUE, cookie);
518                                 CONFIG_FPGA_DELAY ();
519                                 /* Assert the clock */
520                                 (*fn->clk) (TRUE, TRUE, cookie);
521                                 CONFIG_FPGA_DELAY ();
522                                 val <<= 1;
523                                 i --;
524                         } while (i > 0);
525
526 #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
527                         if (bytecount % (bsize / 40) == 0)
528                                 putc ('.');             /* let them know we are alive */
529 #endif
530                 }
531
532                 CONFIG_FPGA_DELAY ();
533
534 #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
535                 putc ('\n');                    /* terminate the dotted line */
536 #endif
537
538                 /* now check for done signal */
539                 ts = get_timer (0);             /* get current time */
540                 ret_val = FPGA_SUCCESS;
541                 (*fn->wr) (TRUE, TRUE, cookie);
542
543                 while (! (*fn->done) (cookie)) {
544                         /* XXX - we should have a check in here somewhere to
545                          * make sure we aren't busy forever... */
546
547                         CONFIG_FPGA_DELAY ();
548                         (*fn->clk) (FALSE, TRUE, cookie);       /* Deassert the clock pin */
549                         CONFIG_FPGA_DELAY ();
550                         (*fn->clk) (TRUE, TRUE, cookie);        /* Assert the clock pin */
551
552                         putc ('*');
553
554                         if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) {    /* check the time */
555                                 puts ("** Timeout waiting for DONE to clear.\n");
556                                 ret_val = FPGA_FAIL;
557                                 break;
558                         }
559                 }
560                 putc ('\n');                    /* terminate the dotted line */
561
562                 /*
563                  * Run the post configuration function if there is one.
564                  */
565                 if (*fn->post) {
566                         (*fn->post) (cookie);
567                 }
568
569 #ifdef CONFIG_SYS_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 Spartan2_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 Spartan2_ss_reloc (Xilinx_desc * desc, ulong reloc_offset)
595 {
596         int ret_val = FPGA_FAIL;        /* assume the worst */
597         Xilinx_Spartan2_Slave_Serial_fns *fn_r, *fn =
598                         (Xilinx_Spartan2_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_Spartan2_Slave_Serial_fns *) addr;
606
607                 if (!fn_r->relocated) {
608
609                         if (memcmp (fn_r, fn,
610                                                 sizeof (Xilinx_Spartan2_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                         if (fn->pre) {
624                                 addr = (ulong) (fn->pre) + reloc_offset;
625                                 fn_r->pre = (Xilinx_pre_fn) addr;
626                         }
627
628                         addr = (ulong) (fn->pgm) + reloc_offset;
629                         fn_r->pgm = (Xilinx_pgm_fn) addr;
630
631                         addr = (ulong) (fn->init) + reloc_offset;
632                         fn_r->init = (Xilinx_init_fn) addr;
633
634                         addr = (ulong) (fn->done) + reloc_offset;
635                         fn_r->done = (Xilinx_done_fn) addr;
636
637                         addr = (ulong) (fn->clk) + reloc_offset;
638                         fn_r->clk = (Xilinx_clk_fn) addr;
639
640                         addr = (ulong) (fn->wr) + reloc_offset;
641                         fn_r->wr = (Xilinx_wr_fn) addr;
642
643                         if (fn->post) {
644                                 addr = (ulong) (fn->post) + reloc_offset;
645                                 fn_r->post = (Xilinx_post_fn) addr;
646                         }
647
648                         fn_r->relocated = TRUE;
649
650                 } else {
651                         /* this table has already been moved */
652                         /* XXX - should check to see if the descriptor is correct */
653                         desc->iface_fns = fn_r;
654                 }
655
656                 ret_val = FPGA_SUCCESS;
657         } else {
658                 printf ("%s: NULL Interface function table!\n", __FUNCTION__);
659         }
660
661         return ret_val;
662
663 }