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