[U-Boot-Users] [PATCH 1/8] Make autocomplete work with HUSH parser too.

Auto complete did not work when the HUSH parser was selected. Fix this obvious problem.
--- Signed-off-by: Pantelis Antoniou pantelis@embeddedalley.com ---
README | 4 ---- common/main.c | 25 +++++++++++++++++++++++-- 2 files changed, 23 insertions(+), 6 deletions(-)
diff --git a/README b/README index ecfd1f8..e28f935 100644 --- a/README +++ b/README @@ -1511,10 +1511,6 @@ The following options need to be configured:
Enable auto completion of commands using TAB.
- Note that this feature has NOT been implemented yet - for the "hush" shell. - - CFG_HUSH_PARSER
Define this variable to enable the "hush" shell (from diff --git a/common/main.c b/common/main.c index cc4b50f..a8ae07c 100644 --- a/common/main.c +++ b/common/main.c @@ -718,10 +718,11 @@ static void cread_add_str(char *str, int strsize, int insert, unsigned long *num } }
-static int cread_line(char *buf, unsigned int *len) +static int cread_line(const char *const prompt, char *buf, unsigned int *len) { unsigned long num = 0; unsigned long eol_num = 0; + int num2, col; unsigned long rlen; unsigned long wlen; char ichar; @@ -840,6 +841,7 @@ static int cread_line(char *buf, unsigned int *len) insert = !insert; break; case CTL_CH('x'): + case CTL_CH('u'): /* like that too */ BEGINNING_OF_LINE(); ERASE_TO_EOL(); break; @@ -889,6 +891,25 @@ static int cread_line(char *buf, unsigned int *len) REFRESH_TO_EOL(); continue; } +#ifdef CONFIG_AUTO_COMPLETE + case '\t': + + /* do not autocomplete when in the middle */ + if (num < eol_num) { + getcmd_cbeep(); + break; + } + + buf[num] = '\0'; + col = strlen(prompt) + eol_num; + num2 = num; + if (cmd_auto_complete(prompt, buf, &num2, &col)) { + col = num2 - num; + num += col; + eol_num += col; + } + break; +#endif default: cread_add_char(ichar, insert, &num, &eol_num, buf, *len); break; @@ -931,7 +952,7 @@ int readline (const char *const prompt)
puts (prompt);
- rc = cread_line(p, &len); + rc = cread_line(prompt, p, &len); return rc < 0 ? rc : len; #else char *p = console_buffer;

Add support for Lattice FPGA parts programmed using JTAG.
--- Signed-off-by: Pantelis Antoniou pantelis@embeddedalley.com ---
common/Makefile | 4 common/fpga.c | 30 +++ common/lattice.c | 218 ++++++++++++++++++++++++ common/lattice_ec.c | 461 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/fpga.h | 3 include/lattice.h | 85 +++++++++ include/lattice_ec.h | 85 +++++++++ 7 files changed, 884 insertions(+), 2 deletions(-)
diff --git a/common/Makefile b/common/Makefile index 0106088..79d11a5 100644 --- a/common/Makefile +++ b/common/Makefile @@ -47,7 +47,9 @@ COBJS = main.o ACEX1K.o altera.o bedbug.o circbuf.o \ env_nvram.o env_nowhere.o \ exports.o \ flash.o fpga.o ft_build.o \ - hush.o kgdb.o lcd.o lists.o lynxkdi.o \ + hush.o kgdb.o \ + lattice.o lattice_ec.o lattice_ivm_core.o lattice_ivm_supp.o \ + lcd.o lists.o lynxkdi.o \ memsize.o miiphybb.o miiphyutil.o \ s_record.o serial.o soft_i2c.o soft_spi.o spartan2.o spartan3.o \ usb.o usb_kbd.o usb_storage.o \ diff --git a/common/fpga.c b/common/fpga.c index 2eff239..8374814 100644 --- a/common/fpga.c +++ b/common/fpga.c @@ -28,6 +28,7 @@ #include <common.h> /* core U-Boot definitions */ #include <xilinx.h> /* xilinx specific definitions */ #include <altera.h> /* altera specific definitions */ +#include <lattice.h> /* lattice specific definitions */
#if defined(CONFIG_FPGA)
@@ -150,6 +151,14 @@ static int fpga_dev_info( int devnum ) fpga_no_sup( (char *)__FUNCTION__, "Altera devices" ); #endif break; + case fpga_lattice: +#if CONFIG_FPGA & CFG_FPGA_LATTICE + printf( "Lattice Device\nDescriptor @ 0x%p\n", desc ); + ret_val = lattice_info( desc->devdesc ); +#else + fpga_no_sup( __FUNCTION__, "Lattice devices" ); +#endif + break; default: printf( "%s: Invalid or unsupported device type %d\n", __FUNCTION__, desc->devtype ); @@ -188,6 +197,13 @@ int fpga_reloc( fpga_type devtype, void *desc, ulong reloc_off ) fpga_no_sup( (char *)__FUNCTION__, "Altera devices" ); #endif break; + case fpga_lattice: +#if CONFIG_FPGA & CFG_FPGA_LATTICE + ret_val = lattice_reloc( desc, reloc_off ); +#else + fpga_no_sup( __FUNCTION__, "Lattice devices" ); +#endif + break; default: printf( "%s: Invalid or unsupported device type %d\n", __FUNCTION__, devtype ); @@ -281,6 +297,13 @@ int fpga_load( int devnum, void *buf, size_t bsize ) fpga_no_sup( (char *)__FUNCTION__, "Altera devices" ); #endif break; + case fpga_lattice: +#if CONFIG_FPGA & CFG_FPGA_LATTICE + ret_val = lattice_load( desc->devdesc, buf, bsize ); +#else + fpga_no_sup( __FUNCTION__, "Lattice devices" ); +#endif + break; default: printf( "%s: Invalid or unsupported device type %d\n", __FUNCTION__, desc->devtype ); @@ -314,6 +337,13 @@ int fpga_dump( int devnum, void *buf, size_t bsize ) fpga_no_sup( (char *)__FUNCTION__, "Altera devices" ); #endif break; + case fpga_lattice: +#if CONFIG_FPGA & CFG_FPGA_LATTICE + ret_val = lattice_dump( desc->devdesc, buf, bsize ); +#else + fpga_no_sup( __FUNCTION__, "Lattice devices" ); +#endif + break; default: printf( "%s: Invalid or unsupported device type %d\n", __FUNCTION__, desc->devtype ); diff --git a/common/lattice.c b/common/lattice.c new file mode 100644 index 0000000..26e1aa2 --- /dev/null +++ b/common/lattice.c @@ -0,0 +1,218 @@ +/* + * (C) Copyright 2006 - Embedded Alley Solutions Inc. + * by Pantelis Antoniou, pantelis@embeddedalley.com + * + * Based on common/lattice.c (C) Copyright 2002 + * by Rich Ireland, Enterasys Networks, rireland@enterasys.com. + * by Keith Outwater, keith_outwater@mvis.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/* + * Lattice FPGA support + */ + +#include <common.h> +#include <lattice_ec.h> + +#include <lattice_vmopcode.h> + +#if (CONFIG_FPGA & CFG_FPGA_LATTICE) + +#if 0 +#define FPGA_DEBUG +#endif + +/* Define FPGA_DEBUG to get debug printf's */ +#ifdef FPGA_DEBUG +#define PRINTF(fmt,args...) printf(fmt ,##args) +#else +#define PRINTF(fmt,args...) +#endif + +/* Local Static Functions */ +static int lattice_validate(Lattice_desc *desc, char *fn); + +int lattice_load(Lattice_desc *desc, void *buf, size_t bsize) +{ + int ret_val = FPGA_FAIL; /* assume a failure */ + + if (!lattice_validate(desc, (char *)__FUNCTION__)) { + printf ("%s: Invalid device descriptor\n", __FUNCTION__); + return FPGA_FAIL; + } + + switch (desc->family) { + case Lattice_EC: +#if (CONFIG_FPGA & CFG_EC) + PRINTF("%s: Launching the EC Loader...\n", + __FUNCTION__); + ret_val = EC_load(desc, buf, bsize); +#else + printf("%s: No support for EC devices.\n", + __FUNCTION__); +#endif + break; + default: + printf("%s: Unsupported family type, %d\n", + __FUNCTION__, desc->family); + } + + return ret_val; +} + +int lattice_dump(Lattice_desc *desc, void *buf, size_t bsize) +{ + int ret_val = FPGA_FAIL; /* assume a failure */ + + if (!lattice_validate(desc, (char *)__FUNCTION__)) { + printf("%s: Invalid device descriptor\n", __FUNCTION__); + return FPGA_FAIL; + } + + switch (desc->family) { + case Lattice_EC: +#if (CONFIG_FPGA & CFG_EC) + PRINTF("%s: Launching the EC Reader...\n", + __FUNCTION__); + ret_val = EC_dump(desc, buf, bsize); +#else + printf("%s: No support for EC devices.\n", + __FUNCTION__); +#endif + break; + + default: + printf("%s: Unsupported family type, %d\n", + __FUNCTION__, desc->family); + } + + return ret_val; +} + +int lattice_info(Lattice_desc *desc) +{ + if (!lattice_validate(desc, (char *)__FUNCTION__)) { + printf("%s: Invalid device descriptor\n", __FUNCTION__); + return FPGA_FAIL; + } + + if (!desc->iface_fns) { + printf("No Device Function Table.\n"); + return FPGA_FAIL; + } + + printf ("Family: \t"); + switch (desc->family) { + case Lattice_EC: + printf ("EC\n"); + break; + /* Add new family types here */ + default: + printf("Unknown family type, %d\n", desc->family); + } + + printf ("Interface type:\t"); + switch (desc->iface) { + case lattice_jtag_mode: + printf("JTAG Mode\n"); + break; + 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); + + printf ("Device Function Table @ 0x%p\n", desc->iface_fns); + switch (desc->family) { + case Lattice_EC: +#if (CONFIG_FPGA & CFG_EC) + EC_info(desc); +#else + /* just in case */ + printf("%s: No support for EC devices.\n", + __FUNCTION__); +#endif + break; + /* Add new family types here */ + default: + /* we don't need a message here - we give one up above */ + ; + } + + return FPGA_SUCCESS; +} + +int lattice_reloc(Lattice_desc *desc, ulong reloc_offset) +{ + int ret_val = FPGA_FAIL; /* assume a failure */ + + if (!lattice_validate (desc, (char *)__FUNCTION__)) { + printf ("%s: Invalid device descriptor\n", __FUNCTION__); + return FPGA_FAIL; + } + + switch (desc->family) { + case Lattice_EC: +#if (CONFIG_FPGA & CFG_EC) + ret_val = EC_reloc(desc, reloc_offset); +#else + printf("%s: No support for EC devices.\n", + __FUNCTION__); +#endif + break; + /* Add new family types here */ + default: + printf("%s: Unsupported family type, %d\n", + __FUNCTION__, desc->family); + } + + return ret_val; +} + +static int lattice_validate(Lattice_desc *desc, char *fn) +{ + if (!desc) { + printf ("%s: NULL descriptor!\n", fn); + return 0; + } + + if (desc->family <= min_lattice_type && + desc->family >= max_lattice_type) { + printf ("%s: Invalid family type, %d\n", fn, desc->family); + return 0; + } + if (desc->iface <= min_lattice_iface_type && + desc->iface >= max_lattice_iface_type) { + printf ("%s: Invalid Interface type, %d\n", fn, desc->iface); + return 0; + } + if (!desc->size) { + printf ("%s: NULL part size\n", fn); + return 0; + } + + return 1; +} + +#endif diff --git a/common/lattice_ec.c b/common/lattice_ec.c new file mode 100644 index 0000000..1b8b485 --- /dev/null +++ b/common/lattice_ec.c @@ -0,0 +1,461 @@ +/* + * (C) Copyright 2006 - Embedded Alley Solutions Inc. + * by Pantelis Antoniou, pantelis@embeddedalley.com + * + * Based on common/spartan2.c + * (C) Copyright 2002 + * by Rich Ireland, Enterasys Networks, rireland@enterasys.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include <common.h> /* core U-Boot definitions */ +#include <asm/types.h> + +#include <lattice_ec.h> /* Lattice EC device family */ + +#include <lattice_vmopcode.h> +#include <lattice_ivm_core.h> + +#if (CONFIG_FPGA & (CFG_LATTICE | CFG_EC)) + +#if 0 +#define FPGA_DEBUG +#endif + +/* Define FPGA_DEBUG to get debug printf's */ +#ifdef FPGA_DEBUG +#define PRINTF(fmt,args...) printf (fmt ,##args) +#else +#define PRINTF(fmt,args...) +#endif + +/* 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 CFG_FPGA_WAIT +#define CFG_FPGA_WAIT CFG_HZ/100 /* 10 ms */ +#endif + +static int EC_jtag_load( Lattice_desc *desc, void *buf, size_t bsize); +static int EC_jtag_dump( Lattice_desc *desc, void *buf, size_t bsize); +/* static int EC_jtag_info( Lattice_desc *desc ); */ +static int EC_jtag_reloc( Lattice_desc *desc, ulong reloc_offset); + +/* Lattice EC Generic Implementation */ +int EC_load (Lattice_desc * desc, void *buf, size_t bsize) +{ + int ret_val = FPGA_FAIL; + + switch (desc->iface) { + case lattice_jtag_mode: + PRINTF ("%s: Launching JTAG Load\n", __FUNCTION__); + ret_val = EC_jtag_load (desc, buf, bsize); + break; + + default: + printf ("%s: Unsupported interface type, %d\n", + __FUNCTION__, desc->iface); + } + + return ret_val; +} + +int EC_dump (Lattice_desc * desc, void *buf, size_t bsize) +{ + int ret_val = FPGA_FAIL; + + switch (desc->iface) { + case lattice_jtag_mode: + PRINTF ("%s: Launching JTAG Dump\n", __FUNCTION__); + ret_val = EC_jtag_dump (desc, buf, bsize); + break; + + default: + printf ("%s: Unsupported interface type, %d\n", + __FUNCTION__, desc->iface); + } + + return ret_val; +} + +int EC_info( Lattice_desc *desc ) +{ + return FPGA_SUCCESS; +} + + +int EC_reloc (Lattice_desc * desc, ulong reloc_offset) +{ + int ret_val = FPGA_FAIL; /* assume a failure */ + + if (desc->family != Lattice_EC) { + printf ("%s: Unsupported family type, %d\n", + __FUNCTION__, desc->family); + return FPGA_FAIL; + } else + switch (desc->iface) { + case lattice_jtag_mode: + ret_val = EC_jtag_reloc (desc, reloc_offset); + break; + + default: + printf ("%s: Unsupported interface type, %d\n", + __FUNCTION__, desc->iface); + } + + return ret_val; +} + +/*********************************************************************/ + +static void rewind_buffer(void *cookie); + +static int lattice_ec_verbose = 0; + +static int EC_jtag_load (Lattice_desc * desc, void *buf, size_t bsize) +{ + static struct Lattice_EC_private priv; + Lattice_EC_JTAG_fns *fn = desc->iface_fns; + char version[9]; + int j, ret; + u16 ecrc = 0; + u16 ccrc = 0; + int val; + + /* play it safe */ + version[0] = '\0'; + + PRINTF ("%s: start with interface functions @ 0x%p\n", + __FUNCTION__, fn); + + if (!fn) { + printf ("%s: NULL Interface function table!\n", __FUNCTION__); + return FPGA_FAIL; + } + + PRINTF ("%s: Function Table:\n" + "ptr:\t0x%p\n" + "struct: 0x%p\n" + "pre:\t0x%p\n" + "post:\t0x%p\n" + "jtag_write_port:\t0x%p\n" + "jtag_read_port:\t0x%p\n\n", + __FUNCTION__, &fn, fn, fn->pre, fn->post, + fn->jtag_write_port, fn->jtag_read_port); + + priv.fpga_prog_base = buf; + priv.fpga_prog_end = buf + bsize; + priv.fpga_prog_next = buf; + priv.fpga_steps_reset = (bsize * 2 / 50); /* one step */ + priv.fpga_steps = 0; + priv.fpga_spin = 0; + desc->priv = &priv; + + ispvm_reset(&priv.d, desc); /* Reset state of programming code */ + rewind_buffer(desc); + +#ifdef CFG_FPGA_PROG_FEEDBACK + printf("FPGA: "); /* Two spaces (at least)! */ +#endif + + lattice_ec_verbose = 0; + + ccrc = 0; + val = lattice_ec_next_byte(desc); + if (val == -1) { + PRINTF("Invalid file\n"); + return VME_INVALID_FILE; + } + switch(val) { + case FILE_CRC: + val = lattice_ec_next_byte(desc); + if (val == -1) { + PRINTF("Invalid file\n"); + return VME_INVALID_FILE; + } + ecrc = (val & 0xff) << 8; + val = lattice_ec_next_byte(desc); + if (val == -1) { + PRINTF("Invalid file\n"); + return VME_INVALID_FILE; + } + ecrc |= val & 0xff; + + while ((val = lattice_ec_next_byte(desc)) != -1) + ccrc = ispvm_crc(&priv.d, (u8)val, ccrc); + + if (ecrc && ecrc != ccrc) { + PRINTF("Expected CRC: 0x%.4X\n", ecrc); + PRINTF("Calculated CRC: 0x%.4X\n", ccrc); + return VME_CRC_FAILURE; + } + + rewind_buffer(desc); +#ifdef FPGA_DEBUG + lattice_ec_verbose = 1; +#endif + (void)lattice_ec_next_byte(desc); + (void)lattice_ec_next_byte(desc); + (void)lattice_ec_next_byte(desc); + + for (j = 0; j < 8; j++) { + val = lattice_ec_next_byte(desc); + if (val == -1) + break; + version[j] = val & 0xff; + } + + break; + + default: + version[0] = (signed char) val; + for (j = 1; j < 8; j++) { + val = lattice_ec_next_byte(desc); + if (val == -1) + break; + version[j] = val & 0xff; + } + break; + } + + ret = ispvm_validate_version(&priv.d, version); + if (ret < 0) + return VME_VERSION_FAILURE; + + PRINTF("FPGA pre-program\n"); + if (fn->pre) + fn->pre(0); + + /* Reset FPGA */ + PRINTF("FPGA reset\n"); + fn->jtag_write_port(0, LATTICE_JTAG_RST, 1); + udelay(1000); + fn->jtag_write_port(0, LATTICE_JTAG_RST, 0); + + /* lattice_ec_verbose = 0; */ + + ispvm_start(&priv.d); + ret = ispvm_code(&priv.d); + ispvm_end(&priv.d); + + if (ret != 0) { + if (fn->post) + (*fn->post)(0, 0); + + PRINTF(" FAILED! (code = %d)\n", cRetCode); + +#ifdef CFG_FPGA_PROG_FEEDBACK + printf(" FAIL!\n"); +#endif + return FPGA_FAIL; + } + + PRINTF(" OK\n"); + + PRINTF("FPGA post-program\n"); + if (fn->post) + (*fn->post)(0, 1); + +#ifdef CFG_FPGA_PROG_FEEDBACK + printf("\b\b done.\n"); +#endif + + return FPGA_SUCCESS; +} + +static int EC_jtag_dump (Lattice_desc * desc, void *buf, size_t bsize) +{ + /* Readback is only available through the Slave Parallel and */ + /* boundary-scan interfaces. */ + printf ("%s: JTAG Dumping is unavailable\n", + __FUNCTION__); + return FPGA_FAIL; +} + +static int EC_jtag_reloc (Lattice_desc * desc, ulong reloc_offset) +{ + ulong addr; + Lattice_EC_JTAG_fns *fn_r, *fn = desc->iface_fns; + + if (!fn) { + printf ("%s: NULL Interface function table!\n", __FUNCTION__); + return FPGA_FAIL; + } + + /* Get the relocated table address */ + addr = (ulong) fn + reloc_offset; + fn_r = (Lattice_EC_JTAG_fns *) addr; + + if (fn_r->relocated) { + /* this table has already been moved */ + /* XXX - should check to see if the descriptor is correct */ + desc->iface_fns = fn_r; + return FPGA_SUCCESS; + } + + if (memcmp(fn_r, fn, sizeof(Lattice_EC_JTAG_fns)) != 0) { + PRINTF ("%s: Invalid function table at 0x%p\n", + __FUNCTION__, fn_r); + return FPGA_FAIL; + } + + /* good copy of the table, + * fix the descriptor pointer + */ + desc->iface_fns = fn_r; + PRINTF ("%s: Relocating descriptor at 0x%p\n", __FUNCTION__, + desc); + + addr = (ulong) (fn->pre) + reloc_offset; + fn_r->pre = (Lattice_pre_fn) addr; + + addr = (ulong) (fn->post) + reloc_offset; + fn_r->post = (Lattice_post_fn) addr; + + addr = (ulong) (fn->jtag_write_port) + reloc_offset; + fn_r->jtag_write_port = (Lattice_jtag_write_port_fn) addr; + + addr = (ulong) (fn->jtag_read_port) + reloc_offset; + fn_r->jtag_read_port = (Lattice_jtag_read_port_fn) addr; + + fn_r->relocated = TRUE; + + return FPGA_SUCCESS; +} + +/****************************************************************************/ + +#ifdef CFG_FPGA_PROG_FEEDBACK + +static const char spin_txt[] = "|/-\"; + +static inline void fpga_progress(Lattice_desc *desc) +{ + struct Lattice_EC_private *priv = desc->priv; + + if (--priv->fpga_steps >= 0) + return; + + priv->fpga_steps = priv->fpga_steps_reset; + printf("\b%c", spin_txt[priv->fpga_spin]); + if (++priv->fpga_spin >= 4) + priv->fpga_spin = 0; +} + +#else + +#define fpga_progress(desc) do { } while(0) + +#endif + +static void rewind_buffer(void *cookie) +{ + Lattice_desc * desc = cookie; + struct Lattice_EC_private *priv = desc->priv; + + priv->fpga_prog_next = priv->fpga_prog_base; + + if (lattice_ec_verbose) + printf("\nRewind:\n"); +} + +int lattice_ec_next_byte(void *cookie) +{ + Lattice_desc * desc = cookie; + struct Lattice_EC_private *priv = desc->priv; + unsigned char val; + int pos; + + if (priv == NULL || priv->fpga_prog_next == NULL || + priv->fpga_prog_next >= priv->fpga_prog_end) + return -1; + + val = *priv->fpga_prog_next & 0xff; + + if (lattice_ec_verbose) { + pos = priv->fpga_prog_next - priv->fpga_prog_base; + if ((pos % 16) == 0) + PRINTF("[%04x]", pos & 0xffff); + + PRINTF(" %02x", val); + } + + priv->fpga_prog_next++; + + if (lattice_ec_verbose) { + pos = priv->fpga_prog_next - priv->fpga_prog_base; + if ((pos % 16) == 0) + PRINTF("\n"); + } + + fpga_progress(desc); + + return val; +} + +#ifdef FPGA_DEBUG +static const char *pin_txt[] = { + [LATTICE_JTAG_TDI] = "TDI", + [LATTICE_JTAG_TCK] = "TCK", + [LATTICE_JTAG_TMS] = "TMS", + [LATTICE_JTAG_TDO] = "TDO", + [LATTICE_JTAG_CE] = "CE", + [LATTICE_JTAG_RST] = "RST", +}; +#endif + +int lattice_ec_read_port(void *cookie) +{ + Lattice_desc * desc = cookie; + Lattice_EC_JTAG_fns *fn = desc->iface_fns; + struct Lattice_EC_private *priv = desc->priv; + int val; + + (void)priv; + val = fn->jtag_read_port(0); + + if (lattice_ec_verbose) + PRINTF("R-TDO=%d\n", val); + + return val; +} + +void lattice_ec_write_port(void *cookie, int pin, int value) +{ + Lattice_desc * desc = cookie; + Lattice_EC_JTAG_fns *fn = desc->iface_fns; + struct Lattice_EC_private *priv = desc->priv; + + (void)priv; + + if (lattice_ec_verbose) + PRINTF("W-%s=%d\n", pin_txt[pin], value & 1); + + fn->jtag_write_port(0, pin, value); +} + +#endif diff --git a/include/fpga.h b/include/fpga.h index a038aa1..f04b64a 100644 --- a/include/fpga.h +++ b/include/fpga.h @@ -47,7 +47,7 @@ /* FPGA Manufacturer bits in CONFIG_FPGA */ #define CFG_FPGA_XILINX CFG_FPGA_MAN( 0x1 ) #define CFG_FPGA_ALTERA CFG_FPGA_MAN( 0x2 ) - +#define CFG_FPGA_LATTICE CFG_FPGA_MAN( 0x4 )
/* fpga_xxxx function return value definitions */ #define FPGA_SUCCESS 0 @@ -61,6 +61,7 @@ typedef enum { /* typedef fpga_type */ fpga_min_type, /* range check value */ fpga_xilinx, /* Xilinx Family) */ fpga_altera, /* unimplemented */ + fpga_lattice, /* lattice */ fpga_undefined /* invalid range check value */ } fpga_type; /* end, typedef fpga_type */
diff --git a/include/lattice.h b/include/lattice.h new file mode 100644 index 0000000..edd3e74 --- /dev/null +++ b/include/lattice.h @@ -0,0 +1,85 @@ +/* + * (C) Copyright 2006 - Embedded Alley Solutions Inc. + * by Pantelis Antoniou, pantelis@embeddedalley.com + * + * Based on include/xilinx.h + * (C) Copyright 2002 + * by Rich Ireland, Enterasys Networks, rireland@enterasys.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include <fpga.h> + +#ifndef _LATTICE_H_ +#define _LATTICE_H_ + +/* Lattice Model definitions */ +#define CFG_EC CFG_FPGA_DEV( 0x1 ) +#define CFG_LATTICE_EC (CFG_FPGA_LATTICE | CFG_EC) + +/* Lattice Interface definitions */ +#define CFG_LATTICE_IF_JTAG CFG_FPGA_IF( 0x1 ) /* jtag */ + +/* Lattice types */ +typedef enum { /* typedef Lattice_iface */ + min_lattice_iface_type, /* low range check value */ + lattice_jtag_mode, /* jtag/tap serial */ + max_lattice_iface_type /* insert all new types before this */ +} Lattice_iface; /* end, typedef Lattice_iface */ + +typedef enum { /* typedef Lattice_Family */ + min_lattice_type, /* low range check value */ + Lattice_EC, /* EC Family */ + max_lattice_type /* insert all new types before this */ +} Lattice_Family; /* end, typedef Lattice_Family */ + +typedef struct { /* typedef Lattice_desc */ + Lattice_Family family; /* part type */ + Lattice_iface iface; /* interface type */ + size_t size; /* bytes of data part can accept */ + void * iface_fns; /* interface function table */ + int cookie; /* implementation specific cookie */ + void * priv; /* private info */ +} Lattice_desc; /* end, typedef Lattice_desc */ + +/* Generic Lattice Functions */ +extern int lattice_load( Lattice_desc *desc, void *image, size_t size ); +extern int lattice_dump( Lattice_desc *desc, void *buf, size_t bsize ); +extern int lattice_info( Lattice_desc *desc ); +extern int lattice_reloc( Lattice_desc *desc, ulong reloc_offset ); + +/* Board specific implementation specific function types */ + +#define LATTICE_JTAG_TDI 0 +#define LATTICE_JTAG_TCK 1 +#define LATTICE_JTAG_TMS 2 +#define LATTICE_JTAG_TDO 3 +#define LATTICE_JTAG_CE 4 +#define LATTICE_JTAG_RST 5 + +typedef int (*Lattice_pre_fn)( int cookie ); +typedef int (*Lattice_post_fn)( int cookie, int success); + +typedef void (*Lattice_jtag_write_port_fn)(int cookie, unsigned int pin, + unsigned int value); +typedef int (*Lattice_jtag_read_port_fn)(int cookie); + +#endif /* _LATTICE_H_ */ diff --git a/include/lattice_ec.h b/include/lattice_ec.h new file mode 100644 index 0000000..f92a87c --- /dev/null +++ b/include/lattice_ec.h @@ -0,0 +1,85 @@ +/* + * (C) Copyright 2006 - Embedded Alley Solutions Inc. + * by Pantelis Antoniou, pantelis@embeddedalley.com + * + * Based on include/spartan2.h + * (C) Copyright 2002 + * by Rich Ireland, Enterasys Networks, rireland@enterasys.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#ifndef _EC_H_ +#define _EC_H_ + +#include <lattice.h> +#include <lattice_ivm_core.h> + +struct Lattice_EC_private { + unsigned char *fpga_prog_base; + unsigned char *fpga_prog_end; + unsigned char *fpga_prog_next; + int fpga_steps_reset; + int fpga_steps; + int fpga_spin; + struct ispvm_desc d; +}; + +extern int EC_load(Lattice_desc *desc, void *image, size_t size); +extern int EC_dump(Lattice_desc *desc, void *buf, size_t bsize); +extern int EC_info(Lattice_desc *desc); +extern int EC_reloc(Lattice_desc *desc, ulong reloc_off); + +/* JTAG Implementation function table */ +typedef struct { + Lattice_pre_fn pre; + Lattice_post_fn post; + Lattice_jtag_write_port_fn jtag_write_port; + Lattice_jtag_read_port_fn jtag_read_port; + int relocated; +} Lattice_EC_JTAG_fns; + +/* Device Image Sizes + *********************************************************************/ +/* Lattice EC (1.8V) */ +#define LATTICE_LFEC1_SIZE 6144/8 +#define LATTICE_LFEC3_SIZE 12288/8 +#define LATTICE_LFEC6_SIZE 25600/8 + +/* Descriptor Macros + *********************************************************************/ +/* CE devices */ +#define LATTICE_LFEC1_DESC(iface, fn_table, cookie) \ +{ Lattice_CE, iface, LATTICE_LFEC1_SIZE, fn_table, cookie } + +#define LATTICE_LFEC3_DESC(iface, fn_table, cookie) \ +{ Lattice_CE, iface, LATTICE_LFEC3_SIZE, fn_table, cookie } + +#define LATTICE_LFEC6_DESC(iface, fn_table, cookie) \ +{ Lattice_CE, iface, LATTICE_LFEC6_SIZE, fn_table, cookie } + +/* API to the IVM */ +/*********************************************************************/ + +extern int lattice_ec_next_byte(void *cookie); +extern int lattice_ec_read_port(void *cookie); +extern void lattice_ec_write_port(void *cookie, int pin, int value); + +#endif

