diff --git a/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.cpp b/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.cpp index 24bc51a7745..d82ceaabc0f 100644 --- a/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.cpp +++ b/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.cpp @@ -53,7 +53,6 @@ using namespace mbed; /* Basic Parameters Table Parsing */ /**********************************/ -#define SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES 64 /* 16 DWORDS */ //READ Instruction support according to BUS Configuration #define QSPIF_BASIC_PARAM_TABLE_FAST_READ_SUPPORT_BYTE 2 #define QSPIF_BASIC_PARAM_TABLE_QPI_READ_SUPPORT_BYTE 16 @@ -84,11 +83,6 @@ using namespace mbed; #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 @@ -158,9 +152,9 @@ QSPIFBlockDevice::QSPIFBlockDevice(PinName io0, PinName io1, PinName io2, PinNam } // Initialize parameters - _min_common_erase_size = 0; - _regions_count = 1; - _region_erase_types_bitfield[0] = ERASE_BITMASK_NONE; + _sfdp_info.smptbl.regions_min_common_erase_size = 0; + _sfdp_info.smptbl.region_cnt = 1; + _sfdp_info.smptbl.region_erase_types_bitfld[0] = SFDP_ERASE_BITMASK_NONE; // Until proven otherwise, assume no quad enable _quad_enable_register_idx = QSPIF_NO_QUAD_ENABLE; @@ -204,8 +198,10 @@ int QSPIFBlockDevice::init() } int status = QSPIF_BD_ERROR_OK; - sfdp_hdr_info hdr_info; - memset(&hdr_info, 0, sizeof hdr_info); + _sfdp_info.bptbl.addr = 0x0; + _sfdp_info.bptbl.size = 0; + _sfdp_info.smptbl.addr = 0x0; + _sfdp_info.smptbl.size = 0; _mutex.lock(); @@ -249,28 +245,29 @@ int QSPIFBlockDevice::init() } /**************************** Parse SFDP Header ***********************************/ - if (0 != _sfdp_parse_sfdp_headers(hdr_info)) { + if (sfdp_parse_headers(callback(this, &QSPIFBlockDevice::_qspi_send_read_sfdp_command), _sfdp_info) < 0) { tr_error("Init - Parse SFDP Headers Failed"); status = QSPIF_BD_ERROR_PARSING_FAILED; goto exit_point; } /**************************** Parse Basic Parameters Table ***********************************/ - if (0 != _sfdp_parse_basic_param_table(hdr_info.basic_table_addr, hdr_info.basic_table_size)) { + if (0 != _sfdp_parse_basic_param_table(_sfdp_info.bptbl.addr, _sfdp_info.bptbl.size)) { tr_error("Init - Parse Basic Param Table Failed"); status = QSPIF_BD_ERROR_PARSING_FAILED; goto exit_point; } /**************************** Parse Sector Map Table ***********************************/ - _region_size_bytes[0] = + _sfdp_info.smptbl.region_size[0] = _device_size_bytes; // If there's no region map, we have a single region sized the entire device size - _region_high_boundary[0] = _device_size_bytes - 1; + _sfdp_info.smptbl.region_high_boundary[0] = _device_size_bytes - 1; - if ((hdr_info.sector_map_table_addr != 0) && (0 != hdr_info.sector_map_table_size)) { - tr_debug("Init - Parsing Sector Map Table - addr: 0x%lxh, Size: %d", hdr_info.sector_map_table_addr, - hdr_info.sector_map_table_size); - if (0 != _sfdp_parse_sector_map_table(hdr_info.sector_map_table_addr, hdr_info.sector_map_table_size)) { + if ((_sfdp_info.smptbl.addr != 0) && (0 != _sfdp_info.smptbl.size)) { + tr_debug("Init - Parsing Sector Map Table - addr: 0x%lxh, Size: %d", _sfdp_info.smptbl.addr, + _sfdp_info.smptbl.size); + if (sfdp_parse_sector_map_table(callback(this, &QSPIFBlockDevice::_qspi_send_read_sfdp_command), + _sfdp_info.smptbl) < 0) { tr_error("Init - Parse Sector Map Table Failed"); status = QSPIF_BD_ERROR_PARSING_FAILED; goto exit_point; @@ -412,9 +409,9 @@ int QSPIFBlockDevice::erase(bd_addr_t addr, bd_size_t in_size) bool erase_failed = false; int status = QSPIF_BD_ERROR_OK; // Find region of erased address - int region = _utils_find_addr_region(addr); + int region = _utils_find_addr_region(addr, _sfdp_info.smptbl); // Erase Types of selected region - uint8_t bitfield = _region_erase_types_bitfield[region]; + uint8_t bitfield = _sfdp_info.smptbl.region_erase_types_bitfld[region]; tr_debug("Erase - addr: %llu, in_size: %llu", addr, in_size); @@ -434,9 +431,11 @@ int QSPIFBlockDevice::erase(bd_addr_t addr, bd_size_t in_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]; + type = _utils_iterate_next_largest_erase_type(bitfield, size, (int)addr, + region, + _sfdp_info.smptbl); + cur_erase_inst = _sfdp_info.smptbl.erase_type_inst_arr[type]; + eu_size = _sfdp_info.smptbl.erase_type_size_arr[type]; } else { // Must use legacy 4k erase instruction cur_erase_inst = _legacy_erase_instruction; @@ -469,10 +468,10 @@ int QSPIFBlockDevice::erase(bd_addr_t addr, bd_size_t in_size) addr += chunk; size -= chunk; - if ((size > 0) && (addr > _region_high_boundary[region])) { + if ((size > 0) && (addr > _sfdp_info.smptbl.region_high_boundary[region])) { // erase crossed to next region region++; - bitfield = _region_erase_types_bitfield[region]; + bitfield = _sfdp_info.smptbl.region_erase_types_bitfld[region]; } if (false == _is_mem_ready()) { @@ -508,7 +507,7 @@ bd_size_t QSPIFBlockDevice::get_program_size() const bd_size_t QSPIFBlockDevice::get_erase_size() const { // return minimal erase size supported by all regions (0 if none exists) - return _min_common_erase_size; + return _sfdp_info.smptbl.regions_min_common_erase_size; } const char *QSPIFBlockDevice::get_type() const @@ -525,10 +524,10 @@ bd_size_t QSPIFBlockDevice::get_erase_size(bd_addr_t addr) } // Find region of current address - int region = _utils_find_addr_region(addr); + int region = _utils_find_addr_region(addr, _sfdp_info.smptbl); - int min_region_erase_size = _min_common_erase_size; - int8_t type_mask = ERASE_BITMASK_TYPE1; + int min_region_erase_size = _sfdp_info.smptbl.regions_min_common_erase_size; + int8_t type_mask = SFDP_ERASE_BITMASK_TYPE1; int i_ind = 0; if (region != -1) { @@ -536,9 +535,9 @@ bd_size_t QSPIFBlockDevice::get_erase_size(bd_addr_t addr) for (i_ind = 0; i_ind < 4; i_ind++) { // loop through erase types bitfield supported by region - if (_region_erase_types_bitfield[region] & type_mask) { + if (_sfdp_info.smptbl.region_erase_types_bitfld[region] & type_mask) { - min_region_erase_size = _erase_type_size_arr[i_ind]; + min_region_erase_size = _sfdp_info.smptbl.erase_type_size_arr[i_ind]; break; } type_mask = type_mask << 1; @@ -627,14 +626,9 @@ int QSPIFBlockDevice::remove_csel_instance(PinName csel) /*********************************************************/ /********** SFDP Parsing and Detection Functions *********/ /*********************************************************/ -int QSPIFBlockDevice::_sfdp_parse_sfdp_headers(mbed::sfdp_hdr_info &hdr_info) -{ - return sfdp_parse_headers(callback(this, &QSPIFBlockDevice::_qspi_send_read_sfdp_command), hdr_info); -} - 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 */ + uint8_t param_table[SFDP_BASIC_PARAMS_TBL_SIZE]; /* Up To 16 DWORDS = 64 Bytes */ int status = _qspi_send_read_sfdp_command(basic_table_addr, (char *)param_table, basic_table_size); if (status != QSPI_STATUS_OK) { @@ -667,7 +661,7 @@ int QSPIFBlockDevice::_sfdp_parse_basic_param_table(uint32_t basic_table_addr, s bool shouldSetQuadEnable = false; bool is_qpi_mode = false; - if (_sfdp_detect_erase_types_inst_and_size(param_table, basic_table_size) != 0) { + if (_sfdp_detect_erase_types_inst_and_size(param_table, basic_table_size, _sfdp_info.smptbl) != 0) { tr_error("Init - Detecting erase types instructions/sizes failed"); return -1; } @@ -851,7 +845,9 @@ 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) +int QSPIFBlockDevice::_sfdp_detect_erase_types_inst_and_size(uint8_t *basic_param_table_ptr, + int basic_param_table_size, + sfdp_smptbl_info &smptbl) { uint8_t bitfield = 0x01; @@ -859,23 +855,26 @@ int QSPIFBlockDevice::_sfdp_detect_erase_types_inst_and_size(uint8_t *basic_para 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] = 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) { + smptbl.erase_type_inst_arr[i_ind] = QSPI_NO_INST; // Default for unsupported type + smptbl.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), smptbl.erase_type_inst_arr[i_ind], + smptbl.erase_type_size_arr[i_ind]); + if (smptbl.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_TABLE_ERASE_TYPE_1_BYTE + 2 * i_ind]; + smptbl.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)) { + if ((smptbl.erase_type_size_arr[i_ind] < smptbl.regions_min_common_erase_size) + || (smptbl.regions_min_common_erase_size == 0)) { //Set default minimal common erase for signal region - _min_common_erase_size = _erase_type_size_arr[i_ind]; + smptbl.regions_min_common_erase_size = smptbl.erase_type_size_arr[i_ind]; } - _region_erase_types_bitfield[0] |= bitfield; // If there's no region map, set region "0" types bitfield as default + smptbl.region_erase_types_bitfld[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), smptbl.erase_type_inst_arr[i_ind], + smptbl.erase_type_size_arr[i_ind]); bitfield = bitfield << 1; } } else { @@ -1108,63 +1107,6 @@ int QSPIFBlockDevice::_sfdp_detect_reset_protocol_and_reset(uint8_t *basic_param 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; - - int 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}; @@ -1378,20 +1320,20 @@ bool QSPIFBlockDevice::_is_mem_ready() /*********************************************/ /************* Utility Functions *************/ /*********************************************/ -int QSPIFBlockDevice::_utils_find_addr_region(bd_size_t offset) +int QSPIFBlockDevice::_utils_find_addr_region(bd_size_t offset, sfdp_smptbl_info &smptbl) { //Find the region to which the given offset belong to - if ((offset > _device_size_bytes) || (_regions_count == 0)) { + if ((offset > _device_size_bytes) || (smptbl.region_cnt == 0)) { return -1; } - if (_regions_count == 1) { + if (smptbl.region_cnt == 1) { return 0; } - for (int i_ind = _regions_count - 2; i_ind >= 0; i_ind--) { + for (int i_ind = smptbl.region_cnt - 2; i_ind >= 0; i_ind--) { - if (offset > _region_high_boundary[i_ind]) { + if (offset > smptbl.region_high_boundary[i_ind]) { return (i_ind + 1); } } @@ -1399,18 +1341,23 @@ int QSPIFBlockDevice::_utils_find_addr_region(bd_size_t offset) } -int QSPIFBlockDevice::_utils_iterate_next_largest_erase_type(uint8_t &bitfield, int size, int offset, int boundry) +int QSPIFBlockDevice::_utils_iterate_next_largest_erase_type(uint8_t &bitfield, + int size, + int offset, + int region, + sfdp_smptbl_info &smptbl) { // Iterate on all supported Erase Types of the Region to which the offset belong to. // Iterates from highest type to lowest - uint8_t type_mask = ERASE_BITMASK_TYPE4; + uint8_t type_mask = SFDP_ERASE_BITMASK_TYPE4; int i_ind = 0; int largest_erase_type = 0; for (i_ind = 3; i_ind >= 0; i_ind--) { if (bitfield & type_mask) { largest_erase_type = i_ind; - if ((size > (int)(_erase_type_size_arr[largest_erase_type])) && - ((boundry - offset) > (int)(_erase_type_size_arr[largest_erase_type]))) { + if ((size > (int)(smptbl.erase_type_size_arr[largest_erase_type])) && + ((_sfdp_info.smptbl.region_high_boundary[region] - offset) + > (int)(smptbl.erase_type_size_arr[largest_erase_type]))) { break; } else { bitfield &= ~type_mask; diff --git a/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.h b/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.h index a3ca84ada2c..13d0f52b5a9 100644 --- a/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.h +++ b/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.h @@ -70,8 +70,6 @@ enum qspif_polarity_mode { QSPIF_POLARITY_MODE_1 /* CPOL=1, CPHA=1 */ }; -#define QSPIF_MAX_REGIONS 10 -#define MAX_NUM_OF_ERASE_TYPES 4 #define QSPIF_MAX_ACTIVE_FLASH_DEVICES 10 /** BlockDevice for SFDP based flash devices over QSPI bus @@ -318,15 +316,9 @@ class QSPIFBlockDevice : public mbed::BlockDevice { /****************************************/ /* SFDP Detection and Parsing Functions */ /****************************************/ - // Parse SFDP Headers and retrieve Basic Param and Sector Map Tables (if exist) - int _sfdp_parse_sfdp_headers(mbed::sfdp_hdr_info &hdr_info); - // 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 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); @@ -344,7 +336,9 @@ class QSPIFBlockDevice : public mbed::BlockDevice { 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); + int _sfdp_detect_erase_types_inst_and_size(uint8_t *basic_param_table_ptr, + int basic_param_table_size, + mbed::sfdp_smptbl_info &smptbl); // 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); @@ -356,11 +350,15 @@ class QSPIFBlockDevice : public mbed::BlockDevice { /* Utilities Functions */ /***********************/ // Find the region to which the given offset belong to - int _utils_find_addr_region(mbed::bd_size_t offset); + int _utils_find_addr_region(mbed::bd_size_t offset, mbed::sfdp_smptbl_info &smptbl); // Iterate on all supported Erase Types of the Region to which the offset belong to. // Iterates from highest type to lowest - int _utils_iterate_next_largest_erase_type(uint8_t &bitfield, int size, int offset, int boundry); + int _utils_iterate_next_largest_erase_type(uint8_t &bitfield, + int size, + int offset, + int region, + mbed::sfdp_smptbl_info &smptbl); private: enum qspif_clear_protection_method_t { @@ -399,10 +397,6 @@ class QSPIFBlockDevice : public mbed::BlockDevice { // 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; @@ -412,13 +406,8 @@ class QSPIFBlockDevice : public mbed::BlockDevice { // 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 - bd_size_t _region_high_boundary[QSPIF_MAX_REGIONS]; //region high address offset boundary - //Each Region can support a bit combination of any of the 4 Erase Types - uint8_t _region_erase_types_bitfield[QSPIF_MAX_REGIONS]; - unsigned int _min_common_erase_size; // minimal common erase size for all regions (0 if none exists) + // Data extracted from the devices SFDP structure + mbed::sfdp_hdr_info _sfdp_info; unsigned int _page_size_bytes; // Page size - 256 Bytes default int _freq; diff --git a/components/storage/blockdevice/COMPONENT_SPIF/SPIFBlockDevice.cpp b/components/storage/blockdevice/COMPONENT_SPIF/SPIFBlockDevice.cpp index 3d2966dec26..18373e19411 100644 --- a/components/storage/blockdevice/COMPONENT_SPIF/SPIFBlockDevice.cpp +++ b/components/storage/blockdevice/COMPONENT_SPIF/SPIFBlockDevice.cpp @@ -65,12 +65,6 @@ using namespace mbed; #define SPIF_BASIC_PARAM_ERASE_TYPE_4_SIZE_BYTE 34 #define SPIF_BASIC_PARAM_4K_ERASE_TYPE_BYTE 1 -// 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 - #define IS_MEM_READY_MAX_RETRIES 10000 enum spif_default_instructions { @@ -113,9 +107,9 @@ SPIFBlockDevice::SPIFBlockDevice( _write_dummy_and_mode_cycles = 0; _dummy_and_mode_cycles = _read_dummy_and_mode_cycles; - _min_common_erase_size = 0; - _regions_count = 1; - _region_erase_types_bitfield[0] = ERASE_BITMASK_NONE; + _sfdp_info.smptbl.regions_min_common_erase_size = 0; + _sfdp_info.smptbl.region_cnt = 1; + _sfdp_info.smptbl.region_erase_types_bitfld[0] = SFDP_ERASE_BITMASK_NONE; if (SPIF_BD_ERROR_OK != _spi_set_frequency(freq)) { tr_error("SPI Set Frequency Failed"); @@ -181,7 +175,7 @@ int SPIFBlockDevice::init() } /**************************** Parse SFDP Header ***********************************/ - if (0 != _sfdp_parse_sfdp_headers(hdr_info)) { + if (0 != sfdp_parse_headers(callback(this, &SPIFBlockDevice::_spi_send_read_sfdp_command), hdr_info)) { tr_error("init - Parse SFDP Headers Failed"); status = SPIF_BD_ERROR_PARSING_FAILED; goto exit_point; @@ -189,21 +183,22 @@ int SPIFBlockDevice::init() /**************************** Parse Basic Parameters Table ***********************************/ - if (0 != _sfdp_parse_basic_param_table(hdr_info.basic_table_addr, hdr_info.basic_table_size)) { + if (0 != _sfdp_parse_basic_param_table(hdr_info.bptbl.addr, hdr_info.bptbl.size)) { tr_error("init - Parse Basic Param Table Failed"); status = SPIF_BD_ERROR_PARSING_FAILED; goto exit_point; } /**************************** Parse Sector Map Table ***********************************/ - _region_size_bytes[0] = + _sfdp_info.smptbl.region_size[0] = _device_size_bytes; // If there's no region map, we have a single region sized the entire device size - _region_high_boundary[0] = _device_size_bytes - 1; + _sfdp_info.smptbl.region_high_boundary[0] = _device_size_bytes - 1; - if ((hdr_info.sector_map_table_addr != 0) && (0 != hdr_info.sector_map_table_size)) { - tr_debug("init - Parsing Sector Map Table - addr: 0x%" PRIx32 "h, Size: %d", hdr_info.sector_map_table_addr, - hdr_info.sector_map_table_size); - if (0 != _sfdp_parse_sector_map_table(hdr_info.sector_map_table_addr, hdr_info.sector_map_table_size)) { + if ((hdr_info.smptbl.addr != 0) && (0 != hdr_info.smptbl.size)) { + tr_debug("init - Parsing Sector Map Table - addr: 0x%" PRIx32 "h, Size: %d", hdr_info.smptbl.addr, + hdr_info.smptbl.size); + if (sfdp_parse_sector_map_table(callback(this, &SPIFBlockDevice::_spi_send_read_sfdp_command), + _sfdp_info.smptbl) < 0) { tr_error("init - Parse Sector Map Table Failed"); status = SPIF_BD_ERROR_PARSING_FAILED; goto exit_point; @@ -347,13 +342,13 @@ int SPIFBlockDevice::erase(bd_addr_t addr, bd_size_t in_size) bool erase_failed = false; int status = SPIF_BD_ERROR_OK; // Find region of erased address - int region = _utils_find_addr_region(addr); + int region = _utils_find_addr_region(addr, _sfdp_info.smptbl); if (region < 0) { tr_error("no region found for address %llu", addr); return SPIF_BD_ERROR_INVALID_ERASE_PARAMS; } // Erase Types of selected region - uint8_t bitfield = _region_erase_types_bitfield[region]; + uint8_t bitfield = _sfdp_info.smptbl.region_erase_types_bitfld[region]; tr_debug("erase - addr: %llu, in_size: %llu", addr, in_size); @@ -372,10 +367,11 @@ int SPIFBlockDevice::erase(bd_addr_t addr, bd_size_t in_size) // 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, (unsigned 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); + type = _utils_iterate_next_largest_erase_type(bitfield, size, (unsigned int)addr, region, _sfdp_info.smptbl); + cur_erase_inst = _sfdp_info.smptbl.erase_type_inst_arr[type]; + offset = addr % _sfdp_info.smptbl.erase_type_size_arr[type]; + chunk = ((offset + size) < _sfdp_info.smptbl.erase_type_size_arr[type]) ? + size : (_sfdp_info.smptbl.erase_type_size_arr[type] - offset); tr_debug("erase - addr: %llu, size:%d, Inst: 0x%xh, chunk: %" PRIu32 " , ", addr, size, cur_erase_inst, chunk); @@ -396,10 +392,10 @@ int SPIFBlockDevice::erase(bd_addr_t addr, bd_size_t in_size) addr += chunk; size -= chunk; - if ((size > 0) && (addr > _region_high_boundary[region])) { + if ((size > 0) && (addr > _sfdp_info.smptbl.region_high_boundary[region])) { // erase crossed to next region region++; - bitfield = _region_erase_types_bitfield[region]; + bitfield = _sfdp_info.smptbl.region_erase_types_bitfld[region]; } if (false == _is_mem_ready()) { @@ -435,17 +431,17 @@ bd_size_t SPIFBlockDevice::get_program_size() const bd_size_t SPIFBlockDevice::get_erase_size() const { // return minimal erase size supported by all regions (0 if none exists) - return _min_common_erase_size; + return _sfdp_info.smptbl.regions_min_common_erase_size; } // Find minimal erase size supported by the region to which the address belongs to bd_size_t SPIFBlockDevice::get_erase_size(bd_addr_t addr) const { // Find region of current address - int region = _utils_find_addr_region(addr); + int region = _utils_find_addr_region(addr, _sfdp_info.smptbl); - unsigned int min_region_erase_size = _min_common_erase_size; - int8_t type_mask = ERASE_BITMASK_TYPE1; + unsigned int min_region_erase_size = _sfdp_info.smptbl.regions_min_common_erase_size; + int8_t type_mask = SFDP_ERASE_BITMASK_TYPE1; int i_ind = 0; if (region != -1) { @@ -453,9 +449,9 @@ bd_size_t SPIFBlockDevice::get_erase_size(bd_addr_t addr) const for (i_ind = 0; i_ind < 4; i_ind++) { // loop through erase types bitfield supported by region - if (_region_erase_types_bitfield[region] & type_mask) { + if (_sfdp_info.smptbl.region_erase_types_bitfld[region] & type_mask) { - min_region_erase_size = _erase_type_size_arr[i_ind]; + min_region_erase_size = _sfdp_info.smptbl.erase_type_size_arr[i_ind]; break; } type_mask = type_mask << 1; @@ -624,65 +620,6 @@ spif_bd_error SPIFBlockDevice::_spi_send_general_command(int instruction, bd_add /*********************************************************/ /********** SFDP Parsing and Detection Functions *********/ /*********************************************************/ -int SPIFBlockDevice::_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; - - - spif_bd_error status = _spi_send_read_command(SPIF_SFDP, sector_map_table, sector_map_table_addr /*address*/, - sector_map_table_size); - if (status != SPIF_BD_ERROR_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 > SPIF_MAX_REGIONS) { - tr_error("Supporting up to %d regions, current setup to %d regions - fail", - SPIF_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 SPIFBlockDevice::_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 */ @@ -719,8 +656,7 @@ int SPIFBlockDevice::_sfdp_parse_basic_param_table(uint32_t basic_table_addr, si _page_size_bytes = _sfdp_detect_page_size(param_table, basic_table_size); // Detect and Set Erase Types - _sfdp_detect_erase_types_inst_and_size(param_table, basic_table_size, _erase4k_inst, _erase_type_inst_arr, - _erase_type_size_arr); + _sfdp_detect_erase_types_inst_and_size(param_table, basic_table_size, _erase4k_inst, _sfdp_info.smptbl); _erase_instruction = _erase4k_inst; // Detect and Set fastest Bus mode (default 1-1-1) @@ -729,11 +665,6 @@ int SPIFBlockDevice::_sfdp_parse_basic_param_table(uint32_t basic_table_addr, si return 0; } -int SPIFBlockDevice::_sfdp_parse_sfdp_headers(sfdp_hdr_info &hdr_info) -{ - return sfdp_parse_headers(callback(this, &SPIFBlockDevice::_spi_send_read_sfdp_command), hdr_info); -} - unsigned int SPIFBlockDevice::_sfdp_detect_page_size(uint8_t *basic_param_table_ptr, int basic_param_table_size) { unsigned int page_size = SPIF_DEFAULT_PAGE_SIZE; @@ -751,7 +682,7 @@ unsigned int SPIFBlockDevice::_sfdp_detect_page_size(uint8_t *basic_param_table_ int SPIFBlockDevice::_sfdp_detect_erase_types_inst_and_size(uint8_t *basic_param_table_ptr, int basic_param_table_size, int &erase4k_inst, - int *erase_type_inst_arr, unsigned int *erase_type_size_arr) + sfdp_smptbl_info &smptbl) { erase4k_inst = 0xff; bool found_4Kerase_type = false; @@ -763,34 +694,36 @@ int SPIFBlockDevice::_sfdp_detect_erase_types_inst_and_size(uint8_t *basic_param if (basic_param_table_size > SPIF_BASIC_PARAM_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[SPIF_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) { + smptbl.erase_type_inst_arr[i_ind] = 0xff; //0xFF default for unsupported type + smptbl.erase_type_size_arr[i_ind] = local_math_power( + 2, basic_param_table_ptr[SPIF_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), smptbl.erase_type_inst_arr[i_ind], + smptbl.erase_type_size_arr[i_ind]); + if (smptbl.erase_type_size_arr[i_ind] > 1) { // if size==1 type is not supported - erase_type_inst_arr[i_ind] = basic_param_table_ptr[SPIF_BASIC_PARAM_ERASE_TYPE_1_BYTE + 2 * i_ind]; + smptbl.erase_type_inst_arr[i_ind] = + basic_param_table_ptr[SPIF_BASIC_PARAM_ERASE_TYPE_1_BYTE + 2 * i_ind]; - if ((erase_type_size_arr[i_ind] < _min_common_erase_size) || (_min_common_erase_size == 0)) { + if ((smptbl.erase_type_size_arr[i_ind] < smptbl.regions_min_common_erase_size) + || (smptbl.regions_min_common_erase_size == 0)) { //Set default minimal common erase for singal region - _min_common_erase_size = erase_type_size_arr[i_ind]; + smptbl.regions_min_common_erase_size = smptbl.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) { + if (smptbl.erase_type_size_arr[i_ind] == 4096) { found_4Kerase_type = true; - if (erase4k_inst != erase_type_inst_arr[i_ind]) { + if (erase4k_inst != smptbl.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]; + erase4k_inst = smptbl.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; + smptbl.region_erase_types_bitfld[0] |= bitfield; // no region map, set region "0" types bitfield as default } tr_info("Erase Type %d - Inst: 0x%xh, Size: %d", (i_ind + 1), - erase_type_inst_arr[i_ind], erase_type_size_arr[i_ind]); + smptbl.erase_type_inst_arr[i_ind], smptbl.erase_type_size_arr[i_ind]); bitfield = bitfield << 1; } } @@ -918,20 +851,20 @@ int SPIFBlockDevice::_set_write_enable() /*********************************************/ /************* Utility Functions *************/ /*********************************************/ -int SPIFBlockDevice::_utils_find_addr_region(bd_size_t offset) const +int SPIFBlockDevice::_utils_find_addr_region(bd_size_t offset, const sfdp_smptbl_info &smptbl) const { //Find the region to which the given offset belong to - if ((offset > _device_size_bytes) || (_regions_count == 0)) { + if ((offset > _device_size_bytes) || (smptbl.region_cnt == 0)) { return -1; } - if (_regions_count == 1) { + if (smptbl.region_cnt == 1) { return 0; } - for (int i_ind = _regions_count - 2; i_ind >= 0; i_ind--) { + for (int i_ind = smptbl.region_cnt - 2; i_ind >= 0; i_ind--) { - if (offset > _region_high_boundary[i_ind]) { + if (offset > smptbl.region_high_boundary[i_ind]) { return (i_ind + 1); } } @@ -939,18 +872,23 @@ int SPIFBlockDevice::_utils_find_addr_region(bd_size_t offset) const } -int SPIFBlockDevice::_utils_iterate_next_largest_erase_type(uint8_t &bitfield, int size, int offset, int boundry) +int SPIFBlockDevice::_utils_iterate_next_largest_erase_type(uint8_t &bitfield, + int size, + int offset, + int region, + sfdp_smptbl_info &smptbl) { // Iterate on all supported Erase Types of the Region to which the offset belong to. // Iterates from highest type to lowest - uint8_t type_mask = ERASE_BITMASK_TYPE4; + uint8_t type_mask = SFDP_ERASE_BITMASK_TYPE4; int i_ind = 0; int largest_erase_type = 0; for (i_ind = 3; i_ind >= 0; i_ind--) { if (bitfield & type_mask) { largest_erase_type = i_ind; - if ((size > (int)(_erase_type_size_arr[largest_erase_type])) && - ((boundry - offset) > (int)(_erase_type_size_arr[largest_erase_type]))) { + if ((size > (int)(smptbl.erase_type_size_arr[largest_erase_type])) && + ((_sfdp_info.smptbl.region_high_boundary[region] - offset) + > (int)(smptbl.erase_type_size_arr[largest_erase_type]))) { break; } else { bitfield &= ~type_mask; @@ -960,10 +898,9 @@ int SPIFBlockDevice::_utils_iterate_next_largest_erase_type(uint8_t &bitfield, i } if (i_ind == 4) { - tr_error("no erase type was found for current region addr"); + tr_error("No erase type was found for current region addr"); } return largest_erase_type; - } /*********************************************/ diff --git a/components/storage/blockdevice/COMPONENT_SPIF/SPIFBlockDevice.h b/components/storage/blockdevice/COMPONENT_SPIF/SPIFBlockDevice.h index d847d364b1f..081c79b535c 100644 --- a/components/storage/blockdevice/COMPONENT_SPIF/SPIFBlockDevice.h +++ b/components/storage/blockdevice/COMPONENT_SPIF/SPIFBlockDevice.h @@ -52,9 +52,6 @@ enum spif_bd_error { }; -#define SPIF_MAX_REGIONS 10 -#define MAX_NUM_OF_ERASE_TYPES 4 - /** BlockDevice for SFDP based flash devices over SPI bus * * @code @@ -222,21 +219,19 @@ class SPIFBlockDevice : public mbed::BlockDevice { // Internal functions + // SFDP helpers + friend int mbed::sfdp_parse_headers(mbed::Callback sfdp_reader, + mbed::sfdp_hdr_info &hdr_info); + /****************************************/ /* SFDP Detection and Parsing Functions */ /****************************************/ // Send SFDP Read command to Driver int _spi_send_read_sfdp_command(mbed::bd_addr_t addr, void *rx_buffer, mbed::bd_size_t rx_length); - // Parse SFDP Headers and retrieve Basic Param and Sector Map Tables (if exist) - int _sfdp_parse_sfdp_headers(mbed::sfdp_hdr_info &hdr_info); - // 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 Sector Map - int _sfdp_parse_sector_map_table(uint32_t sector_map_table_addr, size_t sector_map_table_size); - // 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, int &read_inst); @@ -246,17 +241,21 @@ class SPIFBlockDevice : public mbed::BlockDevice { // Detect all supported erase types int _sfdp_detect_erase_types_inst_and_size(uint8_t *basic_param_table_ptr, int basic_param_table_size, int &erase4k_inst, - int *erase_type_inst_arr, unsigned int *erase_type_size_arr); + mbed::sfdp_smptbl_info &smptbl); /***********************/ /* Utilities Functions */ /***********************/ // Find the region to which the given offset belongs to - int _utils_find_addr_region(bd_size_t offset) const; + int _utils_find_addr_region(bd_size_t offset, const mbed::sfdp_smptbl_info &smptbl) const; // Iterate on all supported Erase Types of the Region to which the offset belongs to. // Iterates from highest type to lowest - int _utils_iterate_next_largest_erase_type(uint8_t &bitfield, int size, int offset, int boundry); + int _utils_iterate_next_largest_erase_type(uint8_t &bitfield, + int size, + int offset, + int region, + mbed::sfdp_smptbl_info &smptbl); /********************************/ /* Calls to SPI Driver APIs */ @@ -304,22 +303,8 @@ class SPIFBlockDevice : public mbed::BlockDevice { int _erase_instruction; int _erase4k_inst; // Legacy 4K erase instruction (default 0x20h) - // SFDP helpers - friend int mbed::sfdp_parse_headers(mbed::Callback sfdp_reader, - mbed::sfdp_hdr_info &hdr_info); - - - // Up To 4 Erase Types are supported by SFDP (each with its own command Instruction and Size) - int _erase_type_inst_arr[MAX_NUM_OF_ERASE_TYPES]; - unsigned int _erase_type_size_arr[MAX_NUM_OF_ERASE_TYPES]; - - // Sector Regions Map - int _regions_count; //number of regions - int _region_size_bytes[SPIF_MAX_REGIONS]; //regions size in bytes - bd_size_t _region_high_boundary[SPIF_MAX_REGIONS]; //region high address offset boundary - //Each Region can support a bit combination of any of the 4 Erase Types - uint8_t _region_erase_types_bitfield[SPIF_MAX_REGIONS]; - unsigned int _min_common_erase_size; // minimal common erase size for all regions (0 if none exists) + // Data extracted from the devices SFDP structure + mbed::sfdp_hdr_info _sfdp_info; unsigned int _page_size_bytes; // Page size - 256 Bytes default bd_size_t _device_size_bytes; diff --git a/drivers/internal/SFDP.h b/drivers/internal/SFDP.h index 012b033a6f6..44d3ed0eb94 100644 --- a/drivers/internal/SFDP.h +++ b/drivers/internal/SFDP.h @@ -25,36 +25,72 @@ namespace mbed { -static const int SFDP_HEADER_SIZE = 8; ///< Size of an SFDP header */ -static const int SFDP_BASIC_PARAMS_TBL_SIZE = 80; ///< Basic Parameter Table size in Bytes, 20 DWORDS */ +/** \defgroup drivers-internal-api-sfdp SFDP + * \ingroup drivers-internal-api + * Serial Flash Discoverable Parameters. + * + * Based on JESD216D.01 Standard. + * @{ + */ + +static const int SFDP_HEADER_SIZE = 8; ///< Size of an SFDP header in bytes, 2 DWORDS +static const int SFDP_BASIC_PARAMS_TBL_SIZE = 80; ///< Basic Parameter Table size in bytes, 20 DWORDS +static const int SFDP_SECTOR_MAP_MAX_REGIONS = 10; ///< Maximum number of regions with different erase granularity + +// Erase Types Per Region BitMask +static const int SFDP_ERASE_BITMASK_TYPE4 = 0x08; ///< Erase type 4 (erase granularity) identifier +static const int SFDP_ERASE_BITMASK_TYPE3 = 0x04; ///< Erase type 3 (erase granularity) identifier +static const int SFDP_ERASE_BITMASK_TYPE2 = 0x02; ///< Erase type 2 (erase granularity) identifier +static const int SFDP_ERASE_BITMASK_TYPE1 = 0x01; ///< Erase type 1 (erase granularity) identifier +static const int SFDP_ERASE_BITMASK_NONE = 0x00; ///< Erase type None +static const int SFDP_ERASE_BITMASK_ALL = 0x0F; ///< Erase type All + +static const int SFDP_MAX_NUM_OF_ERASE_TYPES = 4; ///< Maximum number of different erase types (erase granularity) + +/** SFDP Basic Parameter Table info */ +struct sfdp_bptbl_info { + uint32_t addr; ///< Address + size_t size; ///< Size +}; + +/** SFDP Sector Map Table info */ +struct sfdp_smptbl_info { + uint32_t addr; ///< Address + size_t size; ///< Size + int region_cnt; ///< Number of erase regions + int region_size[SFDP_SECTOR_MAP_MAX_REGIONS]; ///< Erase region size in bytes + uint8_t region_erase_types_bitfld[SFDP_SECTOR_MAP_MAX_REGIONS]; ///< Each Region can support a bit combination of any of the 4 Erase Types + unsigned int regions_min_common_erase_size; ///< Minimal common erase size for all regions (0 if none exists) + bd_size_t region_high_boundary[SFDP_SECTOR_MAP_MAX_REGIONS]; ///< Region high address offset boundary + int erase_type_inst_arr[SFDP_MAX_NUM_OF_ERASE_TYPES]; ///< // Up To 4 Erase Types are supported by SFDP (each with its own command Instruction and Size) + unsigned int erase_type_size_arr[SFDP_MAX_NUM_OF_ERASE_TYPES]; ///< Erase sizes for all different erase types +}; /** SFDP Parameter Table addresses and sizes */ struct sfdp_hdr_info { - uint32_t basic_table_addr; // Basic Parameter Table address - size_t basic_table_size; // Basic Parameter Table size - uint32_t sector_map_table_addr; // Sector Map Parameter Table address - size_t sector_map_table_size; // Sector Map Parameter Table size + sfdp_bptbl_info bptbl; + sfdp_smptbl_info smptbl; }; /** SFDP Header */ struct sfdp_hdr { - uint8_t SIG_B0; // SFDP Signature, Byte 0 - uint8_t SIG_B1; // SFDP Signature, Byte 1 - uint8_t SIG_B2; // SFDP Signature, Byte 2 - uint8_t SIG_B3; // SFDP Signature, Byte 3 - uint8_t R_MINOR; // SFDP Minor Revision - uint8_t R_MAJOR; // SFDP Major Revision - uint8_t NPH; // Number of parameter headers (0-based, 0 indicates 1 parameter header) - uint8_t ACP; // SFDP Access Protocol + uint8_t SIG_B0; ///< SFDP Signature, Byte 0 + uint8_t SIG_B1; ///< SFDP Signature, Byte 1 + uint8_t SIG_B2; ///< SFDP Signature, Byte 2 + uint8_t SIG_B3; ///< SFDP Signature, Byte 3 + uint8_t R_MINOR; ///< SFDP Minor Revision + uint8_t R_MAJOR; ///< SFDP Major Revision + uint8_t NPH; ///< Number of parameter headers (0-based, 0 indicates 1 parameter header) + uint8_t ACP; ///< SFDP Access Protocol }; /** SFDP Parameter header */ struct sfdp_prm_hdr { - uint8_t PID_LSB; // Parameter ID LSB - uint8_t P_MINOR; // Parameter Minor Revision - uint8_t P_MAJOR; // Parameter Major Revision - uint8_t P_LEN; // Parameter length in DWORDS - uint32_t DWORD2; // Parameter ID MSB + Parameter Table Pointer + uint8_t PID_LSB; ///< Parameter ID LSB + uint8_t P_MINOR; ///< Parameter Minor Revision + uint8_t P_MAJOR; ///< Parameter Major Revision + uint8_t P_LEN; ///< Parameter length in DWORDS + uint32_t DWORD2; ///< Parameter ID MSB + Parameter Table Pointer }; /** Parse SFDP Header @@ -80,5 +116,16 @@ int sfdp_parse_single_param_header(sfdp_prm_hdr *parameter_header, sfdp_hdr_info */ int sfdp_parse_headers(Callback sfdp_reader, sfdp_hdr_info &hdr_info); +/** Parse Sector Map Parameter Table + * Retrieves the table from a device and parses the information contained by the table + * + * @param sfdp_reader Callback function used to read headers from a device + * @param smtbl All information parsed from the table gets passed back on this structure + * + * @return 0 on success, negative error code on failure + */ +int sfdp_parse_sector_map_table(Callback sfdp_reader, sfdp_smptbl_info &smtbl); + +/** @}*/ } /* namespace mbed */ #endif diff --git a/drivers/source/SFDP.cpp b/drivers/source/SFDP.cpp index 28ef8955433..5f43192a8e7 100644 --- a/drivers/source/SFDP.cpp +++ b/drivers/source/SFDP.cpp @@ -67,13 +67,13 @@ int sfdp_parse_single_param_header(sfdp_prm_hdr *phdr, sfdp_hdr_info &hdr_info) if ((phdr->PID_LSB == 0) && (sfdp_get_param_id_msb(phdr->DWORD2) == 0xFF)) { tr_debug("Parameter Header: Basic Parameter Header"); - hdr_info.basic_table_addr = sfdp_get_param_tbl_ptr(phdr->DWORD2); - hdr_info.basic_table_size = std::min((phdr->P_LEN * 4), SFDP_BASIC_PARAMS_TBL_SIZE); + hdr_info.bptbl.addr = sfdp_get_param_tbl_ptr(phdr->DWORD2); + hdr_info.bptbl.size = std::min((phdr->P_LEN * 4), SFDP_BASIC_PARAMS_TBL_SIZE); } else if ((phdr->PID_LSB == 0x81) && (sfdp_get_param_id_msb(phdr->DWORD2) == 0xFF)) { tr_debug("Parameter Header: Sector Map Parameter Header"); - hdr_info.sector_map_table_addr = sfdp_get_param_tbl_ptr(phdr->DWORD2); - hdr_info.sector_map_table_size = phdr->P_LEN * 4; + hdr_info.smptbl.addr = sfdp_get_param_tbl_ptr(phdr->DWORD2); + hdr_info.smptbl.size = phdr->P_LEN * 4; } else { tr_debug("Parameter Header vendor specific or unknown. Parameter ID LSB: 0x%" PRIX8 "; MSB: 0x%" PRIX8 "", @@ -134,5 +134,63 @@ int sfdp_parse_headers(Callback sfdp_reader, return 0; } +int sfdp_parse_sector_map_table(Callback sfdp_reader, sfdp_smptbl_info &smptbl) +{ + uint8_t sector_map_table[SFDP_BASIC_PARAMS_TBL_SIZE]; /* Up To 20 DWORDS = 80 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 = SFDP_ERASE_BITMASK_ALL; + + int status = sfdp_reader(smptbl.addr, sector_map_table, smptbl.size); + if (status < 0) { + tr_error("table retrieval 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; + } + + smptbl.region_cnt = sector_map_table[2] + 1; + if (smptbl.region_cnt > SFDP_SECTOR_MAP_MAX_REGIONS) { + tr_error("Supporting up to %d regions, current setup to %d regions - fail", + SFDP_SECTOR_MAP_MAX_REGIONS, + smptbl.region_cnt); + 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 < smptbl.region_cnt; i_ind++) { + tmp_region_size = ((*((uint32_t *)§or_map_table[(i_ind + 1) * 4])) >> 8) & 0x00FFFFFF; // bits 9-32 + smptbl.region_size[i_ind] = (tmp_region_size + 1) * 256; // Region size is 0 based multiple of 256 bytes; + smptbl.region_erase_types_bitfld[i_ind] = sector_map_table[(i_ind + 1) * 4] & 0x0F; // bits 1-4 + min_common_erase_type_bits &= smptbl.region_erase_types_bitfld[i_ind]; + smptbl.region_high_boundary[i_ind] = (smptbl.region_size[i_ind] - 1) + prev_boundary; + prev_boundary = smptbl.region_high_boundary[i_ind] + 1; + } + + // Calc minimum Common Erase Size from min_common_erase_type_bits + uint8_t type_mask = SFDP_ERASE_BITMASK_TYPE1; + for (i_ind = 0; i_ind < 4; i_ind++) { + if (min_common_erase_type_bits & type_mask) { + smptbl.regions_min_common_erase_size = smptbl.erase_type_size_arr[i_ind]; + break; + } + type_mask = type_mask << 1; + } + + if (i_ind == 4) { + // No common erase type was found between regions + smptbl.regions_min_common_erase_size = 0; + } + + return 0; +} + } /* namespace mbed */ #endif /* (DEVICE_SPI || DEVICE_QSPI) */ diff --git a/tools/test_configs/SPIFBlockDeviceAndHeapBlockDevice.json b/tools/test_configs/SPIFBlockDeviceAndHeapBlockDevice.json index 05be4d17ff8..e03c15084ab 100644 --- a/tools/test_configs/SPIFBlockDeviceAndHeapBlockDevice.json +++ b/tools/test_configs/SPIFBlockDeviceAndHeapBlockDevice.json @@ -17,7 +17,7 @@ } }, "target_overrides": { - "NRF52840_DK": { + "*": { "target.components_remove": ["QSPI", "QSPIF"], "target.components_add" : ["SPI", "SPIF"] }