mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-11-03 21:48:15 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			380 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			380 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * (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(PPC405GP_GPIO0_OR);
 | 
						|
 | 
						|
    /* Reset FPGA */
 | 
						|
    grego &= ~GPIO_XCV_PROG;			/* PROG line low */
 | 
						|
    out32(PPC405GP_GPIO0_OR, grego);
 | 
						|
 | 
						|
    /* Setup timeout timer */
 | 
						|
    start = get_timer(0);
 | 
						|
 | 
						|
    /* Wait for FPGA init line */
 | 
						|
    while(in32(PPC405GP_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(PPC405GP_GPIO0_OR, grego);
 | 
						|
 | 
						|
    /* Wait for FPGA end of init period .  */
 | 
						|
    while(!(in32(PPC405GP_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(PPC405GP_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(PPC405GP_GPIO0_ODR);	/* get open drain register */
 | 
						|
	greg |= cnfg;				/* CNFG open drain */
 | 
						|
	out32(PPC405GP_GPIO0_ODR, greg);	/*  .. just do it */
 | 
						|
 | 
						|
	/* Turn output enable on for CNFG */
 | 
						|
	greg = in32(PPC405GP_GPIO0_TCR);	/* get tristate register */
 | 
						|
	greg |= cnfg;				/* CNFG tristate inactive */
 | 
						|
	out32(PPC405GP_GPIO0_TCR, greg);	/*  ... just do it */
 | 
						|
 | 
						|
	/* Setup FPGA for programming */
 | 
						|
	grego &= ~cnfg;				/* CONFIG line low */
 | 
						|
	out32(PPC405GP_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(PPC405GP_GPIO0_OR, grego);
 | 
						|
 | 
						|
	/* Turn output enable OFF for CNFG */
 | 
						|
	greg = in32(PPC405GP_GPIO0_TCR);	/* get tristate register */
 | 
						|
	greg &= ~cnfg;				/* CNFG tristate inactive */
 | 
						|
	out32(PPC405GP_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(PPC405GP_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(PPC405GP_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((char *)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;
 | 
						|
}
 |