/* terminate the FPGA load (parallel mode) */
static int spartan_parallel_finish(struct fpga_desc *desc)
{
	Xilinx_Spartan3_Slave_Parallel_fns *fn = desc->iface_fns;
	unsigned long timestamp;

	if (fn) {
		/* now check for done signal */
		timestamp = get_timer(0);	/* get current time */
		while (!(*fn->done) ()) {
			CONFIG_FPGA_DELAY ();
			(*fn->clk) (0);	/* Deassert the clock pin */
			CONFIG_FPGA_DELAY ();
			(*fn->clk) (1);	/* Assert the clock pin */

			if (get_timer(timestamp) > CFG_FPGA_WAIT) {
				printk("** Timeout waiting for DONE to clear. %d bytes\n", bytecount);
				(*fn->abort) ();	/* abort the burn */
				return -ETIMEDOUT;
			}
		}
		(*fn->cs) (0);	/* Deassert the chip select */
		(*fn->wr) (0);	/* Deassert the write pin */
		(*fn->post) (); /* release resources */
	}

	return 0;
}
/* terminate the FPGA load (serial mode) */
static int spartan_serial_finish(struct fpga_desc *desc)
{
	unsigned long timestamp;
	Xilinx_Spartan_Slave_Serial_fns *fn = desc->iface_fns;

	if (fn) {
		CONFIG_FPGA_DELAY ();

		/* now check for done signal */
		timestamp = get_timer(0);	/* get current time */
		(*fn->wr)(1);

		while (! (*fn->done)()) {
			CONFIG_FPGA_DELAY ();
			(*fn->clk)(0);	/* Deassert the clock pin */
			CONFIG_FPGA_DELAY ();
			(*fn->clk)(1);	/* Assert the clock pin */

			if (get_timer(timestamp) > CFG_FPGA_WAIT) {
				pr_debug("** Timeout waiting for DONE.\n");
				return -ETIMEDOUT;
			}
		}
	}
	return 0;
}
/**
 *  initialize the FPGA programming interface (parallel).
 *  return 0 if success, <0 if error detected
 */
static int spartan_parallel_init(struct fpga_desc *desc)
{
	int res = 0;
	Xilinx_Spartan3_Slave_Parallel_fns *fn = desc->iface_fns;

	if (fn) {
		unsigned long timestamp;
		/*
		 * Run the pre configuration function if there is one.
		 */
		if (*fn->pre) {
			if( (res = (*fn->pre) ()) ) return res;
		}
		mdelay(100);

		/* Establish the initial state */
		(*fn->pgm) (1);	/* Assert the program, commit */
		timestamp = get_timer(0);		/* get current time */
		/* Now wait for INIT to go down */
		do {
			CONFIG_FPGA_DELAY ();
			if (get_timer(timestamp) > CFG_FPGA_WAIT) {
				pr_debug("** Timeout waiting for INIT to set.\n");
				(*fn->abort) ();	/* abort the burn */
				return -ETIMEDOUT;
			}
		} while (!(*fn->init) () );


		/* Get ready for the burn */
		CONFIG_FPGA_DELAY ();
		(*fn->pgm) (0);	/* Deassert the program, commit */

		timestamp = get_timer (0);		/* get current time */
		/* Now wait for INIT and BUSY to go high */
		do {
			CONFIG_FPGA_DELAY ();
			if (get_timer(timestamp) > CFG_FPGA_WAIT) {
				pr_debug("** Timeout waiting for INIT to clear.\n");
				(*fn->abort) ();	/* abort the burn */
				return -ETIMEDOUT;
			}
		} while ((*fn->init) ());
		(*fn->wr) (1); /* Assert write, commit */
		(*fn->cs) (1); /* Assert chip select, commit */
		(*fn->clk) (1);	/* Assert the clock pin */
		bytecount = 0; // reset byte count
	}
	return 0;
}
/**
 *  initialize the FPGA programming interface (serial).
 *  return 0 if success, <0 if error detected
 */
