/* Load previously loaded ihx file into device RAM and restart device */ int ezusb_write_image(usb_dev_handle * dev) { struct eeprom_block *block; int ret; /* Stop the CPU while we load new code */ if (ezusb_cpucs(dev, 0) < 0) return -1; for (block = blocks; block; block = block->next) { ret = ezusb_poke(dev, block->off, block->data, block->len); if (ret < 0) return -1; } /* Reset the CPU to run our downloaded code */ if (ezusb_cpucs(dev, 1) < 0) return -1; return 0; }
/* * Load a firmware file into target RAM. device is the open libusbx * device, and the path is the name of the source file. Open the file, * parse the bytes, and write them in one or two phases. * * If stage == 0, this uses the first stage loader, built into EZ-USB * hardware but limited to writing on-chip memory or CPUCS. Everything * is written during one stage, unless there's an error such as the image * holding data that needs to be written to external memory. * * Otherwise, things are written in two stages. First the external * memory is written, expecting a second stage loader to have already * been loaded. Then file is re-parsed and on-chip memory is written. */ int ezusb_load_ram(libusb_device_handle *device, const char *path, int fx_type, int img_type, int stage) { FILE *image; uint32_t cpucs_addr; bool (*is_external)(uint32_t off, size_t len); struct ram_poke_context ctx; int status; uint8_t iic_header[8] = { 0 }; if (fx_type == FX_TYPE_FX3) return fx3_load_ram(device, path); image = fopen(path, "rb"); if (image == NULL) { logerror("%s: unable to open for input.\n", path); return -2; } else if (verbose > 1) logerror("open firmware image %s for RAM upload\n", path); if (img_type == IMG_TYPE_IIC) { if ( (fread(iic_header, 1, sizeof(iic_header), image) != sizeof(iic_header)) || (((fx_type == FX_TYPE_FX2LP) || (fx_type == FX_TYPE_FX2)) && (iic_header[0] != 0xC2)) || ((fx_type == FX_TYPE_AN21) && (iic_header[0] != 0xB2)) || ((fx_type == FX_TYPE_FX1) && (iic_header[0] != 0xB6)) ) { logerror("IIC image does not contain executable code - cannot load to RAM.\n"); return -1; } } /* EZ-USB original/FX and FX2 devices differ, apart from the 8051 core */ switch(fx_type) { case FX_TYPE_FX2LP: cpucs_addr = 0xe600; is_external = fx2lp_is_external; break; case FX_TYPE_FX2: cpucs_addr = 0xe600; is_external = fx2_is_external; break; default: cpucs_addr = 0x7f92; is_external = fx_is_external; break; } /* use only first stage loader? */ if (stage == 0) { ctx.mode = internal_only; /* if required, halt the CPU while we overwrite its code/data */ if (cpucs_addr && !ezusb_cpucs(device, cpucs_addr, false)) return -1; /* 2nd stage, first part? loader was already uploaded */ } else { ctx.mode = skip_internal; /* let CPU run; overwrite the 2nd stage loader later */ if (verbose) logerror("2nd stage: write external memory\n"); } /* scan the image, first (maybe only) time */ ctx.device = device; ctx.total = ctx.count = 0; status = parse[img_type](image, &ctx, is_external, ram_poke); if (status < 0) { logerror("unable to upload %s\n", path); return status; } /* second part of 2nd stage: rescan */ // TODO: what should we do for non HEX images there? if (stage) { ctx.mode = skip_external; /* if needed, halt the CPU while we overwrite the 1st stage loader */ if (cpucs_addr && !ezusb_cpucs(device, cpucs_addr, false)) return -1; /* at least write the interrupt vectors (at 0x0000) for reset! */ rewind(image); if (verbose) logerror("2nd stage: write on-chip memory\n"); status = parse_ihex(image, &ctx, is_external, ram_poke); if (status < 0) { logerror("unable to completely upload %s\n", path); return status; } } if (verbose) logerror("... WROTE: %d bytes, %d segments, avg %d\n", (int)ctx.total, (int)ctx.count, (int)(ctx.total/ctx.count)); /* if required, reset the CPU so it runs what we just uploaded */ if (cpucs_addr && !ezusb_cpucs(device, cpucs_addr, true)) return -1; return 0; }
/* * Load an Intel HEX file into target RAM. The fd is the open "usbfs" * device, and the path is the name of the source file. Open the file, * parse the bytes, and write them in one or two phases. * * If stage == 0, this uses the first stage loader, built into EZ-USB * hardware but limited to writing on-chip memory or CPUCS. Everything * is written during one stage, unless there's an error such as the image * holding data that needs to be written to external memory. * * Otherwise, things are written in two stages. First the external * memory is written, expecting a second stage loader to have already * been loaded. Then file is re-parsed and on-chip memory is written. */ int ezusb_load_ram (int fd, const char *path, int fx2, int stage) { FILE *image; unsigned short cpucs_addr; int (*is_external)(unsigned short off, size_t len); struct ram_poke_context ctx; int status; image = fopen (path, "r"); if (image == 0) { fprintf (stderr, "%s: unable to open for input.\n", path); return -2; } else if (verbose) fprintf (stderr, "open RAM hexfile image %s\n", path); /* EZ-USB original/FX and FX2 devices differ, apart from the 8051 core */ if (fx2) { cpucs_addr = 0xe600; is_external = fx2_is_external; } else { cpucs_addr = 0x7f92; is_external = fx_is_external; } /* use only first stage loader? */ if (!stage) { ctx.mode = internal_only; /* don't let CPU run while we overwrite its code/data */ if (!ezusb_cpucs (fd, cpucs_addr, 0)) return -1; /* 2nd stage, first part? loader was already downloaded */ } else { ctx.mode = skip_internal; /* let CPU run; overwrite the 2nd stage loader later */ if (verbose) fprintf (stderr, "2nd stage: write external memory\n"); } /* scan the image, first (maybe only) time */ ctx.device = fd; ctx.total = ctx.count = 0; status = parse_ihex (image, &ctx, is_external, ram_poke); if (status < 0) { fprintf (stderr, "unable to download %s\n", path); return status; } /* second part of 2nd stage: rescan */ if (stage) { ctx.mode = skip_external; /* don't let CPU run while we overwrite the 1st stage loader */ if (!ezusb_cpucs (fd, cpucs_addr, 0)) return -1; /* at least write the interrupt vectors (at 0x0000) for reset! */ rewind (image); if (verbose) fprintf (stderr, "2nd stage: write on-chip memory\n"); status = parse_ihex (image, &ctx, is_external, ram_poke); if (status < 0) { fprintf (stderr, "unable to completely download %s\n", path); return status; } } if (verbose) fprintf (stderr, "... WROTE: %d bytes, %d segments, avg %d\n", ctx.total, ctx.count, ctx.total / ctx.count); /* now reset the CPU so it runs what we just downloaded */ if (!ezusb_cpucs (fd, cpucs_addr, 1)) return -1; return 0; }