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