blob: e32b29a01123864d0a726f568248602a93311c94 [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 Loeligera76adc82007-06-11 19:01:43 -050030#if (CONFIG_COMMANDS & CFG_CMD_NET) || 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
Jon Loeligera76adc82007-06-11 19:01:43 -050046#if defined (CONFIG_FPGA) && ((CONFIG_COMMANDS & CFG_CMD_FPGA ) || defined(CONFIG_CMD_FPGA))
wdenk4a9cbbe2002-08-27 09:48:53 +000047
48/* Local functions */
wdenkd4ca31c2004-01-02 14:00:00 +000049static void fpga_usage (cmd_tbl_t * cmdtp);
50static int fpga_get_op (char *opstr);
wdenk4a9cbbe2002-08-27 09:48:53 +000051
52/* Local defines */
53#define FPGA_NONE -1
54#define FPGA_INFO 0
55#define FPGA_LOAD 1
wdenk30ce5ab2005-01-09 18:12:51 +000056#define FPGA_LOADB 2
wdenk4a9cbbe2002-08-27 09:48:53 +000057#define FPGA_DUMP 3
Stefan Roesef0ff4692006-08-15 14:15:51 +020058#define FPGA_LOADMK 4
wdenk4a9cbbe2002-08-27 09:48:53 +000059
wdenk30ce5ab2005-01-09 18:12:51 +000060/* Convert bitstream data and load into the fpga */
61int fpga_loadbitstream(unsigned long dev, char* fpgadata, size_t size)
62{
Wolfgang Denk8b019da2005-08-08 00:14:41 +020063 unsigned int length;
64 unsigned char* swapdata;
65 unsigned int swapsize;
wdenk30ce5ab2005-01-09 18:12:51 +000066 char buffer[80];
Wolfgang Denk8b019da2005-08-08 00:14:41 +020067 unsigned char *ptr;
68 unsigned char *dataptr;
69 unsigned char data;
70 unsigned int i;
wdenk30ce5ab2005-01-09 18:12:51 +000071 int rc;
72
Wolfgang Denk77ddac92005-10-13 16:45:02 +020073 dataptr = (unsigned char *)fpgadata;
wdenk30ce5ab2005-01-09 18:12:51 +000074
75#if CFG_FPGA_XILINX
Wolfgang Denk8b019da2005-08-08 00:14:41 +020076 /* skip the first bytes of the bitsteam, their meaning is unknown */
77 length = (*dataptr << 8) + *(dataptr+1);
78 dataptr+=2;
79 dataptr+=length;
wdenk30ce5ab2005-01-09 18:12:51 +000080
81 /* get design name (identifier, length, string) */
Wolfgang Denk8b019da2005-08-08 00:14:41 +020082 length = (*dataptr << 8) + *(dataptr+1);
83 dataptr+=2;
wdenk30ce5ab2005-01-09 18:12:51 +000084 if (*dataptr++ != 0x61) {
Wolfgang Denk8b019da2005-08-08 00:14:41 +020085 PRINTF ("%s: Design name identifier not recognized in bitstream\n",
86 __FUNCTION__ );
wdenk30ce5ab2005-01-09 18:12:51 +000087 return FPGA_FAIL;
88 }
89
wdenka562e1b2005-01-09 18:21:42 +000090 length = (*dataptr << 8) + *(dataptr+1);
wdenk30ce5ab2005-01-09 18:12:51 +000091 dataptr+=2;
92 for(i=0;i<length;i++)
93 buffer[i]=*dataptr++;
wdenka562e1b2005-01-09 18:21:42 +000094
Wolfgang Denk8b019da2005-08-08 00:14:41 +020095 printf(" design filename = \"%s\"\n", buffer);
wdenk30ce5ab2005-01-09 18:12:51 +000096
97 /* get part number (identifier, length, string) */
98 if (*dataptr++ != 0x62) {
Wolfgang Denk8b019da2005-08-08 00:14:41 +020099 printf("%s: Part number identifier not recognized in bitstream\n",
100 __FUNCTION__ );
wdenk30ce5ab2005-01-09 18:12:51 +0000101 return FPGA_FAIL;
102 }
wdenka562e1b2005-01-09 18:21:42 +0000103
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200104 length = (*dataptr << 8) + *(dataptr+1);
105 dataptr+=2;
wdenka562e1b2005-01-09 18:21:42 +0000106 for(i=0;i<length;i++)
wdenk30ce5ab2005-01-09 18:12:51 +0000107 buffer[i]=*dataptr++;
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200108 printf(" part number = \"%s\"\n", buffer);
wdenka562e1b2005-01-09 18:21:42 +0000109
wdenk30ce5ab2005-01-09 18:12:51 +0000110 /* get date (identifier, length, string) */
111 if (*dataptr++ != 0x63) {
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200112 printf("%s: Date identifier not recognized in bitstream\n",
113 __FUNCTION__);
wdenk30ce5ab2005-01-09 18:12:51 +0000114 return FPGA_FAIL;
115 }
wdenka562e1b2005-01-09 18:21:42 +0000116
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200117 length = (*dataptr << 8) + *(dataptr+1);
118 dataptr+=2;
wdenk30ce5ab2005-01-09 18:12:51 +0000119 for(i=0;i<length;i++)
120 buffer[i]=*dataptr++;
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200121 printf(" date = \"%s\"\n", buffer);
wdenk30ce5ab2005-01-09 18:12:51 +0000122
123 /* get time (identifier, length, string) */
124 if (*dataptr++ != 0x64) {
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200125 printf("%s: Time identifier not recognized in bitstream\n",__FUNCTION__);
wdenk30ce5ab2005-01-09 18:12:51 +0000126 return FPGA_FAIL;
127 }
wdenka562e1b2005-01-09 18:21:42 +0000128
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200129 length = (*dataptr << 8) + *(dataptr+1);
130 dataptr+=2;
wdenk30ce5ab2005-01-09 18:12:51 +0000131 for(i=0;i<length;i++)
132 buffer[i]=*dataptr++;
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200133 printf(" time = \"%s\"\n", buffer);
wdenka562e1b2005-01-09 18:21:42 +0000134
wdenk30ce5ab2005-01-09 18:12:51 +0000135 /* get fpga data length (identifier, length) */
136 if (*dataptr++ != 0x65) {
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200137 printf("%s: Data length identifier not recognized in bitstream\n",
138 __FUNCTION__);
wdenk30ce5ab2005-01-09 18:12:51 +0000139 return FPGA_FAIL;
140 }
Wolfgang Denk8f79e4c2005-08-10 15:14:32 +0200141 swapsize = ((unsigned int) *dataptr <<24) +
142 ((unsigned int) *(dataptr+1) <<16) +
143 ((unsigned int) *(dataptr+2) <<8 ) +
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200144 ((unsigned int) *(dataptr+3) ) ;
wdenk30ce5ab2005-01-09 18:12:51 +0000145 dataptr+=4;
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200146 printf(" bytes in bitstream = %d\n", swapsize);
wdenka562e1b2005-01-09 18:21:42 +0000147
wdenk30ce5ab2005-01-09 18:12:51 +0000148 /* check consistency of length obtained */
149 if (swapsize >= size) {
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200150 printf("%s: Could not find right length of data in bitstream\n",
151 __FUNCTION__);
wdenk30ce5ab2005-01-09 18:12:51 +0000152 return FPGA_FAIL;
153 }
wdenka562e1b2005-01-09 18:21:42 +0000154
wdenk30ce5ab2005-01-09 18:12:51 +0000155 /* allocate memory */
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200156 swapdata = (unsigned char *)malloc(swapsize);
wdenk30ce5ab2005-01-09 18:12:51 +0000157 if (swapdata == NULL) {
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200158 printf("%s: Could not allocate %d bytes memory !\n",
159 __FUNCTION__, swapsize);
wdenk30ce5ab2005-01-09 18:12:51 +0000160 return FPGA_FAIL;
161 }
wdenka562e1b2005-01-09 18:21:42 +0000162
wdenk30ce5ab2005-01-09 18:12:51 +0000163 /* read data into memory and swap bits */
164 ptr = swapdata;
165 for (i = 0; i < swapsize; i++) {
166 data = 0x00;
167 data |= (*dataptr & 0x01) << 7;
168 data |= (*dataptr & 0x02) << 5;
169 data |= (*dataptr & 0x04) << 3;
170 data |= (*dataptr & 0x08) << 1;
171 data |= (*dataptr & 0x10) >> 1;
172 data |= (*dataptr & 0x20) >> 3;
173 data |= (*dataptr & 0x40) >> 5;
174 data |= (*dataptr & 0x80) >> 7;
175 *ptr++ = data;
176 dataptr++;
177 }
178
179 rc = fpga_load(dev, swapdata, swapsize);
180 free(swapdata);
181 return rc;
182#else
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200183 printf("Bitstream support only for Xilinx devices\n");
wdenk30ce5ab2005-01-09 18:12:51 +0000184 return FPGA_FAIL;
185#endif
186}
187
wdenk4a9cbbe2002-08-27 09:48:53 +0000188/* ------------------------------------------------------------------------- */
189/* command form:
190 * fpga <op> <device number> <data addr> <datasize>
191 * where op is 'load', 'dump', or 'info'
192 * If there is no device number field, the fpga environment variable is used.
193 * If there is no data addr field, the fpgadata environment variable is used.
194 * The info command requires no data address field.
195 */
wdenkd4ca31c2004-01-02 14:00:00 +0000196int do_fpga (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
wdenk4a9cbbe2002-08-27 09:48:53 +0000197{
wdenkd4ca31c2004-01-02 14:00:00 +0000198 int op, dev = FPGA_INVALID_DEVICE;
199 size_t data_size = 0;
200 void *fpga_data = NULL;
201 char *devstr = getenv ("fpga");
202 char *datastr = getenv ("fpgadata");
203 int rc = FPGA_FAIL;
wdenk4a9cbbe2002-08-27 09:48:53 +0000204
wdenkd4ca31c2004-01-02 14:00:00 +0000205 if (devstr)
206 dev = (int) simple_strtoul (devstr, NULL, 16);
207 if (datastr)
208 fpga_data = (void *) simple_strtoul (datastr, NULL, 16);
wdenk4a9cbbe2002-08-27 09:48:53 +0000209
wdenkd4ca31c2004-01-02 14:00:00 +0000210 switch (argc) {
211 case 5: /* fpga <op> <dev> <data> <datasize> */
212 data_size = simple_strtoul (argv[4], NULL, 16);
213 case 4: /* fpga <op> <dev> <data> */
214 fpga_data = (void *) simple_strtoul (argv[3], NULL, 16);
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200215 PRINTF ("%s: fpga_data = 0x%x\n", __FUNCTION__, (uint) fpga_data);
wdenkd4ca31c2004-01-02 14:00:00 +0000216 case 3: /* fpga <op> <dev | data addr> */
217 dev = (int) simple_strtoul (argv[2], NULL, 16);
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200218 PRINTF ("%s: device = %d\n", __FUNCTION__, dev);
wdenkd4ca31c2004-01-02 14:00:00 +0000219 /* FIXME - this is a really weak test */
220 if ((argc == 3) && (dev > fpga_count ())) { /* must be buffer ptr */
Wolfgang Denk8f79e4c2005-08-10 15:14:32 +0200221 PRINTF ("%s: Assuming buffer pointer in arg 3\n",
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200222 __FUNCTION__);
wdenkd4ca31c2004-01-02 14:00:00 +0000223 fpga_data = (void *) dev;
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200224 PRINTF ("%s: fpga_data = 0x%x\n",
225 __FUNCTION__, (uint) fpga_data);
wdenkd4ca31c2004-01-02 14:00:00 +0000226 dev = FPGA_INVALID_DEVICE; /* reset device num */
227 }
228 case 2: /* fpga <op> */
229 op = (int) fpga_get_op (argv[1]);
230 break;
231 default:
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200232 PRINTF ("%s: Too many or too few args (%d)\n",
233 __FUNCTION__, argc);
wdenkd4ca31c2004-01-02 14:00:00 +0000234 op = FPGA_NONE; /* force usage display */
235 break;
236 }
wdenk4a9cbbe2002-08-27 09:48:53 +0000237
wdenkd4ca31c2004-01-02 14:00:00 +0000238 switch (op) {
239 case FPGA_NONE:
240 fpga_usage (cmdtp);
241 break;
wdenk4a9cbbe2002-08-27 09:48:53 +0000242
wdenkd4ca31c2004-01-02 14:00:00 +0000243 case FPGA_INFO:
244 rc = fpga_info (dev);
245 break;
wdenk4a9cbbe2002-08-27 09:48:53 +0000246
wdenkd4ca31c2004-01-02 14:00:00 +0000247 case FPGA_LOAD:
248 rc = fpga_load (dev, fpga_data, data_size);
249 break;
wdenk4a9cbbe2002-08-27 09:48:53 +0000250
wdenk30ce5ab2005-01-09 18:12:51 +0000251 case FPGA_LOADB:
252 rc = fpga_loadbitstream(dev, fpga_data, data_size);
253 break;
254
Stefan Roesef0ff4692006-08-15 14:15:51 +0200255 case FPGA_LOADMK:
256 {
257 image_header_t header;
258 image_header_t *hdr = &header;
259 ulong data;
260
261 memmove (&header, (char *)fpga_data, sizeof(image_header_t));
262 if (ntohl(hdr->ih_magic) != IH_MAGIC) {
263 puts ("Bad Magic Number\n");
264 return 1;
265 }
Stefan Roese77d50342006-10-07 11:33:03 +0200266 data = ((ulong)fpga_data + sizeof(image_header_t));
Stefan Roesef0ff4692006-08-15 14:15:51 +0200267 data_size = ntohl(hdr->ih_size);
Stefan Roese77d50342006-10-07 11:33:03 +0200268 rc = fpga_load (dev, (void *)data, data_size);
Stefan Roesef0ff4692006-08-15 14:15:51 +0200269 }
270 break;
271
wdenkd4ca31c2004-01-02 14:00:00 +0000272 case FPGA_DUMP:
273 rc = fpga_dump (dev, fpga_data, data_size);
274 break;
wdenk4a9cbbe2002-08-27 09:48:53 +0000275
wdenkd4ca31c2004-01-02 14:00:00 +0000276 default:
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200277 printf ("Unknown operation\n");
wdenkd4ca31c2004-01-02 14:00:00 +0000278 fpga_usage (cmdtp);
279 break;
280 }
281 return (rc);
wdenk4a9cbbe2002-08-27 09:48:53 +0000282}
283
wdenkd4ca31c2004-01-02 14:00:00 +0000284static void fpga_usage (cmd_tbl_t * cmdtp)
wdenk4a9cbbe2002-08-27 09:48:53 +0000285{
wdenkd4ca31c2004-01-02 14:00:00 +0000286 printf ("Usage:\n%s\n", cmdtp->usage);
wdenk4a9cbbe2002-08-27 09:48:53 +0000287}
288
289/*
290 * Map op to supported operations. We don't use a table since we
291 * would just have to relocate it from flash anyway.
292 */
wdenkd4ca31c2004-01-02 14:00:00 +0000293static int fpga_get_op (char *opstr)
wdenk4a9cbbe2002-08-27 09:48:53 +0000294{
295 int op = FPGA_NONE;
296
297 if (!strcmp ("info", opstr)) {
298 op = FPGA_INFO;
wdenk30ce5ab2005-01-09 18:12:51 +0000299 } else if (!strcmp ("loadb", opstr)) {
300 op = FPGA_LOADB;
wdenkd4ca31c2004-01-02 14:00:00 +0000301 } else if (!strcmp ("load", opstr)) {
wdenk4a9cbbe2002-08-27 09:48:53 +0000302 op = FPGA_LOAD;
Stefan Roesef0ff4692006-08-15 14:15:51 +0200303 } else if (!strcmp ("loadmk", opstr)) {
304 op = FPGA_LOADMK;
wdenkd4ca31c2004-01-02 14:00:00 +0000305 } else if (!strcmp ("dump", opstr)) {
wdenk4a9cbbe2002-08-27 09:48:53 +0000306 op = FPGA_DUMP;
307 }
308
wdenkd4ca31c2004-01-02 14:00:00 +0000309 if (op == FPGA_NONE) {
wdenk4a9cbbe2002-08-27 09:48:53 +0000310 printf ("Unknown fpga operation \"%s\"\n", opstr);
311 }
312 return op;
313}
314
wdenkd4ca31c2004-01-02 14:00:00 +0000315U_BOOT_CMD (fpga, 6, 1, do_fpga,
wdenkdd875c72004-01-03 21:24:46 +0000316 "fpga - loadable FPGA image support\n",
wdenkd4ca31c2004-01-02 14:00:00 +0000317 "fpga [operation type] [device number] [image address] [image size]\n"
318 "fpga operations:\n"
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200319 "\tinfo\tlist known device information\n"
320 "\tload\tLoad device from memory buffer\n"
321 "\tloadb\tLoad device from bitstream buffer (Xilinx devices only)\n"
Stefan Roesef0ff4692006-08-15 14:15:51 +0200322 "\tloadmk\tLoad device generated with mkimage\n"
Wolfgang Denk8b019da2005-08-08 00:14:41 +0200323 "\tdump\tLoad device to memory buffer\n");
wdenkd4ca31c2004-01-02 14:00:00 +0000324#endif /* CONFIG_FPGA && CONFIG_COMMANDS & CFG_CMD_FPGA */