Merge branch 'cleanups' into next
[platform/kernel/u-boot.git] / drivers / fpga / 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                 /*
285                  * Run the post configuration function if there is one.
286                  */
287                 if (*fn->post)
288                         (*fn->post) (cookie);
289
290 #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
291                 if (ret_val == FPGA_SUCCESS)
292                         puts ("Done.\n");
293                 else
294                         puts ("Fail.\n");
295 #endif
296
297         } else {
298                 printf ("%s: NULL Interface function table!\n", __FUNCTION__);
299         }
300
301         return ret_val;
302 }
303
304 static int Spartan3_sp_dump (Xilinx_desc * desc, void *buf, size_t bsize)
305 {
306         int ret_val = FPGA_FAIL;        /* assume the worst */
307         Xilinx_Spartan3_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 Spartan3_sp_reloc (Xilinx_desc * desc, ulong reloc_offset)
351 {
352         int ret_val = FPGA_FAIL;        /* assume the worst */
353         Xilinx_Spartan3_Slave_Parallel_fns *fn_r, *fn =
354                         (Xilinx_Spartan3_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_Spartan3_Slave_Parallel_fns *) addr;
362
363                 if (!fn_r->relocated) {
364
365                         if (memcmp (fn_r, fn,
366                                                 sizeof (Xilinx_Spartan3_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 Spartan3_ss_load (Xilinx_desc * desc, void *buf, size_t bsize)
438 {
439         int ret_val = FPGA_FAIL;        /* assume the worst */
440         Xilinx_Spartan3_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 #ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
569                 if (ret_val == FPGA_SUCCESS)
570                         puts ("Done.\n");
571                 else
572                         puts ("Fail.\n");
573 #endif
574
575         } else {
576                 printf ("%s: NULL Interface function table!\n", __FUNCTION__);
577         }
578
579         return ret_val;
580 }
581
582 static int Spartan3_ss_dump (Xilinx_desc * desc, void *buf, size_t bsize)
583 {
584         /* Readback is only available through the Slave Parallel and         */
585         /* boundary-scan interfaces.                                         */
586         printf ("%s: Slave Serial Dumping is unavailable\n",
587                         __FUNCTION__);
588         return FPGA_FAIL;
589 }
590
591 static int Spartan3_ss_reloc (Xilinx_desc * desc, ulong reloc_offset)
592 {
593         int ret_val = FPGA_FAIL;        /* assume the worst */
594         Xilinx_Spartan3_Slave_Serial_fns *fn_r, *fn =
595                         (Xilinx_Spartan3_Slave_Serial_fns *) (desc->iface_fns);
596
597         if (fn) {
598                 ulong addr;
599
600                 /* Get the relocated table address */
601                 addr = (ulong) fn + reloc_offset;
602                 fn_r = (Xilinx_Spartan3_Slave_Serial_fns *) addr;
603
604                 if (!fn_r->relocated) {
605
606                         if (memcmp (fn_r, fn,
607                                                 sizeof (Xilinx_Spartan3_Slave_Serial_fns))
608                                 == 0) {
609                                 /* good copy of the table, fix the descriptor pointer */
610                                 desc->iface_fns = fn_r;
611                         } else {
612                                 PRINTF ("%s: Invalid function table at 0x%p\n",
613                                                 __FUNCTION__, fn_r);
614                                 return FPGA_FAIL;
615                         }
616
617                         PRINTF ("%s: Relocating descriptor at 0x%p\n", __FUNCTION__,
618                                         desc);
619
620                         if (fn->pre) {
621                                 addr = (ulong) (fn->pre) + reloc_offset;
622                                 fn_r->pre = (Xilinx_pre_fn) addr;
623                         }
624
625                         addr = (ulong) (fn->pgm) + reloc_offset;
626                         fn_r->pgm = (Xilinx_pgm_fn) addr;
627
628                         addr = (ulong) (fn->init) + reloc_offset;
629                         fn_r->init = (Xilinx_init_fn) addr;
630
631                         addr = (ulong) (fn->done) + reloc_offset;
632                         fn_r->done = (Xilinx_done_fn) addr;
633
634                         addr = (ulong) (fn->clk) + reloc_offset;
635                         fn_r->clk = (Xilinx_clk_fn) addr;
636
637                         addr = (ulong) (fn->wr) + reloc_offset;
638                         fn_r->wr = (Xilinx_wr_fn) addr;
639
640                         if (fn->post) {
641                                 addr = (ulong) (fn->post) + reloc_offset;
642                                 fn_r->post = (Xilinx_post_fn) addr;
643                         }
644
645                         fn_r->relocated = TRUE;
646
647                 } else {
648                         /* this table has already been moved */
649                         /* XXX - should check to see if the descriptor is correct */
650                         desc->iface_fns = fn_r;
651                 }
652
653                 ret_val = FPGA_SUCCESS;
654         } else {
655                 printf ("%s: NULL Interface function table!\n", __FUNCTION__);
656         }
657
658         return ret_val;
659
660 }