diff --git a/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.cpp b/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.cpp index 74e57f9a9d..a7e1ae62af 100644 --- a/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.cpp +++ b/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.cpp @@ -32,7 +32,6 @@ using namespace mbed; /* Default QSPIF Parameters */ /****************************/ -#define QSPIF_DEFAULT_PAGE_SIZE 256 #define QSPIF_DEFAULT_SE_SIZE 4096 // The SFDP spec only defines two status registers. But some devices, // have three "status-like" registers (one status, two config) @@ -63,20 +62,9 @@ using namespace mbed; #define QSPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE 23 #define QSPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE 15 #define QSPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE 13 -#define QSPIF_BASIC_PARAM_TABLE_PAGE_SIZE_BYTE 40 // Quad Enable Params #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_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 @@ -112,7 +100,7 @@ using namespace mbed; // Default read/legacy erase instructions #define QSPIF_INST_READ_DEFAULT 0x03 -#define QSPIF_INST_LEGACY_ERASE_DEFAULT QSPI_NO_INST +#define QSPIF_INST_LEGACY_ERASE_DEFAULT (-1) // Default status register 2 read/write instructions #define QSPIF_INST_WSR2_DEFAULT QSPI_NO_INST @@ -153,6 +141,7 @@ QSPIFBlockDevice::QSPIFBlockDevice(PinName io0, PinName io1, PinName io2, PinNam } // Initialize parameters + _sfdp_info.bptbl.legacy_erase_instruction = QSPIF_INST_LEGACY_ERASE_DEFAULT; _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; @@ -172,7 +161,6 @@ QSPIFBlockDevice::QSPIFBlockDevice(PinName io0, PinName io1, PinName io2, PinNam // 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 @@ -253,7 +241,8 @@ int QSPIFBlockDevice::init() } /**************************** Parse Basic Parameters Table ***********************************/ - if (0 != _sfdp_parse_basic_param_table(_sfdp_info.bptbl.addr, _sfdp_info.bptbl.size)) { + if (_sfdp_parse_basic_param_table(callback(this, &QSPIFBlockDevice::_qspi_send_read_sfdp_command), + _sfdp_info) < 0) { tr_error("Init - Parse Basic Param Table Failed"); status = QSPIF_BD_ERROR_PARSING_FAILED; goto exit_point; @@ -429,7 +418,7 @@ 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) { unsigned int eu_size; - if (_legacy_erase_instruction == QSPI_NO_INST) { + if (_sfdp_info.bptbl.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, @@ -439,7 +428,7 @@ int QSPIFBlockDevice::erase(bd_addr_t addr, bd_size_t in_size) eu_size = _sfdp_info.smptbl.erase_type_size_arr[type]; } else { // Must use legacy 4k erase instruction - cur_erase_inst = _legacy_erase_instruction; + cur_erase_inst = _sfdp_info.bptbl.legacy_erase_instruction; eu_size = QSPIF_DEFAULT_SE_SIZE; } offset = addr % eu_size; @@ -520,7 +509,7 @@ const char *QSPIFBlockDevice::get_type() const 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) { + if (_sfdp_info.bptbl.legacy_erase_instruction != QSPI_NO_INST) { return QSPIF_DEFAULT_SE_SIZE; } @@ -627,11 +616,12 @@ int QSPIFBlockDevice::remove_csel_instance(PinName csel) /*********************************************************/ /********** SFDP Parsing and Detection Functions *********/ /*********************************************************/ -int QSPIFBlockDevice::_sfdp_parse_basic_param_table(uint32_t basic_table_addr, size_t basic_table_size) +int QSPIFBlockDevice::_sfdp_parse_basic_param_table(Callback sfdp_reader, + sfdp_hdr_info &sfdp_info) { - uint8_t param_table[SFDP_BASIC_PARAMS_TBL_SIZE]; /* Up To 16 DWORDS = 64 Bytes */ + uint8_t param_table[SFDP_BASIC_PARAMS_TBL_SIZE]; /* Up To 20 DWORDS = 80 Bytes */ - int status = _qspi_send_read_sfdp_command(basic_table_addr, (char *)param_table, basic_table_size); + int status = sfdp_reader(sfdp_info.bptbl.addr, param_table, sfdp_info.bptbl.size); if (status != QSPI_STATUS_OK) { tr_error("Init - Read SFDP First Table Failed"); return -1; @@ -651,7 +641,7 @@ int QSPIFBlockDevice::_sfdp_parse_basic_param_table(uint32_t basic_table_addr, s _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); + _page_size_bytes = sfdp_detect_page_size(param_table, sfdp_info.bptbl.size); if (_sfdp_detect_reset_protocol_and_reset(param_table) != QSPIF_BD_ERROR_OK) { tr_error("Init - Detecting reset protocol/resetting failed"); @@ -662,13 +652,13 @@ 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, _sfdp_info.smptbl) != 0) { + if (sfdp_detect_erase_types_inst_and_size(param_table, _sfdp_info) < 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); + _sfdp_detect_best_bus_read_mode(param_table, sfdp_info.bptbl.size, shouldSetQuadEnable, is_qpi_mode); if (true == shouldSetQuadEnable) { if (_needs_fast_mode) { _enable_fast_mode(); @@ -688,7 +678,7 @@ int QSPIFBlockDevice::_sfdp_parse_basic_param_table(uint32_t basic_table_addr, s #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) { + if (_sfdp_detect_and_enable_4byte_addressing(param_table, sfdp_info.bptbl.size) != QSPIF_BD_ERROR_OK) { tr_error("Init - Detecting/enabling 4-byte addressing failed"); return -1; } @@ -831,67 +821,6 @@ int QSPIFBlockDevice::_sfdp_set_qpi_enabled(uint8_t *basic_param_table_ptr) 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; - - 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 = 1 << page_to_power_size; - tr_debug("Detected Page Size: %d", page_size); - } else { - tr_debug("Using Default Page Size: %d", page_size); - } - return page_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; - - // Erase 4K Inst is taken either from param table legacy 4K erase or superseded by erase Instruction for type of size 4K - 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++) { - 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 - smptbl.erase_type_inst_arr[i_ind] = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_ERASE_TYPE_1_BYTE - + 2 * i_ind]; - - 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 - smptbl.regions_min_common_erase_size = smptbl.erase_type_size_arr[i_ind]; - } - 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), smptbl.erase_type_inst_arr[i_ind], - smptbl.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; - } - } - - 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) { diff --git a/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.h b/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.h index d2afbe9e7e..aa0ff64623 100644 --- a/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.h +++ b/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.h @@ -318,7 +318,8 @@ private: /* SFDP Detection and Parsing Functions */ /****************************************/ // Parse and Detect required Basic Parameters from Table - int _sfdp_parse_basic_param_table(uint32_t basic_table_addr, size_t basic_table_size); + int _sfdp_parse_basic_param_table(mbed::Callback sfdp_reader, + mbed::sfdp_hdr_info &sfdp_info); // 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); @@ -336,11 +337,6 @@ private: // 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::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); @@ -386,7 +382,6 @@ private: // Command Instructions mbed::qspi_inst_t _read_instruction; - mbed::qspi_inst_t _legacy_erase_instruction; // Status register write/read instructions unsigned int _num_status_registers; diff --git a/components/storage/blockdevice/COMPONENT_SPIF/SPIFBlockDevice.cpp b/components/storage/blockdevice/COMPONENT_SPIF/SPIFBlockDevice.cpp index 68a87d9923..da65642fee 100644 --- a/components/storage/blockdevice/COMPONENT_SPIF/SPIFBlockDevice.cpp +++ b/components/storage/blockdevice/COMPONENT_SPIF/SPIFBlockDevice.cpp @@ -31,7 +31,6 @@ using namespace mbed; /****************************/ #define SPIF_DEFAULT_READ_SIZE 1 #define SPIF_DEFAULT_PROG_SIZE 1 -#define SPIF_DEFAULT_PAGE_SIZE 256 #define SPIF_DEFAULT_SE_SIZE 4096 #define SPI_MAX_STATUS_REGISTER_SIZE 2 #ifndef UINT64_MAX @@ -44,27 +43,20 @@ 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 SPIF_BASIC_PARAM_TABLE_FAST_READ_SUPPORT_BYTE 2 #define SPIF_BASIC_PARAM_TABLE_QPI_READ_SUPPORT_BYTE 16 #define SPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE 23 #define SPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE 15 #define SPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE 13 -#define SPIF_BASIC_PARAM_TABLE_PAGE_SIZE_BYTE 40 // Address Length #define SPIF_ADDR_SIZE_3_BYTES 3 #define SPIF_ADDR_SIZE_4_BYTES 4 -// Erase Types Params -#define SPIF_BASIC_PARAM_ERASE_TYPE_1_BYTE 29 -#define SPIF_BASIC_PARAM_ERASE_TYPE_2_BYTE 31 -#define SPIF_BASIC_PARAM_ERASE_TYPE_3_BYTE 33 -#define SPIF_BASIC_PARAM_ERASE_TYPE_4_BYTE 35 -#define SPIF_BASIC_PARAM_ERASE_TYPE_1_SIZE_BYTE 28 -#define SPIF_BASIC_PARAM_ERASE_TYPE_2_SIZE_BYTE 30 -#define SPIF_BASIC_PARAM_ERASE_TYPE_3_SIZE_BYTE 32 -#define SPIF_BASIC_PARAM_ERASE_TYPE_4_SIZE_BYTE 34 -#define SPIF_BASIC_PARAM_4K_ERASE_TYPE_BYTE 1 + +// Default read/legacy erase instructions +#define SPIF_INST_READ_DEFAULT 0x03 +#define SPIF_INST_LEGACY_ERASE_DEFAULT (-1) + #define IS_MEM_READY_MAX_RETRIES 10000 @@ -90,16 +82,15 @@ enum spif_default_instructions { // e.g. (1)Set Write Enable, (2)Program, (3)Wait Memory Ready SingletonPtr SPIFBlockDevice::_mutex; -// Local Function -static unsigned int local_math_power(int base, int exp); - //*********************** // SPIF Block Device APIs //*********************** SPIFBlockDevice::SPIFBlockDevice( PinName mosi, PinName miso, PinName sclk, PinName csel, int freq) - : _spi(mosi, miso, sclk), _cs(csel), _read_instruction(0), _prog_instruction(0), _erase_instruction(0), - _erase4k_inst(0), _page_size_bytes(0), _device_size_bytes(0), _init_ref_count(0), _is_initialized(false) + : + _spi(mosi, miso, sclk), _cs(csel), _prog_instruction(0), _erase_instruction(0), + _page_size_bytes(0), + _device_size_bytes(0), _init_ref_count(0), _is_initialized(false) { _address_size = SPIF_ADDR_SIZE_3_BYTES; // Initial SFDP read tables are read with 8 dummy cycles @@ -108,10 +99,14 @@ SPIFBlockDevice::SPIFBlockDevice( _write_dummy_and_mode_cycles = 0; _dummy_and_mode_cycles = _read_dummy_and_mode_cycles; + _sfdp_info.bptbl.legacy_erase_instruction = SPIF_INST_LEGACY_ERASE_DEFAULT; _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; + // Set default read/erase instructions + _read_instruction = SPIF_INST_READ_DEFAULT; + if (SPIF_BD_ERROR_OK != _spi_set_frequency(freq)) { tr_error("SPI Set Frequency Failed"); } @@ -124,10 +119,12 @@ int SPIFBlockDevice::init() uint8_t vendor_device_ids[4]; size_t data_length = 3; int status = SPIF_BD_ERROR_OK; - struct sfdp_hdr_info hdr_info; spif_bd_error spi_status = SPIF_BD_ERROR_OK; - 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(); @@ -176,7 +173,7 @@ int SPIFBlockDevice::init() } /**************************** Parse SFDP Header ***********************************/ - if (0 != sfdp_parse_headers(callback(this, &SPIFBlockDevice::_spi_send_read_sfdp_command), hdr_info)) { + if (sfdp_parse_headers(callback(this, &SPIFBlockDevice::_spi_send_read_sfdp_command), _sfdp_info) < 0) { tr_error("init - Parse SFDP Headers Failed"); status = SPIF_BD_ERROR_PARSING_FAILED; goto exit_point; @@ -184,7 +181,7 @@ int SPIFBlockDevice::init() /**************************** Parse Basic Parameters Table ***********************************/ - if (0 != _sfdp_parse_basic_param_table(hdr_info.bptbl.addr, hdr_info.bptbl.size)) { + if (_sfdp_parse_basic_param_table(callback(this, &SPIFBlockDevice::_spi_send_read_sfdp_command), _sfdp_info) < 0) { tr_error("init - Parse Basic Param Table Failed"); status = SPIF_BD_ERROR_PARSING_FAILED; goto exit_point; @@ -195,9 +192,9 @@ int SPIFBlockDevice::init() _device_size_bytes; // If there's no region map, we have a single region sized the entire device size _sfdp_info.smptbl.region_high_boundary[0] = _device_size_bytes - 1; - 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_info.smptbl.addr != 0) && (0 != _sfdp_info.smptbl.size)) { + tr_debug("init - Parsing Sector Map Table - addr: 0x%" PRIx32 "h, Size: %d", _sfdp_info.smptbl.addr, + _sfdp_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"); @@ -621,13 +618,12 @@ spif_bd_error SPIFBlockDevice::_spi_send_general_command(int instruction, bd_add /*********************************************************/ /********** SFDP Parsing and Detection Functions *********/ /*********************************************************/ -int SPIFBlockDevice::_sfdp_parse_basic_param_table(uint32_t basic_table_addr, size_t basic_table_size) +int SPIFBlockDevice::_sfdp_parse_basic_param_table(Callback sfdp_reader, + mbed::sfdp_hdr_info &sfdp_info) { - uint8_t param_table[SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES]; /* Up To 16 DWORDS = 64 Bytes */ - //memset(param_table, 0, SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES); + uint8_t param_table[SFDP_BASIC_PARAMS_TBL_SIZE]; /* Up To 20 DWORDS = 80 Bytes */ - spif_bd_error status = _spi_send_read_command(SPIF_SFDP, param_table, basic_table_addr /*address*/, - basic_table_size); + int status = sfdp_reader(sfdp_info.bptbl.addr, param_table, sfdp_info.bptbl.size); if (status != SPIF_BD_ERROR_OK) { tr_error("init - Read SFDP First Table Failed"); return -1; @@ -654,87 +650,22 @@ int SPIFBlockDevice::_sfdp_parse_basic_param_table(uint32_t basic_table_addr, si _erase_instruction = SPIF_SE; // Set Page Size (SPI write must be done on Page limits) - _page_size_bytes = _sfdp_detect_page_size(param_table, basic_table_size); + _page_size_bytes = sfdp_detect_page_size(param_table, sfdp_info.bptbl.size); // Detect and Set Erase Types - _sfdp_detect_erase_types_inst_and_size(param_table, basic_table_size, _erase4k_inst, _sfdp_info.smptbl); - _erase_instruction = _erase4k_inst; + if (sfdp_detect_erase_types_inst_and_size(param_table, sfdp_info) < 0) { + tr_error("Init - Detecting erase types instructions/sizes failed"); + return -1; + } + + _erase_instruction = sfdp_info.bptbl.legacy_erase_instruction; // Detect and Set fastest Bus mode (default 1-1-1) - _sfdp_detect_best_bus_read_mode(param_table, basic_table_size, _read_instruction); + _sfdp_detect_best_bus_read_mode(param_table, sfdp_info.bptbl.size, _read_instruction); return 0; } -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; - - if (basic_param_table_size > SPIF_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[SPIF_BASIC_PARAM_TABLE_PAGE_SIZE_BYTE]) >> 4; - page_size = local_math_power(2, page_to_power_size); - tr_debug("Detected Page Size: %d", page_size); - } else { - tr_debug("Using Default Page Size: %d", page_size); - } - return page_size; -} - -int SPIFBlockDevice::_sfdp_detect_erase_types_inst_and_size(uint8_t *basic_param_table_ptr, int basic_param_table_size, - int &erase4k_inst, - sfdp_smptbl_info &smptbl) -{ - 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[SPIF_BASIC_PARAM_4K_ERASE_TYPE_BYTE]; - - 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++) { - 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 - smptbl.erase_type_inst_arr[i_ind] = - basic_param_table_ptr[SPIF_BASIC_PARAM_ERASE_TYPE_1_BYTE + 2 * i_ind]; - - 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 - 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 (smptbl.erase_type_size_arr[i_ind] == 4096) { - found_4Kerase_type = true; - 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 = smptbl.erase_type_inst_arr[i_ind]; - tr_warning("_detectEraseTypesInstAndSize - Default 4K erase Inst is different than erase type Inst for 4K"); - - } - } - 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), - smptbl.erase_type_inst_arr[i_ind], smptbl.erase_type_size_arr[i_ind]); - bitfield = bitfield << 1; - } - } - - if (false == found_4Kerase_type) { - tr_warning("Couldn't find Erase Type for 4KB size"); - } - return 0; -} - int SPIFBlockDevice::_sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table_ptr, int basic_param_table_size, int &read_inst) { @@ -904,18 +835,3 @@ int SPIFBlockDevice::_utils_iterate_next_largest_erase_type(uint8_t &bitfield, return largest_erase_type; } -/*********************************************/ -/************** Local Functions **************/ -/*********************************************/ -static unsigned 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--; - } - return result; -} - - diff --git a/components/storage/blockdevice/COMPONENT_SPIF/SPIFBlockDevice.h b/components/storage/blockdevice/COMPONENT_SPIF/SPIFBlockDevice.h index 3d3baf37b3..8ea0bab8ed 100644 --- a/components/storage/blockdevice/COMPONENT_SPIF/SPIFBlockDevice.h +++ b/components/storage/blockdevice/COMPONENT_SPIF/SPIFBlockDevice.h @@ -231,7 +231,8 @@ private: int _spi_send_read_sfdp_command(mbed::bd_addr_t addr, void *rx_buffer, mbed::bd_size_t rx_length); // Parse and Detect required Basic Parameters from Table - int _sfdp_parse_basic_param_table(uint32_t basic_table_addr, size_t basic_table_size); + int _sfdp_parse_basic_param_table(mbed::Callback sfdp_reader, + mbed::sfdp_hdr_info &hdr_info); // 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); @@ -239,11 +240,6 @@ private: // Set Page size for program unsigned 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 &erase4k_inst, - mbed::sfdp_smptbl_info &smptbl); - /***********************/ /* Utilities Functions */ /***********************/ @@ -302,7 +298,6 @@ private: int _read_instruction; int _prog_instruction; int _erase_instruction; - int _erase4k_inst; // Legacy 4K erase instruction (default 0x20h) // Data extracted from the devices SFDP structure mbed::sfdp_hdr_info _sfdp_info; diff --git a/drivers/internal/SFDP.h b/drivers/internal/SFDP.h index 44d3ed0eb9..9db4841573 100644 --- a/drivers/internal/SFDP.h +++ b/drivers/internal/SFDP.h @@ -33,24 +33,25 @@ namespace mbed { * @{ */ -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 +constexpr int SFDP_HEADER_SIZE = 8; ///< Size of an SFDP header in bytes, 2 DWORDS +constexpr int SFDP_BASIC_PARAMS_TBL_SIZE = 80; ///< Basic Parameter Table size in bytes, 20 DWORDS +constexpr 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 +constexpr int SFDP_ERASE_BITMASK_TYPE4 = 0x08; ///< Erase type 4 (erase granularity) identifier +constexpr int SFDP_ERASE_BITMASK_TYPE3 = 0x04; ///< Erase type 3 (erase granularity) identifier +constexpr int SFDP_ERASE_BITMASK_TYPE2 = 0x02; ///< Erase type 2 (erase granularity) identifier +constexpr int SFDP_ERASE_BITMASK_TYPE1 = 0x01; ///< Erase type 1 (erase granularity) identifier +constexpr int SFDP_ERASE_BITMASK_NONE = 0x00; ///< Erase type None +constexpr 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) +constexpr 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 + int legacy_erase_instruction; ///< Legacy 4K erase instruction }; /** SFDP Sector Map Table info */ @@ -72,40 +73,6 @@ struct sfdp_hdr_info { 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 -}; - -/** 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 -}; - -/** Parse SFDP Header - * @param sfdp_hdr_ptr Pointer to memory holding an SFDP header - * @return Number of Parameter Headers on success, -1 on failure - */ -int sfdp_parse_sfdp_header(sfdp_hdr *sfdp_hdr_ptr); - -/** Parse Parameter Header - * @param parameter_header Pointer to memory holding a single SFDP Parameter header - * @param hdr_info Reference to a Parameter Table structure where info about the table is written - * @return 0 on success, -1 on failure - */ -int sfdp_parse_single_param_header(sfdp_prm_hdr *parameter_header, sfdp_hdr_info &hdr_info); - /** Parse SFDP Headers * Retrieves SFDP headers from a device and parses the information contained by the headers * @@ -126,6 +93,24 @@ int sfdp_parse_headers(Callback sfdp_reader, */ int sfdp_parse_sector_map_table(Callback sfdp_reader, sfdp_smptbl_info &smtbl); +/** Detect page size used for writing on flash + * + * @param bptbl_ptr Pointer to memory holding a Basic Parameter Table structure + * @param bptbl_size Size of memory holding a Basic Parameter Table + * + * @return Page size + */ +size_t sfdp_detect_page_size(uint8_t *bptbl_ptr, size_t bptbl_size); + +/** Detect all supported erase types + * + * @param bptbl_ptr Pointer to memory holding a Basic Parameter Table structure + * @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_detect_erase_types_inst_and_size(uint8_t *bptbl_ptr, sfdp_hdr_info &sfdp_info); + /** @}*/ } /* namespace mbed */ #endif diff --git a/drivers/source/SFDP.cpp b/drivers/source/SFDP.cpp index 5f43192a8e..99ca5ba3f5 100644 --- a/drivers/source/SFDP.cpp +++ b/drivers/source/SFDP.cpp @@ -42,43 +42,85 @@ inline uint32_t sfdp_get_param_tbl_ptr(uint32_t dword2) namespace mbed { -/* Verifies SFDP Header and return number of parameter headers */ +// Erase Types Params +constexpr int SFDP_BASIC_PARAM_TABLE_ERASE_TYPE_1_BYTE = 29; ///< Erase Type 1 Instruction +constexpr int SFDP_BASIC_PARAM_TABLE_ERASE_TYPE_2_BYTE = 31; ///< Erase Type 2 Instruction +constexpr int SFDP_BASIC_PARAM_TABLE_ERASE_TYPE_3_BYTE = 33; ///< Erase Type 3 Instruction +constexpr int SFDP_BASIC_PARAM_TABLE_ERASE_TYPE_4_BYTE = 35; ///< Erase Type 4 Instruction +constexpr int SFDP_BASIC_PARAM_TABLE_ERASE_TYPE_1_SIZE_BYTE = 28; ///< Erase Type 1 Size +constexpr int SFDP_BASIC_PARAM_TABLE_ERASE_TYPE_2_SIZE_BYTE = 30; ///< Erase Type 2 Size +constexpr int SFDP_BASIC_PARAM_TABLE_ERASE_TYPE_3_SIZE_BYTE = 32; ///< Erase Type 3 Size +constexpr int SFDP_BASIC_PARAM_TABLE_ERASE_TYPE_4_SIZE_BYTE = 34; ///< Erase Type 4 Size +constexpr int SFDP_BASIC_PARAM_TABLE_4K_ERASE_TYPE_BYTE = 1; ///< 4 Kilobyte Erase Instruction + +constexpr int SFDP_ERASE_BITMASK_TYPE_4K_ERASE_UNSUPPORTED = 0xFF; + +/** 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 +}; + +/** 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 +}; + +/** Parse SFDP Header + * @param sfdp_hdr_ptr Pointer to memory holding an SFDP header + * @return Number of Parameter Headers on success, -1 on failure + */ int sfdp_parse_sfdp_header(sfdp_hdr *sfdp_hdr_ptr) { if (!(memcmp(sfdp_hdr_ptr, "SFDP", 4) == 0 && sfdp_hdr_ptr->R_MAJOR == 1)) { - tr_error("verify SFDP signature and version Failed"); + tr_error("Verify SFDP signature and version Failed"); return -1; } - tr_debug("init - verified SFDP Signature and version Successfully"); + tr_debug("Verified SFDP Signature and version successfully"); int hdr_cnt = sfdp_hdr_ptr->NPH + 1; - tr_debug("number of Param Headers: %d", hdr_cnt); + tr_debug("Number of parameter headers: %d", hdr_cnt); return hdr_cnt; } -int sfdp_parse_single_param_header(sfdp_prm_hdr *phdr, sfdp_hdr_info &hdr_info) +/** Parse Parameter Header + * @param phdr_ptr Pointer to memory holding a single SFDP Parameter header + * @param hdr_info Reference to a Parameter Table structure where info about the table is written + * @return 0 on success, -1 on failure + */ +int sfdp_parse_single_param_header(sfdp_prm_hdr *phdr_ptr, sfdp_hdr_info &hdr_info) { - if (phdr->P_MAJOR != 1) { - tr_error("Param Header: - Major Version should be 1!"); + if (phdr_ptr->P_MAJOR != 1) { + tr_error("Parameter header: Major Version must be 1!"); return -1; } - if ((phdr->PID_LSB == 0) && (sfdp_get_param_id_msb(phdr->DWORD2) == 0xFF)) { - tr_debug("Parameter Header: Basic Parameter Header"); - 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); + if ((phdr_ptr->PID_LSB == 0) && (sfdp_get_param_id_msb(phdr_ptr->DWORD2) == 0xFF)) { + tr_debug("Parameter header: Basic Parameter Header"); + hdr_info.bptbl.addr = sfdp_get_param_tbl_ptr(phdr_ptr->DWORD2); + hdr_info.bptbl.size = std::min((phdr_ptr->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.smptbl.addr = sfdp_get_param_tbl_ptr(phdr->DWORD2); - hdr_info.smptbl.size = phdr->P_LEN * 4; + } else if ((phdr_ptr->PID_LSB == 0x81) && (sfdp_get_param_id_msb(phdr_ptr->DWORD2) == 0xFF)) { + tr_debug("Parameter header: Sector Map Parameter Header"); + hdr_info.smptbl.addr = sfdp_get_param_tbl_ptr(phdr_ptr->DWORD2); + hdr_info.smptbl.size = phdr_ptr->P_LEN * 4; } else { - tr_debug("Parameter Header vendor specific or unknown. Parameter ID LSB: 0x%" PRIX8 "; MSB: 0x%" PRIX8 "", - phdr->PID_LSB, - sfdp_get_param_id_msb(phdr->DWORD2)); + tr_debug("Parameter header: header vendor specific or unknown. Parameter ID LSB: 0x%" PRIX8 "; MSB: 0x%" PRIX8 "", + phdr_ptr->PID_LSB, + sfdp_get_param_id_msb(phdr_ptr->DWORD2)); } return 0; @@ -96,7 +138,7 @@ int sfdp_parse_headers(Callback sfdp_reader, int status = sfdp_reader(addr, sfdp_header, data_length); if (status < 0) { - tr_error("retrieving SFDP Header failed"); + tr_error("Retrieving SFDP Header failed"); return -1; } @@ -118,7 +160,7 @@ int sfdp_parse_headers(Callback sfdp_reader, for (int i_ind = 0; i_ind < number_of_param_headers; i_ind++) { status = sfdp_reader(addr, param_header, data_length); if (status < 0) { - tr_error("retrieving Parameter Header %d failed", i_ind + 1); + tr_error("Retrieving a parameter header %d failed", i_ind + 1); return -1; } @@ -145,19 +187,19 @@ int sfdp_parse_sector_map_table(Callback sfdp int status = sfdp_reader(smptbl.addr, sector_map_table, smptbl.size); if (status < 0) { - tr_error("table retrieval failed"); + tr_error("Sector Map: 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)"); + 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", + tr_error("Sector Map: Supporting up to %d regions, current setup to %d regions - fail", SFDP_SECTOR_MAP_MAX_REGIONS, smptbl.region_cnt); return -1; @@ -192,5 +234,68 @@ int sfdp_parse_sector_map_table(Callback sfdp return 0; } +size_t sfdp_detect_page_size(uint8_t *basic_param_table_ptr, size_t basic_param_table_size) +{ + constexpr int SFDP_BASIC_PARAM_TABLE_PAGE_SIZE = 40; + constexpr int SFDP_DEFAULT_PAGE_SIZE = 256; + + unsigned int page_size = SFDP_DEFAULT_PAGE_SIZE; + + if (basic_param_table_size > SFDP_BASIC_PARAM_TABLE_PAGE_SIZE) { + // Page Size is specified by 4 Bits (N), calculated by 2^N + int page_to_power_size = ((int)basic_param_table_ptr[SFDP_BASIC_PARAM_TABLE_PAGE_SIZE]) >> 4; + 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); + } + return page_size; +} + +int sfdp_detect_erase_types_inst_and_size(uint8_t *bptbl_ptr, sfdp_hdr_info &sfdp_info) +{ + 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 + if (sfdp_info.bptbl.size > SFDP_BASIC_PARAM_TABLE_ERASE_TYPE_1_SIZE_BYTE) { + // Loop Erase Types 1-4 + for (int i_ind = 0; i_ind < 4; i_ind++) { + sfdp_info.smptbl.erase_type_inst_arr[i_ind] = -1; // Default for unsupported type + sfdp_info.smptbl.erase_type_size_arr[i_ind] = 1 + << bptbl_ptr[SFDP_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), sfdp_info.smptbl.erase_type_inst_arr[i_ind], + sfdp_info.smptbl.erase_type_size_arr[i_ind]); + if (sfdp_info.smptbl.erase_type_size_arr[i_ind] > 1) { + // if size==1 type is not supported + sfdp_info.smptbl.erase_type_inst_arr[i_ind] = bptbl_ptr[SFDP_BASIC_PARAM_TABLE_ERASE_TYPE_1_BYTE + + 2 * i_ind]; + + if ((sfdp_info.smptbl.erase_type_size_arr[i_ind] < sfdp_info.smptbl.regions_min_common_erase_size) + || (sfdp_info.smptbl.regions_min_common_erase_size == 0)) { + //Set default minimal common erase for signal region + sfdp_info.smptbl.regions_min_common_erase_size = sfdp_info.smptbl.erase_type_size_arr[i_ind]; + } + sfdp_info.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), sfdp_info.smptbl.erase_type_inst_arr[i_ind], + sfdp_info.smptbl.erase_type_size_arr[i_ind]); + bitfield = bitfield << 1; + } + } else { + tr_debug("Erase types are not available - falling back to legacy 4k erase instruction"); + + sfdp_info.bptbl.legacy_erase_instruction = bptbl_ptr[SFDP_BASIC_PARAM_TABLE_4K_ERASE_TYPE_BYTE]; + if (sfdp_info.bptbl.legacy_erase_instruction == SFDP_ERASE_BITMASK_TYPE_4K_ERASE_UNSUPPORTED) { + tr_error("Legacy 4k erase instruction not supported"); + return -1; + } + } + + return 0; +} + + + } /* namespace mbed */ #endif /* (DEVICE_SPI || DEVICE_QSPI) */