#include #include #include "log.h" #include "minmax.h" #include "misc.h" #include "conversions.h" #include "bladeRF.h" #include "board/board.h" #include "driver/spi_flash.h" #include "flash.h" #define OTP_BUFFER_SIZE 256 int spi_flash_write_fx3_fw(struct bladerf *dev, const uint8_t *image, size_t len) { int status; uint8_t *readback_buf; uint8_t *padded_image; uint32_t padded_image_len; /* Pad firwmare data out to a page size */ const uint32_t page_size = dev->flash_arch->psize_bytes; const uint32_t padding_len = (len % page_size == 0) ? 0 : page_size - (len % page_size); /* Flash page where FX3 firmware starts */ const uint32_t flash_page_fw = BLADERF_FLASH_ADDR_FIRMWARE / dev->flash_arch->psize_bytes; /* Flash erase block where FX3 firmware starts */ const uint32_t flash_eb_fw = BLADERF_FLASH_ADDR_FIRMWARE / dev->flash_arch->ebsize_bytes; /** Length of firmware region of flash, in erase blocks */ const uint32_t flash_eb_len_fw = BLADERF_FLASH_BYTE_LEN_FIRMWARE / dev->flash_arch->ebsize_bytes; if (len >= (UINT32_MAX - padding_len)) { return BLADERF_ERR_INVAL; } padded_image_len = (uint32_t) len + padding_len; readback_buf = malloc(padded_image_len); if (readback_buf == NULL) { return BLADERF_ERR_MEM; } padded_image = malloc(padded_image_len); if (padded_image == NULL) { free(readback_buf); return BLADERF_ERR_MEM; } /* Copy image */ memcpy(padded_image, image, len); /* Clear the padded region */ memset(padded_image + len, 0xFF, padded_image_len - len); /* Erase the entire firmware region */ status = spi_flash_erase(dev, flash_eb_fw, flash_eb_len_fw); if (status != 0) { log_debug("Failed to erase firmware region: %s\n", bladerf_strerror(status)); goto error; } /* Convert the image length to pages */ padded_image_len /= page_size; /* Write the firmware image to flash */ status = spi_flash_write(dev, padded_image, flash_page_fw, padded_image_len); if (status < 0) { log_debug("Failed to write firmware: %s\n", bladerf_strerror(status)); goto error; } /* Read back and double-check what we just wrote */ status = spi_flash_verify(dev, readback_buf, padded_image, flash_page_fw, padded_image_len); if (status != 0) { log_debug("Flash verification failed: %s\n", bladerf_strerror(status)); goto error; } error: free(padded_image); free(readback_buf); return status; } static inline void fill_fpga_metadata_page(struct bladerf *dev, uint8_t *metadata, size_t actual_bitstream_len) { char len_str[12]; int idx = 0; memset(len_str, 0, sizeof(len_str)); memset(metadata, 0xff, dev->flash_arch->psize_bytes); snprintf(len_str, sizeof(len_str), "%u", (unsigned int)actual_bitstream_len); binkv_encode_field((char *)metadata, dev->flash_arch->psize_bytes, &idx, "LEN", len_str); } static inline size_t get_flash_eb_len_fpga(struct bladerf *dev) { int status; size_t fpga_bytes; size_t eb_count; status = dev->board->get_fpga_bytes(dev, &fpga_bytes); if (status < 0) { return status; } eb_count = fpga_bytes / dev->flash_arch->ebsize_bytes; if ((fpga_bytes % dev->flash_arch->ebsize_bytes) > 0) { // Round up to nearest full block ++eb_count; } return eb_count; } #define METADATA_LEN 256 int spi_flash_write_fpga_bitstream(struct bladerf *dev, const uint8_t *bitstream, size_t len) { /* Pad data to be page-aligned */ const uint32_t page_size = dev->flash_arch->psize_bytes; const uint32_t padding_len = (len % page_size == 0) ? 0 : page_size - (len % page_size); /** Flash page where FPGA metadata and bitstream start */ const uint32_t flash_page_fpga = BLADERF_FLASH_ADDR_FPGA / dev->flash_arch->psize_bytes; /** Flash erase block where FPGA metadata and bitstream start */ const uint32_t flash_eb_fpga = BLADERF_FLASH_ADDR_FPGA / dev->flash_arch->ebsize_bytes; /** Length of entire FPGA region, in units of erase blocks */ const uint32_t flash_eb_len_fpga = (uint32_t)get_flash_eb_len_fpga(dev); assert(METADATA_LEN <= page_size); int status; uint8_t *readback_buf; uint8_t *padded_bitstream; uint8_t metadata[METADATA_LEN]; uint32_t padded_bitstream_len; if (len >= (UINT32_MAX - padding_len)) { return BLADERF_ERR_INVAL; } padded_bitstream_len = (uint32_t)len + padding_len; /* Fill in metadata with the *actual* FPGA bitstream length */ fill_fpga_metadata_page(dev, metadata, len); readback_buf = malloc(padded_bitstream_len); if (readback_buf == NULL) { return BLADERF_ERR_MEM; } padded_bitstream = malloc(padded_bitstream_len); if (padded_bitstream == NULL) { free(readback_buf); return BLADERF_ERR_MEM; } /* Copy bitstream */ memcpy(padded_bitstream, bitstream, len); /* Clear the padded region */ memset(padded_bitstream + len, 0xFF, padded_bitstream_len - len); /* Erase FPGA metadata and bitstream region */ status = spi_flash_erase(dev, flash_eb_fpga, flash_eb_len_fpga); if (status != 0) { log_debug("Failed to erase FPGA meta & bitstream regions: %s\n", bladerf_strerror(status)); goto error; } /* Write the metadata page */ status = spi_flash_write(dev, metadata, flash_page_fpga, 1); if (status != 0) { log_debug("Failed to write FPGA metadata page: %s\n", bladerf_strerror(status)); goto error; } /* Convert the padded bitstream length to pages */ padded_bitstream_len /= page_size; /* Write the padded bitstream */ status = spi_flash_write(dev, padded_bitstream, flash_page_fpga + 1, padded_bitstream_len); if (status != 0) { log_debug("Failed to write bitstream: %s\n", bladerf_strerror(status)); goto error; } /* Read back and verify metadata */ status = spi_flash_verify(dev, readback_buf, metadata, flash_page_fpga, 1); if (status != 0) { log_debug("Failed to verify metadata: %s\n", bladerf_strerror(status)); goto error; } /* Read back and verify the bitstream data */ status = spi_flash_verify(dev, readback_buf, padded_bitstream, flash_page_fpga + 1, padded_bitstream_len); if (status != 0) { log_debug("Failed to verify bitstream data: %s\n", bladerf_strerror(status)); goto error; } error: free(padded_bitstream); free(readback_buf); return status; } int spi_flash_erase_fpga(struct bladerf *dev) { int status; size_t fpga_bytes; status = dev->board->get_fpga_bytes(dev, &fpga_bytes); if (status < 0) { return status; } /** Flash erase block where FPGA metadata and bitstream start */ const uint32_t flash_eb_fpga = BLADERF_FLASH_ADDR_FPGA / dev->flash_arch->ebsize_bytes; /** Length of entire FPGA region, in units of erase blocks */ const uint32_t flash_eb_len_fpga = (uint32_t)get_flash_eb_len_fpga(dev); /* Erase the entire FPGA region, including both autoload metadata and the * actual bitstream data */ return spi_flash_erase(dev, flash_eb_fpga, flash_eb_len_fpga); } int spi_flash_read_otp(struct bladerf *dev, char *field, char *data, size_t data_size) { int status; char otp[OTP_BUFFER_SIZE]; memset(otp, 0xff, OTP_BUFFER_SIZE); status = dev->backend->get_otp(dev, otp); if (status < 0) return status; else return binkv_decode_field(otp, OTP_BUFFER_SIZE, field, data, data_size); } int spi_flash_read_cal(struct bladerf *dev, char *field, char *data, size_t data_size) { int status; char cal[CAL_BUFFER_SIZE]; status = dev->backend->get_cal(dev, cal); if (status < 0) return status; else return binkv_decode_field(cal, CAL_BUFFER_SIZE, field, data, data_size); } int spi_flash_read_serial(struct bladerf *dev, char *serial_buf) { int status; status = spi_flash_read_otp(dev, "S", serial_buf, BLADERF_SERIAL_LENGTH - 1); if (status < 0) { log_info("Unable to fetch serial number. Defaulting to 0's.\n"); memset(dev->ident.serial, '0', BLADERF_SERIAL_LENGTH - 1); /* Treat this as non-fatal */ status = 0; } serial_buf[BLADERF_SERIAL_LENGTH - 1] = '\0'; return status; } int spi_flash_read_vctcxo_trim(struct bladerf *dev, uint16_t *dac_trim) { int status; bool ok; int16_t trim; char tmp[7] = { 0 }; status = spi_flash_read_cal(dev, "DAC", tmp, sizeof(tmp) - 1); if (status < 0) { return status; } trim = str2uint(tmp, 0, 0xffff, &ok); if (ok == false) { return BLADERF_ERR_INVAL; } *dac_trim = trim; return 0; } int spi_flash_read_fpga_size(struct bladerf *dev, bladerf_fpga_size *fpga_size) { int status; char tmp[7] = { 0 }; status = spi_flash_read_cal(dev, "B", tmp, sizeof(tmp) - 1); if (status < 0) { return status; } if (!strcmp("40", tmp)) { *fpga_size = BLADERF_FPGA_40KLE; } else if(!strcmp("115", tmp)) { *fpga_size = BLADERF_FPGA_115KLE; } else if(!strcmp("A4", tmp)) { *fpga_size = BLADERF_FPGA_A4; } else if(!strcmp("A5", tmp)) { *fpga_size = BLADERF_FPGA_A5; } else if(!strcmp("A9", tmp)) { *fpga_size = BLADERF_FPGA_A9; } else { *fpga_size = BLADERF_FPGA_UNKNOWN; } return status; } int spi_flash_read_flash_id(struct bladerf *dev, uint8_t *mid, uint8_t *did) { int status; status = dev->backend->get_flash_id(dev, mid, did); return status; } int spi_flash_decode_flash_architecture(struct bladerf *dev, bladerf_fpga_size *fpga_size) { int status; struct bladerf_flash_arch *flash_arch; status = 0; flash_arch = dev->flash_arch; /* Fill in defaults */ flash_arch->tsize_bytes = 32 << 17; /* 32 Mbit */ flash_arch->psize_bytes = 256; flash_arch->ebsize_bytes = 64 << 10; /* 64 Kbyte */ flash_arch->status = STATUS_ASSUMED; /* First try to decode the MID/DID of the flash chip */ switch( flash_arch->manufacturer_id ) { case 0xC2: /* MACRONIX */ log_verbose( "Found SPI flash manufacturer: MACRONIX.\n" ); switch( flash_arch->device_id ) { case 0x36: log_verbose( "Found SPI flash device: MX25U3235E (32 Mbit).\n" ); flash_arch->tsize_bytes = 32 << 17; flash_arch->status = STATUS_SUCCESS; break; default: log_debug( "Unknown Macronix flash device ID.\n" ); status = BLADERF_ERR_UNEXPECTED; } break; case 0xEF: /* WINBOND */ log_verbose( "Found SPI flash manufacturer: WINBOND.\n" ); switch( flash_arch->device_id ) { case 0x15: log_verbose( "Found SPI flash device: W25Q32JV (32 Mbit).\n" ); flash_arch->tsize_bytes = 32 << 17; flash_arch->status = STATUS_SUCCESS; break; case 0x16: log_verbose( "Found SPI flash device: W25Q64JV (64 Mbit).\n" ); flash_arch->tsize_bytes = 64 << 17; flash_arch->status = STATUS_SUCCESS; break; case 0x17: log_verbose( "Found SPI flash device: W25Q128JV (128 Mbit).\n" ); flash_arch->tsize_bytes = 128 << 17; flash_arch->status = STATUS_SUCCESS; break; default: log_debug( "Unknown Winbond flash device ID [0x%02X].\n" , flash_arch->device_id ); status = BLADERF_ERR_UNEXPECTED; } break; default: log_debug( "Unknown flash manufacturer ID.\n" ); status = BLADERF_ERR_UNEXPECTED; } /* Could not decode flash MID/DID, so assume based on FPGA size */ if( status < 0 || flash_arch->status != STATUS_SUCCESS ) { if( (fpga_size == NULL) || (*fpga_size == BLADERF_FPGA_UNKNOWN) ) { log_debug( "Could not decode flash manufacturer/device ID and have " "an unknown FPGA size. Assume default flash " "architecture.\n" ); } else { switch( *fpga_size ) { case BLADERF_FPGA_A9: flash_arch->tsize_bytes = 128 << 17; break; default: flash_arch->tsize_bytes = 32 << 17; } log_debug( "Could not decode flash manufacturer/device ID, but " "found a %u kLE FPGA. Setting the most probable " "flash architecture.\n", *fpga_size ); } } flash_arch->num_pages = flash_arch->tsize_bytes / flash_arch->psize_bytes; flash_arch->num_ebs = flash_arch->tsize_bytes / flash_arch->ebsize_bytes; log_verbose("SPI flash total size = %u Mbit\n", (flash_arch->tsize_bytes >> 17)); log_verbose("SPI flash page size = %u bytes\n", flash_arch->psize_bytes); log_verbose("SPI flash erase block size = %u bytes\n", flash_arch->ebsize_bytes); log_verbose("SPI flash number of pages = %u\n", flash_arch->num_pages); log_verbose("SPI flash number of erase blocks = %u pages\n", flash_arch->num_ebs); return status; } int binkv_decode_field(char *ptr, int len, char *field, char *val, size_t maxlen) { int c; unsigned char *ub, *end; unsigned short a1, a2; size_t flen, wlen; flen = strlen(field); ub = (unsigned char *)ptr; end = ub + len; while (ub < end) { c = *ub; if (c == 0xff) // flash and OTP are 0xff if they've never been written to break; a1 = LE16_TO_HOST(*(unsigned short *)(&ub[c+1])); // read checksum a2 = zcrc(ub, c+1); // calculate checksum if (a1 == a2) { if (!strncmp((char *)ub + 1, field, flen)) { wlen = min_sz(c - flen, maxlen); strncpy(val, (char *)ub + 1 + flen, wlen); val[wlen] = 0; return 0; } } else { log_debug( "%s: Field checksum mismatch\n", __FUNCTION__); return BLADERF_ERR_INVAL; } ub += c + 3; //skip past `c' bytes, 2 byte CRC field, and 1 byte len field } return BLADERF_ERR_INVAL; } int binkv_encode_field(char *ptr, int len, int *idx, const char *field, const char *val) { int vlen, flen, tlen; flen = (int)strlen(field); vlen = (int)strlen(val); tlen = flen + vlen + 1; if (tlen >= 256 || *idx + tlen >= len) return BLADERF_ERR_MEM; ptr[*idx] = flen + vlen; strcpy(&ptr[*idx + 1], field); strcpy(&ptr[*idx + 1 + flen], val); *(unsigned short *)(&ptr[*idx + tlen ]) = HOST_TO_LE16(zcrc((uint8_t *)&ptr[*idx ], tlen)); *idx += tlen + 2; return 0; } int binkv_add_field(char *buf, int buf_len, const char *field_name, const char *val) { int dummy_idx = 0; int i = 0; int rv; /* skip to the end, ignoring crc (don't want to further corrupt partially * corrupt data) */ while(i < buf_len) { uint8_t field_len = buf[i]; if(field_len == 0xff) break; /* skip past `field_len' bytes, 2 byte CRC field, and 1 byte len * field */ i += field_len + 3; } rv = binkv_encode_field(buf + i, buf_len - i, &dummy_idx, field_name, val); if(rv < 0) return rv; return 0; }