Add support for Lattice FPGA parts programmed using JTAG.
--- Signed-off-by: Pantelis Antoniou pantelis@embeddedalley.com ---
common/lattice_ivm_core.c | 750 ++++++++++++++++++++++++++++++++++++++++++++ include/lattice_ivm_core.h | 214 +++++++++++++ include/lattice_vmopcode.h | 286 +++++++++++++++++ 3 files changed, 1250 insertions(+), 0 deletions(-)
diff --git a/common/lattice_ivm_core.c b/common/lattice_ivm_core.c new file mode 100644 index 0000000..419b269 --- /dev/null +++ b/common/lattice_ivm_core.c @@ -0,0 +1,750 @@ +/* + * (C) Copyright 2006 - Embedded Alley Solutions Inc. + * by Pantelis Antoniou, pantelis@embeddedalley.com + * + * Based on redboot's lattice_ivm_core.c + * + * This file was based on ASP8347DB's redboot sources + * with the same name. The file was not carrying any copyright + * markings while RedBoot is clearly GPL licensed. + + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include <common.h> +#include <malloc.h> +#include <lattice.h> +#include <lattice_ec.h> + +#include <lattice_ivm_core.h> +#include <lattice_vmopcode.h> + +#if (CONFIG_FPGA & CFG_FPGA_LATTICE) + +/* Enable/Disable debug console messages */ +#ifdef FPGA_DEBUG +#define PRINTF(fmt,args...) printf (fmt ,##args) +#else +#define PRINTF(fmt,args...) +#endif + +/* + * Reset all global variables to a known state, as this code may be + * reused (but not reloaded) + */ +void ispvm_reset(struct ispvm_desc *d, void *input_cookie) +{ + d->cookie = input_cookie; + + d->flow_control = 0x0000; + d->data_type = 0x0000; + d->end_DR = DRPAUSE; + d->end_IR = IRPAUSE; + d->head_DR = 0; + d->head_IR = 0; + d->tail_DR = 0; + d->tail_IR = 0; + d->data_size = 0; + d->frequency = 1000; + d->max_size = 0; + d->shift_value = 0; + d->repeat_loops = 0; + d->vendor = LATTICE; + d->current_jtag_state = 0; + d->heap_memory = NULL; + d->heap_counter = 0; + d->intel_data_idx = 0; + d->intel_buffer_size = 0; + d->TDO_size = 0; + d->MASK_size = 0; + d->TDI_size = 0; + d->DMASK_size = 0; + d->LCOUNT_size = 0; + d->HDR_size = 0; + d->TDR_size = 0; + d->HIR_size = 0; + d->TIR_size = 0; + d->HEAP_size = 0; + + if (d->out_MASK_data) + free(d->out_MASK_data); + if (d->in_TDI_data) + free(d->in_TDI_data); + if (d->out_TDO_data) + free(d->out_TDO_data); + if (d->HIR_data) + free(d->HIR_data); + if (d->TIR_data) + free(d->TIR_data); + if (d->HDR_data) + free(d->HDR_data); + if (d->TDR_data) + free(d->TDR_data); + if (d->intel_buffer) + free(d->intel_buffer); + if (d->out_DMASK_data) + free(d->out_DMASK_data); + if (d->LVDS_list) + free(d->LVDS_list); + + d->out_MASK_data = NULL; + d->in_TDI_data = NULL; + d->out_TDO_data = NULL; + d->HIR_data = NULL; + d->TIR_data = NULL; + d->HDR_data = NULL; + d->TDR_data = NULL; + d->intel_buffer = NULL; + d->out_DMASK_data = NULL; + d->LVDS_list = NULL; + + d->out_MASK_data_size = 0; + d->in_TDI_data_size = 0; + d->out_TDO_data_size = 0; + d->HIR_data_size = 0; + d->TIR_data_size = 0; + d->HDR_data_size = 0; + d->TDR_data_size = 0; + d->intel_buffer_alloc_size = 0; + d->out_DMASK_data_size = 0; + d->LVDS_list_size = 0; + + d->LVDS_pair_count = 0; +} + +/* Enable the port to the device and set the state to RESET (TLR). */ +void ispvm_start(struct ispvm_desc *d) +{ + /* turn the Lattice Cable on */ + lattice_ec_write_port(d->cookie, LATTICE_JTAG_CE, 1); + /* step devices to RESET state */ + ispvm_state_machine(d, RESET); +} + +/* + * Set the state of devices to RESET to enable the devices and disable + * the port. + */ +void ispvm_end(struct ispvm_desc *d) +{ + /* step devices to RESET state */ + ispvm_state_machine(d, RESET); + /* wake up devices */ + udelay(1000); + /* disable the Lattice Cable */ + lattice_ec_write_port(d->cookie, LATTICE_JTAG_CE, 0); +} + +/* Calculate the 32-bit CRC. */ +u16 ispvm_crc(struct ispvm_desc *d, u8 data, u16 ccrc) +{ + int i; + u8 fdata = 0; + u16 crce; + static const u16 crc_table[16] = { + 0x0000, 0xCC01, 0xD801, 0x1400, + 0xF001, 0x3C00, 0x2800, 0xE401, + 0xA001, 0x6C00, 0x7800, 0xB401, + 0x5000, 0x9C01, 0x8801, 0x4400 + }; + + for (i = 0; i < 8; i++) { + fdata <<= 1; + if (data & 0x01) + fdata |= 0x01; + data >>= 1; + } + + crce = crc_table[ccrc & 0xF]; + ccrc = (ccrc >> 4) & 0x0FFF; + ccrc = ccrc ^ crce ^ crc_table[fdata & 0xF]; + crce = crc_table[ccrc & 0xF]; + ccrc = (ccrc >> 4) & 0x0FFF; + ccrc = ccrc ^ crce ^ crc_table[(fdata >> 4) & 0xF]; + + return ccrc; +} + +int ispvm_validate_version(struct ispvm_desc *d, const char *version) +{ + static const char *vertab[] = { + "__VME2.0", + "__VME3.0", + "____12.0", + NULL + }; + int i, j, ret; + + ret = 0; + for (i = 0; vertab[i] != NULL; i++) { + for (j = 0; j < 8; j++) { + if (version[j] != vertab[i][j]) { + ret = VME_VERSION_FAILURE; + break; + } + ret = 0; + } + + if (ret == 0) + break; + } + + return ret; +} + +/* + * Returns a byte to the caller. The returned byte depends on the + * d->data_type 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. + */ +int ispvm_get(struct ispvm_desc *d) +{ + if (d->data_type & HEAP_IN) { + if (d->heap_counter > d->heap_repeat_size) + return -1; + return d->heap_memory[d->heap_counter++]; + } + + if (d->data_type & LHEAP_IN) { + if (d->intel_data_idx > d->intel_buffer_size) + return -1; + return d->intel_buffer[d->intel_buffer_size++]; + } + + /* get next byte from buffer */ + return lattice_ec_next_byte(d->cookie); +} + +/* + * Allocate memory based on target. The memory size is specified + * by size. + */ +int ispvm_alloc(struct ispvm_desc *d, int target, int size) +{ + switch (target) { + case XTDI: + case TDI: + if (d->in_TDI_data != NULL && d->in_TDI_data_size <= size) + break; + + if (d->in_TDI_data != NULL) { + free(d->in_TDI_data); + d->in_TDI_data = NULL; + d->in_TDI_data_size = 0; + } + d->in_TDI_data = malloc(size / 8 + 2); + if (d->in_TDI_data != NULL) + d->in_TDI_data_size = size; + else + return VME_OUT_OF_MEMORY; + break; + + case XTDO: + case TDO: + if (d->out_TDO_data != NULL && d->out_TDO_data_size <= size) + break; + + if (d->out_TDO_data != NULL) { + free(d->out_TDO_data); + d->out_TDO_data = NULL; + d->out_TDO_data_size = 0; + } + d->out_TDO_data = malloc(size / 8 + 2); + if (d->out_TDO_data != NULL) + d->out_TDO_data_size = size; + else + return VME_OUT_OF_MEMORY; + break; + + case MASK: + if (d->out_MASK_data != NULL && d->out_MASK_data_size <= size) + break; + + if (d->out_MASK_data != NULL) { + free(d->out_MASK_data); + d->out_MASK_data = NULL; + d->out_MASK_data_size = 0; + } + d->out_MASK_data = malloc(size / 8 + 2); + if (d->out_MASK_data != NULL) + d->out_MASK_data_size = size; + else + return VME_OUT_OF_MEMORY; + break; + + case HIR: + if (d->HIR_data != NULL && d->HIR_data_size <= size) + break; + + if (d->HIR_data != NULL) { + free(d->HIR_data); + d->HIR_data = NULL; + d->HIR_data_size = 0; + } + d->HIR_data = malloc(size / 8 + 2); + if (d->HIR_data != NULL) + d->HIR_data_size = size; + else + return VME_OUT_OF_MEMORY; + break; + + case TIR: + if (d->TIR_data != NULL && d->TIR_data_size <= size) + break; + + if (d->TIR_data != NULL) { + free(d->TIR_data); + d->TIR_data = NULL; + d->TIR_data_size = 0; + } + d->TIR_data = malloc(size / 8 + 2); + if (d->TIR_data != NULL) + d->TIR_data_size = size; + else + return VME_OUT_OF_MEMORY; + break; + + case HDR: + if (d->HDR_data != NULL && d->HDR_data_size <= size) + break; + + if (d->HDR_data != NULL) { + free(d->HDR_data); + d->HDR_data = NULL; + d->HDR_data_size = 0; + } + d->HDR_data = malloc(size / 8 + 2); + if (d->HDR_data != NULL) + d->HDR_data_size = size; + else + return VME_OUT_OF_MEMORY; + break; + + case TDR: + if (d->TDR_data != NULL && d->TDR_data_size <= size) + break; + + if (d->TDR_data != NULL) { + free(d->TDR_data); + d->TDR_data = NULL; + d->TDR_data_size = 0; + } + d->TDR_data = malloc(size / 8 + 2); + if (d->TDR_data != NULL) + d->TDR_data_size = size; + else + return VME_OUT_OF_MEMORY; + break; + + case HEAP: + if (d->heap_memory != NULL && d->heap_memory_size <= size) + break; + + if (d->heap_memory != NULL) { + free(d->heap_memory); + d->heap_memory = NULL; + d->heap_memory_size = 0; + } + d->heap_memory = malloc(size + 2); + if (d->heap_memory != NULL) + d->heap_memory_size = size; + else + return VME_OUT_OF_MEMORY; + break; + + case DMASK: + if (d->out_DMASK_data != NULL && d->out_DMASK_data_size <= size) + break; + + if (d->out_DMASK_data != NULL) { + free(d->out_DMASK_data); + d->out_DMASK_data = NULL; + d->out_DMASK_data_size = 0; + } + d->out_DMASK_data = malloc(size / 8 + 2); + if (d->out_DMASK_data != NULL) + d->out_DMASK_data_size = size; + else + return VME_OUT_OF_MEMORY; + break; + + case LHEAP: + if (d->intel_buffer != NULL && d->intel_buffer_alloc_size <= size) + break; + + if (d->intel_buffer != NULL) { + free(d->intel_buffer); + d->intel_buffer = NULL; + d->intel_buffer_alloc_size = 0; + } + d->intel_buffer = malloc(size + 2); + if (d->intel_buffer != NULL) + d->intel_buffer_alloc_size = size; + else + return VME_OUT_OF_MEMORY; + break; + + case LVDS: + if (d->LVDS_list != NULL && d->LVDS_list_size <= size) + break; + + if (d->LVDS_list != NULL) { + free(d->LVDS_list); + d->LVDS_list = NULL; + d->LVDS_list_size = 0; + } + d->LVDS_list = malloc(size * sizeof(LVDSPair)); + if (d->LVDS_list != NULL) { + memset(d->LVDS_list, 0, size * sizeof(LVDSPair)); + d->LVDS_list_size = size; + } else + return VME_OUT_OF_MEMORY; + break; + + default: + break; + } + + return 0; +} + +/* + * 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. + */ +int ispvm_code(struct ispvm_desc *d) +{ + int i, j, state, opcode; + int ret = 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 (!(d->data_type & LHEAP_IN) && !(d->data_type & HEAP_IN)) { + ret = ispvm_get(d); + if (ret == -1) + return VME_INVALID_FILE; + if (ret == 0xf1) + d->data_type |= COMPRESS; + else if (ret == 0xf2) + d->data_type &= ~COMPRESS; + else + return VME_INVALID_FILE; + } + + /* Begin looping through all the VME opcodes. */ + while ((opcode = ispvm_get(d)) >= 0) { + + switch (opcode) { + + /* Step the JTAG state machine. */ + case STATE: + PRINTF("STATE:\n"); + state = ispvm_get(d); + if (state == -1) + return VME_INVALID_FILE; + ispvm_state_machine(d, state); + break; + + /* Shift in data into the device. */ + case SIR: + PRINTF("SIR:\n"); + + ret = ispvm_shift(d, opcode); + if (ret != 0) + return ret; + break; + + case SDR: + PRINTF("SDR:\n"); + ret = ispvm_shift(d, opcode); + if (ret != 0) + return ret; + break; + + case XSDR: + PRINTF("XSDR:\n"); + ret = ispvm_shift(d, opcode); + if (ret != 0) + return ret; + break; + + /* perform delay */ + case WAIT: + PRINTF("WAIT:\n"); + j = ispvm_data_size(d); + if (j == -1) + return VME_INVALID_FILE; + if (j & 0x8000) { + i = j & ~0x8000; + while (i-- > 0) + udelay(1000); + } else + udelay(j); + break; + + /* Issue clock toggles. */ + case TCK: + PRINTF("TCK:\n"); + j = ispvm_data_size(d); + if (j == -1) + return VME_INVALID_FILE; + for (i = 0; i < j; i++) + ispvm_clock(d); + break; + + /* Set the ENDDR. */ + case ENDDR: + PRINTF("ENDDR:\n"); + d->end_DR = ispvm_get(d); + break; + + /* Set the ENDIR. */ + case ENDIR: + PRINTF("ENDIR:\n"); + d->end_IR = ispvm_get(d); + break; + + /* + * Set the header/trailer of the device in order to + * bypass successfully. + */ + case HIR: + PRINTF("HIR:\n"); + ret = ispvm_amble(d, opcode); + if (ret != 0) + return ret; + break; + + case TIR: + PRINTF("TIR:\n"); + ret = ispvm_amble(d, opcode); + if (ret != 0) + return ret; + break; + + case HDR: + PRINTF("HDR:\n"); + ret = ispvm_amble(d, opcode); + if (ret != 0) + return ret; + break; + + case TDR: + PRINTF("TDR:\n"); + ret = ispvm_amble(d, opcode); + if (ret != 0) + return ret; + break; + + /* + * The maximum RAM required to support processing + * one row of the VME file. + */ + case MEM: + PRINTF("MEM:\n"); + j = ispvm_data_size(d); + if (j == -1) + return VME_INVALID_FILE; + d->max_size = j; + break; + + /* Set the VENDOR type. */ + case VENDOR: + PRINTF("VENDOR:\n"); + opcode = ispvm_get(d); + switch (opcode) { + case LATTICE: + d->vendor = LATTICE; + break; + case ALTERA: + d->vendor = ALTERA; + break; + case XILINX: + d->vendor = XILINX; + break; + default: + return VME_INVALID_FILE; + } + break; + + /* + * Set the flow control. Flow control determines the + * personality of the embedded engine. + */ + case SETFLOW: + PRINTF("SETFLOW:\n"); + j = ispvm_data_size(d); + if (j == -1) + return VME_INVALID_FILE; + d->flow_control |= j & 0xffff; + break; + + /* Unset the flow control. */ + case RESETFLOW: + PRINTF("RESETFLOW:\n"); + j = ispvm_data_size(d); + if (j == -1) + return VME_INVALID_FILE; + d->flow_control &= ~j & 0xffff; + break; + + /* Allocate heap size to store loops. */ + case HEAP: + PRINTF("HEAP:\n"); + ret = ispvm_get(d); + if (ret != SECUREHEAP) + return VME_INVALID_FILE; + + j = ispvm_data_size(d); + if (j == -1) + return VME_INVALID_FILE; + d->heap_repeat_size = j; + + /* + * Store the maximum size of the HEAP buffer. + * Used to convert VME to HEX. + */ + if (d->heap_repeat_size > d->HEAP_size) + d->HEAP_size = d->heap_repeat_size; + + j = ispvm_alloc(d, HEAP, d->heap_repeat_size); + if (j != 0) + return VME_OUT_OF_MEMORY; + break; + + /* Execute loops. */ + case REPEAT: + PRINTF("REPEAT:\n"); + d->repeat_loops = 0; + j = ispvm_data_size(d); + if (j == -1) + return VME_INVALID_FILE; + ret = ispvm_loop(d, j); + if (ret != 0) + return ret; + break; + + /* Exit point from processing loops. */ + case ENDLOOP: + PRINTF("ENDLOOP:\n"); + return ret; + + /* + * The only valid exit point that indicates end + * of programming. + */ + case ENDVME: + PRINTF("ENDVME:\n"); + return ret; + + /* Right-shift address. */ + case SHR: + PRINTF("SHR:\n"); + d->flow_control |= SHIFTRIGHT; + d->shift_value = d->repeat_loops * ispvm_get(d); + break; + + /* Left-shift address. */ + case SHL: + PRINTF("SHL:\n"); + d->flow_control |= SHIFTLEFT; + d->shift_value = d->repeat_loops * ispvm_get(d); + break; + + /* Set the d->frequency. */ + case FREQUENCY: + PRINTF("FREQUENCY:\n"); + j = ispvm_data_size(d); + if (j == -1) + return VME_INVALID_FILE; + d->frequency = j / 1000; + break; + + /* Process LCOUNT command. */ + case LCOUNT: + PRINTF("LCOUNT:\n"); + j = ispvm_data_size(d); + if (j == -1) + return VME_INVALID_FILE; + ret = ispvm_lcount(d, j); + if (ret != 0) + return ret; + break; + + /* Set the flow control to verify USERCODE. */ + case VUES: + PRINTF("VUES:\n"); + d->flow_control |= VERIFYUES; + break; + + /* Display comment. */ + case COMMENT: + PRINTF("COMMENT:\n"); + j = ispvm_data_size(d); + if (j == -1) + return VME_INVALID_FILE; + j = ispvm_comment(d, j); + if (j == -1) + return VME_INVALID_FILE; + break; + + /* Process LVDS command. */ + case LVDS: + PRINTF("LVDS:\n"); + j = ispvm_data_size(d); + if (j == -1) + return VME_INVALID_FILE; + j = ispvm_process_lvds(d, j); + if (j == -1) + return VME_INVALID_FILE; + break; + + /* Discard header. */ + case HEADER: + PRINTF("HEADER:\n"); + j = ispvm_data_size(d); + if (j == -1) + return VME_INVALID_FILE; + j = ispvm_header(d, j); + if (j == -1) + return VME_INVALID_FILE; + break; + + /* Invalid opcode encountered. */ + default: + 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; +} + +#endif diff --git a/include/lattice_ivm_core.h b/include/lattice_ivm_core.h new file mode 100644 index 0000000..1c939c7 --- /dev/null +++ b/include/lattice_ivm_core.h @@ -0,0 +1,214 @@ +/* + * (C) Copyright 2006 + * by Pantelis Antoniou, pantelis@embeddedalley.com + * + * This file was based on ASP8347DB's redboot sources + * with the same name. The file was not carrying any copyright + * markings while RedBoot is clearly GPL licensed. + + * lattice_ivm_core definitions + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#ifndef LATTICE_IVM_CORE_H +#define LATTICE_IVM_CORE_H + +#include <asm/types.h> + +/* Type definitions */ + +/* Support LVDS */ +typedef struct { + u16 positive_idx; + u16 negative_idx; + int update; +} LVDSPair; + +/* the state of the program engine */ +struct ispvm_desc { + + /* upper layer cookie */ + void *cookie; + + /* + * Flow control register. + * Each bit in the register can potentially change the + * personality of the embedded engine. + */ + u16 flow_control; + + /* holds the data type of the current row */ + u16 data_type; + + /* the state that the device goes to after SDR */ + u8 end_DR; + + /* the state that the device goes to after SIR */ + u8 end_IR; + + /* number of lead devices in bypass */ + u16 head_DR; + + /* sum of IR length of lead devices */ + u16 head_IR; + + /* number of tail devices in bypass */ + u16 tail_DR; + + /* sum of IR length of tail devices */ + u16 tail_IR; + + /* Number of bits of data or instruction + * to be shifted into or out from the device + */ + u16 data_size; + + /* Stores the frequency. Default to 1 MHz. */ + int frequency; + + /* + * Stores the maximum amount of ram needed to hold a + * row of data. + */ + u16 max_size; + + /* Stores the LSH or RSH value. */ + u16 shift_value; + + /* Stores the current repeat loop value. */ + u16 repeat_loops; + + /* Stores the current vendor. */ + int vendor; + + /* Stores the current state of the JTAG state machine. */ + int current_jtag_state; + + /* holds the entire repeat loop */ + u8 *heap_memory; + + /* holds the entire repeat loop allocated size */ + int heap_memory_size; + + /* points to the current byte in the repeat loop */ + u16 heap_counter; + + /* current size of the repeat in bytes */ + u16 heap_repeat_size; + + /* points to the current byte of the intelligent buffer */ + u16 intel_data_idx; + + /* holds the size of the intelligent buffer */ + u16 intel_buffer_size; + + /* + * + * Holds the maximum size of each respective buffer. + * These variables are used to write the HEX files when + * converting VME to HEX. + */ + u16 TDO_size; + u16 MASK_size; + u16 TDI_size; + u16 DMASK_size; + u16 LCOUNT_size; + u16 HDR_size; + u16 TDR_size; + u16 HIR_size; + u16 TIR_size; + u16 HEAP_size; + + /* one row of MASK data */ + u8 *out_MASK_data; + unsigned int out_MASK_data_size; + + /* one row of TDI data */ + u8 *in_TDI_data; + unsigned int in_TDI_data_size; + + /* one row of TDO data */ + u8 *out_TDO_data; + unsigned int out_TDO_data_size; + + /* current SIR header */ + u8 *HIR_data; + unsigned int HIR_data_size; + + /* current SIR trailer */ + u8 *TIR_data; + unsigned int TIR_data_size; + + /* current SDR header */ + u8 *HDR_data; + unsigned int HDR_data_size; + + /* current SDR trailer */ + u8 *TDR_data; + unsigned int TDR_data_size; + + /* current intelligent buffer */ + u8 *intel_buffer; + unsigned int intel_buffer_alloc_size; + + /* one row of DMASK data */ + u8 *out_DMASK_data; + unsigned int out_DMASK_data_size; + + /* List to hold all LVDS pairs. */ + LVDSPair *LVDS_list; + unsigned int LVDS_list_size; + u16 LVDS_pair_count; +}; + +/* interface function prototypes */ +void ispvm_reset(struct ispvm_desc *d, void *cookie); +void ispvm_start(struct ispvm_desc *d); +void ispvm_end(struct ispvm_desc *d); +u16 ispvm_crc(struct ispvm_desc *d, u8 data, u16 ccrc); +int ispvm_validate_version(struct ispvm_desc *d, const char *version); +int ispvm_code(struct ispvm_desc *d); + +/* internal function prototypes. */ +int ispvm_data_code(struct ispvm_desc *d); +int ispvm_data_size(struct ispvm_desc *d); +int ispvm_data(struct ispvm_desc *d, u8 *data); +int ispvm_shift(struct ispvm_desc *d, int code); +int ispvm_amble(struct ispvm_desc *d, int code); +int ispvm_loop(struct ispvm_desc *d, int repeats); +int ispvm_bit_shift(struct ispvm_desc *d, int mode, u16 bits); +int ispvm_comment(struct ispvm_desc *d, int size); +int ispvm_header(struct ispvm_desc *d, int size); +int ispvm_lcount(struct ispvm_desc *d, int size); +void ispvm_clock(struct ispvm_desc *d); +void ispvm_bypass(struct ispvm_desc *d, int scan_type, u16 bits); +void ispvm_state_machine(struct ispvm_desc *d, int next_state); +int ispvm_send(struct ispvm_desc *d, u16 size); +int ispvm_read(struct ispvm_desc *d, u16 size); +int ispvm_read_and_save(struct ispvm_desc *d, u16 size); +int ispvm_process_lvds(struct ispvm_desc *d, int count); + +/* lattice functions */ +int ispvm_get(struct ispvm_desc *d); +int ispvm_alloc(struct ispvm_desc *d, int types, int size); + + +#endif diff --git a/include/lattice_vmopcode.h b/include/lattice_vmopcode.h new file mode 100644 index 0000000..b9c8646 --- /dev/null +++ b/include/lattice_vmopcode.h @@ -0,0 +1,286 @@ +/* + * (C) Copyright 2006 + * by Pantelis Antoniou, pantelis@embeddedalley.com + * + * lattice_ivm_core definitions + * + * This file was based on ASP8347DB's redboot sources + * with the same name. The file was not carrying any copyright + * markings while RedBoot is clearly GPL licensed. + + * This is the include file for Lattice Semiconductor's ispVM + * Embedded software application. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#ifndef LATTICE_VMOPCODE_H +#define LATTICE_VMOPCODE_H + +/* VME version. */ +#define VME_VERSION_NUMBER "12.0" + +#define VMEHEXMAX 60000L /* The hex file is split 60K per file . */ +#define SCANMAX 64000L /* The maximum SDR/SIR burst . */ + +/* Supported JTAG state transitions. */ + +#define RESET 0x00 +#define IDLE 0x01 +#define IRPAUSE 0x02 +#define DRPAUSE 0x03 +#define SHIFTIR 0x04 +#define SHIFTDR 0x05 +/* 11/15/05 Nguyen changed to support DRCAPTURE*/ +#define DRCAPTURE 0x06 + +/* + * Flow control register bit definitions. A set bit indicates + * that the register currently exhibits the corresponding mode. + */ + +#define INTEL_PRGM 0x0001 /* Intelligent programming is in effect */ +#define CASCADE 0x0002 /* Currently splitting large SDR */ +#define REPEATLOOP 0x0008 /* Currently executing a repeat loop */ +#define SHIFTRIGHT 0x0080 /* The next data stream needs a right shift */ +#define SHIFTLEFT 0x0100 /* The next data stream needs a left shift */ +#define VERIFYUES 0x0200 /* Continue if fail is in effect */ + +/* + * DataType register bit definitions. A set bit indicates + * that the register currently holds the corresponding type of data. + */ + +#define EXPRESS 0x0001 /* Simultaneous program and verify */ +#define SIR_DATA 0x0002 /* SIR is the active SVF command */ +#define SDR_DATA 0x0004 /* SDR is the active SVF command */ +#define COMPRESS 0x0008 /* Data is compressed */ +#define TDI_DATA 0x0010 /* TDI data is present */ +#define TDO_DATA 0x0020 /* TDO data is present */ +#define MASK_DATA 0x0040 /* MASK data is present */ +#define HEAP_IN 0x0080 /* Data is from the heap */ +#define LHEAP_IN 0x0200 /* Data is from intel data buffer */ +#define VARIABLE 0x0400 /* Data is from a declared variable */ +#define CRC_DATA 0x0800 /* CRC data is pressent */ +#define CMASK_DATA 0x1000 /* CMASK data is pressent */ +#define RMASK_DATA 0x2000 /* RMASK data is pressent */ +#define READ_DATA 0x4000 /* READ data is pressent */ +#define DMASK_DATA 0x8000 /* DMASK data is pressent */ + +/* Pin opcodes */ +#define signalENABLE 0x1C /* ispENABLE */ +#define signalTMS 0x1D /* TMS */ +#define signalTCK 0x1E /* TCK */ +#define signalTDI 0x1F /* TDI */ +#define signalTRST 0x2 /* TRST */ + +/* Supported vendors. */ +#define VENDOR 0x56 +#define LATTICE 0x01 +#define ALTERA 0x02 +#define XILINX 0x03 + +/* Opcode definitions */ + +/* The end of the current SDR data stream. */ +#define ENDDATA 0x00 + +/* The duration to stay at the stable state. */ +#define RUNTEST 0x01 + +/* The stable state after SDR. */ +#define ENDDR 0x02 + +/* The stable state after SIR. */ +#define ENDIR 0x03 + +/* The stable state after RUNTEST. */ +#define ENDSTATE 0x04 + +/* Assert the TRST pin. */ +#define TRST 0x05 + +/* The sum of the IR bits of the leading devices. */ +#define HIR 0x06 + +/* The sum of the IR bits of the trailing devices. */ +#define TIR 0x07 + +/* The number of leading devices. */ +#define HDR 0x08 + +/* The number of trailing devices. */ +#define TDR 0x09 + +/* Assert the ispEN pin. */ +#define ispEN 0x0A + +/* The maximum clock rate to run the JTAG state machine. */ +#define FREQUENCY 0x0B + +/* Move to the next stable state. */ +#define STATE 0x10 + +/* The instruction stream follows. */ +#define SIR 0x11 + +/* The data stream follows. */ +#define SDR 0x12 + +/* The following data stream feeds into the device. */ +#define TDI 0x13 + +/* The following data stream is compared against the device. */ +#define TDO 0x14 + +/* The following data stream is used as mask. */ +#define MASK 0x15 + +/* The following data stream is for simultaneous program and verify. */ +#define XSDR 0x16 + +/* + * The following data stream is for shift in only. + * It must be stored for the next XSDR. + */ +#define XTDI 0x17 + +/* + * is not data stream. + * The data stream was stored from the previous XTDI. + */ +#define XTDO 0x18 + +/* The maximum memory needed to allocate in order hold one row of data */ +#define MEM 0x19 + +/* The duration of delay to observe. */ +#define WAIT 0x1A + +/* The number of TCK pulses. */ +#define TCK 0x1B + +/* Set the flow control register for right shift. */ +#define SHR 0x23 + +/* Set the flow control register for left shift. */ +#define SHL 0x24 + +/* The memory size needed to hold one loop. */ +#define HEAP 0x32 + +/* The beginning of the loop. */ +#define REPEAT 0x33 + +/* The beginning of data following the loop. */ +#define LEFTPAREN 0x35 + +/* Plac holder for loop data. */ +#define VAR 0x55 + +/* The delay time in seconds that must be observed. */ +#define SEC 0x1C + +/* The mask for TDI data. */ +#define SMASK 0x1D + +/* The absolute maximum wait time. */ +#define MAX 0x1E + +/* Assert the targeted pin. */ +#define ON 0x1F + +/* Dis-assert the targeted pin. */ +#define OFF 0x20 + +/* Change the flow control register. */ +#define SETFLOW 0x30 + +/* Clear the flow control register. */ +#define RESETFLOW 0x31 + +/* The following data stream is used for CRC calculation. */ +#define CRC 0x47 + +/* The following data stream is used as mask for CRC calculation. */ +#define CMASK 0x48 + +/* The following data stream is used as mask for read and save. */ +#define RMASK 0x49 + +/* The following data stream is used for read and save. */ +#define READ 0x50 + +/* The end of the repeat loop. */ +#define ENDLOOP 0x59 + +/* Used to secure the HEAP opcode. */ +#define SECUREHEAP 0x60 + +/* Support continue if fail. */ +#define VUES 0x61 + +/* The following data stream is used for dynamic I/O. */ +#define DMASK 0x62 + +/* Support SVF comments in the VME file. */ +#define COMMENT 0x63 + +/* Support header in VME file. */ +#define HEADER 0x64 + +/* Support crc-protected VME file. */ +#define FILE_CRC 0x65 + +/* Support intelligent programming. */ +#define LCOUNT 0x66 + +/* Support intelligent programming. */ +#define LDELAY 0x67 + +/* Support intelligent programming. */ +#define LSDR 0x68 + +/* Memory needed to hold intelligent data buffer */ +#define LHEAP 0x69 + +/* Allow continuation. */ +#define CONTINUE 0x70 + +/* Support LVDS. */ +#define LVDS 0x71 + +/* End of the VME file. */ +#define ENDVME 0x7F + +/* End of file. */ +#define ENDFILE 0xFF + +/* ispVM Embedded Return Codes */ +#define VME_OK 0 +#define VME_VERIFICATION_FAILURE -1 +#define VME_FILE_READ_FAILURE -2 +#define VME_VERSION_FAILURE -3 +#define VME_INVALID_FILE -4 +#define VME_ARGUMENT_FAILURE -5 +#define VME_CRC_FAILURE -6 +#define VME_OUT_OF_MEMORY -7 + +#endif

