diff options
Diffstat (limited to 'board/w7o/fpga.c')
| -rw-r--r-- | board/w7o/fpga.c | 380 | 
1 files changed, 380 insertions, 0 deletions
| diff --git a/board/w7o/fpga.c b/board/w7o/fpga.c new file mode 100644 index 000000000..e84123b90 --- /dev/null +++ b/board/w7o/fpga.c @@ -0,0 +1,380 @@ +/* + * (C) Copyright 2001 + * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com + *  and + * Bill Hunter, Wave 7 Optics, william.hunter@mediaone.net + * + * 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 <config.h> +#include <common.h> +#include "w7o.h" +#include <asm/processor.h> +#include "errors.h" + +static void +fpga_img_write(unsigned long *src, unsigned long len, unsigned short *daddr) +{ +    unsigned long i; +    volatile unsigned long val; +    volatile unsigned short *dest = daddr;	/* volatile-bypass optimizer */ + +    for (i = 0; i < len; i++, src++) { +        val = *src; +        *dest = (unsigned short)((val & 0xff000000L) >> 16); +        *dest = (unsigned short)((val & 0x00ff0000L) >> 8); +        *dest = (unsigned short)(val & 0x0000ff00L); +        *dest = (unsigned short)((val & 0x000000ffL) << 8); +    } + +    /* Terminate programming with 4 C clocks */ +    dest = daddr; +    val = *(unsigned short *)dest; +    val = *(unsigned short *)dest; +    val = *(unsigned short *)dest; +    val = *(unsigned short *)dest; + +} + + +int +fpgaDownload(unsigned char *saddr, +	     unsigned long size, +	     unsigned short *daddr) +{ +    int i;					/* index, intr disable flag */ +    int start;					/* timer */ +    unsigned long greg, grego;			/* GPIO & output register */ +    unsigned long length;			/* image size in words */ +    unsigned long *source;			/* image source addr */ +    unsigned short *dest;			/* destination FPGA addr */ +    volatile unsigned short *ndest;		/* temp dest FPGA addr */ +    volatile unsigned short val;		/* temp val */ +    unsigned long cnfg = GPIO_XCV_CNFG;		/* FPGA CNFG */ +    unsigned long eirq = GPIO_XCV_IRQ; +    int retval = -1;				/* Function return value */ + +    /* Setup some basic values */ +    length = (size / 4) + 1;			/* size in words, rounding UP +						    is OK */ +    source = (unsigned long *)saddr; +    dest = (unsigned short *)daddr; + +    /* Get DCR output register */ +    grego = in32(IBM405GP_GPIO0_OR); + +    /* Reset FPGA */ +    grego &= ~GPIO_XCV_PROG;			/* PROG line low */ +    out32(IBM405GP_GPIO0_OR, grego); + +    /* Setup timeout timer */ +    start = get_timer(0); + +    /* Wait for FPGA init line */ +    while(in32(IBM405GP_GPIO0_IR) & GPIO_XCV_INIT) { /* Wait INIT line low */ +        /* Check for timeout - 100us max, so use 3ms */ +        if (get_timer(start) > 3) { +            printf("     failed to start init.\n"); +            log_warn(ERR_XINIT0);		/* Don't halt */ + +            /* Reset line stays low */ +            goto done;				/* I like gotos... */ +        } +    } + +    /* Unreset FPGA */ +    grego |= GPIO_XCV_PROG;			/* PROG line high */ +    out32(IBM405GP_GPIO0_OR, grego); + +    /* Wait for FPGA end of init period .  */ +    while(!(in32(IBM405GP_GPIO0_IR) & GPIO_XCV_INIT)) { /* Wait for INIT hi */ + +        /* Check for timeout */ +        if (get_timer(start) > 3) { +            printf("     failed to exit init.\n"); +            log_warn(ERR_XINIT1); + +            /* Reset FPGA */ +            grego &= ~GPIO_XCV_PROG;		/* PROG line low */ +            out32(IBM405GP_GPIO0_OR, grego); + +            goto done; +        } +    } + +    /* Now program FPGA ... */ +    ndest = dest; +    for (i = 0; i < CONFIG_NUM_FPGAS; i++) { +        /* Toggle IRQ/GPIO */ +        greg = mfdcr(CPC0_CR0);			/* get chip ctrl register */ +        greg |= eirq;				/* toggle irq/gpio */ +        mtdcr(CPC0_CR0, greg);			/*  ... just do it */ + +        /* turn on open drain for CNFG */ +        greg = in32(IBM405GP_GPIO0_ODR);	/* get open drain register */ +        greg |= cnfg;				/* CNFG open drain */ +        out32(IBM405GP_GPIO0_ODR, greg);	/*  .. just do it */ + +        /* Turn output enable on for CNFG */ +        greg = in32(IBM405GP_GPIO0_TCR);	/* get tristate register */ +        greg |= cnfg;				/* CNFG tristate inactive */ +        out32(IBM405GP_GPIO0_TCR, greg);	/*  ... just do it */ + +        /* Setup FPGA for programming */ +        grego &= ~cnfg;				/* CONFIG line low */ +        out32(IBM405GP_GPIO0_OR, grego); + +        /* +         * Program the FPGA +         */ +        printf("\n       destination: 0x%lx ", (unsigned long)ndest); + +        fpga_img_write(source,  length,  (unsigned short *)ndest); + +        /* Done programming */ +        grego |= cnfg;				/* CONFIG line high */ +        out32(IBM405GP_GPIO0_OR, grego); + +        /* Turn output enable OFF for CNFG */ +        greg = in32(IBM405GP_GPIO0_TCR);	/* get tristate register */ +        greg &= ~cnfg;				/* CNFG tristate inactive */ +        out32(IBM405GP_GPIO0_TCR, greg);	/*  ... just do it */ + +        /* Toggle IRQ/GPIO */ +        greg = mfdcr(CPC0_CR0);			/* get chip ctrl register */ +        greg &= ~eirq;				/* toggle irq/gpio */ +        mtdcr(CPC0_CR0, greg);			/*  ... just do it */ + +        ndest = (unsigned short *)((char *)ndest + 0x00100000L); /* XXX - Next FPGA addr */ +        cnfg >>= 1;				/* XXX - Next  */ +        eirq >>= 1; +    } + +    /* Terminate programming with 4 C clocks */ +    ndest = dest; +    for (i = 0; i < CONFIG_NUM_FPGAS; i++) { +        val = *ndest; +        val = *ndest; +        val = *ndest; +        val = *ndest; +        ndest = (unsigned short *)((char *)ndest + 0x00100000L); +    } + +    /* Setup timer */ +    start = get_timer(0); + +    /* Wait for FPGA end of programming period .  */ +    while(!(in32(IBM405GP_GPIO0_IR) & GPIO_XCV_DONE)) { /* Test DONE low */ + +        /* Check for timeout */ +        if (get_timer(start) > 3) { +            printf("     done failed to come high.\n"); +            log_warn(ERR_XDONE1); + +            /* Reset FPGA */ +            grego &= ~GPIO_XCV_PROG;		/* PROG line low */ +            out32(IBM405GP_GPIO0_OR, grego); + +            goto done; +        } +    } + +    printf("\n       FPGA load succeeded\n"); +    retval = 0;					/* Program OK */ + +done: +    return retval; +} + +/* FPGA image is stored in flash */ +extern flash_info_t    flash_info[]; + +int init_fpga(void) +{ +    unsigned int i,j,ptr;			/* General purpose */ +    unsigned char bufchar;			/* General purpose character */ +    unsigned char *buf;				/* Start of image pointer */ +    unsigned long len;				/* Length of image */ +    unsigned char *fn_buf;			/* Start of filename string */ +    unsigned int fn_len;			/* Length of filename string */ +    unsigned char *xcv_buf;			/* Pointer to start of image */ +    unsigned long xcv_len;			/* Length of image */ +    unsigned long crc;				/* 30bit crc in image */ +    unsigned long calc_crc;			/* Calc'd 30bit crc */ +    int retval = -1; + +    /* Tell the world what we are doing */ +    printf("FPGA:  "); + +    /* +     * Get address of first sector where the FPGA +     * image is stored. +     */ +    buf = (unsigned char *)flash_info[1].start[0]; + +    /* +     * Get the stored image's CRC & length. +     */ +    crc = *(unsigned long *)(buf+4);		/* CRC is first long word */ +    len = *(unsigned long *)(buf+8);		/* Image len is next long */ + +    /* Pedantic */ +    if ((len < 0x133A4) || (len > 0x80000)) +        goto bad_image; + +    /* +     * Get the file name pointer and length. +     */ +    fn_len = (*(unsigned short *)(buf+12) & 0xff); /* filename length +						      is next short */ +    fn_buf = buf + 14; + +    /* +     * Get the FPGA image pointer and length length. +     */ +    xcv_buf = fn_buf + fn_len;			/* pointer to fpga image */ +    xcv_len = len - 14 - fn_len;		/* fpga image length */ + +    /* Check for uninitialized FLASH */ +    if ((strncmp(buf, "w7o", 3)!=0) || (len > 0x0007ffffL) || (len == 0)) +	goto bad_image; + +    /* +     * Calculate and Check the image's CRC. +     */ +    calc_crc = crc32(0, xcv_buf, xcv_len); +    if (crc != calc_crc) { +        printf("\nfailed - bad CRC\n"); +        goto done; +    } + +    /* Output the file name */ +    printf("file name  : "); +    for (i=0;i<fn_len;i++) { +        bufchar = fn_buf[+i]; +        if (bufchar<' ' || bufchar>'~') bufchar = '.'; +        putc(bufchar); +    } + +    /* +     * find rest of display data +     */ +    ptr = 15;					/* Offset to ncd filename +						   length in fpga image */ +    j = xcv_buf[ptr];				/* Get len of ncd filename */ +    if (j > 32) goto bad_image; +    ptr = ptr + j + 3;				/* skip ncd filename string + +						   3 bytes more bytes */ + +    /* +     * output target device string +     */ +    j = xcv_buf[ptr++] - 1;			/* len of targ str less term */ +    if (j > 32) goto bad_image; +    printf("\n       target     : "); +    for (i = 0; i < j; i++) { +	bufchar = (xcv_buf[ptr++]); +	if (bufchar<' ' || bufchar>'~') bufchar = '.'; +	putc(bufchar); +    } + +    /* +     * output compilation date string and time string +     */ +    ptr += 3;					/* skip 2 bytes */ +    printf("\n       synth time : "); +    j = (xcv_buf[ptr++] - 1);			/* len of date str less term */ +    if (j > 32) goto bad_image; +    for (i = 0; i < j; i++) { +	bufchar = (xcv_buf[ptr++]); +	if (bufchar<' ' || bufchar>'~') bufchar = '.'; +	putc(bufchar); +    } + +    ptr += 3;					/* Skip 2 bytes */ +    printf(" - "); +    j = (xcv_buf[ptr++] - 1);			/* slen = targ dev str len */ +    if (j > 32) goto bad_image; +    for (i = 0; i < j; i++) { +	bufchar = (xcv_buf[ptr++]); +	if (bufchar<' ' || bufchar>'~') bufchar = '.'; +	putc(bufchar); +    } + +    /* +     * output crc and length strings +     */ +    printf("\n       len & crc  : 0x%lx  0x%lx", len, crc); + +    /* +     * Program the FPGA. +     */ +    retval = fpgaDownload((unsigned char*)xcv_buf, xcv_len, +                          (unsigned short *)0xfd000000L); +    return retval; + +bad_image: +    printf("\n       BAD FPGA image format @ %lx\n", flash_info[1].start[0]); +    log_warn(ERR_XIMAGE); +done: +    return retval; +} + +void test_fpga(unsigned short *daddr) +{ +    int i; +    volatile unsigned short *ndest = daddr; + +    for (i = 0; i < CONFIG_NUM_FPGAS; i++) { +#if defined(CONFIG_W7OLMG) +	ndest[0x7e] = 0x55aa; +	if (ndest[0x7e] != 0x55aa) +	    log_warn(ERR_XRW1 + i); +	ndest[0x7e] = 0xaa55; +	if (ndest[0x7e] != 0xaa55) +	    log_warn(ERR_XRW1 + i); +	ndest[0x7e] = 0xc318; +	if (ndest[0x7e] != 0xc318) +	    log_warn(ERR_XRW1 + i); + +#elif defined(CONFIG_W7OLMC) +	ndest[0x800] = 0x55aa; +	ndest[0x801] = 0xaa55; +	ndest[0x802] = 0xc318; +	ndest[0x4800] = 0x55aa; +	ndest[0x4801] = 0xaa55; +	ndest[0x4802] = 0xc318; +	if ((ndest[0x800] != 0x55aa) || +	    (ndest[0x801] != 0xaa55) || +	    (ndest[0x802] != 0xc318)) +	    log_warn(ERR_XRW1 + (2 * i));       /* Auto gen error code */ +	if ((ndest[0x4800] != 0x55aa) || +	    (ndest[0x4801] != 0xaa55) || +	    (ndest[0x4802] != 0xc318)) +	    log_warn(ERR_XRW2 + (2 * i));       /* Auto gen error code */ + +#else +# error "Unknown W7O board configuration" +#endif +    } + +    printf("       FPGA ready\n"); +    return; +} + |