static int spartan_serial_init(struct fpga_desc *desc)
{
	Xilinx_Spartan_Slave_Serial_fns *fn = desc->iface_fns;
	if (fn) {
		unsigned long timestamp;

		if (*fn->pre){
			(*fn->pre)(); /* Run the pre configuration function if there is one. */
		}

		/* Establish the initial state */
		(*fn->pgm)(1);	/* Assert the program, commit */

		/* Wait for INIT state (init low) */
		timestamp = get_timer(0);		/* get current time */
		do {
			CONFIG_FPGA_DELAY ();
			if (get_timer(timestamp) > CFG_FPGA_WAIT) {
				pr_debug("** Timeout waiting for INIT to start.\n");
				return -ETIMEDOUT;
			}
		} while (!(*fn->init)());

		/* Get ready for the burn */
		CONFIG_FPGA_DELAY ();
		(*fn->pgm)(0);	/* Deassert the program, commit */

		timestamp = get_timer(0);		/* get current time */
		/* Now wait for INIT to go high */
		do {
			CONFIG_FPGA_DELAY ();
			if (get_timer(timestamp) > CFG_FPGA_WAIT) {
				pr_debug("** Timeout waiting for INIT to clear.\n");
				return -ETIMEDOUT;
			}
		} while ((*fn->init)());

		bytecount = 0; /* reset byte count */
		return 0; /* success */
	}
	return -EINVAL;
}
/**
 *  program the FPGA (serial mode).
 *  return 0 if success, >0 while programming, <0 if error detected
 */
static size_t spartan_serial_load(struct fpga_desc *desc, const char* buf, size_t bsize)
{
	Xilinx_Spartan_Slave_Serial_fns *fn = desc->iface_fns;

	if (fn) {
		int i;
		unsigned char   val;
		size_t nbbyte = 0; /* init local counter */

		while (nbbyte < bsize) {
			/* Spartan signals an error if INIT goes low (active)
			   while DONE is low (inactive) */
			if ((*fn->done)() == 0 && (*fn->init)()) {
				printk("** CRC error during FPGA load.\n");
				return -ETIMEDOUT;
			}
			val = buf[nbbyte ++];
			bytecount++;
			i = 8;
			do {
				/* Deassert the clock */
				(*fn->clk)(0);
				CONFIG_FPGA_DELAY();
				/* Write data */
				(*fn->wr)(val & 0x80);
				CONFIG_FPGA_DELAY();
				/* Assert the clock */
				(*fn->clk)(1);
				CONFIG_FPGA_DELAY();
				val <<= 1;
				i --;
			} while (i > 0);
		}

		if (bytecount % 4096 == 0)
			printk(".");

		return bsize;
	}
	return -EINVAL;
}
/**
 *  program the FPGA (parallel mode).
 *  return 0 if success, >0 while programming, <0 if error detected
 */
