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 */ 21*5cf22289SMichal Simek enum { 22*5cf22289SMichal Simek FPGA_NONE = -1, 23*5cf22289SMichal Simek FPGA_INFO, 24*5cf22289SMichal Simek FPGA_LOAD, 25*5cf22289SMichal Simek FPGA_LOADB, 26*5cf22289SMichal Simek FPGA_DUMP, 27*5cf22289SMichal Simek FPGA_LOADMK, 28*5cf22289SMichal Simek FPGA_LOADP, 29*5cf22289SMichal Simek FPGA_LOADBP, 30*5cf22289SMichal Simek FPGA_LOADFS, 31*5cf22289SMichal 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 */ 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; 462e192b24SSimon Glass char *devstr = getenv("fpga"); 472e192b24SSimon Glass char *datastr = getenv("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 */ 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