1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2000, 2001 4 * Rich Ireland, Enterasys Networks, rireland@enterasys.com. 5 */ 6 7 /* 8 * FPGA support 9 */ 10 #include <common.h> 11 #include <command.h> 12 #include <fpga.h> 13 #include <fs.h> 14 #include <malloc.h> 15 16 /* Local functions */ 17 static int fpga_get_op(char *opstr); 18 19 /* Local defines */ 20 enum { 21 FPGA_NONE = -1, 22 FPGA_INFO, 23 FPGA_LOAD, 24 FPGA_LOADB, 25 FPGA_DUMP, 26 FPGA_LOADMK, 27 FPGA_LOADP, 28 FPGA_LOADBP, 29 FPGA_LOADFS, 30 }; 31 32 /* ------------------------------------------------------------------------- */ 33 /* command form: 34 * fpga <op> <device number> <data addr> <datasize> 35 * where op is 'load', 'dump', or 'info' 36 * If there is no device number field, the fpga environment variable is used. 37 * If there is no data addr field, the fpgadata environment variable is used. 38 * The info command requires no data address field. 39 */ 40 int do_fpga(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 41 { 42 int op, dev = FPGA_INVALID_DEVICE; 43 size_t data_size = 0; 44 void *fpga_data = NULL; 45 char *devstr = env_get("fpga"); 46 char *datastr = env_get("fpgadata"); 47 int rc = FPGA_FAIL; 48 int wrong_parms = 0; 49 #if defined(CONFIG_FIT) 50 const char *fit_uname = NULL; 51 ulong fit_addr; 52 #endif 53 #if defined(CONFIG_CMD_FPGA_LOADFS) 54 fpga_fs_info fpga_fsinfo; 55 fpga_fsinfo.fstype = FS_TYPE_ANY; 56 #endif 57 58 if (devstr) 59 dev = (int) simple_strtoul(devstr, NULL, 16); 60 if (datastr) 61 fpga_data = (void *)simple_strtoul(datastr, NULL, 16); 62 63 switch (argc) { 64 #if defined(CONFIG_CMD_FPGA_LOADFS) 65 case 9: 66 fpga_fsinfo.blocksize = (unsigned int) 67 simple_strtoul(argv[5], NULL, 16); 68 fpga_fsinfo.interface = argv[6]; 69 fpga_fsinfo.dev_part = argv[7]; 70 fpga_fsinfo.filename = argv[8]; 71 #endif 72 case 5: /* fpga <op> <dev> <data> <datasize> */ 73 data_size = simple_strtoul(argv[4], NULL, 16); 74 75 case 4: /* fpga <op> <dev> <data> */ 76 #if defined(CONFIG_FIT) 77 if (fit_parse_subimage(argv[3], (ulong)fpga_data, 78 &fit_addr, &fit_uname)) { 79 fpga_data = (void *)fit_addr; 80 debug("* fpga: subimage '%s' from FIT image ", 81 fit_uname); 82 debug("at 0x%08lx\n", fit_addr); 83 } else 84 #endif 85 { 86 fpga_data = (void *)simple_strtoul(argv[3], NULL, 16); 87 debug("* fpga: cmdline image address = 0x%08lx\n", 88 (ulong)fpga_data); 89 } 90 debug("%s: fpga_data = 0x%lx\n", __func__, (ulong)fpga_data); 91 92 case 3: /* fpga <op> <dev | data addr> */ 93 dev = (int)simple_strtoul(argv[2], NULL, 16); 94 debug("%s: device = %d\n", __func__, dev); 95 /* FIXME - this is a really weak test */ 96 if ((argc == 3) && (dev > fpga_count())) { 97 /* must be buffer ptr */ 98 debug("%s: Assuming buffer pointer in arg 3\n", 99 __func__); 100 101 #if defined(CONFIG_FIT) 102 if (fit_parse_subimage(argv[2], (ulong)fpga_data, 103 &fit_addr, &fit_uname)) { 104 fpga_data = (void *)fit_addr; 105 debug("* fpga: subimage '%s' from FIT image ", 106 fit_uname); 107 debug("at 0x%08lx\n", fit_addr); 108 } else 109 #endif 110 { 111 fpga_data = (void *)(uintptr_t)dev; 112 debug("* fpga: cmdline image addr = 0x%08lx\n", 113 (ulong)fpga_data); 114 } 115 116 debug("%s: fpga_data = 0x%lx\n", 117 __func__, (ulong)fpga_data); 118 dev = FPGA_INVALID_DEVICE; /* reset device num */ 119 } 120 121 case 2: /* fpga <op> */ 122 op = (int)fpga_get_op(argv[1]); 123 break; 124 125 default: 126 debug("%s: Too many or too few args (%d)\n", __func__, argc); 127 op = FPGA_NONE; /* force usage display */ 128 break; 129 } 130 131 if (dev == FPGA_INVALID_DEVICE) { 132 puts("FPGA device not specified\n"); 133 op = FPGA_NONE; 134 } 135 136 switch (op) { 137 case FPGA_NONE: 138 case FPGA_INFO: 139 break; 140 #if defined(CONFIG_CMD_FPGA_LOADFS) 141 case FPGA_LOADFS: 142 /* Blocksize can be zero */ 143 if (!fpga_fsinfo.interface || !fpga_fsinfo.dev_part || 144 !fpga_fsinfo.filename) 145 wrong_parms = 1; 146 #endif 147 case FPGA_LOAD: 148 case FPGA_LOADP: 149 case FPGA_LOADB: 150 case FPGA_LOADBP: 151 case FPGA_DUMP: 152 if (!fpga_data || !data_size) 153 wrong_parms = 1; 154 break; 155 #if defined(CONFIG_CMD_FPGA_LOADMK) 156 case FPGA_LOADMK: 157 if (!fpga_data) 158 wrong_parms = 1; 159 break; 160 #endif 161 } 162 163 if (wrong_parms) { 164 puts("Wrong parameters for FPGA request\n"); 165 op = FPGA_NONE; 166 } 167 168 switch (op) { 169 case FPGA_NONE: 170 return CMD_RET_USAGE; 171 172 case FPGA_INFO: 173 rc = fpga_info(dev); 174 break; 175 176 case FPGA_LOAD: 177 rc = fpga_load(dev, fpga_data, data_size, BIT_FULL); 178 break; 179 180 #if defined(CONFIG_CMD_FPGA_LOADP) 181 case FPGA_LOADP: 182 rc = fpga_load(dev, fpga_data, data_size, BIT_PARTIAL); 183 break; 184 #endif 185 186 case FPGA_LOADB: 187 rc = fpga_loadbitstream(dev, fpga_data, data_size, BIT_FULL); 188 break; 189 190 #if defined(CONFIG_CMD_FPGA_LOADBP) 191 case FPGA_LOADBP: 192 rc = fpga_loadbitstream(dev, fpga_data, data_size, BIT_PARTIAL); 193 break; 194 #endif 195 196 #if defined(CONFIG_CMD_FPGA_LOADFS) 197 case FPGA_LOADFS: 198 rc = fpga_fsload(dev, fpga_data, data_size, &fpga_fsinfo); 199 break; 200 #endif 201 202 #if defined(CONFIG_CMD_FPGA_LOADMK) 203 case FPGA_LOADMK: 204 switch (genimg_get_format(fpga_data)) { 205 #if defined(CONFIG_IMAGE_FORMAT_LEGACY) 206 case IMAGE_FORMAT_LEGACY: 207 { 208 image_header_t *hdr = 209 (image_header_t *)fpga_data; 210 ulong data; 211 uint8_t comp; 212 213 comp = image_get_comp(hdr); 214 if (comp == IH_COMP_GZIP) { 215 #if defined(CONFIG_GZIP) 216 ulong image_buf = image_get_data(hdr); 217 data = image_get_load(hdr); 218 ulong image_size = ~0UL; 219 220 if (gunzip((void *)data, ~0UL, 221 (void *)image_buf, 222 &image_size) != 0) { 223 puts("GUNZIP: error\n"); 224 return 1; 225 } 226 data_size = image_size; 227 #else 228 puts("Gunzip image is not supported\n"); 229 return 1; 230 #endif 231 } else { 232 data = (ulong)image_get_data(hdr); 233 data_size = image_get_data_size(hdr); 234 } 235 rc = fpga_load(dev, (void *)data, data_size, 236 BIT_FULL); 237 } 238 break; 239 #endif 240 #if defined(CONFIG_FIT) 241 case IMAGE_FORMAT_FIT: 242 { 243 const void *fit_hdr = (const void *)fpga_data; 244 int noffset; 245 const void *fit_data; 246 247 if (fit_uname == NULL) { 248 puts("No FIT subimage unit name\n"); 249 return 1; 250 } 251 252 if (!fit_check_format(fit_hdr)) { 253 puts("Bad FIT image format\n"); 254 return 1; 255 } 256 257 /* get fpga component image node offset */ 258 noffset = fit_image_get_node(fit_hdr, 259 fit_uname); 260 if (noffset < 0) { 261 printf("Can't find '%s' FIT subimage\n", 262 fit_uname); 263 return 1; 264 } 265 266 /* verify integrity */ 267 if (!fit_image_verify(fit_hdr, noffset)) { 268 puts ("Bad Data Hash\n"); 269 return 1; 270 } 271 272 /* get fpga subimage data address and length */ 273 if (fit_image_get_data(fit_hdr, noffset, 274 &fit_data, &data_size)) { 275 puts("Fpga subimage data not found\n"); 276 return 1; 277 } 278 279 rc = fpga_load(dev, fit_data, data_size, 280 BIT_FULL); 281 } 282 break; 283 #endif 284 default: 285 puts("** Unknown image type\n"); 286 rc = FPGA_FAIL; 287 break; 288 } 289 break; 290 #endif 291 292 case FPGA_DUMP: 293 rc = fpga_dump(dev, fpga_data, data_size); 294 break; 295 296 default: 297 printf("Unknown operation\n"); 298 return CMD_RET_USAGE; 299 } 300 return rc; 301 } 302 303 /* 304 * Map op to supported operations. We don't use a table since we 305 * would just have to relocate it from flash anyway. 306 */ 307 static int fpga_get_op(char *opstr) 308 { 309 int op = FPGA_NONE; 310 311 if (!strcmp("info", opstr)) 312 op = FPGA_INFO; 313 else if (!strcmp("loadb", opstr)) 314 op = FPGA_LOADB; 315 else if (!strcmp("load", opstr)) 316 op = FPGA_LOAD; 317 #if defined(CONFIG_CMD_FPGA_LOADP) 318 else if (!strcmp("loadp", opstr)) 319 op = FPGA_LOADP; 320 #endif 321 #if defined(CONFIG_CMD_FPGA_LOADBP) 322 else if (!strcmp("loadbp", opstr)) 323 op = FPGA_LOADBP; 324 #endif 325 #if defined(CONFIG_CMD_FPGA_LOADFS) 326 else if (!strcmp("loadfs", opstr)) 327 op = FPGA_LOADFS; 328 #endif 329 #if defined(CONFIG_CMD_FPGA_LOADMK) 330 else if (!strcmp("loadmk", opstr)) 331 op = FPGA_LOADMK; 332 #endif 333 else if (!strcmp("dump", opstr)) 334 op = FPGA_DUMP; 335 336 if (op == FPGA_NONE) 337 printf("Unknown fpga operation \"%s\"\n", opstr); 338 339 return op; 340 } 341 342 #if defined(CONFIG_CMD_FPGA_LOADFS) 343 U_BOOT_CMD(fpga, 9, 1, do_fpga, 344 #else 345 U_BOOT_CMD(fpga, 6, 1, do_fpga, 346 #endif 347 "loadable FPGA image support", 348 "[operation type] [device number] [image address] [image size]\n" 349 "fpga operations:\n" 350 " dump\t[dev] [address] [size]\tLoad device to memory buffer\n" 351 " info\t[dev]\t\t\tlist known device information\n" 352 " load\t[dev] [address] [size]\tLoad device from memory buffer\n" 353 #if defined(CONFIG_CMD_FPGA_LOADP) 354 " loadp\t[dev] [address] [size]\t" 355 "Load device from memory buffer with partial bitstream\n" 356 #endif 357 " loadb\t[dev] [address] [size]\t" 358 "Load device from bitstream buffer (Xilinx only)\n" 359 #if defined(CONFIG_CMD_FPGA_LOADBP) 360 " loadbp\t[dev] [address] [size]\t" 361 "Load device from bitstream buffer with partial bitstream" 362 "(Xilinx only)\n" 363 #endif 364 #if defined(CONFIG_CMD_FPGA_LOADFS) 365 "Load device from filesystem (FAT by default) (Xilinx only)\n" 366 " loadfs [dev] [address] [image size] [blocksize] <interface>\n" 367 " [<dev[:part]>] <filename>\n" 368 #endif 369 #if defined(CONFIG_CMD_FPGA_LOADMK) 370 " loadmk [dev] [address]\tLoad device generated with mkimage" 371 #if defined(CONFIG_FIT) 372 "\n" 373 "\tFor loadmk operating on FIT format uImage address must include\n" 374 "\tsubimage unit name in the form of addr:<subimg_uname>" 375 #endif 376 #endif 377 ); 378