static size_t spartan_parallel_load(struct fpga_desc *desc, const char* buf, size_t bsize)
{
	unsigned long flags;
	Xilinx_Spartan3_Slave_Parallel_fns *fn = desc->iface_fns;

	if (fn) {
		/* Load the data */
		size_t nbbyte = 0;

		raw_local_irq_save(flags);
		 while (nbbyte < bsize) {
			(*fn->clk) (1);	/* Assert the clock pin */
			CONFIG_FPGA_DELAY ();
 			(*fn->wdata) (buf[nbbyte++]); /* write the data */
			CONFIG_FPGA_DELAY ();
			(*fn->clk) (0);	/* Deassert the clock pin */
			bytecount++;
		}
		raw_local_irq_restore(flags);

		return bsize;
	}
	return -EINVAL;
}
Exemple #7
0
static int Spartan3_ss_load (Xilinx_desc * desc, void *buf, size_t bsize)
{
	int ret_val = FPGA_FAIL;	/* assume the worst */
	Xilinx_Spartan3_Slave_Serial_fns *fn = desc->iface_fns;
	int i;
	unsigned char val;

	PRINTF ("%s: start with interface functions @ 0x%p\n",
			__FUNCTION__, fn);

	if (fn) {
		size_t bytecount = 0;
		unsigned char *data = (unsigned char *) buf;
		int cookie = desc->cookie;	/* make a local copy */
		unsigned long ts;		/* timestamp */

		PRINTF ("%s: Function Table:\n"
				"ptr:\t0x%p\n"
				"struct: 0x%p\n"
				"pgm:\t0x%p\n"
				"init:\t0x%p\n"
				"clk:\t0x%p\n"
				"wr:\t0x%p\n"
				"done:\t0x%p\n\n",
				__FUNCTION__, &fn, fn, fn->pgm, fn->init,
				fn->clk, fn->wr, fn->done);
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
		printf ("Loading FPGA Device %d...\n", cookie);
#endif

		/*
		 * Run the pre configuration function if there is one.
		 */
		if (*fn->pre) {
			(*fn->pre) (cookie);
		}

		/* Establish the initial state */
		(*fn->pgm) (TRUE, TRUE, cookie);	/* Assert the program, commit */

		/* Wait for INIT state (init low)                            */
		ts = get_timer (0);		/* get current time */
		do {
			CONFIG_FPGA_DELAY ();
			if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) {	/* check the time */
				puts ("** Timeout waiting for INIT to start.\n");
				if (*fn->abort)
					(*fn->abort) (cookie);
				return FPGA_FAIL;
			}
		} while (!(*fn->init) (cookie));

		/* Get ready for the burn */
		CONFIG_FPGA_DELAY ();
		(*fn->pgm) (FALSE, TRUE, cookie);	/* Deassert the program, commit */

		ts = get_timer (0);		/* get current time */
		/* Now wait for INIT to go high */
		do {
			CONFIG_FPGA_DELAY ();
			if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) {	/* check the time */
				puts ("** Timeout waiting for INIT to clear.\n");
				if (*fn->abort)
					(*fn->abort) (cookie);
				return FPGA_FAIL;
			}
		} while ((*fn->init) (cookie));

		/* Load the data */
		if(*fn->bwr)
			(*fn->bwr) (data, bsize, TRUE, cookie);
		else {
			while (bytecount < bsize) {

				/* Xilinx detects an error if INIT goes low (active)
				   while DONE is low (inactive) */
				if ((*fn->done) (cookie) == 0 && (*fn->init) (cookie)) {
					puts ("** CRC error during FPGA load.\n");
					if (*fn->abort)
						(*fn->abort) (cookie);
					return (FPGA_FAIL);
				}
				val = data [bytecount ++];
				i = 8;
				do {
					/* Deassert the clock */
					(*fn->clk) (FALSE, TRUE, cookie);
					CONFIG_FPGA_DELAY ();
					/* Write data */
					(*fn->wr) ((val & 0x80), TRUE, cookie);
					CONFIG_FPGA_DELAY ();
					/* Assert the clock */
					(*fn->clk) (TRUE, TRUE, cookie);
					CONFIG_FPGA_DELAY ();
					val <<= 1;
					i --;
				} while (i > 0);

#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
				if (bytecount % (bsize / 40) == 0)
					putc ('.');		/* let them know we are alive */
#endif
			}
		}

		CONFIG_FPGA_DELAY ();

#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
		putc ('\n');			/* terminate the dotted line */
#endif

		/* now check for done signal */
		ts = get_timer (0);		/* get current time */
		ret_val = FPGA_SUCCESS;
		(*fn->wr) (TRUE, TRUE, cookie);

		while (! (*fn->done) (cookie)) {
			/* XXX - we should have a check in here somewhere to
			 * make sure we aren't busy forever... */

			CONFIG_FPGA_DELAY ();
			(*fn->clk) (FALSE, TRUE, cookie);	/* Deassert the clock pin */
			CONFIG_FPGA_DELAY ();
			(*fn->clk) (TRUE, TRUE, cookie);	/* Assert the clock pin */

			putc ('*');

			if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) {	/* check the time */
				puts ("** Timeout waiting for DONE to clear.\n");
				ret_val = FPGA_FAIL;
				break;
			}
		}
		putc ('\n');			/* terminate the dotted line */

		/*
		 * Run the post configuration function if there is one.
		 */
		if (*fn->post)
			(*fn->post) (cookie);

#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
		if (ret_val == FPGA_SUCCESS)
			puts ("Done.\n");
		else
			puts ("Fail.\n");
