]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/w7o/fpga.c
Initial revision
[karo-tx-uboot.git] / board / w7o / fpga.c
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
31 static void
32 fpga_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
56 int
57 fpgaDownload(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(IBM405GP_GPIO0_OR);
81
82     /* Reset FPGA */
83     grego &= ~GPIO_XCV_PROG;                    /* PROG line low */
84     out32(IBM405GP_GPIO0_OR, grego);
85
86     /* Setup timeout timer */
87     start = get_timer(0);
88
89     /* Wait for FPGA init line */
90     while(in32(IBM405GP_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(IBM405GP_GPIO0_OR, grego);
104
105     /* Wait for FPGA end of init period .  */
106     while(!(in32(IBM405GP_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(IBM405GP_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(IBM405GP_GPIO0_ODR);        /* get open drain register */
131         greg |= cnfg;                           /* CNFG open drain */
132         out32(IBM405GP_GPIO0_ODR, greg);        /*  .. just do it */
133
134         /* Turn output enable on for CNFG */
135         greg = in32(IBM405GP_GPIO0_TCR);        /* get tristate register */
136         greg |= cnfg;                           /* CNFG tristate inactive */
137         out32(IBM405GP_GPIO0_TCR, greg);        /*  ... just do it */
138
139         /* Setup FPGA for programming */
140         grego &= ~cnfg;                         /* CONFIG line low */
141         out32(IBM405GP_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(IBM405GP_GPIO0_OR, grego);
153
154         /* Turn output enable OFF for CNFG */
155         greg = in32(IBM405GP_GPIO0_TCR);        /* get tristate register */
156         greg &= ~cnfg;                          /* CNFG tristate inactive */
157         out32(IBM405GP_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(IBM405GP_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(IBM405GP_GPIO0_OR, grego);
193
194             goto done;
195         }
196     }
197
198     printf("\n       FPGA load succeeded\n");
199     retval = 0;                                 /* Program OK */
200
201 done:
202     return retval;
203 }
204
205 /* FPGA image is stored in flash */
206 extern flash_info_t    flash_info[];
207
208 int 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(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
332 bad_image:
333     printf("\n       BAD FPGA image format @ %lx\n", flash_info[1].start[0]);
334     log_warn(ERR_XIMAGE);
335 done:
336     return retval;
337 }
338
339 void 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