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 } 661