#endif

	} else {
		printf ("%s: NULL Interface function table!\n", __FUNCTION__);
	}

	return ret_val;
}
Exemple #8
0
static int Spartan3_sp_load (Xilinx_desc * desc, void *buf, size_t bsize)
{
	int ret_val = FPGA_FAIL;	/* assume the worst */
	Xilinx_Spartan3_Slave_Parallel_fns *fn = desc->iface_fns;

	PRINTF ("%s: start with interface functions @ 0x%p\n",
			__FUNCTION__, fn);

	if (fn) {
		size_t bytecount = 0;
		unsigned char *data = (unsigned char *) buf;
		int cookie = desc->cookie;	/* make a local copy */
		unsigned long ts;		/* timestamp */

		PRINTF ("%s: Function Table:\n"
				"ptr:\t0x%p\n"
				"struct: 0x%p\n"
				"pre: 0x%p\n"
				"pgm:\t0x%p\n"
				"init:\t0x%p\n"
				"err:\t0x%p\n"
				"clk:\t0x%p\n"
				"cs:\t0x%p\n"
				"wr:\t0x%p\n"
				"read data:\t0x%p\n"
				"write data:\t0x%p\n"
				"busy:\t0x%p\n"
				"abort:\t0x%p\n",
				"post:\t0x%p\n\n",
				__FUNCTION__, &fn, fn, fn->pre, fn->pgm, fn->init, fn->err,
				fn->clk, fn->cs, fn->wr, fn->rdata, fn->wdata, fn->busy,
				fn->abort, fn->post);

		/*
		 * This code is designed to emulate the "Express Style"
		 * Continuous Data Loading in Slave Parallel Mode for
		 * the Spartan-II Family.
		 */
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
		printf ("Loading FPGA Device %d...\n", cookie);
#endif
		/*
		 * Run the pre configuration function if there is one.
		 */
		if (*fn->pre) {
			(*fn->pre) (cookie);
		}

		/* Establish the initial state */
		(*fn->pgm) (TRUE, TRUE, cookie);	/* Assert the program, commit */

		/* Get ready for the burn */
		CONFIG_FPGA_DELAY ();
		(*fn->pgm) (FALSE, TRUE, cookie);	/* Deassert the program, commit */

		ts = get_timer (0);		/* get current time */
		/* Now wait for INIT and BUSY to go high */
		do {
			CONFIG_FPGA_DELAY ();
			if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) {	/* check the time */
				puts ("** Timeout waiting for INIT to clear.\n");
				(*fn->abort) (cookie);	/* abort the burn */
				return FPGA_FAIL;
			}
		} while ((*fn->init) (cookie) && (*fn->busy) (cookie));

		(*fn->wr) (TRUE, TRUE, cookie); /* Assert write, commit */
		(*fn->cs) (TRUE, TRUE, cookie); /* Assert chip select, commit */
		(*fn->clk) (TRUE, TRUE, cookie);	/* Assert the clock pin */

		/* Load the data */
		while (bytecount < bsize) {
			/* XXX - do we check for an Ctrl-C press in here ??? */
			/* XXX - Check the error bit? */

			(*fn->wdata) (data[bytecount++], TRUE, cookie); /* write the data */
			CONFIG_FPGA_DELAY ();
			(*fn->clk) (FALSE, TRUE, cookie);	/* Deassert the clock pin */
			CONFIG_FPGA_DELAY ();
			(*fn->clk) (TRUE, TRUE, cookie);	/* Assert the clock pin */

#ifdef CONFIG_SYS_FPGA_CHECK_BUSY
			ts = get_timer (0);	/* get current time */
			while ((*fn->busy) (cookie)) {
				/* XXX - we should have a check in here somewhere to
				 * make sure we aren't busy forever... */

				CONFIG_FPGA_DELAY ();
				(*fn->clk) (FALSE, TRUE, cookie);	/* Deassert the clock pin */
				CONFIG_FPGA_DELAY ();
				(*fn->clk) (TRUE, TRUE, cookie);	/* Assert the clock pin */

				if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) {	/* check the time */
					puts ("** Timeout waiting for BUSY to clear.\n");
					(*fn->abort) (cookie);	/* abort the burn */
					return FPGA_FAIL;
				}
			}
#endif

#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
			if (bytecount % (bsize / 40) == 0)
				putc ('.');		/* let them know we are alive */
#endif
		}

		CONFIG_FPGA_DELAY ();
		(*fn->cs) (FALSE, TRUE, cookie);	/* Deassert the chip select */
		(*fn->wr) (FALSE, TRUE, cookie);	/* Deassert the write pin */

