cmd_fpga.c 9.6 KB
Newer Older
W
wdenk 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/*
 * (C) Copyright 2000, 2001
 * Rich Ireland, Enterasys Networks, rireland@enterasys.com.
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 *
 */

/*
 *  FPGA support
 */
#include <common.h>
#include <command.h>
30
#if defined(CONFIG_CMD_NET)
W
wdenk 已提交
31 32
#include <net.h>
#endif
W
wdenk 已提交
33
#include <fpga.h>
W
wdenk 已提交
34
#include <malloc.h>
W
wdenk 已提交
35 36 37 38 39 40 41 42 43 44 45 46

#if 0
#define	FPGA_DEBUG
#endif

#ifdef	FPGA_DEBUG
#define	PRINTF(fmt,args...)	printf (fmt ,##args)
#else
#define PRINTF(fmt,args...)
#endif

/* Local functions */
W
wdenk 已提交
47
static int fpga_get_op (char *opstr);
W
wdenk 已提交
48 49 50 51 52

/* Local defines */
#define FPGA_NONE   -1
#define FPGA_INFO   0
#define FPGA_LOAD   1
W
wdenk 已提交
53
#define FPGA_LOADB  2
W
wdenk 已提交
54
#define FPGA_DUMP   3
S
Stefan Roese 已提交
55
#define FPGA_LOADMK 4
W
wdenk 已提交
56

W
wdenk 已提交
57 58 59
/* Convert bitstream data and load into the fpga */
int fpga_loadbitstream(unsigned long dev, char* fpgadata, size_t size)
{
60
#if defined(CONFIG_FPGA_XILINX)
61 62
	unsigned int length;
	unsigned int swapsize;
W
wdenk 已提交
63
	char buffer[80];
64 65
	unsigned char *dataptr;
	unsigned int i;
W
wdenk 已提交
66 67
	int rc;

W
Wolfgang Denk 已提交
68
	dataptr = (unsigned char *)fpgadata;
W
wdenk 已提交
69

70 71 72 73
	/* skip the first bytes of the bitsteam, their meaning is unknown */
	length = (*dataptr << 8) + *(dataptr+1);
	dataptr+=2;
	dataptr+=length;
W
wdenk 已提交
74 75

	/* get design name (identifier, length, string) */
76 77
	length = (*dataptr << 8) + *(dataptr+1);
	dataptr+=2;
W
wdenk 已提交
78
	if (*dataptr++ != 0x61) {
79 80
		PRINTF ("%s: Design name identifier not recognized in bitstream\n",
			__FUNCTION__ );
W
wdenk 已提交
81 82 83
		return FPGA_FAIL;
	}

W
wdenk 已提交
84
	length = (*dataptr << 8) + *(dataptr+1);
W
wdenk 已提交
85 86
	dataptr+=2;
	for(i=0;i<length;i++)
87
		buffer[i] = *dataptr++;
W
wdenk 已提交
88

89
	printf("  design filename = \"%s\"\n", buffer);
W
wdenk 已提交
90 91 92

	/* get part number (identifier, length, string) */
	if (*dataptr++ != 0x62) {
93 94
		printf("%s: Part number identifier not recognized in bitstream\n",
			__FUNCTION__ );
W
wdenk 已提交
95 96
		return FPGA_FAIL;
	}
W
wdenk 已提交
97

98 99
	length = (*dataptr << 8) + *(dataptr+1);
	dataptr+=2;
W
wdenk 已提交
100
	for(i=0;i<length;i++)
101
		buffer[i] = *dataptr++;
102
	printf("  part number = \"%s\"\n", buffer);
W
wdenk 已提交
103

W
wdenk 已提交
104 105
	/* get date (identifier, length, string) */
	if (*dataptr++ != 0x63) {
106 107
		printf("%s: Date identifier not recognized in bitstream\n",
		       __FUNCTION__);
W
wdenk 已提交
108 109
		return FPGA_FAIL;
	}
W
wdenk 已提交
110

111 112
	length = (*dataptr << 8) + *(dataptr+1);
	dataptr+=2;
W
wdenk 已提交
113
	for(i=0;i<length;i++)
114
		buffer[i] = *dataptr++;
115
	printf("  date = \"%s\"\n", buffer);
W
wdenk 已提交
116 117 118

	/* get time (identifier, length, string) */
	if (*dataptr++ != 0x64) {
119
		printf("%s: Time identifier not recognized in bitstream\n",__FUNCTION__);
W
wdenk 已提交
120 121
		return FPGA_FAIL;
	}
W
wdenk 已提交
122

123 124
	length = (*dataptr << 8) + *(dataptr+1);
	dataptr+=2;
W
wdenk 已提交
125
	for(i=0;i<length;i++)
126
		buffer[i] = *dataptr++;
127
	printf("  time = \"%s\"\n", buffer);
W
wdenk 已提交
128

W
wdenk 已提交
129 130
	/* get fpga data length (identifier, length) */
	if (*dataptr++ != 0x65) {
131 132
		printf("%s: Data length identifier not recognized in bitstream\n",
			__FUNCTION__);
W
wdenk 已提交
133 134
		return FPGA_FAIL;
	}
135 136 137
	swapsize = ((unsigned int) *dataptr     <<24) +
	           ((unsigned int) *(dataptr+1) <<16) +
	           ((unsigned int) *(dataptr+2) <<8 ) +
138
	           ((unsigned int) *(dataptr+3)     ) ;
W
wdenk 已提交
139
	dataptr+=4;
140
	printf("  bytes in bitstream = %d\n", swapsize);
W
wdenk 已提交
141

142
	rc = fpga_load(dev, dataptr, swapsize);
W
wdenk 已提交
143 144
	return rc;
#else
145
	printf("Bitstream support only for Xilinx devices\n");
W
wdenk 已提交
146 147 148 149
	return FPGA_FAIL;
#endif
}

