diff options
Diffstat (limited to 'drivers/fpga')
| -rw-r--r-- | drivers/fpga/ACEX1K.c | 362 | ||||
| -rw-r--r-- | drivers/fpga/Makefile | 58 | ||||
| -rw-r--r-- | drivers/fpga/altera.c | 283 | ||||
| -rw-r--r-- | drivers/fpga/cyclon2.c | 301 | ||||
| -rw-r--r-- | drivers/fpga/fpga.c | 335 | ||||
| -rw-r--r-- | drivers/fpga/spartan2.c | 663 | ||||
| -rw-r--r-- | drivers/fpga/spartan3.c | 668 | ||||
| -rw-r--r-- | drivers/fpga/stratixII.c | 231 | ||||
| -rw-r--r-- | drivers/fpga/virtex2.c | 554 | ||||
| -rw-r--r-- | drivers/fpga/xilinx.c | 307 | 
10 files changed, 3762 insertions, 0 deletions
| diff --git a/drivers/fpga/ACEX1K.c b/drivers/fpga/ACEX1K.c new file mode 100644 index 000000000..3f7967782 --- /dev/null +++ b/drivers/fpga/ACEX1K.c @@ -0,0 +1,362 @@ +/* + * (C) Copyright 2003 + * Steven Scholz, imc Measurement & Control, steven.scholz@imc-berlin.de + * + * (C) Copyright 2002 + * Rich Ireland, Enterasys Networks, rireland@enterasys.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include <common.h>		/* core U-Boot definitions */ +#include <ACEX1K.h>		/* ACEX device family */ + +/* Define FPGA_DEBUG to get debug printf's */ +#ifdef	FPGA_DEBUG +#define PRINTF(fmt,args...)	printf (fmt ,##args) +#else +#define PRINTF(fmt,args...) +#endif + +/* Note: The assumption is that we cannot possibly run fast enough to + * overrun the device (the Slave Parallel mode can free run at 50MHz). + * If there is a need to operate slower, define CONFIG_FPGA_DELAY in + * the board config file to slow things down. + */ +#ifndef CONFIG_FPGA_DELAY +#define CONFIG_FPGA_DELAY() +#endif + +#ifndef CONFIG_SYS_FPGA_WAIT +#define CONFIG_SYS_FPGA_WAIT CONFIG_SYS_HZ/10		/* 100 ms */ +#endif + +static int ACEX1K_ps_load( Altera_desc *desc, void *buf, size_t bsize ); +static int ACEX1K_ps_dump( Altera_desc *desc, void *buf, size_t bsize ); +/* static int ACEX1K_ps_info( Altera_desc *desc ); */ +static int ACEX1K_ps_reloc( Altera_desc *desc, ulong reloc_offset ); + +/* ------------------------------------------------------------------------- */ +/* ACEX1K Generic Implementation */ +int ACEX1K_load (Altera_desc * desc, void *buf, size_t bsize) +{ +	int ret_val = FPGA_FAIL; + +	switch (desc->iface) { +	case passive_serial: +		PRINTF ("%s: Launching Passive Serial Loader\n", __FUNCTION__); +		ret_val = ACEX1K_ps_load (desc, buf, bsize); +		break; + +		/* Add new interface types here */ + +	default: +		printf ("%s: Unsupported interface type, %d\n", +				__FUNCTION__, desc->iface); +	} + +	return ret_val; +} + +int ACEX1K_dump (Altera_desc * desc, void *buf, size_t bsize) +{ +	int ret_val = FPGA_FAIL; + +	switch (desc->iface) { +	case passive_serial: +		PRINTF ("%s: Launching Passive Serial Dump\n", __FUNCTION__); +		ret_val = ACEX1K_ps_dump (desc, buf, bsize); +		break; + +		/* Add new interface types here */ + +	default: +		printf ("%s: Unsupported interface type, %d\n", +				__FUNCTION__, desc->iface); +	} + +	return ret_val; +} + +int ACEX1K_info( Altera_desc *desc ) +{ +	return FPGA_SUCCESS; +} + + +int ACEX1K_reloc (Altera_desc * desc, ulong reloc_offset) +{ +	int ret_val = FPGA_FAIL;	/* assume a failure */ + +	if (desc->family != Altera_ACEX1K) { +		printf ("%s: Unsupported family type, %d\n", +				__FUNCTION__, desc->family); +		return FPGA_FAIL; +	} else +		switch (desc->iface) { +		case passive_serial: +			ret_val = ACEX1K_ps_reloc (desc, reloc_offset); +			break; + +		/* Add new interface types here */ + +		default: +			printf ("%s: Unsupported interface type, %d\n", +					__FUNCTION__, desc->iface); +		} + +	return ret_val; +} + + +/* ------------------------------------------------------------------------- */ +/* ACEX1K Passive Serial Generic Implementation                                  */ + +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 { +		printf ("%s: NULL Interface function table!\n", __FUNCTION__); +	} + +	return ret_val; +} + +static int ACEX1K_ps_dump (Altera_desc * desc, void *buf, size_t bsize) +{ +	/* Readback is only available through the Slave Parallel and         */ +	/* boundary-scan interfaces.                                         */ +	printf ("%s: Passive Serial Dumping is unavailable\n", +			__FUNCTION__); +	return FPGA_FAIL; +} + +static int ACEX1K_ps_reloc (Altera_desc * desc, ulong reloc_offset) +{ +	int ret_val = FPGA_FAIL;	/* assume the worst */ +	Altera_ACEX1K_Passive_Serial_fns *fn_r, *fn = +			(Altera_ACEX1K_Passive_Serial_fns *) (desc->iface_fns); + +	if (fn) { +		ulong addr; + +		/* Get the relocated table address */ +		addr = (ulong) fn + reloc_offset; +		fn_r = (Altera_ACEX1K_Passive_Serial_fns *) addr; + +		if (!fn_r->relocated) { + +			if (memcmp (fn_r, fn, +						sizeof (Altera_ACEX1K_Passive_Serial_fns)) +				== 0) { +				/* good copy of the table, fix the descriptor pointer */ +				desc->iface_fns = fn_r; +			} else { +				PRINTF ("%s: Invalid function table at 0x%p\n", +						__FUNCTION__, fn_r); +				return FPGA_FAIL; +			} + +			PRINTF ("%s: Relocating descriptor at 0x%p\n", __FUNCTION__, +					desc); + +			addr = (ulong) (fn->pre) + reloc_offset; +			fn_r->pre = (Altera_pre_fn) addr; + +			addr = (ulong) (fn->config) + reloc_offset; +			fn_r->config = (Altera_config_fn) addr; + +			addr = (ulong) (fn->status) + reloc_offset; +			fn_r->status = (Altera_status_fn) addr; + +			addr = (ulong) (fn->done) + reloc_offset; +			fn_r->done = (Altera_done_fn) addr; + +			addr = (ulong) (fn->clk) + reloc_offset; +			fn_r->clk = (Altera_clk_fn) addr; + +			addr = (ulong) (fn->data) + reloc_offset; +			fn_r->data = (Altera_data_fn) addr; + +			addr = (ulong) (fn->abort) + reloc_offset; +			fn_r->abort = (Altera_abort_fn) addr; + +			addr = (ulong) (fn->post) + reloc_offset; +			fn_r->post = (Altera_post_fn) addr; + +			fn_r->relocated = TRUE; + +		} else { +			/* this table has already been moved */ +			/* XXX - should check to see if the descriptor is correct */ +			desc->iface_fns = fn_r; +		} + +		ret_val = FPGA_SUCCESS; +	} else { +		printf ("%s: NULL Interface function table!\n", __FUNCTION__); +	} + +	return ret_val; + +} diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile new file mode 100644 index 000000000..52d8e2432 --- /dev/null +++ b/drivers/fpga/Makefile @@ -0,0 +1,58 @@ +# +# (C) Copyright 2008 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB	:= $(obj)libfpga.a + +ifdef CONFIG_FPGA +COBJS-y += fpga.o +COBJS-$(CONFIG_FPGA_SPARTAN2) += spartan2.o +COBJS-$(CONFIG_FPGA_SPARTAN3) += spartan3.o +COBJS-$(CONFIG_FPGA_VIRTEX2) += virtex2.o +COBJS-$(CONFIG_FPGA_XILINX) += xilinx.o +ifdef CONFIG_FPGA_ALTERA +COBJS-y += altera.o +COBJS-$(CONFIG_FPGA_ACEX1K) += ACEX1K.o +COBJS-$(CONFIG_FPGA_CYCLON2) += cyclon2.o +COBJS-$(CONFIG_FPGA_STRATIX_II) += stratixII.o +endif +endif + +COBJS	:= $(COBJS-y) +SRCS	:= $(COBJS:.o=.c) +OBJS	:= $(addprefix $(obj),$(COBJS)) + +all:	$(LIB) + +$(LIB):	$(obj).depend $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/drivers/fpga/altera.c b/drivers/fpga/altera.c new file mode 100644 index 000000000..09dc0b22e --- /dev/null +++ b/drivers/fpga/altera.c @@ -0,0 +1,283 @@ +/* + * (C) Copyright 2003 + * Steven Scholz, imc Measurement & Control, steven.scholz@imc-berlin.de + * + * (C) Copyright 2002 + * Rich Ireland, Enterasys Networks, rireland@enterasys.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/* + *  Altera FPGA support + */ +#include <common.h> +#include <ACEX1K.h> +#include <stratixII.h> + +/* Define FPGA_DEBUG to get debug printf's */ +/* #define FPGA_DEBUG */ + +#ifdef	FPGA_DEBUG +#define	PRINTF(fmt,args...)	printf (fmt ,##args) +#else +#define PRINTF(fmt,args...) +#endif + +/* Local Static Functions */ +static int altera_validate (Altera_desc * desc, const char *fn); + +/* ------------------------------------------------------------------------- */ +int altera_load( Altera_desc *desc, void *buf, size_t bsize ) +{ +	int ret_val = FPGA_FAIL;	/* assume a failure */ + +	if (!altera_validate (desc, (char *)__FUNCTION__)) { +		printf ("%s: Invalid device descriptor\n", __FUNCTION__); +	} else { +		switch (desc->family) { +		case Altera_ACEX1K: +		case Altera_CYC2: +#if defined(CONFIG_FPGA_ACEX1K) +			PRINTF ("%s: Launching the ACEX1K Loader...\n", +					__FUNCTION__); +			ret_val = ACEX1K_load (desc, buf, bsize); +#elif defined(CONFIG_FPGA_CYCLON2) +			PRINTF ("%s: Launching the CYCLON II Loader...\n", +					__FUNCTION__); +			ret_val = CYC2_load (desc, buf, bsize); +#else +			printf ("%s: No support for ACEX1K devices.\n", +					__FUNCTION__); +#endif +			break; + +#if defined(CONFIG_FPGA_STRATIX_II) +		case Altera_StratixII: +			PRINTF ("%s: Launching the Stratix II Loader...\n", +				__FUNCTION__); +			ret_val = StratixII_load (desc, buf, bsize); +			break; +#endif +		default: +			printf ("%s: Unsupported family type, %d\n", +					__FUNCTION__, desc->family); +		} +	} + +	return ret_val; +} + +int altera_dump( Altera_desc *desc, void *buf, size_t bsize ) +{ +	int ret_val = FPGA_FAIL;	/* assume a failure */ + +	if (!altera_validate (desc, (char *)__FUNCTION__)) { +		printf ("%s: Invalid device descriptor\n", __FUNCTION__); +	} else { +		switch (desc->family) { +		case Altera_ACEX1K: +#if defined(CONFIG_FPGA_ACEX) +			PRINTF ("%s: Launching the ACEX1K Reader...\n", +					__FUNCTION__); +			ret_val = ACEX1K_dump (desc, buf, bsize); +#else +			printf ("%s: No support for ACEX1K devices.\n", +					__FUNCTION__); +#endif +			break; + +#if defined(CONFIG_FPGA_STRATIX_II) +		case Altera_StratixII: +			PRINTF ("%s: Launching the Stratix II Reader...\n", +				__FUNCTION__); +			ret_val = StratixII_dump (desc, buf, bsize); +			break; +#endif +		default: +			printf ("%s: Unsupported family type, %d\n", +					__FUNCTION__, desc->family); +		} +	} + +	return ret_val; +} + +int altera_info( Altera_desc *desc ) +{ +	int ret_val = FPGA_FAIL; + +	if (altera_validate (desc, (char *)__FUNCTION__)) { +		printf ("Family:        \t"); +		switch (desc->family) { +		case Altera_ACEX1K: +			printf ("ACEX1K\n"); +			break; +		case Altera_CYC2: +			printf ("CYCLON II\n"); +			break; +		case Altera_StratixII: +			printf ("Stratix II\n"); +			break; +			/* Add new family types here */ +		default: +			printf ("Unknown family type, %d\n", desc->family); +		} + +		printf ("Interface type:\t"); +		switch (desc->iface) { +		case passive_serial: +			printf ("Passive Serial (PS)\n"); +			break; +		case passive_parallel_synchronous: +			printf ("Passive Parallel Synchronous (PPS)\n"); +			break; +		case passive_parallel_asynchronous: +			printf ("Passive Parallel Asynchronous (PPA)\n"); +			break; +		case passive_serial_asynchronous: +			printf ("Passive Serial Asynchronous (PSA)\n"); +			break; +		case altera_jtag_mode:		/* Not used */ +			printf ("JTAG Mode\n"); +			break; +		case fast_passive_parallel: +			printf ("Fast Passive Parallel (FPP)\n"); +			break; +		case fast_passive_parallel_security: +			printf +			    ("Fast Passive Parallel with Security (FPPS) \n"); +			break; +			/* Add new interface types here */ +		default: +			printf ("Unsupported interface type, %d\n", desc->iface); +		} + +		printf ("Device Size:   \t%d bytes\n" +				"Cookie:        \t0x%x (%d)\n", +				desc->size, desc->cookie, desc->cookie); + +		if (desc->iface_fns) { +			printf ("Device Function Table @ 0x%p\n", desc->iface_fns); +			switch (desc->family) { +			case Altera_ACEX1K: +			case Altera_CYC2: +#if defined(CONFIG_FPGA_ACEX1K) +				ACEX1K_info (desc); +#elif defined(CONFIG_FPGA_CYCLON2) +				CYC2_info (desc); +#else +				/* just in case */ +				printf ("%s: No support for ACEX1K devices.\n", +						__FUNCTION__); +#endif +				break; +#if defined(CONFIG_FPGA_STRATIX_II) +			case Altera_StratixII: +				StratixII_info (desc); +				break; +#endif +				/* Add new family types here */ +			default: +				/* we don't need a message here - we give one up above */ +				break; +			} +		} else { +			printf ("No Device Function Table.\n"); +		} + +		ret_val = FPGA_SUCCESS; +	} else { +		printf ("%s: Invalid device descriptor\n", __FUNCTION__); +	} + +	return ret_val; +} + +int altera_reloc( Altera_desc *desc, ulong reloc_offset) +{ +	int ret_val = FPGA_FAIL;	/* assume a failure */ + +	if (!altera_validate (desc, (char *)__FUNCTION__)) { +		printf ("%s: Invalid device descriptor\n", __FUNCTION__); +	} else { +		switch (desc->family) { +		case Altera_ACEX1K: +#if defined(CONFIG_FPGA_ACEX1K) +			ret_val = ACEX1K_reloc (desc, reloc_offset); +#else +			printf ("%s: No support for ACEX devices.\n", +					__FUNCTION__); +#endif +			break; +#if defined(CONFIG_FPGA_STRATIX_II) +		case Altera_StratixII: +			ret_val = StratixII_reloc (desc, reloc_offset); +			break; +#endif +		case Altera_CYC2: +#if defined(CONFIG_FPGA_CYCLON2) +			ret_val = CYC2_reloc (desc, reloc_offset); +#else +			printf ("%s: No support for CYCLON II devices.\n", +					__FUNCTION__); +#endif +			break; +			/* Add new family types here */ +		default: +			printf ("%s: Unsupported family type, %d\n", +					__FUNCTION__, desc->family); +		} +	} + +	return ret_val; +} + +/* ------------------------------------------------------------------------- */ + +static int altera_validate (Altera_desc * desc, const char *fn) +{ +	int ret_val = FALSE; + +	if (desc) { +		if ((desc->family > min_altera_type) && +			(desc->family < max_altera_type)) { +			if ((desc->iface > min_altera_iface_type) && +				(desc->iface < max_altera_iface_type)) { +				if (desc->size) { +					ret_val = TRUE; +				} else { +					printf ("%s: NULL part size\n", fn); +				} +			} else { +				printf ("%s: Invalid Interface type, %d\n", +					fn, desc->iface); +			} +		} else { +			printf ("%s: Invalid family type, %d\n", fn, desc->family); +		} +	} else { +		printf ("%s: NULL descriptor!\n", fn); +	} + +	return ret_val; +} + +/* ------------------------------------------------------------------------- */ diff --git a/drivers/fpga/cyclon2.c b/drivers/fpga/cyclon2.c new file mode 100644 index 000000000..3ed64b279 --- /dev/null +++ b/drivers/fpga/cyclon2.c @@ -0,0 +1,301 @@ +/* + * (C) Copyright 2006 + * Heiko Schocher, hs@denx.de + * Based on ACE1XK.c + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include <common.h>		/* core U-Boot definitions */ +#include <altera.h> +#include <ACEX1K.h>		/* ACEX device family */ + +/* Define FPGA_DEBUG to get debug printf's */ +#ifdef	FPGA_DEBUG +#define PRINTF(fmt,args...)	printf (fmt ,##args) +#else +#define PRINTF(fmt,args...) +#endif + +/* Note: The assumption is that we cannot possibly run fast enough to + * overrun the device (the Slave Parallel mode can free run at 50MHz). + * If there is a need to operate slower, define CONFIG_FPGA_DELAY in + * the board config file to slow things down. + */ +#ifndef CONFIG_FPGA_DELAY +#define CONFIG_FPGA_DELAY() +#endif + +#ifndef CONFIG_SYS_FPGA_WAIT +#define CONFIG_SYS_FPGA_WAIT CONFIG_SYS_HZ/10		/* 100 ms */ +#endif + +static int CYC2_ps_load( Altera_desc *desc, void *buf, size_t bsize ); +static int CYC2_ps_dump( Altera_desc *desc, void *buf, size_t bsize ); +/* static int CYC2_ps_info( Altera_desc *desc ); */ +static int CYC2_ps_reloc( Altera_desc *desc, ulong reloc_offset ); + +/* ------------------------------------------------------------------------- */ +/* CYCLON2 Generic Implementation */ +int CYC2_load (Altera_desc * desc, void *buf, size_t bsize) +{ +	int ret_val = FPGA_FAIL; + +	switch (desc->iface) { +	case passive_serial: +		PRINTF ("%s: Launching Passive Serial Loader\n", __FUNCTION__); +		ret_val = CYC2_ps_load (desc, buf, bsize); +		break; + +		/* Add new interface types here */ + +	default: +		printf ("%s: Unsupported interface type, %d\n", +				__FUNCTION__, desc->iface); +	} + +	return ret_val; +} + +int CYC2_dump (Altera_desc * desc, void *buf, size_t bsize) +{ +	int ret_val = FPGA_FAIL; + +	switch (desc->iface) { +	case passive_serial: +		PRINTF ("%s: Launching Passive Serial Dump\n", __FUNCTION__); +		ret_val = CYC2_ps_dump (desc, buf, bsize); +		break; + +		/* Add new interface types here */ + +	default: +		printf ("%s: Unsupported interface type, %d\n", +				__FUNCTION__, desc->iface); +	} + +	return ret_val; +} + +int CYC2_info( Altera_desc *desc ) +{ +	return FPGA_SUCCESS; +} + +int CYC2_reloc (Altera_desc * desc, ulong reloc_offset) +{ +	int ret_val = FPGA_FAIL;	/* assume a failure */ + +	if (desc->family != Altera_CYC2) { +		printf ("%s: Unsupported family type, %d\n", +				__FUNCTION__, desc->family); +		return FPGA_FAIL; +	} else +		switch (desc->iface) { +		case passive_serial: +			ret_val = CYC2_ps_reloc (desc, reloc_offset); +			break; + +		/* Add new interface types here */ + +		default: +			printf ("%s: Unsupported interface type, %d\n", +					__FUNCTION__, desc->iface); +		} + +	return ret_val; +} + +/* ------------------------------------------------------------------------- */ +/* 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; +} + +static int CYC2_ps_dump (Altera_desc * desc, void *buf, size_t bsize) +{ +	/* Readback is only available through the Slave Parallel and         */ +	/* boundary-scan interfaces.                                         */ +	printf ("%s: Passive Serial Dumping is unavailable\n", +			__FUNCTION__); +	return FPGA_FAIL; +} + +static int CYC2_ps_reloc (Altera_desc * desc, ulong reloc_offset) +{ +	int ret_val = FPGA_FAIL;	/* assume the worst */ +	Altera_CYC2_Passive_Serial_fns *fn_r, *fn = +			(Altera_CYC2_Passive_Serial_fns *) (desc->iface_fns); + +	if (fn) { +		ulong addr; + +		/* Get the relocated table address */ +		addr = (ulong) fn + reloc_offset; +		fn_r = (Altera_CYC2_Passive_Serial_fns *) addr; + +		if (!fn_r->relocated) { + +			if (memcmp (fn_r, fn, +						sizeof (Altera_CYC2_Passive_Serial_fns)) +				== 0) { +				/* good copy of the table, fix the descriptor pointer */ +				desc->iface_fns = fn_r; +			} else { +				PRINTF ("%s: Invalid function table at 0x%p\n", +						__FUNCTION__, fn_r); +				return FPGA_FAIL; +			} + +			PRINTF ("%s: Relocating descriptor at 0x%p\n", __FUNCTION__, +					desc); + +			addr = (ulong) (fn->pre) + reloc_offset; +			fn_r->pre = (Altera_pre_fn) addr; + +			addr = (ulong) (fn->config) + reloc_offset; +			fn_r->config = (Altera_config_fn) addr; + +			addr = (ulong) (fn->status) + reloc_offset; +			fn_r->status = (Altera_status_fn) addr; + +			addr = (ulong) (fn->done) + reloc_offset; +			fn_r->done = (Altera_done_fn) addr; + +			addr = (ulong) (fn->write) + reloc_offset; +			fn_r->write = (Altera_write_fn) addr; + +			addr = (ulong) (fn->abort) + reloc_offset; +			fn_r->abort = (Altera_abort_fn) addr; + +			addr = (ulong) (fn->post) + reloc_offset; +			fn_r->post = (Altera_post_fn) addr; + +			fn_r->relocated = TRUE; + +		} else { +			/* this table has already been moved */ +			/* XXX - should check to see if the descriptor is correct */ +			desc->iface_fns = fn_r; +		} + +		ret_val = FPGA_SUCCESS; +	} else { +		printf ("%s: NULL Interface function table!\n", __FUNCTION__); +	} + +	return ret_val; +} diff --git a/drivers/fpga/fpga.c b/drivers/fpga/fpga.c new file mode 100644 index 000000000..67a6c300c --- /dev/null +++ b/drivers/fpga/fpga.c @@ -0,0 +1,335 @@ +/* + * (C) Copyright 2002 + * Rich Ireland, Enterasys Networks, rireland@enterasys.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/* + *  Generic FPGA support + */ +#include <common.h>             /* core U-Boot definitions */ +#include <xilinx.h>             /* xilinx specific definitions */ +#include <altera.h>             /* altera specific definitions */ + +#if 0 +#define FPGA_DEBUG              /* define FPGA_DEBUG to get debug messages */ +#endif + +/* Local definitions */ +#ifndef CONFIG_MAX_FPGA_DEVICES +#define CONFIG_MAX_FPGA_DEVICES		5 +#endif + +/* Enable/Disable debug console messages */ +#ifdef FPGA_DEBUG +#define	PRINTF(fmt,args...)	printf (fmt ,##args) +#else +#define	PRINTF(fmt,args...) +#endif + +/* Local static data */ +static ulong relocation_offset = 0; +static int next_desc = FPGA_INVALID_DEVICE; +static fpga_desc desc_table[CONFIG_MAX_FPGA_DEVICES]; + +/* Local static functions */ +static __attribute__((__const__)) fpga_desc * __attribute__((__const__)) fpga_get_desc( int devnum ); +static __attribute__((__const__)) fpga_desc * __attribute__((__const__)) fpga_validate( int devnum, void *buf, +					 size_t bsize, char *fn ); +static int fpga_dev_info( int devnum ); + + +/* ------------------------------------------------------------------------- */ + +/* fpga_no_sup + * 'no support' message function + */ +static void fpga_no_sup( char *fn, char *msg ) +{ +	if ( fn && msg ) { +		printf( "%s: No support for %s.\n", fn, msg); +	} else if ( msg ) { +		printf( "No support for %s.\n", msg); +	} else { +		printf( "No FPGA suport!\n"); +	} +} + + +/* fpga_get_desc + *	map a device number to a descriptor + */ +static __attribute__((__const__)) fpga_desc * __attribute__((__const__)) fpga_get_desc( int devnum ) +{ +	fpga_desc *desc = (fpga_desc * )NULL; + +	if (( devnum >= 0 ) && (devnum < next_desc )) { +		desc = &desc_table[devnum]; +		PRINTF( "%s: found fpga descriptor #%d @ 0x%p\n", +				__FUNCTION__, devnum, desc ); +	} + +	return desc; +} + + +/* fpga_validate + *	generic parameter checking code + */ +static __attribute__((__const__)) fpga_desc * __attribute__((__const__)) fpga_validate( int devnum, void *buf, +					 size_t bsize, char *fn ) +{ +	fpga_desc * desc = fpga_get_desc( devnum ); + +	if ( !desc ) { +		printf( "%s: Invalid device number %d\n", fn, devnum ); +	} + +	if ( !buf ) { +		printf( "%s: Null buffer.\n", fn ); +		return (fpga_desc * const)NULL; +	} +	return desc; +} + + +/* fpga_dev_info + *	generic multiplexing code + */ +static int fpga_dev_info( int devnum ) +{ +	int ret_val = FPGA_FAIL;           /* assume failure */ +	const fpga_desc * const desc = fpga_get_desc( devnum ); + +	if ( desc ) { +		PRINTF( "%s: Device Descriptor @ 0x%p\n", +				__FUNCTION__, desc->devdesc ); + +		switch ( desc->devtype ) { +		case fpga_xilinx: +#if defined(CONFIG_FPGA_XILINX) +			printf( "Xilinx Device\nDescriptor @ 0x%p\n", desc ); +			ret_val = xilinx_info( desc->devdesc ); +#else +			fpga_no_sup( (char *)__FUNCTION__, "Xilinx devices" ); +#endif +			break; +		case fpga_altera: +#if defined(CONFIG_FPGA_ALTERA) +			printf( "Altera Device\nDescriptor @ 0x%p\n", desc ); +			ret_val = altera_info( desc->devdesc ); +#else +			fpga_no_sup( (char *)__FUNCTION__, "Altera devices" ); +#endif +			break; +		default: +			printf( "%s: Invalid or unsupported device type %d\n", +					__FUNCTION__, desc->devtype ); +		} +	} else { +		printf( "%s: Invalid device number %d\n", +			__FUNCTION__, devnum ); +	} + +	return ret_val; +} + + +/* fpga_reloc + *	generic multiplexing code + */ +int fpga_reloc( fpga_type devtype, void *desc, ulong reloc_off ) +{ +	int ret_val = FPGA_FAIL; + +	PRINTF( "%s: Relocating Device of type %d @ 0x%p with offset %lx\n", +				__FUNCTION__, devtype, desc, reloc_off ); + +	switch ( devtype ) { +	case fpga_xilinx: +#if defined(CONFIG_FPGA_XILINX) +		ret_val = xilinx_reloc( desc, reloc_off ); +#else +		fpga_no_sup( (char *)__FUNCTION__, "Xilinx devices" ); +#endif +		break; +	case fpga_altera: +#if defined(CONFIG_FPGA_ALTERA) +		ret_val = altera_reloc( desc, reloc_off ); +#else +		fpga_no_sup( (char *)__FUNCTION__, "Altera devices" ); +#endif +		break; +	default: +		printf( "%s: Invalid or unsupported device type %d\n", +			__FUNCTION__, devtype ); +	} + +	return ret_val; +} + +/* ------------------------------------------------------------------------- */ +/* fgpa_init is usually called from misc_init_r() and MUST be called + * before any of the other fpga functions are used. + */ +void fpga_init( ulong reloc_off ) +{ +	relocation_offset = reloc_off; +	next_desc = 0; +	memset( desc_table, 0, sizeof(desc_table)); + +	PRINTF( "%s: CONFIG_FPGA = 0x%x\n", __FUNCTION__, CONFIG_FPGA ); +} + +/* fpga_count + * Basic interface function to get the current number of devices available. + */ +int fpga_count( void ) +{ +	return next_desc; +} + +/* fpga_add + *	Attempts to relocate the device/board specific interface code + *	to the proper RAM locations and adds the device descriptor to + *	the device table. + */ +int fpga_add( fpga_type devtype, void *desc ) +{ +	int devnum = FPGA_INVALID_DEVICE; + +	if ( next_desc  < 0 ) { +		printf( "%s: FPGA support not initialized!\n", __FUNCTION__ ); +	} else if (( devtype > fpga_min_type ) && ( devtype < fpga_undefined )) { +		if ( desc ) { +			if ( next_desc < CONFIG_MAX_FPGA_DEVICES ) { +				if ( fpga_reloc( devtype, desc, relocation_offset ) +				  == FPGA_SUCCESS ) { +					devnum = next_desc; +					desc_table[next_desc].devtype = devtype; +					desc_table[next_desc++].devdesc = desc; +				} else { +					printf( "%s: Unable to relocate device interface table!\n", +						__FUNCTION__ ); +				} +			} else { +				printf( "%s: Exceeded Max FPGA device count\n", __FUNCTION__ ); +			} +		} else { +			printf( "%s: NULL device descriptor\n", __FUNCTION__ ); +		} +	} else { +		printf( "%s: Unsupported FPGA type %d\n", __FUNCTION__, devtype ); +	} + +	return devnum; +} + +/* + *	Generic multiplexing code + */ +int fpga_load( int devnum, void *buf, size_t bsize ) +{ +	int ret_val = FPGA_FAIL;           /* assume failure */ +	fpga_desc * desc = fpga_validate( devnum, buf, bsize, (char *)__FUNCTION__ ); + +	if ( desc ) { +		switch ( desc->devtype ) { +		case fpga_xilinx: +#if defined(CONFIG_FPGA_XILINX) +			ret_val = xilinx_load( desc->devdesc, buf, bsize ); +#else +			fpga_no_sup( (char *)__FUNCTION__, "Xilinx devices" ); +#endif +			break; +		case fpga_altera: +#if defined(CONFIG_FPGA_ALTERA) +			ret_val = altera_load( desc->devdesc, buf, bsize ); +#else +			fpga_no_sup( (char *)__FUNCTION__, "Altera devices" ); +#endif +			break; +		default: +			printf( "%s: Invalid or unsupported device type %d\n", +				__FUNCTION__, desc->devtype ); +		} +	} + +	return ret_val; +} + +/* fpga_dump + *	generic multiplexing code + */ +int fpga_dump( int devnum, void *buf, size_t bsize ) +{ +	int ret_val = FPGA_FAIL;           /* assume failure */ +	fpga_desc * desc = fpga_validate( devnum, buf, bsize, (char *)__FUNCTION__ ); + +	if ( desc ) { +		switch ( desc->devtype ) { +		case fpga_xilinx: +#if defined(CONFIG_FPGA_XILINX) +			ret_val = xilinx_dump( desc->devdesc, buf, bsize ); +#else +			fpga_no_sup( (char *)__FUNCTION__, "Xilinx devices" ); +#endif +			break; +		case fpga_altera: +#if defined(CONFIG_FPGA_ALTERA) +			ret_val = altera_dump( desc->devdesc, buf, bsize ); +#else +			fpga_no_sup( (char *)__FUNCTION__, "Altera devices" ); +#endif +			break; +		default: +			printf( "%s: Invalid or unsupported device type %d\n", +				__FUNCTION__, desc->devtype ); +		} +	} + +	return ret_val; +} + + +/* fpga_info + *	front end to fpga_dev_info.  If devnum is invalid, report on all + *	available devices. + */ +int fpga_info( int devnum ) +{ +	if ( devnum == FPGA_INVALID_DEVICE ) { +		if ( next_desc > 0 ) { +			int dev; + +			for ( dev = 0; dev < next_desc; dev++ ) { +				fpga_dev_info( dev ); +			} +			return FPGA_SUCCESS; +		} else { +			printf( "%s: No FPGA devices available.\n", __FUNCTION__ ); +			return FPGA_FAIL; +		} +	} +	else return fpga_dev_info( devnum ); +} + +/* ------------------------------------------------------------------------- */ diff --git a/drivers/fpga/spartan2.c b/drivers/fpga/spartan2.c new file mode 100644 index 000000000..f5ba7fc04 --- /dev/null +++ b/drivers/fpga/spartan2.c @@ -0,0 +1,663 @@ +/* + * (C) Copyright 2002 + * Rich Ireland, Enterasys Networks, rireland@enterasys.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include <common.h>		/* core U-Boot definitions */ +#include <spartan2.h>		/* Spartan-II device family */ + +/* Define FPGA_DEBUG to get debug printf's */ +#ifdef	FPGA_DEBUG +#define PRINTF(fmt,args...)	printf (fmt ,##args) +#else +#define PRINTF(fmt,args...) +#endif + +#undef CONFIG_SYS_FPGA_CHECK_BUSY +#undef CONFIG_SYS_FPGA_PROG_FEEDBACK + +/* Note: The assumption is that we cannot possibly run fast enough to + * overrun the device (the Slave Parallel mode can free run at 50MHz). + * If there is a need to operate slower, define CONFIG_FPGA_DELAY in + * the board config file to slow things down. + */ +#ifndef CONFIG_FPGA_DELAY +#define CONFIG_FPGA_DELAY() +#endif + +#ifndef CONFIG_SYS_FPGA_WAIT +#define CONFIG_SYS_FPGA_WAIT CONFIG_SYS_HZ/100	/* 10 ms */ +#endif + +static int Spartan2_sp_load( Xilinx_desc *desc, void *buf, size_t bsize ); +static int Spartan2_sp_dump( Xilinx_desc *desc, void *buf, size_t bsize ); +/* static int Spartan2_sp_info( Xilinx_desc *desc ); */ +static int Spartan2_sp_reloc( Xilinx_desc *desc, ulong reloc_offset ); + +static int Spartan2_ss_load( Xilinx_desc *desc, void *buf, size_t bsize ); +static int Spartan2_ss_dump( Xilinx_desc *desc, void *buf, size_t bsize ); +/* static int Spartan2_ss_info( Xilinx_desc *desc ); */ +static int Spartan2_ss_reloc( Xilinx_desc *desc, ulong reloc_offset ); + +/* ------------------------------------------------------------------------- */ +/* Spartan-II Generic Implementation */ +int Spartan2_load (Xilinx_desc * desc, void *buf, size_t bsize) +{ +	int ret_val = FPGA_FAIL; + +	switch (desc->iface) { +	case slave_serial: +		PRINTF ("%s: Launching Slave Serial Load\n", __FUNCTION__); +		ret_val = Spartan2_ss_load (desc, buf, bsize); +		break; + +	case slave_parallel: +		PRINTF ("%s: Launching Slave Parallel Load\n", __FUNCTION__); +		ret_val = Spartan2_sp_load (desc, buf, bsize); +		break; + +	default: +		printf ("%s: Unsupported interface type, %d\n", +				__FUNCTION__, desc->iface); +	} + +	return ret_val; +} + +int Spartan2_dump (Xilinx_desc * desc, void *buf, size_t bsize) +{ +	int ret_val = FPGA_FAIL; + +	switch (desc->iface) { +	case slave_serial: +		PRINTF ("%s: Launching Slave Serial Dump\n", __FUNCTION__); +		ret_val = Spartan2_ss_dump (desc, buf, bsize); +		break; + +	case slave_parallel: +		PRINTF ("%s: Launching Slave Parallel Dump\n", __FUNCTION__); +		ret_val = Spartan2_sp_dump (desc, buf, bsize); +		break; + +	default: +		printf ("%s: Unsupported interface type, %d\n", +				__FUNCTION__, desc->iface); +	} + +	return ret_val; +} + +int Spartan2_info( Xilinx_desc *desc ) +{ +	return FPGA_SUCCESS; +} + + +int Spartan2_reloc (Xilinx_desc * desc, ulong reloc_offset) +{ +	int ret_val = FPGA_FAIL;	/* assume a failure */ + +	if (desc->family != Xilinx_Spartan2) { +		printf ("%s: Unsupported family type, %d\n", +				__FUNCTION__, desc->family); +		return FPGA_FAIL; +	} else +		switch (desc->iface) { +		case slave_serial: +			ret_val = Spartan2_ss_reloc (desc, reloc_offset); +			break; + +		case slave_parallel: +			ret_val = Spartan2_sp_reloc (desc, reloc_offset); +			break; + +		default: +			printf ("%s: Unsupported interface type, %d\n", +					__FUNCTION__, desc->iface); +		} + +	return ret_val; +} + + +/* ------------------------------------------------------------------------- */ +/* Spartan-II Slave Parallel Generic Implementation */ + +static int Spartan2_sp_load (Xilinx_desc * desc, void *buf, size_t bsize) +{ +	int ret_val = FPGA_FAIL;	/* assume the worst */ +	Xilinx_Spartan2_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; +			} +		} + +		if (ret_val == FPGA_SUCCESS) { +#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK +			puts ("Done.\n"); +#endif +		} +		/* +		 * Run the post configuration function if there is one. +		 */ +		if (*fn->post) { +			(*fn->post) (cookie); +		} + +		else { +#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK +			puts ("Fail.\n"); +#endif +		} + +	} else { +		printf ("%s: NULL Interface function table!\n", __FUNCTION__); +	} + +	return ret_val; +} + +static int Spartan2_sp_dump (Xilinx_desc * desc, void *buf, size_t bsize) +{ +	int ret_val = FPGA_FAIL;	/* assume the worst */ +	Xilinx_Spartan2_Slave_Parallel_fns *fn = desc->iface_fns; + +	if (fn) { +		unsigned char *data = (unsigned char *) buf; +		size_t bytecount = 0; +		int cookie = desc->cookie;	/* make a local copy */ + +		printf ("Starting Dump of FPGA Device %d...\n", cookie); + +		(*fn->cs) (TRUE, TRUE, cookie); /* Assert chip select, commit */ +		(*fn->clk) (TRUE, TRUE, cookie);	/* Assert the clock pin */ + +		/* dump the data */ +		while (bytecount < bsize) { +			/* XXX - do we check for an Ctrl-C press in here ??? */ + +			(*fn->clk) (FALSE, TRUE, cookie);	/* Deassert the clock pin */ +			(*fn->clk) (TRUE, TRUE, cookie);	/* Assert the clock pin */ +			(*fn->rdata) (&(data[bytecount++]), cookie);	/* read the data */ +#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK +			if (bytecount % (bsize / 40) == 0) +				putc ('.');		/* let them know we are alive */ +#endif +		} + +		(*fn->cs) (FALSE, FALSE, cookie);	/* Deassert the chip select */ +		(*fn->clk) (FALSE, TRUE, cookie);	/* Deassert the clock pin */ +		(*fn->clk) (TRUE, TRUE, cookie);	/* Assert the clock pin */ + +#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK +		putc ('\n');			/* terminate the dotted line */ +#endif +		puts ("Done.\n"); + +		/* XXX - checksum the data? */ +	} else { +		printf ("%s: NULL Interface function table!\n", __FUNCTION__); +	} + +	return ret_val; +} + + +static int Spartan2_sp_reloc (Xilinx_desc * desc, ulong reloc_offset) +{ +	int ret_val = FPGA_FAIL;	/* assume the worst */ +	Xilinx_Spartan2_Slave_Parallel_fns *fn_r, *fn = +			(Xilinx_Spartan2_Slave_Parallel_fns *) (desc->iface_fns); + +	if (fn) { +		ulong addr; + +		/* Get the relocated table address */ +		addr = (ulong) fn + reloc_offset; +		fn_r = (Xilinx_Spartan2_Slave_Parallel_fns *) addr; + +		if (!fn_r->relocated) { + +			if (memcmp (fn_r, fn, +						sizeof (Xilinx_Spartan2_Slave_Parallel_fns)) +				== 0) { +				/* good copy of the table, fix the descriptor pointer */ +				desc->iface_fns = fn_r; +			} else { +				PRINTF ("%s: Invalid function table at 0x%p\n", +						__FUNCTION__, fn_r); +				return FPGA_FAIL; +			} + +			PRINTF ("%s: Relocating descriptor at 0x%p\n", __FUNCTION__, +					desc); + +			addr = (ulong) (fn->pre) + reloc_offset; +			fn_r->pre = (Xilinx_pre_fn) addr; + +			addr = (ulong) (fn->pgm) + reloc_offset; +			fn_r->pgm = (Xilinx_pgm_fn) addr; + +			addr = (ulong) (fn->init) + reloc_offset; +			fn_r->init = (Xilinx_init_fn) addr; + +			addr = (ulong) (fn->done) + reloc_offset; +			fn_r->done = (Xilinx_done_fn) addr; + +			addr = (ulong) (fn->clk) + reloc_offset; +			fn_r->clk = (Xilinx_clk_fn) addr; + +			addr = (ulong) (fn->err) + reloc_offset; +			fn_r->err = (Xilinx_err_fn) addr; + +			addr = (ulong) (fn->cs) + reloc_offset; +			fn_r->cs = (Xilinx_cs_fn) addr; + +			addr = (ulong) (fn->wr) + reloc_offset; +			fn_r->wr = (Xilinx_wr_fn) addr; + +			addr = (ulong) (fn->rdata) + reloc_offset; +			fn_r->rdata = (Xilinx_rdata_fn) addr; + +			addr = (ulong) (fn->wdata) + reloc_offset; +			fn_r->wdata = (Xilinx_wdata_fn) addr; + +			addr = (ulong) (fn->busy) + reloc_offset; +			fn_r->busy = (Xilinx_busy_fn) addr; + +			addr = (ulong) (fn->abort) + reloc_offset; +			fn_r->abort = (Xilinx_abort_fn) addr; + +			addr = (ulong) (fn->post) + reloc_offset; +			fn_r->post = (Xilinx_post_fn) addr; + +			fn_r->relocated = TRUE; + +		} else { +			/* this table has already been moved */ +			/* XXX - should check to see if the descriptor is correct */ +			desc->iface_fns = fn_r; +		} + +		ret_val = FPGA_SUCCESS; +	} else { +		printf ("%s: NULL Interface function table!\n", __FUNCTION__); +	} + +	return ret_val; + +} + +/* ------------------------------------------------------------------------- */ + +static int Spartan2_ss_load (Xilinx_desc * desc, void *buf, size_t bsize) +{ +	int ret_val = FPGA_FAIL;	/* assume the worst */ +	Xilinx_Spartan2_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"); +				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"); +				return FPGA_FAIL; +			} +		} while ((*fn->init) (cookie)); + +		/* Load the data */ +		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"); +				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; +} + +static int Spartan2_ss_dump (Xilinx_desc * desc, void *buf, size_t bsize) +{ +	/* Readback is only available through the Slave Parallel and         */ +	/* boundary-scan interfaces.                                         */ +	printf ("%s: Slave Serial Dumping is unavailable\n", +			__FUNCTION__); +	return FPGA_FAIL; +} + +static int Spartan2_ss_reloc (Xilinx_desc * desc, ulong reloc_offset) +{ +	int ret_val = FPGA_FAIL;	/* assume the worst */ +	Xilinx_Spartan2_Slave_Serial_fns *fn_r, *fn = +			(Xilinx_Spartan2_Slave_Serial_fns *) (desc->iface_fns); + +	if (fn) { +		ulong addr; + +		/* Get the relocated table address */ +		addr = (ulong) fn + reloc_offset; +		fn_r = (Xilinx_Spartan2_Slave_Serial_fns *) addr; + +		if (!fn_r->relocated) { + +			if (memcmp (fn_r, fn, +						sizeof (Xilinx_Spartan2_Slave_Serial_fns)) +				== 0) { +				/* good copy of the table, fix the descriptor pointer */ +				desc->iface_fns = fn_r; +			} else { +				PRINTF ("%s: Invalid function table at 0x%p\n", +						__FUNCTION__, fn_r); +				return FPGA_FAIL; +			} + +			PRINTF ("%s: Relocating descriptor at 0x%p\n", __FUNCTION__, +					desc); + +			if (fn->pre) { +				addr = (ulong) (fn->pre) + reloc_offset; +				fn_r->pre = (Xilinx_pre_fn) addr; +			} + +			addr = (ulong) (fn->pgm) + reloc_offset; +			fn_r->pgm = (Xilinx_pgm_fn) addr; + +			addr = (ulong) (fn->init) + reloc_offset; +			fn_r->init = (Xilinx_init_fn) addr; + +			addr = (ulong) (fn->done) + reloc_offset; +			fn_r->done = (Xilinx_done_fn) addr; + +			addr = (ulong) (fn->clk) + reloc_offset; +			fn_r->clk = (Xilinx_clk_fn) addr; + +			addr = (ulong) (fn->wr) + reloc_offset; +			fn_r->wr = (Xilinx_wr_fn) addr; + +			if (fn->post) { +				addr = (ulong) (fn->post) + reloc_offset; +				fn_r->post = (Xilinx_post_fn) addr; +			} + +			fn_r->relocated = TRUE; + +		} else { +			/* this table has already been moved */ +			/* XXX - should check to see if the descriptor is correct */ +			desc->iface_fns = fn_r; +		} + +		ret_val = FPGA_SUCCESS; +	} else { +		printf ("%s: NULL Interface function table!\n", __FUNCTION__); +	} + +	return ret_val; + +} diff --git a/drivers/fpga/spartan3.c b/drivers/fpga/spartan3.c new file mode 100644 index 000000000..9ce41f1d2 --- /dev/null +++ b/drivers/fpga/spartan3.c @@ -0,0 +1,668 @@ +/* + * (C) Copyright 2002 + * Rich Ireland, Enterasys Networks, rireland@enterasys.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/* + * Configuration support for Xilinx Spartan3 devices.  Based + * on spartan2.c (Rich Ireland, rireland@enterasys.com). + */ + +#include <common.h>		/* core U-Boot definitions */ +#include <spartan3.h>		/* Spartan-II device family */ + +/* Define FPGA_DEBUG to get debug printf's */ +#ifdef	FPGA_DEBUG +#define PRINTF(fmt,args...)	printf (fmt ,##args) +#else +#define PRINTF(fmt,args...) +#endif + +#undef CONFIG_SYS_FPGA_CHECK_BUSY +#undef CONFIG_SYS_FPGA_PROG_FEEDBACK + +/* Note: The assumption is that we cannot possibly run fast enough to + * overrun the device (the Slave Parallel mode can free run at 50MHz). + * If there is a need to operate slower, define CONFIG_FPGA_DELAY in + * the board config file to slow things down. + */ +#ifndef CONFIG_FPGA_DELAY +#define CONFIG_FPGA_DELAY() +#endif + +#ifndef CONFIG_SYS_FPGA_WAIT +#define CONFIG_SYS_FPGA_WAIT CONFIG_SYS_HZ/100	/* 10 ms */ +#endif + +static int Spartan3_sp_load( Xilinx_desc *desc, void *buf, size_t bsize ); +static int Spartan3_sp_dump( Xilinx_desc *desc, void *buf, size_t bsize ); +/* static int Spartan3_sp_info( Xilinx_desc *desc ); */ +static int Spartan3_sp_reloc( Xilinx_desc *desc, ulong reloc_offset ); + +static int Spartan3_ss_load( Xilinx_desc *desc, void *buf, size_t bsize ); +static int Spartan3_ss_dump( Xilinx_desc *desc, void *buf, size_t bsize ); +/* static int Spartan3_ss_info( Xilinx_desc *desc ); */ +static int Spartan3_ss_reloc( Xilinx_desc *desc, ulong reloc_offset ); + +/* ------------------------------------------------------------------------- */ +/* Spartan-II Generic Implementation */ +int Spartan3_load (Xilinx_desc * desc, void *buf, size_t bsize) +{ +	int ret_val = FPGA_FAIL; + +	switch (desc->iface) { +	case slave_serial: +		PRINTF ("%s: Launching Slave Serial Load\n", __FUNCTION__); +		ret_val = Spartan3_ss_load (desc, buf, bsize); +		break; + +	case slave_parallel: +		PRINTF ("%s: Launching Slave Parallel Load\n", __FUNCTION__); +		ret_val = Spartan3_sp_load (desc, buf, bsize); +		break; + +	default: +		printf ("%s: Unsupported interface type, %d\n", +				__FUNCTION__, desc->iface); +	} + +	return ret_val; +} + +int Spartan3_dump (Xilinx_desc * desc, void *buf, size_t bsize) +{ +	int ret_val = FPGA_FAIL; + +	switch (desc->iface) { +	case slave_serial: +		PRINTF ("%s: Launching Slave Serial Dump\n", __FUNCTION__); +		ret_val = Spartan3_ss_dump (desc, buf, bsize); +		break; + +	case slave_parallel: +		PRINTF ("%s: Launching Slave Parallel Dump\n", __FUNCTION__); +		ret_val = Spartan3_sp_dump (desc, buf, bsize); +		break; + +	default: +		printf ("%s: Unsupported interface type, %d\n", +				__FUNCTION__, desc->iface); +	} + +	return ret_val; +} + +int Spartan3_info( Xilinx_desc *desc ) +{ +	return FPGA_SUCCESS; +} + + +int Spartan3_reloc (Xilinx_desc * desc, ulong reloc_offset) +{ +	int ret_val = FPGA_FAIL;	/* assume a failure */ + +	if (desc->family != Xilinx_Spartan3) { +		printf ("%s: Unsupported family type, %d\n", +				__FUNCTION__, desc->family); +		return FPGA_FAIL; +	} else +		switch (desc->iface) { +		case slave_serial: +			ret_val = Spartan3_ss_reloc (desc, reloc_offset); +			break; + +		case slave_parallel: +			ret_val = Spartan3_sp_reloc (desc, reloc_offset); +			break; + +		default: +			printf ("%s: Unsupported interface type, %d\n", +					__FUNCTION__, desc->iface); +		} + +	return ret_val; +} + + +/* ------------------------------------------------------------------------- */ +/* Spartan-II Slave Parallel Generic Implementation */ + +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; +			} +		} + +		if (ret_val == FPGA_SUCCESS) { +#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK +			puts ("Done.\n"); +#endif +		} +		/* +		 * Run the post configuration function if there is one. +		 */ +		if (*fn->post) { +			(*fn->post) (cookie); +		} + +		else { +#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK +			puts ("Fail.\n"); +#endif +		} + +	} else { +		printf ("%s: NULL Interface function table!\n", __FUNCTION__); +	} + +	return ret_val; +} + +static int Spartan3_sp_dump (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; + +	if (fn) { +		unsigned char *data = (unsigned char *) buf; +		size_t bytecount = 0; +		int cookie = desc->cookie;	/* make a local copy */ + +		printf ("Starting Dump of FPGA Device %d...\n", cookie); + +		(*fn->cs) (TRUE, TRUE, cookie); /* Assert chip select, commit */ +		(*fn->clk) (TRUE, TRUE, cookie);	/* Assert the clock pin */ + +		/* dump the data */ +		while (bytecount < bsize) { +			/* XXX - do we check for an Ctrl-C press in here ??? */ + +			(*fn->clk) (FALSE, TRUE, cookie);	/* Deassert the clock pin */ +			(*fn->clk) (TRUE, TRUE, cookie);	/* Assert the clock pin */ +			(*fn->rdata) (&(data[bytecount++]), cookie);	/* read the data */ +#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK +			if (bytecount % (bsize / 40) == 0) +				putc ('.');		/* let them know we are alive */ +#endif +		} + +		(*fn->cs) (FALSE, FALSE, cookie);	/* Deassert the chip select */ +		(*fn->clk) (FALSE, TRUE, cookie);	/* Deassert the clock pin */ +		(*fn->clk) (TRUE, TRUE, cookie);	/* Assert the clock pin */ + +#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK +		putc ('\n');			/* terminate the dotted line */ +#endif +		puts ("Done.\n"); + +		/* XXX - checksum the data? */ +	} else { +		printf ("%s: NULL Interface function table!\n", __FUNCTION__); +	} + +	return ret_val; +} + + +static int Spartan3_sp_reloc (Xilinx_desc * desc, ulong reloc_offset) +{ +	int ret_val = FPGA_FAIL;	/* assume the worst */ +	Xilinx_Spartan3_Slave_Parallel_fns *fn_r, *fn = +			(Xilinx_Spartan3_Slave_Parallel_fns *) (desc->iface_fns); + +	if (fn) { +		ulong addr; + +		/* Get the relocated table address */ +		addr = (ulong) fn + reloc_offset; +		fn_r = (Xilinx_Spartan3_Slave_Parallel_fns *) addr; + +		if (!fn_r->relocated) { + +			if (memcmp (fn_r, fn, +						sizeof (Xilinx_Spartan3_Slave_Parallel_fns)) +				== 0) { +				/* good copy of the table, fix the descriptor pointer */ +				desc->iface_fns = fn_r; +			} else { +				PRINTF ("%s: Invalid function table at 0x%p\n", +						__FUNCTION__, fn_r); +				return FPGA_FAIL; +			} + +			PRINTF ("%s: Relocating descriptor at 0x%p\n", __FUNCTION__, +					desc); + +			addr = (ulong) (fn->pre) + reloc_offset; +			fn_r->pre = (Xilinx_pre_fn) addr; + +			addr = (ulong) (fn->pgm) + reloc_offset; +			fn_r->pgm = (Xilinx_pgm_fn) addr; + +			addr = (ulong) (fn->init) + reloc_offset; +			fn_r->init = (Xilinx_init_fn) addr; + +			addr = (ulong) (fn->done) + reloc_offset; +			fn_r->done = (Xilinx_done_fn) addr; + +			addr = (ulong) (fn->clk) + reloc_offset; +			fn_r->clk = (Xilinx_clk_fn) addr; + +			addr = (ulong) (fn->err) + reloc_offset; +			fn_r->err = (Xilinx_err_fn) addr; + +			addr = (ulong) (fn->cs) + reloc_offset; +			fn_r->cs = (Xilinx_cs_fn) addr; + +			addr = (ulong) (fn->wr) + reloc_offset; +			fn_r->wr = (Xilinx_wr_fn) addr; + +			addr = (ulong) (fn->rdata) + reloc_offset; +			fn_r->rdata = (Xilinx_rdata_fn) addr; + +			addr = (ulong) (fn->wdata) + reloc_offset; +			fn_r->wdata = (Xilinx_wdata_fn) addr; + +			addr = (ulong) (fn->busy) + reloc_offset; +			fn_r->busy = (Xilinx_busy_fn) addr; + +			addr = (ulong) (fn->abort) + reloc_offset; +			fn_r->abort = (Xilinx_abort_fn) addr; + +			addr = (ulong) (fn->post) + reloc_offset; +			fn_r->post = (Xilinx_post_fn) addr; + +			fn_r->relocated = TRUE; + +		} else { +			/* this table has already been moved */ +			/* XXX - should check to see if the descriptor is correct */ +			desc->iface_fns = fn_r; +		} + +		ret_val = FPGA_SUCCESS; +	} else { +		printf ("%s: NULL Interface function table!\n", __FUNCTION__); +	} + +	return ret_val; + +} + +/* ------------------------------------------------------------------------- */ + +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"); +				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"); +				return FPGA_FAIL; +			} +		} while ((*fn->init) (cookie)); + +		/* Load the data */ +		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"); +				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; +} + +static int Spartan3_ss_dump (Xilinx_desc * desc, void *buf, size_t bsize) +{ +	/* Readback is only available through the Slave Parallel and         */ +	/* boundary-scan interfaces.                                         */ +	printf ("%s: Slave Serial Dumping is unavailable\n", +			__FUNCTION__); +	return FPGA_FAIL; +} + +static int Spartan3_ss_reloc (Xilinx_desc * desc, ulong reloc_offset) +{ +	int ret_val = FPGA_FAIL;	/* assume the worst */ +	Xilinx_Spartan3_Slave_Serial_fns *fn_r, *fn = +			(Xilinx_Spartan3_Slave_Serial_fns *) (desc->iface_fns); + +	if (fn) { +		ulong addr; + +		/* Get the relocated table address */ +		addr = (ulong) fn + reloc_offset; +		fn_r = (Xilinx_Spartan3_Slave_Serial_fns *) addr; + +		if (!fn_r->relocated) { + +			if (memcmp (fn_r, fn, +						sizeof (Xilinx_Spartan3_Slave_Serial_fns)) +				== 0) { +				/* good copy of the table, fix the descriptor pointer */ +				desc->iface_fns = fn_r; +			} else { +				PRINTF ("%s: Invalid function table at 0x%p\n", +						__FUNCTION__, fn_r); +				return FPGA_FAIL; +			} + +			PRINTF ("%s: Relocating descriptor at 0x%p\n", __FUNCTION__, +					desc); + +			if (fn->pre) { +				addr = (ulong) (fn->pre) + reloc_offset; +				fn_r->pre = (Xilinx_pre_fn) addr; +			} + +			addr = (ulong) (fn->pgm) + reloc_offset; +			fn_r->pgm = (Xilinx_pgm_fn) addr; + +			addr = (ulong) (fn->init) + reloc_offset; +			fn_r->init = (Xilinx_init_fn) addr; + +			addr = (ulong) (fn->done) + reloc_offset; +			fn_r->done = (Xilinx_done_fn) addr; + +			addr = (ulong) (fn->clk) + reloc_offset; +			fn_r->clk = (Xilinx_clk_fn) addr; + +			addr = (ulong) (fn->wr) + reloc_offset; +			fn_r->wr = (Xilinx_wr_fn) addr; + +			if (fn->post) { +				addr = (ulong) (fn->post) + reloc_offset; +				fn_r->post = (Xilinx_post_fn) addr; +			} + +			fn_r->relocated = TRUE; + +		} else { +			/* this table has already been moved */ +			/* XXX - should check to see if the descriptor is correct */ +			desc->iface_fns = fn_r; +		} + +		ret_val = FPGA_SUCCESS; +	} else { +		printf ("%s: NULL Interface function table!\n", __FUNCTION__); +	} + +	return ret_val; + +} diff --git a/drivers/fpga/stratixII.c b/drivers/fpga/stratixII.c new file mode 100644 index 000000000..7556dbfb3 --- /dev/null +++ b/drivers/fpga/stratixII.c @@ -0,0 +1,231 @@ +/* + * (C) Copyright 2007 + * Eran Liberty, Extricom , eran.liberty@gmail.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include <common.h>		/* core U-Boot definitions */ +#include <altera.h> + +int StratixII_ps_fpp_load (Altera_desc * desc, void *buf, size_t bsize, +			   int isSerial, int isSecure); +int StratixII_ps_fpp_dump (Altera_desc * desc, void *buf, size_t bsize); + +/****************************************************************/ +/* Stratix II Generic Implementation                            */ +int StratixII_load (Altera_desc * desc, void *buf, size_t bsize) +{ +	int ret_val = FPGA_FAIL; + +	switch (desc->iface) { +	case passive_serial: +		ret_val = StratixII_ps_fpp_load (desc, buf, bsize, 1, 0); +		break; +	case fast_passive_parallel: +		ret_val = StratixII_ps_fpp_load (desc, buf, bsize, 0, 0); +		break; +	case fast_passive_parallel_security: +		ret_val = StratixII_ps_fpp_load (desc, buf, bsize, 0, 1); +		break; + +		/* Add new interface types here */ +	default: +		printf ("%s: Unsupported interface type, %d\n", __FUNCTION__, +			desc->iface); +	} +	return ret_val; +} + +int StratixII_dump (Altera_desc * desc, void *buf, size_t bsize) +{ +	int ret_val = FPGA_FAIL; + +	switch (desc->iface) { +	case passive_serial: +	case fast_passive_parallel: +	case fast_passive_parallel_security: +		ret_val = StratixII_ps_fpp_dump (desc, buf, bsize); +		break; +		/* Add new interface types here */ +	default: +		printf ("%s: Unsupported interface type, %d\n", __FUNCTION__, +			desc->iface); +	} +	return ret_val; +} + +int StratixII_info (Altera_desc * desc) +{ +	return FPGA_SUCCESS; +} + +int StratixII_reloc (Altera_desc * desc, ulong reloc_offset) +{ +	int i; +	uint32_t dest = (uint32_t) desc & 0xff000000; + +	/* we assume a relocated code and non relocated code has different upper 8 bits */ +	if (dest != ((uint32_t) desc->iface_fns & 0xff000000)) { +		desc->iface_fns = +		    (void *)((uint32_t) (desc->iface_fns) + reloc_offset); +	} +	for (i = 0; i < sizeof (altera_board_specific_func) / sizeof (void *); +	     i++) { +		if (dest != +		    ((uint32_t) (((void **)(desc->iface_fns))[i]) & 0xff000000)) +		{ +			((void **)(desc->iface_fns))[i] = +			    (void +			     *)(((uint32_t) (((void **)(desc->iface_fns))[i])) + +				reloc_offset); +		} +	} +	return FPGA_SUCCESS; +} + +int StratixII_ps_fpp_dump (Altera_desc * desc, void *buf, size_t bsize) +{ +	printf ("Stratix II Fast Passive Parallel dump is not implemented\n"); +	return FPGA_FAIL; +} + +int StratixII_ps_fpp_load (Altera_desc * desc, void *buf, size_t bsize, +			   int isSerial, int isSecure) +{ +	altera_board_specific_func *fns; +	int cookie; +	int ret_val = FPGA_FAIL; +	int bytecount; +	char *buff = buf; +	int i; + +	if (!desc) { +		printf ("%s(%d) Altera_desc missing\n", __FUNCTION__, __LINE__); +		return FPGA_FAIL; +	} +	if (!buff) { +		printf ("%s(%d) buffer is missing\n", __FUNCTION__, __LINE__); +		return FPGA_FAIL; +	} +	if (!bsize) { +		printf ("%s(%d) size is zero\n", __FUNCTION__, __LINE__); +		return FPGA_FAIL; +	} +	if (!desc->iface_fns) { +		printf +		    ("%s(%d) Altera_desc function interface table is missing\n", +		     __FUNCTION__, __LINE__); +		return FPGA_FAIL; +	} +	fns = (altera_board_specific_func *) (desc->iface_fns); +	cookie = desc->cookie; + +	if (! +	    (fns->config && fns->status && fns->done && fns->data +	     && fns->abort)) { +		printf +		    ("%s(%d) Missing some function in the function interface table\n", +		     __FUNCTION__, __LINE__); +		return FPGA_FAIL; +	} + +	/* 1. give board specific a chance to do anything before we start */ +	if (fns->pre) { +		if ((ret_val = fns->pre (cookie)) < 0) { +			return ret_val; +		} +	} + +	/* from this point on we must fail gracfully by calling lower layer abort */ + +	/* 2. Strat burn cycle by deasserting config for t_CFG and waiting t_CF2CK after reaserted */ +	fns->config (0, 1, cookie); +	udelay (5);		/* nCONFIG low pulse width 2usec */ +	fns->config (1, 1, cookie); +	udelay (100);		/* nCONFIG high to first rising edge on DCLK */ + +	/* 3. Start the Data cycle with clk deasserted */ +	bytecount = 0; +	fns->clk (0, 1, cookie); + +	printf ("loading to fpga    "); +	while (bytecount < bsize) { +		/* 3.1 check stratix has not signaled us an error */ +		if (fns->status (cookie) != 1) { +			printf +			    ("\n%s(%d) Stratix failed (byte transfered till failure 0x%x)\n", +			     __FUNCTION__, __LINE__, bytecount); +			fns->abort (cookie); +			return FPGA_FAIL; +		} +		if (isSerial) { +			int i; +			uint8_t data = buff[bytecount++]; +			for (i = 0; i < 8; i++) { +				/* 3.2(ps) put data on the bus */ +				fns->data ((data >> i) & 1, 1, cookie); + +				/* 3.3(ps) clock once */ +				fns->clk (1, 1, cookie); +				fns->clk (0, 1, cookie); +			} +		} else { +			/* 3.2(fpp) put data on the bus */ +			fns->data (buff[bytecount++], 1, cookie); + +			/* 3.3(fpp) clock once */ +			fns->clk (1, 1, cookie); +			fns->clk (0, 1, cookie); + +			/* 3.4(fpp) for secure cycle push 3 more  clocks */ +			for (i = 0; isSecure && i < 3; i++) { +				fns->clk (1, 1, cookie); +				fns->clk (0, 1, cookie); +			} +		} + +		/* 3.5 while clk is deasserted it is safe to print some progress indication */ +		if ((bytecount % (bsize / 100)) == 0) { +			printf ("\b\b\b%02d\%", bytecount * 100 / bsize); +		} +	} + +	/* 4. Set one last clock and check conf done signal */ +	fns->clk (1, 1, cookie); +	udelay (100); +	if (!fns->done (cookie)) { +		printf (" error!.\n"); +		fns->abort (cookie); +		return FPGA_FAIL; +	} else { +		printf ("\b\b\b done.\n"); +	} + +	/* 5. call lower layer post configuration */ +	if (fns->post) { +		if ((ret_val = fns->post (cookie)) < 0) { +			fns->abort (cookie); +			return ret_val; +		} +	} + +	return FPGA_SUCCESS; +} diff --git a/drivers/fpga/virtex2.c b/drivers/fpga/virtex2.c new file mode 100644 index 000000000..50d092184 --- /dev/null +++ b/drivers/fpga/virtex2.c @@ -0,0 +1,554 @@ +/* + * (C) Copyright 2002 + * Rich Ireland, Enterasys Networks, rireland@enterasys.com. + * Keith Outwater, keith_outwater@mvis.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/* + * Configuration support for Xilinx Virtex2 devices.  Based + * on spartan2.c (Rich Ireland, rireland@enterasys.com). + */ + +#include <common.h> +#include <virtex2.h> + +#if 0 +#define FPGA_DEBUG +#endif + +#ifdef	FPGA_DEBUG +#define	PRINTF(fmt,args...)	printf (fmt ,##args) +#else +#define PRINTF(fmt,args...) +#endif + +/* + * If the SelectMap interface can be overrun by the processor, define + * CONFIG_SYS_FPGA_CHECK_BUSY and/or CONFIG_FPGA_DELAY in the board configuration + * file and add board-specific support for checking BUSY status. By default, + * assume that the SelectMap interface cannot be overrun. + */ +#ifndef CONFIG_SYS_FPGA_CHECK_BUSY +#undef CONFIG_SYS_FPGA_CHECK_BUSY +#endif + +#ifndef CONFIG_FPGA_DELAY +#define CONFIG_FPGA_DELAY() +#endif + +#ifndef CONFIG_SYS_FPGA_PROG_FEEDBACK +#define CONFIG_SYS_FPGA_PROG_FEEDBACK +#endif + +/* + * Don't allow config cycle to be interrupted + */ +#ifndef CONFIG_SYS_FPGA_CHECK_CTRLC +#undef CONFIG_SYS_FPGA_CHECK_CTRLC +#endif + +/* + * Check for errors during configuration by default + */ +#ifndef CONFIG_SYS_FPGA_CHECK_ERROR +#define CONFIG_SYS_FPGA_CHECK_ERROR +#endif + +/* + * The default timeout in mS for INIT_B to deassert after PROG_B has + * been deasserted. Per the latest Virtex II Handbook (page 347), the + * max time from PORG_B deassertion to INIT_B deassertion is 4uS per + * data frame for the XC2V8000.  The XC2V8000 has 2860 data frames + * which yields 11.44 mS.  So let's make it bigger in order to handle + * an XC2V1000, if anyone can ever get ahold of one. + */ +#ifndef CONFIG_SYS_FPGA_WAIT_INIT +#define CONFIG_SYS_FPGA_WAIT_INIT	CONFIG_SYS_HZ/2	/* 500 ms */ +#endif + +/* + * The default timeout for waiting for BUSY to deassert during configuration. + * This is normally not necessary since for most reasonable configuration + * clock frequencies (i.e. 66 MHz or less), BUSY monitoring is unnecessary. + */ +#ifndef CONFIG_SYS_FPGA_WAIT_BUSY +#define CONFIG_SYS_FPGA_WAIT_BUSY	CONFIG_SYS_HZ/200	/* 5 ms*/ +#endif + +/* Default timeout for waiting for FPGA to enter operational mode after + * configuration data has been written. + */ +#ifndef	CONFIG_SYS_FPGA_WAIT_CONFIG +#define CONFIG_SYS_FPGA_WAIT_CONFIG	CONFIG_SYS_HZ/5	/* 200 ms */ +#endif + +static int Virtex2_ssm_load (Xilinx_desc * desc, void *buf, size_t bsize); +static int Virtex2_ssm_dump (Xilinx_desc * desc, void *buf, size_t bsize); +static int Virtex2_ssm_reloc (Xilinx_desc * desc, ulong reloc_offset); + +static int Virtex2_ss_load (Xilinx_desc * desc, void *buf, size_t bsize); +static int Virtex2_ss_dump (Xilinx_desc * desc, void *buf, size_t bsize); +static int Virtex2_ss_reloc (Xilinx_desc * desc, ulong reloc_offset); + +int Virtex2_load (Xilinx_desc * desc, void *buf, size_t bsize) +{ +	int ret_val = FPGA_FAIL; + +	switch (desc->iface) { +	case slave_serial: +		PRINTF ("%s: Launching Slave Serial Load\n", __FUNCTION__); +		ret_val = Virtex2_ss_load (desc, buf, bsize); +		break; + +	case slave_selectmap: +		PRINTF ("%s: Launching Slave Parallel Load\n", __FUNCTION__); +		ret_val = Virtex2_ssm_load (desc, buf, bsize); +		break; + +	default: +		printf ("%s: Unsupported interface type, %d\n", +				__FUNCTION__, desc->iface); +	} +	return ret_val; +} + +int Virtex2_dump (Xilinx_desc * desc, void *buf, size_t bsize) +{ +	int ret_val = FPGA_FAIL; + +	switch (desc->iface) { +	case slave_serial: +		PRINTF ("%s: Launching Slave Serial Dump\n", __FUNCTION__); +		ret_val = Virtex2_ss_dump (desc, buf, bsize); +		break; + +	case slave_parallel: +		PRINTF ("%s: Launching Slave Parallel Dump\n", __FUNCTION__); +		ret_val = Virtex2_ssm_dump (desc, buf, bsize); +		break; + +	default: +		printf ("%s: Unsupported interface type, %d\n", +				__FUNCTION__, desc->iface); +	} +	return ret_val; +} + +int Virtex2_info (Xilinx_desc * desc) +{ +	return FPGA_SUCCESS; +} + +int Virtex2_reloc (Xilinx_desc * desc, ulong reloc_offset) +{ +	int ret_val = FPGA_FAIL; + +	if (desc->family != Xilinx_Virtex2) { +		printf ("%s: Unsupported family type, %d\n", +				__FUNCTION__, desc->family); +		return FPGA_FAIL; +	} else +		switch (desc->iface) { +		case slave_serial: +			ret_val = Virtex2_ss_reloc (desc, reloc_offset); +			break; + +		case slave_selectmap: +			ret_val = Virtex2_ssm_reloc (desc, reloc_offset); +			break; + +		default: +			printf ("%s: Unsupported interface type, %d\n", +					__FUNCTION__, desc->iface); +		} +	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 CONFIG_SYS_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) > CONFIG_SYS_FPGA_WAIT_INIT) { +				printf ("%s:%d: ** Timeout after %d ticks waiting for INIT" +						" to assert.\n", __FUNCTION__, __LINE__, +						CONFIG_SYS_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) > CONFIG_SYS_FPGA_WAIT_INIT) { +				printf ("%s:%d: ** Timeout after %d ticks waiting for INIT" +						" to deassert.\n", __FUNCTION__, __LINE__, +						CONFIG_SYS_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 CONFIG_SYS_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 CONFIG_SYS_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 CONFIG_SYS_FPGA_CHECK_BUSY +			ts = get_timer (0); +			while ((*fn->busy) (cookie)) { +				if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT_BUSY) { +					printf ("%s:%d: ** Timeout after %d ticks waiting for" +							" BUSY to deassert\n", +							__FUNCTION__, __LINE__, CONFIG_SYS_FPGA_WAIT_BUSY); +					(*fn->abort) (cookie); +					return FPGA_FAIL; +				} +			} +#endif + +#ifdef CONFIG_SYS_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 CONFIG_SYS_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) > CONFIG_SYS_FPGA_WAIT_CONFIG) { +				printf ("%s:%d: ** Timeout after %d ticks waiting for DONE to" +						"assert and INIT to deassert\n", +						__FUNCTION__, __LINE__, CONFIG_SYS_FPGA_WAIT_CONFIG); +				(*fn->abort) (cookie); +				ret_val = FPGA_FAIL; +				break; +			} +		} + +		if (ret_val == FPGA_SUCCESS) { +#ifdef CONFIG_SYS_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 CONFIG_SYS_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; +} + +/* + * Read the FPGA configuration data + */ +static int Virtex2_ssm_dump (Xilinx_desc * desc, void *buf, size_t bsize) +{ +	int ret_val = FPGA_FAIL; +	Xilinx_Virtex2_Slave_SelectMap_fns *fn = desc->iface_fns; + +	if (fn) { +		unsigned char *data = (unsigned char *) buf; +		size_t bytecount = 0; +		int cookie = desc->cookie; + +		printf ("Starting Dump of FPGA Device %d...\n", cookie); + +		(*fn->cs) (TRUE, TRUE, cookie); +		(*fn->clk) (TRUE, TRUE, cookie); + +		while (bytecount < bsize) { +#ifdef CONFIG_SYS_FPGA_CHECK_CTRLC +			if (ctrlc ()) { +				(*fn->abort) (cookie); +				return FPGA_FAIL; +			} +#endif +			/* +			 * Cycle the clock and read the data +			 */ +			(*fn->clk) (FALSE, TRUE, cookie); +			(*fn->clk) (TRUE, TRUE, cookie); +			(*fn->rdata) (&(data[bytecount++]), cookie); +#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK +			if (bytecount % (bsize / 40) == 0) +				putc ('.'); +#endif +		} + +		/* +		 * Deassert CS_B and cycle the clock to deselect the device. +		 */ +		(*fn->cs) (FALSE, FALSE, cookie); +		(*fn->clk) (FALSE, TRUE, cookie); +		(*fn->clk) (TRUE, TRUE, cookie); + +#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK +		putc ('\n'); +#endif +		puts ("Done.\n"); +	} else { +		printf ("%s:%d: NULL Interface function table!\n", +				__FUNCTION__, __LINE__); +	} +	return ret_val; +} + +/* + * Relocate the addresses in the function table from FLASH (or ROM, + * or whatever) to RAM. + */ +static int Virtex2_ssm_reloc (Xilinx_desc * desc, ulong reloc_offset) +{ +	ulong addr; +	int ret_val = FPGA_FAIL; +	Xilinx_Virtex2_Slave_SelectMap_fns *fn_r, *fn = +			(Xilinx_Virtex2_Slave_SelectMap_fns *) (desc->iface_fns); + +	if (fn) { +		/* +		 * Get the relocated table address +		 */ +		addr = (ulong) fn + reloc_offset; +		fn_r = (Xilinx_Virtex2_Slave_SelectMap_fns *) addr; + +		/* +		 * Check to see if the table has already been relocated.  If not, do +		 * a sanity check to make sure there is a faithful copy of the +		 * FLASH based function table in RAM, then adjust the table. +		 */ +		if (!fn_r->relocated) { +			if (memcmp +				(fn_r, fn, sizeof (Xilinx_Virtex2_Slave_SelectMap_fns)) +				== 0) { +				desc->iface_fns = fn_r; +			} else { +				PRINTF ("%s:%d: Invalid function table at 0x%p\n", +						__FUNCTION__, __LINE__, fn_r); +				return FPGA_FAIL; +			} + +			PRINTF ("%s:%d: Relocating descriptor at 0x%p\n", +					__FUNCTION__, __LINE__, desc); + +			addr = (ulong) (fn->pre) + reloc_offset; +			fn_r->pre = (Xilinx_pre_fn) addr; +			addr = (ulong) (fn->pgm) + reloc_offset; +			fn_r->pgm = (Xilinx_pgm_fn) addr; +			addr = (ulong) (fn->init) + reloc_offset; +			fn_r->init = (Xilinx_init_fn) addr; +			addr = (ulong) (fn->done) + reloc_offset; +			fn_r->done = (Xilinx_done_fn) addr; +			addr = (ulong) (fn->err) + reloc_offset; +			fn_r->err = (Xilinx_err_fn) addr; +			addr = (ulong) (fn->clk) + reloc_offset; +			fn_r->clk = (Xilinx_clk_fn) addr; +			addr = (ulong) (fn->cs) + reloc_offset; +			fn_r->cs = (Xilinx_cs_fn) addr; +			addr = (ulong) (fn->wr) + reloc_offset; +			fn_r->wr = (Xilinx_wr_fn) addr; +			addr = (ulong) (fn->rdata) + reloc_offset; +			fn_r->rdata = (Xilinx_rdata_fn) addr; +			addr = (ulong) (fn->wdata) + reloc_offset; +			fn_r->wdata = (Xilinx_wdata_fn) addr; +			addr = (ulong) (fn->busy) + reloc_offset; +			fn_r->busy = (Xilinx_busy_fn) addr; +			addr = (ulong) (fn->abort) + reloc_offset; +			fn_r->abort = (Xilinx_abort_fn) addr; +			addr = (ulong) (fn->post) + reloc_offset; +			fn_r->post = (Xilinx_post_fn) addr; +			fn_r->relocated = TRUE; +		} else { +			printf ("%s:%d: Function table @0x%p has already been relocated\n", __FUNCTION__, __LINE__, fn_r); +			desc->iface_fns = fn_r; +		} +		ret_val = FPGA_SUCCESS; +	} else { +		printf ("%s: NULL Interface function table!\n", __FUNCTION__); +	} +	return ret_val; +} + +static int Virtex2_ss_load (Xilinx_desc * desc, void *buf, size_t bsize) +{ +	printf ("%s: Slave Serial Loading is unsupported\n", __FUNCTION__); +	return FPGA_FAIL; +} + +static int Virtex2_ss_dump (Xilinx_desc * desc, void *buf, size_t bsize) +{ +	printf ("%s: Slave Serial Dumping is unsupported\n", __FUNCTION__); +	return FPGA_FAIL; +} + +static int Virtex2_ss_reloc (Xilinx_desc * desc, ulong reloc_offset) +{ +	int ret_val = FPGA_FAIL; +	Xilinx_Virtex2_Slave_Serial_fns *fn = +			(Xilinx_Virtex2_Slave_Serial_fns *) (desc->iface_fns); + +	if (fn) { +		printf ("%s:%d: Slave Serial Loading is unsupported\n", +				__FUNCTION__, __LINE__); +	} else { +		printf ("%s:%d: NULL Interface function table!\n", +				__FUNCTION__, __LINE__); +	} +	return ret_val; +} + +/* vim: set ts=4 tw=78: */ diff --git a/drivers/fpga/xilinx.c b/drivers/fpga/xilinx.c new file mode 100644 index 000000000..7b5e8c5bb --- /dev/null +++ b/drivers/fpga/xilinx.c @@ -0,0 +1,307 @@ +/* + * (C) Copyright 2002 + * Rich Ireland, Enterasys Networks, rireland@enterasys.com. + * Keith Outwater, keith_outwater@mvis.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/* + *  Xilinx FPGA support + */ + +#include <common.h> +#include <virtex2.h> +#include <spartan2.h> +#include <spartan3.h> + +#if 0 +#define FPGA_DEBUG +#endif + +/* Define FPGA_DEBUG to get debug printf's */ +#ifdef	FPGA_DEBUG +#define	PRINTF(fmt,args...)	printf (fmt ,##args) +#else +#define PRINTF(fmt,args...) +#endif + +/* Local Static Functions */ +static int xilinx_validate (Xilinx_desc * desc, char *fn); + +/* ------------------------------------------------------------------------- */ + +int xilinx_load (Xilinx_desc * desc, void *buf, size_t bsize) +{ +	int ret_val = FPGA_FAIL;	/* assume a failure */ + +	if (!xilinx_validate (desc, (char *)__FUNCTION__)) { +		printf ("%s: Invalid device descriptor\n", __FUNCTION__); +	} else +		switch (desc->family) { +		case Xilinx_Spartan2: +#if defined(CONFIG_FPGA_SPARTAN2) +			PRINTF ("%s: Launching the Spartan-II Loader...\n", +					__FUNCTION__); +			ret_val = Spartan2_load (desc, buf, bsize); +#else +			printf ("%s: No support for Spartan-II devices.\n", +					__FUNCTION__); +#endif +			break; +		case Xilinx_Spartan3: +#if defined(CONFIG_FPGA_SPARTAN3) +			PRINTF ("%s: Launching the Spartan-III Loader...\n", +					__FUNCTION__); +			ret_val = Spartan3_load (desc, buf, bsize); +#else +			printf ("%s: No support for Spartan-III devices.\n", +					__FUNCTION__); +#endif +			break; +		case Xilinx_Virtex2: +#if defined(CONFIG_FPGA_VIRTEX2) +			PRINTF ("%s: Launching the Virtex-II Loader...\n", +					__FUNCTION__); +			ret_val = Virtex2_load (desc, buf, bsize); +#else +			printf ("%s: No support for Virtex-II devices.\n", +					__FUNCTION__); +#endif +			break; + +		default: +			printf ("%s: Unsupported family type, %d\n", +					__FUNCTION__, desc->family); +		} + +	return ret_val; +} + +int xilinx_dump (Xilinx_desc * desc, void *buf, size_t bsize) +{ +	int ret_val = FPGA_FAIL;	/* assume a failure */ + +	if (!xilinx_validate (desc, (char *)__FUNCTION__)) { +		printf ("%s: Invalid device descriptor\n", __FUNCTION__); +	} else +		switch (desc->family) { +		case Xilinx_Spartan2: +#if defined(CONFIG_FPGA_SPARTAN2) +			PRINTF ("%s: Launching the Spartan-II Reader...\n", +					__FUNCTION__); +			ret_val = Spartan2_dump (desc, buf, bsize); +#else +			printf ("%s: No support for Spartan-II devices.\n", +					__FUNCTION__); +#endif +			break; +		case Xilinx_Spartan3: +#if defined(CONFIG_FPGA_SPARTAN3) +			PRINTF ("%s: Launching the Spartan-III Reader...\n", +					__FUNCTION__); +			ret_val = Spartan3_dump (desc, buf, bsize); +#else +			printf ("%s: No support for Spartan-III devices.\n", +					__FUNCTION__); +#endif +			break; +		case Xilinx_Virtex2: +#if defined( CONFIG_FPGA_VIRTEX2) +			PRINTF ("%s: Launching the Virtex-II Reader...\n", +					__FUNCTION__); +			ret_val = Virtex2_dump (desc, buf, bsize); +#else +			printf ("%s: No support for Virtex-II devices.\n", +					__FUNCTION__); +#endif +			break; + +		default: +			printf ("%s: Unsupported family type, %d\n", +					__FUNCTION__, desc->family); +		} + +	return ret_val; +} + +int xilinx_info (Xilinx_desc * desc) +{ +	int ret_val = FPGA_FAIL; + +	if (xilinx_validate (desc, (char *)__FUNCTION__)) { +		printf ("Family:        \t"); +		switch (desc->family) { +		case Xilinx_Spartan2: +			printf ("Spartan-II\n"); +			break; +		case Xilinx_Spartan3: +			printf ("Spartan-III\n"); +			break; +		case Xilinx_Virtex2: +			printf ("Virtex-II\n"); +			break; +			/* Add new family types here */ +		default: +			printf ("Unknown family type, %d\n", desc->family); +		} + +		printf ("Interface type:\t"); +		switch (desc->iface) { +		case slave_serial: +			printf ("Slave Serial\n"); +			break; +		case master_serial:	/* Not used */ +			printf ("Master Serial\n"); +			break; +		case slave_parallel: +			printf ("Slave Parallel\n"); +			break; +		case jtag_mode:		/* Not used */ +			printf ("JTAG Mode\n"); +			break; +		case slave_selectmap: +			printf ("Slave SelectMap Mode\n"); +			break; +		case master_selectmap: +			printf ("Master SelectMap Mode\n"); +			break; +			/* Add new interface types here */ +		default: +			printf ("Unsupported interface type, %d\n", desc->iface); +		} + +		printf ("Device Size:   \t%d bytes\n" +				"Cookie:        \t0x%x (%d)\n", +				desc->size, desc->cookie, desc->cookie); + +		if (desc->iface_fns) { +			printf ("Device Function Table @ 0x%p\n", desc->iface_fns); +			switch (desc->family) { +			case Xilinx_Spartan2: +#if defined(CONFIG_FPGA_SPARTAN2) +				Spartan2_info (desc); +#else +				/* just in case */ +				printf ("%s: No support for Spartan-II devices.\n", +						__FUNCTION__); +#endif +				break; +			case Xilinx_Spartan3: +#if defined(CONFIG_FPGA_SPARTAN3) +				Spartan3_info (desc); +#else +				/* just in case */ +				printf ("%s: No support for Spartan-III devices.\n", +						__FUNCTION__); +#endif +				break; +			case Xilinx_Virtex2: +#if defined(CONFIG_FPGA_VIRTEX2) +				Virtex2_info (desc); +#else +				/* just in case */ +				printf ("%s: No support for Virtex-II devices.\n", +						__FUNCTION__); +#endif +				break; +				/* Add new family types here */ +			default: +				/* we don't need a message here - we give one up above */ +				; +			} +		} else +			printf ("No Device Function Table.\n"); + +		ret_val = FPGA_SUCCESS; +	} else { +		printf ("%s: Invalid device descriptor\n", __FUNCTION__); +	} + +	return ret_val; +} + +int xilinx_reloc (Xilinx_desc * desc, ulong reloc_offset) +{ +	int ret_val = FPGA_FAIL;	/* assume a failure */ + +	if (!xilinx_validate (desc, (char *)__FUNCTION__)) { +		printf ("%s: Invalid device descriptor\n", __FUNCTION__); +	} else +		switch (desc->family) { +		case Xilinx_Spartan2: +#if defined(CONFIG_FPGA_SPARTAN2) +			ret_val = Spartan2_reloc (desc, reloc_offset); +#else +			printf ("%s: No support for Spartan-II devices.\n", +					__FUNCTION__); +#endif +			break; +		case Xilinx_Spartan3: +#if defined(CONFIG_FPGA_SPARTAN3) +			ret_val = Spartan3_reloc (desc, reloc_offset); +#else +			printf ("%s: No support for Spartan-III devices.\n", +					__FUNCTION__); +#endif +			break; +		case Xilinx_Virtex2: +#if defined(CONFIG_FPGA_VIRTEX2) +			ret_val = Virtex2_reloc (desc, reloc_offset); +#else +			printf ("%s: No support for Virtex-II devices.\n", +					__FUNCTION__); +#endif +			break; +			/* Add new family types here */ +		default: +			printf ("%s: Unsupported family type, %d\n", +					__FUNCTION__, desc->family); +		} + +	return ret_val; +} + + +/* ------------------------------------------------------------------------- */ + +static int xilinx_validate (Xilinx_desc * desc, char *fn) +{ +	int ret_val = FALSE; + +	if (desc) { +		if ((desc->family > min_xilinx_type) && +			(desc->family < max_xilinx_type)) { +			if ((desc->iface > min_xilinx_iface_type) && +				(desc->iface < max_xilinx_iface_type)) { +				if (desc->size) { +					ret_val = TRUE; +				} else +					printf ("%s: NULL part size\n", fn); +			} else +				printf ("%s: Invalid Interface type, %d\n", +						fn, desc->iface); +		} else +			printf ("%s: Invalid family type, %d\n", fn, desc->family); +	} else +		printf ("%s: NULL descriptor!\n", fn); + +	return ret_val; +} |