Merge commit '3deca9d'
[platform/kernel/u-boot.git] / common / cmd_fpga.c
1 /*
2  * (C) Copyright 2000, 2001
3  * Rich Ireland, Enterasys Networks, rireland@enterasys.com.
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  *
23  */
24
25 /*
26  *  FPGA support
27  */
28 #include <common.h>
29 #include <command.h>
30 #if defined(CONFIG_CMD_NET)
31 #include <net.h>
32 #endif
33 #include <fpga.h>
34 #include <malloc.h>
35
36 #if 0
37 #define FPGA_DEBUG
38 #endif
39
40 #ifdef  FPGA_DEBUG
41 #define PRINTF(fmt,args...)     printf (fmt ,##args)
42 #else
43 #define PRINTF(fmt,args...)
44 #endif
45
46 /* Local functions */
47 static void fpga_usage (cmd_tbl_t * cmdtp);
48 static int fpga_get_op (char *opstr);
49
50 /* Local defines */
51 #define FPGA_NONE   -1
52 #define FPGA_INFO   0
53 #define FPGA_LOAD   1
54 #define FPGA_LOADB  2
55 #define FPGA_DUMP   3
56 #define FPGA_LOADMK 4
57
58 /* Convert bitstream data and load into the fpga */
59 int fpga_loadbitstream(unsigned long dev, char* fpgadata, size_t size)
60 {
61 #if (CONFIG_FPGA & CFG_FPGA_XILINX)
62         unsigned int length;
63         unsigned char* swapdata;
64         unsigned int swapsize;
65         char buffer[80];
66         unsigned char *ptr;
67         unsigned char *dataptr;
68         unsigned char data;
69         unsigned int i;
70         int rc;
71
72         dataptr = (unsigned char *)fpgadata;
73
74         /* skip the first bytes of the bitsteam, their meaning is unknown */
75         length = (*dataptr << 8) + *(dataptr+1);
76         dataptr+=2;
77         dataptr+=length;
78
79         /* get design name (identifier, length, string) */
80         length = (*dataptr << 8) + *(dataptr+1);
81         dataptr+=2;
82         if (*dataptr++ != 0x61) {
83                 PRINTF ("%s: Design name identifier not recognized in bitstream\n",
84                         __FUNCTION__ );
85                 return FPGA_FAIL;
86         }
87
88         length = (*dataptr << 8) + *(dataptr+1);
89         dataptr+=2;
90         for(i=0;i<length;i++)
91                 buffer[i]=*dataptr++;
92
93         printf("  design filename = \"%s\"\n", buffer);
94
95         /* get part number (identifier, length, string) */
96         if (*dataptr++ != 0x62) {
97                 printf("%s: Part number identifier not recognized in bitstream\n",
98                         __FUNCTION__ );
99                 return FPGA_FAIL;
100         }
101
102         length = (*dataptr << 8) + *(dataptr+1);
103         dataptr+=2;
104         for(i=0;i<length;i++)
105                 buffer[i]=*dataptr++;
106         printf("  part number = \"%s\"\n", buffer);
107
108         /* get date (identifier, length, string) */
109         if (*dataptr++ != 0x63) {
110                 printf("%s: Date identifier not recognized in bitstream\n",
111                        __FUNCTION__);
112                 return FPGA_FAIL;
113         }
114
115         length = (*dataptr << 8) + *(dataptr+1);
116         dataptr+=2;
117         for(i=0;i<length;i++)
118                 buffer[i]=*dataptr++;
119         printf("  date = \"%s\"\n", buffer);
120
121         /* get time (identifier, length, string) */
122         if (*dataptr++ != 0x64) {
123                 printf("%s: Time identifier not recognized in bitstream\n",__FUNCTION__);
124                 return FPGA_FAIL;
125         }
126
127         length = (*dataptr << 8) + *(dataptr+1);
128         dataptr+=2;
129         for(i=0;i<length;i++)
130                 buffer[i]=*dataptr++;
131         printf("  time = \"%s\"\n", buffer);
132
133         /* get fpga data length (identifier, length) */
134         if (*dataptr++ != 0x65) {
135                 printf("%s: Data length identifier not recognized in bitstream\n",
136                         __FUNCTION__);
137                 return FPGA_FAIL;
138         }
139         swapsize = ((unsigned int) *dataptr     <<24) +
140                    ((unsigned int) *(dataptr+1) <<16) +
141                    ((unsigned int) *(dataptr+2) <<8 ) +
142                    ((unsigned int) *(dataptr+3)     ) ;
143         dataptr+=4;
144         printf("  bytes in bitstream = %d\n", swapsize);
145
146         /* check consistency of length obtained */
147         if (swapsize >= size) {
148                 printf("%s: Could not find right length of data in bitstream\n",
149                         __FUNCTION__);
150                 return FPGA_FAIL;
151         }
152
153         /* allocate memory */
154         swapdata = (unsigned char *)malloc(swapsize);
155         if (swapdata == NULL) {
156                 printf("%s: Could not allocate %d bytes memory !\n",
157                         __FUNCTION__, swapsize);
158                 return FPGA_FAIL;
159         }
160
161         /* read data into memory and swap bits */
162         ptr = swapdata;
163         for (i = 0; i < swapsize; i++) {
164                 data = 0x00;
165                 data |= (*dataptr & 0x01) << 7;
166                 data |= (*dataptr & 0x02) << 5;
167                 data |= (*dataptr & 0x04) << 3;
168                 data |= (*dataptr & 0x08) << 1;
169                 data |= (*dataptr & 0x10) >> 1;
170                 data |= (*dataptr & 0x20) >> 3;
171                 data |= (*dataptr & 0x40) >> 5;
172                 data |= (*dataptr & 0x80) >> 7;
173                 *ptr++ = data;
174                 dataptr++;
175         }
176
177         rc = fpga_load(dev, swapdata, swapsize);
178         free(swapdata);
179         return rc;
180 #else
181         printf("Bitstream support only for Xilinx devices\n");
182         return FPGA_FAIL;
183 #endif
184 }
185
186 /* ------------------------------------------------------------------------- */
187 /* command form:
188  *   fpga <op> <device number> <data addr> <datasize>
189  * where op is 'load', 'dump', or 'info'
190  * If there is no device number field, the fpga environment variable is used.
191  * If there is no data addr field, the fpgadata environment variable is used.
192  * The info command requires no data address field.
193  */
194 int do_fpga (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
195 {
196         int op, dev = FPGA_INVALID_DEVICE;
197         size_t data_size = 0;
198         void *fpga_data = NULL;
199         char *devstr = getenv ("fpga");
200         char *datastr = getenv ("fpgadata");
201         int rc = FPGA_FAIL;
202
203         if (devstr)
204                 dev = (int) simple_strtoul (devstr, NULL, 16);
205         if (datastr)
206                 fpga_data = (void *) simple_strtoul (datastr, NULL, 16);
207
208         switch (argc) {
209         case 5:         /* fpga <op> <dev> <data> <datasize> */
210                 data_size = simple_strtoul (argv[4], NULL, 16);
211         case 4:         /* fpga <op> <dev> <data> */
212                 fpga_data = (void *) simple_strtoul (argv[3], NULL, 16);
213                 PRINTF ("%s: fpga_data = 0x%x\n", __FUNCTION__, (uint) fpga_data);
214         case 3:         /* fpga <op> <dev | data addr> */
215                 dev = (int) simple_strtoul (argv[2], NULL, 16);
216                 PRINTF ("%s: device = %d\n", __FUNCTION__, dev);
217                 /* FIXME - this is a really weak test */
218                 if ((argc == 3) && (dev > fpga_count ())) {     /* must be buffer ptr */
219                         PRINTF ("%s: Assuming buffer pointer in arg 3\n",
220                                 __FUNCTION__);
221                         fpga_data = (void *) dev;
222                         PRINTF ("%s: fpga_data = 0x%x\n",
223                                 __FUNCTION__, (uint) fpga_data);
224                         dev = FPGA_INVALID_DEVICE;      /* reset device num */
225                 }
226         case 2:         /* fpga <op> */
227                 op = (int) fpga_get_op (argv[1]);
228                 break;
229         default:
230                 PRINTF ("%s: Too many or too few args (%d)\n",
231                         __FUNCTION__, argc);
232                 op = FPGA_NONE; /* force usage display */
233                 break;
234         }
235
236         switch (op) {
237         case FPGA_NONE:
238                 fpga_usage (cmdtp);
239                 break;
240
241         case FPGA_INFO:
242                 rc = fpga_info (dev);
243                 break;
244
245         case FPGA_LOAD:
246                 rc = fpga_load (dev, fpga_data, data_size);
247                 break;
248
249         case FPGA_LOADB:
250                 rc = fpga_loadbitstream(dev, fpga_data, data_size);
251                 break;
252
253         case FPGA_LOADMK:
254                 {
255                         image_header_t header;
256                         image_header_t *hdr = &header;
257                         ulong   data;
258
259                         memmove (&header, (char *)fpga_data, sizeof(image_header_t));
260                         if (ntohl(hdr->ih_magic) != IH_MAGIC) {
261                                 puts ("Bad Magic Number\n");
262                                 return 1;
263                         }
264                         data = ((ulong)fpga_data + sizeof(image_header_t));
265                         data_size  = ntohl(hdr->ih_size);
266                         rc = fpga_load (dev, (void *)data, data_size);
267                 }
268                 break;
269
270         case FPGA_DUMP:
271                 rc = fpga_dump (dev, fpga_data, data_size);
272                 break;
273
274         default:
275                 printf ("Unknown operation\n");
276                 fpga_usage (cmdtp);
277                 break;
278         }
279         return (rc);
280 }
281
282 static void fpga_usage (cmd_tbl_t * cmdtp)
283 {
284         printf ("Usage:\n%s\n", cmdtp->usage);
285 }
286
287 /*
288  * Map op to supported operations.  We don't use a table since we
289  * would just have to relocate it from flash anyway.
290  */
291 static int fpga_get_op (char *opstr)
292 {
293         int op = FPGA_NONE;
294
295         if (!strcmp ("info", opstr)) {
296                 op = FPGA_INFO;
297         } else if (!strcmp ("loadb", opstr)) {
298                 op = FPGA_LOADB;
299         } else if (!strcmp ("load", opstr)) {
300                 op = FPGA_LOAD;
301         } else if (!strcmp ("loadmk", opstr)) {
302                 op = FPGA_LOADMK;
303         } else if (!strcmp ("dump", opstr)) {
304                 op = FPGA_DUMP;
305         }
306
307         if (op == FPGA_NONE) {
308                 printf ("Unknown fpga operation \"%s\"\n", opstr);
309         }
310         return op;
311 }
312
313 U_BOOT_CMD (fpga, 6, 1, do_fpga,
314             "fpga    - loadable FPGA image support\n",
315             "fpga [operation type] [device number] [image address] [image size]\n"
316             "fpga operations:\n"
317             "\tinfo\tlist known device information\n"
318             "\tload\tLoad device from memory buffer\n"
319             "\tloadb\tLoad device from bitstream buffer (Xilinx devices only)\n"
320             "\tloadmk\tLoad device generated with mkimage\n"
321             "\tdump\tLoad device to memory buffer\n");