Add support for Lattice FPGA parts programmed using JTAG.
--- Signed-off-by: Pantelis Antoniou pantelis@embeddedalley.com ---
common/lattice_ivm_supp.c | 1426 +++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 1426 insertions(+), 0 deletions(-)
diff --git a/common/lattice_ivm_supp.c b/common/lattice_ivm_supp.c new file mode 100644 index 0000000..797dff1 --- /dev/null +++ b/common/lattice_ivm_supp.c @@ -0,0 +1,1426 @@ +/* + * (C) Copyright 2006 - Embedded Alley Solutions Inc. + * by Pantelis Antoniou, pantelis@embeddedalley.com + * + * Based on redboot's lattice_ivm_core.c + * + * This file was based on ASP8347DB's redboot sources + * with the same name. The file was not carrying any copyright + * markings while RedBoot is clearly GPL licensed. + + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include <common.h> +#include <malloc.h> +#include <lattice.h> +#include <lattice_ec.h> + +#include <lattice_ivm_core.h> +#include <lattice_vmopcode.h> + +#if (CONFIG_FPGA & CFG_FPGA_LATTICE) + +/* Enable/Disable debug console messages */ +#ifdef FPGA_DEBUG +#define PRINTF(fmt,args...) printf (fmt ,##args) +#else +#define PRINTF(fmt,args...) +#endif + +/* + * Returns a VME-encoded number, usually used to indicate the + * bit length of an SIR/SDR command. + */ +int ispvm_data_size(struct ispvm_desc *d) +{ + int i, j, val; + + i = j = 0; + while ((val = ispvm_get(d)) != -1 && (val & 0x80)) { + j |= (val & 0x7F) << i; + i += 7; + } + if (val == -1) + return -1; + j |= (val & 0x7F) << i; + return j; +} + +/* Processes the TDI/TDO/MASK/DMASK etc of an SIR/SDR command. */ +int ispvm_data_code(struct ispvm_desc *d) +{ + int ret, data; + int data_source = 0; /* source file by default */ + + if (d->data_type & HEAP_IN) + data_source = 1; /* source from memory */ + + /* Clear the data type register. */ + d->data_type &= ~(MASK_DATA + TDI_DATA + TDO_DATA + DMASK_DATA); + + /* + * Iterate through SIR/SDR command and look + * for TDI, TDO, MASK, etc. + */ + while ((data = ispvm_get(d)) >= 0) { + + ret = ispvm_alloc(d, data, d->max_size); + if (ret != 0) + return VME_OUT_OF_MEMORY; + + switch (data) { + + case TDI: + /* + * Store the maximum size of the TDI buffer. + * Used to convert VME to HEX. + */ + if (d->data_size > d->TDI_size) + d->TDI_size = d->data_size; + + /* + * Updated data type register to indicate that TDI data + * is currently being used. Process the data in the VME + * file into the TDI buffer. + */ + d->data_type |= TDI_DATA; + ret = ispvm_data(d, d->in_TDI_data); + if (ret != 0) + return VME_INVALID_FILE; + break; + + case XTDO: + /* + * Store the maximum size of the TDO buffer. + * Used to convert VME to HEX. + */ + if (d->data_size > d->TDO_size) + d->TDO_size = d->data_size; + + /* + * Updated data type register to indicate that TDO data + * is currently being used. + */ + d->data_type |= TDO_DATA; + break; + + case TDO: + /* + * Store the maximum size of the TDO buffer. + * Used to convert VME to HEX. + */ + if (d->data_size > d->TDO_size) + d->TDO_size = d->data_size; + + /* + * Updated data type register to indicate that TDO data + * is currently being used. Process the data in the VME + * file into the TDO buffer. + */ + d->data_type |= TDO_DATA; + ret = ispvm_data(d, d->out_TDO_data); + if (ret != 0) + return VME_INVALID_FILE; + break; + + case MASK: + /* + * Store the maximum size of the MASK buffer. + * Used to convert VME to HEX. + */ + if (d->data_size > d->MASK_size) + d->MASK_size = d->data_size; + + /* + * Updated data type register to indicate that MASK data + * is currently being used. Process the data in the VME + * file into the TDO buffer. + */ + d->data_type |= MASK_DATA; + ret = ispvm_data(d, d->out_MASK_data); + if (ret != 0) + return VME_INVALID_FILE; + break; + + case DMASK: + /* + * Store the maximum size of the DMASK buffer. + * Used to convert VME to HEX. + */ + if (d->data_size > d->DMASK_size) + d->DMASK_size = d->data_size; + + /* + * Updated data type register to indicate that DMASK + * data is currently being used. Process the data in + * the VME file into the TDO buffer. + */ + + d->data_type |= DMASK_DATA; + ret = ispvm_data(d, d->out_DMASK_data); + if (ret != 0) + return VME_INVALID_FILE; + break; + + case CONTINUE: + return 0; + + /* Encountered invalid opcode. */ + default: + return VME_INVALID_FILE; + } + + if (data == TDI) { + /* + * Left bit shift. Used when performing + * algorithm looping. + */ + if (d->flow_control & SHIFTLEFT) { + ispvm_bit_shift(d, SHL, d->shift_value); + d->flow_control &= ~SHIFTLEFT; + } + + /* + * Right bit shift. Used when performing + * algorithm looping. + */ + if (d->flow_control & SHIFTRIGHT) { + ispvm_bit_shift(d, SHR, d->shift_value); + d->flow_control &= ~SHIFTRIGHT; + } + } + + if (data_source) + d->data_type |= HEAP_IN; /* restore data from memory */ + } + + if (data_source) /* fetch data from heap memory upon return */ + d->data_type |= HEAP_IN; + + if (data < 0) + return VME_INVALID_FILE; /* invalid opcode */ + + return 0; +} + +/* + * 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 d->data_size + * The number of times the block repeat itself + * is found by d->data_size/(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. + */ + +int ispvm_data(struct ispvm_desc *d, u8 *ptr) +{ + int i, j, k, l, size, gotdata, FFcount, compress, data; + u8 compr_char, val; + int compression = 0; + + gotdata = 0; + FFcount = 0; + compress = 0; + data = 0; + compr_char = 0xff; + + /*convert number in bits to bytes */ + if (d->data_size % 8 > 0) + size = d->data_size / 8 + 1; + else + size = d->data_size / 8; + + /* + * If there is compression, then check if compress by + * key of 0x00 or 0xFF + * or by other keys or by nibble blocks + */ + if (d->data_type & COMPRESS) { + compression = 1; + + compress = ispvm_get(d); + if (compress == -1) + return VME_INVALID_FILE; + + if (compress == VAR && (d->data_type & HEAP_IN)) { + gotdata = 1; + d->data_type &= ~HEAP_IN; + compress = ispvm_get(d); + if (compress == -1) + return VME_INVALID_FILE; + } + + switch (compress) { + + /* No compression */ + case 0x00: + compression = 0; + break; + + /* Compress by byte 0x00 */ + case 0x01: + compr_char = 0x00; + break; + + /* Compress by byte 0xFF */ + case 0x02: + compr_char = 0xFF; + break; + + /* Huffman encoding */ + case 0xFF: + j = ispvm_get(d); + if (j == -1) + return VME_INVALID_FILE; + + compr_char = j; + + i = 8; + for (l = 0; l < size; l++) { + ptr[l] = 0x00; + if (i > 7) { + data = ispvm_get(d); + if (data == -1) + return VME_INVALID_FILE; + i = 0; + } + if ((data << i++) & 0x80) { + k = 8; + } else { + ptr[l] = compr_char; + k = 0; + } + + for (j = 0; j < k; j++) { + if (i > 7) { + data = ispvm_get(d); + if (data == -1) + return VME_INVALID_FILE; + i = 0; + } + ptr[l] |= ((data << i++) & 0x80) >> j; + } + } + size = 0; + break; + + default: + for (l = 0; l < size; l++) + ptr[l] = 0x00; + + for (l = 0; l < compress; l++) { + if ((l % 2) == 0) { + data = ispvm_get(d); + if (data == -1) + return VME_INVALID_FILE; + } + for (i = 0; i < size * 2 / compress; i++) { + j = l + i * compress; + /* clear the nibble to zero first */ + if (j % 2) { + if (l % 2) + val = data & 0x0F; + else + val = data >> 4; + } else { + if (l % 2) + val = data << 4; + else + val = data & 0xF0; + } + + ptr[j / 2] |= val; + } + } + size = 0; + break; + } + } + + FFcount = 0; + + /* Decompress by byte 0x00 or 0xFF */ + for (l = 0; l < size; l++) { + if (FFcount <= 0) { + data = ispvm_get(d); + if (data == -1) + return VME_INVALID_FILE; + + if (data == VAR && (d->data_type & HEAP_IN) && + !gotdata && !(d->data_type & COMPRESS)) { + gotdata = 1; + d->data_type &= ~HEAP_IN; + data = ispvm_get(d); + if (data == -1) + return VME_INVALID_FILE; + } + ptr[l] = data & 0xff; + + /* decompression is on? set num. of 0xff/0x00 bytes */ + if (compression && data == compr_char) { + FFcount = ispvm_data_size(d); + if (FFcount == -1) + return VME_INVALID_FILE; + } + } else { + FFcount--; /* Use up the 0xFF chain first */ + ptr[l] = compr_char & 0xff; + } + } + + if (gotdata) { + d->data_type |= HEAP_IN; + gotdata = 0; + } + + return 0; +} + +/* Processes the SDR/XSDR/SIR commands. */ +int ispvm_shift(struct ispvm_desc *d, int code) +{ + int i, j; + int ret; + + ret = 0; + j = ispvm_data_size(d); + if (j == -1) + return VME_INVALID_FILE; + + d->data_size = j; + + /* clear the flags first */ + d->data_type &= ~(SIR_DATA + EXPRESS + SDR_DATA); + + switch (code) { + + case SIR: + d->data_type |= SIR_DATA; + /* + * 1/15/04 If performing cascading, then go + * directly to SHIFTIR. + * Else, go to IRPAUSE before going to SHIFTIR + */ + if (d->flow_control & CASCADE) { + ispvm_state_machine(d, SHIFTIR); + break; + } + ispvm_state_machine(d, IRPAUSE); + ispvm_state_machine(d, SHIFTIR); + if (d->head_IR > 0) { + ispvm_bypass(d, HIR, d->head_IR); + ispvm_clock(d); + } + break; + + case XSDR: + /* mark simultaneous in and out */ + d->data_type |= EXPRESS; + /* fall-through */ + + case SDR: + d->data_type |= 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 (d->current_jtag_state == SHIFTDR) + break; + + /* + * 1/15/04 If performing cascading, then go directly + * to SHIFTDR. Else, go to DRPAUSE before going to SHIFTDR + */ + if (d->flow_control & CASCADE) { + if (d->current_jtag_state == DRPAUSE) { + ispvm_state_machine(d, SHIFTDR); + /* + * 1/15/04 If cascade flag has been set 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 (d->head_DR > 0) { + ispvm_bypass(d, HDR, d->head_DR); + ispvm_clock(d); + } + } else + ispvm_state_machine(d, SHIFTDR); + } else { + ispvm_state_machine(d, DRPAUSE); + ispvm_state_machine(d, SHIFTDR); + if (d->head_DR > 0) { + ispvm_bypass(d, HDR, d->head_DR); + ispvm_clock(d); + } + } + break; + + default: + return VME_INVALID_FILE; + } + + ret = ispvm_data_code(d); + if (ret != 0) + return VME_INVALID_FILE; + + if (d->data_type & DMASK_DATA) { + ret = ispvm_read_and_save(d, d->data_size); + if (!ret) { + if (d->tail_DR > 0) { + ispvm_clock(d); + ispvm_bypass(d, TDR, d->tail_DR); + } + ispvm_state_machine(d, DRPAUSE); + ispvm_state_machine(d, SHIFTDR); + if (d->head_DR > 0) { + ispvm_bypass(d, HDR, d->head_DR); + ispvm_clock(d); + } + for (i = 0; i < d->data_size / 8 + 1; i++) + d->in_TDI_data[i] = d->out_TDO_data[i]; + d->data_type &= ~(TDO_DATA + DMASK_DATA); + ret = ispvm_send(d, d->data_size); + } + } else if (d->data_type & TDO_DATA) { + ret = ispvm_read(d, d->data_size); + if (ret == -1 && d->vendor == XILINX) { + for (j = 0; j < 30; j++) { + ret = ispvm_read(d, d->data_size); + if (!ret) + break; + + /* Always DRPAUSE */ + ispvm_state_machine(d, DRPAUSE); + + /* Bypass other devices when appropriate */ + ispvm_bypass(d, TDR, d->tail_DR); + ispvm_state_machine(d, d->end_DR); + ispvm_state_machine(d, IDLE); + udelay(1000); + } + } + } else + ret = ispvm_send(d, d->data_size); /*TDI only */ + + /*transfer the input data to the output buffer for the next verify */ + if ((d->data_type & EXPRESS) || + (code == SDR && d->out_TDO_data != NULL)) + for (i = 0; i < d->data_size / 8 + 1; i++) + d->out_TDO_data[i] = d->in_TDI_data[i]; + + switch (code) { + + case SIR: + /* 1/15/04 If not performing cascading, then shift ENDIR */ + if ((d->flow_control & CASCADE)) + break; + + if (d->tail_IR > 0) { + ispvm_clock(d); + ispvm_bypass(d, TIR, d->tail_IR); + } + ispvm_state_machine(d, d->end_IR); + break; + + case XSDR: + case SDR: + /* 1/15/04 If not performing cascading, then shift ENDDR */ + if ((d->flow_control & CASCADE)) + break; + + if (d->tail_DR > 0) { + ispvm_clock(d); + ispvm_bypass(d, TDR, d->tail_DR); + } + ispvm_state_machine(d, d->end_DR); + break; + + default: + break; + } + + return ret; +} + +/* 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. + */ + +int ispvm_amble(struct ispvm_desc *d, int code) +{ + int j, ret; + int compress = 0; + + j = ispvm_data_size(d); + if (j == -1) + return VME_INVALID_FILE; + + d->data_size = j; + + if (d->data_size) { + /* + * 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. + */ + j = ispvm_get(d); + if (j == -1) + return VME_INVALID_FILE; + + if (d->data_type & COMPRESS) { + d->data_type &= ~(COMPRESS); + compress = 1; + } + } + + switch (code) { + case HIR: + /* + * Store the maximum size of the HIR buffer. + * Used to convert VME to HEX. + */ + if (d->data_size > d->HIR_size) + d->HIR_size = d->data_size; + + /* Assign the HIR value and allocate memory. */ + d->head_IR = d->data_size; + if (d->head_IR) { + ret = ispvm_alloc(d, HIR, d->head_IR); + if (ret != 0) + return VME_OUT_OF_MEMORY; + ret = ispvm_data(d, d->HIR_data); + if (ret != 0) + return VME_INVALID_FILE; + + } + break; + + case TIR: + /* + * Store the maximum size of the TIR buffer. + * Used to convert VME to HEX. + */ + if (d->data_size > d->TIR_size) + d->TIR_size = d->data_size; + + /* Assign the TIR value and allocate memory. */ + d->tail_IR = d->data_size; + if (d->tail_IR) { + ret = ispvm_alloc(d, TIR, d->tail_IR); + if (ret != 0) + return VME_OUT_OF_MEMORY; + ret = ispvm_data(d, d->TIR_data); + if (ret != 0) + return VME_INVALID_FILE; + } + break; + + case HDR: + /* + * Store the maximum size of the HDR buffer. + * Used to convert VME to HEX. + */ + if (d->data_size > d->HDR_size) + d->HDR_size = d->data_size; + + /* Assign the HDR value and allocate memory. */ + d->head_DR = d->data_size; + if (d->head_DR) { + ret = ispvm_alloc(d, HDR, d->head_DR); + if (ret != 0) + return VME_OUT_OF_MEMORY; + ret = ispvm_data(d, d->HDR_data); + if (ret != 0) + return VME_INVALID_FILE; + } + break; + + case TDR: + + /* + * Store the maximum size of the TDR buffer. + * Used to convert VME to HEX. + */ + if (d->data_size > d->TDR_size) + d->TDR_size = d->data_size; + + /* Assign the TDR value and allocate memory. */ + d->tail_DR = d->data_size; + if (d->tail_DR) { + ret = ispvm_alloc(d, TDR, d->tail_DR); + if (ret != 0) + return VME_OUT_OF_MEMORY; + ret = ispvm_data(d, d->TDR_data); + if (ret != 0) + return VME_INVALID_FILE; + } + break; + + default: + break; + } + + /* Re-enable compression if it was previously set. */ + if (compress) + d->data_type |= COMPRESS; + + if (d->data_size > 0 && ispvm_get(d) != CONTINUE) + return VME_INVALID_FILE; /* invalid opcode */ + + return 0; +} + +/* + * 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 d->flow_control register to indicate the repeat loop is in session + * and therefore fetch opcode from the memory instead of from the file. + */ +int ispvm_loop(struct ispvm_desc *d, int repeats) +{ + int i, j; + int ret = 0; + + d->shift_value = 0; + for (i = 0; i < d->heap_repeat_size; i++) { + j = ispvm_get(d); + if (j == -1) + return VME_INVALID_FILE; + d->heap_memory[i] = j; + } + + if (d->heap_memory[i - 1] != ENDLOOP) + return VME_INVALID_FILE; + + d->flow_control |= REPEATLOOP; + d->data_type |= HEAP_IN; + + for (i = 0; i < repeats; i++) { + d->heap_counter = 0; + ret = ispvm_code(d); + d->repeat_loops++; + if (ret < 0) + break; + } + + d->data_type &= ~HEAP_IN; + d->flow_control &= ~REPEATLOOP; + return ret; +} + +/* + * Shift the TDI stream left or right by the number of bits. The data in + * d->in_TDI_data is of the VME format, so the actual shifting is the reverse of + * IEEE 1532 or SVF format. + */ +int ispvm_bit_shift(struct ispvm_desc *d, int mode, u16 bits) +{ + u16 i, size, j; + + if (d->data_size % 8 > 0) + size = d->data_size / 8 + 1; + else + size = d->data_size / 8; + + switch (mode) { + + case SHR: + for (i = 0; i < size; i++) { + if (d->in_TDI_data[i] == 0) + continue; + j = bits; + while (j > 0) { + d->in_TDI_data[i] <<= 1; + if (d->in_TDI_data[i] == 0) { + i--; + d->in_TDI_data[i] = 1; + } + j--; + } + } + break; + + case SHL: + for (i = 0; i < size; i++) { + if (d->in_TDI_data[i] == 0) + continue; + j = bits; + while (j > 0) { + d->in_TDI_data[i] >>= 1; + if (d->in_TDI_data[i] == 0) { + i--; + d->in_TDI_data[i] = 8; + } + j--; + } + } + break; + + default: + return VME_INVALID_FILE; + } + + return 0; +} + +/* Displays the SVF comments. */ +int ispvm_comment(struct ispvm_desc *d, int size) +{ + int i, j; + + /* Print character to the terminal. */ + printf("VM-Comment: "); + for (i = 0; i < size; i++) { + j = ispvm_get(d); + if (j == -1) + return VME_INVALID_FILE; + printf("%c", j); + } + printf("\n"); + + return 0; +} + +/* Iterate the length of the header and discard it. */ +int ispvm_header(struct ispvm_desc *d, int size) +{ + int i, j; + + for (i = 0; i < size; i++) { + j = ispvm_get(d); + if (j == -1) + return VME_INVALID_FILE; + } + return 0; +} + +/* Process the intelligent programming loops. */ +int ispvm_lcount(struct ispvm_desc *d, int size) +{ + int i, j, k; + int ret = 0; + int repheap = 0; + + j = ispvm_data_size(d); + if (j == -1) + return VME_INVALID_FILE; + + d->intel_buffer_size = j; + + /* Allocate memory for intel buffer. */ + ret = ispvm_alloc(d, LHEAP, d->intel_buffer_size); + if (ret != 0) + return VME_OUT_OF_MEMORY; + + /* + * Store the maximum size of the intelligent buffer. + * Used to convert VME to HEX. + */ + if (d->intel_buffer_size > d->LCOUNT_size) + d->LCOUNT_size = d->intel_buffer_size; + + /* Copy intel data to the buffer */ + for (i = 0; i < d->intel_buffer_size; i++) { + k = ispvm_get(d); + if (k == -1) + return VME_INVALID_FILE; + d->intel_buffer[i] = k; + } + + /* + * Set the data type register to get data from the + * intelligent data buffer. + */ + d->data_type |= LHEAP_IN; + + /* + * If the HEAP_IN flag is set, temporarily unset the flag + * so data will be retrieved from the status buffer. + */ + if (d->data_type & HEAP_IN) { + d->data_type &= ~HEAP_IN; + repheap = 1; + } + + /* Iterate through the intelligent programming command. */ + for (i = 0; i < size; i++) { + d->intel_data_idx = 0; + + /* + * Make recursive call to process the intelligent + * programming commands. + */ + ret = ispvm_code(d); + if (ret >= 0) + break; /* success? */ + } + + /* + * If HEAP_IN flag was temporarily disabled, + * re-enable it before exiting. + */ + if (repheap) + d->data_type |= HEAP_IN; + + /* + * Set the data type register to not get data from + * the intelligent data buffer. + */ + d->data_type &= ~LHEAP_IN; + return ret; +} + +/* Applies a single pulse to TCK. */ +void ispvm_clock(struct ispvm_desc *d) +{ + int idle; + + idle = 1000 / d->frequency + !!(1000 % d->frequency); + + /* NOTE: we assume that at least one usec will pass + * until getting the port toggled + */ + idle--; + + lattice_ec_write_port(d->cookie, LATTICE_JTAG_TCK, 0x01); + if (idle > 0) + udelay(idle); + + lattice_ec_write_port(d->cookie, LATTICE_JTAG_TCK, 0x00); + if (idle > 0) + udelay(idle); +} + +/* + * 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 ispvm_bypass(struct ispvm_desc *d, int scan_type, u16 bits) +{ + int i, j, bit; + u8 val = 0; + u8 *pcSource = 0; + + if (bits <= 0) + return; + + switch (scan_type) { + case HIR: + pcSource = d->HIR_data; + break; + case TIR: + pcSource = d->TIR_data; + break; + case HDR: + pcSource = d->HDR_data; + break; + case TDR: + pcSource = d->TDR_data; + break; + default: + break; + } + + j = 0; + for (i = 0; i < bits - 1; i++) { + /* Scan instruction or bypass register */ + if (i % 8 == 0) + val = pcSource[j++]; + bit = !!((val << (i % 8)) & 0x80); + lattice_ec_write_port(d->cookie, LATTICE_JTAG_TDI, bit); + ispvm_clock(d); + } + + if ((i % 8) == 0) + val = pcSource[j++]; + + bit = !!((val << (i % 8)) & 0x80); + lattice_ec_write_port(d->cookie, LATTICE_JTAG_TDI, bit); +} + +/* + * 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 ispvm_state_machine(struct ispvm_desc *d, int next) +{ + /* + * JTAG state machine transition trajectory table + */ + static const struct { + u8 cur_state; /* From this state */ + u8 next_state; /* Step to this state */ + u8 pattern; /* Tragectory of TMS */ + u8 pulses; /* Number of steps */ + } jtag_transitions[24] = { + /* Transitions from RESET */ + { RESET, RESET, 0xFC, 6 }, + { RESET, IDLE, 0x00, 1 }, + { RESET, DRPAUSE, 0x50, 5 }, + { RESET, IRPAUSE, 0x68, 6 }, + + /* Transitions from IDLE */ + { IDLE, RESET, 0xE0, 3 }, + { IDLE, DRPAUSE, 0xA0, 4 }, + { IDLE, IRPAUSE, 0xD0, 5 }, + + /* Transitions from DRPAUSE */ + { DRPAUSE, RESET, 0xF8, 5 }, + { DRPAUSE, IDLE, 0xC0, 3 }, + { DRPAUSE, IRPAUSE, 0xF4, 7 }, + + /* Transitions from IRPAUSE */ + { IRPAUSE, RESET, 0xF8, 5 }, + { IRPAUSE, IDLE, 0xC0, 3 }, + { IRPAUSE, DRPAUSE, 0xE8, 6 }, + + /* Extra transitions using SHIFTDR */ + { DRPAUSE, SHIFTDR, 0x80, 2 }, + { IRPAUSE, SHIFTDR, 0xE0, 5 }, + { SHIFTDR, DRPAUSE, 0x80, 2 }, + { SHIFTDR, IDLE, 0xC0, 3 }, + + /* Extra transitions using SHIFTIR */ + { IRPAUSE, SHIFTIR, 0x80, 2 }, + { SHIFTIR, IRPAUSE, 0x80, 2 }, + { SHIFTIR, IDLE, 0xC0, 3 }, + + /* 11/15/05 Nguyen changed to support DRCAPTURE */ + { DRPAUSE, DRCAPTURE, 0xE0, 4 }, + { DRCAPTURE, DRPAUSE, 0x80, 2 }, + { IDLE, DRCAPTURE, 0x80, 2 }, + { IRPAUSE, DRCAPTURE, 0xE0, 4} + }; + + int i, j, maxstate; + + /* already there? */ + if (d->current_jtag_state == next && next != RESET) + return; + + maxstate = sizeof(jtag_transitions) / sizeof(jtag_transitions[0]); + for (j = 0; j < maxstate; j++) + if (d->current_jtag_state == jtag_transitions[j].cur_state && + next == jtag_transitions[j].next_state) + break; + + d->current_jtag_state = next; + for (i = 0; i < jtag_transitions[j].pulses; i++) { + lattice_ec_write_port(d->cookie, LATTICE_JTAG_TMS, + (jtag_transitions[j].pattern << i) & 0x80); + ispvm_clock(d); + } + + lattice_ec_write_port(d->cookie, LATTICE_JTAG_TDI, 0); + lattice_ec_write_port(d->cookie, LATTICE_JTAG_TMS, 0); +} + +/* + * Send the TDI data stream to devices. The data stream can be + * instructions or data. + */ +int ispvm_send(struct ispvm_desc *d, u16 size) +{ + int i, j, bit; + u8 val = 0; + + for (i = 0, j = 0; i < size - 1; i++) { + if ((i % 8) == 0) + val = d->in_TDI_data[j++]; + bit = !!((val << (i % 8)) & 0x80); + lattice_ec_write_port(d->cookie, LATTICE_JTAG_TDI, bit); + ispvm_clock(d); + } + + /* Take care of the last bit */ + if ((i % 8) == 0) + val = d->in_TDI_data[j]; + + bit = !!((val << (i % 8)) & 0x80); + lattice_ec_write_port(d->cookie, LATTICE_JTAG_TDI, bit); + + /* 1/15/04 Clock in last bit for the first n-1 cascaded frames */ + if (d->flow_control & CASCADE) + ispvm_clock(d); + + return 0; +} + +/* Read the data stream from devices and verify. */ +int ispvm_read(struct ispvm_desc *d, u16 size) +{ + int i, j, k, bit, lasti, errors, dflg; + u8 data, mask, indata, display; + + errors = 0; + lasti = size - 1; + j = 0; + k = 0; + dflg = 1; + data = 0; + mask = 0; + indata = 0; + display = 0; + + /* + * 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 VME_DEBUG is defined, always + * display data. + */ + for (i = 0; i < (size + 7) / 8; i++) { + if (d->data_type & MASK_DATA) { + if (d->out_MASK_data[i] != 0x00) { + dflg = 0; + break; + } + } else { + dflg = 0x00; + break; + } + } + + /* Begin shifting data in and out of the device. */ + for (i = 0; i < size; i++) { + if (k == 0) { + /* Grab byte from TDO buffer. */ + if (d->data_type & TDO_DATA) + data = d->out_TDO_data[j]; + + /* Grab byte from MASK buffer. */ + if (d->data_type & MASK_DATA) + mask = d->out_MASK_data[j]; + else + mask = 0xFF; + + /* Grab byte from TDI buffer. */ + if (d->data_type & TDI_DATA) + indata = d->in_TDI_data[j]; + + j++; + } + + bit = lattice_ec_read_port(d->cookie); + + if (dflg) { + display <<= 1; + display |= bit; + } + + /* Check if data read from port matches with expected TDO. */ + if (d->data_type & TDO_DATA) { + if ((mask << k) & 0x80) { + if (bit != !!((data << k) & 0x80)) { + errors++; + dflg = 1; + } + } + } + + /* Write TDI data to the port. */ + lattice_ec_write_port(d->cookie, LATTICE_JTAG_TDI, + (((indata << k) & 0x80) ? 0x01 : 0x00)); + + /* Clock data out from the data shift register. */ + if (i < lasti || (d->flow_control & CASCADE)) + ispvm_clock(d); + + k++; + if (k >= 8) { + + if (dflg) { + /* + * 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. + */ + d->out_TDO_data[j - 1] = display; + display = 0; + } + k = 0; + } + } + + if (dflg) { + /* Display data read from the device. */ + printf("\nDisplay Data: 0x"); + + for (i = ((size + 7) / 8); i > 0; i--) { + mask = d->out_TDO_data[i - 1]; + data = 0; + + /* Flip mask and store it in data. */ + for (j = 0; j < 8; j++) { + data <<= 1; + if (mask & 0x01) + data |= 0x01; + mask >>= 1; + } + + printf(" %02X", ((unsigned int)data) & 0xff); + } + printf("\n\n"); + } + + if (errors > 0) { + if (d->flow_control & VERIFYUES) { + printf("USERCODE verification failed." + " Continue programming......\n\n"); + d->flow_control &= ~VERIFYUES; + return 0; + } + + return VME_VERIFICATION_FAILURE; + + } + + if (d->flow_control & VERIFYUES) { + printf("USERCODE verification passed." + " Programming aborted. \n\n"); + d->flow_control &= ~VERIFYUES; + return 1; + } + return 0; +} + +/* Support dynamic I/O. */ +int ispvm_read_and_save(struct ispvm_desc *d, u16 size) +{ + int i, j, k, l, m, lasti, bit, outbit; + u8 data, dmask, indata, outdata; + + lasti = size - 1; + j = 0; + k = 0; + l = 0; + m = 0; + data = 0; + dmask = 0; + indata = 0; + + /* Iterate through the data bits. */ + for (i = 0; i < size; i++) { + if (k == 0) { + /* Grab byte from DMASK buffer. */ + if (d->data_type & DMASK_DATA) + dmask = d->out_DMASK_data[j]; + else + dmask = 0x00; + + /* Grab byte from TDI buffer. */ + if (d->data_type & TDI_DATA) + indata = d->in_TDI_data[j]; + + j++; + } + + bit = lattice_ec_read_port(d->cookie); + data = !!((indata << k) & 0x80); + + /* Initialize the byte to be zero. */ + if (l % 8 == 0) + d->out_TDO_data[l / 8] = 0x00; + + /* + * Use TDI, DMASK, and device TDO to create new TDI (actually + * stored in d->out_TDO_data). + */ + if ((dmask << k) & 0x80) { + + if (d->LVDS_list) { + for (m = 0; m < d->LVDS_pair_count; m++) { + if (d->LVDS_list[m].negative_idx + == i) { + d->LVDS_list[m].update = 0x01; + break; + } + } + } + + /* DMASK bit is 1, use TDI. */ + outbit = data & 1; + } else + outbit = bit; + + /* DMASK bit is 0, use device TDO. */ + outdata = outbit << (7 - l % 8); + d->out_TDO_data[l / 8] |= outdata; + + /* Shift in TDI in order to get TDO out. */ + l++; + lattice_ec_write_port(d->cookie, LATTICE_JTAG_TDI, data); + if (i < lasti) + ispvm_clock(d); + + k++; + if (k >= 8) + k = 0; + } + + /* + * If d->LVDS_list exists and pairs need updating, then update + * the negative-pair to receive the flipped positive-pair value. + */ + if (!d->LVDS_list) + return 0; + + for (m = 0; m < d->LVDS_pair_count; m++) + if (d->LVDS_list[m].update) + break; + + /* update not found? */ + if (m >= d->LVDS_pair_count) + return 0; + + /* Read the positive value and flip it. */ + outdata = d->out_TDO_data[d->LVDS_list[m].positive_idx / 8]; + data = !((outdata << (d->LVDS_list[m].positive_idx % 8)) & 0x80); + + /* Get the byte that needs modification. */ + indata = d->out_TDO_data[d->LVDS_list[m].negative_idx / 8]; + + if (data) { + /* Copy over the current byte and set the negative bit to 1 */ + data = 0x00; + for (i = 7; i >= 0; i--) { + data <<= 1; + if (7 - (d->LVDS_list[m].negative_idx % 8) == i) + /* Set negative bit to 1. */ + data |= 0x01; + else if (indata & 0x80) + data |= 0x01; + + indata <<= 1; + } + + + } else { + /* Copy over the current byte and set the negative bit to 0. */ + data = 0x00; + for (i = 7; i >= 0; i--) { + data <<= 1; + if (7 - (d->LVDS_list[m].negative_idx % 8) == i) + /* Set negative bit to 0. */ + data |= 0x00; + else if (indata & 0x80) + data |= 0x01; + + indata <<= 1; + } + } + + /* Store the modified byte. */ + d->out_TDO_data[d->LVDS_list[m].negative_idx / 8] = data; + + return 0; +} + +int ispvm_process_lvds(struct ispvm_desc *d, int count) +{ + int i, j; + /* LVDSPair * pLVDSPair = NULL; */ + + /* Allocate memory to hold LVDS pairs. */ + j = ispvm_alloc(d, LVDS, count); + if (j != 0) + return VME_OUT_OF_MEMORY; + d->LVDS_pair_count = count; + + /* Iterate through each given LVDS pair. */ + for (i = 0; i < count; i++) { + /* + * Assign the positive and negative indices + * of the LVDS pair. + */ + j = ispvm_data_size(d); + if (j == -1) + return VME_INVALID_FILE; + + d->LVDS_list[i].positive_idx = j; + + j = ispvm_data_size(d); + if (j == -1) + return VME_INVALID_FILE; + d->LVDS_list[i].negative_idx = j; + } + + return 0; +} + +#endif

