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