Merge pull request #12318 from VeijoPesonen/sfdp_split_smptbl

SFDP: Move Sector Map Parameter Table parsing under SFDP module
pull/12473/head
Martin Kojtal 2020-02-19 15:49:40 +00:00 committed by GitHub
commit 829a3cded3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 277 additions and 314 deletions

View File

@ -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 *)&sector_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;

View File

@ -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 @@ private:
/****************************************/
/* 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 @@ private:
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 @@ private:
/* 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 @@ private:
// 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 @@ private:
// 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;

View File

@ -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 *)&sector_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;
}
/*********************************************/

View File

@ -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 @@ private:
// Internal functions
// SFDP helpers
friend int mbed::sfdp_parse_headers(mbed::Callback<int(bd_addr_t, void *, bd_size_t)> 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 @@ private:
// 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 @@ private:
int _erase_instruction;
int _erase4k_inst; // Legacy 4K erase instruction (default 0x20h)
// SFDP helpers
friend int mbed::sfdp_parse_headers(mbed::Callback<int(bd_addr_t, void *, bd_size_t)> 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;

View File

@ -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 <a href="https://www.jedec.org/standards-documents/docs/jesd216b">JESD216D.01 Standard</a>.
* @{
*/
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<int(bd_addr_t, void *, bd_size_t)> 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<int(bd_addr_t, void *, bd_size_t)> sfdp_reader, sfdp_smptbl_info &smtbl);
/** @}*/
} /* namespace mbed */
#endif

View File

@ -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<int(bd_addr_t, void *, bd_size_t)> sfdp_reader,
return 0;
}
int sfdp_parse_sector_map_table(Callback<int(bd_addr_t, void *, bd_size_t)> 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 *)&sector_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) */

View File

@ -17,7 +17,7 @@
}
},
"target_overrides": {
"NRF52840_DK": {
"*": {
"target.components_remove": ["QSPI", "QSPIF"],
"target.components_add" : ["SPI", "SPIF"]
}