uboot/board/w7o/fpga.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2001
   3 * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com
   4 *  and
   5 * Bill Hunter, Wave 7 Optics, william.hunter@mediaone.net
   6 *
   7 * See file CREDITS for list of people who contributed to this
   8 * project.
   9 *
  10 * This program is free software; you can redistribute it and/or
  11 * modify it under the terms of the GNU General Public License as
  12 * published by the Free Software Foundation; either version 2 of
  13 * the License, or (at your option) any later version.
  14 *
  15 * This program is distributed in the hope that it will be useful,
  16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18 * GNU General Public License for more details.
  19 *
  20 * You should have received a copy of the GNU General Public License
  21 * along with this program; if not, write to the Free Software
  22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  23 * MA 02111-1307 USA
  24 */
  25#include <config.h>
  26#include <common.h>
  27#include "w7o.h"
  28#include <asm/processor.h>
  29#include "errors.h"
  30
  31static void
  32fpga_img_write(unsigned long *src, unsigned long len, unsigned short *daddr)
  33{
  34    unsigned long i;
  35    volatile unsigned long val;
  36    volatile unsigned short *dest = daddr;      /* volatile-bypass optimizer */
  37
  38    for (i = 0; i < len; i++, src++) {
  39        val = *src;
  40        *dest = (unsigned short)((val & 0xff000000L) >> 16);
  41        *dest = (unsigned short)((val & 0x00ff0000L) >> 8);
  42        *dest = (unsigned short)(val & 0x0000ff00L);
  43        *dest = (unsigned short)((val & 0x000000ffL) << 8);
  44    }
  45
  46    /* Terminate programming with 4 C clocks */
  47    dest = daddr;
  48    val = *(unsigned short *)dest;
  49    val = *(unsigned short *)dest;
  50    val = *(unsigned short *)dest;
  51    val = *(unsigned short *)dest;
  52
  53}
  54
  55
  56int
  57fpgaDownload(unsigned char *saddr,
  58             unsigned long size,
  59             unsigned short *daddr)
  60{
  61    int i;                                      /* index, intr disable flag */
  62    int start;                                  /* timer */
  63    unsigned long greg, grego;                  /* GPIO & output register */
  64    unsigned long length;                       /* image size in words */
  65    unsigned long *source;                      /* image source addr */
  66    unsigned short *dest;                       /* destination FPGA addr */
  67    volatile unsigned short *ndest;             /* temp dest FPGA addr */
  68    volatile unsigned short val;                /* temp val */
  69    unsigned long cnfg = GPIO_XCV_CNFG;         /* FPGA CNFG */
  70    unsigned long eirq = GPIO_XCV_IRQ;
  71    int retval = -1;                            /* Function return value */
  72
  73    /* Setup some basic values */
  74    length = (size / 4) + 1;                    /* size in words, rounding UP
  75                                                    is OK */
  76    source = (unsigned long *)saddr;
  77    dest = (unsigned short *)daddr;
  78
  79    /* Get DCR output register */
  80    grego = in32(PPC405GP_GPIO0_OR);
  81
  82    /* Reset FPGA */
  83    grego &= ~GPIO_XCV_PROG;                    /* PROG line low */
  84    out32(PPC405GP_GPIO0_OR, grego);
  85
  86    /* Setup timeout timer */
  87    start = get_timer(0);
  88
  89    /* Wait for FPGA init line */
  90    while(in32(PPC405GP_GPIO0_IR) & GPIO_XCV_INIT) { /* Wait INIT line low */
  91        /* Check for timeout - 100us max, so use 3ms */
  92        if (get_timer(start) > 3) {
  93            printf("     failed to start init.\n");
  94            log_warn(ERR_XINIT0);               /* Don't halt */
  95
  96            /* Reset line stays low */
  97            goto done;                          /* I like gotos... */
  98        }
  99    }
 100
 101    /* Unreset FPGA */
 102    grego |= GPIO_XCV_PROG;                     /* PROG line high */
 103    out32(PPC405GP_GPIO0_OR, grego);
 104
 105    /* Wait for FPGA end of init period .  */
 106    while(!(in32(PPC405GP_GPIO0_IR) & GPIO_XCV_INIT)) { /* Wait for INIT hi */
 107
 108        /* Check for timeout */
 109        if (get_timer(start) > 3) {
 110            printf("     failed to exit init.\n");
 111            log_warn(ERR_XINIT1);
 112
 113            /* Reset FPGA */
 114            grego &= ~GPIO_XCV_PROG;            /* PROG line low */
 115            out32(PPC405GP_GPIO0_OR, grego);
 116
 117            goto done;
 118        }
 119    }
 120
 121    /* Now program FPGA ... */
 122    ndest = dest;
 123    for (i = 0; i < CONFIG_NUM_FPGAS; i++) {
 124        /* Toggle IRQ/GPIO */
 125        greg = mfdcr(CPC0_CR0);                 /* get chip ctrl register */
 126        greg |= eirq;                           /* toggle irq/gpio */
 127        mtdcr(CPC0_CR0, greg);                  /*  ... just do it */
 128
 129        /* turn on open drain for CNFG */
 130        greg = in32(PPC405GP_GPIO0_ODR);        /* get open drain register */
 131        greg |= cnfg;                           /* CNFG open drain */
 132        out32(PPC405GP_GPIO0_ODR, greg);        /*  .. just do it */
 133
 134        /* Turn output enable on for CNFG */
 135        greg = in32(PPC405GP_GPIO0_TCR);        /* get tristate register */
 136        greg |= cnfg;                           /* CNFG tristate inactive */
 137        out32(PPC405GP_GPIO0_TCR, greg);        /*  ... just do it */
 138
 139        /* Setup FPGA for programming */
 140        grego &= ~cnfg;                         /* CONFIG line low */
 141        out32(PPC405GP_GPIO0_OR, grego);
 142
 143        /*
 144         * Program the FPGA
 145         */
 146        printf("\n       destination: 0x%lx ", (unsigned long)ndest);
 147
 148        fpga_img_write(source,  length,  (unsigned short *)ndest);
 149
 150        /* Done programming */
 151        grego |= cnfg;                          /* CONFIG line high */
 152        out32(PPC405GP_GPIO0_OR, grego);
 153
 154        /* Turn output enable OFF for CNFG */
 155        greg = in32(PPC405GP_GPIO0_TCR);        /* get tristate register */
 156        greg &= ~cnfg;                          /* CNFG tristate inactive */
 157        out32(PPC405GP_GPIO0_TCR, greg);        /*  ... just do it */
 158
 159        /* Toggle IRQ/GPIO */
 160        greg = mfdcr(CPC0_CR0);                 /* get chip ctrl register */
 161        greg &= ~eirq;                          /* toggle irq/gpio */
 162        mtdcr(CPC0_CR0, greg);                  /*  ... just do it */
 163
 164        ndest = (unsigned short *)((char *)ndest + 0x00100000L); /* XXX - Next FPGA addr */
 165        cnfg >>= 1;                             /* XXX - Next  */
 166        eirq >>= 1;
 167    }
 168
 169    /* Terminate programming with 4 C clocks */
 170    ndest = dest;
 171    for (i = 0; i < CONFIG_NUM_FPGAS; i++) {
 172        val = *ndest;
 173        val = *ndest;
 174        val = *ndest;
 175        val = *ndest;
 176        ndest = (unsigned short *)((char *)ndest + 0x00100000L);
 177    }
 178
 179    /* Setup timer */
 180    start = get_timer(0);
 181
 182    /* Wait for FPGA end of programming period .  */
 183    while(!(in32(PPC405GP_GPIO0_IR) & GPIO_XCV_DONE)) { /* Test DONE low */
 184
 185        /* Check for timeout */
 186        if (get_timer(start) > 3) {
 187            printf("     done failed to come high.\n");
 188            log_warn(ERR_XDONE1);
 189
 190            /* Reset FPGA */
 191            grego &= ~GPIO_XCV_PROG;            /* PROG line low */
 192            out32(PPC405GP_GPIO0_OR, grego);
 193
 194            goto done;
 195        }
 196    }
 197
 198    printf("\n       FPGA load succeeded\n");
 199    retval = 0;                                 /* Program OK */
 200
 201done:
 202    return retval;
 203}
 204
 205/* FPGA image is stored in flash */
 206extern flash_info_t    flash_info[];
 207
 208int init_fpga(void)
 209{
 210    unsigned int i,j,ptr;                       /* General purpose */
 211    unsigned char bufchar;                      /* General purpose character */
 212    unsigned char *buf;                         /* Start of image pointer */
 213    unsigned long len;                          /* Length of image */
 214    unsigned char *fn_buf;                      /* Start of filename string */
 215    unsigned int fn_len;                        /* Length of filename string */
 216    unsigned char *xcv_buf;                     /* Pointer to start of image */
 217    unsigned long xcv_len;                      /* Length of image */
 218    unsigned long crc;                          /* 30bit crc in image */
 219    unsigned long calc_crc;                     /* Calc'd 30bit crc */
 220    int retval = -1;
 221
 222    /* Tell the world what we are doing */
 223    printf("FPGA:  ");
 224
 225    /*
 226     * Get address of first sector where the FPGA
 227     * image is stored.
 228     */
 229    buf = (unsigned char *)flash_info[1].start[0];
 230
 231    /*
 232     * Get the stored image's CRC & length.
 233     */
 234    crc = *(unsigned long *)(buf+4);            /* CRC is first long word */
 235    len = *(unsigned long *)(buf+8);            /* Image len is next long */
 236
 237    /* Pedantic */
 238    if ((len < 0x133A4) || (len > 0x80000))
 239        goto bad_image;
 240
 241    /*
 242     * Get the file name pointer and length.
 243     */
 244    fn_len = (*(unsigned short *)(buf+12) & 0xff); /* filename length
 245                                                      is next short */
 246    fn_buf = buf + 14;
 247
 248    /*
 249     * Get the FPGA image pointer and length length.
 250     */
 251    xcv_buf = fn_buf + fn_len;                  /* pointer to fpga image */
 252    xcv_len = len - 14 - fn_len;                /* fpga image length */
 253
 254    /* Check for uninitialized FLASH */
 255    if ((strncmp((char *)buf, "w7o", 3)!=0) || (len > 0x0007ffffL) || (len == 0))
 256        goto bad_image;
 257
 258    /*
 259     * Calculate and Check the image's CRC.
 260     */
 261    calc_crc = crc32(0, xcv_buf, xcv_len);
 262    if (crc != calc_crc) {
 263        printf("\nfailed - bad CRC\n");
 264        goto done;
 265    }
 266
 267    /* Output the file name */
 268    printf("file name  : ");
 269    for (i=0;i<fn_len;i++) {
 270        bufchar = fn_buf[+i];
 271        if (bufchar<' ' || bufchar>'~') bufchar = '.';
 272        putc(bufchar);
 273    }
 274
 275    /*
 276     * find rest of display data
 277     */
 278    ptr = 15;                                   /* Offset to ncd filename
 279                                                   length in fpga image */
 280    j = xcv_buf[ptr];                           /* Get len of ncd filename */
 281    if (j > 32) goto bad_image;
 282    ptr = ptr + j + 3;                          /* skip ncd filename string +
 283                                                   3 bytes more bytes */
 284
 285    /*
 286     * output target device string
 287     */
 288    j = xcv_buf[ptr++] - 1;                     /* len of targ str less term */
 289    if (j > 32) goto bad_image;
 290    printf("\n       target     : ");
 291    for (i = 0; i < j; i++) {
 292        bufchar = (xcv_buf[ptr++]);
 293        if (bufchar<' ' || bufchar>'~') bufchar = '.';
 294        putc(bufchar);
 295    }
 296
 297    /*
 298     * output compilation date string and time string
 299     */
 300    ptr += 3;                                   /* skip 2 bytes */
 301    printf("\n       synth time : ");
 302    j = (xcv_buf[ptr++] - 1);                   /* len of date str less term */
 303    if (j > 32) goto bad_image;
 304    for (i = 0; i < j; i++) {
 305        bufchar = (xcv_buf[ptr++]);
 306        if (bufchar<' ' || bufchar>'~') bufchar = '.';
 307        putc(bufchar);
 308    }
 309
 310    ptr += 3;                                   /* Skip 2 bytes */
 311    printf(" - ");
 312    j = (xcv_buf[ptr++] - 1);                   /* slen = targ dev str len */
 313    if (j > 32) goto bad_image;
 314    for (i = 0; i < j; i++) {
 315        bufchar = (xcv_buf[ptr++]);
 316        if (bufchar<' ' || bufchar>'~') bufchar = '.';
 317        putc(bufchar);
 318    }
 319
 320    /*
 321     * output crc and length strings
 322     */
 323    printf("\n       len & crc  : 0x%lx  0x%lx", len, crc);
 324
 325    /*
 326     * Program the FPGA.
 327     */
 328    retval = fpgaDownload((unsigned char*)xcv_buf, xcv_len,
 329                          (unsigned short *)0xfd000000L);
 330    return retval;
 331
 332bad_image:
 333    printf("\n       BAD FPGA image format @ %lx\n", flash_info[1].start[0]);
 334    log_warn(ERR_XIMAGE);
 335done:
 336    return retval;
 337}
 338
 339void test_fpga(unsigned short *daddr)
 340{
 341    int i;
 342    volatile unsigned short *ndest = daddr;
 343
 344    for (i = 0; i < CONFIG_NUM_FPGAS; i++) {
 345#if defined(CONFIG_W7OLMG)
 346        ndest[0x7e] = 0x55aa;
 347        if (ndest[0x7e] != 0x55aa)
 348            log_warn(ERR_XRW1 + i);
 349        ndest[0x7e] = 0xaa55;
 350        if (ndest[0x7e] != 0xaa55)
 351            log_warn(ERR_XRW1 + i);
 352        ndest[0x7e] = 0xc318;
 353        if (ndest[0x7e] != 0xc318)
 354            log_warn(ERR_XRW1 + i);
 355
 356#elif defined(CONFIG_W7OLMC)
 357        ndest[0x800] = 0x55aa;
 358        ndest[0x801] = 0xaa55;
 359        ndest[0x802] = 0xc318;
 360        ndest[0x4800] = 0x55aa;
 361        ndest[0x4801] = 0xaa55;
 362        ndest[0x4802] = 0xc318;
 363        if ((ndest[0x800] != 0x55aa) ||
 364            (ndest[0x801] != 0xaa55) ||
 365            (ndest[0x802] != 0xc318))
 366            log_warn(ERR_XRW1 + (2 * i));       /* Auto gen error code */
 367        if ((ndest[0x4800] != 0x55aa) ||
 368            (ndest[0x4801] != 0xaa55) ||
 369            (ndest[0x4802] != 0xc318))
 370            log_warn(ERR_XRW2 + (2 * i));       /* Auto gen error code */
 371
 372#else
 373# error "Unknown W7O board configuration"
 374#endif
 375    }
 376
 377    printf("       FPGA ready\n");
 378    return;
 379}
 380