blob: 377a692f7dc3b2810500e020df420f91aaee30ee [file] [log] [blame]
wdenk4a9cbbe2002-08-27 09:48:53 +00001/*
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>
Jon Loeligerbaa26db2007-07-08 17:51:39 -050030#if defined(CONFIG_CMD_NET)
wdenk4a9cbbe2002-08-27 09:48:53 +000031#include <net.h>
32#endif
wdenk8bde7f72003-06-27 21:31:46 +000033#include <fpga.h>
wdenkc3d2b4b2005-01-22 18:13:04 +000034#include <malloc.h>
wdenk4a9cbbe2002-08-27 09:48:53 +000035
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
wdenk4a9cbbe2002-08-27 09:48:53 +000046/* Local functions */
wdenkd4ca31c2004-01-02 14:00:00 +000047static void fpga_usage (cmd_tbl_t * cmdtp);
48static int fpga_get_op (char *opstr);
wdenk4a9cbbe2002-08-27 09:48:53 +000049
50/* Local defines */
51#define FPGA_NONE -1
52#define FPGA_INFO 0
53#define FPGA_LOAD 1
wdenk30ce5ab2005-01-09 18:12:51 +000054#define FPGA_LOADB 2
wdenk4a9cbbe2002-08-27 09:48:53 +000055#define FPGA_DUMP 3
Stefan Roesef0ff4692006-08-15 14:15:51 +020056#define FPGA_LOADMK 4
wdenk4a9cbbe2002-08-27 09:48:53 +000057
wdenk30ce5ab2005-01-09 18:12:51 +000058/* Convert bitstream data and load into the fpga */
59int fpga_loadbitstream(unsigned long dev, char* fpgadata, size_t size)
60{
Grant Likely0d38eff2007-09-25 15:48:05 -060061#if (CONFIG_FPGA & CFG_FPGA_XILINX)
Wolfgang Denk8b019da2005-08-08 00:14:41 +020062 unsigned int length;
63 unsigned char* swapdata;
64 unsigned int swapsize;
wdenk30ce5ab2005-01-09 18:12:51 +000065 char buffer[80];
Wolfgang Denk8b019da2005-08-08 00:14:41 +020066 unsigned char *ptr;
67 unsigned char *dataptr;
68 unsigned char data;
69 unsigned int i;
wdenk30ce5ab2005-01-09 18:12:51 +000070 int rc;
71
Wolfgang Denk77ddac92005-10-13 16:45:02 +020072 dataptr = (unsigned char *)fpgadata;
wdenk30ce5ab2005-01-09 18:12:51 +000073
Wolfgang Denk8b019da2005-08-08 00:14:41 +020074 /* skip the first bytes of the bitsteam, their meaning is unknown */
75 length = (*dataptr << 8) + *(dataptr+1);
76 dataptr+=2;
77 dataptr+=length;
wdenk30ce5ab2005-01-09 18:12:51 +000078
79 /* get design name (identifier, length, string) */
Wolfgang Denk8b019da2005-08-08 00:14:41 +020080 length = (*dataptr << 8) + *(dataptr+1);
81 dataptr+=2;
wdenk30ce5ab2005-01-09 18:12:51 +000082 if (*dataptr++ != 0x61) {
Wolfgang Denk8b019da2005-08-08 00:14:41 +020083 PRINTF ("%s: Design name identifier not recognized in bitstream\n",
84 __FUNCTION__ );
wdenk30ce5ab2005-01-09 18:12:51 +000085 return FPGA_FAIL;
86 }
87
wdenka562e1b2005-01-09 18:21:42 +000088 length = (*dataptr << 8) + *(dataptr+1);
wdenk30ce5ab2005-01-09 18:12:51 +000089 dataptr+=2;
90 for(i=0;i<length;i++)
91 buffer[i]=*dataptr++;
wdenka562e1b2005-01-09 18:21:42 +000092
Wolfgang Denk8b019da2005-08-08 00:14:41 +020093 printf(" design filename = \"%s\"\n", buffer);
wdenk30ce5ab2005-01-09 18:12:51 +000094
95 /* get part number (identifier, length, string) */
96 if (*dataptr++ != 0x62) {
Wolfgang Denk8b019da2005-08-08 00:14:41 +020097 printf("%s: Part number identifier not recognized in bitstream\n",
98 __FUNCTION__ );
wdenk30ce5ab2005-01-09 18:12:51 +000099 return FPGA_FAIL;
100 }
wdenka562e1b2005-01-09 18:21:42 +0000101
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200102 length = (*dataptr << 8) + *(dataptr+1);
103 dataptr+=2;
wdenka562e1b2005-01-09 18:21:42 +0000104 for(i=0;i<length;i++)
wdenk30ce5ab2005-01-09 18:12:51 +0000105 buffer[i]=*dataptr++;
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200106 printf(" part number = \"%s\"\n", buffer);
wdenka562e1b2005-01-09 18:21:42 +0000107
wdenk30ce5ab2005-01-09 18:12:51 +0000108 /* get date (identifier, length, string) */
109 if (*dataptr++ != 0x63) {
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200110 printf("%s: Date identifier not recognized in bitstream\n",
111 __FUNCTION__);
wdenk30ce5ab2005-01-09 18:12:51 +0000112 return FPGA_FAIL;
113 }
wdenka562e1b2005-01-09 18:21:42 +0000114
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200115 length = (*dataptr << 8) + *(dataptr+1);
116 dataptr+=2;
wdenk30ce5ab2005-01-09 18:12:51 +0000117 for(i=0;i<length;i++)
118 buffer[i]=*dataptr++;
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200119 printf(" date = \"%s\"\n", buffer);
wdenk30ce5ab2005-01-09 18:12:51 +0000120
121 /* get time (identifier, length, string) */
122 if (*dataptr++ != 0x64) {
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200123 printf("%s: Time identifier not recognized in bitstream\n",__FUNCTION__);
wdenk30ce5ab2005-01-09 18:12:51 +0000124 return FPGA_FAIL;
125 }
wdenka562e1b2005-01-09 18:21:42 +0000126
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200127 length = (*dataptr << 8) + *(dataptr+1);
128 dataptr+=2;
wdenk30ce5ab2005-01-09 18:12:51 +0000129 for(i=0;i<length;i++)
130 buffer[i]=*dataptr++;
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200131 printf(" time = \"%s\"\n", buffer);
wdenka562e1b2005-01-09 18:21:42 +0000132
wdenk30ce5ab2005-01-09 18:12:51 +0000133 /* get fpga data length (identifier, length) */
134 if (*dataptr++ != 0x65) {
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200135 printf("%s: Data length identifier not recognized in bitstream\n",
136 __FUNCTION__);
wdenk30ce5ab2005-01-09 18:12:51 +0000137 return FPGA_FAIL;
138 }
Wolfgang Denk8f79e4c2005-08-10 15:14:32 +0200139 swapsize = ((unsigned int) *dataptr <<24) +
140 ((unsigned int) *(dataptr+1) <<16) +
141 ((unsigned int) *(dataptr+2) <<8 ) +
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200142 ((unsigned int) *(dataptr+3) ) ;
wdenk30ce5ab2005-01-09 18:12:51 +0000143 dataptr+=4;
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200144 printf(" bytes in bitstream = %d\n", swapsize);
wdenka562e1b2005-01-09 18:21:42 +0000145
wdenk30ce5ab2005-01-09 18:12:51 +0000146 /* check consistency of length obtained */
147 if (swapsize >= size) {
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200148 printf("%s: Could not find right length of data in bitstream\n",
149 __FUNCTION__);
wdenk30ce5ab2005-01-09 18:12:51 +0000150 return FPGA_FAIL;
151 }
wdenka562e1b2005-01-09 18:21:42 +0000152
wdenk30ce5ab2005-01-09 18:12:51 +0000153 /* allocate memory */
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200154 swapdata = (unsigned char *)malloc(swapsize);
wdenk30ce5ab2005-01-09 18:12:51 +0000155 if (swapdata == NULL) {
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200156 printf("%s: Could not allocate %d bytes memory !\n",
157 __FUNCTION__, swapsize);
wdenk30ce5ab2005-01-09 18:12:51 +0000158 return FPGA_FAIL;
159 }
wdenka562e1b2005-01-09 18:21:42 +0000160
wdenk30ce5ab2005-01-09 18:12:51 +0000161 /* 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
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200181 printf("Bitstream support only for Xilinx devices\n");
wdenk30ce5ab2005-01-09 18:12:51 +0000182 return FPGA_FAIL;
183#endif
184}
185
wdenk4a9cbbe2002-08-27 09:48:53 +0000186/* ------------------------------------------------------------------------- */
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 */
wdenkd4ca31c2004-01-02 14:00:00 +0000194int do_fpga (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
wdenk4a9cbbe2002-08-27 09:48:53 +0000195{
wdenkd4ca31c2004-01-02 14:00:00 +0000196 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;
wdenk4a9cbbe2002-08-27 09:48:53 +0000202
wdenkd4ca31c2004-01-02 14:00:00 +0000203 if (devstr)
204 dev = (int) simple_strtoul (devstr, NULL, 16);
205 if (datastr)
206 fpga_data = (void *) simple_strtoul (datastr, NULL, 16);
wdenk4a9cbbe2002-08-27 09:48:53 +0000207
wdenkd4ca31c2004-01-02 14:00:00 +0000208 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);
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200213 PRINTF ("%s: fpga_data = 0x%x\n", __FUNCTION__, (uint) fpga_data);
wdenkd4ca31c2004-01-02 14:00:00 +0000214 case 3: /* fpga <op> <dev | data addr> */
215 dev = (int) simple_strtoul (argv[2], NULL, 16);
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200216 PRINTF ("%s: device = %d\n", __FUNCTION__, dev);
wdenkd4ca31c2004-01-02 14:00:00 +0000217 /* FIXME - this is a really weak test */
218 if ((argc == 3) && (dev > fpga_count ())) { /* must be buffer ptr */
Wolfgang Denk8f79e4c2005-08-10 15:14:32 +0200219 PRINTF ("%s: Assuming buffer pointer in arg 3\n",
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200220 __FUNCTION__);
wdenkd4ca31c2004-01-02 14:00:00 +0000221 fpga_data = (void *) dev;
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200222 PRINTF ("%s: fpga_data = 0x%x\n",
223 __FUNCTION__, (uint) fpga_data);
wdenkd4ca31c2004-01-02 14:00:00 +0000224 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:
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200230 PRINTF ("%s: Too many or too few args (%d)\n",
231 __FUNCTION__, argc);
wdenkd4ca31c2004-01-02 14:00:00 +0000232 op = FPGA_NONE; /* force usage display */
233 break;
234 }
wdenk4a9cbbe2002-08-27 09:48:53 +0000235
wdenkd4ca31c2004-01-02 14:00:00 +0000236 switch (op) {
237 case FPGA_NONE:
238 fpga_usage (cmdtp);
239 break;
wdenk4a9cbbe2002-08-27 09:48:53 +0000240
wdenkd4ca31c2004-01-02 14:00:00 +0000241 case FPGA_INFO:
242 rc = fpga_info (dev);
243 break;
wdenk4a9cbbe2002-08-27 09:48:53 +0000244
wdenkd4ca31c2004-01-02 14:00:00 +0000245 case FPGA_LOAD:
246 rc = fpga_load (dev, fpga_data, data_size);
247 break;
wdenk4a9cbbe2002-08-27 09:48:53 +0000248
wdenk30ce5ab2005-01-09 18:12:51 +0000249 case FPGA_LOADB:
250 rc = fpga_loadbitstream(dev, fpga_data, data_size);
251 break;
252
Stefan Roesef0ff4692006-08-15 14:15:51 +0200253 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 }
Stefan Roese77d50342006-10-07 11:33:03 +0200264 data = ((ulong)fpga_data + sizeof(image_header_t));
Stefan Roesef0ff4692006-08-15 14:15:51 +0200265 data_size = ntohl(hdr->ih_size);
Stefan Roese77d50342006-10-07 11:33:03 +0200266 rc = fpga_load (dev, (void *)data, data_size);
Stefan Roesef0ff4692006-08-15 14:15:51 +0200267 }
268 break;
269
wdenkd4ca31c2004-01-02 14:00:00 +0000270 case FPGA_DUMP:
271 rc = fpga_dump (dev, fpga_data, data_size);
272 break;
wdenk4a9cbbe2002-08-27 09:48:53 +0000273
wdenkd4ca31c2004-01-02 14:00:00 +0000274 default:
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200275 printf ("Unknown operation\n");
wdenkd4ca31c2004-01-02 14:00:00 +0000276 fpga_usage (cmdtp);
277 break;
278 }
279 return (rc);
wdenk4a9cbbe2002-08-27 09:48:53 +0000280}
281
wdenkd4ca31c2004-01-02 14:00:00 +0000282static void fpga_usage (cmd_tbl_t * cmdtp)
wdenk4a9cbbe2002-08-27 09:48:53 +0000283{
wdenkd4ca31c2004-01-02 14:00:00 +0000284 printf ("Usage:\n%s\n", cmdtp->usage);
wdenk4a9cbbe2002-08-27 09:48:53 +0000285}
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 */
wdenkd4ca31c2004-01-02 14:00:00 +0000291static int fpga_get_op (char *opstr)
wdenk4a9cbbe2002-08-27 09:48:53 +0000292{
293 int op = FPGA_NONE;
294
295 if (!strcmp ("info", opstr)) {
296 op = FPGA_INFO;
wdenk30ce5ab2005-01-09 18:12:51 +0000297 } else if (!strcmp ("loadb", opstr)) {
298 op = FPGA_LOADB;
wdenkd4ca31c2004-01-02 14:00:00 +0000299 } else if (!strcmp ("load", opstr)) {
wdenk4a9cbbe2002-08-27 09:48:53 +0000300 op = FPGA_LOAD;
Stefan Roesef0ff4692006-08-15 14:15:51 +0200301 } else if (!strcmp ("loadmk", opstr)) {
302 op = FPGA_LOADMK;
wdenkd4ca31c2004-01-02 14:00:00 +0000303 } else if (!strcmp ("dump", opstr)) {
wdenk4a9cbbe2002-08-27 09:48:53 +0000304 op = FPGA_DUMP;
305 }
306
wdenkd4ca31c2004-01-02 14:00:00 +0000307 if (op == FPGA_NONE) {
wdenk4a9cbbe2002-08-27 09:48:53 +0000308 printf ("Unknown fpga operation \"%s\"\n", opstr);
309 }
310 return op;
311}
312
wdenkd4ca31c2004-01-02 14:00:00 +0000313U_BOOT_CMD (fpga, 6, 1, do_fpga,
wdenkdd875c72004-01-03 21:24:46 +0000314 "fpga - loadable FPGA image support\n",
wdenkd4ca31c2004-01-02 14:00:00 +0000315 "fpga [operation type] [device number] [image address] [image size]\n"
316 "fpga operations:\n"
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200317 "\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"
Stefan Roesef0ff4692006-08-15 14:15:51 +0200320 "\tloadmk\tLoad device generated with mkimage\n"
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200321 "\tdump\tLoad device to memory buffer\n");