#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
		putc ('\n');			/* terminate the dotted line */
#endif

		/* now check for done signal */
		ts = get_timer (0);		/* get current time */
		ret_val = FPGA_SUCCESS;
		while ((*fn->done) (cookie) == FPGA_FAIL) {
			/* XXX - we should have a check in here somewhere to
			 * make sure we aren't busy forever... */

			CONFIG_FPGA_DELAY ();
			(*fn->clk) (FALSE, TRUE, cookie);	/* Deassert the clock pin */
			CONFIG_FPGA_DELAY ();
			(*fn->clk) (TRUE, TRUE, cookie);	/* Assert the clock pin */

			if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) {	/* check the time */
				puts ("** Timeout waiting for DONE to clear.\n");
				(*fn->abort) (cookie);	/* abort the burn */
				ret_val = FPGA_FAIL;
				break;
			}
		}

		/*
		 * Run the post configuration function if there is one.
		 */
		if (*fn->post)
			(*fn->post) (cookie);

#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
		if (ret_val == FPGA_SUCCESS)
			puts ("Done.\n");
		else
			puts ("Fail.\n");
#endif

	} else {
		printf ("%s: NULL Interface function table!\n", __FUNCTION__);
	}

	return ret_val;
}
static int ACEX1K_ps_load (Altera_desc * desc, void *buf, size_t bsize)
{
	int ret_val = FPGA_FAIL;	/* assume the worst */
	Altera_ACEX1K_Passive_Serial_fns *fn = desc->iface_fns;
	int i;

	PRINTF ("%s: start with interface functions @ 0x%p\n",
			__FUNCTION__, fn);

	if (fn) {
		size_t bytecount = 0;
		unsigned char *data = (unsigned char *) buf;
		int cookie = desc->cookie;	/* make a local copy */
		unsigned long ts;		/* timestamp */

		PRINTF ("%s: Function Table:\n"
				"ptr:\t0x%p\n"
				"struct: 0x%p\n"
				"config:\t0x%p\n"
				"status:\t0x%p\n"
				"clk:\t0x%p\n"
				"data:\t0x%p\n"
				"done:\t0x%p\n\n",
				__FUNCTION__, &fn, fn, fn->config, fn->status,
				fn->clk, fn->data, fn->done);
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
		printf ("Loading FPGA Device %d...", cookie);
#endif

		/*
		 * Run the pre configuration function if there is one.
		 */
		if (*fn->pre) {
			(*fn->pre) (cookie);
		}

		/* Establish the initial state */
		(*fn->config) (TRUE, TRUE, cookie);	/* Assert nCONFIG */

		udelay(2);		/* T_cfg > 2us	*/

		/* nSTATUS should be asserted now */
		(*fn->done) (cookie);
		if ( !(*fn->status) (cookie) ) {
			puts ("** nSTATUS is not asserted.\n");
			(*fn->abort) (cookie);
			return FPGA_FAIL;
		}

		(*fn->config) (FALSE, TRUE, cookie);	/* Deassert nCONFIG */
		udelay(2);		/* T_cf2st1 < 4us	*/

		/* Wait for nSTATUS to be released (i.e. deasserted) */
		ts = get_timer (0);		/* get current time */
		do {
			CONFIG_FPGA_DELAY ();
			if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) {	/* check the time */
				puts ("** Timeout waiting for STATUS to go high.\n");
				(*fn->abort) (cookie);
				return FPGA_FAIL;
			}
			(*fn->done) (cookie);
		} while ((*fn->status) (cookie));

		/* Get ready for the burn */
		CONFIG_FPGA_DELAY ();

		/* Load the data */
		while (bytecount < bsize) {
			unsigned char val=0;
#ifdef CONFIG_SYS_FPGA_CHECK_CTRLC
			if (ctrlc ()) {
				(*fn->abort) (cookie);
				return FPGA_FAIL;
			}
#endif
			/* Altera detects an error if INIT goes low (active)
			   while DONE is low (inactive) */
#if 0 /* not yet implemented */
			if ((*fn->done) (cookie) == 0 && (*fn->init) (cookie)) {
				puts ("** CRC error during FPGA load.\n");
				(*fn->abort) (cookie);
				return (FPGA_FAIL);
			}
#endif
			val = data [bytecount ++ ];
			i = 8;
			do {
				/* Deassert the clock */
				(*fn->clk) (FALSE, TRUE, cookie);
				CONFIG_FPGA_DELAY ();
				/* Write data */
				(*fn->data) ( (val & 0x01), TRUE, cookie);
				CONFIG_FPGA_DELAY ();
				/* Assert the clock */
				(*fn->clk) (TRUE, TRUE, cookie);
				CONFIG_FPGA_DELAY ();
				val >>= 1;
				i --;
			} while (i > 0);

#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
			if (bytecount % (bsize / 40) == 0)
				putc ('.');		/* let them know we are alive */
#endif
		}

		CONFIG_FPGA_DELAY ();

#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
		putc (' ');			/* terminate the dotted line */
#endif

	/*
	 * Checking FPGA's CONF_DONE signal - correctly booted ?
	 */

	if ( ! (*fn->done) (cookie) ) {
		puts ("** Booting failed! CONF_DONE is still deasserted.\n");
		(*fn->abort) (cookie);
		return (FPGA_FAIL);
	}

	/*
	 * "DCLK must be clocked an additional 10 times fpr ACEX 1K..."
	 */

	for (i = 0; i < 12; i++) {
		CONFIG_FPGA_DELAY ();
		(*fn->clk) (TRUE, TRUE, cookie);	/* Assert the clock pin */
		CONFIG_FPGA_DELAY ();
		(*fn->clk) (FALSE, TRUE, cookie);	/* Deassert the clock pin */
	}

	ret_val = FPGA_SUCCESS;

#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
		if (ret_val == FPGA_SUCCESS) {
			puts ("Done.\n");
		}
		else {
			puts ("Fail.\n");
		}
#endif
	(*fn->post) (cookie);

	} else {
/* CYCLON2 Passive Serial Generic Implementation                                  */
static int CYC2_ps_load (Altera_desc * desc, void *buf, size_t bsize)
{
	int ret_val = FPGA_FAIL;	/* assume the worst */
	Altera_CYC2_Passive_Serial_fns *fn = desc->iface_fns;
	int	ret = 0;

	PRINTF ("%s: start with interface functions @ 0x%p\n",
			__FUNCTION__, fn);

	if (fn) {
		int cookie = desc->cookie;	/* make a local copy */
		unsigned long ts;		/* timestamp */

		PRINTF ("%s: Function Table:\n"
				"ptr:\t0x%p\n"
				"struct: 0x%p\n"
				"config:\t0x%p\n"
				"status:\t0x%p\n"
				"write:\t0x%p\n"
				"done:\t0x%p\n\n",
				__FUNCTION__, &fn, fn, fn->config, fn->status,
				fn->write, fn->done);
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
		printf ("Loading FPGA Device %d...", cookie);
#endif

		/*
		 * Run the pre configuration function if there is one.
		 */
		if (*fn->pre) {
			(*fn->pre) (cookie);
		}

		/* Establish the initial state */
		(*fn->config) (TRUE, TRUE, cookie);	/* Assert nCONFIG */

		udelay(2);		/* T_cfg > 2us	*/

		/* Wait for nSTATUS to be asserted */
		ts = get_timer (0);		/* get current time */
		do {
			CONFIG_FPGA_DELAY ();
			if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) {	/* check the time */
				puts ("** Timeout waiting for STATUS to go high.\n");
				(*fn->abort) (cookie);
				return FPGA_FAIL;
			}
		} while (!(*fn->status) (cookie));

		/* Get ready for the burn */
		CONFIG_FPGA_DELAY ();

		ret = (*fn->write) (buf, bsize, TRUE, cookie);
		if (ret) {
			puts ("** Write failed.\n");
			(*fn->abort) (cookie);
			return FPGA_FAIL;
		}
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
		puts(" OK? ...");
#endif

		CONFIG_FPGA_DELAY ();

#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
		putc (' ');			/* terminate the dotted line */
#endif

	/*
	 * Checking FPGA's CONF_DONE signal - correctly booted ?
	 */

	if ( ! (*fn->done) (cookie) ) {
		puts ("** Booting failed! CONF_DONE is still deasserted.\n");
		(*fn->abort) (cookie);
		return (FPGA_FAIL);
	}
#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
	puts(" OK\n");
#endif

	ret_val = FPGA_SUCCESS;

#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
	if (ret_val == FPGA_SUCCESS) {
		puts ("Done.\n");
	}
	else {
		puts ("Fail.\n");
	}
#endif
	(*fn->post) (cookie);

	} else {
		printf ("%s: NULL Interface function table!\n", __FUNCTION__);
	}

	return ret_val;
}
/*
 * Virtex-II Slave SelectMap configuration loader. Configuration via
 * SelectMap is as follows:
 * 1. Set the FPGA's PROG_B line low.
 * 2. Set the FPGA's PROG_B line high.  Wait for INIT_B to go high.
 * 3. Write data to the SelectMap port.  If INIT_B goes low at any time
 *    this process, a configuration error (most likely CRC failure) has
 *    ocurred.  At this point a status word may be read from the
 *    SelectMap interface to determine the source of the problem (You
 *    could, for instance, put this in your 'abort' function handler).
 * 4. After all data has been written, test the state of the FPGA
 *    INIT_B and DONE lines.  If both are high, configuration has
 *    succeeded. Congratulations!
 */
