]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/w7o/fpga.c
77e0a180227dcf4e352509d8235d5a2b68e95e3b
[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  * 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
16 static void
17 fpga_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
41 int
42 fpgaDownload(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
185 done:
186         return retval;
187 }
188
189 /* FPGA image is stored in flash */
190 extern flash_info_t flash_info[];
191
192 int 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
325 bad_image:
326         printf("\n       BAD FPGA image format @ %lx\n",
327                flash_info[1].start[0]);
328         log_warn(ERR_XIMAGE);
329 done:
330         return retval;
331 }
332
333 void 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 }