Provide support for RedBoot's FIS & config variables.
For PPC provide also a way to boot a redboot compiled Linux kernel. The bd_t is different in that case.
--- Signed-off-by: Pantelis Antoniou pantelis@embeddedalley.com ---
README | 70 ++++ common/Makefile | 1 common/cmd_bootm.c | 20 + common/redboot.c | 978 ++++++++++++++++++++++++++++++++++++++++++++++++++++ include/redboot.h | 98 +++++ 5 files changed, 1166 insertions(+), 1 deletions(-)
diff --git a/README b/README index e28f935..c3055c0 100644 --- a/README +++ b/README @@ -2324,6 +2324,76 @@ Low Level (hardware related) configuration options: some other boot loader or by a debugger which performs these intializations itself.
+- CONFIG_REDBOOT + Add support for read-only parsing of the FIS & config areas. + For PPC also add an option to boot a kernel compiled for RedBoot. + + The redboot command is also enabled conditional on CFG_CMD_FLASH. + + - Select a different FIS + > redboot fis select ([bank] [sector] | reset) + + - Display FIS + > redboot fis list + + - Set an environment variable from a member variable of a FIS entry + + > redboot fis setenv var type name + + Where type: flash_base, mem_base, size, entry_point, data_length. + + An example given a FIS entry of + + Name FLASH addr Mem addr Datalen Length Entry point + Linux 0xF0470000 0x00100000 0x000FA000 0x00100000 0x00100000 + + > redboot fis setenv linux_base flash_base Linux + + Would set the environment variable linux_base to 0xf0470000 + + - Print either all the RedBoot config variables or a specific one + + > redboot config printenv [config-var] [member] + + member is one of value, type, enable-sense, enable-key with value + being the default one. + + - Set an environment variable from a RedBoot config variable + + > redboot config setenv var config-var [member] + + For example when given a config variable of + + tsec1_esa=00:08:e5:11:32:33 + type=esa enable-sense=true + + > redboot config setenv ethaddr tsec1_esa + + would set the ethaddr environment variable to 00:08:e5:11:32:33 + + - Boot a RedBoot kernel [PPC specific] + + > redboot exec address + + The PPC bd_t differs for kernels compiled for redboot; this command + lets you boot such a kernel. + + RedBoot config defaults (can be overriden on board config): + + - Sector containing the FIS area (negative values for counting from the end) + CONFIG_REDBOOT_FIS_DIRECTORY_BLOCK -1 + + - FIS directory entry size + CONFIG_REDBOOT_DIRECTORY_ENTRY_SIZE 0x100 + + - Size of the config area + CONFIG_REDBOOT_FLASH_CONFIG_SIZE 4096 + + - Size of the script config variables + CONFIG_REDBOOT_FLASH_SCRIPT_SIZE 256 + + - Size of the string config variables + CONFIG_REDBOOT_FLASH_STRING_SIZE 128
Building the Software: ====================== diff --git a/common/Makefile b/common/Makefile index 79d11a5..13dc6ae 100644 --- a/common/Makefile +++ b/common/Makefile @@ -51,6 +51,7 @@ COBJS = main.o ACEX1K.o altera.o bedbug.o circbuf.o \ lattice.o lattice_ec.o lattice_ivm_core.o lattice_ivm_supp.o \ lcd.o lists.o lynxkdi.o \ memsize.o miiphybb.o miiphyutil.o \ + redboot.o \ s_record.o serial.o soft_i2c.o soft_spi.o spartan2.o spartan3.o \ usb.o usb_kbd.o usb_storage.o \ virtex2.o xilinx.o crc16.o xyzModem.o cmd_mac.o diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c index 7aae8a6..578d05b 100644 --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -146,6 +146,12 @@ extern void lynxkdi_boot( image_header_t * ); #define CFG_BOOTM_LEN 0x800000 /* use 8MByte as default max gunzip size */ #endif
+#ifdef CONFIG_REDBOOT_BD_T_SIZE +extern void board_redboot_bd_t_adapt(void *kbd, + ulong cmd_start, ulong cmd_end, + ulong initrd_start, ulong initrd_end); +#endif + image_header_t header;
ulong load_addr = CFG_LOAD_ADDR; /* Default Load Address */ @@ -533,6 +539,11 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, char *of_flat_tree = NULL; ulong of_data = 0; #endif +#ifdef CONFIG_REDBOOT_BD_T_SIZE +#define BD_T_SIZE max(sizeof(bd_t), CONFIG_REDBOOT_BD_T_SIZE) +#else +#define BD_T_SIZE sizeof(bd_t) +#endif
if ((s = getenv ("initrd_high")) != NULL) { /* a value of "no" or a similar string will act like 0, @@ -575,7 +586,7 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, debug ("=> set upper limit to 0x%08lX\n", sp);
cmdline = (char *)((sp - CFG_BARGSIZE) & ~0xF); - kbd = (bd_t *)(((ulong)cmdline - sizeof(bd_t)) & ~0xF); + kbd = (bd_t *)(((ulong)cmdline - BD_T_SIZE) & ~0xF);
if ((s = getenv("bootargs")) == NULL) s = ""; @@ -904,6 +915,13 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, initrd_end = 0; }
+ /* redboot bd_t modify */ +#ifdef CONFIG_REDBOOT_BD_T_SIZE + if ((s = getenv ("redboot_bd_t")) != NULL) + board_redboot_bd_t_adapt(kbd, cmd_start, cmd_end, + initrd_start, initrd_end); +#endif + debug ("## Transferring control to Linux (at address %08lx) ...\n", (ulong)kernel);
diff --git a/common/redboot.c b/common/redboot.c new file mode 100644 index 0000000..22c4373 --- /dev/null +++ b/common/redboot.c @@ -0,0 +1,978 @@ +/* + * (C) Copyright 2006 - Embedded Alley Solutions Inc. + * by Pantelis Antoniou, pantelis@embeddedalley.com + * + * Based on Linux & RedBoot code fragments + * by David Woodhouse, dwmw2@infradead.org + * by Mark Sattler, msalter@redhat.com + * by Gary Thomas, gthomas@redhat.com + * + * RedBoot flash images/configuration & kernel startup + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include <common.h> +#include <malloc.h> +#include <flash.h> +#include <command.h> + +#include <redboot.h> + +#ifdef CONFIG_SHOW_BOOT_PROGRESS +# include <status_led.h> +# define SHOW_BOOT_PROGRESS(arg) show_boot_progress(arg) +#else +# define SHOW_BOOT_PROGRESS(arg) +#endif + +#ifdef CFG_INIT_RAM_LOCK +#include <asm/cache.h> +#endif + +#if (CONFIG_COMMANDS & CFG_CMD_FLASH) && defined(CONFIG_REDBOOT) + +DECLARE_GLOBAL_DATA_PTR; + +extern void board_redboot_bd_t_adapt(void *kbd, + ulong cmd_start, ulong cmd_end, + ulong initrd_start, ulong initrd_end); + +extern flash_info_t flash_info[]; /* info for FLASH chips */ + +static inline int redboot_checksum(struct fis_image_desc *img) +{ + /* RedBoot doesn't actually write the desc_cksum field yet AFAICT */ + return 1; +} + +static int get_sector_size(flash_info_t *info, int sector) +{ + ulong s, e; + + if (info->flash_id == FLASH_UNKNOWN) + return 0; + + if ((unsigned int)sector >= info->sector_count) + return 0; + + s = info->start[sector]; + if (sector < info->sector_count - 1) + e = info->start[sector + 1]; + else + e = info->start[0] + info->size; + + return e - s; +} + +/* get the sector which corresponds to this address */ +static int get_sector(flash_info_t *info, void *ptr) +{ + int i; + ulong s, e; + + if (info->flash_id == FLASH_UNKNOWN) + return -1; + + if (info->start[0] > (ulong)ptr || + info->start[info->sector_count - 1] < (ulong)ptr) + return -1; + + for (i = 0; i < info->sector_count; i++) { + s = info->start[i]; + if (i < info->sector_count - 1) + e = info->start[i + 1]; + else + e = info->start[0] + info->size; + + if (s <= (ulong)ptr && e > (ulong)ptr) + return i; + } + + /* should not happen */ + return -1; +} + +static void *get_fis(flash_info_t *info, void *fis) +{ + int dir_block, sector; + + if (info->flash_id == FLASH_UNKNOWN) + return NULL; + + /* already given a fis address (verify it) */ + if (fis != NULL) { + if (info->start[0] > (ulong)fis || + info->start[info->sector_count - 1] < (ulong)fis) + return NULL; + return fis; + } + + /* go with defaults */ + dir_block = CONFIG_REDBOOT_FIS_DIRECTORY_BLOCK; + if (dir_block < 0) + sector = info->sector_count + dir_block; + else + sector = dir_block; + + if ((unsigned int)sector >= info->sector_count) + return NULL; + + return (void *)info->start[sector]; +} + +static int get_fis_slots(flash_info_t *info, void *fis, int *swapped) +{ + int i, sector, sector_size, slots; + struct fis_image_desc *ptr; + + *swapped = -1; + + fis = get_fis(info, fis); + if (fis == NULL) + return -1; + + sector = get_sector(info, fis); + sector_size = get_sector_size(info, sector); + + slots = sector_size / sizeof(struct fis_image_desc); + + /* first pass; detect swap status */ + for (i = 0, ptr = fis; i < slots; i++, ptr++) { + if (ptr->name[0] == 0xFF) + break; + + if (!memcmp(ptr->name, "FIS directory", 14)) + *swapped = swab32(ptr->size) == sector_size; + } + + if (*swapped == -1) + return -1; + + return i; +} + +void *redboot_fis_get(int bank, int dir_block, flash_info_t **infop) +{ + flash_info_t *info; + int block; + + if (bank < 1 || bank > CFG_MAX_FLASH_BANKS) { + printf("Only FLASH Banks # 1 ... # %d supported\n", + CFG_MAX_FLASH_BANKS); + return NULL; + } + info = &flash_info[bank-1]; + if (info->flash_id == FLASH_UNKNOWN) { + printf("FLASH Bank #%d, not present\n", bank); + return NULL; + } + + if (dir_block < 0) + block = info->sector_count + dir_block; + else + block = dir_block; + + if ((unsigned int)block >= info->sector_count) { + printf("FLASH dir_block %d out of range in Bank #%d\n", + dir_block, bank); + return NULL; + } + + if (infop) + *infop = info; + return (void *)info->start[block]; +} + + +int redboot_fis_entry_lookup(flash_info_t *info, void *fis, + struct fis_image_desc *fis_buf, const char *name) +{ + int i, slots, swapped, name_len; + struct fis_image_desc *ptr; + + fis = get_fis(info, fis); + if (fis == NULL) + return -1; + + slots = get_fis_slots(info, fis, &swapped); + if (slots == -1) { + printf("fis list: FIS not found\n"); + return -1; + } + + name_len = strlen(name); + + /* now do the proper read (with swapping if needed */ + for (i = 0, ptr = fis; i < slots; i++, ptr++) { + + if (ptr->name[0] == 0xFF) + break; + + /* copy to buffer */ + memcpy(fis_buf, ptr, sizeof(struct fis_image_desc)); + if (swapped) { + /* The unsigned long fields were written with the + * wrong byte sex, name and pad have no byte sex. + */ + swab32s(&fis_buf->flash_base); + swab32s(&fis_buf->mem_base); + swab32s(&fis_buf->size); + swab32s(&fis_buf->entry_point); + swab32s(&fis_buf->data_length); + swab32s(&fis_buf->desc_cksum); + swab32s(&fis_buf->file_cksum); + } + + /* found */ + if (strcmp(name, fis_buf->name) == 0) + return 0; + } + + return -1; +} + +int redboot_fis_list(flash_info_t *info, void *fis) +{ + int i, slots, swapped, found; + static struct fis_image_desc fis_buf; /* static; save stack space */ + struct fis_image_desc *ptr; + u32 last, lowest, flash_base; + + fis = get_fis(info, fis); + if (fis == NULL) { + printf("fis list: could not get FIS\n"); + return -1; + } + + slots = get_fis_slots(info, fis, &swapped); + if (slots == -1) { + printf("fis list: FIS not found\n"); + return -1; + } + + printf("%-16s %-10s %-10s %-10s %-10s %-s\n", + "Name", "FLASH addr", "Mem addr", + "Datalen", "Length", "Entry point" ); + + last = 0; + do { + found = -1; + lowest = 0xFFFFFFFF; + + /* now do the proper read (with swapping if needed */ + for (i = 0, ptr = fis; i < slots; i++, ptr++) { + + if (ptr->name[0] == 0xFF) + break; + + if (swapped) + flash_base = swab32(ptr->flash_base); + else + flash_base = ptr->flash_base; + + if (flash_base > last && flash_base < lowest) { + lowest = flash_base; + found = i; + } + } + + if (found >= 0) { + ptr = fis; + memcpy(&fis_buf, &ptr[found], + sizeof(struct fis_image_desc)); + if (swapped) { + /* The unsigned long fields were written + * with the wrong byte sex, name and pad + * have no byte sex. + */ + swab32s(&fis_buf.flash_base); + swab32s(&fis_buf.mem_base); + swab32s(&fis_buf.size); + swab32s(&fis_buf.entry_point); + swab32s(&fis_buf.data_length); + swab32s(&fis_buf.desc_cksum); + swab32s(&fis_buf.file_cksum); + } + + printf("%-16s 0x%08lX 0x%08lX 0x%08lX " + "0x%08lX 0x%08lX\n", + fis_buf.name, + (unsigned long)fis_buf.flash_base, + fis_buf.mem_base, + fis_buf.data_length, fis_buf.size, + (unsigned long)fis_buf.entry_point); + } + last = lowest; + } while (found >= 0); + + return 0; +} + +int redboot_fis_setenv(flash_info_t *info, void *fis, const char *name, + const char *what, char *var) +{ + static struct fis_image_desc fis_buf; /* static; save stack space */ + static char varbuf[12]; + int i; + + i = redboot_fis_entry_lookup(info, fis, &fis_buf, name); + if (i != 0) + return -1; + + if (strcmp(what, "flash_base") == 0) + sprintf(varbuf, "0x%x", fis_buf.flash_base); + else if (strcmp(what, "mem_base") == 0) + sprintf(varbuf, "0x%x", fis_buf.mem_base); + else if (strcmp(what, "size") == 0) + sprintf(varbuf, "0x%x", fis_buf.size); + else if (strcmp(what, "entry_point") == 0) + sprintf(varbuf, "0x%x", fis_buf.entry_point); + else if (strcmp(what, "data_length") == 0) + sprintf(varbuf, "0x%x", fis_buf.data_length); + else + return -1; + + setenv(var, varbuf); + + return 0; +} + +/*************************************************************************/ + +#define CONFIG_KEY1 0x0badface +#define CONFIG_KEY2 0xdeaddead + +/* + * Layout of config data + * Each data item is variable length, with the name, type and dependencies + * encoded into the object. + * offset contents + * 0 data type + * 1 length of name (N) + * 2 enable sense + * 3 length of enable key (M) + * 4 key name + * N+4 enable key + * M+N+4 data value + */ + +#define TYPE(dp) ((dp)[0]) +#define KEYLEN(dp) ((dp)[1]) +#define ENABLE_SENSE(dp) ((dp)[2]) +#define ENABLE_KEYLEN(dp) ((dp)[3]) +#define KEY(dp) ((dp)+4) +#define ENABLE_KEY(dp) ((dp)+4+KEYLEN(dp)) +#define VALUE(dp) ((dp)+4+KEYLEN(dp)+ENABLE_KEYLEN(dp)) + +void *get_config(flash_info_t *info, void *fis, int *sizep, int *swappedp) +{ + static struct fis_image_desc fis_buf; /* static; save stack space */ + int i; + ulong base, size; + void *config; + u32 *ps, *pe; + + /* lookup the RedBoot config */ + i = redboot_fis_entry_lookup(info, fis, &fis_buf, "RedBoot config"); + if (i != 0) + return NULL; + + base = fis_buf.flash_base; + size = fis_buf.data_length; + + config = (void *)base; + + /* verify */ + ps = (u32 *)base; + if (ps[1] != CONFIG_KEY1 && ps[1] != swab32(CONFIG_KEY1)) + return NULL; + + if (ps[1] == CONFIG_KEY1) { + *swappedp = 0; + if (ps[0] != size) + return NULL; + pe = (u32 *)(base + ps[0]); + if (pe[-2] != CONFIG_KEY2) + return NULL; + } else { + *swappedp = 1; + if (swab32(ps[0]) != size) + return NULL; + pe = (u32 *)(base + swab32(ps[0])); + if (pe[-2] != swab32(CONFIG_KEY2)) + return NULL; + } + + *sizep = size; + return config; +} + +#define CONFIG_EMPTY 0 +#define CONFIG_BOOL 1 +#define CONFIG_INT 2 +#define CONFIG_STRING 3 +#define CONFIG_SCRIPT 4 +#define CONFIG_IP 5 +#define CONFIG_ESA 6 +#define CONFIG_NETPORT 7 + +static const int config_len_tab[] = { + [CONFIG_EMPTY] = 0, + [CONFIG_BOOL] = 4, + [CONFIG_INT] = 4, + [CONFIG_STRING] = CONFIG_REDBOOT_FLASH_STRING_SIZE, + [CONFIG_SCRIPT] = CONFIG_REDBOOT_FLASH_SCRIPT_SIZE, + [CONFIG_IP] = 4, + [CONFIG_ESA] = 8, + [CONFIG_NETPORT]= CONFIG_REDBOOT_FLASH_STRING_SIZE, +}; + +static const char *config_txt_tab[] = { + [CONFIG_EMPTY] = "", + [CONFIG_BOOL] = "bool", + [CONFIG_INT] = "int", + [CONFIG_STRING] = "string", + [CONFIG_SCRIPT] = "script", + [CONFIG_IP] = "ip", + [CONFIG_ESA] = "esa", + [CONFIG_NETPORT]= "netport", +}; + +static inline int config_length(int type) +{ + if ((unsigned int)type >= + sizeof(config_len_tab)/sizeof(config_len_tab[0])) + return -1; + return config_len_tab[type]; +} + +static const char *config_format_value(int type, const char *value, + char *small_buf, int swapped) +{ + int val; + unsigned int uval; + const char *fmt; + + switch (type) { + case CONFIG_BOOL: + val = *(int *)value; + if (swapped) + val = swab32(val); + fmt = val ? "true" : "false"; + break; + case CONFIG_INT: + val = *(int *)value; + if (swapped) + val = swab32(val); + sprintf(small_buf, "%d", val); + fmt = small_buf; + break; + case CONFIG_STRING: + fmt = value; + break; + case CONFIG_SCRIPT: + fmt = value; + break; + case CONFIG_IP: + uval = *(unsigned int *)value; + if (swapped) + uval = swab32(uval); + sprintf(small_buf, "%u.%u.%u.%u", + (uval >> 24) & 0xff, (uval >> 16) & 0xff, + (uval >> 8) & 0xff, uval & 0xff); + fmt = small_buf; + break; + case CONFIG_ESA: + sprintf(small_buf, "%02x:%02x:%02x:%02x:%02x:%02x", + value[0] & 0xff, value[1] & 0xff, + value[2] & 0xff, value[3] & 0xff, + value[4] & 0xff, value[5] & 0xff); + fmt = small_buf; + break; + case CONFIG_NETPORT: + fmt = value; + break; + + default: + fmt = ""; /* empty */ + break; + } + + return fmt; +} + +int redboot_config_printenv(flash_info_t *info, void *fis, + char *small_buf, const char *what) +{ + int size, cfglen, len, printit, swapped; + void *config; + char *dp, *dpe; + + if (small_buf == NULL) + return -1; + + config = get_config(info, fis, &size, &swapped); + if (config == NULL) + return -1; + + /* point to the config data */ + dp = config + 8; + dpe = config + size - 8; + + for (; dp < dpe; dp += len) { + + cfglen = config_length(TYPE(dp)); + if (cfglen < 0) /* illegal type */ + return -1; + + len = 4 + KEYLEN(dp) + ENABLE_KEYLEN(dp) + cfglen; + + /* don't bother with the empty */ + if (TYPE(dp) == CONFIG_EMPTY) + continue; + + /* printf("%p: %02x %02x %02x %02x\n", + dp, (int)dp[0] & 0xff, (int)dp[1] & 0xff, + (int)dp[2] & 0xff, (int)dp[3] & 0xff); */ + + printit = what == NULL || + (what != NULL && strcmp(what, KEY(dp)) == 0); + + if (printit) { + printf("%s=%s\n", KEY(dp), + config_format_value(TYPE(dp), + VALUE(dp), small_buf, swapped)); + printf("\ttype=%s", config_txt_tab[(int)TYPE(dp)]); + printf(" enable-sense=%s", + ENABLE_SENSE(dp) ? "true" : "false"); + if (ENABLE_KEYLEN(dp) > 0) + printf(" enable-key=%s", ENABLE_KEY(dp)); + printf("\n"); + + if (what) + break; + } + } + + return 0; +} + +const char *redboot_config_getenv(flash_info_t *info, void *fis, + char *small_buf, const char *what, const char *special) +{ + int size, cfglen, len, swapped; + void *config; + char *dp, *dpe; + + /* this time we need that */ + if (what == NULL || small_buf == NULL) + return NULL; + + config = get_config(info, fis, &size, &swapped); + if (config == NULL) + return NULL; + + /* point to the config data */ + dp = config + 8; + dpe = config + size - 8; + + for (; dp < dpe; dp += len) { + + cfglen = config_length(TYPE(dp)); + if (cfglen < 0) /* illegal type */ + return NULL; + + len = 4 + KEYLEN(dp) + ENABLE_KEYLEN(dp) + cfglen; + + /* don't bother with the empty */ + if (TYPE(dp) == CONFIG_EMPTY) + continue; + + if (strcmp(what, KEY(dp)) == 0) { + + /* return value */ + if (special == NULL || strcmp(special, "value") == 0) + return config_format_value(TYPE(dp), VALUE(dp), + small_buf, swapped); + + if (strcmp(special, "type") == 0) + return config_txt_tab[(int)TYPE(dp)]; + + if (strcmp(special, "enable-sense") == 0) + return ENABLE_SENSE(dp) ? "true" : "false"; + + if (strcmp(special, "enable-key") == 0) + return ENABLE_KEY(dp); + } + } + + return NULL; +} + +int redboot_config_setenv(flash_info_t *info, void *fis, + const char *var, const char *what, const char *special) +{ + static char small_buf[18]; + const char *value; + + value = redboot_config_getenv(info, fis, small_buf, what, special); + if (!value) + return -1; + + setenv((char *)var, (char *)value); + + return 0; +} + +/*************************************************************/ + +#ifdef CONFIG_PPC + +/* Note: Only tested on a PPC board - other arches + * should be made to work with not much trouble + * + * The way this works is: we do pretty much what + * we do for a bootm case of a uImage (even creating + * the u-boot's idea of bd_t). And then we call + * board specific code to fix the mess. + */ + +static void __attribute__((noinline)) +redboot_linux_exec(ulong addr, ulong ramdisk_address, ulong ramdisk_length) +{ + ulong sp; + ulong initrd_start, initrd_end; + ulong cmd_start, cmd_end; + char *cmdline; + char *s; + bd_t *kbd; + + initrd_start = ramdisk_address; + initrd_end = ramdisk_address + ramdisk_length; + + /* + * Booting a (Linux) kernel image + * + * Allocate space for command line and board info - the + * address should be as high as possible within the reach of + * the kernel (see CFG_BOOTMAPSZ settings), but in unused + * memory, which means far enough below the current stack + * pointer. + */ + + /* point stack at the end of memory */ + /* redboot is different that u-boot in that regard */ + sp = (gd->bd->bi_memstart + gd->bd->bi_memsize) - 16; + sp &= ~0x0f; + + debug ("## Current stack ends at 0x%08lX ", sp); + + sp -= 2048; /* just to be sure */ + + debug ("=> set upper limit to 0x%08lX\n", sp); + + cmdline = (char *)((sp - CFG_BARGSIZE) & ~0xF); + kbd = (bd_t *)(((ulong)cmdline - CONFIG_REDBOOT_BD_T_SIZE) & ~0xF); + + if ((s = getenv("bootargs")) != NULL) { + + strcpy (cmdline, s); + + cmd_start = (ulong)&cmdline[0]; + cmd_end = cmd_start + strlen(cmdline); + } else { + cmd_start = 0; + cmd_end = 0; + } + + *kbd = *(gd->bd); + + if ((s = getenv("clocks_in_mhz")) != NULL) { + /* convert all clock information to MHz */ + kbd->bi_intfreq /= 1000000L; + kbd->bi_busfreq /= 1000000L; +#if defined(CONFIG_MPC8220) + kbd->bi_inpfreq /= 1000000L; + kbd->bi_pcifreq /= 1000000L; + kbd->bi_pevfreq /= 1000000L; + kbd->bi_flbfreq /= 1000000L; + kbd->bi_vcofreq /= 1000000L; +#endif +#if defined(CONFIG_CPM2) + kbd->bi_cpmfreq /= 1000000L; + kbd->bi_brgfreq /= 1000000L; + kbd->bi_sccfreq /= 1000000L; + kbd->bi_vco /= 1000000L; +#endif +#if defined(CONFIG_MPC5xxx) + kbd->bi_ipbfreq /= 1000000L; + kbd->bi_pcifreq /= 1000000L; +#endif /* CONFIG_MPC5xxx */ + } + + /* convert u-boot bd_t to redboot_bd_t in place */ + board_redboot_bd_t_adapt(kbd, cmd_start, cmd_end, + initrd_start, initrd_end); + + debug ("## Transferring control to Linux (at address %08lx) ...\n", + (ulong)kernel); + + SHOW_BOOT_PROGRESS (15); + +#if defined(CFG_INIT_RAM_LOCK) && !defined(CONFIG_E500) + unlock_ram_in_cache(); +#endif + dcache_disable(); + icache_disable(); + disable_interrupts(); + + /* Call into Linux */ + __asm__ volatile ( + /* Start by disabling MMU - the mappings are */ + /* 1-1 so this should not cause any problems */ + "mfmsr 3\n" + "li 4,0xFFFFFFCF\n" + "and 3,3,4\n" + "sync\n" + "mtmsr 3\n" + "sync\n" + + /* Now set up parameters to jump into linux */ + + "mtlr %0\n" /* set entry address in LR */ + "mr 1,%1\n" /* set stack pointer */ + "mr 3,%2\n" /* set board info in R3 */ + "mr 4,%3\n" /* set command line in R4 */ + "blr \n" /* jump into linux */ + : + : "r"(addr), "r"(sp), "r"(kbd), "r"(cmd_start) + : "r3", "r4"); + + /* never reached */ +} +#endif /* CONFIG_PPC */ + +extern flash_info_t flash_info[]; /* info for FLASH chips */ + +int do_redboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int i, j; + char *name, *var; + static int bank = 1; + static int dir_block = -1; /* defaults */ + void *fis; + static char small_buf[18]; + const char *value; + + if (argc < 2) + goto usage; + + if (strcmp(argv[1], "fis") == 0) { + + if (argc < 3) + goto usage; + + if (strcmp(argv[2], "select") == 0) { + + i = bank; + j = dir_block; + + if (argc == 3 || strcmp(argv[3], "show") == 0) { + ; /* nothing */ + } else if (argc >= 4 && strcmp(argv[3], "reset") == 0) { + i = 1; + j = -1; + } else { + if (argc >= 4) + i = simple_strtoul(argv[3], NULL, 16); + if (argc >= 5) + j = simple_strtol(argv[4], NULL, 16); + } + + fis = redboot_fis_get(i, j, NULL); + if (fis == NULL) { + printf("Illegal selection:" + " bank %ld, dir_block # %ld\n", + i, j); + return 1; + } + + printf("bank #%ld, dir-block #%ld:" + " RedBoot FIS @%p\n", + bank, dir_block, fis); + bank = i; + dir_block = j; + return 0; + } + + if (strcmp(argv[2], "list") == 0) { + + fis = redboot_fis_get(bank, dir_block, NULL); + if (fis == NULL) { + printf("Illegal selection:" + " bank %ld, dir_block # %ld\n", + bank, dir_block); + return 1; + } + + printf("\nbank #%ld, dir-block #%ld:" + " RedBoot FIS @%p\n", bank, dir_block, + fis); + + redboot_fis_list(&flash_info[bank-1], fis); + + return 0; + } + + if (strcmp(argv[2], "setenv") == 0) { + + if (argc < 6) + goto usage; + + var = argv[3]; + name = argv[5]; + + fis = redboot_fis_get(bank, dir_block, NULL); + if (fis == NULL) { + printf("Illegal selection:" + " bank %ld, dir_block # %ld\n", + bank, dir_block); + return 1; + } + + i = redboot_fis_setenv(&flash_info[bank-1], fis, name, + argv[4], var); + if (i != 0) { + printf("Unable to set var '%s' from '%s'\n", + argv[4], name); + return 1; + } + + return 0; + } + } + + if (strcmp(argv[1], "config") == 0) { + + if (argc < 3) + goto usage; + + fis = redboot_fis_get(bank, dir_block, NULL); + if (fis == NULL) { + printf("Illegal selection:" + " bank %ld, dir_block # %ld\n", + bank, dir_block); + return 1; + } + + if (strcmp(argv[2], "printenv") == 0) { + + if (argc >= 5) { + value = redboot_config_getenv( + &flash_info[bank-1], + fis, small_buf, + argv[3], argv[4]); + if (value) + printf("%s=%s\n", argv[3], value); + } else + redboot_config_printenv( + &flash_info[bank-1], + fis, small_buf, + argc >= 4 ? argv[3] : NULL); + + return 0; + } + + if (strcmp(argv[2], "setenv") == 0) { + + if (argc < 5) + goto usage; + + i = redboot_config_setenv(&flash_info[bank-1], fis, + argv[3], argv[4], argc >= 6 ? argv[5] : NULL); + if (i != 0) { + printf("Failed to set variable\n"); + return 1; + } + + return 0; + } + } + +#ifdef CONFIG_PPC + if (strcmp(argv[1], "exec") == 0) { + ulong addr, ramdisk_start, ramdisk_length; + + addr = 0; + ramdisk_start = 0; + ramdisk_length = 0; + + if (argc >= 3) + addr = simple_strtoul(argv[2], NULL, 16); + else if ((value = getenv("loadaddr")) != NULL) + addr = simple_strtoul(value, NULL, 16); + else if ((value = getenv("redboot_kernel_address")) != NULL) + addr = simple_strtoul(value, NULL, 16); + else { + printf("Kernel address not found\n"); + goto usage; + } + + if ((value = getenv("redboot_ramdisk_address")) != NULL) + ramdisk_start = simple_strtoul(value, NULL, 16); + + if ((value = getenv("redboot_ramdisk_length")) != NULL) + ramdisk_length = simple_strtoul(value, NULL, 16); + + redboot_linux_exec(addr, ramdisk_start, ramdisk_length); + } + +#endif + +usage: + printf("Usage:\n%s\n", cmdtp->usage); + return 1; +} + + +U_BOOT_CMD( + redboot, 6, 1, do_redboot, + "redboot - redboot support commands\n", + "select ([bank] [sector] | reset)\n" + " - Select FIS\n" + "redboot fis list\n" + " - List FIS\n" + "redboot fis setenv var type name\n" + " - Set variable var to the type variable of the image\n" + " type: flash_base, mem_base, size, entry_point, data_length\n" + "redboot config printenv [cfgvar] [member]\n" + " - Print Redboot config key(s) of [member] of [cfgvar]\n" + "redboot config setenv var cfgvar [member]\n" + " - Print Redboot config key(s) of [member] of cfgvar\n" +#ifdef CONFIG_PPC + "redboot exec [address]\n" + " - Boot a Linux kernel compiled for redboot\n" +#endif + "" /* last empty string */ +); + +#endif + diff --git a/include/redboot.h b/include/redboot.h new file mode 100644 index 0000000..620fe86 --- /dev/null +++ b/include/redboot.h @@ -0,0 +1,98 @@ +/* + * (C) Copyright 2006 - Embedded Alley Solutions Inc. + * by Pantelis Antoniou, pantelis@embeddedalley.com + * + * Based on Linux & RedBoot code fragments + * by David Woodhouse, dwmw2@infradead.org + * by Mark Sattler, msalter@redhat.com + * by Gary Thomas, gthomas@redhat.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#ifndef REDBOOT_H +#define REDBOOT_H + +#include <common.h> +#include <flash.h> + +struct fis_image_desc { + u8 name[16]; /* Null terminated name */ + u32 flash_base; /* Address within FLASH of image */ + u32 mem_base; /* Address in memory where it executes */ + u32 size; /* Length of image */ + u32 entry_point; /* Execution entry point */ + u32 data_length; /* Length of actual data */ + u8 _pad[256-(16+7*sizeof(u32))]; + u32 desc_cksum; /* Checksum over image descriptor */ + u32 file_cksum; /* Checksum over image data */ +}; + +/* + * redboot config is stored like this + * note that we don't define it, since we can work + * without having a fixed size config + * + * struct redboot_config { + * u32 len; + * u32 key1; + * char config_data[MAX_CONFIG_DATA-(4*4)]; + * u32 key2; + * u32 long cksum; + * }; + * + */ + +/* defaults */ +#ifndef CONFIG_REDBOOT_FIS_DIRECTORY_BLOCK +#define CONFIG_REDBOOT_FIS_DIRECTORY_BLOCK -1 /* last block */ +#endif + +#ifndef CONFIG_REDBOOT_DIRECTORY_ENTRY_SIZE +#define CONFIG_REDBOOT_DIRECTORY_ENTRY_SIZE 0x100 /* default */ +#endif + +#ifndef CONFIG_REDBOOT_FLASH_SCRIPT_SIZE +#define CONFIG_REDBOOT_FLASH_SCRIPT_SIZE 256 +#endif + +#ifndef CONFIG_REDBOOT_FLASH_STRING_SIZE +#define CONFIG_REDBOOT_FLASH_STRING_SIZE 128 +#endif + +#ifndef CONFIG_REDBOOT_FLASH_CONFIG_SIZE +#define CONFIG_REDBOOT_FLASH_CONFIG_SIZE 4096 +#endif + +void *redboot_fis_get(int bank, int dir_block, flash_info_t **infop); +int redboot_fis_list(flash_info_t *info, void *fis); +int redboot_fis_entry_lookup(flash_info_t *info, void *fis, + struct fis_image_desc *fis_buf, const char *name); +int redboot_fis_setenv(flash_info_t *info, void *fis, + const char *name, const char *what, char *var); + +int redboot_config_printenv(flash_info_t *info, void *fis, + char *small_buf, const char *what); +const char *redboot_config_getenv(flash_info_t *info, void *fis, + char *small_buf, const char *what, const char *special); +int redboot_config_setenv(flash_info_t *info, void *fis, + const char *var, const char *what, const char *special); + +#endif

Add support for Analogue Micro's ASP8347DB board. The board is originally shipped with RedBoot. All appropriate settings are migrated to u-boot & the old kernel booted; a drop in bootloader replacement.
--- Signed-off-by: Pantelis Antoniou pantelis@embeddedalley.com ---
include/configs/ASP8347DB.h | 690 +++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 690 insertions(+), 0 deletions(-)
diff --git a/include/configs/ASP8347DB.h b/include/configs/ASP8347DB.h new file mode 100644 index 0000000..83ffb7b --- /dev/null +++ b/include/configs/ASP8347DB.h @@ -0,0 +1,690 @@ +/* + * (C) Copyright 2006 + * Pantelis Antoniou, Embedded Alley pantelis@embeddedalley.com + * + * Based on TQM834x by + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * ASP8347DB board configuration file + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#define DEBUG +#undef DEBUG + +/* + * High Level Configuration Options + */ +#define CONFIG_E300 1 /* E300 Family */ +#define CONFIG_MPC83XX 1 /* MPC83XX family */ +#define CONFIG_MPC834X 1 /* MPC834X specific */ +#define CONFIG_MPC8349 1 /* MPC8349 specific */ +#define CONFIG_ASP8347DB 1 /* ASP8347DB board specific */ + +/* IMMR Base Addres Register, use Freescale default: 0xff400000 */ +#define CFG_IMMR 0xff000000 + +/* System clock. Primary input clock when in PCI host mode */ +#define CONFIG_83XX_CLKIN 66666000 /* 66,666 MHz */ + +/* + * Local Bus LCRR + * LCRR: DLL bypass, Clock divider is 8 + * + * for CSB = 266 MHz it gives LCB clock frequency = 33 MHz + * + * External Local Bus rate is + * CLKIN * HRCWL_CSB_TO_CLKIN / HRCWL_LCL_BUS_TO_SCB_CLK / LCRR_CLKDIV + */ +#define CFG_LCRR (LCRR_DBYP | LCRR_CLKDIV_8) + +/* board pre init: do not call, nothing to do */ +#undef CONFIG_BOARD_EARLY_INIT_F + +/* detect the number of flash banks */ +#define CONFIG_BOARD_EARLY_INIT_R + +/* auto complete please */ +#define CONFIG_AUTO_COMPLETE + +/* + * DDR Setup + */ +#define CFG_DDR_BASE 0x00000000 /* DDR is system memory */ +#define CFG_SDRAM_BASE CFG_DDR_BASE +#define CFG_SDRAM_SIZE 128 +#define CFG_DDR_SDRAM_BASE CFG_DDR_BASE +#define DDR_CASLAT_25 /* CASLAT set to 2.5 */ +#undef CONFIG_DDR_ECC /* only for ECC DDR module */ +#undef CONFIG_SPD_EEPROM /* do not use SPD EEPROM for DDR setup */ + +#define CFG_MEMTEST_START 0x00100000 /* memtest region */ +#define CFG_MEMTEST_END 0x00200000 + +/* + * FLASH on the Local Bus + */ +#define CFG_FLASH_CFI /* use the Common Flash Interface */ +#define CFG_FLASH_CFI_DRIVER /* use the CFI driver */ +#undef CFG_FLASH_CHECKSUM +#define CFG_FLASH_BASE 0xf0000000 /* start of FLASH */ +#define CFG_FLASH_SIZE 64 /* FLASH size in MB */ + +/* buffered writes in the AMD chip set is not supported yet */ +#undef CFG_FLASH_USE_BUFFER_WRITE + +/* + * FLASH bank number detection + */ + +#define CFG_MAX_FLASH_BANKS 1 +#define CFG_MAX_FLASH_SECT 512 /* max sectors per device */ + +/* 32 bit device at 0x80000000 via GPCM (0x8000_1801) */ +#define CFG_BR0_PRELIM ((CFG_FLASH_BASE & BR_BA) | \ + BR_MS_GPCM | BR_PS_16 | BR_V) + +/* FLASH timing */ +#define CFG_OR_TIMING_FLASH (OR_GPCM_CSNT | OR_GPCM_BCTLD | \ + OR_GPCM_CSNT | OR_GPCM_ACS_0b11 | \ + OR_GPCM_SCY_7 | OR_GPCM_TRLX | \ + OR_GPCM_EHTR) + +#define CFG_PRELIM_OR_AM 0xfc000000 /* OR addr mask: 64MB */ + +#define CFG_OR0_PRELIM (CFG_PRELIM_OR_AM | CFG_OR_TIMING_FLASH) + +#define CFG_LBLAWAR0_PRELIM 0x8000001c /* 32 MB size (2^(size + 1)) */ +#define CFG_LBLAWBAR0_PRELIM CFG_FLASH_BASE /* Window base at flash base */ + +#define ASP8347DB_FPGA_BASE 0xf8000000 + +/* FPGA : 32bit */ +#define CFG_BR1_PRELIM ((ASP8347DB_FPGA_BASE & BR_BA) | \ + BR_MS_GPCM | BR_PS_32 | BR_V) +#define CFG_OR1_PRELIM (0xffff0000 | OR_GPCM_ACS_0b11 | \ + OR_GPCM_SCY_15 | OR_GPCM_TRLX | \ + OR_GPCM_EHTR) +#define CFG_LBLAWBAR1_PRELIM ASP8347DB_FPGA_BASE +#define CFG_LBLAWAR1_PRELIM 0x80000016 + +/* disable remaining mappings */ +#define CFG_BR2_PRELIM 0x00000000 +#define CFG_OR2_PRELIM 0x00000000 +#define CFG_LBLAWBAR2_PRELIM 0x00000000 +#define CFG_LBLAWAR2_PRELIM 0x00000000 + +#define CFG_BR3_PRELIM 0x00000000 +#define CFG_OR3_PRELIM 0x00000000 +#define CFG_LBLAWBAR3_PRELIM 0x00000000 +#define CFG_LBLAWAR3_PRELIM 0x00000000 + +#define CFG_BR4_PRELIM 0x00000000 +#define CFG_OR4_PRELIM 0x00000000 +#define CFG_LBLAWBAR4_PRELIM 0x00000000 +#define CFG_LBLAWAR4_PRELIM 0x00000000 + +#define CFG_BR5_PRELIM 0x00000000 +#define CFG_OR5_PRELIM 0x00000000 +#define CFG_LBLAWBAR5_PRELIM 0x00000000 +#define CFG_LBLAWAR5_PRELIM 0x00000000 + +#define CFG_BR6_PRELIM 0x00000000 +#define CFG_OR6_PRELIM 0x00000000 +#define CFG_LBLAWBAR6_PRELIM 0x00000000 +#define CFG_LBLAWAR6_PRELIM 0x00000000 + +#define CFG_BR7_PRELIM 0x00000000 +#define CFG_OR7_PRELIM 0x00000000 +#define CFG_LBLAWBAR7_PRELIM 0x00000000 +#define CFG_LBLAWAR7_PRELIM 0x00000000 + +/* + * Monitor config + */ +#define CFG_MONITOR_BASE TEXT_BASE + +#if (CFG_MONITOR_BASE < CFG_FLASH_BASE) +#define CFG_RAMBOOT +#else +#undef CFG_RAMBOOT +#endif + +#define CONFIG_L1_INIT_RAM +#define CFG_INIT_RAM_LOCK 1 +#define CFG_INIT_RAM_ADDR 0xFD000000 /* Initial RAM address */ +#define CFG_INIT_RAM_END 0x1000 /* End of used area in RAM */ + +#define CFG_GBL_DATA_SIZE 0x100 /* num bytes initial data */ +#define CFG_GBL_DATA_OFFSET (CFG_INIT_RAM_END - CFG_GBL_DATA_SIZE) +#define CFG_INIT_SP_OFFSET CFG_GBL_DATA_OFFSET + +#define CFG_MONITOR_LEN (256 * 1024) /* Reserve 256 kB for Mon */ +#define CFG_MALLOC_LEN (128 * 1024) /* Reserved for malloc */ + +/* + * Serial Port + */ +#define CONFIG_CONS_INDEX 1 +#undef CONFIG_SERIAL_SOFTWARE_FIFO +#define CFG_NS16550 +#define CFG_NS16550_SERIAL +#define CFG_NS16550_REG_SIZE 1 +#define CFG_NS16550_CLK get_bus_freq(0) + +#define CFG_BAUDRATE_TABLE \ + {300, 600, 1200, 2400, 4800, 9600, 19200, 38400,115200} + +#define CFG_NS16550_COM1 (CFG_IMMR + 0x4500) +#define CFG_NS16550_COM2 (CFG_IMMR + 0x4600) + +/* + * I2C + */ +#undef CONFIG_HARD_I2C /* I2C with hardware support */ +#undef CONFIG_SOFT_I2C /* I2C bit-banged */ +#define CFG_I2C_SPEED 400000 /* I2C speed: 400KHz */ +#define CFG_I2C_SLAVE 0x7F /* slave address */ +#define CFG_I2C_OFFSET 0x3000 + +/* + * TSEC + */ +#define CONFIG_TSEC_ENET /* tsec ethernet support */ +#define CONFIG_MII + +#define CFG_TSEC1_OFFSET 0x24000 +#define CFG_TSEC1 (CFG_IMMR + CFG_TSEC1_OFFSET) +#define CFG_TSEC2_OFFSET 0x25000 +#define CFG_TSEC2 (CFG_IMMR + CFG_TSEC2_OFFSET) + +#if defined(CONFIG_TSEC_ENET) + +#ifndef CONFIG_NET_MULTI +#define CONFIG_NET_MULTI +#endif + +#define CONFIG_MPC83XX_TSEC1 1 +#define CONFIG_MPC83XX_TSEC1_NAME "TSEC0" +#define CONFIG_MPC83XX_TSEC2 1 +#define CONFIG_MPC83XX_TSEC2_NAME "TSEC1" +#define TSEC1_PHY_ADDR 1 +#define TSEC2_PHY_ADDR 2 +#define TSEC1_PHYIDX 0 +#define TSEC2_PHYIDX 0 + +/* Options are: TSEC[0-1] */ +#define CONFIG_ETHPRIME "TSEC0" + +#endif /* CONFIG_TSEC_ENET */ + +/* + * General PCI + * Addresses are mapped 1-1. + */ +#define CONFIG_PCI + +#if defined(CONFIG_PCI) + +#define CONFIG_PCI_PNP /* do pci plug-and-play */ +#define CONFIG_PCI_SCAN_SHOW /* show pci devices on startup */ + +/* PCI1 host bridge */ +#define CFG_PCI1_MEM_BASE 0xc0000000 +#define CFG_PCI1_MEM_PHYS CFG_PCI1_MEM_BASE +#define CFG_PCI1_MEM_SIZE 0x20000000 /* 512M */ +#define CFG_PCI1_IO_BASE 0xe2000000 +#define CFG_PCI1_IO_PHYS CFG_PCI1_IO_BASE +#define CFG_PCI1_IO_SIZE 0x1000000 /* 16M */ + + +#undef CONFIG_EEPRO100 +#define CONFIG_EEPRO100 +#undef CONFIG_TULIP + +#if !defined(CONFIG_PCI_PNP) + #define PCI_ENET0_IOADDR CFG_PCI1_IO_BASE + #define PCI_ENET0_MEMADDR CFG_PCI1_MEM_BASE + #define PCI_IDSEL_NUMBER 0x1c /* slot0 (IDSEL) = 28 */ +#endif + +#define CFG_PCI_SUBSYS_VENDORID 0x1957 /* Freescale */ + +#endif /* CONFIG_PCI */ + +/* + * Environment + */ +#define CONFIG_ENV_OVERWRITE + +#ifndef CFG_RAMBOOT +#define CFG_ENV_IS_IN_FLASH 1 +#define CFG_ENV_ADDR (CFG_MONITOR_BASE + 0x40000) +#define CFG_ENV_SECT_SIZE 0x10000 /* 64K(one sector) for env */ +#define CFG_ENV_SIZE 0x2000 +#else +#define CFG_NO_FLASH 1 /* Flash is not usable now */ +#define CFG_ENV_IS_NOWHERE 1 /* Store ENV in memory only */ +#define CFG_ENV_ADDR (CFG_MONITOR_BASE - 0x1000) +#define CFG_ENV_SIZE 0x2000 +#endif + +#define CONFIG_LOADS_ECHO 1 /* echo on serial download */ +#define CFG_LOADS_BAUD_CHANGE 1 /* allow baudrate change */ + +/* Common commands */ +#define CFG_CMD_ASP8347DB_COMMON CFG_CMD_PING \ + | CFG_CMD_MII | CFG_CMD_JFFS2 + +#if defined(CFG_RAMBOOT) + +#if defined(CONFIG_PCI) +#define CONFIG_COMMANDS ((CONFIG_CMD_DFL | CFG_CMD_PCI \ + | CFG_CMD_ASP8347DB_COMMON) \ + & \ + ~(CFG_CMD_ENV | CFG_CMD_LOADS)) +#else +#define CONFIG_COMMANDS ((CONFIG_CMD_DFL \ + | CFG_CMD_ASP8347DB_COMMON) \ + & \ + ~(CFG_CMD_ENV | CFG_CMD_LOADS)) +#endif + +#else /* CFG_RAMBOOT */ + +#if defined(CONFIG_PCI) +#define CONFIG_COMMANDS (CONFIG_CMD_DFL | CFG_CMD_PCI \ + | CFG_CMD_ASP8347DB_COMMON) +#else +#define CONFIG_COMMANDS (CONFIG_CMD_DFL \ + | CFG_CMD_ASP8347DB_COMMON) +#endif + +#endif /* CFG_RAMBOOT */ + +#include <cmd_confdefs.h> + +/* + * Miscellaneous configurable options + */ +#define CFG_LONGHELP /* undef to save memory */ +#define CFG_LOAD_ADDR 0x2000000 /* default load address */ +#define CFG_PROMPT "=> " /* Monitor Command Prompt */ + +#define CONFIG_CMDLINE_EDITING 1 /* add command line history */ +#define CFG_HUSH_PARSER 1 /* Use the HUSH parser */ +#ifdef CFG_HUSH_PARSER +#define CFG_PROMPT_HUSH_PS2 "> " +#endif + +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#define CFG_CBSIZE 1024 /* Console I/O Buffer Size */ +#else +#define CFG_CBSIZE 256 /* Console I/O Buffer Size */ +#endif + +#define CFG_PBSIZE (CFG_CBSIZE+sizeof(CFG_PROMPT)+16) /* print buffer size */ +#define CFG_MAXARGS 16 /* max num of command args */ +#define CFG_BARGSIZE CFG_CBSIZE /* boot arg buffer size */ +#define CFG_HZ 1000 /* decrementer freq: 1ms */ + +#undef CONFIG_WATCHDOG /* watchdog disabled */ + +/* + * For booting Linux, the board info and command line data + * have to be in the first 8 MB of memory, since this is + * the maximum mapped by the Linux kernel during initialization. + */ +#define CFG_BOOTMAPSZ (8 << 20) /* Initial Memory map for Linux */ + +/* + * Cache Configuration + */ +#define CFG_DCACHE_SIZE 32768 +#define CFG_CACHELINE_SIZE 32 +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#define CFG_CACHELINE_SHIFT 5 /*log base 2 of the above value*/ +#endif + +#define CFG_HRCW_LOW ( \ + HRCWL_LCL_BUS_TO_SCB_CLK_1X1 | \ + HRCWL_DDR_TO_SCB_CLK_1X1 | \ + HRCWL_CSB_TO_CLKIN_4X1 | \ + HRCWL_VCO_BYPASS | \ + HRCWL_CORE_TO_CSB_1_5X1) + +#define CFG_HRCW_HIGH ( \ + HRCWH_PCI_HOST | \ + HRCWH_32_BIT_PCI | \ + HRCWH_PCI1_ARBITER_ENABLE | \ + HRCWH_PCI2_ARBITER_DISABLE | \ + HRCWH_CORE_ENABLE | \ + HRCWH_FROM_0X00000100 | \ + HRCWH_BOOTSEQ_DISABLE | \ + HRCWH_SW_WATCHDOG_DISABLE | \ + HRCWH_ROM_LOC_LOCAL_16BIT | \ + HRCWH_TSEC1M_IN_GMII | \ + HRCWH_TSEC2M_IN_GMII) + +/* System IO Config */ +#if 0 +#define CFG_SICRH SICRH_TSOBI1 +#define CFG_SICRL SICRL_LDP_A +#else +#define CFG_SICRH 0x000000a0 +#define CFG_SICRL 0x80000000 +#endif + +/* i-cache and d-cache disabled */ +#define CFG_HID0_INIT 0x000000000 +#define CFG_HID0_FINAL CFG_HID0_INIT +#define CFG_HID2 HID2_HBE + +/* DDR 0 - 128 */ +#define CFG_IBAT0L (CFG_SDRAM_BASE | BATL_PP_10 | \ + BATL_MEMCOHERENCE) +#define CFG_IBAT0U (CFG_SDRAM_BASE | BATU_BL_256M | \ + BATU_VS | BATU_VP) + +/* DCACHE */ +#define CFG_IBAT1L (CFG_INIT_RAM_ADDR | BATL_PP_10 | \ + BATL_MEMCOHERENCE) +#define CFG_IBAT1U (CFG_INIT_RAM_ADDR | BATU_BL_128K | \ + BATU_VS | BATU_VP) + +#define CFG_IBAT2L 0 +#define CFG_IBAT2U 0 + +/* PCI */ +#ifdef CONFIG_PCI +#define CFG_IBAT3L (CFG_PCI1_MEM_BASE | BATL_PP_10 | BATL_MEMCOHERENCE) +#define CFG_IBAT3U (CFG_PCI1_MEM_BASE | BATU_BL_256M | BATU_VS | BATU_VP) +#define CFG_IBAT4L (CFG_PCI1_MEM_BASE + 0x10000000 | BATL_PP_10 | \ + BATL_MEMCOHERENCE) +#define CFG_IBAT4U (CFG_PCI1_MEM_BASE + 0x10000000 | BATU_BL_256M | \ + BATU_VS | BATU_VP) +#define CFG_IBAT5L (CFG_PCI1_IO_BASE | BATL_PP_10 | BATL_CACHEINHIBIT | \ + BATL_GUARDEDSTORAGE) +#define CFG_IBAT5U (CFG_PCI1_IO_BASE + 0x10000000 | BATU_BL_16M | \ + BATU_VS | BATU_VP) +#else +#define CFG_IBAT3L (0) +#define CFG_IBAT3U (0) +#define CFG_IBAT4L (0) +#define CFG_IBAT4U (0) +#define CFG_IBAT5L (0) +#define CFG_IBAT5U (0) +#endif + +/* IMMR */ +#define CFG_IBAT6L (CFG_IMMR | BATL_PP_10 | BATL_CACHEINHIBIT | \ + BATL_GUARDEDSTORAGE) +#define CFG_IBAT6U (CFG_IMMR | BATU_BL_1M | BATU_VS | BATU_VP) + +/* FLASH */ +#define CFG_IBAT7L (CFG_FLASH_BASE | BATL_PP_10 | BATL_CACHEINHIBIT | \ + BATL_GUARDEDSTORAGE) +#define CFG_IBAT7U (CFG_FLASH_BASE | BATU_BL_256M | BATU_VS | BATU_VP) + +#define CFG_DBAT0L CFG_IBAT0L +#define CFG_DBAT0U CFG_IBAT0U +#define CFG_DBAT1L CFG_IBAT1L +#define CFG_DBAT1U CFG_IBAT1U +#define CFG_DBAT2L CFG_IBAT2L +#define CFG_DBAT2U CFG_IBAT2U +#define CFG_DBAT3L CFG_IBAT3L +#define CFG_DBAT3U CFG_IBAT3U +#define CFG_DBAT4L CFG_IBAT4L +#define CFG_DBAT4U CFG_IBAT4U +#define CFG_DBAT5L CFG_IBAT5L +#define CFG_DBAT5U CFG_IBAT5U +#define CFG_DBAT6L CFG_IBAT6L +#define CFG_DBAT6U CFG_IBAT6U +#define CFG_DBAT7L CFG_IBAT7L +#define CFG_DBAT7U CFG_IBAT7U + +/* + * Internal Definitions + * + * Boot Flags + */ +#define BOOTFLAG_COLD 0x01 /* Normal Power-On: Boot from FLASH */ +#define BOOTFLAG_WARM 0x02 /* Software reboot */ + +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#define CONFIG_KGDB_BAUDRATE 230400 /* speed of kgdb serial port */ +#define CONFIG_KGDB_SER_INDEX 2 /* which serial port to use */ +#endif + +/* + * Environment Configuration + */ + +#if defined(CONFIG_TSEC_ENET) +#define CONFIG_ETHADDR D2:DA:5E:44:BC:29 +#define CONFIG_HAS_ETH1 +#define CONFIG_ETH1ADDR 1E:F3:40:21:92:53 +#endif + +#define CONFIG_IPADDR 192.168.1.249 + +#define CONFIG_HOSTNAME asp8347db +#define CONFIG_ROOTPATH /exports/asp8347db-root +#define CONFIG_BOOTFILE uImage-rattler + +#define CONFIG_SERVERIP 192.168.1.10 +#define CONFIG_GATEWAYIP 192.168.1.1 +#define CONFIG_NETMASK 255.255.255.0 + +#define CONFIG_LOADADDR 200000 /* default for tftp and bootm */ + +#define CONFIG_BOOTDELAY 6 /* -1 disables auto-boot */ +#undef CONFIG_BOOTARGS /* the boot command will set bootargs */ + +#define CONFIG_BAUDRATE 38400 + +#define CONFIG_PREBOOT "echo;" \ + "echo Type "run flash_nfs" to mount root filesystem over NFS;" \ + "echo" + +#undef CONFIG_BOOTARGS + +#define CONFIG_EXTRA_ENV_SETTINGS \ + "netdev=eth0\0" \ + "hostname=asp8347db\0" \ + "nfsargs=setenv bootargs root=/dev/nfs rw " \ + "nfsroot=${serverip}:${rootpath}\0" \ + "ramargs=setenv bootargs root=/dev/ram rw\0" \ + "addip=setenv bootargs ${bootargs} " \ + "ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}" \ + ":${hostname}:${netdev}:off panic=1\0" \ + "addtty=setenv bootargs ${bootargs} console=ttyS0,${baudrate}\0"\ + "flash_nfs=run nfsargs addip addtty;" \ + "bootm ${kernel_addr}\0" \ + "flash_self=run ramargs addip addtty;" \ + "bootm ${kernel_addr} ${ramdisk_addr}\0" \ + "net_nfs=tftp 200000 ${bootfile};run nfsargs addip addtty;" \ + "bootm\0" \ + "rootpath=/exports/asp8347db-root\0" \ + "bootfile=uImage-rattler\0" \ + "kernel_addr=80060000\0" \ + "ramdisk_addr=80160000\0" \ + "load=tftp 100000 /tftpboot/asp8347db/u-boot.bin\0" \ + "update=protect off 80000000 8003ffff; " \ + "era 80000000 8003ffff; cp.b 100000 80000000 40000\0" \ + "upd=run load;run update\0" \ + "" + +#define CONFIG_BOOTCOMMAND "run flash_self" + +/* + * JFFS2 partitions + */ +/* mtdparts command line support */ +#define CONFIG_JFFS2_CMDLINE +#define MTDIDS_DEFAULT "nor0=ASP8347DB" + +/* default mtd partition table */ +#define MTDPARTS_DEFAULT "mtdparts=ASP8347DB:" \ + "256k(u-boot),64k(env),64k(env2)," \ + "64k(ASP8347DB.FPGA)," \ + "4m(jffs2),1m(Linux)," \ + "27136k(spare)," \ + "64k(RedBoot);"\ +/* + * Lattice FPGA configuration support + */ +#define CONFIG_FPGA_COUNT 1 +#define CONFIG_FPGA CFG_LATTICE_EC +#define CFG_FPGA_PROG_FEEDBACK + +/* + * Enable the call to misc_init_r() for miscellaneous platform + * dependent initialization. + */ +#define CONFIG_MISC_INIT_R + +/* + * Enable call to last_stage_init() + */ +#define CONFIG_LAST_STAGE_INIT + +/* + * RedBoot support (this is conditional to CFG_CMD_FLASH) + */ +#define CONFIG_REDBOOT 1 +#define CONFIG_REDBOOT_FLASH_SCRIPT_SIZE 512 +#define CONFIG_REDBOOT_FLASH_CONFIG_SIZE 65536 + +#ifndef __ASSEMBLY__ + +/* Damn RedBoot has a totally different bd_t */ +typedef struct redboot_bd_info { + unsigned int bi_tag; /* Should be 0x42444944 "BDID" */ + unsigned int bi_size; /* Size of this structure */ + unsigned int bi_revision; /* revision of this structure */ + unsigned int bi_bdate; /* bootstrap date, i.e. 0x19971106 */ + unsigned int bi_memstart; /* Memory start address */ + unsigned int bi_memsize; /* Memory (end) size in bytes */ + unsigned int bi_intfreq; /* Internal Freq, in Hz */ + unsigned int bi_busfreq; /* Bus Freq, in Hz */ + unsigned int bi_cpmfreq; /* CPM Freq, in Hz */ + unsigned int bi_brgfreq; /* BRG Freq, in Hz */ + unsigned int bi_vco; /* VCO Out from PLL */ + unsigned int bi_pci_freq; /* PCI Freq, in Hz */ + unsigned int bi_baudrate; /* Default console baud rate */ + unsigned int bi_immr; /* IMMR when called from boot rom */ + unsigned char bi_enetaddr[6]; + unsigned int bi_flashbase; /* Physical address of FLASH memory */ + unsigned int bi_flashsize; /* Length of FLASH memory */ + int bi_flashwidth; /* Width (8,16,32,64) */ + unsigned char *bi_cmdline; /* Pointer to command line */ + unsigned char bi_esa[3][6]; /* Ethernet station addresses */ + unsigned int bi_ramdisk_begin; + unsigned int bi_ramdisk_end; + struct { /* info about [main] video screen */ + short x_res; /* Horizontal resolution in pixels */ + short y_res; /* Vertical resolution in pixels */ + short bpp; /* Bits/pixel */ + short mode; /* Type of pixels (packed, indexed) */ + unsigned long fb; /* frame buffer (pixel) memory */ + } bi_video; + void (*bi_cputc)(char); /* Write a character */ + char (*bi_cgetc)(void); /* Read a character */ + int (*bi_ctstc)(void); /* Test for input */ +} redboot_bd_t; + +#endif + +#define CONFIG_REDBOOT_BD_T_SIZE sizeof(redboot_bd_t) + +/* + * Status LEDs + */ +#define CONFIG_STATUS_LED 1 /* Status LED enabled */ +#define CONFIG_BOARD_SPECIFIC_LED /* board has board specific leds */ + +#define STATUS_LED_BIT LED1 + +#define STATUS_LED_PERIOD (CFG_HZ / 2) +#define STATUS_LED_STATE STATUS_LED_BLINKING + +#define STATUS_LED_ACTIVE 1 /* LED on for bit == 0 */ +#define STATUS_LED_BOOT 0 /* LED 0 used for boot status */ + +#ifndef __ASSEMBLY__ + +/* LEDs */ + +/* led_id_t is unsigned int mask */ +typedef unsigned int led_id_t; + +#define __led_toggle(_msk) \ + do { \ + ((volatile immap_t *)CFG_IMMR)->pgio[0].dat ^= (_msk); \ + } while(0) + +#define __led_set(_msk, _st) \ + do { \ + if ((_st)) \ + ((volatile immap_t *)CFG_IMMR)->pgio[0].dat |= \ + (_msk); \ + else \ + ((volatile immap_t *)CFG_IMMR)->pgio[0].dat &= \ + ~(_msk); \ + } while(0) + +#define __led_init(msk, st) __led_set(msk, st) + +#endif + +/* + * GPIOS + */ + +/* easy powerpc bit defines */ +#define _B(x) (1 << (31 - (x))) + +/* GPIO1 */ +#define ECP_TMS _B(2) /* FPGA programming */ +#define ECP_TCK _B(3) +#define ECP_TDI _B(4) +#define ECP_TDO _B(5) +#define FPGA_RST _B(6) /* FPGA reset */ +#define USB0_RST _B(7) /* USB0 reset */ +#define USB1_RST _B(8) /* USB1 reset */ +#define LED1 _B(9) +#define LED2 _B(10) +#define LED3 _B(11) +#define LED4 _B(12) +#define LED_ALL (LED1 | LED2 | LED3 /* | LED4 */ ) + +/* GPIO2 */ +#define PHY1_RST _B(13) /* PHY1 reset */ +#define PHY2_RST _B(14) /* PHY2 reset */ +#define ETH_RST _B(19) /* Ethernet global reset */ +#define ETH_EN _B(18) /* Ethernet global enable */ + +#endif /* __CONFIG_H */

Add support for Analogue Micro's ASP8347DB board. The board is originally shipped with RedBoot. All appropriate settings are migrated to u-boot & the old kernel booted; a drop in bootloader replacement.
--- Signed-off-by: Pantelis Antoniou pantelis@embeddedalley.com ---
MAKEALL | 3 Makefile | 3 board/asp8347db/Makefile | 52 ++++++ board/asp8347db/asp8347db.c | 371 +++++++++++++++++++++++++++++++++++++++++++ board/asp8347db/config.mk | 23 +++ board/asp8347db/fpga.c | 240 ++++++++++++++++++++++++++++ board/asp8347db/pci.c | 222 ++++++++++++++++++++++++++ board/asp8347db/u-boot.lds | 122 ++++++++++++++ include/status_led.h | 2 9 files changed, 1037 insertions(+), 1 deletions(-)
diff --git a/MAKEALL b/MAKEALL index 74bf383..82ade78 100755 --- a/MAKEALL +++ b/MAKEALL @@ -130,7 +130,8 @@ LIST_8260=" \ #########################################################################
LIST_83xx=" \ - TQM834x MPC8349EMDS MPC8349ITX MPC8360EMDS \ + ASP8347DB TQM834x MPC8349EMDS MPC8349ITX \ + MPC8360EMDS \ "
diff --git a/Makefile b/Makefile index d2534ab..4e5a78d 100644 --- a/Makefile +++ b/Makefile @@ -1588,6 +1588,9 @@ r5200_config : unconfig ## MPC83xx Systems #########################################################################
+ASP8347DB_config: unconfig + @$(MKCONFIG) $(@:_config=) ppc mpc83xx asp8347db + TQM834x_config: unconfig @$(MKCONFIG) $(@:_config=) ppc mpc83xx tqm834x
diff --git a/board/asp8347db/Makefile b/board/asp8347db/Makefile new file mode 100644 index 0000000..a865a9b --- /dev/null +++ b/board/asp8347db/Makefile @@ -0,0 +1,52 @@ +# +# (C) Copyright 2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# Copyright 2004 Freescale Semiconductor, Inc. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(BOARD).a + +COBJS = $(BOARD).o fpga.o pci.o + +SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) +SOBJS := $(addprefix $(obj),$(SOBJS)) + +$(LIB): $(obj).depend $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +clean: + rm -f $(SOBJS) $(OBJS) + +distclean: clean + rm -f $(LIB) core *.bak .depend + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/board/asp8347db/asp8347db.c b/board/asp8347db/asp8347db.c new file mode 100644 index 0000000..10551d3 --- /dev/null +++ b/board/asp8347db/asp8347db.c @@ -0,0 +1,371 @@ +/* + * (C) Copyright 2006 + * Pantelis Antoniou, Embedded Alley, pantelis@embeddedalley.com + * + * Based on tqm384x.c by + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#define DEBUG + +#include <common.h> +#include <ioports.h> +#include <mpc83xx.h> +#include <asm/mpc8349_pci.h> +#include <i2c.h> +#include <spd.h> +#include <miiphy.h> +#include <asm-ppc/mmu.h> +#include <pci.h> + +#ifdef CONFIG_REDBOOT +#include <redboot.h> +#endif + +DECLARE_GLOBAL_DATA_PTR; + +#define IOSYNC asm("eieio") +#define ISYNC asm("isync") +#define SYNC asm("sync") +#define FPW FLASH_PORT_WIDTH +#define FPWV FLASH_PORT_WIDTHV + +#define DDR_MAX_SIZE_PER_CS 0x20000000 + +#define TIMING_CASLAT TIMING_CFG1_CASLAT_25 +#define MODE_CASLAT DDR_MODE_CASLAT_25 + +#define INITIAL_CS_CONFIG (CSCONFIG_EN | CSCONFIG_ROW_BIT_12 | \ + CSCONFIG_COL_BIT_9) + +/* External definitions */ +ulong flash_get_size (ulong base, int banknum); +extern flash_info_t flash_info[]; + +/* Local variable */ +static volatile immap_t *im = (immap_t *)CFG_IMMR; + +/************************************************************************** + * Board initialzation after relocation to RAM. Used to detect the number + * of Flash banks on TQM834x. + */ +int board_early_init_r (void) +{ + /* sanity check, IMMARBAR should be mirrored at offset zero of IMMR */ + if ((im->sysconf.immrbar & IMMRBAR_BASE_ADDR) != (u32)im) + return 0; + + /* setup GPIO ports */ + im->pgio[0].dat = 0xc5f00000; + im->pgio[0].odr = 0; + im->pgio[0].dir = 0x3a700000; + im->pgio[0].imr = 0; + im->pgio[0].icr = 0; + + im->pgio[1].dat = 0x00001000; + im->pgio[1].odr = 0; + im->pgio[1].dir = 0x00003000; + im->pgio[1].imr = 0; + im->pgio[1].icr = 0; + + /* turn on all LEDS */ + im->pgio[0].dat |= LED_ALL; + im->pgio[0].odr &= ~LED_ALL; + im->pgio[0].dir |= LED_ALL; + + /* reset & enable ethernet */ + udelay(100); + im->pgio[1].dat = (im->pgio[1].dat & ~ETH_RST) | ETH_EN; + udelay(100); + im->pgio[1].dat |= ETH_RST; + udelay(100); + im->pgio[1].dat &= ~ETH_EN; + udelay(100); + + /* reset PHYs */ + im->pgio[1].dat |= PHY1_RST | PHY2_RST; + udelay(250); + im->pgio[1].dat &= ~(PHY1_RST | PHY2_RST); + udelay(250); + + /* turn off all leds */ + im->pgio[0].dat &= ~LED_ALL; + + return 0; +} + +/************************************************************************** + * DRAM initalization and size detection + */ +long int initdram (int board_type) +{ + long size, known_size; + + /* 128MB */ + known_size = 128 << 20; + + im->sysconf.ddrlaw[0].bar = 0; + im->sysconf.ddrlaw[0].ar = 0; + + /* 128M */ + im->sysconf.ddrlaw[0].bar = CFG_DDR_BASE; + im->sysconf.ddrlaw[0].ar = LAWAR_EN | LAWAR_SIZE_128M; + im->sysconf.ddrlaw[1].bar = 0; + im->sysconf.ddrlaw[1].ar = 0; + + /* set CS bounds to 128M */ + im->ddr.sdram_cfg = 0x02000000; + im->ddr.csbnds[0].csbnds = 0x00000007; + im->ddr.csbnds[1].csbnds = 0; + im->ddr.csbnds[2].csbnds = 0; + im->ddr.csbnds[3].csbnds = 0; + im->ddr.cs_config[0] = 0x80800101; + im->ddr.cs_config[1] = 0; + im->ddr.cs_config[2] = 0; + im->ddr.cs_config[3] = 0; + im->ddr.timing_cfg_1 = 0x36332321; + im->ddr.timing_cfg_2 = 0x02000400; + im->ddr.sdram_cfg = 0x02000000; + im->ddr.sdram_mode = 0x00000062; + SYNC; + + im->ddr.sdram_interval = 0x03e80000; + im->ddr.sdram_clk_cntl = 0x81000000; + SYNC; + + /* the errata workaround from TQM does not work */ + /* I don't really know why, */ + + udelay(200); + + im->ddr.sdram_cfg = 0xc2000000; + SYNC; + + udelay(1000); + + /* size detection */ + debug("\n"); + size = get_ram_size(CFG_DDR_BASE, known_size); + if (size != known_size) + debug("Detected other size than what expected!\n"); + + return size; +} + +/************************************************************************** + * checkboard() + */ +int checkboard (void) +{ + puts("Board: ASP8347DB\n"); + +#ifdef CONFIG_PCI + volatile immap_t * immr; + u32 w, f; + + immr = (immap_t *)CFG_IMMR; + if (!(immr->reset.rcwh & RCWH_PCIHOST)) { + printf("PCI: NOT in host mode..?!\n"); + return 0; + } + + /* get bus width */ + w = 32; + if (immr->reset.rcwh & RCWH_PCI64) + w = 64; + + /* get clock */ + f = gd->pci_clk; + + printf("PCI1: %d bit, %d MHz\n", w, f / 1000000); +#else + printf("PCI: disabled\n"); +#endif + return 0; +} + +/* in fpga.c */ +extern int asp8347db_init_fpga(void); +extern int asp8347db_autoload_fpga(void); + +/* + * Miscellaneous intialization + */ +int misc_init_r (void) +{ +#ifdef CONFIG_FPGA + asp8347db_init_fpga(); +#endif + return 0; +} + +/* + * Final init hook before entering command loop. + */ +int last_stage_init (void) +{ +#ifdef CONFIG_REDBOOT + const char *s; + void *fis; + flash_info_t *info; + int migrated; + static const char *image_name = "ASP8347DB.FPGA"; + ulong fpga_image_base = 0, fpga_image_size = 0; + ulong redboot_linux_base = 0, redboot_linux_size = 0; + + /* we now migrate settings from redboot */ + /* only we locate the FIS */ + if ((s = getenv("redboot_migrated")) == NULL && *s != 'n' && + (fis = redboot_fis_get(1, -1, &info)) != NULL) { + + migrated = 0; + + printf("REDB.:"); + + /* first snarf the FPGA image location from the FIS */ + if (redboot_fis_setenv(info, fis, image_name, "flash_base", + "fpga_image_base") == 0 && + (s = getenv("fpga_image_base")) != NULL) + fpga_image_base = simple_strtoul(s, NULL, 16); + + if (redboot_fis_setenv(info, fis, image_name, "data_length", + "fpga_image_size") == 0 && + (s = getenv("fpga_image_size")) != NULL) + fpga_image_size = simple_strtoul(s, NULL, 16); + + if (fpga_image_base == 0 || fpga_image_size == 0) { + setenv("fpga_image_base", NULL); + setenv("fpga_image_size", NULL); + } else { + printf(" FPGA"); + migrated += 2; + } + + /* now get the ethernet addresses */ + if (redboot_config_setenv(info, fis, "ethaddr", + "tsec1_esa", NULL) == 0 && + getenv("ethaddr")) { + printf(" TSEC1"); + migrated++; + } + + if (redboot_config_setenv(info, fis, "eth1addr", + "tsec2_esa", NULL) == 0 && + getenv("eth1addr")) { + printf(" TSEC2"); + migrated++; + } + + /* now get the linux image */ + if (redboot_fis_setenv(info, fis, "Linux", "flash_base", + "redboot_linux_base") == 0 && + (s = getenv("redboot_linux_base")) != NULL) + redboot_linux_base = simple_strtoul(s, NULL, 16); + + if (redboot_fis_setenv(info, fis, "Linux", "data_length", + "redboot_linux_size") == 0 && + (s = getenv("redboot_linux_size")) != NULL) + redboot_linux_size = simple_strtoul(s, NULL, 16); + + if (redboot_linux_base == 0 || redboot_linux_size == 0) { + setenv("redboot_linux_base", NULL); + setenv("redboot_linux_size", NULL); + } else { + setenv("bootcmd", "redboot exec ${redboot_linux_base}"); + + printf(" Linux"); + migrated += 2; + } + + if (migrated > 0) { + printf(".\n"); + setenv("redboot_migrated", "y"); + } else { + printf("No variables migrated!\n"); + } + + } +#endif + +#ifdef CONFIG_FPGA + asp8347db_autoload_fpga(); +#endif + return 0; +} + +/* immediate return - no printing from redboot */ +volatile void __attribute__((noinline)) redboot_nothing(void) { } + +void board_redboot_bd_t_adapt(void *kbd, + ulong cmd_start, ulong cmd_end, + ulong initrd_start, ulong initrd_end) +{ + static bd_t ubd; + redboot_bd_t *rbd; + + /* keep u-boot's idea of a bd_t */ + ubd = *(bd_t *)kbd; + + /* point redboot bd at the old uboot space + * we make sure that the area is large enough to hold both + */ + rbd = kbd; + memset(rbd, 0, sizeof(*rbd)); + + /* now fill in redboot bd_t with the proper values */ + rbd->bi_tag = 0x42444944; + rbd->bi_size = sizeof(*rbd); + rbd->bi_revision = 0x0102; + rbd->bi_bdate = 0x04012005; + rbd->bi_memstart = ubd.bi_memstart; + rbd->bi_memsize = ubd.bi_memsize; + rbd->bi_baudrate = ubd.bi_baudrate; + rbd->bi_cmdline = (unsigned char *)cmd_start; + memcpy(rbd->bi_enetaddr, ubd.bi_enetaddr, 6); + memcpy(rbd->bi_esa[0], ubd.bi_enetaddr, 6); +#ifdef CONFIG_HAS_ETH1 + memcpy(rbd->bi_esa[1], ubd.bi_enet1addr, 6); +#endif +#ifdef CONFIG_HAS_ETH2 + memcpy(rbd->bi_esa[2], ubd.bi_enet2addr, 6); +#endif +#ifdef CONFIG_HAS_ETH3 + memcpy(rbd->bi_esa[3], ubd.bi_enet3addr, 6); +#endif + rbd->bi_ramdisk_begin = initrd_start; + rbd->bi_ramdisk_end = initrd_end; + rbd->bi_intfreq = ubd.bi_intfreq; + rbd->bi_busfreq = ubd.bi_busfreq; + rbd->bi_immr = ubd.bi_immrbar; + rbd->bi_flashbase = 0xf0000000; + rbd->bi_flashsize = 0x04000000; + rbd->bi_flashwidth = 16; + + /* I/O functions */ + /* we assume we don't overwrite them */ + /* we are running pretty low & the stack is */ + /* placed at the end of memory */ + rbd->bi_cputc = (void *)redboot_nothing; + rbd->bi_cgetc = (void *)redboot_nothing; + rbd->bi_ctstc = (void *)redboot_nothing; +} + diff --git a/board/asp8347db/config.mk b/board/asp8347db/config.mk new file mode 100644 index 0000000..c3c8574 --- /dev/null +++ b/board/asp8347db/config.mk @@ -0,0 +1,23 @@ +# +# Copyright 2004 Freescale Semiconductor, Inc. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +TEXT_BASE = 0xf0000000 diff --git a/board/asp8347db/fpga.c b/board/asp8347db/fpga.c new file mode 100644 index 0000000..389ec56 --- /dev/null +++ b/board/asp8347db/fpga.c @@ -0,0 +1,240 @@ +/* + * (C) Copyright 2006 - Embedded Alley Solutions Inc. + * by Pantelis Antoniou, pantelis@embeddedalley.com + * + * Based on board/asp8347db/fpga.c + * (C) Copyright 2002 + * by Rich Ireland, Enterasys Networks, rireland@enterasys.com. + * & Keith Outwater, keith_outwater@mvis.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/* + * EC FPGA configuration support for the ASP8437DB computer + */ + +#include <common.h> +#include <command.h> +#include <watchdog.h> +#include <flash.h> + +#include <lattice_ec.h> + +DECLARE_GLOBAL_DATA_PTR; + +#if (CONFIG_FPGA) + +#if 0 +#define ASP8437DB_FPGA_DEBUG +#endif + +#ifdef ASP8437DB_FPGA_DEBUG +#define PRINTF(fmt,args...) printf (fmt ,##args) +#else +#define PRINTF(fmt,args...) +#endif + +static void mdelay(int ms) +{ + ulong start = get_timer(0); + ulong delay; + + delay = (ms * CFG_HZ) / 1000; + while (get_timer(start) < delay) { + udelay (1000); + WATCHDOG_RESET(); /* Trigger watchdog, if needed */ + } +} + +int rattler_fpga_loaded = 0; + +/****************************************************************/ + +/* configure */ +static int rattler_pre_fn (int cookie) +{ + volatile immap_t *im = (immap_t *)CFG_IMMR; + + PRINTF ("%s:%d:\n", __FUNCTION__, __LINE__); + + im->pgio[0].dir &= ~(ECP_TMS | ECP_TCK | ECP_TDI | ECP_TDO | FPGA_RST); + im->pgio[0].dat |= ECP_TMS | ECP_TCK | ECP_TDI | FPGA_RST; + im->pgio[0].dir |= ECP_TMS | ECP_TCK | ECP_TDI | FPGA_RST; + + /* and now reset */ + im->pgio[0].dat |= FPGA_RST; + udelay(1000); + im->pgio[0].dat &= ~FPGA_RST; + + rattler_fpga_loaded = 0; + + return 0; +} + +static int rattler_post_fn (int cookie, int success) +{ + PRINTF ("%s:%d:\n", __FUNCTION__, __LINE__); + + if (!success) + return -1; + + /* FLASH LEDs so we know FPGA is alive */ + *(unsigned long *)(ASP8347DB_FPGA_BASE + 0xC) = 0x00; /* off */ + mdelay(1000); + *(unsigned long *)(ASP8347DB_FPGA_BASE + 0xC) = 0x55; /* toggle */ + mdelay(500); + *(unsigned long *)(ASP8347DB_FPGA_BASE + 0xC) = 0xAA; /* toggle */ + mdelay(500); + *(unsigned long *)(ASP8347DB_FPGA_BASE + 0xC) = 0x00; /* off */ + + rattler_fpga_loaded = 1; + + return 0; +} + +static void rattler_jtag_write_port_fn(int cookie, unsigned int pin, + unsigned int val) +{ + volatile immap_t *im = (immap_t *)CFG_IMMR; + u32 mask = 0; + + switch (pin) { + case LATTICE_JTAG_TDI: + mask = ECP_TDI; + break; + + case LATTICE_JTAG_TCK: + mask = ECP_TCK; + break; + + case LATTICE_JTAG_TMS: + mask = ECP_TMS; + break; + + case LATTICE_JTAG_RST: + mask = FPGA_RST; + break; + + case LATTICE_JTAG_CE: /* not present */ + break; + + default: + PRINTF("Illegal pin %d\n", pin); + break; + } + + /* not supported */ + if (mask == 0) + return; + + if (val) + im->pgio[0].dat |= mask; + else + im->pgio[0].dat &= ~mask; +} + +static int rattler_jtag_read_port_fn(int cookie) +{ + volatile immap_t *im = (immap_t *)CFG_IMMR; + + return !!(im->pgio[0].dat & ECP_TDO); +} + +/* Note that these are pointers to code that is in Flash. They will be + * relocated at runtime. + */ +static Lattice_EC_JTAG_fns fpga_fns = { + .pre = rattler_pre_fn, + .post = rattler_post_fn, + .jtag_write_port = rattler_jtag_write_port_fn, + .jtag_read_port = rattler_jtag_read_port_fn, +}; + +Lattice_desc fpga[CONFIG_FPGA_COUNT] = { + { + Lattice_EC, + lattice_jtag_mode, + 65536, /* XXX */ + &fpga_fns, + 0 } +}; + +/* + * Initialize the fpga. Return 1 on success, 0 on failure. + */ +int asp8347db_init_fpga(void) +{ + int i; + + PRINTF ("%s:%d: Initialize FPGA interface" + " (relocation offset = 0x%.8lx)\n", + __FUNCTION__, __LINE__, gd->reloc_off); + fpga_init (gd->reloc_off); + + for (i = 0; i < CONFIG_FPGA_COUNT; i++) { + PRINTF ("%s:%d: Adding fpga %d\n", __FUNCTION__, + __LINE__, i); + fpga_add (fpga_lattice, &fpga[i]); + } + return 1; +} + +extern int lattice_load (Lattice_desc * desc, void *buf, size_t bsize); + +/* + * Autoload the fpga. Return 1 on success, 0 on failure. + */ +int asp8347db_autoload_fpga(void) +{ + char *value; + ulong base = 0, size = 0; + int ret; + + /* disable autoload set? */ + value = getenv("fpga_autoload_disable"); + if (value && *value == 'y') { + printf("FPGA: Autoload disabled; load manually...\n"); + return 0; + } + + if ((value = getenv("fpga_image_base")) != NULL) + base = simple_strtoul(value, NULL, 16); + + if ((value = getenv("fpga_image_size")) != NULL) + size = simple_strtoul(value, NULL, 16); + + if (base == 0 || size == 0) { + PRINTF("FPGA image variables not found\n"); + return -1; + } + + PRINTF("Autoloading FPGA\n"); + + ret = lattice_load(&fpga[0], (void *)base, (size_t)size); + if (ret != 0) + PRINTF("Autoloading FPGA failed with error %d\n", ret); + + return ret; +} + +#endif + +/* vim: set ts=8 tw=78 sw=8: */ diff --git a/board/asp8347db/pci.c b/board/asp8347db/pci.c new file mode 100644 index 0000000..5ecf101 --- /dev/null +++ b/board/asp8347db/pci.c @@ -0,0 +1,222 @@ +/* + * (C) Copyright 2005 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include <asm/mmu.h> +#include <common.h> +#include <pci.h> + +#ifdef CONFIG_PCI + +/* System RAM mapped to PCI space */ +#define CONFIG_PCI_SYS_MEM_BUS CFG_SDRAM_BASE +#define CONFIG_PCI_SYS_MEM_PHYS CFG_SDRAM_BASE +#define CONFIG_PCI_SYS_MEM_SIZE (1024 * 1024 * 1024) + +#ifndef CONFIG_PCI_PNP +static struct pci_config_table pci_tqm834x_config_table[] = { + {PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + PCI_IDSEL_NUMBER, PCI_ANY_ID, + pci_cfgfunc_config_device, {PCI_ENET0_IOADDR, + PCI_ENET0_MEMADDR, + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER + } + }, + {} +}; +#endif + +static struct pci_controller pci1_hose = { +#ifndef CONFIG_PCI_PNP + config_table:pci_tqm834x_config_table, +#endif +}; + + +/************************************************************************** + * pci_init_board() + * + * NOTICE: MPC8349 internally has two PCI controllers (PCI1 and PCI2) but since + * per ASP8347DB design physical connections to external devices (PCI sockets) + * are routed only to the PCI1 we do not account for the second one - this code + * supports PCI1 module only. Should support for the PCI2 be required in the + * future it needs a separate pci_controller structure (above) and handling - + * please refer to other boards' implementation for dual PCI host controllers, + * for example board/Marvell/db64360/pci.c, pci_init_board() + * + */ +void +pci_init_board(void) +{ + volatile immap_t * immr; + volatile clk83xx_t * clk; + volatile law83xx_t * pci_law; + volatile pot83xx_t * pci_pot; + volatile pcictrl83xx_t * pci_ctrl; + volatile pciconf83xx_t * pci_conf; + u16 reg16; + u32 reg32; + struct pci_controller * hose; + + immr = (immap_t *)CFG_IMMR; + clk = (clk83xx_t *)&immr->clk; + pci_law = immr->sysconf.pcilaw; + pci_pot = immr->ios.pot; + pci_ctrl = immr->pci_ctrl; + pci_conf = immr->pci_conf; + + hose = &pci1_hose; + + /* + * Configure PCI controller and PCI_CLK_OUTPUT + */ + + /* + * WARNING! only PCI_CLK_OUTPUT1 is enabled here as this is the one + * line actually used for clocking all external PCI devices in TQM83xx. + * Enabling other PCI_CLK_OUTPUT lines may lead to board's hang for + * unknown reasons - particularly PCI_CLK_OUTPUT6 and PCI_CLK_OUTPUT7 + * are known to hang the board; this issue is under investigation + * (13 oct 05) + */ + reg32 = OCCR_PCICOE1; +#if 0 + /* enabling all PCI_CLK_OUTPUT lines HANGS the board... */ + reg32 = 0xff000000; +#endif + if (clk->spmr & SPMR_CKID) { + /* PCI Clock is half CONFIG_83XX_CLKIN so need to set up OCCR + * fields accordingly */ + reg32 |= (OCCR_PCI1CR | OCCR_PCI2CR); + + reg32 |= (OCCR_PCICD0 | OCCR_PCICD1 | OCCR_PCICD2 \ + | OCCR_PCICD3 | OCCR_PCICD4 | OCCR_PCICD5 \ + | OCCR_PCICD6 | OCCR_PCICD7); + } + + clk->occr = reg32; + udelay(2000); + + /* + * Release PCI RST Output signal + */ + pci_ctrl[0].gcr = 0; + udelay(2000); + pci_ctrl[0].gcr = 1; + udelay(2000); + + /* + * Configure PCI Local Access Windows + */ + pci_law[0].bar = CFG_PCI1_MEM_PHYS & LAWBAR_BAR; + pci_law[0].ar = LAWAR_EN | LAWAR_SIZE_512M; + + pci_law[1].bar = CFG_PCI1_IO_PHYS & LAWBAR_BAR; + pci_law[1].ar = LAWAR_EN | LAWAR_SIZE_16M; + + /* + * Configure PCI Outbound Translation Windows + */ + + /* PCI1 mem space */ + pci_pot[0].potar = (CFG_PCI1_MEM_BASE >> 12) & POTAR_TA_MASK; + pci_pot[0].pobar = (CFG_PCI1_MEM_PHYS >> 12) & POBAR_BA_MASK; + pci_pot[0].pocmr = POCMR_EN | (POCMR_CM_512M & POCMR_CM_MASK); + + /* PCI1 IO space */ + pci_pot[1].potar = (CFG_PCI1_IO_BASE >> 12) & POTAR_TA_MASK; + pci_pot[1].pobar = (CFG_PCI1_IO_PHYS >> 12) & POBAR_BA_MASK; + pci_pot[1].pocmr = POCMR_EN | POCMR_IO | (POCMR_CM_16M & POCMR_CM_MASK); + + /* + * Configure PCI Inbound Translation Windows + */ + + /* we need RAM mapped to PCI space for the devices to + * access main memory */ + pci_ctrl[0].pitar1 = 0x0; + pci_ctrl[0].pibar1 = 0x0; + pci_ctrl[0].piebar1 = 0x0; + pci_ctrl[0].piwar1 = PIWAR_EN | PIWAR_PF | \ + PIWAR_RTT_SNOOP | PIWAR_WTT_SNOOP | \ + PIWAR_IWS_256M; + + hose->first_busno = 0; + hose->last_busno = 0xff; + + /* PCI memory space */ + pci_set_region(hose->regions + 0, + CFG_PCI1_MEM_BASE, + CFG_PCI1_MEM_PHYS, + CFG_PCI1_MEM_SIZE, + PCI_REGION_MEM); + + /* PCI IO space */ + pci_set_region(hose->regions + 1, + CFG_PCI1_IO_BASE, + CFG_PCI1_IO_PHYS, + CFG_PCI1_IO_SIZE, + PCI_REGION_IO); + + /* System memory space */ + pci_set_region(hose->regions + 2, + CONFIG_PCI_SYS_MEM_BUS, + CONFIG_PCI_SYS_MEM_PHYS, + CONFIG_PCI_SYS_MEM_SIZE, + PCI_REGION_MEM | PCI_REGION_MEMORY); + + hose->region_count = 3; + + pci_setup_indirect(hose, + (CFG_IMMR+0x8300), + (CFG_IMMR+0x8304)); + + pci_register_hose(hose); + + /* + * Write to Command register + */ + reg16 = 0xff; + pci_hose_read_config_word (hose, PCI_BDF(0,0,0), PCI_COMMAND, + ®16); + reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; + pci_hose_write_config_word(hose, PCI_BDF(0,0,0), PCI_COMMAND, + reg16); + + /* + * Clear non-reserved bits in status register. + */ + pci_hose_write_config_word(hose, PCI_BDF(0,0,0), PCI_STATUS, + 0xffff); + pci_hose_write_config_byte(hose, PCI_BDF(0,0,0), PCI_LATENCY_TIMER, + 0x80); + +#ifdef CONFIG_PCI_SCAN_SHOW + printf("PCI: Bus Dev VenId DevId Class Int\n"); +#endif + /* + * Hose scan. + */ + hose->last_busno = pci_hose_scan(hose); +} +#endif /* CONFIG_PCI */ diff --git a/board/asp8347db/u-boot.lds b/board/asp8347db/u-boot.lds new file mode 100644 index 0000000..020cfa6 --- /dev/null +++ b/board/asp8347db/u-boot.lds @@ -0,0 +1,122 @@ +/* + * Copyright 2004 Freescale Semiconductor, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +OUTPUT_ARCH(powerpc) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) } + .rela.text : { *(.rela.text) } + .rel.data : { *(.rel.data) } + .rela.data : { *(.rela.data) } + .rel.rodata : { *(.rel.rodata) } + .rela.rodata : { *(.rela.rodata) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } + .plt : { *(.plt) } + .text : + { + cpu/mpc83xx/start.o (.text) + *(.text) + *(.fixup) + *(.got1) + . = ALIGN(16); + *(.rodata) + *(.rodata1) + *(.rodata.str1.4) + *(.eh_frame) + } + .fini : { *(.fini) } =0 + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + + /* Read-write section, merged into data segment: */ + . = (. + 0x0FFF) & 0xFFFFF000; + _erotext = .; + PROVIDE (erotext = .); + .reloc : + { + *(.got) + _GOT2_TABLE_ = .; + *(.got2) + _FIXUP_TABLE_ = .; + *(.fixup) + } + __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2; + __fixup_entries = (. - _FIXUP_TABLE_) >> 2; + + .data : + { + *(.data) + *(.data1) + *(.sdata) + *(.sdata2) + *(.dynamic) + CONSTRUCTORS + } + _edata = .; + PROVIDE (edata = .); + + . = .; + __u_boot_cmd_start = .; + .u_boot_cmd : { *(.u_boot_cmd) } + __u_boot_cmd_end = .; + + + . = .; + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + . = ALIGN(4096); + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(4096); + __init_end = .; + + __bss_start = .; + .bss : + { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); +} +ENTRY(_start) diff --git a/include/status_led.h b/include/status_led.h index db4c60f..52fb233 100644 --- a/include/status_led.h +++ b/include/status_led.h @@ -355,6 +355,8 @@ void status_led_set (int led, int state); # define STATUS_LED_ACTIVE 0 /* LED on for bit == 0 */ # define STATUS_LED_BOOT 0 /* LED 0 used for boot status */
+#elif defined(CONFIG_ASP8347DB) +/* XXX empty just to avoid the error */ #else # error Status LED configuration missing #endif

Update with my new email address, add as a maintainer of ASP8347DB. Also move NETVIA to unmaintained section.
--- Signed-off-by: Pantelis Antoniou pantelis@embeddedalley.com ---
MAINTAINERS | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS index ce20def..dfdf46c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -21,9 +21,9 @@ Greg Allen gallen@arlut.utexas.edu
UTX8245 MPC8245
-Pantelis Antoniou panto@intracom.gr +Pantelis Antoniou pantelis@embeddedalley.com
- NETVIA MPC8xx + ASP8347DB MPC834x
Reinhard Arlt reinhard.arlt@esd-electronics.com
@@ -368,6 +368,7 @@ Unknown / orphaned boards: IAD210 MPC8xx MBX MPC8xx MBX860T MPC8xx + NETVIA MPC8xx NX823 MPC8xx RPXClassic MPC8xx RPXlite MPC8xx
participants (1)
-
Pantelis Antoniou