12e192b24SSimon Glass /*
22e192b24SSimon Glass * (C) Copyright 2000, 2001
32e192b24SSimon Glass * Rich Ireland, Enterasys Networks, rireland@enterasys.com.
42e192b24SSimon Glass *
52e192b24SSimon Glass * SPDX-License-Identifier: GPL-2.0+
62e192b24SSimon Glass */
72e192b24SSimon Glass
82e192b24SSimon Glass /*
92e192b24SSimon Glass * FPGA support
102e192b24SSimon Glass */
112e192b24SSimon Glass #include <common.h>
122e192b24SSimon Glass #include <command.h>
132e192b24SSimon Glass #include <fpga.h>
142e192b24SSimon Glass #include <fs.h>
152e192b24SSimon Glass #include <malloc.h>
162e192b24SSimon Glass
172e192b24SSimon Glass /* Local functions */
182e192b24SSimon Glass static int fpga_get_op(char *opstr);
192e192b24SSimon Glass
202e192b24SSimon Glass /* Local defines */
215cf22289SMichal Simek enum {
225cf22289SMichal Simek FPGA_NONE = -1,
235cf22289SMichal Simek FPGA_INFO,
245cf22289SMichal Simek FPGA_LOAD,
255cf22289SMichal Simek FPGA_LOADB,
265cf22289SMichal Simek FPGA_DUMP,
275cf22289SMichal Simek FPGA_LOADMK,
285cf22289SMichal Simek FPGA_LOADP,
295cf22289SMichal Simek FPGA_LOADBP,
305cf22289SMichal Simek FPGA_LOADFS,
315cf22289SMichal Simek };
322e192b24SSimon Glass
332e192b24SSimon Glass /* ------------------------------------------------------------------------- */
342e192b24SSimon Glass /* command form:
352e192b24SSimon Glass * fpga <op> <device number> <data addr> <datasize>
362e192b24SSimon Glass * where op is 'load', 'dump', or 'info'
372e192b24SSimon Glass * If there is no device number field, the fpga environment variable is used.
382e192b24SSimon Glass * If there is no data addr field, the fpgadata environment variable is used.
392e192b24SSimon Glass * The info command requires no data address field.
402e192b24SSimon Glass */
do_fpga(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])412e192b24SSimon Glass int do_fpga(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
422e192b24SSimon Glass {
432e192b24SSimon Glass int op, dev = FPGA_INVALID_DEVICE;
442e192b24SSimon Glass size_t data_size = 0;
452e192b24SSimon Glass void *fpga_data = NULL;
46*00caae6dSSimon Glass char *devstr = env_get("fpga");
47*00caae6dSSimon Glass char *datastr = env_get("fpgadata");
482e192b24SSimon Glass int rc = FPGA_FAIL;
492e192b24SSimon Glass int wrong_parms = 0;
502e192b24SSimon Glass #if defined(CONFIG_FIT)
512e192b24SSimon Glass const char *fit_uname = NULL;
522e192b24SSimon Glass ulong fit_addr;
532e192b24SSimon Glass #endif
542e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADFS)
552e192b24SSimon Glass fpga_fs_info fpga_fsinfo;
562e192b24SSimon Glass fpga_fsinfo.fstype = FS_TYPE_ANY;
572e192b24SSimon Glass #endif
582e192b24SSimon Glass
592e192b24SSimon Glass if (devstr)
602e192b24SSimon Glass dev = (int) simple_strtoul(devstr, NULL, 16);
612e192b24SSimon Glass if (datastr)
622e192b24SSimon Glass fpga_data = (void *)simple_strtoul(datastr, NULL, 16);
632e192b24SSimon Glass
642e192b24SSimon Glass switch (argc) {
652e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADFS)
662e192b24SSimon Glass case 9:
672e192b24SSimon Glass fpga_fsinfo.blocksize = (unsigned int)
682e192b24SSimon Glass simple_strtoul(argv[5], NULL, 16);
692e192b24SSimon Glass fpga_fsinfo.interface = argv[6];
702e192b24SSimon Glass fpga_fsinfo.dev_part = argv[7];
712e192b24SSimon Glass fpga_fsinfo.filename = argv[8];
722e192b24SSimon Glass #endif
732e192b24SSimon Glass case 5: /* fpga <op> <dev> <data> <datasize> */
742e192b24SSimon Glass data_size = simple_strtoul(argv[4], NULL, 16);
752e192b24SSimon Glass
762e192b24SSimon Glass case 4: /* fpga <op> <dev> <data> */
772e192b24SSimon Glass #if defined(CONFIG_FIT)
782e192b24SSimon Glass if (fit_parse_subimage(argv[3], (ulong)fpga_data,
792e192b24SSimon Glass &fit_addr, &fit_uname)) {
802e192b24SSimon Glass fpga_data = (void *)fit_addr;
812e192b24SSimon Glass debug("* fpga: subimage '%s' from FIT image ",
822e192b24SSimon Glass fit_uname);
832e192b24SSimon Glass debug("at 0x%08lx\n", fit_addr);
842e192b24SSimon Glass } else
852e192b24SSimon Glass #endif
862e192b24SSimon Glass {
872e192b24SSimon Glass fpga_data = (void *)simple_strtoul(argv[3], NULL, 16);
882e192b24SSimon Glass debug("* fpga: cmdline image address = 0x%08lx\n",
892e192b24SSimon Glass (ulong)fpga_data);
902e192b24SSimon Glass }
91455ad585SMichal Simek debug("%s: fpga_data = 0x%lx\n", __func__, (ulong)fpga_data);
922e192b24SSimon Glass
932e192b24SSimon Glass case 3: /* fpga <op> <dev | data addr> */
942e192b24SSimon Glass dev = (int)simple_strtoul(argv[2], NULL, 16);
952e192b24SSimon Glass debug("%s: device = %d\n", __func__, dev);
962e192b24SSimon Glass /* FIXME - this is a really weak test */
972e192b24SSimon Glass if ((argc == 3) && (dev > fpga_count())) {
982e192b24SSimon Glass /* must be buffer ptr */
992e192b24SSimon Glass debug("%s: Assuming buffer pointer in arg 3\n",
1002e192b24SSimon Glass __func__);
1012e192b24SSimon Glass
1022e192b24SSimon Glass #if defined(CONFIG_FIT)
1032e192b24SSimon Glass if (fit_parse_subimage(argv[2], (ulong)fpga_data,
1042e192b24SSimon Glass &fit_addr, &fit_uname)) {
1052e192b24SSimon Glass fpga_data = (void *)fit_addr;
1062e192b24SSimon Glass debug("* fpga: subimage '%s' from FIT image ",
1072e192b24SSimon Glass fit_uname);
1082e192b24SSimon Glass debug("at 0x%08lx\n", fit_addr);
1092e192b24SSimon Glass } else
1102e192b24SSimon Glass #endif
1112e192b24SSimon Glass {
112455ad585SMichal Simek fpga_data = (void *)(uintptr_t)dev;
1132e192b24SSimon Glass debug("* fpga: cmdline image addr = 0x%08lx\n",
1142e192b24SSimon Glass (ulong)fpga_data);
1152e192b24SSimon Glass }
1162e192b24SSimon Glass
117455ad585SMichal Simek debug("%s: fpga_data = 0x%lx\n",
118455ad585SMichal Simek __func__, (ulong)fpga_data);
1192e192b24SSimon Glass dev = FPGA_INVALID_DEVICE; /* reset device num */
1202e192b24SSimon Glass }
1212e192b24SSimon Glass
1222e192b24SSimon Glass case 2: /* fpga <op> */
1232e192b24SSimon Glass op = (int)fpga_get_op(argv[1]);
1242e192b24SSimon Glass break;
1252e192b24SSimon Glass
1262e192b24SSimon Glass default:
1272e192b24SSimon Glass debug("%s: Too many or too few args (%d)\n", __func__, argc);
1282e192b24SSimon Glass op = FPGA_NONE; /* force usage display */
1292e192b24SSimon Glass break;
1302e192b24SSimon Glass }
1312e192b24SSimon Glass
1322e192b24SSimon Glass if (dev == FPGA_INVALID_DEVICE) {
1332e192b24SSimon Glass puts("FPGA device not specified\n");
1342e192b24SSimon Glass op = FPGA_NONE;
1352e192b24SSimon Glass }
1362e192b24SSimon Glass
1372e192b24SSimon Glass switch (op) {
1382e192b24SSimon Glass case FPGA_NONE:
1392e192b24SSimon Glass case FPGA_INFO:
1402e192b24SSimon Glass break;
1412e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADFS)
1422e192b24SSimon Glass case FPGA_LOADFS:
1432e192b24SSimon Glass /* Blocksize can be zero */
1442e192b24SSimon Glass if (!fpga_fsinfo.interface || !fpga_fsinfo.dev_part ||
1452e192b24SSimon Glass !fpga_fsinfo.filename)
1462e192b24SSimon Glass wrong_parms = 1;
1472e192b24SSimon Glass #endif
1482e192b24SSimon Glass case FPGA_LOAD:
1492e192b24SSimon Glass case FPGA_LOADP:
1502e192b24SSimon Glass case FPGA_LOADB:
1512e192b24SSimon Glass case FPGA_LOADBP:
1522e192b24SSimon Glass case FPGA_DUMP:
1532e192b24SSimon Glass if (!fpga_data || !data_size)
1542e192b24SSimon Glass wrong_parms = 1;
1552e192b24SSimon Glass break;
1562e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADMK)
1572e192b24SSimon Glass case FPGA_LOADMK:
1582e192b24SSimon Glass if (!fpga_data)
1592e192b24SSimon Glass wrong_parms = 1;
1602e192b24SSimon Glass break;
1612e192b24SSimon Glass #endif
1622e192b24SSimon Glass }
1632e192b24SSimon Glass
1642e192b24SSimon Glass if (wrong_parms) {
1652e192b24SSimon Glass puts("Wrong parameters for FPGA request\n");
1662e192b24SSimon Glass op = FPGA_NONE;
1672e192b24SSimon Glass }
1682e192b24SSimon Glass
1692e192b24SSimon Glass switch (op) {
1702e192b24SSimon Glass case FPGA_NONE:
1712e192b24SSimon Glass return CMD_RET_USAGE;
1722e192b24SSimon Glass
1732e192b24SSimon Glass case FPGA_INFO:
1742e192b24SSimon Glass rc = fpga_info(dev);
1752e192b24SSimon Glass break;
1762e192b24SSimon Glass
1772e192b24SSimon Glass case FPGA_LOAD:
1782e192b24SSimon Glass rc = fpga_load(dev, fpga_data, data_size, BIT_FULL);
1792e192b24SSimon Glass break;
1802e192b24SSimon Glass
1812e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADP)
1822e192b24SSimon Glass case FPGA_LOADP:
1832e192b24SSimon Glass rc = fpga_load(dev, fpga_data, data_size, BIT_PARTIAL);
1842e192b24SSimon Glass break;
1852e192b24SSimon Glass #endif
1862e192b24SSimon Glass
1872e192b24SSimon Glass case FPGA_LOADB:
1882e192b24SSimon Glass rc = fpga_loadbitstream(dev, fpga_data, data_size, BIT_FULL);
1892e192b24SSimon Glass break;
1902e192b24SSimon Glass
1912e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADBP)
1922e192b24SSimon Glass case FPGA_LOADBP:
1932e192b24SSimon Glass rc = fpga_loadbitstream(dev, fpga_data, data_size, BIT_PARTIAL);
1942e192b24SSimon Glass break;
1952e192b24SSimon Glass #endif
1962e192b24SSimon Glass
1972e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADFS)
1982e192b24SSimon Glass case FPGA_LOADFS:
1992e192b24SSimon Glass rc = fpga_fsload(dev, fpga_data, data_size, &fpga_fsinfo);
2002e192b24SSimon Glass break;
2012e192b24SSimon Glass #endif
2022e192b24SSimon Glass
2032e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADMK)
2042e192b24SSimon Glass case FPGA_LOADMK:
2052e192b24SSimon Glass switch (genimg_get_format(fpga_data)) {
2062e192b24SSimon Glass #if defined(CONFIG_IMAGE_FORMAT_LEGACY)
2072e192b24SSimon Glass case IMAGE_FORMAT_LEGACY:
2082e192b24SSimon Glass {
2092e192b24SSimon Glass image_header_t *hdr =
2102e192b24SSimon Glass (image_header_t *)fpga_data;
2112e192b24SSimon Glass ulong data;
2122e192b24SSimon Glass uint8_t comp;
2132e192b24SSimon Glass
2142e192b24SSimon Glass comp = image_get_comp(hdr);
2152e192b24SSimon Glass if (comp == IH_COMP_GZIP) {
2162e192b24SSimon Glass #if defined(CONFIG_GZIP)
2172e192b24SSimon Glass ulong image_buf = image_get_data(hdr);
2182e192b24SSimon Glass data = image_get_load(hdr);
2192e192b24SSimon Glass ulong image_size = ~0UL;
2202e192b24SSimon Glass
2212e192b24SSimon Glass if (gunzip((void *)data, ~0UL,
2222e192b24SSimon Glass (void *)image_buf,
2232e192b24SSimon Glass &image_size) != 0) {
2242e192b24SSimon Glass puts("GUNZIP: error\n");
2252e192b24SSimon Glass return 1;
2262e192b24SSimon Glass }
2272e192b24SSimon Glass data_size = image_size;
2282e192b24SSimon Glass #else
2292e192b24SSimon Glass puts("Gunzip image is not supported\n");
2302e192b24SSimon Glass return 1;
2312e192b24SSimon Glass #endif
2322e192b24SSimon Glass } else {
2332e192b24SSimon Glass data = (ulong)image_get_data(hdr);
2342e192b24SSimon Glass data_size = image_get_data_size(hdr);
2352e192b24SSimon Glass }
2362e192b24SSimon Glass rc = fpga_load(dev, (void *)data, data_size,
2372e192b24SSimon Glass BIT_FULL);
2382e192b24SSimon Glass }
2392e192b24SSimon Glass break;
2402e192b24SSimon Glass #endif
2412e192b24SSimon Glass #if defined(CONFIG_FIT)
2422e192b24SSimon Glass case IMAGE_FORMAT_FIT:
2432e192b24SSimon Glass {
2442e192b24SSimon Glass const void *fit_hdr = (const void *)fpga_data;
2452e192b24SSimon Glass int noffset;
2462e192b24SSimon Glass const void *fit_data;
2472e192b24SSimon Glass
2482e192b24SSimon Glass if (fit_uname == NULL) {
2492e192b24SSimon Glass puts("No FIT subimage unit name\n");
2502e192b24SSimon Glass return 1;
2512e192b24SSimon Glass }
2522e192b24SSimon Glass
2532e192b24SSimon Glass if (!fit_check_format(fit_hdr)) {
2542e192b24SSimon Glass puts("Bad FIT image format\n");
2552e192b24SSimon Glass return 1;
2562e192b24SSimon Glass }
2572e192b24SSimon Glass
2582e192b24SSimon Glass /* get fpga component image node offset */
2592e192b24SSimon Glass noffset = fit_image_get_node(fit_hdr,
2602e192b24SSimon Glass fit_uname);
2612e192b24SSimon Glass if (noffset < 0) {
2622e192b24SSimon Glass printf("Can't find '%s' FIT subimage\n",
2632e192b24SSimon Glass fit_uname);
2642e192b24SSimon Glass return 1;
2652e192b24SSimon Glass }
2662e192b24SSimon Glass
2672e192b24SSimon Glass /* verify integrity */
2682e192b24SSimon Glass if (!fit_image_verify(fit_hdr, noffset)) {
2692e192b24SSimon Glass puts ("Bad Data Hash\n");
2702e192b24SSimon Glass return 1;
2712e192b24SSimon Glass }
2722e192b24SSimon Glass
2732e192b24SSimon Glass /* get fpga subimage data address and length */
2742e192b24SSimon Glass if (fit_image_get_data(fit_hdr, noffset,
2752e192b24SSimon Glass &fit_data, &data_size)) {
2762e192b24SSimon Glass puts("Fpga subimage data not found\n");
2772e192b24SSimon Glass return 1;
2782e192b24SSimon Glass }
2792e192b24SSimon Glass
2802e192b24SSimon Glass rc = fpga_load(dev, fit_data, data_size,
2812e192b24SSimon Glass BIT_FULL);
2822e192b24SSimon Glass }
2832e192b24SSimon Glass break;
2842e192b24SSimon Glass #endif
2852e192b24SSimon Glass default:
2862e192b24SSimon Glass puts("** Unknown image type\n");
2872e192b24SSimon Glass rc = FPGA_FAIL;
2882e192b24SSimon Glass break;
2892e192b24SSimon Glass }
2902e192b24SSimon Glass break;
2912e192b24SSimon Glass #endif
2922e192b24SSimon Glass
2932e192b24SSimon Glass case FPGA_DUMP:
2942e192b24SSimon Glass rc = fpga_dump(dev, fpga_data, data_size);
2952e192b24SSimon Glass break;
2962e192b24SSimon Glass
2972e192b24SSimon Glass default:
2982e192b24SSimon Glass printf("Unknown operation\n");
2992e192b24SSimon Glass return CMD_RET_USAGE;
3002e192b24SSimon Glass }
3012e192b24SSimon Glass return rc;
3022e192b24SSimon Glass }
3032e192b24SSimon Glass
3042e192b24SSimon Glass /*
3052e192b24SSimon Glass * Map op to supported operations. We don't use a table since we
3062e192b24SSimon Glass * would just have to relocate it from flash anyway.
3072e192b24SSimon Glass */
fpga_get_op(char * opstr)3082e192b24SSimon Glass static int fpga_get_op(char *opstr)
3092e192b24SSimon Glass {
3102e192b24SSimon Glass int op = FPGA_NONE;
3112e192b24SSimon Glass
3122e192b24SSimon Glass if (!strcmp("info", opstr))
3132e192b24SSimon Glass op = FPGA_INFO;
3142e192b24SSimon Glass else if (!strcmp("loadb", opstr))
3152e192b24SSimon Glass op = FPGA_LOADB;
3162e192b24SSimon Glass else if (!strcmp("load", opstr))
3172e192b24SSimon Glass op = FPGA_LOAD;
3182e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADP)
3192e192b24SSimon Glass else if (!strcmp("loadp", opstr))
3202e192b24SSimon Glass op = FPGA_LOADP;
3212e192b24SSimon Glass #endif
3222e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADBP)
3232e192b24SSimon Glass else if (!strcmp("loadbp", opstr))
3242e192b24SSimon Glass op = FPGA_LOADBP;
3252e192b24SSimon Glass #endif
3262e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADFS)
3272e192b24SSimon Glass else if (!strcmp("loadfs", opstr))
3282e192b24SSimon Glass op = FPGA_LOADFS;
3292e192b24SSimon Glass #endif
3302e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADMK)
3312e192b24SSimon Glass else if (!strcmp("loadmk", opstr))
3322e192b24SSimon Glass op = FPGA_LOADMK;
3332e192b24SSimon Glass #endif
3342e192b24SSimon Glass else if (!strcmp("dump", opstr))
3352e192b24SSimon Glass op = FPGA_DUMP;
3362e192b24SSimon Glass
3372e192b24SSimon Glass if (op == FPGA_NONE)
3382e192b24SSimon Glass printf("Unknown fpga operation \"%s\"\n", opstr);
3392e192b24SSimon Glass
3402e192b24SSimon Glass return op;
3412e192b24SSimon Glass }
3422e192b24SSimon Glass
3432e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADFS)
3442e192b24SSimon Glass U_BOOT_CMD(fpga, 9, 1, do_fpga,
3452e192b24SSimon Glass #else
3462e192b24SSimon Glass U_BOOT_CMD(fpga, 6, 1, do_fpga,
3472e192b24SSimon Glass #endif
3482e192b24SSimon Glass "loadable FPGA image support",
3492e192b24SSimon Glass "[operation type] [device number] [image address] [image size]\n"
3502e192b24SSimon Glass "fpga operations:\n"
3512e192b24SSimon Glass " dump\t[dev] [address] [size]\tLoad device to memory buffer\n"
3522e192b24SSimon Glass " info\t[dev]\t\t\tlist known device information\n"
3532e192b24SSimon Glass " load\t[dev] [address] [size]\tLoad device from memory buffer\n"
3542e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADP)
3552e192b24SSimon Glass " loadp\t[dev] [address] [size]\t"
3562e192b24SSimon Glass "Load device from memory buffer with partial bitstream\n"
3572e192b24SSimon Glass #endif
3582e192b24SSimon Glass " loadb\t[dev] [address] [size]\t"
3592e192b24SSimon Glass "Load device from bitstream buffer (Xilinx only)\n"
3602e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADBP)
3612e192b24SSimon Glass " loadbp\t[dev] [address] [size]\t"
3622e192b24SSimon Glass "Load device from bitstream buffer with partial bitstream"
3632e192b24SSimon Glass "(Xilinx only)\n"
3642e192b24SSimon Glass #endif
3652e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADFS)
3662e192b24SSimon Glass "Load device from filesystem (FAT by default) (Xilinx only)\n"
3672e192b24SSimon Glass " loadfs [dev] [address] [image size] [blocksize] <interface>\n"
3682e192b24SSimon Glass " [<dev[:part]>] <filename>\n"
3692e192b24SSimon Glass #endif
3702e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADMK)
3712e192b24SSimon Glass " loadmk [dev] [address]\tLoad device generated with mkimage"
3722e192b24SSimon Glass #if defined(CONFIG_FIT)
3732e192b24SSimon Glass "\n"
3742e192b24SSimon Glass "\tFor loadmk operating on FIT format uImage address must include\n"
3752e192b24SSimon Glass "\tsubimage unit name in the form of addr:<subimg_uname>"
3762e192b24SSimon Glass #endif
3772e192b24SSimon Glass #endif
3782e192b24SSimon Glass );
379