]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
4a9cbbe8 WD |
2 | /* |
3 | * (C) Copyright 2000, 2001 | |
4 | * Rich Ireland, Enterasys Networks, [email protected]. | |
4a9cbbe8 WD |
5 | */ |
6 | ||
7 | /* | |
8 | * FPGA support | |
9 | */ | |
10 | #include <common.h> | |
11 | #include <command.h> | |
7b51b576 | 12 | #include <env.h> |
8bde7f77 | 13 | #include <fpga.h> |
1a897668 | 14 | #include <fs.h> |
0c670fc1 | 15 | #include <gzip.h> |
4d72caa5 | 16 | #include <image.h> |
f7ae49fc | 17 | #include <log.h> |
c3d2b4b4 | 18 | #include <malloc.h> |
4a9cbbe8 | 19 | |
f4c7a4ae MS |
20 | static long do_fpga_get_device(char *arg) |
21 | { | |
22 | long dev = FPGA_INVALID_DEVICE; | |
23 | char *devstr = env_get("fpga"); | |
24 | ||
25 | if (devstr) | |
26 | /* Should be strtol to handle -1 cases */ | |
27 | dev = simple_strtol(devstr, NULL, 16); | |
28 | ||
8c75f794 | 29 | if (dev == FPGA_INVALID_DEVICE && arg) |
f4c7a4ae MS |
30 | dev = simple_strtol(arg, NULL, 16); |
31 | ||
32 | debug("%s: device = %ld\n", __func__, dev); | |
33 | ||
34 | return dev; | |
35 | } | |
36 | ||
85754795 | 37 | static int do_fpga_check_params(long *dev, long *fpga_data, size_t *data_size, |
09140113 SG |
38 | struct cmd_tbl *cmdtp, int argc, |
39 | char *const argv[]) | |
85754795 MS |
40 | { |
41 | size_t local_data_size; | |
42 | long local_fpga_data; | |
43 | ||
44 | debug("%s %d, %d\n", __func__, argc, cmdtp->maxargs); | |
45 | ||
46 | if (argc != cmdtp->maxargs) { | |
47 | debug("fpga: incorrect parameters passed\n"); | |
48 | return CMD_RET_USAGE; | |
49 | } | |
50 | ||
51 | *dev = do_fpga_get_device(argv[0]); | |
52 | ||
53 | local_fpga_data = simple_strtol(argv[1], NULL, 16); | |
54 | if (!local_fpga_data) { | |
55 | debug("fpga: zero fpga_data address\n"); | |
56 | return CMD_RET_USAGE; | |
57 | } | |
58 | *fpga_data = local_fpga_data; | |
59 | ||
7e5f460e | 60 | local_data_size = hextoul(argv[2], NULL); |
85754795 MS |
61 | if (!local_data_size) { |
62 | debug("fpga: zero size\n"); | |
63 | return CMD_RET_USAGE; | |
64 | } | |
65 | *data_size = local_data_size; | |
66 | ||
67 | return 0; | |
68 | } | |
69 | ||
323fe38e | 70 | #if defined(CONFIG_CMD_FPGA_LOAD_SECURE) |
09140113 | 71 | int do_fpga_loads(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) |
4a9cbbe8 | 72 | { |
d4ca31c4 | 73 | size_t data_size = 0; |
b5d19a93 MS |
74 | long fpga_data, dev; |
75 | int ret; | |
cedd48e2 SDPP |
76 | struct fpga_secure_info fpga_sec_info; |
77 | ||
78 | memset(&fpga_sec_info, 0, sizeof(fpga_sec_info)); | |
d4ca31c4 | 79 | |
b5d19a93 MS |
80 | if (argc < 5) { |
81 | debug("fpga: incorrect parameters passed\n"); | |
f5953610 SDPP |
82 | return CMD_RET_USAGE; |
83 | } | |
84 | ||
b5d19a93 MS |
85 | if (argc == 6) |
86 | fpga_sec_info.userkey_addr = (u8 *)(uintptr_t) | |
87 | simple_strtoull(argv[5], | |
88 | NULL, 16); | |
89 | else | |
90 | /* | |
91 | * If 6th parameter is not passed then do_fpga_check_params | |
92 | * will get 5 instead of expected 6 which means that function | |
93 | * return CMD_RET_USAGE. Increase number of params +1 to pass | |
94 | * this. | |
95 | */ | |
96 | argc++; | |
97 | ||
7e5f460e SG |
98 | fpga_sec_info.encflag = (u8)hextoul(argv[4], NULL); |
99 | fpga_sec_info.authflag = (u8)hextoul(argv[3], NULL); | |
b5d19a93 MS |
100 | |
101 | if (fpga_sec_info.authflag >= FPGA_NO_ENC_OR_NO_AUTH && | |
102 | fpga_sec_info.encflag >= FPGA_NO_ENC_OR_NO_AUTH) { | |
103 | debug("fpga: Use <fpga load> for NonSecure bitstream\n"); | |
55010969 | 104 | return CMD_RET_USAGE; |
f5953610 SDPP |
105 | } |
106 | ||
b5d19a93 MS |
107 | if (fpga_sec_info.encflag == FPGA_ENC_USR_KEY && |
108 | !fpga_sec_info.userkey_addr) { | |
109 | debug("fpga: User key not provided\n"); | |
ccd65203 | 110 | return CMD_RET_USAGE; |
a790b5b2 SB |
111 | } |
112 | ||
b5d19a93 MS |
113 | ret = do_fpga_check_params(&dev, &fpga_data, &data_size, |
114 | cmdtp, argc, argv); | |
115 | if (ret) | |
116 | return ret; | |
f0ff4692 | 117 | |
b5d19a93 | 118 | return fpga_loads(dev, (void *)fpga_data, data_size, &fpga_sec_info); |
4a9cbbe8 | 119 | } |
b5d19a93 | 120 | #endif |
4a9cbbe8 | 121 | |
49503f9a | 122 | #if defined(CONFIG_CMD_FPGA_LOADFS) |
09140113 | 123 | static int do_fpga_loadfs(struct cmd_tbl *cmdtp, int flag, int argc, |
49503f9a MS |
124 | char *const argv[]) |
125 | { | |
126 | size_t data_size = 0; | |
127 | long fpga_data, dev; | |
128 | int ret; | |
129 | fpga_fs_info fpga_fsinfo; | |
130 | ||
131 | ret = do_fpga_check_params(&dev, &fpga_data, &data_size, | |
132 | cmdtp, argc, argv); | |
133 | if (ret) | |
134 | return ret; | |
135 | ||
136 | fpga_fsinfo.fstype = FS_TYPE_ANY; | |
7e5f460e | 137 | fpga_fsinfo.blocksize = (unsigned int)hextoul(argv[3], NULL); |
49503f9a MS |
138 | fpga_fsinfo.interface = argv[4]; |
139 | fpga_fsinfo.dev_part = argv[5]; | |
140 | fpga_fsinfo.filename = argv[6]; | |
141 | ||
142 | return fpga_fsload(dev, (void *)fpga_data, data_size, &fpga_fsinfo); | |
143 | } | |
144 | #endif | |
145 | ||
09140113 SG |
146 | static int do_fpga_info(struct cmd_tbl *cmdtp, int flag, int argc, |
147 | char *const argv[]) | |
f4c7a4ae MS |
148 | { |
149 | long dev = do_fpga_get_device(argv[0]); | |
150 | ||
151 | return fpga_info(dev); | |
152 | } | |
153 | ||
09140113 SG |
154 | static int do_fpga_dump(struct cmd_tbl *cmdtp, int flag, int argc, |
155 | char *const argv[]) | |
85754795 MS |
156 | { |
157 | size_t data_size = 0; | |
158 | long fpga_data, dev; | |
159 | int ret; | |
160 | ||
161 | ret = do_fpga_check_params(&dev, &fpga_data, &data_size, | |
162 | cmdtp, argc, argv); | |
163 | if (ret) | |
164 | return ret; | |
165 | ||
166 | return fpga_dump(dev, (void *)fpga_data, data_size); | |
167 | } | |
168 | ||
09140113 SG |
169 | static int do_fpga_load(struct cmd_tbl *cmdtp, int flag, int argc, |
170 | char *const argv[]) | |
85754795 MS |
171 | { |
172 | size_t data_size = 0; | |
173 | long fpga_data, dev; | |
174 | int ret; | |
175 | ||
176 | ret = do_fpga_check_params(&dev, &fpga_data, &data_size, | |
177 | cmdtp, argc, argv); | |
178 | if (ret) | |
179 | return ret; | |
180 | ||
181 | return fpga_load(dev, (void *)fpga_data, data_size, BIT_FULL); | |
182 | } | |
183 | ||
09140113 SG |
184 | static int do_fpga_loadb(struct cmd_tbl *cmdtp, int flag, int argc, |
185 | char *const argv[]) | |
85754795 MS |
186 | { |
187 | size_t data_size = 0; | |
188 | long fpga_data, dev; | |
189 | int ret; | |
190 | ||
191 | ret = do_fpga_check_params(&dev, &fpga_data, &data_size, | |
192 | cmdtp, argc, argv); | |
193 | if (ret) | |
194 | return ret; | |
195 | ||
196 | return fpga_loadbitstream(dev, (void *)fpga_data, data_size, BIT_FULL); | |
197 | } | |
198 | ||
199 | #if defined(CONFIG_CMD_FPGA_LOADP) | |
09140113 SG |
200 | static int do_fpga_loadp(struct cmd_tbl *cmdtp, int flag, int argc, |
201 | char *const argv[]) | |
85754795 MS |
202 | { |
203 | size_t data_size = 0; | |
204 | long fpga_data, dev; | |
205 | int ret; | |
206 | ||
207 | ret = do_fpga_check_params(&dev, &fpga_data, &data_size, | |
208 | cmdtp, argc, argv); | |
209 | if (ret) | |
210 | return ret; | |
211 | ||
212 | return fpga_load(dev, (void *)fpga_data, data_size, BIT_PARTIAL); | |
213 | } | |
214 | #endif | |
215 | ||
216 | #if defined(CONFIG_CMD_FPGA_LOADBP) | |
09140113 SG |
217 | static int do_fpga_loadbp(struct cmd_tbl *cmdtp, int flag, int argc, |
218 | char *const argv[]) | |
85754795 MS |
219 | { |
220 | size_t data_size = 0; | |
221 | long fpga_data, dev; | |
222 | int ret; | |
223 | ||
224 | ret = do_fpga_check_params(&dev, &fpga_data, &data_size, | |
225 | cmdtp, argc, argv); | |
226 | if (ret) | |
227 | return ret; | |
228 | ||
229 | return fpga_loadbitstream(dev, (void *)fpga_data, data_size, | |
230 | BIT_PARTIAL); | |
231 | } | |
232 | #endif | |
233 | ||
2892fe80 | 234 | #if defined(CONFIG_CMD_FPGA_LOADMK) |
09140113 SG |
235 | static int do_fpga_loadmk(struct cmd_tbl *cmdtp, int flag, int argc, |
236 | char *const argv[]) | |
2892fe80 MS |
237 | { |
238 | size_t data_size = 0; | |
239 | void *fpga_data = NULL; | |
240 | #if defined(CONFIG_FIT) | |
241 | const char *fit_uname = NULL; | |
242 | ulong fit_addr; | |
243 | #endif | |
244 | ulong dev = do_fpga_get_device(argv[0]); | |
245 | char *datastr = env_get("fpgadata"); | |
246 | ||
8c75f794 MS |
247 | debug("fpga: argc %x, dev %lx, datastr %s\n", argc, dev, datastr); |
248 | ||
249 | if (dev == FPGA_INVALID_DEVICE) { | |
250 | debug("fpga: Invalid fpga device\n"); | |
251 | return CMD_RET_USAGE; | |
252 | } | |
253 | ||
254 | if (argc == 0 && !datastr) { | |
255 | debug("fpga: No datastr passed\n"); | |
256 | return CMD_RET_USAGE; | |
257 | } | |
2892fe80 MS |
258 | |
259 | if (argc == 2) { | |
8c75f794 MS |
260 | datastr = argv[1]; |
261 | debug("fpga: Full command with two args\n"); | |
262 | } else if (argc == 1 && !datastr) { | |
263 | debug("fpga: Dev is setup - fpgadata passed\n"); | |
264 | datastr = argv[0]; | |
265 | } | |
266 | ||
2892fe80 | 267 | #if defined(CONFIG_FIT) |
8c75f794 MS |
268 | if (fit_parse_subimage(datastr, (ulong)fpga_data, |
269 | &fit_addr, &fit_uname)) { | |
270 | fpga_data = (void *)fit_addr; | |
271 | debug("* fpga: subimage '%s' from FIT image ", | |
272 | fit_uname); | |
273 | debug("at 0x%08lx\n", fit_addr); | |
274 | } else | |
2892fe80 | 275 | #endif |
8c75f794 | 276 | { |
7e5f460e | 277 | fpga_data = (void *)hextoul(datastr, NULL); |
8c75f794 MS |
278 | debug("* fpga: cmdline image address = 0x%08lx\n", |
279 | (ulong)fpga_data); | |
280 | } | |
281 | debug("%s: fpga_data = 0x%lx\n", __func__, (ulong)fpga_data); | |
282 | if (!fpga_data) { | |
283 | puts("Zero fpga_data address\n"); | |
284 | return CMD_RET_USAGE; | |
2892fe80 MS |
285 | } |
286 | ||
287 | switch (genimg_get_format(fpga_data)) { | |
c76c93a3 | 288 | #if defined(CONFIG_LEGACY_IMAGE_FORMAT) |
2892fe80 MS |
289 | case IMAGE_FORMAT_LEGACY: |
290 | { | |
291 | image_header_t *hdr = (image_header_t *)fpga_data; | |
292 | ulong data; | |
293 | u8 comp; | |
294 | ||
295 | comp = image_get_comp(hdr); | |
296 | if (comp == IH_COMP_GZIP) { | |
297 | #if defined(CONFIG_GZIP) | |
298 | ulong image_buf = image_get_data(hdr); | |
299 | ulong image_size = ~0UL; | |
300 | ||
301 | data = image_get_load(hdr); | |
302 | ||
303 | if (gunzip((void *)data, ~0UL, (void *)image_buf, | |
304 | &image_size) != 0) { | |
305 | puts("GUNZIP: error\n"); | |
a2d1033b | 306 | return CMD_RET_FAILURE; |
2892fe80 MS |
307 | } |
308 | data_size = image_size; | |
309 | #else | |
310 | puts("Gunzip image is not supported\n"); | |
311 | return 1; | |
312 | #endif | |
313 | } else { | |
314 | data = (ulong)image_get_data(hdr); | |
315 | data_size = image_get_data_size(hdr); | |
316 | } | |
317 | return fpga_load(dev, (void *)data, data_size, | |
318 | BIT_FULL); | |
319 | } | |
320 | #endif | |
321 | #if defined(CONFIG_FIT) | |
322 | case IMAGE_FORMAT_FIT: | |
323 | { | |
324 | const void *fit_hdr = (const void *)fpga_data; | |
325 | int noffset; | |
326 | const void *fit_data; | |
327 | ||
328 | if (!fit_uname) { | |
329 | puts("No FIT subimage unit name\n"); | |
a2d1033b | 330 | return CMD_RET_FAILURE; |
2892fe80 MS |
331 | } |
332 | ||
c5819701 | 333 | if (fit_check_format(fit_hdr, IMAGE_SIZE_INVAL)) { |
2892fe80 | 334 | puts("Bad FIT image format\n"); |
a2d1033b | 335 | return CMD_RET_FAILURE; |
2892fe80 MS |
336 | } |
337 | ||
338 | /* get fpga component image node offset */ | |
339 | noffset = fit_image_get_node(fit_hdr, fit_uname); | |
340 | if (noffset < 0) { | |
341 | printf("Can't find '%s' FIT subimage\n", fit_uname); | |
a2d1033b | 342 | return CMD_RET_FAILURE; |
2892fe80 MS |
343 | } |
344 | ||
345 | /* verify integrity */ | |
346 | if (!fit_image_verify(fit_hdr, noffset)) { | |
347 | puts("Bad Data Hash\n"); | |
a2d1033b | 348 | return CMD_RET_FAILURE; |
2892fe80 MS |
349 | } |
350 | ||
9184c92f TFC |
351 | /* get fpga subimage/external data address and length */ |
352 | if (fit_image_get_data_and_size(fit_hdr, noffset, | |
353 | &fit_data, &data_size)) { | |
2892fe80 | 354 | puts("Fpga subimage data not found\n"); |
a2d1033b | 355 | return CMD_RET_FAILURE; |
2892fe80 MS |
356 | } |
357 | ||
358 | return fpga_load(dev, fit_data, data_size, BIT_FULL); | |
359 | } | |
360 | #endif | |
361 | default: | |
362 | puts("** Unknown image type\n"); | |
a2d1033b | 363 | return CMD_RET_FAILURE; |
2892fe80 MS |
364 | } |
365 | } | |
366 | #endif | |
367 | ||
09140113 | 368 | static struct cmd_tbl fpga_commands[] = { |
f4c7a4ae | 369 | U_BOOT_CMD_MKENT(info, 1, 1, do_fpga_info, "", ""), |
85754795 MS |
370 | U_BOOT_CMD_MKENT(dump, 3, 1, do_fpga_dump, "", ""), |
371 | U_BOOT_CMD_MKENT(load, 3, 1, do_fpga_load, "", ""), | |
372 | U_BOOT_CMD_MKENT(loadb, 3, 1, do_fpga_loadb, "", ""), | |
373 | #if defined(CONFIG_CMD_FPGA_LOADP) | |
374 | U_BOOT_CMD_MKENT(loadp, 3, 1, do_fpga_loadp, "", ""), | |
375 | #endif | |
376 | #if defined(CONFIG_CMD_FPGA_LOADBP) | |
377 | U_BOOT_CMD_MKENT(loadbp, 3, 1, do_fpga_loadbp, "", ""), | |
378 | #endif | |
49503f9a MS |
379 | #if defined(CONFIG_CMD_FPGA_LOADFS) |
380 | U_BOOT_CMD_MKENT(loadfs, 7, 1, do_fpga_loadfs, "", ""), | |
381 | #endif | |
2892fe80 MS |
382 | #if defined(CONFIG_CMD_FPGA_LOADMK) |
383 | U_BOOT_CMD_MKENT(loadmk, 2, 1, do_fpga_loadmk, "", ""), | |
384 | #endif | |
b5d19a93 MS |
385 | #if defined(CONFIG_CMD_FPGA_LOAD_SECURE) |
386 | U_BOOT_CMD_MKENT(loads, 6, 1, do_fpga_loads, "", ""), | |
387 | #endif | |
9657d97c MS |
388 | }; |
389 | ||
09140113 | 390 | static int do_fpga_wrapper(struct cmd_tbl *cmdtp, int flag, int argc, |
9657d97c MS |
391 | char *const argv[]) |
392 | { | |
09140113 | 393 | struct cmd_tbl *fpga_cmd; |
9657d97c MS |
394 | int ret; |
395 | ||
396 | if (argc < 2) | |
397 | return CMD_RET_USAGE; | |
398 | ||
399 | fpga_cmd = find_cmd_tbl(argv[1], fpga_commands, | |
400 | ARRAY_SIZE(fpga_commands)); | |
9657d97c MS |
401 | if (!fpga_cmd) { |
402 | debug("fpga: non existing command\n"); | |
403 | return CMD_RET_USAGE; | |
404 | } | |
405 | ||
406 | argc -= 2; | |
407 | argv += 2; | |
408 | ||
409 | if (argc > fpga_cmd->maxargs) { | |
410 | debug("fpga: more parameters passed\n"); | |
411 | return CMD_RET_USAGE; | |
412 | } | |
413 | ||
414 | ret = fpga_cmd->cmd(fpga_cmd, flag, argc, argv); | |
415 | ||
416 | return cmd_process_error(fpga_cmd, ret); | |
417 | } | |
418 | ||
cedd48e2 | 419 | #if defined(CONFIG_CMD_FPGA_LOADFS) || defined(CONFIG_CMD_FPGA_LOAD_SECURE) |
9657d97c | 420 | U_BOOT_CMD(fpga, 9, 1, do_fpga_wrapper, |
1a897668 | 421 | #else |
9657d97c | 422 | U_BOOT_CMD(fpga, 6, 1, do_fpga_wrapper, |
1a897668 | 423 | #endif |
fc598412 MS |
424 | "loadable FPGA image support", |
425 | "[operation type] [device number] [image address] [image size]\n" | |
426 | "fpga operations:\n" | |
2d73f0d6 | 427 | " dump\t[dev] [address] [size]\tLoad device to memory buffer\n" |
fc598412 MS |
428 | " info\t[dev]\t\t\tlist known device information\n" |
429 | " load\t[dev] [address] [size]\tLoad device from memory buffer\n" | |
67193864 MS |
430 | #if defined(CONFIG_CMD_FPGA_LOADP) |
431 | " loadp\t[dev] [address] [size]\t" | |
432 | "Load device from memory buffer with partial bitstream\n" | |
433 | #endif | |
fc598412 MS |
434 | " loadb\t[dev] [address] [size]\t" |
435 | "Load device from bitstream buffer (Xilinx only)\n" | |
67193864 MS |
436 | #if defined(CONFIG_CMD_FPGA_LOADBP) |
437 | " loadbp\t[dev] [address] [size]\t" | |
438 | "Load device from bitstream buffer with partial bitstream" | |
439 | "(Xilinx only)\n" | |
440 | #endif | |
1a897668 SDPP |
441 | #if defined(CONFIG_CMD_FPGA_LOADFS) |
442 | "Load device from filesystem (FAT by default) (Xilinx only)\n" | |
443 | " loadfs [dev] [address] [image size] [blocksize] <interface>\n" | |
444 | " [<dev[:part]>] <filename>\n" | |
445 | #endif | |
64e809af | 446 | #if defined(CONFIG_CMD_FPGA_LOADMK) |
fc598412 | 447 | " loadmk [dev] [address]\tLoad device generated with mkimage" |
c28c4d19 | 448 | #if defined(CONFIG_FIT) |
fc598412 MS |
449 | "\n" |
450 | "\tFor loadmk operating on FIT format uImage address must include\n" | |
451 | "\tsubimage unit name in the form of addr:<subimg_uname>" | |
c28c4d19 | 452 | #endif |
64e809af | 453 | #endif |
cedd48e2 SDPP |
454 | #if defined(CONFIG_CMD_FPGA_LOAD_SECURE) |
455 | "Load encrypted bitstream (Xilinx only)\n" | |
456 | " loads [dev] [address] [size] [auth-OCM-0/DDR-1/noauth-2]\n" | |
457 | " [enc-devkey(0)/userkey(1)/nenc(2) [Userkey address]\n" | |
458 | "Loads the secure bistreams(authenticated/encrypted/both\n" | |
459 | "authenticated and encrypted) of [size] from [address].\n" | |
460 | "The auth-OCM/DDR flag specifies to perform authentication\n" | |
461 | "in OCM or in DDR. 0 for OCM, 1 for DDR, 2 for no authentication.\n" | |
462 | "The enc flag specifies which key to be used for decryption\n" | |
463 | "0-device key, 1-user key, 2-no encryption.\n" | |
464 | "The optional Userkey address specifies from which address key\n" | |
465 | "has to be used for decryption if user key is selected.\n" | |
ce9e4e0d | 466 | "NOTE: the secure bitstream has to be created using Xilinx\n" |
cedd48e2 SDPP |
467 | "bootgen tool only.\n" |
468 | #endif | |
c28c4d19 | 469 | ); |