diff --git a/TESTS/mbed_hal/qspi/main.cpp b/TESTS/mbed_hal/qspi/main.cpp index ed7db93a24..721d32e2ab 100644 --- a/TESTS/mbed_hal/qspi/main.cpp +++ b/TESTS/mbed_hal/qspi/main.cpp @@ -84,6 +84,7 @@ static uint32_t gen_flash_address() { srand(ticker_read(get_us_ticker_data())); uint32_t address = (((uint32_t)rand()) % QSPI_SECTOR_COUNT) * QSPI_SECTOR_SIZE; + address &= 0xFFFFFF; // Ensure address is within 24 bits so as to not have to deal with 4-byte addressing return address; } diff --git a/TESTS/mbed_hal/qspi/qspi_test_utils.cpp b/TESTS/mbed_hal/qspi/qspi_test_utils.cpp index 7c42384724..4fb49f409d 100644 --- a/TESTS/mbed_hal/qspi/qspi_test_utils.cpp +++ b/TESTS/mbed_hal/qspi/qspi_test_utils.cpp @@ -58,7 +58,7 @@ void QspiCommand::set_dummy_cycles(int dummy_cycles) void QspiCommand::build(int instruction, int address, int alt) { - _cmd.instruction.disabled = (instruction == QSPI_NONE); + _cmd.instruction.disabled = (instruction == QSPI_NO_INST); if (!_cmd.instruction.disabled) { _cmd.instruction.value = instruction; } @@ -127,17 +127,33 @@ void flash_init(Qspi &qspi) ret = qspi_command_transfer(&qspi.handle, qspi.cmd.get(), NULL, 0, status, QSPI_STATUS_REG_SIZE); TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - qspi.cmd.build(QSPI_CMD_RSTEN); - ret = qspi_command_transfer(&qspi.handle, qspi.cmd.get(), NULL, 0, NULL, 0); - TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + // Only do reset enable if device needs it + if (QSPI_CMD_RSTEN != 0) { + qspi.cmd.build(QSPI_CMD_RSTEN); + ret = qspi_command_transfer(&qspi.handle, qspi.cmd.get(), NULL, 0, NULL, 0); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - WAIT_FOR(WRSR_MAX_TIME, qspi); + WAIT_FOR(WRSR_MAX_TIME, qspi); + } qspi.cmd.build(QSPI_CMD_RST); ret = qspi_command_transfer(&qspi.handle, qspi.cmd.get(), NULL, 0, NULL, 0); TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); WAIT_FOR(WAIT_MAX_TIME, qspi); + + // Zero out status register to attempt to clear block protection bits + uint8_t blanks[QSPI_STATUS_REG_SIZE] = {0}; + + qspi.cmd.build(QSPI_CMD_WREN); + ret = qspi_command_transfer(&qspi.handle, qspi.cmd.get(), NULL, 0, NULL, 0); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + + qspi.cmd.build(QSPI_CMD_WRSR); + ret = qspi_command_transfer(&qspi.handle, qspi.cmd.get(), blanks, 1, NULL, 0); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + + WAIT_FOR(WRSR_MAX_TIME, qspi); } diff --git a/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.cpp b/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.cpp index 4ae242c9d5..f3083515d0 100644 --- a/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.cpp +++ b/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.cpp @@ -31,18 +31,23 @@ using namespace mbed; /****************************/ #define QSPIF_DEFAULT_PAGE_SIZE 256 #define QSPIF_DEFAULT_SE_SIZE 4096 -#define QSPI_MAX_STATUS_REGISTER_SIZE 3 +// The SFDP spec only defines two status registers. But some devices, +// have three "status-like" registers (one status, two config) +#define QSPI_MAX_STATUS_REGISTERS 3 +#define QSPI_DEFAULT_STATUS_REGISTERS 2 #ifndef UINT64_MAX #define UINT64_MAX -1 #endif #define QSPI_NO_ADDRESS_COMMAND UINT64_MAX #define QSPI_ALT_DEFAULT_VALUE 0 // Status Register Bits -#define QSPIF_STATUS_BIT_WIP 0x1 //Write In Progress +#define QSPIF_STATUS_BIT_WIP 0x1 // Write In Progress #define QSPIF_STATUS_BIT_WEL 0x2 // Write Enable Latch +#define QSPIF_NO_QUAD_ENABLE (-1) /* SFDP Header Parsing */ /***********************/ +#define QSPIF_RSFDP_DUMMY_CYCLES 8 #define QSPIF_SFDP_HEADER_SIZE 8 #define QSPIF_PARAM_HEADER_SIZE 8 @@ -63,42 +68,68 @@ using namespace mbed; #define QSPIF_BASIC_PARAM_TABLE_QER_BYTE 58 #define QSPIF_BASIC_PARAM_TABLE_444_MODE_EN_SEQ_BYTE 56 // Erase Types Params -#define QSPIF_BASIC_PARAM_ERASE_TYPE_1_BYTE 29 -#define QSPIF_BASIC_PARAM_ERASE_TYPE_2_BYTE 31 -#define QSPIF_BASIC_PARAM_ERASE_TYPE_3_BYTE 33 -#define QSPIF_BASIC_PARAM_ERASE_TYPE_4_BYTE 35 -#define QSPIF_BASIC_PARAM_ERASE_TYPE_1_SIZE_BYTE 28 -#define QSPIF_BASIC_PARAM_ERASE_TYPE_2_SIZE_BYTE 30 -#define QSPIF_BASIC_PARAM_ERASE_TYPE_3_SIZE_BYTE 32 -#define QSPIF_BASIC_PARAM_ERASE_TYPE_4_SIZE_BYTE 34 +#define QSPIF_BASIC_PARAM_TABLE_ERASE_TYPE_1_BYTE 29 +#define QSPIF_BASIC_PARAM_TABLE_ERASE_TYPE_2_BYTE 31 +#define QSPIF_BASIC_PARAM_TABLE_ERASE_TYPE_3_BYTE 33 +#define QSPIF_BASIC_PARAM_TABLE_ERASE_TYPE_4_BYTE 35 +#define QSPIF_BASIC_PARAM_TABLE_ERASE_TYPE_1_SIZE_BYTE 28 +#define QSPIF_BASIC_PARAM_TABLE_ERASE_TYPE_2_SIZE_BYTE 30 +#define QSPIF_BASIC_PARAM_TABLE_ERASE_TYPE_3_SIZE_BYTE 32 +#define QSPIF_BASIC_PARAM_TABLE_ERASE_TYPE_4_SIZE_BYTE 34 #define QSPIF_BASIC_PARAM_4K_ERASE_TYPE_BYTE 1 +#define QSPIF_BASIC_PARAM_TABLE_SOFT_RESET_BYTE 61 +#define QSPIF_BASIC_PARAM_TABLE_4BYTE_ADDR_BYTE 63 + +#define SOFT_RESET_RESET_INST_BITMASK 0b001000 +#define SOFT_RESET_ENABLE_AND_RESET_INST_BITMASK 0b010000 + // Erase Types Per Region BitMask #define ERASE_BITMASK_TYPE4 0x08 #define ERASE_BITMASK_TYPE1 0x01 #define ERASE_BITMASK_NONE 0x00 #define ERASE_BITMASK_ALL 0x0F +// 4-Byte Addressing Support Bitmasks +#define FOURBYTE_ADDR_B7_BITMASK 0b00000001 +#define FOURBYTE_ADDR_B7_WREN_BITMASK 0b00000010 +#define FOURBYTE_ADDR_EXT_ADDR_REG_BITMASK 0b00000100 +#define FOURBYTE_ADDR_BANK_REG_BITMASK 0b00001000 +#define FOURBYTE_ADDR_CONF_REG_BITMASK 0b00010000 +#define FOURBYTE_ADDR_INSTS_BITMASK 0b00100000 +#define FOURBYTE_ADDR_ALWAYS_BITMASK 0b01000000 + #define IS_MEM_READY_MAX_RETRIES 10000 -enum qspif_default_instructions { - QSPIF_NOP = 0x00, // No operation - QSPIF_PP = 0x02, // Page Program data - QSPIF_READ = 0x03, // Read data - QSPIF_SE = 0x20, // 4KB Sector Erase - QSPIF_SFDP = 0x5a, // Read SFDP - QSPIF_WRSR = 0x01, // Write Status/Configuration Register - QSPIF_WRDI = 0x04, // Write Disable - QSPIF_RDSR = 0x05, // Read Status Register - QSPIF_WREN = 0x06, // Write Enable - QSPIF_RSTEN = 0x66, // Reset Enable - QSPIF_RST = 0x99, // Reset - QSPIF_RDID = 0x9f, // Read Manufacturer and JDEC Device ID - QSPIF_ULBPR = 0x98, // Clears all write-protection bits in the Block-Protection register -}; -// Local Function -static int local_math_power(int base, int exp); +// General QSPI instructions +#define QSPIF_INST_WSR1 0x01 // Write status register 1 +#define QSPIF_INST_PROG 0x02 // Page program +#define QSPIF_INST_WRDI 0x04 // Write disable +#define QSPIF_INST_RSR1 0x05 // Read status register 1 +#define QSPIF_INST_WREN 0x06 // Write enable +#define QSPIF_INST_RSFDP 0x5A // Read SFDP +#define QSPIF_INST_RDID 0x9F // Read Manufacturer and JDEC Device ID + +// Device-specific instructions +#define QSPIF_INST_ULBPR 0x98 // Clear all write-protection bits in the Block-Protection register +#define QSPIF_INST_RDCR 0x15 // Read the two control registers + +// Default read/legacy erase instructions +#define QSPIF_INST_READ_DEFAULT 0x03 +#define QSPIF_INST_LEGACY_ERASE_DEFAULT QSPI_NO_INST + +// Default status register 2 read/write instructions +#define QSPIF_INST_WSR2_DEFAULT QSPI_NO_INST +#define QSPIF_INST_RSR2_DEFAULT 0x35 + +// Default 4-byte extended addressing register write instruction +#define QSPIF_INST_4BYTE_REG_WRITE_DEFAULT QSPI_NO_INST + + +// Length of data returned from RDID instruction +#define QSPI_RDID_DATA_LENGTH 3 + /* Init function to initialize Different Devices CS static list */ static PinName *generate_initialized_active_qspif_csel_arr(); @@ -125,6 +156,39 @@ QSPIFBlockDevice::QSPIFBlockDevice(PinName io0, PinName io1, PinName io2, PinNam } else { tr_error("Too many different QSPIFBlockDevice devices - max allowed: %d", QSPIF_MAX_ACTIVE_FLASH_DEVICES); } + + // Initialize parameters + _min_common_erase_size = 0; + _regions_count = 1; + _region_erase_types_bitfield[0] = ERASE_BITMASK_NONE; + + // Until proven otherwise, assume no quad enable + _quad_enable_register_idx = QSPIF_NO_QUAD_ENABLE; + _quad_enable_bit = QSPIF_NO_QUAD_ENABLE; + _needs_fast_mode = false; + + // Default Bus Setup 1_1_1 with 0 dummy and mode cycles + _inst_width = QSPI_CFG_BUS_SINGLE; + _address_width = QSPI_CFG_BUS_SINGLE; + _address_size = QSPI_CFG_ADDR_SIZE_24; + _alt_size = 0; + _dummy_cycles = 0; + _data_width = QSPI_CFG_BUS_SINGLE; + + // Set default read/erase instructions + _read_instruction = QSPIF_INST_READ_DEFAULT; + _legacy_erase_instruction = QSPIF_INST_LEGACY_ERASE_DEFAULT; + + _num_status_registers = QSPI_DEFAULT_STATUS_REGISTERS; + // Set default status register 2 write/read instructions + _write_status_reg_2_inst = QSPIF_INST_WSR2_DEFAULT; + _read_status_reg_2_inst = QSPIF_INST_RSR2_DEFAULT; + + _clear_protection_method = QSPIF_BP_CLEAR_SR; + + // Set default 4-byte addressing extension register write instruction + _attempt_4_byte_addressing = true; + _4byte_msb_reg_write_inst = QSPIF_INST_4BYTE_REG_WRITE_DEFAULT; } int QSPIFBlockDevice::init() @@ -133,23 +197,28 @@ int QSPIFBlockDevice::init() tr_debug("QSPIFBlockDevice csel: %d", (int)_csel); } else if (_unique_device_status == -1) { tr_error("QSPIFBlockDevice with the same csel(%d) already exists", (int)_csel); - return QSPIF_BD_ERROR_DEVICE_NOT_UNIQE; + return QSPIF_BD_ERROR_DEVICE_NOT_UNIQUE; } else { tr_error("Too many different QSPIFBlockDevice devices - max allowed: %d", QSPIF_MAX_ACTIVE_FLASH_DEVICES); return QSPIF_BD_ERROR_DEVICE_MAX_EXCEED; } - uint8_t vendor_device_ids[4]; - size_t data_length = 3; int status = QSPIF_BD_ERROR_OK; uint32_t basic_table_addr = 0; size_t basic_table_size = 0; uint32_t sector_map_table_addr = 0; size_t sector_map_table_size = 0; - int qspi_status = QSPI_STATUS_OK; _mutex.lock(); + // All commands other than Read and RSFDP use default 1-1-1 bus mode (Program/Erase are constrained by flash memory performance more than bus performance) + if (QSPI_STATUS_OK != _qspi.configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, _address_size, QSPI_CFG_BUS_SINGLE, + 0, QSPI_CFG_BUS_SINGLE, 0)) { + tr_error("_qspi_configure_format failed"); + status = QSPIF_BD_ERROR_DEVICE_ERROR; + goto exit_point; + } + if (!_is_initialized) { _init_ref_count = 0; } @@ -160,63 +229,27 @@ int QSPIFBlockDevice::init() goto exit_point; } - //Initialize parameters - _min_common_erase_size = 0; - _regions_count = 1; - _region_erase_types_bitfield[0] = ERASE_BITMASK_NONE; - - //Default Bus Setup 1_1_1 with 0 dummy and mode cycles - _inst_width = QSPI_CFG_BUS_SINGLE; - _address_width = QSPI_CFG_BUS_SINGLE; - _address_size = QSPI_CFG_ADDR_SIZE_24; _alt_size = 0; _dummy_cycles = 0; - _data_width = QSPI_CFG_BUS_SINGLE; - _write_register_inst = QSPIF_WRSR; - _read_register_inst = QSPIF_RDSR; - if (QSPI_STATUS_OK != _qspi_set_frequency(_freq)) { tr_error("QSPI Set Frequency Failed"); status = QSPIF_BD_ERROR_DEVICE_ERROR; goto exit_point; } - // Soft Reset - if (-1 == _reset_flash_mem()) { - tr_error("Init - Unable to initialize flash memory, tests failed"); - status = QSPIF_BD_ERROR_DEVICE_ERROR; - goto exit_point; - } else { - tr_debug("Initialize flash memory OK"); - } - - /* Read Manufacturer ID (1byte), and Device ID (2bytes)*/ - qspi_status = _qspi_send_general_command(QSPIF_RDID, QSPI_NO_ADDRESS_COMMAND, NULL, 0, (char *)vendor_device_ids, - data_length); - if (qspi_status != QSPI_STATUS_OK) { - tr_error("Init - Read Vendor ID Failed"); - status = QSPIF_BD_ERROR_DEVICE_ERROR; - goto exit_point; - } - - tr_debug("Vendor device ID = 0x%x 0x%x 0x%x 0x%x", vendor_device_ids[0], - vendor_device_ids[1], vendor_device_ids[2], vendor_device_ids[3]); - switch (vendor_device_ids[0]) { - case 0xbf: - // SST devices come preset with block protection - // enabled for some regions, issue global protection unlock to clear - _set_write_enable(); - _qspi_send_general_command(QSPIF_ULBPR, QSPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0); - break; - } - - //Synchronize Device + // Synchronize Device if (false == _is_mem_ready()) { tr_error("Init - _is_mem_ready Failed"); status = QSPIF_BD_ERROR_READY_FAILED; goto exit_point; } + if (0 != _handle_vendor_quirks()) { + tr_error("Init - Could not read vendor id"); + status = QSPIF_BD_ERROR_DEVICE_ERROR; + goto exit_point; + } + /**************************** Parse SFDP Header ***********************************/ if (0 != _sfdp_parse_sfdp_headers(basic_table_addr, basic_table_size, sector_map_table_addr, sector_map_table_size)) { tr_error("Init - Parse SFDP Headers Failed"); @@ -246,11 +279,9 @@ int QSPIFBlockDevice::init() } } - // Configure BUS Mode to 1_1_1 for all commands other than Read - if (QSPI_STATUS_OK != _qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE, - 0, QSPI_CFG_BUS_SINGLE, 0)) { - tr_error("_qspi_configure_format failed"); - status = QSPIF_BD_ERROR_DEVICE_ERROR; + if (0 != _clear_block_protection()) { + tr_error("Init - clearing block protection failed"); + status = QSPIF_BD_ERROR_PARSING_FAILED; goto exit_point; } @@ -282,7 +313,7 @@ int QSPIFBlockDevice::deinit() } // Disable Device for Writing - qspi_status_t status = _qspi_send_general_command(QSPIF_WRDI, QSPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0); + qspi_status_t status = _qspi_send_general_command(QSPIF_INST_WRDI, QSPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0); if (status != QSPI_STATUS_OK) { tr_error("Write Disable failed"); result = QSPIF_BD_ERROR_DEVICE_ERROR; @@ -306,28 +337,11 @@ int QSPIFBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size) _mutex.lock(); - // Configure Bus for Reading - if (QSPI_STATUS_OK != _qspi_configure_format(_inst_width, _address_width, _address_size, _address_width, // Alt width == address width - _alt_size, _data_width, _dummy_cycles)) { - tr_error("_qspi_configure_format failed"); - status = QSPIF_BD_ERROR_DEVICE_ERROR; - goto exit_point; - } - if (QSPI_STATUS_OK != _qspi_send_read_command(_read_instruction, buffer, addr, size)) { tr_error("Read Command failed"); status = QSPIF_BD_ERROR_DEVICE_ERROR; - goto exit_point; } - // All commands other than Read use default 1-1-1 Bus mode (Program/Erase are constrained by flash memory performance more than bus performance) - if (QSPI_STATUS_OK != _qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE, 0, QSPI_CFG_BUS_SINGLE, 0)) { - tr_error("_qspi_configure_format failed"); - status = QSPIF_BD_ERROR_DEVICE_ERROR; - goto exit_point; - } - -exit_point: _mutex.unlock(); return status; @@ -361,7 +375,7 @@ int QSPIFBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size goto exit_point; } - result = _qspi_send_program_command(_prog_instruction, buffer, addr, &written_bytes); + result = _qspi_send_program_command(QSPIF_INST_PROG, buffer, addr, &written_bytes); if ((result != QSPI_STATUS_OK) || (chunk != written_bytes)) { tr_error("Write failed"); program_failed = true; @@ -395,7 +409,7 @@ int QSPIFBlockDevice::erase(bd_addr_t addr, bd_size_t in_size) int type = 0; uint32_t offset = 0; uint32_t chunk = 4096; - qspi_inst_t cur_erase_inst = _erase_instruction; + qspi_inst_t cur_erase_inst = QSPI_NO_INST; int size = (int)in_size; bool erase_failed = false; int status = QSPIF_BD_ERROR_OK; @@ -418,12 +432,20 @@ int QSPIFBlockDevice::erase(bd_addr_t addr, bd_size_t in_size) // For each iteration erase the largest section supported by current region while (size > 0) { - // iterate to find next Largest erase type ( a. supported by region, b. smaller than size) - // find the matching instruction and erase size chunk for that type. - type = _utils_iterate_next_largest_erase_type(bitfield, size, (int)addr, _region_high_boundary[region]); - cur_erase_inst = _erase_type_inst_arr[type]; - offset = addr % _erase_type_size_arr[type]; - chunk = ((offset + size) < _erase_type_size_arr[type]) ? size : (_erase_type_size_arr[type] - offset); + unsigned int eu_size; + if (_legacy_erase_instruction == QSPI_NO_INST) { + // Iterate to find next largest erase type that is a) supported by region, and b) smaller than size. + // Find the matching instruction and erase size chunk for that type. + type = _utils_iterate_next_largest_erase_type(bitfield, size, (int)addr, _region_high_boundary[region]); + cur_erase_inst = _erase_type_inst_arr[type]; + eu_size = _erase_type_size_arr[type]; + } else { + // Must use legacy 4k erase instruction + cur_erase_inst = _legacy_erase_instruction; + eu_size = QSPIF_DEFAULT_SE_SIZE; + } + offset = addr % eu_size; + chunk = ((offset + size) < eu_size) ? size : (eu_size - offset); tr_debug("Erase - addr: %llu, size:%d, Inst: 0x%xh, chunk: %lu ", addr, size, cur_erase_inst, chunk); @@ -499,6 +521,11 @@ const char *QSPIFBlockDevice::get_type() const // Find minimal erase size supported by the region to which the address belongs to bd_size_t QSPIFBlockDevice::get_erase_size(bd_addr_t addr) { + // If the legacy erase instruction is in use, the erase size is uniformly 4k + if (_legacy_erase_instruction != QSPI_NO_INST) { + return QSPIF_DEFAULT_SE_SIZE; + } + // Find region of current address int region = _utils_find_addr_region(addr); @@ -506,7 +533,6 @@ bd_size_t QSPIFBlockDevice::get_erase_size(bd_addr_t addr) int8_t type_mask = ERASE_BITMASK_TYPE1; int i_ind = 0; - if (region != -1) { type_mask = 0x01; @@ -603,126 +629,6 @@ int QSPIFBlockDevice::remove_csel_instance(PinName csel) /*********************************************************/ /********** SFDP Parsing and Detection Functions *********/ /*********************************************************/ -int QSPIFBlockDevice::_sfdp_parse_sector_map_table(uint32_t sector_map_table_addr, size_t sector_map_table_size) -{ - uint8_t sector_map_table[SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES]; /* Up To 16 DWORDS = 64 Bytes */ - uint32_t tmp_region_size = 0; - int i_ind = 0; - int prev_boundary = 0; - // Default set to all type bits 1-4 are common - int min_common_erase_type_bits = ERASE_BITMASK_ALL; - - - qspi_status_t status = _qspi_send_read_command(QSPIF_SFDP, (char *)sector_map_table, sector_map_table_addr /*address*/, - sector_map_table_size); - if (status != QSPI_STATUS_OK) { - tr_error("Init - Read SFDP First Table Failed"); - return -1; - } - - // Currently we support only Single Map Descriptor - if (!((sector_map_table[0] & 0x3) == 0x03) && (sector_map_table[1] == 0x0)) { - tr_error("Sector Map - Supporting Only Single! Map Descriptor (not map commands)"); - return -1; - } - - _regions_count = sector_map_table[2] + 1; - if (_regions_count > QSPIF_MAX_REGIONS) { - tr_error("Supporting up to %d regions, current setup to %d regions - fail", - QSPIF_MAX_REGIONS, _regions_count); - return -1; - } - - // Loop through Regions and set for each one: size, supported erase types, high boundary offset - // Calculate minimum Common Erase Type for all Regions - for (i_ind = 0; i_ind < _regions_count; i_ind++) { - tmp_region_size = ((*((uint32_t *)§or_map_table[(i_ind + 1) * 4])) >> 8) & 0x00FFFFFF; // bits 9-32 - _region_size_bytes[i_ind] = (tmp_region_size + 1) * 256; // Region size is 0 based multiple of 256 bytes; - _region_erase_types_bitfield[i_ind] = sector_map_table[(i_ind + 1) * 4] & 0x0F; // bits 1-4 - min_common_erase_type_bits &= _region_erase_types_bitfield[i_ind]; - _region_high_boundary[i_ind] = (_region_size_bytes[i_ind] - 1) + prev_boundary; - prev_boundary = _region_high_boundary[i_ind] + 1; - } - - // Calc minimum Common Erase Size from min_common_erase_type_bits - uint8_t type_mask = ERASE_BITMASK_TYPE1; - for (i_ind = 0; i_ind < 4; i_ind++) { - if (min_common_erase_type_bits & type_mask) { - _min_common_erase_size = _erase_type_size_arr[i_ind]; - break; - } - type_mask = type_mask << 1; - } - - if (i_ind == 4) { - // No common erase type was found between regions - _min_common_erase_size = 0; - } - - return 0; -} - -int QSPIFBlockDevice::_sfdp_parse_basic_param_table(uint32_t basic_table_addr, size_t basic_table_size) -{ - uint8_t param_table[SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES]; /* Up To 16 DWORDS = 64 Bytes */ - - qspi_status_t status = _qspi_send_read_command(QSPIF_SFDP, (char *)param_table, basic_table_addr /*address*/, - basic_table_size); - if (status != QSPI_STATUS_OK) { - tr_error("Init - Read SFDP First Table Failed"); - return -1; - } - - // Check address size, currently only supports 3byte addresses - if ((param_table[2] & 0x4) != 0 || (param_table[7] & 0x80) != 0) { - tr_error("Init - verify 3byte addressing Failed"); - return -1; - } - - // Get device density (stored in bits - 1) - uint32_t density_bits = ( - (param_table[7] << 24) | - (param_table[6] << 16) | - (param_table[5] << 8) | - param_table[4]); - _device_size_bytes = (density_bits + 1) / 8; - - // Set Default read/program/erase Instructions - _read_instruction = QSPIF_READ; - _prog_instruction = QSPIF_PP; - _erase_instruction = QSPIF_SE; - - _erase_instruction = _erase4k_inst; - - // Set Page Size (QSPI write must be done on Page limits) - _page_size_bytes = _sfdp_detect_page_size(param_table, basic_table_size); - - // Detect and Set Erase Types - bool shouldSetQuadEnable = false; - bool is_qpi_mode = false; - - _sfdp_detect_erase_types_inst_and_size(param_table, basic_table_size, _erase4k_inst, _erase_type_inst_arr, - _erase_type_size_arr); - _erase_instruction = _erase4k_inst; - - // Detect and Set fastest Bus mode (default 1-1-1) - _sfdp_detect_best_bus_read_mode(param_table, basic_table_size, shouldSetQuadEnable, is_qpi_mode, _read_instruction); - if (true == shouldSetQuadEnable) { - _enable_fast_mdoe(); - // Set Quad Enable and QPI Bus modes if Supported - tr_debug("Init - Setting Quad Enable"); - if (0 != _sfdp_set_quad_enabled(param_table)) { - tr_error("Device supports Quad bus, but Quad Enable Failed"); - return -1; - } - if (true == is_qpi_mode) { - tr_debug("Init - Setting QPI mode"); - _sfdp_set_qpi_enabled(param_table); - } - } - return 0; -} - int QSPIFBlockDevice::_sfdp_parse_sfdp_headers(uint32_t &basic_table_addr, size_t &basic_table_size, uint32_t §or_map_table_addr, size_t §or_map_table_size) { @@ -731,14 +637,7 @@ int QSPIFBlockDevice::_sfdp_parse_sfdp_headers(uint32_t &basic_table_addr, size_ size_t data_length = QSPIF_SFDP_HEADER_SIZE; bd_addr_t addr = 0x0; - // Set 1-1-1 bus mode for SFDP header parsing - if (QSPI_STATUS_OK != _qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE, - 0, QSPI_CFG_BUS_SINGLE, 8)) { - tr_error("_qspi_configure_format failed"); - return -1; - } - - qspi_status_t status = _qspi_send_read_command(QSPIF_SFDP, (char *)sfdp_header, addr /*address*/, data_length); + qspi_status_t status = _qspi_send_read_sfdp_command(addr, (char *) sfdp_header, data_length); if (status != QSPI_STATUS_OK) { tr_error("Init - Read SFDP Failed"); return -1; @@ -747,10 +646,10 @@ int QSPIFBlockDevice::_sfdp_parse_sfdp_headers(uint32_t &basic_table_addr, size_ // Verify SFDP signature for sanity // Also check that major/minor version is acceptable if (!(memcmp(&sfdp_header[0], "SFDP", 4) == 0 && sfdp_header[5] == 1)) { - tr_error("Init - _verify SFDP signature and version Failed"); + tr_error("Init - Verification of SFDP signature and version failed"); return -1; } else { - tr_debug("Init - verified SFDP Signature and version Successfully"); + tr_debug("Init - Verification of SFDP signature and version succeeded"); } // Discover Number of Parameter Headers @@ -761,10 +660,9 @@ int QSPIFBlockDevice::_sfdp_parse_sfdp_headers(uint32_t &basic_table_addr, size_ addr += QSPIF_SFDP_HEADER_SIZE; data_length = QSPIF_PARAM_HEADER_SIZE; - // Loop over Param Headers and parse them (currently supported Basic Param Table and Sector Region Map Table) + // Loop over Param Headers and parse them (currently supports Basic Param Table and Sector Region Map Table) for (int i_ind = 0; i_ind < number_of_param_headers; i_ind++) { - - status = _qspi_send_read_command(QSPIF_SFDP, (char *)param_header, addr, data_length); + status = _qspi_send_read_sfdp_command(addr, (char *) param_header, data_length); if (status != QSPI_STATUS_OK) { tr_error("Init - Read Param Table %d Failed", i_ind + 1); return -1; @@ -783,17 +681,166 @@ int QSPIFBlockDevice::_sfdp_parse_sfdp_headers(uint32_t &basic_table_addr, size_ basic_table_addr = ((param_header[6] << 16) | (param_header[5] << 8) | (param_header[4])); // Supporting up to 64 Bytes Table (16 DWORDS) basic_table_size = ((param_header[3] * 4) < SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES) ? (param_header[3] * 4) : 64; - } else if ((param_header[0] == 81) && (param_header[7] == 0xFF)) { // Found Sector Map Table: LSB=0x81, MSB=0xFF tr_debug("Found Sector Map Table at Table: %d", i_ind + 1); sector_map_table_addr = ((param_header[6] << 16) | (param_header[5] << 8) | (param_header[4])); sector_map_table_size = param_header[3] * 4; - } addr += QSPIF_PARAM_HEADER_SIZE; - } + + return 0; +} + +int QSPIFBlockDevice::_sfdp_parse_basic_param_table(uint32_t basic_table_addr, size_t basic_table_size) +{ + uint8_t param_table[SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES]; /* Up To 16 DWORDS = 64 Bytes */ + + qspi_status_t status = _qspi_send_read_sfdp_command(basic_table_addr, (char *) param_table, basic_table_size); + if (status != QSPI_STATUS_OK) { + tr_error("Init - Read SFDP First Table Failed"); + return -1; + } + + // Check that density is not greater than 4 gigabits (i.e. that addressing beyond 4 bytes is not required) + if ((param_table[7] & 0x80) != 0) { + tr_error("Init - verify flash density failed"); + return -1; + } + + // Get device density (stored in bits - 1) + uint32_t density_bits = ((param_table[7] << 24) | + (param_table[6] << 16) | + (param_table[5] << 8) | + param_table[4]); + _device_size_bytes = (density_bits + 1) / 8; + + // Set Page Size (QSPI write must be done on Page limits) + _page_size_bytes = _sfdp_detect_page_size(param_table, basic_table_size); + + if (_sfdp_detect_reset_protocol_and_reset(param_table) != QSPIF_BD_ERROR_OK) { + tr_error("Init - Detecting reset protocol/resetting failed"); + return -1; + } + + // Detect and Set Erase Types + bool shouldSetQuadEnable = false; + bool is_qpi_mode = false; + + if (_sfdp_detect_erase_types_inst_and_size(param_table, basic_table_size) != 0) { + tr_error("Init - Detecting erase types instructions/sizes failed"); + return -1; + } + + // Detect and Set fastest Bus mode (default 1-1-1) + _sfdp_detect_best_bus_read_mode(param_table, basic_table_size, shouldSetQuadEnable, is_qpi_mode); + if (true == shouldSetQuadEnable) { + if (_needs_fast_mode) { + _enable_fast_mode(); + } + // Set Quad Enable and QPI Bus modes if Supported + tr_debug("Init - Setting Quad Enable"); + if (0 != _sfdp_set_quad_enabled(param_table)) { + tr_error("Device supports Quad bus, but Quad Enable Failed"); + return -1; + } + if (true == is_qpi_mode) { + tr_debug("Init - Setting QPI mode"); + _sfdp_set_qpi_enabled(param_table); + } + } + +#ifndef TARGET_NORDIC + // 4 byte addressing is not currently supported with the Nordic QSPI controller + if (_attempt_4_byte_addressing) { + if (_sfdp_detect_and_enable_4byte_addressing(param_table, basic_table_size) != QSPIF_BD_ERROR_OK) { + tr_error("Init - Detecting/enabling 4-byte addressing failed"); + return -1; + } + } +#endif + + if (false == _is_mem_ready()) { + tr_error("Init - _is_mem_ready Failed"); + return -1; + } + + return 0; +} + +int QSPIFBlockDevice::_sfdp_set_quad_enabled(uint8_t *basic_param_table_ptr) +{ + uint8_t status_reg_setup[QSPI_MAX_STATUS_REGISTERS] = {0}; + uint8_t status_regs[QSPI_MAX_STATUS_REGISTERS] = {0}; + + // QUAD Enable procedure is specified by 3 bits + uint8_t qer_value = (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_QER_BYTE] & 0x70) >> 4; + + switch (qer_value) { + case 0: + tr_debug("Device Does not Have a QE Bit, continue based on Read Inst"); + return 0; + case 1: + case 4: + // Bit 1 of Status Reg 2 + _quad_enable_register_idx = 1; + _quad_enable_bit = 1; + tr_debug("Setting QE Bit, Bit 1 of Status Reg 2"); + break; + case 2: + // Bit 6 of Status Reg 1 + _quad_enable_register_idx = 0; + _quad_enable_bit = 6; + tr_debug("Setting QE Bit, Bit 6 of Status Reg 1"); + break; + case 3: + // Bit 7 of Status Reg 1 + _quad_enable_register_idx = 0; + _quad_enable_bit = 7; + _write_status_reg_2_inst = 0x3E; + _read_status_reg_2_inst = 0x3F; + tr_debug("Setting QE Bit, Bit 7 of Status Reg 1"); + break; + case 5: + // Bit 1 of status Reg 2 + _quad_enable_register_idx = 1; + _quad_enable_bit = 1; + tr_debug("Setting QE Bit, Bit 1 of Status Reg 2"); + break; + default: + tr_warning("Unsupported QER configuration"); + return 0; + } + + if (_quad_enable_register_idx != QSPIF_NO_QUAD_ENABLE && _quad_enable_bit != QSPIF_NO_QUAD_ENABLE) { + status_reg_setup[_quad_enable_register_idx] = 1 << _quad_enable_bit; + } + + // Read existing status register values + _qspi_read_status_registers(status_regs); + + // Set Bits for Quad Enable + for (int i = 0; i < QSPI_MAX_STATUS_REGISTERS; i++) { + status_regs[i] |= status_reg_setup[i]; + } + + // Write new Status Register Setup + _qspi_write_status_registers(status_regs); + + if (false == _is_mem_ready()) { + tr_error("Device not ready after write, failed"); + return -1; + } + + // For Debug + memset(status_regs, 0, QSPI_MAX_STATUS_REGISTERS); + _qspi_read_status_registers(status_regs); + if (((status_regs[0] & status_reg_setup[0]) | (status_regs[1] & status_reg_setup[1])) == 0) { + tr_error("Status register not set correctly"); + return -1; + } + return 0; } @@ -844,121 +891,12 @@ int QSPIFBlockDevice::_sfdp_set_qpi_enabled(uint8_t *basic_param_table_ptr) break; default: - tr_warning("_sfdp_set_qpi_enabled - Unsuported En Seq 444 configuration"); + tr_warning("_sfdp_set_qpi_enabled - Unsupported En Seq 444 configuration"); break; } return 0; } - - -int QSPIFBlockDevice::_sfdp_set_quad_enabled(uint8_t *basic_param_table_ptr) -{ - int sr_read_size = QSPI_MAX_STATUS_REGISTER_SIZE; - int sr_write_size = QSPI_MAX_STATUS_REGISTER_SIZE; - - char status_reg_setup[QSPI_MAX_STATUS_REGISTER_SIZE] = {0}; - char status_reg[QSPI_MAX_STATUS_REGISTER_SIZE] = {0}; - - // QUAD Enable procedure is specified by 3 bits - uint8_t qer_value = (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_QER_BYTE] & 0x70) >> 4; - - - switch (qer_value) { - case 0: - tr_debug("Device Does not Have a QE Bit, continue based on Read Inst"); - return 0; - - case 1: - case 4: - status_reg_setup[1] = 0x02; //Bit 1 of Status Reg 2 - sr_write_size = 2; - tr_debug("Setting QE Bit, Bit 1 of Status Reg 2"); - break; - - case 2: - status_reg_setup[0] = 0x40; // Bit 6 of Status Reg 1 - sr_write_size = 1; - tr_debug("Setting QE Bit, Bit 6 of Status Reg 1"); - break; - - case 3: - status_reg_setup[0] = 0x80; // Bit 7 of Status Reg 1 - sr_write_size = 1; - _write_register_inst = 0x3E; - _read_register_inst = 0x3F; - tr_debug("Setting QE Bit, Bit 7 of Status Reg 1"); - break; - case 5: - status_reg_setup[1] = 0x2; // Bit 1 of status Reg 2 - _read_register_inst = 0x35; - sr_read_size = 1; - sr_write_size = 2; - tr_debug("Setting QE Bit, Bit 1 of Status Reg 2 -special read command"); - break; - default: - tr_warning("Unsuported QER configuration"); - return 0; - } - - // Configure BUS Mode to 1_1_1 for all commands other than Read - if (QSPI_STATUS_OK != _qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE, - 0, QSPI_CFG_BUS_SINGLE, 0)) { - tr_error("_qspi_configure_format failed"); - return -1; - } - - // Read Status Register - if (QSPI_STATUS_OK == _qspi_send_general_command(_read_register_inst, QSPI_NO_ADDRESS_COMMAND, NULL, 0, - status_reg, - sr_read_size)) { // store received values in status_value - tr_debug("Reading Status Register Success: value = 0x%x", (int)status_reg[0]); - } else { - tr_error("Reading Status Register failed"); - return -1; - } - - // Set Bits for Quad Enable - for (int i = 0; i < QSPI_MAX_STATUS_REGISTER_SIZE; i++) { - status_reg[i] |= status_reg_setup[i]; - } - - // Write new Status Register Setup - if (_set_write_enable() != 0) { - tr_error("Write Enabe failed"); - return -1; - } - - if (QSPI_STATUS_OK == _qspi_send_general_command(_write_register_inst, QSPI_NO_ADDRESS_COMMAND, (char *)status_reg, - sr_write_size, NULL, - 0)) { // Write QE to status_register - tr_debug("_setQuadEnable - Writing Status Register Success: value = 0x%x", - (int)status_reg[0]); - } else { - tr_error("_setQuadEnable - Writing Status Register failed"); - return -1; - } - - if (false == _is_mem_ready()) { - tr_error("Device not ready after write, failed"); - return -1; - } - - - // For Debug - memset(status_reg, 0, QSPI_MAX_STATUS_REGISTER_SIZE); - if (QSPI_STATUS_OK == _qspi_send_general_command(_read_register_inst, QSPI_NO_ADDRESS_COMMAND, NULL, 0, - (char *)status_reg, - sr_read_size)) { // store received values in status_value - tr_debug("Reading Status Register Success: value = 0x%x", (int)status_reg[0]); - } else { - tr_error("Reading Status Register failed"); - return -1; - } - - return 0; -} - int QSPIFBlockDevice::_sfdp_detect_page_size(uint8_t *basic_param_table_ptr, int basic_param_table_size) { unsigned int page_size = QSPIF_DEFAULT_PAGE_SIZE; @@ -966,7 +904,7 @@ int QSPIFBlockDevice::_sfdp_detect_page_size(uint8_t *basic_param_table_ptr, int if (basic_param_table_size > QSPIF_BASIC_PARAM_TABLE_PAGE_SIZE_BYTE) { // Page Size is specified by 4 Bits (N), calculated by 2^N int page_to_power_size = ((int)basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_PAGE_SIZE_BYTE]) >> 4; - page_size = local_math_power(2, page_to_power_size); + page_size = 1 << page_to_power_size; tr_debug("Detected Page Size: %d", page_size); } else { tr_debug("Using Default Page Size: %d", page_size); @@ -974,62 +912,49 @@ int QSPIFBlockDevice::_sfdp_detect_page_size(uint8_t *basic_param_table_ptr, int return page_size; } -int QSPIFBlockDevice::_sfdp_detect_erase_types_inst_and_size(uint8_t *basic_param_table_ptr, int basic_param_table_size, - qspi_inst_t &erase4k_inst, - qspi_inst_t *erase_type_inst_arr, unsigned int *erase_type_size_arr) +int QSPIFBlockDevice::_sfdp_detect_erase_types_inst_and_size(uint8_t *basic_param_table_ptr, int basic_param_table_size) { - erase4k_inst = 0xff; - bool found_4Kerase_type = false; uint8_t bitfield = 0x01; // Erase 4K Inst is taken either from param table legacy 4K erase or superseded by erase Instruction for type of size 4K - erase4k_inst = basic_param_table_ptr[QSPIF_BASIC_PARAM_4K_ERASE_TYPE_BYTE]; - - if (basic_param_table_size > QSPIF_BASIC_PARAM_ERASE_TYPE_1_SIZE_BYTE) { + if (basic_param_table_size > QSPIF_BASIC_PARAM_TABLE_ERASE_TYPE_1_SIZE_BYTE) { // Loop Erase Types 1-4 for (int i_ind = 0; i_ind < 4; i_ind++) { - erase_type_inst_arr[i_ind] = 0xff; //0xFF default for unsupported type - erase_type_size_arr[i_ind] = local_math_power(2, - basic_param_table_ptr[QSPIF_BASIC_PARAM_ERASE_TYPE_1_SIZE_BYTE + 2 * i_ind]); // Size given as 2^N - tr_debug("Erase Type(A) %d - Inst: 0x%xh, Size: %d", (i_ind + 1), erase_type_inst_arr[i_ind], - erase_type_size_arr[i_ind]); - if (erase_type_size_arr[i_ind] > 1) { + _erase_type_inst_arr[i_ind] = QSPI_NO_INST; // Default for unsupported type + _erase_type_size_arr[i_ind] = 1 << basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_ERASE_TYPE_1_SIZE_BYTE + 2 * i_ind]; // Size is 2^N where N is the table value + tr_debug("Erase Type(A) %d - Inst: 0x%xh, Size: %d", (i_ind + 1), _erase_type_inst_arr[i_ind], + _erase_type_size_arr[i_ind]); + if (_erase_type_size_arr[i_ind] > 1) { // if size==1 type is not supported - erase_type_inst_arr[i_ind] = basic_param_table_ptr[QSPIF_BASIC_PARAM_ERASE_TYPE_1_BYTE + 2 * i_ind]; + _erase_type_inst_arr[i_ind] = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_ERASE_TYPE_1_BYTE + 2 * i_ind]; - if ((erase_type_size_arr[i_ind] < _min_common_erase_size) || (_min_common_erase_size == 0)) { - //Set default minimal common erase for singal region - _min_common_erase_size = erase_type_size_arr[i_ind]; + if ((_erase_type_size_arr[i_ind] < _min_common_erase_size) || (_min_common_erase_size == 0)) { + //Set default minimal common erase for signal region + _min_common_erase_size = _erase_type_size_arr[i_ind]; } - - // SFDP standard requires 4K Erase type to exist and its instruction to be identical to legacy field erase instruction - if (erase_type_size_arr[i_ind] == 4096) { - found_4Kerase_type = true; - if (erase4k_inst != erase_type_inst_arr[i_ind]) { - //Verify 4KErase Type is identical to Legacy 4K erase type specified in Byte 1 of Param Table - erase4k_inst = erase_type_inst_arr[i_ind]; - tr_warning("_detectEraseTypesInstAndSize - Default 4K erase Inst is different than erase type Inst for 4K"); - - } - } - _region_erase_types_bitfield[0] |= bitfield; // If there's no region map, set region "0" types bitfield as defualt; + _region_erase_types_bitfield[0] |= bitfield; // If there's no region map, set region "0" types bitfield as default } - tr_debug("Erase Type %d - Inst: 0x%xh, Size: %d", (i_ind + 1), erase_type_inst_arr[i_ind], - erase_type_size_arr[i_ind]); + tr_debug("Erase Type %d - Inst: 0x%xh, Size: %d", (i_ind + 1), _erase_type_inst_arr[i_ind], + _erase_type_size_arr[i_ind]); bitfield = bitfield << 1; } + } else { + tr_debug("SFDP erase types are not available - falling back to legacy 4k erase instruction"); + + // 0xFF indicates that the legacy 4k erase instruction is not supported + _legacy_erase_instruction = basic_param_table_ptr[QSPIF_BASIC_PARAM_4K_ERASE_TYPE_BYTE]; + if (_legacy_erase_instruction == 0xFF) { + tr_error("_detectEraseTypesInstAndSize - Legacy 4k erase instruction not supported"); + return -1; + } } - if (false == found_4Kerase_type) { - tr_warning("Couldn't find Erase Type for 4KB size"); - } return 0; } int QSPIFBlockDevice::_sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table_ptr, int basic_param_table_size, - bool &set_quad_enable, - bool &is_qpi_mode, qspi_inst_t &read_inst) + bool &set_quad_enable, bool &is_qpi_mode) { set_quad_enable = false; is_qpi_mode = false; @@ -1042,14 +967,13 @@ int QSPIFBlockDevice::_sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table if (examined_byte & 0x10) { // QPI 4-4-4 Supported - read_inst = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_444_READ_INST_BYTE]; + _read_instruction = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_444_READ_INST_BYTE]; set_quad_enable = true; is_qpi_mode = true; _dummy_cycles = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_444_READ_INST_BYTE - 1] & 0x1F; uint8_t mode_cycles = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_444_READ_INST_BYTE - 1] >> 5; _alt_size = mode_cycles * 4; tr_debug("Read Bus Mode set to 4-4-4, Instruction: 0x%xh", _read_instruction); - //_inst_width = QSPI_CFG_BUS_QUAD; _address_width = QSPI_CFG_BUS_QUAD; _data_width = QSPI_CFG_BUS_QUAD; } @@ -1058,7 +982,7 @@ int QSPIFBlockDevice::_sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table examined_byte = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_FAST_READ_SUPPORT_BYTE]; if (examined_byte & 0x20) { // Fast Read 1-4-4 Supported - read_inst = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_144_READ_INST_BYTE]; + _read_instruction = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_144_READ_INST_BYTE]; set_quad_enable = true; _dummy_cycles = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_144_READ_INST_BYTE - 1] & 0x1F; uint8_t mode_cycles = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_144_READ_INST_BYTE - 1] >> 5; @@ -1071,7 +995,7 @@ int QSPIFBlockDevice::_sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table if (examined_byte & 0x40) { // Fast Read 1-1-4 Supported - read_inst = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_114_READ_INST_BYTE]; + _read_instruction = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_114_READ_INST_BYTE]; set_quad_enable = true; _dummy_cycles = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_114_READ_INST_BYTE - 1] & 0x1F; uint8_t mode_cycles = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_114_READ_INST_BYTE - 1] >> 5; @@ -1083,7 +1007,7 @@ int QSPIFBlockDevice::_sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table examined_byte = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_QPI_READ_SUPPORT_BYTE]; if (examined_byte & 0x01) { // Fast Read 2-2-2 Supported - read_inst = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE]; + _read_instruction = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE]; _dummy_cycles = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE - 1] & 0x1F; uint8_t mode_cycles = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE - 1] >> 5; _alt_size = mode_cycles * 2; @@ -1096,7 +1020,7 @@ int QSPIFBlockDevice::_sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table examined_byte = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_FAST_READ_SUPPORT_BYTE]; if (examined_byte & 0x10) { // Fast Read 1-2-2 Supported - read_inst = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE]; + _read_instruction = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE]; _dummy_cycles = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE - 1] & 0x1F; uint8_t mode_cycles = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE - 1] >> 5; _alt_size = mode_cycles * 2; @@ -1107,7 +1031,7 @@ int QSPIFBlockDevice::_sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table } if (examined_byte & 0x01) { // Fast Read 1-1-2 Supported - read_inst = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE]; + _read_instruction = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE]; _dummy_cycles = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE - 1] & 0x1F; uint8_t mode_cycles = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE - 1] >> 5; _alt_size = mode_cycles; @@ -1115,88 +1039,292 @@ int QSPIFBlockDevice::_sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table tr_debug("Read Bus Mode set to 1-1-2, Instruction: 0x%xh", _read_instruction); break; } + _read_instruction = QSPIF_INST_READ_DEFAULT; tr_debug("Read Bus Mode set to 1-1-1, Instruction: 0x%xh", _read_instruction); } while (false); return 0; } -int QSPIFBlockDevice::_reset_flash_mem() +int QSPIFBlockDevice::_sfdp_detect_and_enable_4byte_addressing(uint8_t *basic_param_table_ptr, int basic_param_table_size) { - // Perform Soft Reset of the Device prior to initialization - int status = 0; - char status_value[QSPI_MAX_STATUS_REGISTER_SIZE] = {0}; - tr_debug("_reset_flash_mem:"); - //Read the Status Register from device - if (QSPI_STATUS_OK == _qspi_send_general_command(QSPIF_RDSR, QSPI_NO_ADDRESS_COMMAND, NULL, 0, status_value, - QSPI_MAX_STATUS_REGISTER_SIZE)) { // store received values in status_value - tr_debug("Reading Status Register Success: value = 0x%x", (int)status_value[0]); - } else { - tr_error("Reading Status Register failed: value = 0x%x", (int)status_value[0]); - status = -1; - } + int status = QSPIF_BD_ERROR_OK; + qspi_status_t qspi_status = QSPI_STATUS_OK; - if (0 == status) { - //Send Reset Enable - if (QSPI_STATUS_OK == _qspi_send_general_command(QSPIF_RSTEN, QSPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, - 0)) { // store received values in status_value - tr_debug("Sending RSTEN Success"); + // Always enable 4-byte addressing if possible + if (basic_param_table_size > QSPIF_BASIC_PARAM_TABLE_4BYTE_ADDR_BYTE) { + uint8_t examined_byte = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_4BYTE_ADDR_BYTE]; + + if (examined_byte & FOURBYTE_ADDR_ALWAYS_BITMASK) { + // No need to do anything if 4-byte addressing is always enabled + _address_size = QSPI_CFG_ADDR_SIZE_32; + } else if (examined_byte & FOURBYTE_ADDR_B7_BITMASK) { + // Issue instruction B7h to enable 4-byte addressing + qspi_status = _qspi_send_general_command(0xB7, QSPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0); + status = (qspi_status == QSPI_STATUS_OK) ? QSPIF_BD_ERROR_OK : QSPIF_BD_ERROR_PARSING_FAILED; + if (status == QSPIF_BD_ERROR_OK) { + _address_size = QSPI_CFG_ADDR_SIZE_32; + } + } else if (examined_byte & FOURBYTE_ADDR_B7_WREN_BITMASK) { + // Issue WREN and then instruction B7h to enable 4-byte addressing + if (_set_write_enable() == 0) { + qspi_status = _qspi_send_general_command(0xB7, QSPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0); + status = (qspi_status == QSPI_STATUS_OK) ? QSPIF_BD_ERROR_OK : QSPIF_BD_ERROR_PARSING_FAILED; + + if (status == QSPIF_BD_ERROR_OK) { + _address_size = QSPI_CFG_ADDR_SIZE_32; + } + } else { + tr_error("Write enable failed"); + status = QSPIF_BD_ERROR_WREN_FAILED; + } + } else if (examined_byte & FOURBYTE_ADDR_CONF_REG_BITMASK) { + // Write 1 to bit 0 of a configuration register to enable 4-byte addressing + // Write to register with instruction B1h, read from register with instruction B5h + uint8_t conf_register = 0; + qspi_status = _qspi_send_general_command(0xB5, QSPI_NO_ADDRESS_COMMAND, NULL, 0, (char *) &conf_register, 1); + status = (qspi_status == QSPI_STATUS_OK) ? QSPIF_BD_ERROR_OK : QSPIF_BD_ERROR_PARSING_FAILED; + + if (status == QSPIF_BD_ERROR_OK) { + conf_register |= 0b00000001; + if (_set_write_enable() == 0) { + qspi_status_t qspi_status = _qspi_send_general_command(0xB1, QSPI_NO_ADDRESS_COMMAND, (char *) &conf_register, 1, NULL, 0); + status = (qspi_status == QSPI_STATUS_OK) ? QSPIF_BD_ERROR_OK : QSPIF_BD_ERROR_PARSING_FAILED; + + if (status == QSPIF_BD_ERROR_OK) { + _address_size = QSPI_CFG_ADDR_SIZE_32; + } + } else { + tr_error("Write enable failed"); + status = QSPIF_BD_ERROR_WREN_FAILED; + } + } + } else if (examined_byte & FOURBYTE_ADDR_BANK_REG_BITMASK) { + // Write 1 to bit 7 of a bank register to enable 4-byte addressing + // Write to register with instruction 17h, read from register with instruction 16h + uint8_t to_write = 0b10000000; + qspi_status = _qspi_send_general_command(0x17, QSPI_NO_ADDRESS_COMMAND, (char *) &to_write, 1, NULL, 0); + status = (qspi_status == QSPI_STATUS_OK) ? QSPIF_BD_ERROR_OK : QSPIF_BD_ERROR_PARSING_FAILED; + if (status == QSPIF_BD_ERROR_OK) { + _address_size = QSPI_CFG_ADDR_SIZE_32; + } + } else if (examined_byte & FOURBYTE_ADDR_EXT_ADDR_REG_BITMASK) { + // Extended address register stores most significant byte of a 4-byte address + // Instructions are sent with the lower 3 bytes of the address + // Write to register with instruction C5h, read from register with instruction C8h + _4byte_msb_reg_write_inst = 0xC5; + _address_size = QSPI_CFG_ADDR_SIZE_24; } else { - tr_error("Sending RSTEN failed"); - status = -1; + // Either part specific instructions are required to use 4-byte addressing or it isn't supported, so use 3-byte addressing instead + tr_debug("_sfdp_detect_and_enable_4byte_addressing - 4-byte addressing not supported, falling back to 3-byte addressing"); + _address_size = QSPI_CFG_ADDR_SIZE_24; } - - if (0 == status) { - //Send Reset - if (QSPI_STATUS_OK == _qspi_send_general_command(QSPIF_RST, QSPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, - 0)) { // store received values in status_value - tr_debug("Sending RST Success"); - } else { - tr_error("Sending RST failed"); - status = -1; + if (_address_size == QSPI_CFG_ADDR_SIZE_32) { + // Update 1-1-1 format to match new address size + if (QSPI_STATUS_OK != _qspi.configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, _address_size, QSPI_CFG_BUS_SINGLE, + 0, QSPI_CFG_BUS_SINGLE, 0)) { + tr_error("_qspi_configure_format failed"); + status = QSPIF_BD_ERROR_DEVICE_ERROR; } - - _is_mem_ready(); } } return status; } -bool QSPIFBlockDevice::_is_mem_ready() +int QSPIFBlockDevice::_sfdp_detect_reset_protocol_and_reset(uint8_t *basic_param_table_ptr) { - // Check Status Register Busy Bit to Verify the Device isn't Busy - char status_value[QSPI_MAX_STATUS_REGISTER_SIZE]; - int retries = 0; - bool mem_ready = true; + int status = QSPIF_BD_ERROR_OK; + uint8_t examined_byte = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_SOFT_RESET_BYTE]; - do { - rtos::ThisThread::sleep_for(1); - retries++; - //Read the Status Register from device - memset(status_value, 0xFF, QSPI_MAX_STATUS_REGISTER_SIZE); - if (QSPI_STATUS_OK != _qspi_send_general_command(QSPIF_RDSR, QSPI_NO_ADDRESS_COMMAND, NULL, 0, status_value, - QSPI_MAX_STATUS_REGISTER_SIZE)) { // store received values in status_value - tr_error("Reading Status Register failed"); + // Ignore bit indicating need to exit 0-4-4 mode - should not enter 0-4-4 mode from QSPIFBlockDevice + if (examined_byte & SOFT_RESET_RESET_INST_BITMASK) { + // Issue instruction 0xF0 to reset the device + qspi_status_t qspi_status = _qspi_send_general_command(0xF0, QSPI_NO_ADDRESS_COMMAND, // Send reset instruction + NULL, 0, NULL, 0); + status = (qspi_status == QSPI_STATUS_OK) ? QSPIF_BD_ERROR_OK : QSPIF_BD_ERROR_PARSING_FAILED; + } else if (examined_byte & SOFT_RESET_ENABLE_AND_RESET_INST_BITMASK) { + // Issue instruction 66h to enable resets on the device + // Then issue instruction 99h to reset the device + qspi_status_t qspi_status = _qspi_send_general_command(0x66, QSPI_NO_ADDRESS_COMMAND, // Send reset enable instruction + NULL, 0, NULL, 0); + if (qspi_status == QSPI_STATUS_OK) { + qspi_status = _qspi_send_general_command(0x99, QSPI_NO_ADDRESS_COMMAND, // Send reset instruction + NULL, 0, NULL, 0); } - } while ((status_value[0] & QSPIF_STATUS_BIT_WIP) != 0 && retries < IS_MEM_READY_MAX_RETRIES); - - if ((status_value[0] & QSPIF_STATUS_BIT_WIP) != 0) { - tr_error("_is_mem_ready FALSE: status value = 0x%x ", (int)status_value[0]); - mem_ready = false; + status = (qspi_status == QSPI_STATUS_OK) ? QSPIF_BD_ERROR_OK : QSPIF_BD_ERROR_PARSING_FAILED; + } else { + // Soft reset either is not supported or requires direct control over data lines + status = QSPIF_BD_ERROR_PARSING_FAILED; } - return mem_ready; + + if (status == QSPIF_BD_ERROR_OK) { + if (false == _is_mem_ready()) { + tr_error("Device not ready, reset failed"); + status = QSPIF_BD_ERROR_READY_FAILED; + } + } + + return status; +} + +int QSPIFBlockDevice::_sfdp_parse_sector_map_table(uint32_t sector_map_table_addr, size_t sector_map_table_size) +{ + uint8_t sector_map_table[SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES]; /* Up To 16 DWORDS = 64 Bytes */ + uint32_t tmp_region_size = 0; + int i_ind = 0; + int prev_boundary = 0; + // Default set to all type bits 1-4 are common + int min_common_erase_type_bits = ERASE_BITMASK_ALL; + + qspi_status_t status = _qspi_send_read_sfdp_command(sector_map_table_addr, (char *) sector_map_table, sector_map_table_size); + if (status != QSPI_STATUS_OK) { + tr_error("Init - Read SFDP First Table Failed"); + return -1; + } + + // Currently we support only Single Map Descriptor + if (!((sector_map_table[0] & 0x3) == 0x03) && (sector_map_table[1] == 0x0)) { + tr_error("Sector Map - Supporting Only Single! Map Descriptor (not map commands)"); + return -1; + } + + _regions_count = sector_map_table[2] + 1; + if (_regions_count > QSPIF_MAX_REGIONS) { + tr_error("Supporting up to %d regions, current setup to %d regions - fail", + QSPIF_MAX_REGIONS, _regions_count); + return -1; + } + + // Loop through Regions and set for each one: size, supported erase types, high boundary offset + // Calculate minimum Common Erase Type for all Regions + for (i_ind = 0; i_ind < _regions_count; i_ind++) { + tmp_region_size = ((*((uint32_t *)§or_map_table[(i_ind + 1) * 4])) >> 8) & 0x00FFFFFF; // bits 9-32 + _region_size_bytes[i_ind] = (tmp_region_size + 1) * 256; // Region size is 0 based multiple of 256 bytes; + _region_erase_types_bitfield[i_ind] = sector_map_table[(i_ind + 1) * 4] & 0x0F; // bits 1-4 + min_common_erase_type_bits &= _region_erase_types_bitfield[i_ind]; + _region_high_boundary[i_ind] = (_region_size_bytes[i_ind] - 1) + prev_boundary; + prev_boundary = _region_high_boundary[i_ind] + 1; + } + + // Calc minimum Common Erase Size from min_common_erase_type_bits + uint8_t type_mask = ERASE_BITMASK_TYPE1; + for (i_ind = 0; i_ind < 4; i_ind++) { + if (min_common_erase_type_bits & type_mask) { + _min_common_erase_size = _erase_type_size_arr[i_ind]; + break; + } + type_mask = type_mask << 1; + } + + if (i_ind == 4) { + // No common erase type was found between regions + _min_common_erase_size = 0; + } + + return 0; +} + +int QSPIFBlockDevice::_handle_vendor_quirks() +{ + uint8_t vendor_device_ids[QSPI_RDID_DATA_LENGTH] = {0}; + /* Read Manufacturer ID (1byte), and Device ID (2bytes) */ + qspi_status_t status = _qspi_send_general_command(QSPIF_INST_RDID, QSPI_NO_ADDRESS_COMMAND, + NULL, 0, + (char *) vendor_device_ids, QSPI_RDID_DATA_LENGTH); + if (QSPI_STATUS_OK != status) { + tr_error("Read Vendor ID Failed"); + return -1; + } + + tr_debug("Vendor device ID = 0x%x 0x%x 0x%x", vendor_device_ids[0], vendor_device_ids[1], vendor_device_ids[2]); + + switch (vendor_device_ids[0]) { + case 0xbf: + // SST devices come preset with block protection + // enabled for some regions, issue global protection unlock to clear + tr_debug("Applying quirks for SST"); + _clear_protection_method = QSPIF_BP_ULBPR; + break; + case 0xc2: + // Macronix devices have several quirks: + // 1. Have one status register and 2 config registers, with a nonstandard instruction for reading the config registers + // 2. Require setting a "fast mode" bit in config register 2 to operate at higher clock rates + // 3. Should never attempt to enable 4-byte addressing (it causes reads and writes to fail) + tr_debug("Applying quirks for macronix"); + _needs_fast_mode = true; + _num_status_registers = 3; + _read_status_reg_2_inst = QSPIF_INST_RDCR; + _attempt_4_byte_addressing = false; + break; + } + + return 0; +} + +int QSPIFBlockDevice::_clear_block_protection() +{ + uint8_t status_regs[QSPI_MAX_STATUS_REGISTERS] = {0}; + + if (false == _is_mem_ready()) { + tr_error("Device not ready, clearing block protection failed"); + return -1; + } + qspi_status_t status; + switch (_clear_protection_method) { + case QSPIF_BP_ULBPR: + tr_debug("Clearing block protection via ULBPR"); + // SST devices come preset with block protection + // enabled for some regions, issue global protection unlock to clear + if (0 != _set_write_enable()) { + tr_error("Write enable failed"); + return -1; + } + status = _qspi_send_general_command(QSPIF_INST_ULBPR, QSPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0); + if (QSPI_STATUS_OK != status) { + tr_error("Global block protection unlock failed"); + return -1; + } + break; + case QSPIF_BP_CLEAR_SR: + // For all other devices, to clear the block protection bits clear all bits + // in status register 1 that aren't the WIP or WEL bits, or the QE bit (if it is in SR 1) + tr_debug("Clearing block protection via status register protection bits"); + status = _qspi_read_status_registers(status_regs); + if (QSPI_STATUS_OK != status) { + tr_error("_clear_block_protection - Status register read failed"); + return -1; + } + uint8_t status_mask = (QSPIF_STATUS_BIT_WIP | QSPIF_STATUS_BIT_WEL); + if (_quad_enable_register_idx == 0) { + status_mask |= 1 << _quad_enable_bit; + } + status_regs[0] &= status_mask; + status = _qspi_write_status_registers(status_regs); + if (QSPI_STATUS_OK != status) { + tr_error("__clear_block_protection - Status register write failed"); + return -1; + } + break; + } + + if (false == _is_mem_ready()) { + tr_error("Device not ready, clearing block protection failed"); + return -1; + } + + return 0; } int QSPIFBlockDevice::_set_write_enable() { // Check Status Register Busy Bit to Verify the Device isn't Busy - char status_value[QSPI_MAX_STATUS_REGISTER_SIZE]; + uint8_t status_value = 0; int status = -1; do { - if (QSPI_STATUS_OK != _qspi_send_general_command(QSPIF_WREN, QSPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0)) { + if (QSPI_STATUS_OK != _qspi_send_general_command(QSPIF_INST_WREN, QSPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0)) { tr_error("Sending WREN command FAILED"); break; } @@ -1206,61 +1334,59 @@ int QSPIFBlockDevice::_set_write_enable() break; } - memset(status_value, 0, QSPI_MAX_STATUS_REGISTER_SIZE); - if (QSPI_STATUS_OK != _qspi_send_general_command(QSPIF_RDSR, QSPI_NO_ADDRESS_COMMAND, NULL, 0, status_value, - QSPI_MAX_STATUS_REGISTER_SIZE)) { // store received values in status_value - tr_error("Reading Status Register failed"); + if (QSPI_STATUS_OK != _qspi_send_general_command(QSPIF_INST_RSR1, QSPI_NO_ADDRESS_COMMAND, + NULL, 0, + (char *) &status_value, 1)) { + tr_error("Reading Status Register 1 failed"); break; } - if ((status_value[0] & QSPIF_STATUS_BIT_WEL) == 0) { - tr_error("_set_write_enable failed"); + if ((status_value & QSPIF_STATUS_BIT_WEL) == 0) { + tr_error("_set_write_enable failed - status register 1 value: %u", status_value); break; } + status = 0; } while (false); + return status; } -int QSPIFBlockDevice::_enable_fast_mdoe() +int QSPIFBlockDevice::_enable_fast_mode() { - char status_reg[QSPI_MAX_STATUS_REGISTER_SIZE] = {0}; - qspi_inst_t read_conf_register_inst = 0x15; - char status_reg_qer_setup[QSPI_MAX_STATUS_REGISTER_SIZE] = {0}; + tr_debug("enabling fast mode"); + MBED_ASSERT(_num_status_registers == 3); // Make sure the register for fast mode enable exists + uint8_t status_reg[QSPI_MAX_STATUS_REGISTERS] = {0}; - status_reg_qer_setup[2] = 0x2; // Bit 1 of config Reg 2 + // Bit 1 of config reg 2 (aka "status register 3" in our generic register representation) + const int QER_REG_IDX = 2; + const int QER_REG_VALUE = 0x2; // Configure BUS Mode to 1_1_1 for all commands other than Read - if (QSPI_STATUS_OK != _qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE, + if (QSPI_STATUS_OK != _qspi.configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE, 0, QSPI_CFG_BUS_SINGLE, 0)) { tr_error("_qspi_configure_format failed"); - return QSPIF_BD_ERROR_DEVICE_ERROR; + return -1; + } - // Read Status Register - if (QSPI_STATUS_OK == _qspi_send_general_command(read_conf_register_inst, QSPI_NO_ADDRESS_COMMAND, NULL, 0, - &status_reg[1], - QSPI_MAX_STATUS_REGISTER_SIZE - 1)) { // store received values in status_value - tr_debug("Reading Config Register Success: value = 0x%x", (int)status_reg[2]); + if (QSPI_STATUS_OK == _qspi_read_status_registers(status_reg)) { + tr_debug("Reading Config Register Success: value = 0x%x", status_reg[2]); } else { tr_error("Reading Config Register failed"); return -1; } // Set Bits for Quad Enable - for (int i = 0; i < QSPI_MAX_STATUS_REGISTER_SIZE; i++) { - status_reg[i] |= status_reg_qer_setup[i]; - } + status_reg[QER_REG_IDX] |= QER_REG_VALUE; // Write new Status Register Setup if (_set_write_enable() != 0) { - tr_error("Write Enabe failed"); + tr_error("Write Enable failed"); return -1; } - if (QSPI_STATUS_OK == _qspi_send_general_command(_write_register_inst, QSPI_NO_ADDRESS_COMMAND, status_reg, - QSPI_MAX_STATUS_REGISTER_SIZE, NULL, - 0)) { // Write Fast mode bit to status_register + if (QSPI_STATUS_OK == _qspi_write_status_registers(status_reg)) { tr_debug("fast mode enable - Writing Config Register Success: value = 0x%x", (int)status_reg[2]); } else { @@ -1274,11 +1400,9 @@ int QSPIFBlockDevice::_enable_fast_mdoe() } // For Debug - memset(status_reg, 0, QSPI_MAX_STATUS_REGISTER_SIZE); - if (QSPI_STATUS_OK == _qspi_send_general_command(read_conf_register_inst, QSPI_NO_ADDRESS_COMMAND, NULL, 0, - &status_reg[1], - QSPI_MAX_STATUS_REGISTER_SIZE - 1)) { // store received values in status_value - tr_debug("Verifying Config Register Success: value = 0x%x", (int)status_reg[2]); + memset(status_reg, 0, QSPI_MAX_STATUS_REGISTERS); + if (QSPI_STATUS_OK == _qspi_read_status_registers(status_reg)) { + tr_debug("Verifying Register Success: status = 0x%x config 1 = 0x%x config 2 = 0x%x", (int)status_reg[0], (int)status_reg[1], (int)status_reg[2]); } else { tr_error("Verifying Config Register failed"); return -1; @@ -1287,6 +1411,31 @@ int QSPIFBlockDevice::_enable_fast_mdoe() return 0; } +bool QSPIFBlockDevice::_is_mem_ready() +{ + // Check Status Register Busy Bit to Verify the Device isn't Busy + uint8_t status_value = 0; + int retries = 0; + bool mem_ready = true; + + do { + rtos::ThisThread::sleep_for(1); + retries++; + //Read Status Register 1 from device + if (QSPI_STATUS_OK != _qspi_send_general_command(QSPIF_INST_RSR1, QSPI_NO_ADDRESS_COMMAND, + NULL, 0, + (char *) &status_value, 1)) { // store received value in status_value + tr_error("Reading Status Register failed"); + } + } while ((status_value & QSPIF_STATUS_BIT_WIP) != 0 && retries < IS_MEM_READY_MAX_RETRIES); + + if ((status_value & QSPIF_STATUS_BIT_WIP) != 0) { + tr_error("_is_mem_ready FALSE: status value = 0x%x ", status_value); + mem_ready = false; + } + return mem_ready; +} + /*********************************************/ /************* Utility Functions *************/ /*********************************************/ @@ -1345,92 +1494,253 @@ qspi_status_t QSPIFBlockDevice::_qspi_set_frequency(int freq) return _qspi.set_frequency(freq); } -qspi_status_t QSPIFBlockDevice::_qspi_send_read_command(qspi_inst_t read_inst, void *buffer, bd_addr_t addr, - bd_size_t size) +qspi_status_t QSPIFBlockDevice::_qspi_update_4byte_ext_addr_reg(bd_addr_t addr) { - // Send Read command to device driver + qspi_status_t status = QSPI_STATUS_OK; + // Only update register if in the extended address register mode + if (_4byte_msb_reg_write_inst != QSPI_NO_INST) { + // Set register to the most significant byte of the address + uint8_t most_significant_byte = addr >> 24; + if (_set_write_enable() == 0) { + status = _qspi.command_transfer(_4byte_msb_reg_write_inst, (int) QSPI_NO_ADDRESS_COMMAND, + (char *) &most_significant_byte, 1, + NULL, 0); + } else { + tr_error("Write enable failed"); + status = QSPI_STATUS_ERROR; + } + } else if ((_address_size != QSPI_CFG_ADDR_SIZE_32) && (addr != QSPI_NO_ADDRESS_COMMAND) && (addr >= (1 << 24))) { + tr_error("Attempted to use 4-byte address but 4-byte addressing is not supported"); + status = QSPI_STATUS_ERROR; + } + return status; +} + +qspi_status_t QSPIFBlockDevice::_qspi_send_read_command(qspi_inst_t read_inst, void *buffer, + bd_addr_t addr, bd_size_t size) +{ + tr_debug("Inst: 0x%xh, addr: %llu, size: %llu", read_inst, addr, size); + size_t buf_len = size; - if (_qspi.read(read_inst, (_alt_size == 0) ? -1 : QSPI_ALT_DEFAULT_VALUE, (unsigned int)addr, (char *)buffer, &buf_len) != QSPI_STATUS_OK) { - tr_error("Read failed"); - return QSPI_STATUS_ERROR; + qspi_status_t status = _qspi_update_4byte_ext_addr_reg(addr); + if (QSPI_STATUS_OK != status) { + tr_error("QSPI Read - Updating 4-byte addressing extended address register failed"); + return status; + } + + // Send read command to device driver + // Read commands use the best bus mode supported by the part + status = _qspi.configure_format(_inst_width, _address_width, _address_size, _address_width, // Alt width should be the same as address width + _alt_size, _data_width, _dummy_cycles); + if (QSPI_STATUS_OK != status) { + tr_error("_qspi_configure_format failed"); + return status; + } + + // Don't check the read status until after we've configured the format back to 1-1-1, to avoid leaving the interface in an + // incorrect state if the read fails. + status = _qspi.read(read_inst, (_alt_size == 0) ? -1 : QSPI_ALT_DEFAULT_VALUE, (unsigned int)addr, (char *)buffer, &buf_len); + + // All commands other than Read and RSFDP use default 1-1-1 bus mode (Program/Erase are constrained by flash memory performance more than bus performance) + qspi_status_t format_status = _qspi.configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, _address_size, QSPI_CFG_BUS_SINGLE, 0, QSPI_CFG_BUS_SINGLE, 0); + if (QSPI_STATUS_OK != format_status) { + tr_error("_qspi_configure_format failed"); + return format_status; + } + + if (QSPI_STATUS_OK != status) { + tr_error("QSPI Read failed"); + return status; } return QSPI_STATUS_OK; - } -qspi_status_t QSPIFBlockDevice::_qspi_send_program_command(qspi_inst_t progInst, const void *buffer, bd_addr_t addr, - bd_size_t *size) +qspi_status_t QSPIFBlockDevice::_qspi_send_program_command(qspi_inst_t prog_inst, const void *buffer, + bd_addr_t addr, bd_size_t *size) { - // Send Program (write) command to device driver - qspi_status_t result = QSPI_STATUS_OK; + tr_debug("Inst: 0x%xh, addr: %llu, size: %llu", prog_inst, addr, *size); - result = _qspi.write(progInst, -1, addr, (char *)buffer, (size_t *)size); - if (result != QSPI_STATUS_OK) { - tr_error("QSPI Write failed"); + qspi_status_t status = _qspi_update_4byte_ext_addr_reg(addr); + if (QSPI_STATUS_OK != status) { + tr_error("QSPI Write - Updating 4-byte addressing extended address register failed"); + return status; } - return result; + // Send program (write) command to device driver + status = _qspi.write(prog_inst, -1, addr, (char *)buffer, (size_t *)size); + if (QSPI_STATUS_OK != status) { + tr_error("QSPI Write failed"); + return status; + } + + return QSPI_STATUS_OK; } qspi_status_t QSPIFBlockDevice::_qspi_send_erase_command(qspi_inst_t erase_inst, bd_addr_t addr, bd_size_t size) { - // Send Erase Instruction command to driver - qspi_status_t result = QSPI_STATUS_OK; - tr_debug("Inst: 0x%xh, addr: %llu, size: %llu", erase_inst, addr, size); - result = _qspi.command_transfer(erase_inst, // command to send - (((int)addr) & 0x00FFF000), // Align addr to 4096 - NULL, // do not transmit - 0, // do not transmit - NULL, // just receive two bytes of data - 0); // store received values in status_value - - if (QSPI_STATUS_OK != result) { - tr_error("QSPI Erase failed"); + qspi_status_t status = _qspi_update_4byte_ext_addr_reg(addr); + if (QSPI_STATUS_OK != status) { + tr_error("QSPI Erase - Updating 4-byte addressing extended address register failed"); + return status; } - return result; + // Send erase command to driver + status = _qspi.command_transfer(erase_inst, (int) addr, NULL, 0, NULL, 0); + if (QSPI_STATUS_OK != status) { + tr_error("QSPI Erase failed"); + return status; + } + + return QSPI_STATUS_OK; } qspi_status_t QSPIFBlockDevice::_qspi_send_general_command(qspi_inst_t instruction, bd_addr_t addr, - const char *tx_buffer, - mbed::bd_size_t tx_length, const char *rx_buffer, mbed::bd_size_t rx_length) + const char *tx_buffer, bd_size_t tx_length, + const char *rx_buffer, bd_size_t rx_length) { - // Send a general command Instruction to driver - qspi_status_t status = _qspi.command_transfer(instruction, (int)addr, tx_buffer, tx_length, rx_buffer, rx_length); + tr_debug("Inst: 0x%xh, addr: %llu, tx length: %llu, rx length: %llu", instruction, addr, tx_length, rx_length); + qspi_status_t status = _qspi_update_4byte_ext_addr_reg(addr); + if (QSPI_STATUS_OK != status) { + tr_error("QSPI Generic command - Updating 4-byte addressing extended address register failed"); + return status; + } + + // Send a general command instruction to driver + status = _qspi.command_transfer(instruction, (int)addr, tx_buffer, tx_length, rx_buffer, rx_length); if (QSPI_STATUS_OK != status) { tr_error("Sending Generic command: %x", instruction); + return status; } - return status; + return QSPI_STATUS_OK; } -qspi_status_t QSPIFBlockDevice::_qspi_configure_format(qspi_bus_width_t inst_width, qspi_bus_width_t address_width, - qspi_address_size_t address_size, qspi_bus_width_t alt_width, qspi_alt_size_t alt_size, qspi_bus_width_t data_width, - int dummy_cycles) +qspi_status_t QSPIFBlockDevice::_qspi_send_read_sfdp_command(bd_addr_t addr, void *rx_buffer, bd_size_t rx_length) { - // Configure QSPI driver Bus format - qspi_status_t status = _qspi.configure_format(inst_width, address_width, address_size, alt_width, alt_size, data_width, - dummy_cycles); + size_t rx_len = rx_length; - return status; -} - -/*********************************************/ -/************** Local Functions **************/ -/*********************************************/ -static int local_math_power(int base, int exp) -{ - // Integer X^Y function, used to calculate size fields given in 2^N format - int result = 1; - while (exp) { - result *= base; - exp--; + // SFDP read instruction requires 1-1-1 bus mode with 8 dummy cycles and a 3-byte address + qspi_status_t status = _qspi.configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE, 0, QSPI_CFG_BUS_SINGLE, QSPIF_RSFDP_DUMMY_CYCLES); + if (QSPI_STATUS_OK != status) { + tr_error("_qspi_configure_format failed"); + return status; } - return result; + + // Don't check the read status until after we've configured the format back to 1-1-1, to avoid leaving the interface in an + // incorrect state if the read fails. + status = _qspi.read(QSPIF_INST_RSFDP, -1, (unsigned int) addr, (char *) rx_buffer, &rx_len); + + qspi_status_t format_status = _qspi.configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, _address_size, QSPI_CFG_BUS_SINGLE, 0, QSPI_CFG_BUS_SINGLE, 0); + // All commands other than Read and RSFDP use default 1-1-1 bus mode (Program/Erase are constrained by flash memory performance more than bus performance) + if (QSPI_STATUS_OK != format_status) { + tr_error("_qspi_configure_format failed"); + return format_status; + } + + if (QSPI_STATUS_OK != status) { + tr_error("Sending SFDP read instruction"); + return status; + } + + return QSPI_STATUS_OK; +} + +qspi_status_t QSPIFBlockDevice::_qspi_read_status_registers(uint8_t *reg_buffer) +{ + // Read Status Register 1 + qspi_status_t status = _qspi_send_general_command(QSPIF_INST_RSR1, QSPI_NO_ADDRESS_COMMAND, + NULL, 0, + (char *) ®_buffer[0], 1); + if (QSPI_STATUS_OK == status) { + tr_debug("Reading Status Register 1 Success: value = 0x%x", (int) reg_buffer[0]); + } else { + tr_error("Reading Status Register 1 failed"); + return status; + } + + // Read Status Register 2 (and beyond, if applicable) + unsigned int read_length = _num_status_registers - 1; // We already read status reg 1 above + status = _qspi_send_general_command(_read_status_reg_2_inst, QSPI_NO_ADDRESS_COMMAND, + NULL, 0, + (char *) ®_buffer[1], read_length); + if (QSPI_STATUS_OK == status) { + tr_debug("Reading Status Register 2 Success: value = 0x%x", (int) reg_buffer[1]); + if (_num_status_registers > 2) { + tr_debug("Reading Register 3 Success: value = 0x%x", (int) reg_buffer[2]); + } + } else { + tr_error("Reading Status Register 2 failed"); + return status; + } + + return QSPI_STATUS_OK; +} + +qspi_status_t QSPIFBlockDevice::_qspi_write_status_registers(uint8_t *reg_buffer) +{ + qspi_status_t status; + + if (_write_status_reg_2_inst == QSPI_NO_INST) { + // Status registers are written on different data bytes of the same command + if (_set_write_enable() != 0) { + tr_error("Write Enable failed"); + return QSPI_STATUS_ERROR; + } + status = _qspi_send_general_command(QSPIF_INST_WSR1, QSPI_NO_ADDRESS_COMMAND, + (char *) reg_buffer, _num_status_registers, + NULL, 0); + if (QSPI_STATUS_OK == status) { + tr_debug("Writing Status Registers Success: reg 1 value = 0x%x, reg 2 value = 0x%x", + (int) reg_buffer[0], (int) reg_buffer[1]); + if (_num_status_registers > 2) { + tr_debug("Writing Register 3 Success: value = 0x%x", (int) reg_buffer[2]); + } + } else { + tr_error("Writing Status Registers failed"); + return status; + } + } else { + // Status registers are written using different commands + MBED_ASSERT(_num_status_registers == 2); // This flow doesn't support a nonstandard third status/config register + + // Write status register 1 + if (_set_write_enable() != 0) { + tr_error("Write Enable failed"); + return QSPI_STATUS_ERROR; + } + status = _qspi_send_general_command(QSPIF_INST_WSR1, QSPI_NO_ADDRESS_COMMAND, + (char *) ®_buffer[0], 1, + NULL, 0); + if (QSPI_STATUS_OK == status) { + tr_debug("Writing Status Register 1 Success: value = 0x%x", + (int) reg_buffer[0]); + } else { + tr_error("Writing Status Register 1 failed"); + return status; + } + + // Write status register 2 + if (_set_write_enable() != 0) { + tr_error("Write Enable failed"); + return QSPI_STATUS_ERROR; + } + status = _qspi_send_general_command(_write_status_reg_2_inst, QSPI_NO_ADDRESS_COMMAND, + (char *) ®_buffer[0], 1, + NULL, 0); + if (QSPI_STATUS_OK == status) { + tr_debug("Writing Status Register 2 Success: value = 0x%x", + (int) reg_buffer[1]); + } else { + tr_error("Writing Status Register 2 failed"); + return status; + } + } + + return QSPI_STATUS_OK; } diff --git a/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.h b/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.h index 907d13135f..3a3dc712b0 100644 --- a/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.h +++ b/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.h @@ -27,11 +27,11 @@ enum qspif_bd_error { QSPIF_BD_ERROR_OK = 0, /*!< no error */ QSPIF_BD_ERROR_DEVICE_ERROR = BD_ERROR_DEVICE_ERROR, /*!< device specific error -4001 */ QSPIF_BD_ERROR_PARSING_FAILED = -4002, /* SFDP Parsing failed */ - QSPIF_BD_ERROR_READY_FAILED = -4003, /* Wait for Mem Ready failed */ + QSPIF_BD_ERROR_READY_FAILED = -4003, /* Wait for Mem Ready failed */ QSPIF_BD_ERROR_WREN_FAILED = -4004, /* Write Enable Failed */ QSPIF_BD_ERROR_INVALID_ERASE_PARAMS = -4005, /* Erase command not on sector aligned addresses or exceeds device size */ - QSPIF_BD_ERROR_DEVICE_NOT_UNIQE = -4006, /* Only one instance per csel is allowed */ - QSPIF_BD_ERROR_DEVICE_MAX_EXCEED = -4007 /* Max active QSPIF devices exceeded */ + QSPIF_BD_ERROR_DEVICE_NOT_UNIQUE = -4006, /* Only one instance per csel is allowed */ + QSPIF_BD_ERROR_DEVICE_MAX_EXCEED = -4007 /* Max active QSPIF devices exceeded */ }; /** Enum qspif polarity mode @@ -248,19 +248,26 @@ private: qspi_status_t _qspi_send_general_command(mbed::qspi_inst_t instruction_int, mbed::bd_addr_t addr, const char *tx_buffer, mbed::bd_size_t tx_length, const char *rx_buffer, mbed::bd_size_t rx_length); - // Send Bus configure_format command to Driver - qspi_status_t _qspi_configure_format(qspi_bus_width_t inst_width, qspi_bus_width_t address_width, - qspi_address_size_t address_size, qspi_bus_width_t alt_width, qspi_alt_size_t alt_size, qspi_bus_width_t data_width, - int dummy_cycles); + // Send command to read from the SFDP table + qspi_status_t _qspi_send_read_sfdp_command(mbed::bd_addr_t addr, void *rx_buffer, mbed::bd_size_t rx_length); + + // Read the contents of status registers 1 and 2 into a buffer (buffer must have a length of 2) + qspi_status_t _qspi_read_status_registers(uint8_t *reg_buffer); + + // Set the contents of status registers 1 and 2 from a buffer (buffer must have a length of 2) + qspi_status_t _qspi_write_status_registers(uint8_t *reg_buffer); // Send set_frequency command to Driver qspi_status_t _qspi_set_frequency(int freq); + // Update the 4-byte addressing extension register with the MSB of the address if it is in use + qspi_status_t _qspi_update_4byte_ext_addr_reg(bd_addr_t addr); + /*********************************/ /* Flash Configuration Functions */ /*********************************/ - // Soft Reset Flash Memory - int _reset_flash_mem(); + // Clear the device's block protection + int _clear_block_protection(); // Configure Write Enable in Status Register int _set_write_enable(); @@ -269,7 +276,7 @@ private: bool _is_mem_ready(); // Enable Fast Mode - for flash chips with low power default - int _enable_fast_mdoe(); + int _enable_fast_mode(); /****************************************/ /* SFDP Detection and Parsing Functions */ @@ -281,26 +288,33 @@ private: // Parse and Detect required Basic Parameters from Table int _sfdp_parse_basic_param_table(uint32_t basic_table_addr, size_t basic_table_size); - // Parse and read information required by Regions Secotr Map + // Parse and read information required by Regions Sector Map int _sfdp_parse_sector_map_table(uint32_t sector_map_table_addr, size_t sector_map_table_size); + // Detect the soft reset protocol and reset - returns error if soft reset is not supported + int _sfdp_detect_reset_protocol_and_reset(uint8_t *basic_param_table_ptr); + // Detect fastest read Bus mode supported by device - int _sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table_ptr, int basic_param_table_size, bool &set_quad_enable, - bool &is_qpi_mode, mbed::qspi_inst_t &read_inst); + int _sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table_ptr, int basic_param_table_size, + bool &set_quad_enable, bool &is_qpi_mode); // Enable Quad mode if supported (1-1-4, 1-4-4, 4-4-4 bus modes) int _sfdp_set_quad_enabled(uint8_t *basic_param_table_ptr); - // Enable QPI mode (4-4-4) is supported + // Enable QPI mode (4-4-4) int _sfdp_set_qpi_enabled(uint8_t *basic_param_table_ptr); // Set Page size for program int _sfdp_detect_page_size(uint8_t *basic_param_table_ptr, int basic_param_table_size); // Detect all supported erase types - int _sfdp_detect_erase_types_inst_and_size(uint8_t *basic_param_table_ptr, int basic_param_table_size, - mbed::qspi_inst_t &erase4k_inst, - mbed::qspi_inst_t *erase_type_inst_arr, unsigned int *erase_type_size_arr); + int _sfdp_detect_erase_types_inst_and_size(uint8_t *basic_param_table_ptr, int basic_param_table_size); + + // Detect 4-byte addressing mode and enable it if supported + int _sfdp_detect_and_enable_4byte_addressing(uint8_t *basic_param_table_ptr, int basic_param_table_size); + + // Query vendor ID and handle special behavior that isn't covered by SFDP data + int _handle_vendor_quirks(); /***********************/ /* Utilities Functions */ @@ -313,6 +327,11 @@ private: int _utils_iterate_next_largest_erase_type(uint8_t &bitfield, int size, int offset, int boundry); private: + enum qspif_clear_protection_method_t { + QSPIF_BP_ULBPR, // Issue global protection unlock instruction + QSPIF_BP_CLEAR_SR, // Clear protection bits in status register 1 + }; + // QSPI Driver Object mbed::QSPI _qspi; @@ -332,16 +351,31 @@ private: // Command Instructions mbed::qspi_inst_t _read_instruction; - mbed::qspi_inst_t _prog_instruction; - mbed::qspi_inst_t _erase_instruction; - mbed::qspi_inst_t _erase4k_inst; // Legacy 4K erase instruction (default 0x20h) - mbed::qspi_inst_t _write_register_inst; // Write status/config register instruction may vary between chips - mbed::qspi_inst_t _read_register_inst; // Read status/config register instruction may vary between chips + mbed::qspi_inst_t _legacy_erase_instruction; + + // Status register write/read instructions + unsigned int _num_status_registers; + mbed::qspi_inst_t _write_status_reg_2_inst; + mbed::qspi_inst_t _read_status_reg_2_inst; // If three registers, this instruction reads the latter two + + // Attempt to enable 4-byte addressing. True by default, but may be disabled for some vendors + bool _attempt_4_byte_addressing; + // 4-byte addressing extension register write instruction + mbed::qspi_inst_t _4byte_msb_reg_write_inst; // Up To 4 Erase Types are supported by SFDP (each with its own command Instruction and Size) mbed::qspi_inst_t _erase_type_inst_arr[MAX_NUM_OF_ERASE_TYPES]; unsigned int _erase_type_size_arr[MAX_NUM_OF_ERASE_TYPES]; + // Quad mode enable status register and bit + int _quad_enable_register_idx; + int _quad_enable_bit; + + bool _needs_fast_mode; + + // Clear block protection + qspif_clear_protection_method_t _clear_protection_method; + // Sector Regions Map int _regions_count; //number of regions int _region_size_bytes[QSPIF_MAX_REGIONS]; //regions size in bytes diff --git a/features/storage/TESTS/blockdevice/general_block_device/main.cpp b/features/storage/TESTS/blockdevice/general_block_device/main.cpp index 00bdf90a81..c29bfdab76 100644 --- a/features/storage/TESTS/blockdevice/general_block_device/main.cpp +++ b/features/storage/TESTS/blockdevice/general_block_device/main.cpp @@ -64,7 +64,7 @@ using namespace utest::v1; #define TEST_BLOCK_COUNT 10 #define TEST_ERROR_MASK 16 #define TEST_NUM_OF_THREADS 5 -#define TEST_THREAD_STACK_SIZE 1024 +#define TEST_THREAD_STACK_SIZE 1152 uint8_t num_of_sectors = TEST_NUM_OF_THREADS * TEST_BLOCK_COUNT; uint32_t sectors_addr[TEST_NUM_OF_THREADS * TEST_BLOCK_COUNT] = {0}; diff --git a/features/storage/TESTS/kvstore/filesystemstore_tests/main.cpp b/features/storage/TESTS/kvstore/filesystemstore_tests/main.cpp index d8a75286cd..8a06c1e1e8 100644 --- a/features/storage/TESTS/kvstore/filesystemstore_tests/main.cpp +++ b/features/storage/TESTS/kvstore/filesystemstore_tests/main.cpp @@ -30,8 +30,8 @@ #include "utest.h" #include -#if !defined(TARGET_K64F) && !defined(TARGET_ARM_FM) -#error [NOT_SUPPORTED] Kvstore API tests run only on K64F devices and Fastmodels +#if !defined(TARGET_K64F) && !defined(TARGET_ARM_FM) && !defined(TARGET_MCU_PSOC6) +#error [NOT_SUPPORTED] Kvstore API tests run only on K64F devices, Fastmodels, and PSoC 6 #else #define FSST_TEST_NUM_OF_THREADS 5 diff --git a/features/storage/TESTS/kvstore/general_tests_phase_1/main.cpp b/features/storage/TESTS/kvstore/general_tests_phase_1/main.cpp index 7bbbfb6130..075c6b00ce 100644 --- a/features/storage/TESTS/kvstore/general_tests_phase_1/main.cpp +++ b/features/storage/TESTS/kvstore/general_tests_phase_1/main.cpp @@ -32,8 +32,8 @@ using namespace utest::v1; using namespace mbed; -#if !defined(TARGET_K64F) && !defined(TARGET_ARM_FM) -#error [NOT_SUPPORTED] Kvstore API tests run only on K64F devices and Fastmodels +#if !defined(TARGET_K64F) && !defined(TARGET_ARM_FM) && !defined(TARGET_MCU_PSOC6) +#error [NOT_SUPPORTED] Kvstore API tests run only on K64F devices, Fastmodels, and PSoC 6 #else static const char data[] = "data"; @@ -66,9 +66,6 @@ static const char *kv_prefix[] = {"TDB_", "FS_", "SEC_"}; static int kv_setup = TDBStoreSet; -static const size_t ul_bd_size = 16 * 4096; -static const size_t rbp_bd_size = 8 * 4096; - static const int heap_alloc_threshold_size = 4096; /*----------------initialization------------------*/ @@ -77,6 +74,8 @@ static const int heap_alloc_threshold_size = 4096; static void kvstore_init() { int res; + size_t erase_size, ul_bd_size, rbp_bd_size; + BlockDevice *sec_bd; res = bd->init(); TEST_ASSERT_EQUAL_ERROR_CODE(0, res); @@ -105,14 +104,19 @@ static void kvstore_init() #if SECURESTORE_ENABLED if (kv_setup == SecStoreSet) { + sec_bd = bd; if (erase_val == -1) { flash_bd = new FlashSimBlockDevice(bd); - ul_bd = new SlicingBlockDevice(flash_bd, 0, ul_bd_size); - rbp_bd = new SlicingBlockDevice(flash_bd, ul_bd_size, ul_bd_size + rbp_bd_size); - } else { - ul_bd = new SlicingBlockDevice(bd, 0, ul_bd_size); - rbp_bd = new SlicingBlockDevice(bd, ul_bd_size, ul_bd_size + rbp_bd_size); + sec_bd = flash_bd; } + + erase_size = sec_bd->get_erase_size(); + ul_bd_size = erase_size * 4; + rbp_bd_size = erase_size * 2; + + ul_bd = new SlicingBlockDevice(sec_bd, 0, ul_bd_size); + rbp_bd = new SlicingBlockDevice(sec_bd, ul_bd_size, ul_bd_size + rbp_bd_size); + TDBStore *ul_kv = new TDBStore(ul_bd); TDBStore *rbp_kv = new TDBStore(rbp_bd); kvstore = new SecureStore(ul_kv, rbp_kv); diff --git a/features/storage/TESTS/kvstore/general_tests_phase_2/main.cpp b/features/storage/TESTS/kvstore/general_tests_phase_2/main.cpp index 33aa6c5849..91599f2960 100644 --- a/features/storage/TESTS/kvstore/general_tests_phase_2/main.cpp +++ b/features/storage/TESTS/kvstore/general_tests_phase_2/main.cpp @@ -32,8 +32,8 @@ using namespace utest::v1; using namespace mbed; -#if !defined(TARGET_K64F) && !defined(TARGET_ARM_FM) -#error [NOT_SUPPORTED] Kvstore API tests run only on K64F devices and Fastmodels +#if !defined(TARGET_K64F) && !defined(TARGET_ARM_FM) && !defined(TARGET_MCU_PSOC6) +#error [NOT_SUPPORTED] Kvstore API tests run only on K64F devices, Fastmodels, and PSoC 6 #else static const char data[] = "data"; @@ -66,9 +66,6 @@ static const char *kv_prefix[] = {"TDB_", "FS_", "SEC_"}; static int kv_setup = TDBStoreSet; -static const size_t ul_bd_size = 16 * 4096; -static const size_t rbp_bd_size = 8 * 4096; - static const int heap_alloc_threshold_size = 4096; /*----------------initialization------------------*/ @@ -77,6 +74,8 @@ static const int heap_alloc_threshold_size = 4096; static void kvstore_init() { int res; + size_t erase_size, ul_bd_size, rbp_bd_size; + BlockDevice *sec_bd; res = bd->init(); TEST_ASSERT_EQUAL_ERROR_CODE(0, res); @@ -105,14 +104,19 @@ static void kvstore_init() #if SECURESTORE_ENABLED if (kv_setup == SecStoreSet) { + sec_bd = bd; if (erase_val == -1) { flash_bd = new FlashSimBlockDevice(bd); - ul_bd = new SlicingBlockDevice(flash_bd, 0, ul_bd_size); - rbp_bd = new SlicingBlockDevice(flash_bd, ul_bd_size, ul_bd_size + rbp_bd_size); - } else { - ul_bd = new SlicingBlockDevice(bd, 0, ul_bd_size); - rbp_bd = new SlicingBlockDevice(bd, ul_bd_size, ul_bd_size + rbp_bd_size); + sec_bd = flash_bd; } + + erase_size = sec_bd->get_erase_size(); + ul_bd_size = erase_size * 4; + rbp_bd_size = erase_size * 2; + + ul_bd = new SlicingBlockDevice(sec_bd, 0, ul_bd_size); + rbp_bd = new SlicingBlockDevice(sec_bd, ul_bd_size, ul_bd_size + rbp_bd_size); + TDBStore *ul_kv = new TDBStore(ul_bd); TDBStore *rbp_kv = new TDBStore(rbp_bd); kvstore = new SecureStore(ul_kv, rbp_kv); diff --git a/features/storage/TESTS/kvstore/securestore_whitebox/main.cpp b/features/storage/TESTS/kvstore/securestore_whitebox/main.cpp index af2bb1d5f1..ab5b759714 100644 --- a/features/storage/TESTS/kvstore/securestore_whitebox/main.cpp +++ b/features/storage/TESTS/kvstore/securestore_whitebox/main.cpp @@ -34,8 +34,8 @@ #include #include -#if (!defined(TARGET_K64F) && !defined(TARGET_ARM_FM)) || !SECURESTORE_ENABLED -#error [NOT_SUPPORTED] Kvstore API tests run only on K64F devices and Fastmodels. KVStore & SecureStore need to be enabled for this test +#if (!defined(TARGET_K64F) && !defined(TARGET_ARM_FM)) && !defined(TARGET_MCU_PSOC6) || !SECURESTORE_ENABLED +#error [NOT_SUPPORTED] Kvstore API tests run only on K64F devices, Fastmodels, and PSoC 6. KVStore & SecureStore need to be enabled for this test #else using namespace mbed; diff --git a/features/storage/TESTS/kvstore/tdbstore_whitebox/main.cpp b/features/storage/TESTS/kvstore/tdbstore_whitebox/main.cpp index eb43e6c601..b1055d1921 100644 --- a/features/storage/TESTS/kvstore/tdbstore_whitebox/main.cpp +++ b/features/storage/TESTS/kvstore/tdbstore_whitebox/main.cpp @@ -92,8 +92,8 @@ static const char *const res_val2 = "This should surely not be saved as the res static void white_box_test() { -#if !defined(TARGET_K64F) - TEST_SKIP_MESSAGE("Kvstore API tests run only on K64F devices"); +#if !defined(TARGET_K64F) && !defined(TARGET_MCU_PSOC6) + TEST_SKIP_MESSAGE("Kvstore API tests run only on K64F devices and PSoC 6"); #endif bd_params_t bd_params[] = { @@ -334,8 +334,8 @@ static void white_box_test() static void multi_set_test() { -#if !defined(TARGET_K64F) - TEST_SKIP_MESSAGE("Kvstore API tests run only on K64F devices"); +#if !defined(TARGET_K64F) && !defined(TARGET_MCU_PSOC6) + TEST_SKIP_MESSAGE("Kvstore API tests run only on K64F devices and PSoC 6"); #endif char *key; @@ -458,8 +458,8 @@ static void multi_set_test() static void error_inject_test() { -#if !defined(TARGET_K64F) - TEST_SKIP_MESSAGE("Kvstore API tests run only on K64F devices"); +#if !defined(TARGET_K64F) && !defined(TARGET_MCU_PSOC6) + TEST_SKIP_MESSAGE("Kvstore API tests run only on K64F devices and PSoC 6"); #endif char *key;