diff options
author | Timothy Pearson <tpearson@raptorengineering.com> | 2019-05-11 15:12:49 -0500 |
---|---|---|
committer | Timothy Pearson <tpearson@raptorengineering.com> | 2019-05-11 15:12:49 -0500 |
commit | 9e80202352dd49bdd9e67b8b906d86f058431505 (patch) | |
tree | 5673c17aad6e3833da8c4ff21b5a11f666ec9fbe /src/roms/u-boot/drivers/fpga | |
download | hqemu-master.zip hqemu-master.tar.gz |
Diffstat (limited to 'src/roms/u-boot/drivers/fpga')
-rw-r--r-- | src/roms/u-boot/drivers/fpga/ACEX1K.c | 249 | ||||
-rw-r--r-- | src/roms/u-boot/drivers/fpga/Makefile | 20 | ||||
-rw-r--r-- | src/roms/u-boot/drivers/fpga/altera.c | 227 | ||||
-rw-r--r-- | src/roms/u-boot/drivers/fpga/cyclon2.c | 205 | ||||
-rw-r--r-- | src/roms/u-boot/drivers/fpga/fpga.c | 287 | ||||
-rw-r--r-- | src/roms/u-boot/drivers/fpga/ivm_core.c | 3149 | ||||
-rw-r--r-- | src/roms/u-boot/drivers/fpga/lattice.c | 380 | ||||
-rw-r--r-- | src/roms/u-boot/drivers/fpga/spartan2.c | 455 | ||||
-rw-r--r-- | src/roms/u-boot/drivers/fpga/spartan3.c | 473 | ||||
-rw-r--r-- | src/roms/u-boot/drivers/fpga/stratixII.c | 190 | ||||
-rw-r--r-- | src/roms/u-boot/drivers/fpga/virtex2.c | 425 | ||||
-rw-r--r-- | src/roms/u-boot/drivers/fpga/xilinx.c | 249 | ||||
-rw-r--r-- | src/roms/u-boot/drivers/fpga/zynqpl.c | 416 |
13 files changed, 6725 insertions, 0 deletions
diff --git a/src/roms/u-boot/drivers/fpga/ACEX1K.c b/src/roms/u-boot/drivers/fpga/ACEX1K.c new file mode 100644 index 0000000..06b8837 --- /dev/null +++ b/src/roms/u-boot/drivers/fpga/ACEX1K.c @@ -0,0 +1,249 @@ +/* + * (C) Copyright 2003 + * Steven Scholz, imc Measurement & Control, steven.scholz@imc-berlin.de + * + * (C) Copyright 2002 + * Rich Ireland, Enterasys Networks, rireland@enterasys.com. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#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, const void *buf, size_t bsize); +static int ACEX1K_ps_dump(Altera_desc *desc, const void *buf, size_t bsize); +/* static int ACEX1K_ps_info(Altera_desc *desc); */ + +/* ------------------------------------------------------------------------- */ +/* ACEX1K Generic Implementation */ +int ACEX1K_load(Altera_desc *desc, const 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, const 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; +} + + +/* ------------------------------------------------------------------------- */ +/* ACEX1K Passive Serial Generic Implementation */ + +static int ACEX1K_ps_load(Altera_desc *desc, const 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, const 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; +} diff --git a/src/roms/u-boot/drivers/fpga/Makefile b/src/roms/u-boot/drivers/fpga/Makefile new file mode 100644 index 0000000..dfb2e7f --- /dev/null +++ b/src/roms/u-boot/drivers/fpga/Makefile @@ -0,0 +1,20 @@ +# +# (C) Copyright 2008 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y += fpga.o +obj-$(CONFIG_FPGA_SPARTAN2) += spartan2.o +obj-$(CONFIG_FPGA_SPARTAN3) += spartan3.o +obj-$(CONFIG_FPGA_VIRTEX2) += virtex2.o +obj-$(CONFIG_FPGA_ZYNQPL) += zynqpl.o +obj-$(CONFIG_FPGA_XILINX) += xilinx.o +obj-$(CONFIG_FPGA_LATTICE) += ivm_core.o lattice.o +ifdef CONFIG_FPGA_ALTERA +obj-y += altera.o +obj-$(CONFIG_FPGA_ACEX1K) += ACEX1K.o +obj-$(CONFIG_FPGA_CYCLON2) += cyclon2.o +obj-$(CONFIG_FPGA_STRATIX_II) += stratixII.o +endif diff --git a/src/roms/u-boot/drivers/fpga/altera.c b/src/roms/u-boot/drivers/fpga/altera.c new file mode 100644 index 0000000..af189f4 --- /dev/null +++ b/src/roms/u-boot/drivers/fpga/altera.c @@ -0,0 +1,227 @@ +/* + * (C) Copyright 2003 + * Steven Scholz, imc Measurement & Control, steven.scholz@imc-berlin.de + * + * (C) Copyright 2002 + * Rich Ireland, Enterasys Networks, rireland@enterasys.com. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * 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, const 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 CYCLONE 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, const 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; +} + +/* ------------------------------------------------------------------------- */ + +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/src/roms/u-boot/drivers/fpga/cyclon2.c b/src/roms/u-boot/drivers/fpga/cyclon2.c new file mode 100644 index 0000000..8ab7679 --- /dev/null +++ b/src/roms/u-boot/drivers/fpga/cyclon2.c @@ -0,0 +1,205 @@ +/* + * (C) Copyright 2006 + * Heiko Schocher, hs@denx.de + * Based on ACE1XK.c + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#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, const void *buf, size_t bsize); +static int CYC2_ps_dump(Altera_desc *desc, const void *buf, size_t bsize); +/* static int CYC2_ps_info( Altera_desc *desc ); */ + +/* ------------------------------------------------------------------------- */ +/* CYCLON2 Generic Implementation */ +int CYC2_load(Altera_desc *desc, const 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; + + case fast_passive_parallel: + /* Fast Passive Parallel (FPP) and PS only differ in what is + * done in the write() callback. Use the existing PS load + * function for FPP, too. + */ + PRINTF ("%s: Launching Fast Passive Parallel 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, const 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; +} + +/* ------------------------------------------------------------------------- */ +/* CYCLON2 Passive Serial Generic Implementation */ +static int CYC2_ps_load(Altera_desc *desc, const 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) (false, true, cookie); /* De-assert nCONFIG */ + udelay(100); + (*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, const 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; +} diff --git a/src/roms/u-boot/drivers/fpga/fpga.c b/src/roms/u-boot/drivers/fpga/fpga.c new file mode 100644 index 0000000..b940d9b --- /dev/null +++ b/src/roms/u-boot/drivers/fpga/fpga.c @@ -0,0 +1,287 @@ +/* + * (C) Copyright 2002 + * Rich Ireland, Enterasys Networks, rireland@enterasys.com. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* Generic FPGA support */ +#include <common.h> /* core U-Boot definitions */ +#include <xilinx.h> /* xilinx specific definitions */ +#include <altera.h> /* altera specific definitions */ +#include <lattice.h> + +/* Local definitions */ +#ifndef CONFIG_MAX_FPGA_DEVICES +#define CONFIG_MAX_FPGA_DEVICES 5 +#endif + +/* Local static data */ +static int next_desc = FPGA_INVALID_DEVICE; +static fpga_desc desc_table[CONFIG_MAX_FPGA_DEVICES]; + +/* + * 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 const fpga_desc *const fpga_get_desc(int devnum) +{ + fpga_desc *desc = (fpga_desc *)NULL; + + if ((devnum >= 0) && (devnum < next_desc)) { + desc = &desc_table[devnum]; + debug("%s: found fpga descriptor #%d @ 0x%p\n", + __func__, devnum, desc); + } + + return desc; +} + +/* + * fpga_validate + * generic parameter checking code + */ +const fpga_desc *const fpga_validate(int devnum, const void *buf, + size_t bsize, char *fn) +{ + const 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) { + debug("%s: Device Descriptor @ 0x%p\n", + __func__, 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 *)__func__, "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 *)__func__, "Altera devices"); +#endif + break; + case fpga_lattice: +#if defined(CONFIG_FPGA_LATTICE) + printf("Lattice Device\nDescriptor @ 0x%p\n", desc); + ret_val = lattice_info(desc->devdesc); +#else + fpga_no_sup((char *)__func__, "Lattice devices"); +#endif + break; + default: + printf("%s: Invalid or unsupported device type %d\n", + __func__, desc->devtype); + } + } else { + printf("%s: Invalid device number %d\n", __func__, devnum); + } + + 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(void) +{ + next_desc = 0; + memset(desc_table, 0, sizeof(desc_table)); + + debug("%s\n", __func__); +} + +/* + * fpga_count + * Basic interface function to get the current number of devices available. + */ +int fpga_count(void) +{ + return next_desc; +} + +/* + * fpga_add + * Add 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", __func__); + } else if ((devtype > fpga_min_type) && (devtype < fpga_undefined)) { + if (desc) { + if (next_desc < CONFIG_MAX_FPGA_DEVICES) { + devnum = next_desc; + desc_table[next_desc].devtype = devtype; + desc_table[next_desc++].devdesc = desc; + } else { + printf("%s: Exceeded Max FPGA device count\n", + __func__); + } + } else { + printf("%s: NULL device descriptor\n", __func__); + } + } else { + printf("%s: Unsupported FPGA type %d\n", __func__, devtype); + } + + return devnum; +} + +/* + * Convert bitstream data and load into the fpga + */ +int __weak fpga_loadbitstream(int devnum, char *fpgadata, size_t size) +{ + printf("Bitstream support not implemented for this FPGA device\n"); + return FPGA_FAIL; +} + +/* + * Generic multiplexing code + */ +int fpga_load(int devnum, const void *buf, size_t bsize) +{ + int ret_val = FPGA_FAIL; /* assume failure */ + const fpga_desc *desc = fpga_validate(devnum, buf, bsize, + (char *)__func__); + + 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 *)__func__, "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 *)__func__, "Altera devices"); +#endif + break; + case fpga_lattice: +#if defined(CONFIG_FPGA_LATTICE) + ret_val = lattice_load(desc->devdesc, buf, bsize); +#else + fpga_no_sup((char *)__func__, "Lattice devices"); +#endif + break; + default: + printf("%s: Invalid or unsupported device type %d\n", + __func__, desc->devtype); + } + } + + return ret_val; +} + +/* + * fpga_dump + * generic multiplexing code + */ +int fpga_dump(int devnum, const void *buf, size_t bsize) +{ + int ret_val = FPGA_FAIL; /* assume failure */ + const fpga_desc *desc = fpga_validate(devnum, buf, bsize, + (char *)__func__); + + 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 *)__func__, "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 *)__func__, "Altera devices"); +#endif + break; + case fpga_lattice: +#if defined(CONFIG_FPGA_LATTICE) + ret_val = lattice_dump(desc->devdesc, buf, bsize); +#else + fpga_no_sup((char *)__func__, "Lattice devices"); +#endif + break; + default: + printf("%s: Invalid or unsupported device type %d\n", + __func__, 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", __func__); + return FPGA_FAIL; + } + } + + return fpga_dev_info(devnum); +} diff --git a/src/roms/u-boot/drivers/fpga/ivm_core.c b/src/roms/u-boot/drivers/fpga/ivm_core.c new file mode 100644 index 0000000..03aea62 --- /dev/null +++ b/src/roms/u-boot/drivers/fpga/ivm_core.c @@ -0,0 +1,3149 @@ +/* + * Porting to u-boot: + * + * (C) Copyright 2010 + * Stefano Babic, DENX Software Engineering, sbabic@denx.de. + * + * Lattice ispVME Embedded code to load Lattice's FPGA: + * + * Copyright 2009 Lattice Semiconductor Corp. + * + * ispVME Embedded allows programming of Lattice's suite of FPGA + * devices on embedded systems through the JTAG port. The software + * is distributed in source code form and is open to re - distribution + * and modification where applicable. + * + * Revision History of ivm_core.c module: + * 4/25/06 ht Change some variables from unsigned short or int + * to long int to make the code compiler independent. + * 5/24/06 ht Support using RESET (TRST) pin as a special purpose + * control pin such as triggering the loading of known + * state exit. + * 3/6/07 ht added functions to support output to terminals + * + * 09/11/07 NN Type cast mismatch variables + * Moved the sclock() function to hardware.c + * 08/28/08 NN Added Calculate checksum support. + * 4/1/09 Nguyen replaced the recursive function call codes on + * the ispVMLCOUNT function + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <linux/string.h> +#include <malloc.h> +#include <lattice.h> + +#define vme_out_char(c) printf("%c", c) +#define vme_out_hex(c) printf("%x", c) +#define vme_out_string(s) printf("%s", s) + +/* + * + * Global variables used to specify the flow control and data type. + * + * g_usFlowControl: flow control register. Each bit in the + * register can potentially change the + * personality of the embedded engine. + * g_usDataType: holds the data type of the current row. + * + */ + +static unsigned short g_usFlowControl; +unsigned short g_usDataType; + +/* + * + * Global variables used to specify the ENDDR and ENDIR. + * + * g_ucEndDR: the state that the device goes to after SDR. + * g_ucEndIR: the state that the device goes to after SIR. + * + */ + +unsigned char g_ucEndDR = DRPAUSE; +unsigned char g_ucEndIR = IRPAUSE; + +/* + * + * Global variables used to support header/trailer. + * + * g_usHeadDR: the number of lead devices in bypass. + * g_usHeadIR: the sum of IR length of lead devices. + * g_usTailDR: the number of tail devices in bypass. + * g_usTailIR: the sum of IR length of tail devices. + * + */ + +static unsigned short g_usHeadDR; +static unsigned short g_usHeadIR; +static unsigned short g_usTailDR; +static unsigned short g_usTailIR; + +/* + * + * Global variable to store the number of bits of data or instruction + * to be shifted into or out from the device. + * + */ + +static unsigned short g_usiDataSize; + +/* + * + * Stores the frequency. Default to 1 MHz. + * + */ + +static int g_iFrequency = 1000; + +/* + * + * Stores the maximum amount of ram needed to hold a row of data. + * + */ + +static unsigned short g_usMaxSize; + +/* + * + * Stores the LSH or RSH value. + * + */ + +static unsigned short g_usShiftValue; + +/* + * + * Stores the current repeat loop value. + * + */ + +static unsigned short g_usRepeatLoops; + +/* + * + * Stores the current vendor. + * + */ + +static signed char g_cVendor = LATTICE; + +/* + * + * Stores the VME file CRC. + * + */ + +unsigned short g_usCalculatedCRC; + +/* + * + * Stores the Device Checksum. + * + */ +/* 08/28/08 NN Added Calculate checksum support. */ +unsigned long g_usChecksum; +static unsigned int g_uiChecksumIndex; + +/* + * + * Stores the current state of the JTAG state machine. + * + */ + +static signed char g_cCurrentJTAGState; + +/* + * + * Global variables used to support looping. + * + * g_pucHeapMemory: holds the entire repeat loop. + * g_iHeapCounter: points to the current byte in the repeat loop. + * g_iHEAPSize: the current size of the repeat in bytes. + * + */ + +unsigned char *g_pucHeapMemory; +unsigned short g_iHeapCounter; +unsigned short g_iHEAPSize; +static unsigned short previous_size; + +/* + * + * Global variables used to support intelligent programming. + * + * g_usIntelDataIndex: points to the current byte of the + * intelligent buffer. + * g_usIntelBufferSize: holds the size of the intelligent + * buffer. + * + */ + +unsigned short g_usIntelDataIndex; +unsigned short g_usIntelBufferSize; + +/* + * + * Supported VME versions. + * + */ + +const char *const g_szSupportedVersions[] = { + "__VME2.0", "__VME3.0", "____12.0", "____12.1", 0}; + +/* + * + * Holds the maximum size of each respective buffer. These variables are used + * to write the HEX files when converting VME to HEX. + * +*/ + +static unsigned short g_usTDOSize; +static unsigned short g_usMASKSize; +static unsigned short g_usTDISize; +static unsigned short g_usDMASKSize; +static unsigned short g_usLCOUNTSize; +static unsigned short g_usHDRSize; +static unsigned short g_usTDRSize; +static unsigned short g_usHIRSize; +static unsigned short g_usTIRSize; +static unsigned short g_usHeapSize; + +/* + * + * Global variables used to store data. + * + * g_pucOutMaskData: local RAM to hold one row of MASK data. + * g_pucInData: local RAM to hold one row of TDI data. + * g_pucOutData: local RAM to hold one row of TDO data. + * g_pucHIRData: local RAM to hold the current SIR header. + * g_pucTIRData: local RAM to hold the current SIR trailer. + * g_pucHDRData: local RAM to hold the current SDR header. + * g_pucTDRData: local RAM to hold the current SDR trailer. + * g_pucIntelBuffer: local RAM to hold the current intelligent buffer + * g_pucOutDMaskData: local RAM to hold one row of DMASK data. + * + */ + +unsigned char *g_pucOutMaskData = NULL, + *g_pucInData = NULL, + *g_pucOutData = NULL, + *g_pucHIRData = NULL, + *g_pucTIRData = NULL, + *g_pucHDRData = NULL, + *g_pucTDRData = NULL, + *g_pucIntelBuffer = NULL, + *g_pucOutDMaskData = NULL; + +/* + * + * JTAG state machine transition table. + * + */ + +struct { + unsigned char CurState; /* From this state */ + unsigned char NextState; /* Step to this state */ + unsigned char Pattern; /* The tragetory of TMS */ + unsigned char Pulses; /* The number of steps */ +} g_JTAGTransistions[25] = { +{ RESET, RESET, 0xFC, 6 }, /* Transitions from RESET */ +{ RESET, IDLE, 0x00, 1 }, +{ RESET, DRPAUSE, 0x50, 5 }, +{ RESET, IRPAUSE, 0x68, 6 }, +{ IDLE, RESET, 0xE0, 3 }, /* Transitions from IDLE */ +{ IDLE, DRPAUSE, 0xA0, 4 }, +{ IDLE, IRPAUSE, 0xD0, 5 }, +{ DRPAUSE, RESET, 0xF8, 5 }, /* Transitions from DRPAUSE */ +{ DRPAUSE, IDLE, 0xC0, 3 }, +{ DRPAUSE, IRPAUSE, 0xF4, 7 }, +{ DRPAUSE, DRPAUSE, 0xE8, 6 },/* 06/14/06 Support POLL STATUS LOOP*/ +{ IRPAUSE, RESET, 0xF8, 5 }, /* Transitions from IRPAUSE */ +{ IRPAUSE, IDLE, 0xC0, 3 }, +{ IRPAUSE, DRPAUSE, 0xE8, 6 }, +{ DRPAUSE, SHIFTDR, 0x80, 2 }, /* Extra transitions using SHIFTDR */ +{ IRPAUSE, SHIFTDR, 0xE0, 5 }, +{ SHIFTDR, DRPAUSE, 0x80, 2 }, +{ SHIFTDR, IDLE, 0xC0, 3 }, +{ IRPAUSE, SHIFTIR, 0x80, 2 },/* Extra transitions using SHIFTIR */ +{ SHIFTIR, IRPAUSE, 0x80, 2 }, +{ SHIFTIR, IDLE, 0xC0, 3 }, +{ DRPAUSE, DRCAPTURE, 0xE0, 4 }, /* 11/15/05 Support DRCAPTURE*/ +{ DRCAPTURE, DRPAUSE, 0x80, 2 }, +{ IDLE, DRCAPTURE, 0x80, 2 }, +{ IRPAUSE, DRCAPTURE, 0xE0, 4 } +}; + +/* + * + * List to hold all LVDS pairs. + * + */ + +LVDSPair *g_pLVDSList; +unsigned short g_usLVDSPairCount; + +/* + * + * Function prototypes. + * + */ + +static signed char ispVMDataCode(void); +static long int ispVMDataSize(void); +static void ispVMData(unsigned char *Data); +static signed char ispVMShift(signed char Code); +static signed char ispVMAmble(signed char Code); +static signed char ispVMLoop(unsigned short a_usLoopCount); +static signed char ispVMBitShift(signed char mode, unsigned short bits); +static void ispVMComment(unsigned short a_usCommentSize); +static void ispVMHeader(unsigned short a_usHeaderSize); +static signed char ispVMLCOUNT(unsigned short a_usCountSize); +static void ispVMClocks(unsigned short Clocks); +static void ispVMBypass(signed char ScanType, unsigned short Bits); +static void ispVMStateMachine(signed char NextState); +static signed char ispVMSend(unsigned short int); +static signed char ispVMRead(unsigned short int); +static signed char ispVMReadandSave(unsigned short int); +static signed char ispVMProcessLVDS(unsigned short a_usLVDSCount); +static void ispVMMemManager(signed char types, unsigned short size); + +/* + * + * External variables and functions in hardware.c module + * + */ +static signed char g_cCurrentJTAGState; + +#ifdef DEBUG + +/* + * + * GetState + * + * Returns the state as a string based on the opcode. Only used + * for debugging purposes. + * + */ + +const char *GetState(unsigned char a_ucState) +{ + switch (a_ucState) { + case RESET: + return "RESET"; + case IDLE: + return "IDLE"; + case IRPAUSE: + return "IRPAUSE"; + case DRPAUSE: + return "DRPAUSE"; + case SHIFTIR: + return "SHIFTIR"; + case SHIFTDR: + return "SHIFTDR"; + case DRCAPTURE:/* 11/15/05 support DRCAPTURE*/ + return "DRCAPTURE"; + default: + break; + } + + return 0; +} + +/* + * + * PrintData + * + * Prints the data. Only used for debugging purposes. + * + */ + +void PrintData(unsigned short a_iDataSize, unsigned char *a_pucData) +{ + /* 09/11/07 NN added local variables initialization */ + unsigned short usByteSize = 0; + unsigned short usBitIndex = 0; + signed short usByteIndex = 0; + unsigned char ucByte = 0; + unsigned char ucFlipByte = 0; + + if (a_iDataSize % 8) { + /* 09/11/07 NN Type cast mismatch variables */ + usByteSize = (unsigned short)(a_iDataSize / 8 + 1); + } else { + /* 09/11/07 NN Type cast mismatch variables */ + usByteSize = (unsigned short)(a_iDataSize / 8); + } + puts("("); + /* 09/11/07 NN Type cast mismatch variables */ + for (usByteIndex = (signed short)(usByteSize - 1); + usByteIndex >= 0; usByteIndex--) { + ucByte = a_pucData[usByteIndex]; + ucFlipByte = 0x00; + + /* + * + * Flip each byte. + * + */ + + for (usBitIndex = 0; usBitIndex < 8; usBitIndex++) { + ucFlipByte <<= 1; + if (ucByte & 0x1) { + ucFlipByte |= 0x1; + } + + ucByte >>= 1; + } + + /* + * + * Print the flipped byte. + * + */ + + printf("%.02X", ucFlipByte); + if ((usByteSize - usByteIndex) % 40 == 39) { + puts("\n\t\t"); + } + if (usByteIndex < 0) + break; + } + puts(")"); +} +#endif /* DEBUG */ + +void ispVMMemManager(signed char cTarget, unsigned short usSize) +{ + switch (cTarget) { + case XTDI: + case TDI: + if (g_pucInData != NULL) { + if (previous_size == usSize) {/*memory exist*/ + break; + } else { + free(g_pucInData); + g_pucInData = NULL; + } + } + g_pucInData = (unsigned char *) malloc(usSize / 8 + 2); + previous_size = usSize; + case XTDO: + case TDO: + if (g_pucOutData != NULL) { + if (previous_size == usSize) { /*already exist*/ + break; + } else { + free(g_pucOutData); + g_pucOutData = NULL; + } + } + g_pucOutData = (unsigned char *) malloc(usSize / 8 + 2); + previous_size = usSize; + break; + case MASK: + if (g_pucOutMaskData != NULL) { + if (previous_size == usSize) {/*already allocated*/ + break; + } else { + free(g_pucOutMaskData); + g_pucOutMaskData = NULL; + } + } + g_pucOutMaskData = (unsigned char *) malloc(usSize / 8 + 2); + previous_size = usSize; + break; + case HIR: + if (g_pucHIRData != NULL) { + free(g_pucHIRData); + g_pucHIRData = NULL; + } + g_pucHIRData = (unsigned char *) malloc(usSize / 8 + 2); + break; + case TIR: + if (g_pucTIRData != NULL) { + free(g_pucTIRData); + g_pucTIRData = NULL; + } + g_pucTIRData = (unsigned char *) malloc(usSize / 8 + 2); + break; + case HDR: + if (g_pucHDRData != NULL) { + free(g_pucHDRData); + g_pucHDRData = NULL; + } + g_pucHDRData = (unsigned char *) malloc(usSize / 8 + 2); + break; + case TDR: + if (g_pucTDRData != NULL) { + free(g_pucTDRData); + g_pucTDRData = NULL; + } + g_pucTDRData = (unsigned char *) malloc(usSize / 8 + 2); + break; + case HEAP: + if (g_pucHeapMemory != NULL) { + free(g_pucHeapMemory); + g_pucHeapMemory = NULL; + } + g_pucHeapMemory = (unsigned char *) malloc(usSize + 2); + break; + case DMASK: + if (g_pucOutDMaskData != NULL) { + if (previous_size == usSize) { /*already allocated*/ + break; + } else { + free(g_pucOutDMaskData); + g_pucOutDMaskData = NULL; + } + } + g_pucOutDMaskData = (unsigned char *) malloc(usSize / 8 + 2); + previous_size = usSize; + break; + case LHEAP: + if (g_pucIntelBuffer != NULL) { + free(g_pucIntelBuffer); + g_pucIntelBuffer = NULL; + } + g_pucIntelBuffer = (unsigned char *) malloc(usSize + 2); + break; + case LVDS: + if (g_pLVDSList != NULL) { + free(g_pLVDSList); + g_pLVDSList = NULL; + } + g_pLVDSList = (LVDSPair *) malloc(usSize * sizeof(LVDSPair)); + if (g_pLVDSList) + memset(g_pLVDSList, 0, usSize * sizeof(LVDSPair)); + break; + default: + return; + } +} + +void ispVMFreeMem(void) +{ + if (g_pucHeapMemory != NULL) { + free(g_pucHeapMemory); + g_pucHeapMemory = NULL; + } + + if (g_pucOutMaskData != NULL) { + free(g_pucOutMaskData); + g_pucOutMaskData = NULL; + } + + if (g_pucInData != NULL) { + free(g_pucInData); + g_pucInData = NULL; + } + + if (g_pucOutData != NULL) { + free(g_pucOutData); + g_pucOutData = NULL; + } + + if (g_pucHIRData != NULL) { + free(g_pucHIRData); + g_pucHIRData = NULL; + } + + if (g_pucTIRData != NULL) { + free(g_pucTIRData); + g_pucTIRData = NULL; + } + + if (g_pucHDRData != NULL) { + free(g_pucHDRData); + g_pucHDRData = NULL; + } + + if (g_pucTDRData != NULL) { + free(g_pucTDRData); + g_pucTDRData = NULL; + } + + if (g_pucOutDMaskData != NULL) { + free(g_pucOutDMaskData); + g_pucOutDMaskData = NULL; + } + + if (g_pucIntelBuffer != NULL) { + free(g_pucIntelBuffer); + g_pucIntelBuffer = NULL; + } + + if (g_pLVDSList != NULL) { + free(g_pLVDSList); + g_pLVDSList = NULL; + } +} + + +/* + * + * ispVMDataSize + * + * Returns a VME-encoded number, usually used to indicate the + * bit length of an SIR/SDR command. + * + */ + +long int ispVMDataSize() +{ + /* 09/11/07 NN added local variables initialization */ + long int iSize = 0; + signed char cCurrentByte = 0; + signed char cIndex = 0; + cIndex = 0; + while ((cCurrentByte = GetByte()) & 0x80) { + iSize |= ((long int) (cCurrentByte & 0x7F)) << cIndex; + cIndex += 7; + } + iSize |= ((long int) (cCurrentByte & 0x7F)) << cIndex; + return iSize; +} + +/* + * + * ispVMCode + * + * This is the heart of the embedded engine. All the high-level opcodes + * are extracted here. Once they have been identified, then it + * will call other functions to handle the processing. + * + */ + +signed char ispVMCode() +{ + /* 09/11/07 NN added local variables initialization */ + unsigned short iRepeatSize = 0; + signed char cOpcode = 0; + signed char cRetCode = 0; + unsigned char ucState = 0; + unsigned short usDelay = 0; + unsigned short usToggle = 0; + unsigned char usByte = 0; + + /* + * + * Check the compression flag only if this is the first time + * this function is entered. Do not check the compression flag if + * it is being called recursively from other functions within + * the embedded engine. + * + */ + + if (!(g_usDataType & LHEAP_IN) && !(g_usDataType & HEAP_IN)) { + usByte = GetByte(); + if (usByte == 0xf1) { + g_usDataType |= COMPRESS; + } else if (usByte == 0xf2) { + g_usDataType &= ~COMPRESS; + } else { + return VME_INVALID_FILE; + } + } + + /* + * + * Begin looping through all the VME opcodes. + * + */ + + while ((cOpcode = GetByte()) >= 0) { + + switch (cOpcode) { + case STATE: + + /* + * Step the JTAG state machine. + */ + + ucState = GetByte(); + + /* + * Step the JTAG state machine to DRCAPTURE + * to support Looping. + */ + + if ((g_usDataType & LHEAP_IN) && + (ucState == DRPAUSE) && + (g_cCurrentJTAGState == ucState)) { + ispVMStateMachine(DRCAPTURE); + } + + ispVMStateMachine(ucState); + +#ifdef DEBUG + if (g_usDataType & LHEAP_IN) { + debug("LDELAY %s ", GetState(ucState)); + } else { + debug("STATE %s;\n", GetState(ucState)); + } +#endif /* DEBUG */ + break; + case SIR: + case SDR: + case XSDR: + +#ifdef DEBUG + switch (cOpcode) { + case SIR: + puts("SIR "); + break; + case SDR: + case XSDR: + if (g_usDataType & LHEAP_IN) { + puts("LSDR "); + } else { + puts("SDR "); + } + break; + } +#endif /* DEBUG */ + /* + * + * Shift in data into the device. + * + */ + + cRetCode = ispVMShift(cOpcode); + if (cRetCode != 0) { + return cRetCode; + } + break; + case WAIT: + + /* + * + * Observe delay. + * + */ + + /* 09/11/07 NN Type cast mismatch variables */ + usDelay = (unsigned short) ispVMDataSize(); + ispVMDelay(usDelay); + +#ifdef DEBUG + if (usDelay & 0x8000) { + + /* + * Since MSB is set, the delay time must be + * decoded to millisecond. The SVF2VME encodes + * the MSB to represent millisecond. + */ + + usDelay &= ~0x8000; + if (g_usDataType & LHEAP_IN) { + printf("%.2E SEC;\n", + (float) usDelay / 1000); + } else { + printf("RUNTEST %.2E SEC;\n", + (float) usDelay / 1000); + } + } else { + /* + * Since MSB is not set, the delay time + * is given as microseconds. + */ + + if (g_usDataType & LHEAP_IN) { + printf("%.2E SEC;\n", + (float) usDelay / 1000000); + } else { + printf("RUNTEST %.2E SEC;\n", + (float) usDelay / 1000000); + } + } +#endif /* DEBUG */ + break; + case TCK: + + /* + * Issue clock toggles. + */ + + /* 09/11/07 NN Type cast mismatch variables */ + usToggle = (unsigned short) ispVMDataSize(); + ispVMClocks(usToggle); + +#ifdef DEBUG + printf("RUNTEST %d TCK;\n", usToggle); +#endif /* DEBUG */ + break; + case ENDDR: + + /* + * + * Set the ENDDR. + * + */ + + g_ucEndDR = GetByte(); + +#ifdef DEBUG + printf("ENDDR %s;\n", GetState(g_ucEndDR)); +#endif /* DEBUG */ + break; + case ENDIR: + + /* + * + * Set the ENDIR. + * + */ + + g_ucEndIR = GetByte(); + +#ifdef DEBUG + printf("ENDIR %s;\n", GetState(g_ucEndIR)); +#endif /* DEBUG */ + break; + case HIR: + case TIR: + case HDR: + case TDR: + +#ifdef DEBUG + switch (cOpcode) { + case HIR: + puts("HIR "); + break; + case TIR: + puts("TIR "); + break; + case HDR: + puts("HDR "); + break; + case TDR: + puts("TDR "); + break; + } +#endif /* DEBUG */ + /* + * Set the header/trailer of the device in order + * to bypass + * successfully. + */ + + cRetCode = ispVMAmble(cOpcode); + if (cRetCode != 0) { + return cRetCode; + } + +#ifdef DEBUG + puts(";\n"); +#endif /* DEBUG */ + break; + case MEM: + + /* + * The maximum RAM required to support + * processing one row of the VME file. + */ + + /* 09/11/07 NN Type cast mismatch variables */ + g_usMaxSize = (unsigned short) ispVMDataSize(); + +#ifdef DEBUG + printf("// MEMSIZE %d\n", g_usMaxSize); +#endif /* DEBUG */ + break; + case VENDOR: + + /* + * + * Set the VENDOR type. + * + */ + + cOpcode = GetByte(); + switch (cOpcode) { + case LATTICE: +#ifdef DEBUG + puts("// VENDOR LATTICE\n"); +#endif /* DEBUG */ + g_cVendor = LATTICE; + break; + case ALTERA: +#ifdef DEBUG + puts("// VENDOR ALTERA\n"); +#endif /* DEBUG */ + g_cVendor = ALTERA; + break; + case XILINX: +#ifdef DEBUG + puts("// VENDOR XILINX\n"); +#endif /* DEBUG */ + g_cVendor = XILINX; + break; + default: + break; + } + break; + case SETFLOW: + + /* + * Set the flow control. Flow control determines + * the personality of the embedded engine. + */ + + /* 09/11/07 NN Type cast mismatch variables */ + g_usFlowControl |= (unsigned short) ispVMDataSize(); + break; + case RESETFLOW: + + /* + * + * Unset the flow control. + * + */ + + /* 09/11/07 NN Type cast mismatch variables */ + g_usFlowControl &= (unsigned short) ~(ispVMDataSize()); + break; + case HEAP: + + /* + * + * Allocate heap size to store loops. + * + */ + + cRetCode = GetByte(); + if (cRetCode != SECUREHEAP) { + return VME_INVALID_FILE; + } + /* 09/11/07 NN Type cast mismatch variables */ + g_iHEAPSize = (unsigned short) ispVMDataSize(); + + /* + * Store the maximum size of the HEAP buffer. + * Used to convert VME to HEX. + */ + + if (g_iHEAPSize > g_usHeapSize) { + g_usHeapSize = g_iHEAPSize; + } + + ispVMMemManager(HEAP, (unsigned short) g_iHEAPSize); + break; + case REPEAT: + + /* + * + * Execute loops. + * + */ + + g_usRepeatLoops = 0; + + /* 09/11/07 NN Type cast mismatch variables */ + iRepeatSize = (unsigned short) ispVMDataSize(); + + cRetCode = ispVMLoop((unsigned short) iRepeatSize); + if (cRetCode != 0) { + return cRetCode; + } + break; + case ENDLOOP: + + /* + * + * Exit point from processing loops. + * + */ + + return cRetCode; + case ENDVME: + + /* + * The only valid exit point that indicates + * end of programming. + */ + + return cRetCode; + case SHR: + + /* + * + * Right-shift address. + * + */ + + g_usFlowControl |= SHIFTRIGHT; + + /* 09/11/07 NN Type cast mismatch variables */ + g_usShiftValue = (unsigned short) (g_usRepeatLoops * + (unsigned short)GetByte()); + break; + case SHL: + + /* + * Left-shift address. + */ + + g_usFlowControl |= SHIFTLEFT; + + /* 09/11/07 NN Type cast mismatch variables */ + g_usShiftValue = (unsigned short) (g_usRepeatLoops * + (unsigned short)GetByte()); + break; + case FREQUENCY: + + /* + * + * Set the frequency. + * + */ + + /* 09/11/07 NN Type cast mismatch variables */ + g_iFrequency = (int) (ispVMDataSize() / 1000); + if (g_iFrequency == 1) + g_iFrequency = 1000; + +#ifdef DEBUG + printf("FREQUENCY %.2E HZ;\n", + (float) g_iFrequency * 1000); +#endif /* DEBUG */ + break; + case LCOUNT: + + /* + * + * Process LCOUNT command. + * + */ + + cRetCode = ispVMLCOUNT((unsigned short)ispVMDataSize()); + if (cRetCode != 0) { + return cRetCode; + } + break; + case VUES: + + /* + * + * Set the flow control to verify USERCODE. + * + */ + + g_usFlowControl |= VERIFYUES; + break; + case COMMENT: + + /* + * + * Display comment. + * + */ + + ispVMComment((unsigned short) ispVMDataSize()); + break; + case LVDS: + + /* + * + * Process LVDS command. + * + */ + + ispVMProcessLVDS((unsigned short) ispVMDataSize()); + break; + case HEADER: + + /* + * + * Discard header. + * + */ + + ispVMHeader((unsigned short) ispVMDataSize()); + break; + /* 03/14/06 Support Toggle ispENABLE signal*/ + case ispEN: + ucState = GetByte(); + if ((ucState == ON) || (ucState == 0x01)) + writePort(g_ucPinENABLE, 0x01); + else + writePort(g_ucPinENABLE, 0x00); + ispVMDelay(1); + break; + /* 05/24/06 support Toggle TRST pin*/ + case TRST: + ucState = GetByte(); + if (ucState == 0x01) + writePort(g_ucPinTRST, 0x01); + else + writePort(g_ucPinTRST, 0x00); + ispVMDelay(1); + break; + default: + + /* + * + * Invalid opcode encountered. + * + */ + +#ifdef DEBUG + printf("\nINVALID OPCODE: 0x%.2X\n", cOpcode); +#endif /* DEBUG */ + + return VME_INVALID_FILE; + } + } + + /* + * + * Invalid exit point. Processing the token 'ENDVME' is the only + * valid way to exit the embedded engine. + * + */ + + return VME_INVALID_FILE; +} + +/* + * + * ispVMDataCode + * + * Processes the TDI/TDO/MASK/DMASK etc of an SIR/SDR command. + * + */ + +signed char ispVMDataCode() +{ + /* 09/11/07 NN added local variables initialization */ + signed char cDataByte = 0; + signed char siDataSource = 0; /*source of data from file by default*/ + + if (g_usDataType & HEAP_IN) { + siDataSource = 1; /*the source of data from memory*/ + } + + /* + * + * Clear the data type register. + * + **/ + + g_usDataType &= ~(MASK_DATA + TDI_DATA + + TDO_DATA + DMASK_DATA + CMASK_DATA); + + /* + * Iterate through SIR/SDR command and look for TDI, + * TDO, MASK, etc. + */ + + while ((cDataByte = GetByte()) >= 0) { + ispVMMemManager(cDataByte, g_usMaxSize); + switch (cDataByte) { + case TDI: + + /* + * Store the maximum size of the TDI buffer. + * Used to convert VME to HEX. + */ + + if (g_usiDataSize > g_usTDISize) { + g_usTDISize = g_usiDataSize; + } + /* + * Updated data type register to indicate that + * TDI data is currently being used. Process the + * data in the VME file into the TDI buffer. + */ + + g_usDataType |= TDI_DATA; + ispVMData(g_pucInData); + break; + case XTDO: + + /* + * Store the maximum size of the TDO buffer. + * Used to convert VME to HEX. + */ + + if (g_usiDataSize > g_usTDOSize) { + g_usTDOSize = g_usiDataSize; + } + + /* + * Updated data type register to indicate that + * TDO data is currently being used. + */ + + g_usDataType |= TDO_DATA; + break; + case TDO: + + /* + * Store the maximum size of the TDO buffer. + * Used to convert VME to HEX. + */ + + if (g_usiDataSize > g_usTDOSize) { + g_usTDOSize = g_usiDataSize; + } + + /* + * Updated data type register to indicate + * that TDO data is currently being used. + * Process the data in the VME file into the + * TDO buffer. + */ + + g_usDataType |= TDO_DATA; + ispVMData(g_pucOutData); + break; + case MASK: + + /* + * Store the maximum size of the MASK buffer. + * Used to convert VME to HEX. + */ + + if (g_usiDataSize > g_usMASKSize) { + g_usMASKSize = g_usiDataSize; + } + + /* + * Updated data type register to indicate that + * MASK data is currently being used. Process + * the data in the VME file into the MASK buffer + */ + + g_usDataType |= MASK_DATA; + ispVMData(g_pucOutMaskData); + break; + case DMASK: + + /* + * Store the maximum size of the DMASK buffer. + * Used to convert VME to HEX. + */ + + if (g_usiDataSize > g_usDMASKSize) { + g_usDMASKSize = g_usiDataSize; + } + + /* + * Updated data type register to indicate that + * DMASK data is currently being used. Process + * the data in the VME file into the DMASK + * buffer. + */ + + g_usDataType |= DMASK_DATA; + ispVMData(g_pucOutDMaskData); + break; + case CMASK: + + /* + * Updated data type register to indicate that + * MASK data is currently being used. Process + * the data in the VME file into the MASK buffer + */ + + g_usDataType |= CMASK_DATA; + ispVMData(g_pucOutMaskData); + break; + case CONTINUE: + return 0; + default: + /* + * Encountered invalid opcode. + */ + return VME_INVALID_FILE; + } + + switch (cDataByte) { + case TDI: + + /* + * Left bit shift. Used when performing + * algorithm looping. + */ + + if (g_usFlowControl & SHIFTLEFT) { + ispVMBitShift(SHL, g_usShiftValue); + g_usFlowControl &= ~SHIFTLEFT; + } + + /* + * Right bit shift. Used when performing + * algorithm looping. + */ + + if (g_usFlowControl & SHIFTRIGHT) { + ispVMBitShift(SHR, g_usShiftValue); + g_usFlowControl &= ~SHIFTRIGHT; + } + default: + break; + } + + if (siDataSource) { + g_usDataType |= HEAP_IN; /*restore from memory*/ + } + } + + if (siDataSource) { /*fetch data from heap memory upon return*/ + g_usDataType |= HEAP_IN; + } + + if (cDataByte < 0) { + + /* + * Encountered invalid opcode. + */ + + return VME_INVALID_FILE; + } else { + return 0; + } +} + +/* + * + * ispVMData + * Extract one row of data operand from the current data type opcode. Perform + * the decompression if necessary. Extra RAM is not required for the + * decompression process. The decompression scheme employed in this module + * is on row by row basis. The format of the data stream: + * [compression code][compressed data stream] + * 0x00 --No compression + * 0x01 --Compress by 0x00. + * Example: + * Original stream: 0x000000000000000000000001 + * Compressed stream: 0x01000901 + * Detail: 0x01 is the code, 0x00 is the key, + * 0x09 is the count of 0x00 bytes, + * 0x01 is the uncompressed byte. + * 0x02 --Compress by 0xFF. + * Example: + * Original stream: 0xFFFFFFFFFFFFFFFFFFFFFF01 + * Compressed stream: 0x02FF0901 + * Detail: 0x02 is the code, 0xFF is the key, + * 0x09 is the count of 0xFF bytes, + * 0x01 is the uncompressed byte. + * 0x03 + * : : + * 0xFE -- Compress by nibble blocks. + * Example: + * Original stream: 0x84210842108421084210 + * Compressed stream: 0x0584210 + * Detail: 0x05 is the code, means 5 nibbles block. + * 0x84210 is the 5 nibble blocks. + * The whole row is 80 bits given by g_usiDataSize. + * The number of times the block repeat itself + * is found by g_usiDataSize/(4*0x05) which is 4. + * 0xFF -- Compress by the most frequently happen byte. + * Example: + * Original stream: 0x04020401030904040404 + * Compressed stream: 0xFF04(0,1,0x02,0,1,0x01,1,0x03,1,0x09,0,0,0) + * or: 0xFF044090181C240 + * Detail: 0xFF is the code, 0x04 is the key. + * a bit of 0 represent the key shall be put into + * the current bit position and a bit of 1 + * represent copying the next of 8 bits of data + * in. + * + */ + +void ispVMData(unsigned char *ByteData) +{ + /* 09/11/07 NN added local variables initialization */ + unsigned short size = 0; + unsigned short i, j, m, getData = 0; + unsigned char cDataByte = 0; + unsigned char compress = 0; + unsigned short FFcount = 0; + unsigned char compr_char = 0xFF; + unsigned short index = 0; + signed char compression = 0; + + /*convert number in bits to bytes*/ + if (g_usiDataSize % 8 > 0) { + /* 09/11/07 NN Type cast mismatch variables */ + size = (unsigned short)(g_usiDataSize / 8 + 1); + } else { + /* 09/11/07 NN Type cast mismatch variables */ + size = (unsigned short)(g_usiDataSize / 8); + } + + /* + * If there is compression, then check if compress by key + * of 0x00 or 0xFF or by other keys or by nibble blocks + */ + + if (g_usDataType & COMPRESS) { + compression = 1; + compress = GetByte(); + if ((compress == VAR) && (g_usDataType & HEAP_IN)) { + getData = 1; + g_usDataType &= ~(HEAP_IN); + compress = GetByte(); + } + + switch (compress) { + case 0x00: + /* No compression */ + compression = 0; + break; + case 0x01: + /* Compress by byte 0x00 */ + compr_char = 0x00; + break; + case 0x02: + /* Compress by byte 0xFF */ + compr_char = 0xFF; + break; + case 0xFF: + /* Huffman encoding */ + compr_char = GetByte(); + i = 8; + for (index = 0; index < size; index++) { + ByteData[index] = 0x00; + if (i > 7) { + cDataByte = GetByte(); + i = 0; + } + if ((cDataByte << i++) & 0x80) + m = 8; + else { + ByteData[index] = compr_char; + m = 0; + } + + for (j = 0; j < m; j++) { + if (i > 7) { + cDataByte = GetByte(); + i = 0; + } + ByteData[index] |= + ((cDataByte << i++) & 0x80) >> j; + } + } + size = 0; + break; + default: + for (index = 0; index < size; index++) + ByteData[index] = 0x00; + for (index = 0; index < compress; index++) { + if (index % 2 == 0) + cDataByte = GetByte(); + for (i = 0; i < size * 2 / compress; i++) { + j = (unsigned short)(index + + (i * (unsigned short)compress)); + /*clear the nibble to zero first*/ + if (j%2) { + if (index % 2) + ByteData[j/2] |= + cDataByte & 0xF; + else + ByteData[j/2] |= + cDataByte >> 4; + } else { + if (index % 2) + ByteData[j/2] |= + cDataByte << 4; + else + ByteData[j/2] |= + cDataByte & 0xF0; + } + } + } + size = 0; + break; + } + } + + FFcount = 0; + + /* Decompress by byte 0x00 or 0xFF */ + for (index = 0; index < size; index++) { + if (FFcount <= 0) { + cDataByte = GetByte(); + if ((cDataByte == VAR) && (g_usDataType&HEAP_IN) && + !getData && !(g_usDataType&COMPRESS)) { + getData = 1; + g_usDataType &= ~(HEAP_IN); + cDataByte = GetByte(); + } + ByteData[index] = cDataByte; + if ((compression) && (cDataByte == compr_char)) + /* 09/11/07 NN Type cast mismatch variables */ + FFcount = (unsigned short) ispVMDataSize(); + /*The number of 0xFF or 0x00 bytes*/ + } else { + FFcount--; /*Use up the 0xFF chain first*/ + ByteData[index] = compr_char; + } + } + + if (getData) { + g_usDataType |= HEAP_IN; + getData = 0; + } +} + +/* + * + * ispVMShift + * + * Processes the SDR/XSDR/SIR commands. + * + */ + +signed char ispVMShift(signed char a_cCode) +{ + /* 09/11/07 NN added local variables initialization */ + unsigned short iDataIndex = 0; + unsigned short iReadLoop = 0; + signed char cRetCode = 0; + + cRetCode = 0; + /* 09/11/07 NN Type cast mismatch variables */ + g_usiDataSize = (unsigned short) ispVMDataSize(); + + /*clear the flags first*/ + g_usDataType &= ~(SIR_DATA + EXPRESS + SDR_DATA); + switch (a_cCode) { + case SIR: + g_usDataType |= SIR_DATA; + /* + * 1/15/04 If performing cascading, then go directly to SHIFTIR. + * Else, go to IRPAUSE before going to SHIFTIR + */ + if (g_usFlowControl & CASCADE) { + ispVMStateMachine(SHIFTIR); + } else { + ispVMStateMachine(IRPAUSE); + ispVMStateMachine(SHIFTIR); + if (g_usHeadIR > 0) { + ispVMBypass(HIR, g_usHeadIR); + sclock(); + } + } + break; + case XSDR: + g_usDataType |= EXPRESS; /*mark simultaneous in and out*/ + case SDR: + g_usDataType |= SDR_DATA; + /* + * 1/15/04 If already in SHIFTDR, then do not move state or + * shift in header. This would imply that the previously + * shifted frame was a cascaded frame. + */ + if (g_cCurrentJTAGState != SHIFTDR) { + /* + * 1/15/04 If performing cascading, then go directly + * to SHIFTDR. Else, go to DRPAUSE before going + * to SHIFTDR + */ + if (g_usFlowControl & CASCADE) { + if (g_cCurrentJTAGState == DRPAUSE) { + ispVMStateMachine(SHIFTDR); + /* + * 1/15/04 If cascade flag has been seat + * and the current state is DRPAUSE, + * this implies that the first cascaded + * frame is about to be shifted in. The + * header must be shifted prior to + * shifting the first cascaded frame. + */ + if (g_usHeadDR > 0) { + ispVMBypass(HDR, g_usHeadDR); + sclock(); + } + } else { + ispVMStateMachine(SHIFTDR); + } + } else { + ispVMStateMachine(DRPAUSE); + ispVMStateMachine(SHIFTDR); + if (g_usHeadDR > 0) { + ispVMBypass(HDR, g_usHeadDR); + sclock(); + } + } + } + break; + default: + return VME_INVALID_FILE; + } + + cRetCode = ispVMDataCode(); + + if (cRetCode != 0) { + return VME_INVALID_FILE; + } + +#ifdef DEBUG + printf("%d ", g_usiDataSize); + + if (g_usDataType & TDI_DATA) { + puts("TDI "); + PrintData(g_usiDataSize, g_pucInData); + } + + if (g_usDataType & TDO_DATA) { + puts("\n\t\tTDO "); + PrintData(g_usiDataSize, g_pucOutData); + } + + if (g_usDataType & MASK_DATA) { + puts("\n\t\tMASK "); + PrintData(g_usiDataSize, g_pucOutMaskData); + } + + if (g_usDataType & DMASK_DATA) { + puts("\n\t\tDMASK "); + PrintData(g_usiDataSize, g_pucOutDMaskData); + } + + puts(";\n"); +#endif /* DEBUG */ + + if (g_usDataType & TDO_DATA || g_usDataType & DMASK_DATA) { + if (g_usDataType & DMASK_DATA) { + cRetCode = ispVMReadandSave(g_usiDataSize); + if (!cRetCode) { + if (g_usTailDR > 0) { + sclock(); + ispVMBypass(TDR, g_usTailDR); + } + ispVMStateMachine(DRPAUSE); + ispVMStateMachine(SHIFTDR); + if (g_usHeadDR > 0) { + ispVMBypass(HDR, g_usHeadDR); + sclock(); + } + for (iDataIndex = 0; + iDataIndex < g_usiDataSize / 8 + 1; + iDataIndex++) + g_pucInData[iDataIndex] = + g_pucOutData[iDataIndex]; + g_usDataType &= ~(TDO_DATA + DMASK_DATA); + cRetCode = ispVMSend(g_usiDataSize); + } + } else { + cRetCode = ispVMRead(g_usiDataSize); + if (cRetCode == -1 && g_cVendor == XILINX) { + for (iReadLoop = 0; iReadLoop < 30; + iReadLoop++) { + cRetCode = ispVMRead(g_usiDataSize); + if (!cRetCode) { + break; + } else { + /* Always DRPAUSE */ + ispVMStateMachine(DRPAUSE); + /* + * Bypass other devices + * when appropriate + */ + ispVMBypass(TDR, g_usTailDR); + ispVMStateMachine(g_ucEndDR); + ispVMStateMachine(IDLE); + ispVMDelay(1000); + } + } + } + } + } else { /*TDI only*/ + cRetCode = ispVMSend(g_usiDataSize); + } + + /*transfer the input data to the output buffer for the next verify*/ + if ((g_usDataType & EXPRESS) || (a_cCode == SDR)) { + if (g_pucOutData) { + for (iDataIndex = 0; iDataIndex < g_usiDataSize / 8 + 1; + iDataIndex++) + g_pucOutData[iDataIndex] = + g_pucInData[iDataIndex]; + } + } + + switch (a_cCode) { + case SIR: + /* 1/15/04 If not performing cascading, then shift ENDIR */ + if (!(g_usFlowControl & CASCADE)) { + if (g_usTailIR > 0) { + sclock(); + ispVMBypass(TIR, g_usTailIR); + } + ispVMStateMachine(g_ucEndIR); + } + break; + case XSDR: + case SDR: + /* 1/15/04 If not performing cascading, then shift ENDDR */ + if (!(g_usFlowControl & CASCADE)) { + if (g_usTailDR > 0) { + sclock(); + ispVMBypass(TDR, g_usTailDR); + } + ispVMStateMachine(g_ucEndDR); + } + break; + default: + break; + } + + return cRetCode; +} + +/* + * + * ispVMAmble + * + * This routine is to extract Header and Trailer parameter for SIR and + * SDR operations. + * + * The Header and Trailer parameter are the pre-amble and post-amble bit + * stream need to be shifted into TDI or out of TDO of the devices. Mostly + * is for the purpose of bypassing the leading or trailing devices. ispVM + * supports only shifting data into TDI to bypass the devices. + * + * For a single device, the header and trailer parameters are all set to 0 + * as default by ispVM. If it is for multiple devices, the header and trailer + * value will change as specified by the VME file. + * + */ + +signed char ispVMAmble(signed char Code) +{ + signed char compress = 0; + /* 09/11/07 NN Type cast mismatch variables */ + g_usiDataSize = (unsigned short)ispVMDataSize(); + +#ifdef DEBUG + printf("%d", g_usiDataSize); +#endif /* DEBUG */ + + if (g_usiDataSize) { + + /* + * Discard the TDI byte and set the compression bit in the data + * type register to false if compression is set because TDI data + * after HIR/HDR/TIR/TDR is not compressed. + */ + + GetByte(); + if (g_usDataType & COMPRESS) { + g_usDataType &= ~(COMPRESS); + compress = 1; + } + } + + switch (Code) { + case HIR: + + /* + * Store the maximum size of the HIR buffer. + * Used to convert VME to HEX. + */ + + if (g_usiDataSize > g_usHIRSize) { + g_usHIRSize = g_usiDataSize; + } + + /* + * Assign the HIR value and allocate memory. + */ + + g_usHeadIR = g_usiDataSize; + if (g_usHeadIR) { + ispVMMemManager(HIR, g_usHeadIR); + ispVMData(g_pucHIRData); + +#ifdef DEBUG + puts(" TDI "); + PrintData(g_usHeadIR, g_pucHIRData); +#endif /* DEBUG */ + } + break; + case TIR: + + /* + * Store the maximum size of the TIR buffer. + * Used to convert VME to HEX. + */ + + if (g_usiDataSize > g_usTIRSize) { + g_usTIRSize = g_usiDataSize; + } + + /* + * Assign the TIR value and allocate memory. + */ + + g_usTailIR = g_usiDataSize; + if (g_usTailIR) { + ispVMMemManager(TIR, g_usTailIR); + ispVMData(g_pucTIRData); + +#ifdef DEBUG + puts(" TDI "); + PrintData(g_usTailIR, g_pucTIRData); +#endif /* DEBUG */ + } + break; + case HDR: + + /* + * Store the maximum size of the HDR buffer. + * Used to convert VME to HEX. + */ + + if (g_usiDataSize > g_usHDRSize) { + g_usHDRSize = g_usiDataSize; + } + + /* + * Assign the HDR value and allocate memory. + * + */ + + g_usHeadDR = g_usiDataSize; + if (g_usHeadDR) { + ispVMMemManager(HDR, g_usHeadDR); + ispVMData(g_pucHDRData); + +#ifdef DEBUG + puts(" TDI "); + PrintData(g_usHeadDR, g_pucHDRData); +#endif /* DEBUG */ + } + break; + case TDR: + + /* + * Store the maximum size of the TDR buffer. + * Used to convert VME to HEX. + */ + + if (g_usiDataSize > g_usTDRSize) { + g_usTDRSize = g_usiDataSize; + } + + /* + * Assign the TDR value and allocate memory. + * + */ + + g_usTailDR = g_usiDataSize; + if (g_usTailDR) { + ispVMMemManager(TDR, g_usTailDR); + ispVMData(g_pucTDRData); + +#ifdef DEBUG + puts(" TDI "); + PrintData(g_usTailDR, g_pucTDRData); +#endif /* DEBUG */ + } + break; + default: + break; + } + + /* + * + * Re-enable compression if it was previously set. + * + **/ + + if (compress) { + g_usDataType |= COMPRESS; + } + + if (g_usiDataSize) { + Code = GetByte(); + if (Code == CONTINUE) { + return 0; + } else { + + /* + * Encountered invalid opcode. + */ + + return VME_INVALID_FILE; + } + } + + return 0; +} + +/* + * + * ispVMLoop + * + * Perform the function call upon by the REPEAT opcode. + * Memory is to be allocated to store the entire loop from REPEAT to ENDLOOP. + * After the loop is stored then execution begin. The REPEATLOOP flag is set + * on the g_usFlowControl register to indicate the repeat loop is in session + * and therefore fetch opcode from the memory instead of from the file. + * + */ + +signed char ispVMLoop(unsigned short a_usLoopCount) +{ + /* 09/11/07 NN added local variables initialization */ + signed char cRetCode = 0; + unsigned short iHeapIndex = 0; + unsigned short iLoopIndex = 0; + + g_usShiftValue = 0; + for (iHeapIndex = 0; iHeapIndex < g_iHEAPSize; iHeapIndex++) { + g_pucHeapMemory[iHeapIndex] = GetByte(); + } + + if (g_pucHeapMemory[iHeapIndex - 1] != ENDLOOP) { + return VME_INVALID_FILE; + } + + g_usFlowControl |= REPEATLOOP; + g_usDataType |= HEAP_IN; + + for (iLoopIndex = 0; iLoopIndex < a_usLoopCount; iLoopIndex++) { + g_iHeapCounter = 0; + cRetCode = ispVMCode(); + g_usRepeatLoops++; + if (cRetCode < 0) { + break; + } + } + + g_usDataType &= ~(HEAP_IN); + g_usFlowControl &= ~(REPEATLOOP); + return cRetCode; +} + +/* + * + * ispVMBitShift + * + * Shift the TDI stream left or right by the number of bits. The data in + * *g_pucInData is of the VME format, so the actual shifting is the reverse of + * IEEE 1532 or SVF format. + * + */ + +signed char ispVMBitShift(signed char mode, unsigned short bits) +{ + /* 09/11/07 NN added local variables initialization */ + unsigned short i = 0; + unsigned short size = 0; + unsigned short tmpbits = 0; + + if (g_usiDataSize % 8 > 0) { + /* 09/11/07 NN Type cast mismatch variables */ + size = (unsigned short)(g_usiDataSize / 8 + 1); + } else { + /* 09/11/07 NN Type cast mismatch variables */ + size = (unsigned short)(g_usiDataSize / 8); + } + + switch (mode) { + case SHR: + for (i = 0; i < size; i++) { + if (g_pucInData[i] != 0) { + tmpbits = bits; + while (tmpbits > 0) { + g_pucInData[i] <<= 1; + if (g_pucInData[i] == 0) { + i--; + g_pucInData[i] = 1; + } + tmpbits--; + } + } + } + break; + case SHL: + for (i = 0; i < size; i++) { + if (g_pucInData[i] != 0) { + tmpbits = bits; + while (tmpbits > 0) { + g_pucInData[i] >>= 1; + if (g_pucInData[i] == 0) { + i--; + g_pucInData[i] = 8; + } + tmpbits--; + } + } + } + break; + default: + return VME_INVALID_FILE; + } + + return 0; +} + +/* + * + * ispVMComment + * + * Displays the SVF comments. + * + */ + +void ispVMComment(unsigned short a_usCommentSize) +{ + char cCurByte = 0; + for (; a_usCommentSize > 0; a_usCommentSize--) { + /* + * + * Print character to the terminal. + * + **/ + cCurByte = GetByte(); + vme_out_char(cCurByte); + } + cCurByte = '\n'; + vme_out_char(cCurByte); +} + +/* + * + * ispVMHeader + * + * Iterate the length of the header and discard it. + * + */ + +void ispVMHeader(unsigned short a_usHeaderSize) +{ + for (; a_usHeaderSize > 0; a_usHeaderSize--) { + GetByte(); + } +} + +/* + * + * ispVMCalculateCRC32 + * + * Calculate the 32-bit CRC. + * + */ + +void ispVMCalculateCRC32(unsigned char a_ucData) +{ + /* 09/11/07 NN added local variables initialization */ + unsigned char ucIndex = 0; + unsigned char ucFlipData = 0; + unsigned short usCRCTableEntry = 0; + unsigned int crc_table[16] = { + 0x0000, 0xCC01, 0xD801, + 0x1400, 0xF001, 0x3C00, + 0x2800, 0xE401, 0xA001, + 0x6C00, 0x7800, 0xB401, + 0x5000, 0x9C01, 0x8801, + 0x4400 + }; + + for (ucIndex = 0; ucIndex < 8; ucIndex++) { + ucFlipData <<= 1; + if (a_ucData & 0x01) { + ucFlipData |= 0x01; + } + a_ucData >>= 1; + } + + /* 09/11/07 NN Type cast mismatch variables */ + usCRCTableEntry = (unsigned short)(crc_table[g_usCalculatedCRC & 0xF]); + g_usCalculatedCRC = (unsigned short)((g_usCalculatedCRC >> 4) & 0x0FFF); + g_usCalculatedCRC = (unsigned short)(g_usCalculatedCRC ^ + usCRCTableEntry ^ crc_table[ucFlipData & 0xF]); + usCRCTableEntry = (unsigned short)(crc_table[g_usCalculatedCRC & 0xF]); + g_usCalculatedCRC = (unsigned short)((g_usCalculatedCRC >> 4) & 0x0FFF); + g_usCalculatedCRC = (unsigned short)(g_usCalculatedCRC ^ + usCRCTableEntry ^ crc_table[(ucFlipData >> 4) & 0xF]); +} + +/* + * + * ispVMLCOUNT + * + * Process the intelligent programming loops. + * + */ + +signed char ispVMLCOUNT(unsigned short a_usCountSize) +{ + unsigned short usContinue = 1; + unsigned short usIntelBufferIndex = 0; + unsigned short usCountIndex = 0; + signed char cRetCode = 0; + signed char cRepeatHeap = 0; + signed char cOpcode = 0; + unsigned char ucState = 0; + unsigned short usDelay = 0; + unsigned short usToggle = 0; + + g_usIntelBufferSize = (unsigned short)ispVMDataSize(); + + /* + * Allocate memory for intel buffer. + * + */ + + ispVMMemManager(LHEAP, g_usIntelBufferSize); + + /* + * Store the maximum size of the intelligent buffer. + * Used to convert VME to HEX. + */ + + if (g_usIntelBufferSize > g_usLCOUNTSize) { + g_usLCOUNTSize = g_usIntelBufferSize; + } + + /* + * Copy intel data to the buffer. + */ + + for (usIntelBufferIndex = 0; usIntelBufferIndex < g_usIntelBufferSize; + usIntelBufferIndex++) { + g_pucIntelBuffer[usIntelBufferIndex] = GetByte(); + } + + /* + * Set the data type register to get data from the intelligent + * data buffer. + */ + + g_usDataType |= LHEAP_IN; + + /* + * + * If the HEAP_IN flag is set, temporarily unset the flag so data will be + * retrieved from the status buffer. + * + **/ + + if (g_usDataType & HEAP_IN) { + g_usDataType &= ~HEAP_IN; + cRepeatHeap = 1; + } + +#ifdef DEBUG + printf("LCOUNT %d;\n", a_usCountSize); +#endif /* DEBUG */ + + /* + * Iterate through the intelligent programming command. + */ + + for (usCountIndex = 0; usCountIndex < a_usCountSize; usCountIndex++) { + + /* + * + * Initialize the intel data index to 0 before each iteration. + * + **/ + + g_usIntelDataIndex = 0; + cOpcode = 0; + ucState = 0; + usDelay = 0; + usToggle = 0; + usContinue = 1; + + /* + * + * Begin looping through all the VME opcodes. + * + */ + /* + * 4/1/09 Nguyen replaced the recursive function call codes on + * the ispVMLCOUNT function + * + */ + while (usContinue) { + cOpcode = GetByte(); + switch (cOpcode) { + case HIR: + case TIR: + case HDR: + case TDR: + /* + * Set the header/trailer of the device in order + * to bypass successfully. + */ + + ispVMAmble(cOpcode); + break; + case STATE: + + /* + * Step the JTAG state machine. + */ + + ucState = GetByte(); + /* + * Step the JTAG state machine to DRCAPTURE + * to support Looping. + */ + + if ((g_usDataType & LHEAP_IN) && + (ucState == DRPAUSE) && + (g_cCurrentJTAGState == ucState)) { + ispVMStateMachine(DRCAPTURE); + } + ispVMStateMachine(ucState); +#ifdef DEBUG + printf("LDELAY %s ", GetState(ucState)); +#endif /* DEBUG */ + break; + case SIR: +#ifdef DEBUG + printf("SIR "); +#endif /* DEBUG */ + /* + * Shift in data into the device. + */ + + cRetCode = ispVMShift(cOpcode); + break; + case SDR: + +#ifdef DEBUG + printf("LSDR "); +#endif /* DEBUG */ + /* + * Shift in data into the device. + */ + + cRetCode = ispVMShift(cOpcode); + break; + case WAIT: + + /* + * + * Observe delay. + * + */ + + usDelay = (unsigned short)ispVMDataSize(); + ispVMDelay(usDelay); + +#ifdef DEBUG + if (usDelay & 0x8000) { + + /* + * Since MSB is set, the delay time must + * be decoded to millisecond. The + * SVF2VME encodes the MSB to represent + * millisecond. + */ + + usDelay &= ~0x8000; + printf("%.2E SEC;\n", + (float) usDelay / 1000); + } else { + /* + * Since MSB is not set, the delay time + * is given as microseconds. + */ + + printf("%.2E SEC;\n", + (float) usDelay / 1000000); + } +#endif /* DEBUG */ + break; + case TCK: + + /* + * Issue clock toggles. + */ + + usToggle = (unsigned short)ispVMDataSize(); + ispVMClocks(usToggle); + +#ifdef DEBUG + printf("RUNTEST %d TCK;\n", usToggle); +#endif /* DEBUG */ + break; + case ENDLOOP: + + /* + * Exit point from processing loops. + */ + usContinue = 0; + break; + + case COMMENT: + + /* + * Display comment. + */ + + ispVMComment((unsigned short) ispVMDataSize()); + break; + case ispEN: + ucState = GetByte(); + if ((ucState == ON) || (ucState == 0x01)) + writePort(g_ucPinENABLE, 0x01); + else + writePort(g_ucPinENABLE, 0x00); + ispVMDelay(1); + break; + case TRST: + if (GetByte() == 0x01) + writePort(g_ucPinTRST, 0x01); + else + writePort(g_ucPinTRST, 0x00); + ispVMDelay(1); + break; + default: + + /* + * Invalid opcode encountered. + */ + + debug("\nINVALID OPCODE: 0x%.2X\n", cOpcode); + + return VME_INVALID_FILE; + } + } + if (cRetCode >= 0) { + /* + * Break if intelligent programming is successful. + */ + + break; + } + + } + /* + * If HEAP_IN flag was temporarily disabled, + * re-enable it before exiting + */ + + if (cRepeatHeap) { + g_usDataType |= HEAP_IN; + } + + /* + * Set the data type register to not get data from the + * intelligent data buffer. + */ + + g_usDataType &= ~LHEAP_IN; + return cRetCode; +} +/* + * + * ispVMClocks + * + * Applies the specified number of pulses to TCK. + * + */ + +void ispVMClocks(unsigned short Clocks) +{ + unsigned short iClockIndex = 0; + for (iClockIndex = 0; iClockIndex < Clocks; iClockIndex++) { + sclock(); + } +} + +/* + * + * ispVMBypass + * + * This procedure takes care of the HIR, HDR, TIR, TDR for the + * purpose of putting the other devices into Bypass mode. The + * current state is checked to find out if it is at DRPAUSE or + * IRPAUSE. If it is at DRPAUSE, perform bypass register scan. + * If it is at IRPAUSE, scan into instruction registers the bypass + * instruction. + * + */ + +void ispVMBypass(signed char ScanType, unsigned short Bits) +{ + /* 09/11/07 NN added local variables initialization */ + unsigned short iIndex = 0; + unsigned short iSourceIndex = 0; + unsigned char cBitState = 0; + unsigned char cCurByte = 0; + unsigned char *pcSource = NULL; + + if (Bits <= 0) { + return; + } + + switch (ScanType) { + case HIR: + pcSource = g_pucHIRData; + break; + case TIR: + pcSource = g_pucTIRData; + break; + case HDR: + pcSource = g_pucHDRData; + break; + case TDR: + pcSource = g_pucTDRData; + break; + default: + break; + } + + iSourceIndex = 0; + cBitState = 0; + for (iIndex = 0; iIndex < Bits - 1; iIndex++) { + /* Scan instruction or bypass register */ + if (iIndex % 8 == 0) { + cCurByte = pcSource[iSourceIndex++]; + } + cBitState = (unsigned char) (((cCurByte << iIndex % 8) & 0x80) + ? 0x01 : 0x00); + writePort(g_ucPinTDI, cBitState); + sclock(); + } + + if (iIndex % 8 == 0) { + cCurByte = pcSource[iSourceIndex++]; + } + + cBitState = (unsigned char) (((cCurByte << iIndex % 8) & 0x80) + ? 0x01 : 0x00); + writePort(g_ucPinTDI, cBitState); +} + +/* + * + * ispVMStateMachine + * + * This procedure steps all devices in the daisy chain from a given + * JTAG state to the next desirable state. If the next state is TLR, + * the JTAG state machine is brute forced into TLR by driving TMS + * high and pulse TCK 6 times. + * + */ + +void ispVMStateMachine(signed char cNextJTAGState) +{ + /* 09/11/07 NN added local variables initialization */ + signed char cPathIndex = 0; + signed char cStateIndex = 0; + + if ((g_cCurrentJTAGState == cNextJTAGState) && + (cNextJTAGState != RESET)) { + return; + } + + for (cStateIndex = 0; cStateIndex < 25; cStateIndex++) { + if ((g_cCurrentJTAGState == + g_JTAGTransistions[cStateIndex].CurState) && + (cNextJTAGState == + g_JTAGTransistions[cStateIndex].NextState)) { + break; + } + } + + g_cCurrentJTAGState = cNextJTAGState; + for (cPathIndex = 0; + cPathIndex < g_JTAGTransistions[cStateIndex].Pulses; + cPathIndex++) { + if ((g_JTAGTransistions[cStateIndex].Pattern << cPathIndex) + & 0x80) { + writePort(g_ucPinTMS, (unsigned char) 0x01); + } else { + writePort(g_ucPinTMS, (unsigned char) 0x00); + } + sclock(); + } + + writePort(g_ucPinTDI, 0x00); + writePort(g_ucPinTMS, 0x00); +} + +/* + * + * ispVMStart + * + * Enable the port to the device and set the state to RESET (TLR). + * + */ + +void ispVMStart() +{ +#ifdef DEBUG + printf("// ISPVM EMBEDDED ADDED\n"); + printf("STATE RESET;\n"); +#endif + g_usFlowControl = 0; + g_usDataType = g_uiChecksumIndex = g_cCurrentJTAGState = 0; + g_usHeadDR = g_usHeadIR = g_usTailDR = g_usTailIR = 0; + g_usMaxSize = g_usShiftValue = g_usRepeatLoops = 0; + g_usTDOSize = g_usMASKSize = g_usTDISize = 0; + g_usDMASKSize = g_usLCOUNTSize = g_usHDRSize = 0; + g_usTDRSize = g_usHIRSize = g_usTIRSize = g_usHeapSize = 0; + g_pLVDSList = NULL; + g_usLVDSPairCount = 0; + previous_size = 0; + + ispVMStateMachine(RESET); /*step devices to RESET state*/ +} + +/* + * + * ispVMEnd + * + * Set the state of devices to RESET to enable the devices and disable + * the port. + * + */ + +void ispVMEnd() +{ +#ifdef DEBUG + printf("// ISPVM EMBEDDED ADDED\n"); + printf("STATE RESET;\n"); + printf("RUNTEST 1.00E-001 SEC;\n"); +#endif + + ispVMStateMachine(RESET); /*step devices to RESET state */ + ispVMDelay(1000); /*wake up devices*/ +} + +/* + * + * ispVMSend + * + * Send the TDI data stream to devices. The data stream can be + * instructions or data. + * + */ + +signed char ispVMSend(unsigned short a_usiDataSize) +{ + /* 09/11/07 NN added local variables initialization */ + unsigned short iIndex = 0; + unsigned short iInDataIndex = 0; + unsigned char cCurByte = 0; + unsigned char cBitState = 0; + + for (iIndex = 0; iIndex < a_usiDataSize - 1; iIndex++) { + if (iIndex % 8 == 0) { + cCurByte = g_pucInData[iInDataIndex++]; + } + cBitState = (unsigned char)(((cCurByte << iIndex % 8) & 0x80) + ? 0x01 : 0x00); + writePort(g_ucPinTDI, cBitState); + sclock(); + } + + if (iIndex % 8 == 0) { + /* Take care of the last bit */ + cCurByte = g_pucInData[iInDataIndex]; + } + + cBitState = (unsigned char) (((cCurByte << iIndex % 8) & 0x80) + ? 0x01 : 0x00); + + writePort(g_ucPinTDI, cBitState); + if (g_usFlowControl & CASCADE) { + /*1/15/04 Clock in last bit for the first n-1 cascaded frames */ + sclock(); + } + + return 0; +} + +/* + * + * ispVMRead + * + * Read the data stream from devices and verify. + * + */ + +signed char ispVMRead(unsigned short a_usiDataSize) +{ + /* 09/11/07 NN added local variables initialization */ + unsigned short usDataSizeIndex = 0; + unsigned short usErrorCount = 0; + unsigned short usLastBitIndex = 0; + unsigned char cDataByte = 0; + unsigned char cMaskByte = 0; + unsigned char cInDataByte = 0; + unsigned char cCurBit = 0; + unsigned char cByteIndex = 0; + unsigned short usBufferIndex = 0; + unsigned char ucDisplayByte = 0x00; + unsigned char ucDisplayFlag = 0x01; + char StrChecksum[256] = {0}; + unsigned char g_usCalculateChecksum = 0x00; + + /* 09/11/07 NN Type cast mismatch variables */ + usLastBitIndex = (unsigned short)(a_usiDataSize - 1); + +#ifndef DEBUG + /* + * If mask is not all zeros, then set the display flag to 0x00, + * otherwise it shall be set to 0x01 to indicate that data read + * from the device shall be displayed. If DEBUG is defined, + * always display data. + */ + + for (usDataSizeIndex = 0; usDataSizeIndex < (a_usiDataSize + 7) / 8; + usDataSizeIndex++) { + if (g_usDataType & MASK_DATA) { + if (g_pucOutMaskData[usDataSizeIndex] != 0x00) { + ucDisplayFlag = 0x00; + break; + } + } else if (g_usDataType & CMASK_DATA) { + g_usCalculateChecksum = 0x01; + ucDisplayFlag = 0x00; + break; + } else { + ucDisplayFlag = 0x00; + break; + } + } +#endif /* DEBUG */ + + /* + * + * Begin shifting data in and out of the device. + * + **/ + + for (usDataSizeIndex = 0; usDataSizeIndex < a_usiDataSize; + usDataSizeIndex++) { + if (cByteIndex == 0) { + + /* + * Grab byte from TDO buffer. + */ + + if (g_usDataType & TDO_DATA) { + cDataByte = g_pucOutData[usBufferIndex]; + } + + /* + * Grab byte from MASK buffer. + */ + + if (g_usDataType & MASK_DATA) { + cMaskByte = g_pucOutMaskData[usBufferIndex]; + } else { + cMaskByte = 0xFF; + } + + /* + * Grab byte from CMASK buffer. + */ + + if (g_usDataType & CMASK_DATA) { + cMaskByte = 0x00; + g_usCalculateChecksum = 0x01; + } + + /* + * Grab byte from TDI buffer. + */ + + if (g_usDataType & TDI_DATA) { + cInDataByte = g_pucInData[usBufferIndex]; + } + + usBufferIndex++; + } + + cCurBit = readPort(); + + if (ucDisplayFlag) { + ucDisplayByte <<= 1; + ucDisplayByte |= cCurBit; + } + + /* + * Check if data read from port matches with expected TDO. + */ + + if (g_usDataType & TDO_DATA) { + /* 08/28/08 NN Added Calculate checksum support. */ + if (g_usCalculateChecksum) { + if (cCurBit == 0x01) + g_usChecksum += + (1 << (g_uiChecksumIndex % 8)); + g_uiChecksumIndex++; + } else { + if ((((cMaskByte << cByteIndex) & 0x80) + ? 0x01 : 0x00)) { + if (cCurBit != (unsigned char) + (((cDataByte << cByteIndex) & 0x80) + ? 0x01 : 0x00)) { + usErrorCount++; + } + } + } + } + + /* + * Write TDI data to the port. + */ + + writePort(g_ucPinTDI, + (unsigned char)(((cInDataByte << cByteIndex) & 0x80) + ? 0x01 : 0x00)); + + if (usDataSizeIndex < usLastBitIndex) { + + /* + * Clock data out from the data shift register. + */ + + sclock(); + } else if (g_usFlowControl & CASCADE) { + + /* + * Clock in last bit for the first N - 1 cascaded frames + */ + + sclock(); + } + + /* + * Increment the byte index. If it exceeds 7, then reset it back + * to zero. + */ + + cByteIndex++; + if (cByteIndex >= 8) { + if (ucDisplayFlag) { + + /* + * Store displayed data in the TDO buffer. By reusing + * the TDO buffer to store displayed data, there is no + * need to allocate a buffer simply to hold display + * data. This will not cause any false verification + * errors because the true TDO byte has already + * been consumed. + */ + + g_pucOutData[usBufferIndex - 1] = ucDisplayByte; + ucDisplayByte = 0; + } + + cByteIndex = 0; + } + /* 09/12/07 Nguyen changed to display the 1 bit expected data */ + else if (a_usiDataSize == 1) { + if (ucDisplayFlag) { + + /* + * Store displayed data in the TDO buffer. + * By reusing the TDO buffer to store displayed + * data, there is no need to allocate + * a buffer simply to hold display data. This + * will not cause any false verification errors + * because the true TDO byte has already + * been consumed. + */ + + /* + * Flip ucDisplayByte and store it in cDataByte. + */ + cDataByte = 0x00; + for (usBufferIndex = 0; usBufferIndex < 8; + usBufferIndex++) { + cDataByte <<= 1; + if (ucDisplayByte & 0x01) { + cDataByte |= 0x01; + } + ucDisplayByte >>= 1; + } + g_pucOutData[0] = cDataByte; + ucDisplayByte = 0; + } + + cByteIndex = 0; + } + } + + if (ucDisplayFlag) { + +#ifdef DEBUG + debug("RECEIVED TDO ("); +#else + vme_out_string("Display Data: 0x"); +#endif /* DEBUG */ + + /* 09/11/07 NN Type cast mismatch variables */ + for (usDataSizeIndex = (unsigned short) + ((a_usiDataSize + 7) / 8); + usDataSizeIndex > 0 ; usDataSizeIndex--) { + cMaskByte = g_pucOutData[usDataSizeIndex - 1]; + cDataByte = 0x00; + + /* + * Flip cMaskByte and store it in cDataByte. + */ + + for (usBufferIndex = 0; usBufferIndex < 8; + usBufferIndex++) { + cDataByte <<= 1; + if (cMaskByte & 0x01) { + cDataByte |= 0x01; + } + cMaskByte >>= 1; + } +#ifdef DEBUG + printf("%.2X", cDataByte); + if ((((a_usiDataSize + 7) / 8) - usDataSizeIndex) + % 40 == 39) { + printf("\n\t\t"); + } +#else + vme_out_hex(cDataByte); +#endif /* DEBUG */ + } + +#ifdef DEBUG + printf(")\n\n"); +#else + vme_out_string("\n\n"); +#endif /* DEBUG */ + /* 09/02/08 Nguyen changed to display the data Checksum */ + if (g_usChecksum != 0) { + g_usChecksum &= 0xFFFF; + sprintf(StrChecksum, "Data Checksum: %.4lX\n\n", + g_usChecksum); + vme_out_string(StrChecksum); + g_usChecksum = 0; + } + } + + if (usErrorCount > 0) { + if (g_usFlowControl & VERIFYUES) { + vme_out_string( + "USERCODE verification failed. " + "Continue programming......\n\n"); + g_usFlowControl &= ~(VERIFYUES); + return 0; + } else { + +#ifdef DEBUG + printf("TOTAL ERRORS: %d\n", usErrorCount); +#endif /* DEBUG */ + + return VME_VERIFICATION_FAILURE; + } + } else { + if (g_usFlowControl & VERIFYUES) { + vme_out_string("USERCODE verification passed. " + "Programming aborted.\n\n"); + g_usFlowControl &= ~(VERIFYUES); + return 1; + } else { + return 0; + } + } +} + +/* + * + * ispVMReadandSave + * + * Support dynamic I/O. + * + */ + +signed char ispVMReadandSave(unsigned short int a_usiDataSize) +{ + /* 09/11/07 NN added local variables initialization */ + unsigned short int usDataSizeIndex = 0; + unsigned short int usLastBitIndex = 0; + unsigned short int usBufferIndex = 0; + unsigned short int usOutBitIndex = 0; + unsigned short int usLVDSIndex = 0; + unsigned char cDataByte = 0; + unsigned char cDMASKByte = 0; + unsigned char cInDataByte = 0; + unsigned char cCurBit = 0; + unsigned char cByteIndex = 0; + signed char cLVDSByteIndex = 0; + + /* 09/11/07 NN Type cast mismatch variables */ + usLastBitIndex = (unsigned short) (a_usiDataSize - 1); + + /* + * + * Iterate through the data bits. + * + */ + + for (usDataSizeIndex = 0; usDataSizeIndex < a_usiDataSize; + usDataSizeIndex++) { + if (cByteIndex == 0) { + + /* + * Grab byte from DMASK buffer. + */ + + if (g_usDataType & DMASK_DATA) { + cDMASKByte = g_pucOutDMaskData[usBufferIndex]; + } else { + cDMASKByte = 0x00; + } + + /* + * Grab byte from TDI buffer. + */ + + if (g_usDataType & TDI_DATA) { + cInDataByte = g_pucInData[usBufferIndex]; + } + + usBufferIndex++; + } + + cCurBit = readPort(); + cDataByte = (unsigned char)(((cInDataByte << cByteIndex) & 0x80) + ? 0x01 : 0x00); + + /* + * Initialize the byte to be zero. + */ + + if (usOutBitIndex % 8 == 0) { + g_pucOutData[usOutBitIndex / 8] = 0x00; + } + + /* + * Use TDI, DMASK, and device TDO to create new TDI (actually + * stored in g_pucOutData). + */ + + if ((((cDMASKByte << cByteIndex) & 0x80) ? 0x01 : 0x00)) { + + if (g_pLVDSList) { + for (usLVDSIndex = 0; + usLVDSIndex < g_usLVDSPairCount; + usLVDSIndex++) { + if (g_pLVDSList[usLVDSIndex]. + usNegativeIndex == + usDataSizeIndex) { + g_pLVDSList[usLVDSIndex]. + ucUpdate = 0x01; + break; + } + } + } + + /* + * DMASK bit is 1, use TDI. + */ + + g_pucOutData[usOutBitIndex / 8] |= (unsigned char) + (((cDataByte & 0x1) ? 0x01 : 0x00) << + (7 - usOutBitIndex % 8)); + } else { + + /* + * DMASK bit is 0, use device TDO. + */ + + g_pucOutData[usOutBitIndex / 8] |= (unsigned char) + (((cCurBit & 0x1) ? 0x01 : 0x00) << + (7 - usOutBitIndex % 8)); + } + + /* + * Shift in TDI in order to get TDO out. + */ + + usOutBitIndex++; + writePort(g_ucPinTDI, cDataByte); + if (usDataSizeIndex < usLastBitIndex) { + sclock(); + } + + /* + * Increment the byte index. If it exceeds 7, then reset it back + * to zero. + */ + + cByteIndex++; + if (cByteIndex >= 8) { + cByteIndex = 0; + } + } + + /* + * If g_pLVDSList exists and pairs need updating, then update + * the negative-pair to receive the flipped positive-pair value. + */ + + if (g_pLVDSList) { + for (usLVDSIndex = 0; usLVDSIndex < g_usLVDSPairCount; + usLVDSIndex++) { + if (g_pLVDSList[usLVDSIndex].ucUpdate) { + + /* + * Read the positive value and flip it. + */ + + cDataByte = (unsigned char) + (((g_pucOutData[g_pLVDSList[usLVDSIndex]. + usPositiveIndex / 8] + << (g_pLVDSList[usLVDSIndex]. + usPositiveIndex % 8)) & 0x80) ? + 0x01 : 0x00); + /* 09/11/07 NN Type cast mismatch variables */ + cDataByte = (unsigned char) (!cDataByte); + + /* + * Get the byte that needs modification. + */ + + cInDataByte = + g_pucOutData[g_pLVDSList[usLVDSIndex]. + usNegativeIndex / 8]; + + if (cDataByte) { + + /* + * Copy over the current byte and + * set the negative bit to 1. + */ + + cDataByte = 0x00; + for (cLVDSByteIndex = 7; + cLVDSByteIndex >= 0; + cLVDSByteIndex--) { + cDataByte <<= 1; + if (7 - + (g_pLVDSList[usLVDSIndex]. + usNegativeIndex % 8) == + cLVDSByteIndex) { + + /* + * Set negative bit to 1 + */ + + cDataByte |= 0x01; + } else if (cInDataByte & 0x80) { + cDataByte |= 0x01; + } + + cInDataByte <<= 1; + } + + /* + * Store the modified byte. + */ + + g_pucOutData[g_pLVDSList[usLVDSIndex]. + usNegativeIndex / 8] = cDataByte; + } else { + + /* + * Copy over the current byte and set + * the negative bit to 0. + */ + + cDataByte = 0x00; + for (cLVDSByteIndex = 7; + cLVDSByteIndex >= 0; + cLVDSByteIndex--) { + cDataByte <<= 1; + if (7 - + (g_pLVDSList[usLVDSIndex]. + usNegativeIndex % 8) == + cLVDSByteIndex) { + + /* + * Set negative bit to 0 + */ + + cDataByte |= 0x00; + } else if (cInDataByte & 0x80) { + cDataByte |= 0x01; + } + + cInDataByte <<= 1; + } + + /* + * Store the modified byte. + */ + + g_pucOutData[g_pLVDSList[usLVDSIndex]. + usNegativeIndex / 8] = cDataByte; + } + + break; + } + } + } + + return 0; +} + +signed char ispVMProcessLVDS(unsigned short a_usLVDSCount) +{ + unsigned short usLVDSIndex = 0; + + /* + * Allocate memory to hold LVDS pairs. + */ + + ispVMMemManager(LVDS, a_usLVDSCount); + g_usLVDSPairCount = a_usLVDSCount; + +#ifdef DEBUG + printf("LVDS %d (", a_usLVDSCount); +#endif /* DEBUG */ + + /* + * Iterate through each given LVDS pair. + */ + + for (usLVDSIndex = 0; usLVDSIndex < g_usLVDSPairCount; usLVDSIndex++) { + + /* + * Assign the positive and negative indices of the LVDS pair. + */ + + /* 09/11/07 NN Type cast mismatch variables */ + g_pLVDSList[usLVDSIndex].usPositiveIndex = + (unsigned short) ispVMDataSize(); + /* 09/11/07 NN Type cast mismatch variables */ + g_pLVDSList[usLVDSIndex].usNegativeIndex = + (unsigned short)ispVMDataSize(); + +#ifdef DEBUG + if (usLVDSIndex < g_usLVDSPairCount - 1) { + printf("%d:%d, ", + g_pLVDSList[usLVDSIndex].usPositiveIndex, + g_pLVDSList[usLVDSIndex].usNegativeIndex); + } else { + printf("%d:%d", + g_pLVDSList[usLVDSIndex].usPositiveIndex, + g_pLVDSList[usLVDSIndex].usNegativeIndex); + } +#endif /* DEBUG */ + + } + +#ifdef DEBUG + printf(");\n", a_usLVDSCount); +#endif /* DEBUG */ + + return 0; +} diff --git a/src/roms/u-boot/drivers/fpga/lattice.c b/src/roms/u-boot/drivers/fpga/lattice.c new file mode 100644 index 0000000..615a485 --- /dev/null +++ b/src/roms/u-boot/drivers/fpga/lattice.c @@ -0,0 +1,380 @@ +/* + * (C) Copyright 2010 + * Stefano Babic, DENX Software Engineering, sbabic@denx.de. + * + * (C) Copyright 2002 + * Rich Ireland, Enterasys Networks, rireland@enterasys.com. + * + * ispVM functions adapted from Lattice's ispmVMEmbedded code: + * Copyright 2009 Lattice Semiconductor Corp. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <malloc.h> +#include <fpga.h> +#include <lattice.h> + +static lattice_board_specific_func *pfns; +static const char *fpga_image; +static unsigned long read_bytes; +static unsigned long bufsize; +static unsigned short expectedCRC; + +/* + * External variables and functions declared in ivm_core.c module. + */ +extern unsigned short g_usCalculatedCRC; +extern unsigned short g_usDataType; +extern unsigned char *g_pucIntelBuffer; +extern unsigned char *g_pucHeapMemory; +extern unsigned short g_iHeapCounter; +extern unsigned short g_iHEAPSize; +extern unsigned short g_usIntelDataIndex; +extern unsigned short g_usIntelBufferSize; +extern char *const g_szSupportedVersions[]; + + +/* + * ispVMDelay + * + * Users must implement a delay to observe a_usTimeDelay, where + * bit 15 of the a_usTimeDelay defines the unit. + * 1 = milliseconds + * 0 = microseconds + * Example: + * a_usTimeDelay = 0x0001 = 1 microsecond delay. + * a_usTimeDelay = 0x8001 = 1 millisecond delay. + * + * This subroutine is called upon to provide a delay from 1 millisecond to a few + * hundreds milliseconds each time. + * It is understood that due to a_usTimeDelay is defined as unsigned short, a 16 + * bits integer, this function is restricted to produce a delay to 64000 + * micro-seconds or 32000 milli-second maximum. The VME file will never pass on + * to this function a delay time > those maximum number. If it needs more than + * those maximum, the VME file will launch the delay function several times to + * realize a larger delay time cummulatively. + * It is perfectly alright to provide a longer delay than required. It is not + * acceptable if the delay is shorter. + */ +void ispVMDelay(unsigned short delay) +{ + if (delay & 0x8000) + delay = (delay & ~0x8000) * 1000; + udelay(delay); +} + +void writePort(unsigned char a_ucPins, unsigned char a_ucValue) +{ + a_ucValue = a_ucValue ? 1 : 0; + + switch (a_ucPins) { + case g_ucPinTDI: + pfns->jtag_set_tdi(a_ucValue); + break; + case g_ucPinTCK: + pfns->jtag_set_tck(a_ucValue); + break; + case g_ucPinTMS: + pfns->jtag_set_tms(a_ucValue); + break; + default: + printf("%s: requested unknown pin\n", __func__); + } +} + +unsigned char readPort(void) +{ + return pfns->jtag_get_tdo(); +} + +void sclock(void) +{ + writePort(g_ucPinTCK, 0x01); + writePort(g_ucPinTCK, 0x00); +} + +void calibration(void) +{ + /* Apply 2 pulses to TCK. */ + writePort(g_ucPinTCK, 0x00); + writePort(g_ucPinTCK, 0x01); + writePort(g_ucPinTCK, 0x00); + writePort(g_ucPinTCK, 0x01); + writePort(g_ucPinTCK, 0x00); + + ispVMDelay(0x8001); + + /* Apply 2 pulses to TCK. */ + writePort(g_ucPinTCK, 0x01); + writePort(g_ucPinTCK, 0x00); + writePort(g_ucPinTCK, 0x01); + writePort(g_ucPinTCK, 0x00); +} + +/* + * GetByte + * + * Returns a byte to the caller. The returned byte depends on the + * g_usDataType register. If the HEAP_IN bit is set, then the byte + * is returned from the HEAP. If the LHEAP_IN bit is set, then + * the byte is returned from the intelligent buffer. Otherwise, + * the byte is returned directly from the VME file. + */ +unsigned char GetByte(void) +{ + unsigned char ucData; + unsigned int block_size = 4 * 1024; + + if (g_usDataType & HEAP_IN) { + + /* + * Get data from repeat buffer. + */ + + if (g_iHeapCounter > g_iHEAPSize) { + + /* + * Data over-run. + */ + + return 0xFF; + } + + ucData = g_pucHeapMemory[g_iHeapCounter++]; + } else if (g_usDataType & LHEAP_IN) { + + /* + * Get data from intel buffer. + */ + + if (g_usIntelDataIndex >= g_usIntelBufferSize) { + return 0xFF; + } + + ucData = g_pucIntelBuffer[g_usIntelDataIndex++]; + } else { + if (read_bytes == bufsize) { + return 0xFF; + } + ucData = *fpga_image++; + read_bytes++; + + if (!(read_bytes % block_size)) { + printf("Downloading FPGA %ld/%ld completed\r", + read_bytes, + bufsize); + } + + if (expectedCRC != 0) { + ispVMCalculateCRC32(ucData); + } + } + + return ucData; +} + +signed char ispVM(void) +{ + char szFileVersion[9] = { 0 }; + signed char cRetCode = 0; + signed char cIndex = 0; + signed char cVersionIndex = 0; + unsigned char ucReadByte = 0; + unsigned short crc; + + g_pucHeapMemory = NULL; + g_iHeapCounter = 0; + g_iHEAPSize = 0; + g_usIntelDataIndex = 0; + g_usIntelBufferSize = 0; + g_usCalculatedCRC = 0; + expectedCRC = 0; + ucReadByte = GetByte(); + switch (ucReadByte) { + case FILE_CRC: + crc = (unsigned char)GetByte(); + crc <<= 8; + crc |= GetByte(); + expectedCRC = crc; + + for (cIndex = 0; cIndex < 8; cIndex++) + szFileVersion[cIndex] = GetByte(); + + break; + default: + szFileVersion[0] = (signed char) ucReadByte; + for (cIndex = 1; cIndex < 8; cIndex++) + szFileVersion[cIndex] = GetByte(); + + break; + } + + /* + * + * Compare the VME file version against the supported version. + * + */ + + for (cVersionIndex = 0; g_szSupportedVersions[cVersionIndex] != 0; + cVersionIndex++) { + for (cIndex = 0; cIndex < 8; cIndex++) { + if (szFileVersion[cIndex] != + g_szSupportedVersions[cVersionIndex][cIndex]) { + cRetCode = VME_VERSION_FAILURE; + break; + } + cRetCode = 0; + } + + if (cRetCode == 0) { + break; + } + } + + if (cRetCode < 0) { + return VME_VERSION_FAILURE; + } + + printf("VME file checked: starting downloading to FPGA\n"); + + ispVMStart(); + + cRetCode = ispVMCode(); + + ispVMEnd(); + ispVMFreeMem(); + puts("\n"); + + if (cRetCode == 0 && expectedCRC != 0 && + (expectedCRC != g_usCalculatedCRC)) { + printf("Expected CRC: 0x%.4X\n", expectedCRC); + printf("Calculated CRC: 0x%.4X\n", g_usCalculatedCRC); + return VME_CRC_FAILURE; + } + return cRetCode; +} + +static int lattice_validate(Lattice_desc *desc, const char *fn) +{ + int ret_val = false; + + if (desc) { + if ((desc->family > min_lattice_type) && + (desc->family < max_lattice_type)) { + if ((desc->iface > min_lattice_iface_type) && + (desc->iface < max_lattice_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; +} + +int lattice_load(Lattice_desc *desc, const void *buf, size_t bsize) +{ + int ret_val = FPGA_FAIL; + + if (!lattice_validate(desc, (char *)__func__)) { + printf("%s: Invalid device descriptor\n", __func__); + } else { + pfns = desc->iface_fns; + + switch (desc->family) { + case Lattice_XP2: + fpga_image = buf; + read_bytes = 0; + bufsize = bsize; + debug("%s: Launching the Lattice ISPVME Loader:" + " addr %p size 0x%lx...\n", + __func__, fpga_image, bufsize); + ret_val = ispVM(); + if (ret_val) + printf("%s: error %d downloading FPGA image\n", + __func__, ret_val); + else + puts("FPGA downloaded successfully\n"); + break; + default: + printf("%s: Unsupported family type, %d\n", + __func__, desc->family); + } + } + + return ret_val; +} + +int lattice_dump(Lattice_desc *desc, const void *buf, size_t bsize) +{ + puts("Dump not supported for Lattice FPGA\n"); + + return FPGA_FAIL; + +} + +int lattice_info(Lattice_desc *desc) +{ + int ret_val = FPGA_FAIL; + + if (lattice_validate(desc, (char *)__func__)) { + printf("Family: \t"); + switch (desc->family) { + case Lattice_XP2: + puts("XP2\n"); + break; + /* Add new family types here */ + default: + printf("Unknown family type, %d\n", desc->family); + } + + puts("Interface type:\t"); + switch (desc->iface) { + case lattice_jtag_mode: + puts("JTAG Mode\n"); + break; + /* Add new interface types here */ + default: + printf("Unsupported interface type, %d\n", desc->iface); + } + + printf("Device Size: \t%d bytes\n", + desc->size); + + if (desc->iface_fns) { + printf("Device Function Table @ 0x%p\n", + desc->iface_fns); + switch (desc->family) { + case Lattice_XP2: + break; + /* Add new family types here */ + default: + break; + } + } else { + puts("No Device Function Table.\n"); + } + + if (desc->desc) + printf("Model: \t%s\n", desc->desc); + + ret_val = FPGA_SUCCESS; + } else { + printf("%s: Invalid device descriptor\n", __func__); + } + + return ret_val; +} diff --git a/src/roms/u-boot/drivers/fpga/spartan2.c b/src/roms/u-boot/drivers/fpga/spartan2.c new file mode 100644 index 0000000..7054056 --- /dev/null +++ b/src/roms/u-boot/drivers/fpga/spartan2.c @@ -0,0 +1,455 @@ +/* + * (C) Copyright 2002 + * Rich Ireland, Enterasys Networks, rireland@enterasys.com. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#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, const void *buf, size_t bsize); +static int spartan2_sp_dump(xilinx_desc *desc, const void *buf, size_t bsize); +/* static int spartan2_sp_info(xilinx_desc *desc ); */ + +static int spartan2_ss_load(xilinx_desc *desc, const void *buf, size_t bsize); +static int spartan2_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize); +/* static int spartan2_ss_info(xilinx_desc *desc ); */ + +/* ------------------------------------------------------------------------- */ +/* Spartan-II Generic Implementation */ +static int spartan2_load(xilinx_desc *desc, const 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; +} + +static int spartan2_dump(xilinx_desc *desc, const 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; +} + +static int spartan2_info(xilinx_desc *desc) +{ + return FPGA_SUCCESS; +} + + +/* ------------------------------------------------------------------------- */ +/* Spartan-II Slave Parallel Generic Implementation */ + +static int spartan2_sp_load(xilinx_desc *desc, const 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) { + + CONFIG_FPGA_DELAY (); + (*fn->clk) (false, true, cookie); /* Deassert the clock pin */ + CONFIG_FPGA_DELAY (); + (*fn->clk) (true, true, cookie); /* Assert the clock pin */ + + if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */ + puts ("** Timeout waiting for DONE to clear.\n"); + (*fn->abort) (cookie); /* abort the burn */ + ret_val = FPGA_FAIL; + break; + } + } + + /* + * Run the post configuration function if there is one. + */ + if (*fn->post) + (*fn->post) (cookie); + +#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK + if (ret_val == FPGA_SUCCESS) + puts ("Done.\n"); + else + puts ("Fail.\n"); +#endif + + } else { + printf ("%s: NULL Interface function table!\n", __FUNCTION__); + } + + return ret_val; +} + +static int spartan2_sp_dump(xilinx_desc *desc, const 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_ss_load(xilinx_desc *desc, const 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)) { + + 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, const 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; +} + +struct xilinx_fpga_op spartan2_op = { + .load = spartan2_load, + .dump = spartan2_dump, + .info = spartan2_info, +}; diff --git a/src/roms/u-boot/drivers/fpga/spartan3.c b/src/roms/u-boot/drivers/fpga/spartan3.c new file mode 100644 index 0000000..5c9412c --- /dev/null +++ b/src/roms/u-boot/drivers/fpga/spartan3.c @@ -0,0 +1,473 @@ +/* + * (C) Copyright 2002 + * Rich Ireland, Enterasys Networks, rireland@enterasys.com. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * 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 + +/* 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, const void *buf, size_t bsize); +static int spartan3_sp_dump(xilinx_desc *desc, const void *buf, size_t bsize); +/* static int spartan3_sp_info(xilinx_desc *desc ); */ + +static int spartan3_ss_load(xilinx_desc *desc, const void *buf, size_t bsize); +static int spartan3_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize); +/* static int spartan3_ss_info(xilinx_desc *desc); */ + +/* ------------------------------------------------------------------------- */ +/* Spartan-II Generic Implementation */ +static int spartan3_load(xilinx_desc *desc, const 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; +} + +static int spartan3_dump(xilinx_desc *desc, const 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; +} + +static int spartan3_info(xilinx_desc *desc) +{ + return FPGA_SUCCESS; +} + + +/* ------------------------------------------------------------------------- */ +/* Spartan-II Slave Parallel Generic Implementation */ + +static int spartan3_sp_load(xilinx_desc *desc, const void *buf, size_t bsize) +{ + int ret_val = FPGA_FAIL; /* assume the worst */ + xilinx_spartan3_slave_parallel_fns *fn = desc->iface_fns; + + PRINTF ("%s: start with interface functions @ 0x%p\n", + __FUNCTION__, fn); + + if (fn) { + size_t bytecount = 0; + unsigned char *data = (unsigned char *) buf; + int cookie = desc->cookie; /* make a local copy */ + unsigned long ts; /* timestamp */ + + PRINTF ("%s: Function Table:\n" + "ptr:\t0x%p\n" + "struct: 0x%p\n" + "pre: 0x%p\n" + "pgm:\t0x%p\n" + "init:\t0x%p\n" + "err:\t0x%p\n" + "clk:\t0x%p\n" + "cs:\t0x%p\n" + "wr:\t0x%p\n" + "read data:\t0x%p\n" + "write data:\t0x%p\n" + "busy:\t0x%p\n" + "abort:\t0x%p\n", + "post:\t0x%p\n\n", + __FUNCTION__, &fn, fn, fn->pre, fn->pgm, fn->init, fn->err, + fn->clk, fn->cs, fn->wr, fn->rdata, fn->wdata, fn->busy, + fn->abort, fn->post); + + /* + * This code is designed to emulate the "Express Style" + * Continuous Data Loading in Slave Parallel Mode for + * the Spartan-II Family. + */ +#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK + printf ("Loading FPGA Device %d...\n", cookie); +#endif + /* + * Run the pre configuration function if there is one. + */ + if (*fn->pre) { + (*fn->pre) (cookie); + } + + /* Establish the initial state */ + (*fn->pgm) (true, true, cookie); /* Assert the program, commit */ + + /* Get ready for the burn */ + CONFIG_FPGA_DELAY (); + (*fn->pgm) (false, true, cookie); /* Deassert the program, commit */ + + ts = get_timer (0); /* get current time */ + /* Now wait for INIT and BUSY to go high */ + do { + CONFIG_FPGA_DELAY (); + if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */ + puts ("** Timeout waiting for INIT to clear.\n"); + (*fn->abort) (cookie); /* abort the burn */ + return FPGA_FAIL; + } + } while ((*fn->init) (cookie) && (*fn->busy) (cookie)); + + (*fn->wr) (true, true, cookie); /* Assert write, commit */ + (*fn->cs) (true, true, cookie); /* Assert chip select, commit */ + (*fn->clk) (true, true, cookie); /* Assert the clock pin */ + + /* Load the data */ + while (bytecount < bsize) { + /* XXX - do we check for an Ctrl-C press in here ??? */ + /* XXX - Check the error bit? */ + + (*fn->wdata) (data[bytecount++], true, cookie); /* write the data */ + CONFIG_FPGA_DELAY (); + (*fn->clk) (false, true, cookie); /* Deassert the clock pin */ + CONFIG_FPGA_DELAY (); + (*fn->clk) (true, true, cookie); /* Assert the clock pin */ + +#ifdef CONFIG_SYS_FPGA_CHECK_BUSY + ts = get_timer (0); /* get current time */ + while ((*fn->busy) (cookie)) { + /* XXX - we should have a check in here somewhere to + * make sure we aren't busy forever... */ + + CONFIG_FPGA_DELAY (); + (*fn->clk) (false, true, cookie); /* Deassert the clock pin */ + CONFIG_FPGA_DELAY (); + (*fn->clk) (true, true, cookie); /* Assert the clock pin */ + + if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */ + puts ("** Timeout waiting for BUSY to clear.\n"); + (*fn->abort) (cookie); /* abort the burn */ + return FPGA_FAIL; + } + } +#endif + +#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK + if (bytecount % (bsize / 40) == 0) + putc ('.'); /* let them know we are alive */ +#endif + } + + CONFIG_FPGA_DELAY (); + (*fn->cs) (false, true, cookie); /* Deassert the chip select */ + (*fn->wr) (false, true, cookie); /* Deassert the write pin */ + +#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK + putc ('\n'); /* terminate the dotted line */ +#endif + + /* now check for done signal */ + ts = get_timer (0); /* get current time */ + ret_val = FPGA_SUCCESS; + while ((*fn->done) (cookie) == FPGA_FAIL) { + /* XXX - we should have a check in here somewhere to + * make sure we aren't busy forever... */ + + CONFIG_FPGA_DELAY (); + (*fn->clk) (false, true, cookie); /* Deassert the clock pin */ + CONFIG_FPGA_DELAY (); + (*fn->clk) (true, true, cookie); /* Assert the clock pin */ + + if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */ + puts ("** Timeout waiting for DONE to clear.\n"); + (*fn->abort) (cookie); /* abort the burn */ + ret_val = FPGA_FAIL; + break; + } + } + + /* + * Run the post configuration function if there is one. + */ + if (*fn->post) + (*fn->post) (cookie); + +#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK + if (ret_val == FPGA_SUCCESS) + puts ("Done.\n"); + else + puts ("Fail.\n"); +#endif + + } else { + printf ("%s: NULL Interface function table!\n", __FUNCTION__); + } + + return ret_val; +} + +static int spartan3_sp_dump(xilinx_desc *desc, const 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_ss_load(xilinx_desc *desc, const void *buf, size_t bsize) +{ + int ret_val = FPGA_FAIL; /* assume the worst */ + xilinx_spartan3_slave_serial_fns *fn = desc->iface_fns; + int i; + unsigned char val; + + PRINTF ("%s: start with interface functions @ 0x%p\n", + __FUNCTION__, fn); + + if (fn) { + size_t bytecount = 0; + unsigned char *data = (unsigned char *) buf; + int cookie = desc->cookie; /* make a local copy */ + unsigned long ts; /* timestamp */ + + PRINTF ("%s: Function Table:\n" + "ptr:\t0x%p\n" + "struct: 0x%p\n" + "pgm:\t0x%p\n" + "init:\t0x%p\n" + "clk:\t0x%p\n" + "wr:\t0x%p\n" + "done:\t0x%p\n\n", + __FUNCTION__, &fn, fn, fn->pgm, fn->init, + fn->clk, fn->wr, fn->done); +#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK + printf ("Loading FPGA Device %d...\n", cookie); +#endif + + /* + * Run the pre configuration function if there is one. + */ + if (*fn->pre) { + (*fn->pre) (cookie); + } + + /* Establish the initial state */ + (*fn->pgm) (true, true, cookie); /* Assert the program, commit */ + + /* Wait for INIT state (init low) */ + ts = get_timer (0); /* get current time */ + do { + CONFIG_FPGA_DELAY (); + if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */ + puts ("** Timeout waiting for INIT to start.\n"); + if (*fn->abort) + (*fn->abort) (cookie); + return FPGA_FAIL; + } + } while (!(*fn->init) (cookie)); + + /* Get ready for the burn */ + CONFIG_FPGA_DELAY (); + (*fn->pgm) (false, true, cookie); /* Deassert the program, commit */ + + ts = get_timer (0); /* get current time */ + /* Now wait for INIT to go high */ + do { + CONFIG_FPGA_DELAY (); + if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */ + puts ("** Timeout waiting for INIT to clear.\n"); + if (*fn->abort) + (*fn->abort) (cookie); + return FPGA_FAIL; + } + } while ((*fn->init) (cookie)); + + /* Load the data */ + if(*fn->bwr) + (*fn->bwr) (data, bsize, true, cookie); + else { + while (bytecount < bsize) { + + /* Xilinx detects an error if INIT goes low (active) + while DONE is low (inactive) */ + if ((*fn->done) (cookie) == 0 && (*fn->init) (cookie)) { + puts ("** CRC error during FPGA load.\n"); + if (*fn->abort) + (*fn->abort) (cookie); + return (FPGA_FAIL); + } + val = data [bytecount ++]; + i = 8; + do { + /* Deassert the clock */ + (*fn->clk) (false, true, cookie); + CONFIG_FPGA_DELAY (); + /* Write data */ + (*fn->wr) ((val & 0x80), true, cookie); + CONFIG_FPGA_DELAY (); + /* Assert the clock */ + (*fn->clk) (true, true, cookie); + CONFIG_FPGA_DELAY (); + val <<= 1; + i --; + } while (i > 0); + +#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK + if (bytecount % (bsize / 40) == 0) + putc ('.'); /* let them know we are alive */ +#endif + } + } + + CONFIG_FPGA_DELAY (); + +#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK + putc ('\n'); /* terminate the dotted line */ +#endif + + /* now check for done signal */ + ts = get_timer (0); /* get current time */ + ret_val = FPGA_SUCCESS; + (*fn->wr) (true, true, cookie); + + while (! (*fn->done) (cookie)) { + /* XXX - we should have a check in here somewhere to + * make sure we aren't busy forever... */ + + CONFIG_FPGA_DELAY (); + (*fn->clk) (false, true, cookie); /* Deassert the clock pin */ + CONFIG_FPGA_DELAY (); + (*fn->clk) (true, true, cookie); /* Assert the clock pin */ + + putc ('*'); + + if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT) { /* check the time */ + puts ("** Timeout waiting for DONE to clear.\n"); + ret_val = FPGA_FAIL; + break; + } + } + putc ('\n'); /* terminate the dotted line */ + + /* + * Run the post configuration function if there is one. + */ + if (*fn->post) + (*fn->post) (cookie); + +#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK + if (ret_val == FPGA_SUCCESS) + puts ("Done.\n"); + else + puts ("Fail.\n"); +#endif + + } else { + printf ("%s: NULL Interface function table!\n", __FUNCTION__); + } + + return ret_val; +} + +static int spartan3_ss_dump(xilinx_desc *desc, const 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; +} + +struct xilinx_fpga_op spartan3_op = { + .load = spartan3_load, + .dump = spartan3_dump, + .info = spartan3_info, +}; diff --git a/src/roms/u-boot/drivers/fpga/stratixII.c b/src/roms/u-boot/drivers/fpga/stratixII.c new file mode 100644 index 0000000..820d016 --- /dev/null +++ b/src/roms/u-boot/drivers/fpga/stratixII.c @@ -0,0 +1,190 @@ +/* + * (C) Copyright 2007 + * Eran Liberty, Extricom , eran.liberty@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#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_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/src/roms/u-boot/drivers/fpga/virtex2.c b/src/roms/u-boot/drivers/fpga/virtex2.c new file mode 100644 index 0000000..e092147 --- /dev/null +++ b/src/roms/u-boot/drivers/fpga/virtex2.c @@ -0,0 +1,425 @@ +/* + * (C) Copyright 2002 + * Rich Ireland, Enterasys Networks, rireland@enterasys.com. + * Keith Outwater, keith_outwater@mvis.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * 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, const void *buf, size_t bsize); +static int virtex2_ssm_dump(xilinx_desc *desc, const void *buf, size_t bsize); + +static int virtex2_ss_load(xilinx_desc *desc, const void *buf, size_t bsize); +static int virtex2_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize); + +static int virtex2_load(xilinx_desc *desc, const 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; +} + +static int virtex2_dump(xilinx_desc *desc, const 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; +} + +static int virtex2_info(xilinx_desc *desc) +{ + return FPGA_SUCCESS; +} + +/* + * 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, const 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, const 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; +} + +static int virtex2_ss_load(xilinx_desc *desc, const 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, const void *buf, size_t bsize) +{ + printf ("%s: Slave Serial Dumping is unsupported\n", __FUNCTION__); + return FPGA_FAIL; +} + +/* vim: set ts=4 tw=78: */ + +struct xilinx_fpga_op virtex2_op = { + .load = virtex2_load, + .dump = virtex2_dump, + .info = virtex2_info, +}; diff --git a/src/roms/u-boot/drivers/fpga/xilinx.c b/src/roms/u-boot/drivers/fpga/xilinx.c new file mode 100644 index 0000000..8837f5c --- /dev/null +++ b/src/roms/u-boot/drivers/fpga/xilinx.c @@ -0,0 +1,249 @@ +/* + * (C) Copyright 2012-2013, Xilinx, Michal Simek + * + * (C) Copyright 2002 + * Rich Ireland, Enterasys Networks, rireland@enterasys.com. + * Keith Outwater, keith_outwater@mvis.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * Xilinx FPGA support + */ + +#include <common.h> +#include <fpga.h> +#include <virtex2.h> +#include <spartan2.h> +#include <spartan3.h> +#include <zynqpl.h> + +/* Local Static Functions */ +static int xilinx_validate(xilinx_desc *desc, char *fn); + +/* ------------------------------------------------------------------------- */ + +int fpga_loadbitstream(int devnum, char *fpgadata, size_t size) +{ + unsigned int length; + unsigned int swapsize; + char buffer[80]; + unsigned char *dataptr; + unsigned int i; + const fpga_desc *desc; + xilinx_desc *xdesc; + + dataptr = (unsigned char *)fpgadata; + /* Find out fpga_description */ + desc = fpga_validate(devnum, dataptr, 0, (char *)__func__); + /* Assign xilinx device description */ + xdesc = desc->devdesc; + + /* skip the first bytes of the bitsteam, their meaning is unknown */ + length = (*dataptr << 8) + *(dataptr + 1); + dataptr += 2; + dataptr += length; + + /* get design name (identifier, length, string) */ + length = (*dataptr << 8) + *(dataptr + 1); + dataptr += 2; + if (*dataptr++ != 0x61) { + debug("%s: Design name id not recognized in bitstream\n", + __func__); + return FPGA_FAIL; + } + + length = (*dataptr << 8) + *(dataptr + 1); + dataptr += 2; + for (i = 0; i < length; i++) + buffer[i] = *dataptr++; + + printf(" design filename = \"%s\"\n", buffer); + + /* get part number (identifier, length, string) */ + if (*dataptr++ != 0x62) { + printf("%s: Part number id not recognized in bitstream\n", + __func__); + return FPGA_FAIL; + } + + length = (*dataptr << 8) + *(dataptr + 1); + dataptr += 2; + for (i = 0; i < length; i++) + buffer[i] = *dataptr++; + + if (xdesc->name) { + i = strncmp(buffer, xdesc->name, strlen(xdesc->name)); + if (i) { + printf("%s: Wrong bitstream ID for this device\n", + __func__); + printf("%s: Bitstream ID %s, current device ID %d/%s\n", + __func__, buffer, devnum, xdesc->name); + return FPGA_FAIL; + } + } else { + printf("%s: Please fill correct device ID to xilinx_desc\n", + __func__); + } + printf(" part number = \"%s\"\n", buffer); + + /* get date (identifier, length, string) */ + if (*dataptr++ != 0x63) { + printf("%s: Date identifier not recognized in bitstream\n", + __func__); + return FPGA_FAIL; + } + + length = (*dataptr << 8) + *(dataptr+1); + dataptr += 2; + for (i = 0; i < length; i++) + buffer[i] = *dataptr++; + printf(" date = \"%s\"\n", buffer); + + /* get time (identifier, length, string) */ + if (*dataptr++ != 0x64) { + printf("%s: Time identifier not recognized in bitstream\n", + __func__); + return FPGA_FAIL; + } + + length = (*dataptr << 8) + *(dataptr+1); + dataptr += 2; + for (i = 0; i < length; i++) + buffer[i] = *dataptr++; + printf(" time = \"%s\"\n", buffer); + + /* get fpga data length (identifier, length) */ + if (*dataptr++ != 0x65) { + printf("%s: Data length id not recognized in bitstream\n", + __func__); + return FPGA_FAIL; + } + swapsize = ((unsigned int) *dataptr << 24) + + ((unsigned int) *(dataptr + 1) << 16) + + ((unsigned int) *(dataptr + 2) << 8) + + ((unsigned int) *(dataptr + 3)); + dataptr += 4; + printf(" bytes in bitstream = %d\n", swapsize); + + return fpga_load(devnum, dataptr, swapsize); +} + +int xilinx_load(xilinx_desc *desc, const void *buf, size_t bsize) +{ + if (!xilinx_validate (desc, (char *)__FUNCTION__)) { + printf ("%s: Invalid device descriptor\n", __FUNCTION__); + return FPGA_FAIL; + } + + return desc->operations->load(desc, buf, bsize); +} + +int xilinx_dump(xilinx_desc *desc, const void *buf, size_t bsize) +{ + if (!xilinx_validate (desc, (char *)__FUNCTION__)) { + printf ("%s: Invalid device descriptor\n", __FUNCTION__); + return FPGA_FAIL; + } + + return desc->operations->dump(desc, buf, bsize); +} + +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; + case xilinx_zynq: + printf("Zynq PL\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; + case devcfg: + printf("Device configuration interface (Zynq)\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->name) + printf("Device name: \t%s\n", desc->name); + + if (desc->iface_fns) { + printf ("Device Function Table @ 0x%p\n", desc->iface_fns); + desc->operations->info(desc); + } else + printf ("No Device Function Table.\n"); + + ret_val = FPGA_SUCCESS; + } else { + printf ("%s: Invalid device descriptor\n", __FUNCTION__); + } + + 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; +} diff --git a/src/roms/u-boot/drivers/fpga/zynqpl.c b/src/roms/u-boot/drivers/fpga/zynqpl.c new file mode 100644 index 0000000..c066f21 --- /dev/null +++ b/src/roms/u-boot/drivers/fpga/zynqpl.c @@ -0,0 +1,416 @@ +/* + * (C) Copyright 2012-2013, Xilinx, Michal Simek + * + * (C) Copyright 2012 + * Joe Hershberger <joe.hershberger@ni.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <zynqpl.h> +#include <linux/sizes.h> +#include <asm/arch/hardware.h> +#include <asm/arch/sys_proto.h> + +#define DEVCFG_CTRL_PCFG_PROG_B 0x40000000 +#define DEVCFG_ISR_FATAL_ERROR_MASK 0x00740040 +#define DEVCFG_ISR_ERROR_FLAGS_MASK 0x00340840 +#define DEVCFG_ISR_RX_FIFO_OV 0x00040000 +#define DEVCFG_ISR_DMA_DONE 0x00002000 +#define DEVCFG_ISR_PCFG_DONE 0x00000004 +#define DEVCFG_STATUS_DMA_CMD_Q_F 0x80000000 +#define DEVCFG_STATUS_DMA_CMD_Q_E 0x40000000 +#define DEVCFG_STATUS_DMA_DONE_CNT_MASK 0x30000000 +#define DEVCFG_STATUS_PCFG_INIT 0x00000010 +#define DEVCFG_MCTRL_PCAP_LPBK 0x00000010 +#define DEVCFG_MCTRL_RFIFO_FLUSH 0x00000002 +#define DEVCFG_MCTRL_WFIFO_FLUSH 0x00000001 + +#ifndef CONFIG_SYS_FPGA_WAIT +#define CONFIG_SYS_FPGA_WAIT CONFIG_SYS_HZ/100 /* 10 ms */ +#endif + +#ifndef CONFIG_SYS_FPGA_PROG_TIME +#define CONFIG_SYS_FPGA_PROG_TIME (CONFIG_SYS_HZ * 4) /* 4 s */ +#endif + +static int zynq_info(xilinx_desc *desc) +{ + return FPGA_SUCCESS; +} + +#define DUMMY_WORD 0xffffffff + +/* Xilinx binary format header */ +static const u32 bin_format[] = { + DUMMY_WORD, /* Dummy words */ + DUMMY_WORD, + DUMMY_WORD, + DUMMY_WORD, + DUMMY_WORD, + DUMMY_WORD, + DUMMY_WORD, + DUMMY_WORD, + 0x000000bb, /* Sync word */ + 0x11220044, /* Sync word */ + DUMMY_WORD, + DUMMY_WORD, + 0xaa995566, /* Sync word */ +}; + +#define SWAP_NO 1 +#define SWAP_DONE 2 + +/* + * Load the whole word from unaligned buffer + * Keep in your mind that it is byte loading on little-endian system + */ +static u32 load_word(const void *buf, u32 swap) +{ + u32 word = 0; + u8 *bitc = (u8 *)buf; + int p; + + if (swap == SWAP_NO) { + for (p = 0; p < 4; p++) { + word <<= 8; + word |= bitc[p]; + } + } else { + for (p = 3; p >= 0; p--) { + word <<= 8; + word |= bitc[p]; + } + } + + return word; +} + +static u32 check_header(const void *buf) +{ + u32 i, pattern; + int swap = SWAP_NO; + u32 *test = (u32 *)buf; + + debug("%s: Let's check bitstream header\n", __func__); + + /* Checking that passing bin is not a bitstream */ + for (i = 0; i < ARRAY_SIZE(bin_format); i++) { + pattern = load_word(&test[i], swap); + + /* + * Bitstreams in binary format are swapped + * compare to regular bistream. + * Do not swap dummy word but if swap is done assume + * that parsing buffer is binary format + */ + if ((__swab32(pattern) != DUMMY_WORD) && + (__swab32(pattern) == bin_format[i])) { + pattern = __swab32(pattern); + swap = SWAP_DONE; + debug("%s: data swapped - let's swap\n", __func__); + } + + debug("%s: %d/%x: pattern %x/%x bin_format\n", __func__, i, + (u32)&test[i], pattern, bin_format[i]); + if (pattern != bin_format[i]) { + debug("%s: Bitstream is not recognized\n", __func__); + return 0; + } + } + debug("%s: Found bitstream header at %x %s swapinng\n", __func__, + (u32)buf, swap == SWAP_NO ? "without" : "with"); + + return swap; +} + +static void *check_data(u8 *buf, size_t bsize, u32 *swap) +{ + u32 word, p = 0; /* possition */ + + /* Because buf doesn't need to be aligned let's read it by chars */ + for (p = 0; p < bsize; p++) { + word = load_word(&buf[p], SWAP_NO); + debug("%s: word %x %x/%x\n", __func__, word, p, (u32)&buf[p]); + + /* Find the first bitstream dummy word */ + if (word == DUMMY_WORD) { + debug("%s: Found dummy word at position %x/%x\n", + __func__, p, (u32)&buf[p]); + *swap = check_header(&buf[p]); + if (*swap) { + /* FIXME add full bitstream checking here */ + return &buf[p]; + } + } + /* Loop can be huge - support CTRL + C */ + if (ctrlc()) + return NULL; + } + return NULL; +} + +static int zynq_dma_transfer(u32 srcbuf, u32 srclen, u32 dstbuf, u32 dstlen) +{ + unsigned long ts; + u32 isr_status; + + /* Set up the transfer */ + writel((u32)srcbuf, &devcfg_base->dma_src_addr); + writel(dstbuf, &devcfg_base->dma_dst_addr); + writel(srclen, &devcfg_base->dma_src_len); + writel(dstlen, &devcfg_base->dma_dst_len); + + isr_status = readl(&devcfg_base->int_sts); + + /* Polling the PCAP_INIT status for Set */ + ts = get_timer(0); + while (!(isr_status & DEVCFG_ISR_DMA_DONE)) { + if (isr_status & DEVCFG_ISR_ERROR_FLAGS_MASK) { + debug("%s: Error: isr = 0x%08X\n", __func__, + isr_status); + debug("%s: Write count = 0x%08X\n", __func__, + readl(&devcfg_base->write_count)); + debug("%s: Read count = 0x%08X\n", __func__, + readl(&devcfg_base->read_count)); + + return FPGA_FAIL; + } + if (get_timer(ts) > CONFIG_SYS_FPGA_PROG_TIME) { + printf("%s: Timeout wait for DMA to complete\n", + __func__); + return FPGA_FAIL; + } + isr_status = readl(&devcfg_base->int_sts); + } + + debug("%s: DMA transfer is done\n", __func__); + + /* Clear out the DMA status */ + writel(DEVCFG_ISR_DMA_DONE, &devcfg_base->int_sts); + + return FPGA_SUCCESS; +} + +static int zynq_dma_xfer_init(u32 partialbit) +{ + u32 status, control, isr_status; + unsigned long ts; + + /* Clear loopback bit */ + clrbits_le32(&devcfg_base->mctrl, DEVCFG_MCTRL_PCAP_LPBK); + + if (!partialbit) { + zynq_slcr_devcfg_disable(); + + /* Setting PCFG_PROG_B signal to high */ + control = readl(&devcfg_base->ctrl); + writel(control | DEVCFG_CTRL_PCFG_PROG_B, &devcfg_base->ctrl); + /* Setting PCFG_PROG_B signal to low */ + writel(control & ~DEVCFG_CTRL_PCFG_PROG_B, &devcfg_base->ctrl); + + /* Polling the PCAP_INIT status for Reset */ + ts = get_timer(0); + while (readl(&devcfg_base->status) & DEVCFG_STATUS_PCFG_INIT) { + if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT) { + printf("%s: Timeout wait for INIT to clear\n", + __func__); + return FPGA_FAIL; + } + } + + /* Setting PCFG_PROG_B signal to high */ + writel(control | DEVCFG_CTRL_PCFG_PROG_B, &devcfg_base->ctrl); + + /* Polling the PCAP_INIT status for Set */ + ts = get_timer(0); + while (!(readl(&devcfg_base->status) & + DEVCFG_STATUS_PCFG_INIT)) { + if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT) { + printf("%s: Timeout wait for INIT to set\n", + __func__); + return FPGA_FAIL; + } + } + } + + isr_status = readl(&devcfg_base->int_sts); + + /* Clear it all, so if Boot ROM comes back, it can proceed */ + writel(0xFFFFFFFF, &devcfg_base->int_sts); + + if (isr_status & DEVCFG_ISR_FATAL_ERROR_MASK) { + debug("%s: Fatal errors in PCAP 0x%X\n", __func__, isr_status); + + /* If RX FIFO overflow, need to flush RX FIFO first */ + if (isr_status & DEVCFG_ISR_RX_FIFO_OV) { + writel(DEVCFG_MCTRL_RFIFO_FLUSH, &devcfg_base->mctrl); + writel(0xFFFFFFFF, &devcfg_base->int_sts); + } + return FPGA_FAIL; + } + + status = readl(&devcfg_base->status); + + debug("%s: Status = 0x%08X\n", __func__, status); + + if (status & DEVCFG_STATUS_DMA_CMD_Q_F) { + debug("%s: Error: device busy\n", __func__); + return FPGA_FAIL; + } + + debug("%s: Device ready\n", __func__); + + if (!(status & DEVCFG_STATUS_DMA_CMD_Q_E)) { + if (!(readl(&devcfg_base->int_sts) & DEVCFG_ISR_DMA_DONE)) { + /* Error state, transfer cannot occur */ + debug("%s: ISR indicates error\n", __func__); + return FPGA_FAIL; + } else { + /* Clear out the status */ + writel(DEVCFG_ISR_DMA_DONE, &devcfg_base->int_sts); + } + } + + if (status & DEVCFG_STATUS_DMA_DONE_CNT_MASK) { + /* Clear the count of completed DMA transfers */ + writel(DEVCFG_STATUS_DMA_DONE_CNT_MASK, &devcfg_base->status); + } + + return FPGA_SUCCESS; +} + +static u32 *zynq_align_dma_buffer(u32 *buf, u32 len, u32 swap) +{ + u32 *new_buf; + u32 i; + + if ((u32)buf != ALIGN((u32)buf, ARCH_DMA_MINALIGN)) { + new_buf = (u32 *)ALIGN((u32)buf, ARCH_DMA_MINALIGN); + + /* + * This might be dangerous but permits to flash if + * ARCH_DMA_MINALIGN is greater than header size + */ + if (new_buf > buf) { + debug("%s: Aligned buffer is after buffer start\n", + __func__); + new_buf -= ARCH_DMA_MINALIGN; + } + printf("%s: Align buffer at %x to %x(swap %d)\n", __func__, + (u32)buf, (u32)new_buf, swap); + + for (i = 0; i < (len/4); i++) + new_buf[i] = load_word(&buf[i], swap); + + buf = new_buf; + } else if (swap != SWAP_DONE) { + /* For bitstream which are aligned */ + u32 *new_buf = (u32 *)buf; + + printf("%s: Bitstream is not swapped(%d) - swap it\n", __func__, + swap); + + for (i = 0; i < (len/4); i++) + new_buf[i] = load_word(&buf[i], swap); + } + + return buf; +} + +static int zynq_validate_bitstream(xilinx_desc *desc, const void *buf, + size_t bsize, u32 blocksize, u32 *swap, + u32 *partialbit) +{ + u32 *buf_start; + u32 diff; + + /* Detect if we are going working with partial or full bitstream */ + if (bsize != desc->size) { + printf("%s: Working with partial bitstream\n", __func__); + *partialbit = 1; + } + buf_start = check_data((u8 *)buf, blocksize, swap); + + if (!buf_start) + return FPGA_FAIL; + + /* Check if data is postpone from start */ + diff = (u32)buf_start - (u32)buf; + if (diff) { + printf("%s: Bitstream is not validated yet (diff %x)\n", + __func__, diff); + return FPGA_FAIL; + } + + if ((u32)buf < SZ_1M) { + printf("%s: Bitstream has to be placed up to 1MB (%x)\n", + __func__, (u32)buf); + return FPGA_FAIL; + } + + if (zynq_dma_xfer_init(*partialbit)) + return FPGA_FAIL; + + return 0; +} + + +static int zynq_load(xilinx_desc *desc, const void *buf, size_t bsize) +{ + unsigned long ts; /* Timestamp */ + u32 partialbit = 0; + u32 isr_status, swap; + + /* + * send bsize inplace of blocksize as it was not a bitstream + * in chunks + */ + if (zynq_validate_bitstream(desc, buf, bsize, bsize, &swap, + &partialbit)) + return FPGA_FAIL; + + buf = zynq_align_dma_buffer((u32 *)buf, bsize, swap); + + debug("%s: Source = 0x%08X\n", __func__, (u32)buf); + debug("%s: Size = %zu\n", __func__, bsize); + + /* flush(clean & invalidate) d-cache range buf */ + flush_dcache_range((u32)buf, (u32)buf + + roundup(bsize, ARCH_DMA_MINALIGN)); + + if (zynq_dma_transfer((u32)buf | 1, bsize >> 2, 0xffffffff, 0)) + return FPGA_FAIL; + + isr_status = readl(&devcfg_base->int_sts); + /* Check FPGA configuration completion */ + ts = get_timer(0); + while (!(isr_status & DEVCFG_ISR_PCFG_DONE)) { + if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT) { + printf("%s: Timeout wait for FPGA to config\n", + __func__); + return FPGA_FAIL; + } + isr_status = readl(&devcfg_base->int_sts); + } + + debug("%s: FPGA config done\n", __func__); + + if (!partialbit) + zynq_slcr_devcfg_enable(); + + return FPGA_SUCCESS; +} + +static int zynq_dump(xilinx_desc *desc, const void *buf, size_t bsize) +{ + return FPGA_FAIL; +} + +struct xilinx_fpga_op zynq_op = { + .load = zynq_load, + .dump = zynq_dump, + .info = zynq_info, +}; |