Merge pull request #12426 from VeijoPesonen/sfdp_split_bptbl

SFDP: consolidation of SFDP parsing [2/n]
pull/12450/head
Martin Kojtal 2020-02-25 13:57:23 +00:00 committed by GitHub
commit 1c12083949
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 210 additions and 285 deletions

View File

@ -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<int(bd_addr_t, void *, bd_size_t)> 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)
{

View File

@ -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<int(mbed::bd_addr_t, void *, mbed::bd_size_t)> 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;

View File

@ -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<PlatformMutex> 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<int(bd_addr_t, void *, bd_size_t)> 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;
}

View File

@ -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<int(mbed::bd_addr_t, void *, mbed::bd_size_t)> 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;

View File

@ -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<int(bd_addr_t, void *, bd_size_t)> sfdp_reader,
*/
int sfdp_parse_sector_map_table(Callback<int(bd_addr_t, void *, bd_size_t)> 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

View File

@ -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<int(bd_addr_t, void *, bd_size_t)> 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<int(bd_addr_t, void *, bd_size_t)> 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<int(bd_addr_t, void *, bd_size_t)> 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<int(bd_addr_t, void *, bd_size_t)> 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) */