static int Virtex2_ssm_load (Xilinx_desc * desc, void *buf, size_t bsize)
{
	int ret_val = FPGA_FAIL;
	Xilinx_Virtex2_Slave_SelectMap_fns *fn = desc->iface_fns;

	PRINTF ("%s:%d: Start with interface functions @ 0x%p\n",
			__FUNCTION__, __LINE__, fn);

	if (fn) {
		size_t bytecount = 0;
		unsigned char *data = (unsigned char *) buf;
		int cookie = desc->cookie;
		unsigned long ts;

		/* Gotta split this one up (so the stack won't blow??) */
		PRINTF ("%s:%d: Function Table:\n"
				"  base   0x%p\n"
				"  struct 0x%p\n"
				"  pre    0x%p\n"
				"  prog   0x%p\n"
				"  init   0x%p\n"
				"  error  0x%p\n",
				__FUNCTION__, __LINE__,
				&fn, fn, fn->pre, fn->pgm, fn->init, fn->err);
		PRINTF ("  clock  0x%p\n"
				"  cs     0x%p\n"
				"  write  0x%p\n"
				"  rdata  0x%p\n"
				"  wdata  0x%p\n"
				"  busy   0x%p\n"
				"  abort  0x%p\n"
				"  post   0x%p\n\n",
				fn->clk, fn->cs, fn->wr, fn->rdata, fn->wdata,
				fn->busy, fn->abort, fn->post);

#ifdef CFG_FPGA_PROG_FEEDBACK
		printf ("Initializing FPGA Device %d...\n", cookie);
#endif
		/*
		 * Run the pre configuration function if there is one.
		 */
		if (*fn->pre) {
			(*fn->pre) (cookie);
		}

		/*
		 * Assert the program line.  The minimum pulse width for
		 * Virtex II devices is 300 nS (Tprogram parameter in datasheet).
		 * There is no maximum value for the pulse width.  Check to make
		 * sure that INIT_B goes low after assertion of PROG_B
		 */
		(*fn->pgm) (TRUE, TRUE, cookie);
		udelay (10);
		ts = get_timer (0);
		do {
			if (get_timer (ts) > CFG_FPGA_WAIT_INIT) {
				printf ("%s:%d: ** Timeout after %d ticks waiting for INIT"
						" to assert.\n", __FUNCTION__, __LINE__,
						CFG_FPGA_WAIT_INIT);
				(*fn->abort) (cookie);
				return FPGA_FAIL;
			}
		} while (!(*fn->init) (cookie));

		(*fn->pgm) (FALSE, TRUE, cookie);
		CONFIG_FPGA_DELAY ();
		(*fn->clk) (TRUE, TRUE, cookie);

		/*
		 * Start a timer and wait for INIT_B to go high
		 */
		ts = get_timer (0);
		do {
			CONFIG_FPGA_DELAY ();
			if (get_timer (ts) > CFG_FPGA_WAIT_INIT) {
				printf ("%s:%d: ** Timeout after %d ticks waiting for INIT"
						" to deassert.\n", __FUNCTION__, __LINE__,
						CFG_FPGA_WAIT_INIT);
				(*fn->abort) (cookie);
				return FPGA_FAIL;
			}
		} while ((*fn->init) (cookie) && (*fn->busy) (cookie));

		(*fn->wr) (TRUE, TRUE, cookie);
		(*fn->cs) (TRUE, TRUE, cookie);

		udelay (10000);

		/*
		 * Load the data byte by byte
		 */
		while (bytecount < bsize) {
#ifdef CFG_FPGA_CHECK_CTRLC
			if (ctrlc ()) {
				(*fn->abort) (cookie);
				return FPGA_FAIL;
			}
#endif

			if ((*fn->done) (cookie) == FPGA_SUCCESS) {
			    PRINTF ("%s:%d:done went active early, bytecount = %d\n",
				    __FUNCTION__, __LINE__, bytecount);
			    break;
			}

#ifdef CFG_FPGA_CHECK_ERROR
			if ((*fn->init) (cookie)) {
				printf ("\n%s:%d:  ** Error: INIT asserted during"
						" configuration\n", __FUNCTION__, __LINE__);
				printf ("%d = buffer offset, %d = buffer size\n",
					bytecount, bsize);
				(*fn->abort) (cookie);
				return FPGA_FAIL;
			}
#endif

			(*fn->wdata) (data[bytecount++], TRUE, cookie);
			CONFIG_FPGA_DELAY ();

			/*
			 * Cycle the clock pin
			 */
			(*fn->clk) (FALSE, TRUE, cookie);
			CONFIG_FPGA_DELAY ();
			(*fn->clk) (TRUE, TRUE, cookie);

#ifdef CFG_FPGA_CHECK_BUSY
			ts = get_timer (0);
			while ((*fn->busy) (cookie)) {
				if (get_timer (ts) > CFG_FPGA_WAIT_BUSY) {
					printf ("%s:%d: ** Timeout after %d ticks waiting for"
							" BUSY to deassert\n",
							__FUNCTION__, __LINE__, CFG_FPGA_WAIT_BUSY);
					(*fn->abort) (cookie);
					return FPGA_FAIL;
				}
			}
#endif

#ifdef CFG_FPGA_PROG_FEEDBACK
			if (bytecount % (bsize / 40) == 0)
				putc ('.');
#endif
		}

		/*
		 * Finished writing the data; deassert FPGA CS_B and WRITE_B signals.
		 */
		CONFIG_FPGA_DELAY ();
		(*fn->cs) (FALSE, TRUE, cookie);
		(*fn->wr) (FALSE, TRUE, cookie);

#ifdef CFG_FPGA_PROG_FEEDBACK
		putc ('\n');
#endif

		/*
		 * Check for successful configuration.  FPGA INIT_B and DONE should
		 * both be high upon successful configuration.
		 */
		ts = get_timer (0);
		ret_val = FPGA_SUCCESS;
		while (((*fn->done) (cookie) == FPGA_FAIL) || (*fn->init) (cookie)) {
			if (get_timer (ts) > CFG_FPGA_WAIT_CONFIG) {
				printf ("%s:%d: ** Timeout after %d ticks waiting for DONE to"
						"assert and INIT to deassert\n",
						__FUNCTION__, __LINE__, CFG_FPGA_WAIT_CONFIG);
				(*fn->abort) (cookie);
				ret_val = FPGA_FAIL;
				break;
			}
		}

		if (ret_val == FPGA_SUCCESS) {
#ifdef CFG_FPGA_PROG_FEEDBACK
			printf ("Initialization of FPGA device %d complete\n", cookie);
#endif
			/*
			 * Run the post configuration function if there is one.
			 */
			if (*fn->post) {
				(*fn->post) (cookie);
			}
		} else {
#ifdef CFG_FPGA_PROG_FEEDBACK
			printf ("** Initialization of FPGA device %d FAILED\n",
					cookie);
#endif
		}
	} else {
		printf ("%s:%d: NULL Interface function table!\n",
				__FUNCTION__, __LINE__);
	}
	return ret_val;
}