W
wdenk 已提交
150 151 152 153 154 155 156 157
/* ------------------------------------------------------------------------- */
/* command form:
 *   fpga <op> <device number> <data addr> <datasize>
 * where op is 'load', 'dump', or 'info'
 * If there is no device number field, the fpga environment variable is used.
 * If there is no data addr field, the fpgadata environment variable is used.
 * The info command requires no data address field.
 */
158
int do_fpga (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
W
wdenk 已提交
159
{
W
wdenk 已提交
160 161 162 163 164 165
	int op, dev = FPGA_INVALID_DEVICE;
	size_t data_size = 0;
	void *fpga_data = NULL;
	char *devstr = getenv ("fpga");
	char *datastr = getenv ("fpgadata");
	int rc = FPGA_FAIL;
166
	int wrong_parms = 0;
167 168 169 170
#if defined (CONFIG_FIT)
	const char *fit_uname = NULL;
	ulong fit_addr;
#endif
W
wdenk 已提交
171 172 173 174 175 176 177 178 179

	if (devstr)
		dev = (int) simple_strtoul (devstr, NULL, 16);
	if (datastr)
		fpga_data = (void *) simple_strtoul (datastr, NULL, 16);

	switch (argc) {
	case 5:		/* fpga <op> <dev> <data> <datasize> */
		data_size = simple_strtoul (argv[4], NULL, 16);
180

W
wdenk 已提交
181
	case 4:		/* fpga <op> <dev> <data> */
182 183 184 185 186 187 188 189 190 191 192 193
#if defined(CONFIG_FIT)
		if (fit_parse_subimage (argv[3], (ulong)fpga_data,
					&fit_addr, &fit_uname)) {
			fpga_data = (void *)fit_addr;
			debug ("*  fpga: subimage '%s' from FIT image at 0x%08lx\n",
					fit_uname, fit_addr);
		} else
#endif
		{
			fpga_data = (void *) simple_strtoul (argv[3], NULL, 16);
			debug ("*  fpga: cmdline image address = 0x%08lx\n", (ulong)fpga_data);
		}
194
		PRINTF ("%s: fpga_data = 0x%x\n", __FUNCTION__, (uint) fpga_data);
195

W
wdenk 已提交
196 197
	case 3:		/* fpga <op> <dev | data addr> */
		dev = (int) simple_strtoul (argv[2], NULL, 16);
198
		PRINTF ("%s: device = %d\n", __FUNCTION__, dev);
W
wdenk 已提交
199 200
		/* FIXME - this is a really weak test */
		if ((argc == 3) && (dev > fpga_count ())) {	/* must be buffer ptr */
201
			PRINTF ("%s: Assuming buffer pointer in arg 3\n",
202
				__FUNCTION__);
203 204 205 206 207 208 209 210 211 212 213 214 215 216

#if defined(CONFIG_FIT)
			if (fit_parse_subimage (argv[2], (ulong)fpga_data,
						&fit_addr, &fit_uname)) {
				fpga_data = (void *)fit_addr;
				debug ("*  fpga: subimage '%s' from FIT image at 0x%08lx\n",
						fit_uname, fit_addr);
			} else
#endif
			{
				fpga_data = (void *) dev;
				debug ("*  fpga: cmdline image address = 0x%08lx\n", (ulong)fpga_data);
			}

217 218
			PRINTF ("%s: fpga_data = 0x%x\n",
				__FUNCTION__, (uint) fpga_data);
W
wdenk 已提交
219 220
			dev = FPGA_INVALID_DEVICE;	/* reset device num */
		}
221

W
wdenk 已提交
222 223 224
	case 2:		/* fpga <op> */
		op = (int) fpga_get_op (argv[1]);
		break;
225

W
wdenk 已提交
226
	default:
227 228
		PRINTF ("%s: Too many or too few args (%d)\n",
			__FUNCTION__, argc);
W
wdenk 已提交
229 230 231 232
		op = FPGA_NONE;	/* force usage display */
		break;
	}

233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
	if (dev == FPGA_INVALID_DEVICE) {
		puts("FPGA device not specified\n");
		op = FPGA_NONE;
	}

	switch (op) {
	case FPGA_NONE:
	case FPGA_INFO:
		break;
	case FPGA_LOAD:
	case FPGA_LOADB:
	case FPGA_DUMP:
		if (!fpga_data || !data_size)
			wrong_parms = 1;
		break;
	case FPGA_LOADMK:
		if (!fpga_data)
			wrong_parms = 1;
		break;
	}

	if (wrong_parms) {
		puts("Wrong parameters for FPGA request\n");
		op = FPGA_NONE;
	}

W
wdenk 已提交
259 260
	switch (op) {
	case FPGA_NONE:
261
		return cmd_usage(cmdtp);
W
wdenk 已提交
262 263 264 265 266 267 268 269 270

	case FPGA_INFO:
		rc = fpga_info (dev);
		break;

	case FPGA_LOAD:
		rc = fpga_load (dev, fpga_data, data_size);
		break;

W
wdenk 已提交
271 272 273 274
	case FPGA_LOADB:
		rc = fpga_loadbitstream(dev, fpga_data, data_size);
		break;

S
Stefan Roese 已提交
275
	case FPGA_LOADMK:
276
		switch (genimg_get_format (fpga_data)) {
277 278 279 280 281 282 283 284
		case IMAGE_FORMAT_LEGACY:
			{
				image_header_t *hdr = (image_header_t *)fpga_data;
				ulong	data;

				data = (ulong)image_get_data (hdr);
				data_size = image_get_data_size (hdr);
				rc = fpga_load (dev, (void *)data, data_size);
S
Stefan Roese 已提交
285
			}
286 287 288
			break;
#if defined(CONFIG_FIT)
		case IMAGE_FORMAT_FIT:
289 290 291
			{
				const void *fit_hdr = (const void *)fpga_data;
				int noffset;
292
				const void *fit_data;
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324

				if (fit_uname == NULL) {
					puts ("No FIT subimage unit name\n");
					return 1;
				}

				if (!fit_check_format (fit_hdr)) {
					puts ("Bad FIT image format\n");
					return 1;
				}

				/* get fpga component image node offset */
				noffset = fit_image_get_node (fit_hdr, fit_uname);
				if (noffset < 0) {
					printf ("Can't find '%s' FIT subimage\n", fit_uname);
					return 1;
				}

				/* verify integrity */
				if (!fit_image_check_hashes (fit_hdr, noffset)) {
					puts ("Bad Data Hash\n");
					return 1;
				}

				/* get fpga subimage data address and length */
				if (fit_image_get_data (fit_hdr, noffset, &fit_data, &data_size)) {
					puts ("Could not find fpga subimage data\n");
					return 1;
				}

				rc = fpga_load (dev, fit_data, data_size);
			}
325 326 327 328 329 330
			break;
#endif
		default:
			puts ("** Unknown image type\n");
			rc = FPGA_FAIL;
			break;
S
Stefan Roese 已提交
331 332 333
		}
		break;

W
wdenk 已提交
334 335 336 337 338
	case FPGA_DUMP:
		rc = fpga_dump (dev, fpga_data, data_size);
		break;

	default:
339
		printf ("Unknown operation\n");
340
		return cmd_usage(cmdtp);
W
wdenk 已提交
341 342
	}
	return (rc);
W
wdenk 已提交
343 344 345 346 347 348
}

/*
 * Map op to supported operations.  We don't use a table since we
 * would just have to relocate it from flash anyway.
 */
W
wdenk 已提交
349
static int fpga_get_op (char *opstr)
W
wdenk 已提交
350 351 352 353 354
{
	int op = FPGA_NONE;

	if (!strcmp ("info", opstr)) {
		op = FPGA_INFO;
W
wdenk 已提交
355 356
	} else if (!strcmp ("loadb", opstr)) {
		op = FPGA_LOADB;
W
wdenk 已提交
357
	} else if (!strcmp ("load", opstr)) {
W
wdenk 已提交
358
		op = FPGA_LOAD;
S
Stefan Roese 已提交
359 360
	} else if (!strcmp ("loadmk", opstr)) {
		op = FPGA_LOADMK;
W
wdenk 已提交
361
	} else if (!strcmp ("dump", opstr)) {
W
wdenk 已提交
362 363 364
		op = FPGA_DUMP;
	}

W
wdenk 已提交
365
	if (op == FPGA_NONE) {
W
wdenk 已提交
366 367 368 369 370
		printf ("Unknown fpga operation \"%s\"\n", opstr);
	}
	return op;
}

W
wdenk 已提交
371
U_BOOT_CMD (fpga, 6, 1, do_fpga,
372 373 374 375 376 377 378 379 380
	"loadable FPGA image support",
	"[operation type] [device number] [image address] [image size]\n"
	"fpga operations:\n"
	"  dump\t[dev]\t\t\tLoad device to memory buffer\n"
	"  info\t[dev]\t\t\tlist known device information\n"
	"  load\t[dev] [address] [size]\tLoad device from memory buffer\n"
	"  loadb\t[dev] [address] [size]\t"
	"Load device from bitstream buffer (Xilinx only)\n"
	"  loadmk [dev] [address]\tLoad device generated with mkimage"
381
#if defined(CONFIG_FIT)
382 383 384
	"\n"
	"\tFor loadmk operating on FIT format uImage address must include\n"
	"\tsubimage unit name in the form of addr:<subimg_uname>"
385 386
#endif
);