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