mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #12318 from VeijoPesonen/sfdp_split_smptbl
SFDP: Move Sector Map Parameter Table parsing under SFDP modulepull/12473/head
commit
829a3cded3
|
@ -53,7 +53,6 @@ using namespace mbed;
|
|||
|
||||
/* Basic Parameters Table Parsing */
|
||||
/**********************************/
|
||||
#define SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES 64 /* 16 DWORDS */
|
||||
//READ Instruction support according to BUS Configuration
|
||||
#define QSPIF_BASIC_PARAM_TABLE_FAST_READ_SUPPORT_BYTE 2
|
||||
#define QSPIF_BASIC_PARAM_TABLE_QPI_READ_SUPPORT_BYTE 16
|
||||
|
@ -84,11 +83,6 @@ using namespace mbed;
|
|||
#define SOFT_RESET_RESET_INST_BITMASK 0b001000
|
||||
#define SOFT_RESET_ENABLE_AND_RESET_INST_BITMASK 0b010000
|
||||
|
||||
// Erase Types Per Region BitMask
|
||||
#define ERASE_BITMASK_TYPE4 0x08
|
||||
#define ERASE_BITMASK_TYPE1 0x01
|
||||
#define ERASE_BITMASK_NONE 0x00
|
||||
#define ERASE_BITMASK_ALL 0x0F
|
||||
|
||||
// 4-Byte Addressing Support Bitmasks
|
||||
#define FOURBYTE_ADDR_B7_BITMASK 0b00000001
|
||||
|
@ -158,9 +152,9 @@ QSPIFBlockDevice::QSPIFBlockDevice(PinName io0, PinName io1, PinName io2, PinNam
|
|||
}
|
||||
|
||||
// Initialize parameters
|
||||
_min_common_erase_size = 0;
|
||||
_regions_count = 1;
|
||||
_region_erase_types_bitfield[0] = ERASE_BITMASK_NONE;
|
||||
_sfdp_info.smptbl.regions_min_common_erase_size = 0;
|
||||
_sfdp_info.smptbl.region_cnt = 1;
|
||||
_sfdp_info.smptbl.region_erase_types_bitfld[0] = SFDP_ERASE_BITMASK_NONE;
|
||||
|
||||
// Until proven otherwise, assume no quad enable
|
||||
_quad_enable_register_idx = QSPIF_NO_QUAD_ENABLE;
|
||||
|
@ -204,8 +198,10 @@ int QSPIFBlockDevice::init()
|
|||
}
|
||||
|
||||
int status = QSPIF_BD_ERROR_OK;
|
||||
sfdp_hdr_info hdr_info;
|
||||
memset(&hdr_info, 0, sizeof hdr_info);
|
||||
_sfdp_info.bptbl.addr = 0x0;
|
||||
_sfdp_info.bptbl.size = 0;
|
||||
_sfdp_info.smptbl.addr = 0x0;
|
||||
_sfdp_info.smptbl.size = 0;
|
||||
|
||||
_mutex.lock();
|
||||
|
||||
|
@ -249,28 +245,29 @@ int QSPIFBlockDevice::init()
|
|||
}
|
||||
|
||||
/**************************** Parse SFDP Header ***********************************/
|
||||
if (0 != _sfdp_parse_sfdp_headers(hdr_info)) {
|
||||
if (sfdp_parse_headers(callback(this, &QSPIFBlockDevice::_qspi_send_read_sfdp_command), _sfdp_info) < 0) {
|
||||
tr_error("Init - Parse SFDP Headers Failed");
|
||||
status = QSPIF_BD_ERROR_PARSING_FAILED;
|
||||
goto exit_point;
|
||||
}
|
||||
|
||||
/**************************** Parse Basic Parameters Table ***********************************/
|
||||
if (0 != _sfdp_parse_basic_param_table(hdr_info.basic_table_addr, hdr_info.basic_table_size)) {
|
||||
if (0 != _sfdp_parse_basic_param_table(_sfdp_info.bptbl.addr, _sfdp_info.bptbl.size)) {
|
||||
tr_error("Init - Parse Basic Param Table Failed");
|
||||
status = QSPIF_BD_ERROR_PARSING_FAILED;
|
||||
goto exit_point;
|
||||
}
|
||||
|
||||
/**************************** Parse Sector Map Table ***********************************/
|
||||
_region_size_bytes[0] =
|
||||
_sfdp_info.smptbl.region_size[0] =
|
||||
_device_size_bytes; // If there's no region map, we have a single region sized the entire device size
|
||||
_region_high_boundary[0] = _device_size_bytes - 1;
|
||||
_sfdp_info.smptbl.region_high_boundary[0] = _device_size_bytes - 1;
|
||||
|
||||
if ((hdr_info.sector_map_table_addr != 0) && (0 != hdr_info.sector_map_table_size)) {
|
||||
tr_debug("Init - Parsing Sector Map Table - addr: 0x%lxh, Size: %d", hdr_info.sector_map_table_addr,
|
||||
hdr_info.sector_map_table_size);
|
||||
if (0 != _sfdp_parse_sector_map_table(hdr_info.sector_map_table_addr, hdr_info.sector_map_table_size)) {
|
||||
if ((_sfdp_info.smptbl.addr != 0) && (0 != _sfdp_info.smptbl.size)) {
|
||||
tr_debug("Init - Parsing Sector Map Table - addr: 0x%lxh, Size: %d", _sfdp_info.smptbl.addr,
|
||||
_sfdp_info.smptbl.size);
|
||||
if (sfdp_parse_sector_map_table(callback(this, &QSPIFBlockDevice::_qspi_send_read_sfdp_command),
|
||||
_sfdp_info.smptbl) < 0) {
|
||||
tr_error("Init - Parse Sector Map Table Failed");
|
||||
status = QSPIF_BD_ERROR_PARSING_FAILED;
|
||||
goto exit_point;
|
||||
|
@ -412,9 +409,9 @@ int QSPIFBlockDevice::erase(bd_addr_t addr, bd_size_t in_size)
|
|||
bool erase_failed = false;
|
||||
int status = QSPIF_BD_ERROR_OK;
|
||||
// Find region of erased address
|
||||
int region = _utils_find_addr_region(addr);
|
||||
int region = _utils_find_addr_region(addr, _sfdp_info.smptbl);
|
||||
// Erase Types of selected region
|
||||
uint8_t bitfield = _region_erase_types_bitfield[region];
|
||||
uint8_t bitfield = _sfdp_info.smptbl.region_erase_types_bitfld[region];
|
||||
|
||||
tr_debug("Erase - addr: %llu, in_size: %llu", addr, in_size);
|
||||
|
||||
|
@ -434,9 +431,11 @@ int QSPIFBlockDevice::erase(bd_addr_t addr, bd_size_t in_size)
|
|||
if (_legacy_erase_instruction == QSPI_NO_INST) {
|
||||
// Iterate to find next largest erase type that is a) supported by region, and b) smaller than size.
|
||||
// Find the matching instruction and erase size chunk for that type.
|
||||
type = _utils_iterate_next_largest_erase_type(bitfield, size, (int)addr, _region_high_boundary[region]);
|
||||
cur_erase_inst = _erase_type_inst_arr[type];
|
||||
eu_size = _erase_type_size_arr[type];
|
||||
type = _utils_iterate_next_largest_erase_type(bitfield, size, (int)addr,
|
||||
region,
|
||||
_sfdp_info.smptbl);
|
||||
cur_erase_inst = _sfdp_info.smptbl.erase_type_inst_arr[type];
|
||||
eu_size = _sfdp_info.smptbl.erase_type_size_arr[type];
|
||||
} else {
|
||||
// Must use legacy 4k erase instruction
|
||||
cur_erase_inst = _legacy_erase_instruction;
|
||||
|
@ -469,10 +468,10 @@ int QSPIFBlockDevice::erase(bd_addr_t addr, bd_size_t in_size)
|
|||
addr += chunk;
|
||||
size -= chunk;
|
||||
|
||||
if ((size > 0) && (addr > _region_high_boundary[region])) {
|
||||
if ((size > 0) && (addr > _sfdp_info.smptbl.region_high_boundary[region])) {
|
||||
// erase crossed to next region
|
||||
region++;
|
||||
bitfield = _region_erase_types_bitfield[region];
|
||||
bitfield = _sfdp_info.smptbl.region_erase_types_bitfld[region];
|
||||
}
|
||||
|
||||
if (false == _is_mem_ready()) {
|
||||
|
@ -508,7 +507,7 @@ bd_size_t QSPIFBlockDevice::get_program_size() const
|
|||
bd_size_t QSPIFBlockDevice::get_erase_size() const
|
||||
{
|
||||
// return minimal erase size supported by all regions (0 if none exists)
|
||||
return _min_common_erase_size;
|
||||
return _sfdp_info.smptbl.regions_min_common_erase_size;
|
||||
}
|
||||
|
||||
const char *QSPIFBlockDevice::get_type() const
|
||||
|
@ -525,10 +524,10 @@ bd_size_t QSPIFBlockDevice::get_erase_size(bd_addr_t addr)
|
|||
}
|
||||
|
||||
// Find region of current address
|
||||
int region = _utils_find_addr_region(addr);
|
||||
int region = _utils_find_addr_region(addr, _sfdp_info.smptbl);
|
||||
|
||||
int min_region_erase_size = _min_common_erase_size;
|
||||
int8_t type_mask = ERASE_BITMASK_TYPE1;
|
||||
int min_region_erase_size = _sfdp_info.smptbl.regions_min_common_erase_size;
|
||||
int8_t type_mask = SFDP_ERASE_BITMASK_TYPE1;
|
||||
int i_ind = 0;
|
||||
|
||||
if (region != -1) {
|
||||
|
@ -536,9 +535,9 @@ bd_size_t QSPIFBlockDevice::get_erase_size(bd_addr_t addr)
|
|||
|
||||
for (i_ind = 0; i_ind < 4; i_ind++) {
|
||||
// loop through erase types bitfield supported by region
|
||||
if (_region_erase_types_bitfield[region] & type_mask) {
|
||||
if (_sfdp_info.smptbl.region_erase_types_bitfld[region] & type_mask) {
|
||||
|
||||
min_region_erase_size = _erase_type_size_arr[i_ind];
|
||||
min_region_erase_size = _sfdp_info.smptbl.erase_type_size_arr[i_ind];
|
||||
break;
|
||||
}
|
||||
type_mask = type_mask << 1;
|
||||
|
@ -627,14 +626,9 @@ int QSPIFBlockDevice::remove_csel_instance(PinName csel)
|
|||
/*********************************************************/
|
||||
/********** SFDP Parsing and Detection Functions *********/
|
||||
/*********************************************************/
|
||||
int QSPIFBlockDevice::_sfdp_parse_sfdp_headers(mbed::sfdp_hdr_info &hdr_info)
|
||||
{
|
||||
return sfdp_parse_headers(callback(this, &QSPIFBlockDevice::_qspi_send_read_sfdp_command), hdr_info);
|
||||
}
|
||||
|
||||
int QSPIFBlockDevice::_sfdp_parse_basic_param_table(uint32_t basic_table_addr, size_t basic_table_size)
|
||||
{
|
||||
uint8_t param_table[SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES]; /* Up To 16 DWORDS = 64 Bytes */
|
||||
uint8_t param_table[SFDP_BASIC_PARAMS_TBL_SIZE]; /* Up To 16 DWORDS = 64 Bytes */
|
||||
|
||||
int status = _qspi_send_read_sfdp_command(basic_table_addr, (char *)param_table, basic_table_size);
|
||||
if (status != QSPI_STATUS_OK) {
|
||||
|
@ -667,7 +661,7 @@ int QSPIFBlockDevice::_sfdp_parse_basic_param_table(uint32_t basic_table_addr, s
|
|||
bool shouldSetQuadEnable = false;
|
||||
bool is_qpi_mode = false;
|
||||
|
||||
if (_sfdp_detect_erase_types_inst_and_size(param_table, basic_table_size) != 0) {
|
||||
if (_sfdp_detect_erase_types_inst_and_size(param_table, basic_table_size, _sfdp_info.smptbl) != 0) {
|
||||
tr_error("Init - Detecting erase types instructions/sizes failed");
|
||||
return -1;
|
||||
}
|
||||
|
@ -851,7 +845,9 @@ int QSPIFBlockDevice::_sfdp_detect_page_size(uint8_t *basic_param_table_ptr, int
|
|||
return page_size;
|
||||
}
|
||||
|
||||
int QSPIFBlockDevice::_sfdp_detect_erase_types_inst_and_size(uint8_t *basic_param_table_ptr, int basic_param_table_size)
|
||||
int QSPIFBlockDevice::_sfdp_detect_erase_types_inst_and_size(uint8_t *basic_param_table_ptr,
|
||||
int basic_param_table_size,
|
||||
sfdp_smptbl_info &smptbl)
|
||||
{
|
||||
uint8_t bitfield = 0x01;
|
||||
|
||||
|
@ -859,23 +855,26 @@ int QSPIFBlockDevice::_sfdp_detect_erase_types_inst_and_size(uint8_t *basic_para
|
|||
if (basic_param_table_size > QSPIF_BASIC_PARAM_TABLE_ERASE_TYPE_1_SIZE_BYTE) {
|
||||
// Loop Erase Types 1-4
|
||||
for (int i_ind = 0; i_ind < 4; i_ind++) {
|
||||
_erase_type_inst_arr[i_ind] = QSPI_NO_INST; // Default for unsupported type
|
||||
_erase_type_size_arr[i_ind] = 1 << basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_ERASE_TYPE_1_SIZE_BYTE + 2 * i_ind]; // Size is 2^N where N is the table value
|
||||
tr_debug("Erase Type(A) %d - Inst: 0x%xh, Size: %d", (i_ind + 1), _erase_type_inst_arr[i_ind],
|
||||
_erase_type_size_arr[i_ind]);
|
||||
if (_erase_type_size_arr[i_ind] > 1) {
|
||||
smptbl.erase_type_inst_arr[i_ind] = QSPI_NO_INST; // Default for unsupported type
|
||||
smptbl.erase_type_size_arr[i_ind] = 1
|
||||
<< basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_ERASE_TYPE_1_SIZE_BYTE + 2 * i_ind]; // Size is 2^N where N is the table value
|
||||
tr_debug("Erase Type(A) %d - Inst: 0x%xh, Size: %d", (i_ind + 1), smptbl.erase_type_inst_arr[i_ind],
|
||||
smptbl.erase_type_size_arr[i_ind]);
|
||||
if (smptbl.erase_type_size_arr[i_ind] > 1) {
|
||||
// if size==1 type is not supported
|
||||
_erase_type_inst_arr[i_ind] = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_ERASE_TYPE_1_BYTE + 2 * i_ind];
|
||||
smptbl.erase_type_inst_arr[i_ind] = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_ERASE_TYPE_1_BYTE
|
||||
+ 2 * i_ind];
|
||||
|
||||
if ((_erase_type_size_arr[i_ind] < _min_common_erase_size) || (_min_common_erase_size == 0)) {
|
||||
if ((smptbl.erase_type_size_arr[i_ind] < smptbl.regions_min_common_erase_size)
|
||||
|| (smptbl.regions_min_common_erase_size == 0)) {
|
||||
//Set default minimal common erase for signal region
|
||||
_min_common_erase_size = _erase_type_size_arr[i_ind];
|
||||
smptbl.regions_min_common_erase_size = smptbl.erase_type_size_arr[i_ind];
|
||||
}
|
||||
_region_erase_types_bitfield[0] |= bitfield; // If there's no region map, set region "0" types bitfield as default
|
||||
smptbl.region_erase_types_bitfld[0] |= bitfield; // If there's no region map, set region "0" types bitfield as default
|
||||
}
|
||||
|
||||
tr_debug("Erase Type %d - Inst: 0x%xh, Size: %d", (i_ind + 1), _erase_type_inst_arr[i_ind],
|
||||
_erase_type_size_arr[i_ind]);
|
||||
tr_debug("Erase Type %d - Inst: 0x%xh, Size: %d", (i_ind + 1), smptbl.erase_type_inst_arr[i_ind],
|
||||
smptbl.erase_type_size_arr[i_ind]);
|
||||
bitfield = bitfield << 1;
|
||||
}
|
||||
} else {
|
||||
|
@ -1108,63 +1107,6 @@ int QSPIFBlockDevice::_sfdp_detect_reset_protocol_and_reset(uint8_t *basic_param
|
|||
return status;
|
||||
}
|
||||
|
||||
int QSPIFBlockDevice::_sfdp_parse_sector_map_table(uint32_t sector_map_table_addr, size_t sector_map_table_size)
|
||||
{
|
||||
uint8_t sector_map_table[SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES]; /* Up To 16 DWORDS = 64 Bytes */
|
||||
uint32_t tmp_region_size = 0;
|
||||
int i_ind = 0;
|
||||
int prev_boundary = 0;
|
||||
// Default set to all type bits 1-4 are common
|
||||
int min_common_erase_type_bits = ERASE_BITMASK_ALL;
|
||||
|
||||
int status = _qspi_send_read_sfdp_command(sector_map_table_addr, (char *)sector_map_table, sector_map_table_size);
|
||||
if (status != QSPI_STATUS_OK) {
|
||||
tr_error("Init - Read SFDP First Table Failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Currently we support only Single Map Descriptor
|
||||
if (!((sector_map_table[0] & 0x3) == 0x03) && (sector_map_table[1] == 0x0)) {
|
||||
tr_error("Sector Map - Supporting Only Single! Map Descriptor (not map commands)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
_regions_count = sector_map_table[2] + 1;
|
||||
if (_regions_count > QSPIF_MAX_REGIONS) {
|
||||
tr_error("Supporting up to %d regions, current setup to %d regions - fail",
|
||||
QSPIF_MAX_REGIONS, _regions_count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Loop through Regions and set for each one: size, supported erase types, high boundary offset
|
||||
// Calculate minimum Common Erase Type for all Regions
|
||||
for (i_ind = 0; i_ind < _regions_count; i_ind++) {
|
||||
tmp_region_size = ((*((uint32_t *)§or_map_table[(i_ind + 1) * 4])) >> 8) & 0x00FFFFFF; // bits 9-32
|
||||
_region_size_bytes[i_ind] = (tmp_region_size + 1) * 256; // Region size is 0 based multiple of 256 bytes;
|
||||
_region_erase_types_bitfield[i_ind] = sector_map_table[(i_ind + 1) * 4] & 0x0F; // bits 1-4
|
||||
min_common_erase_type_bits &= _region_erase_types_bitfield[i_ind];
|
||||
_region_high_boundary[i_ind] = (_region_size_bytes[i_ind] - 1) + prev_boundary;
|
||||
prev_boundary = _region_high_boundary[i_ind] + 1;
|
||||
}
|
||||
|
||||
// Calc minimum Common Erase Size from min_common_erase_type_bits
|
||||
uint8_t type_mask = ERASE_BITMASK_TYPE1;
|
||||
for (i_ind = 0; i_ind < 4; i_ind++) {
|
||||
if (min_common_erase_type_bits & type_mask) {
|
||||
_min_common_erase_size = _erase_type_size_arr[i_ind];
|
||||
break;
|
||||
}
|
||||
type_mask = type_mask << 1;
|
||||
}
|
||||
|
||||
if (i_ind == 4) {
|
||||
// No common erase type was found between regions
|
||||
_min_common_erase_size = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int QSPIFBlockDevice::_handle_vendor_quirks()
|
||||
{
|
||||
uint8_t vendor_device_ids[QSPI_RDID_DATA_LENGTH] = {0};
|
||||
|
@ -1378,20 +1320,20 @@ bool QSPIFBlockDevice::_is_mem_ready()
|
|||
/*********************************************/
|
||||
/************* Utility Functions *************/
|
||||
/*********************************************/
|
||||
int QSPIFBlockDevice::_utils_find_addr_region(bd_size_t offset)
|
||||
int QSPIFBlockDevice::_utils_find_addr_region(bd_size_t offset, sfdp_smptbl_info &smptbl)
|
||||
{
|
||||
//Find the region to which the given offset belong to
|
||||
if ((offset > _device_size_bytes) || (_regions_count == 0)) {
|
||||
if ((offset > _device_size_bytes) || (smptbl.region_cnt == 0)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_regions_count == 1) {
|
||||
if (smptbl.region_cnt == 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i_ind = _regions_count - 2; i_ind >= 0; i_ind--) {
|
||||
for (int i_ind = smptbl.region_cnt - 2; i_ind >= 0; i_ind--) {
|
||||
|
||||
if (offset > _region_high_boundary[i_ind]) {
|
||||
if (offset > smptbl.region_high_boundary[i_ind]) {
|
||||
return (i_ind + 1);
|
||||
}
|
||||
}
|
||||
|
@ -1399,18 +1341,23 @@ int QSPIFBlockDevice::_utils_find_addr_region(bd_size_t offset)
|
|||
|
||||
}
|
||||
|
||||
int QSPIFBlockDevice::_utils_iterate_next_largest_erase_type(uint8_t &bitfield, int size, int offset, int boundry)
|
||||
int QSPIFBlockDevice::_utils_iterate_next_largest_erase_type(uint8_t &bitfield,
|
||||
int size,
|
||||
int offset,
|
||||
int region,
|
||||
sfdp_smptbl_info &smptbl)
|
||||
{
|
||||
// Iterate on all supported Erase Types of the Region to which the offset belong to.
|
||||
// Iterates from highest type to lowest
|
||||
uint8_t type_mask = ERASE_BITMASK_TYPE4;
|
||||
uint8_t type_mask = SFDP_ERASE_BITMASK_TYPE4;
|
||||
int i_ind = 0;
|
||||
int largest_erase_type = 0;
|
||||
for (i_ind = 3; i_ind >= 0; i_ind--) {
|
||||
if (bitfield & type_mask) {
|
||||
largest_erase_type = i_ind;
|
||||
if ((size > (int)(_erase_type_size_arr[largest_erase_type])) &&
|
||||
((boundry - offset) > (int)(_erase_type_size_arr[largest_erase_type]))) {
|
||||
if ((size > (int)(smptbl.erase_type_size_arr[largest_erase_type])) &&
|
||||
((_sfdp_info.smptbl.region_high_boundary[region] - offset)
|
||||
> (int)(smptbl.erase_type_size_arr[largest_erase_type]))) {
|
||||
break;
|
||||
} else {
|
||||
bitfield &= ~type_mask;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -65,12 +65,6 @@ using namespace mbed;
|
|||
#define SPIF_BASIC_PARAM_ERASE_TYPE_4_SIZE_BYTE 34
|
||||
#define SPIF_BASIC_PARAM_4K_ERASE_TYPE_BYTE 1
|
||||
|
||||
// Erase Types Per Region BitMask
|
||||
#define ERASE_BITMASK_TYPE4 0x08
|
||||
#define ERASE_BITMASK_TYPE1 0x01
|
||||
#define ERASE_BITMASK_NONE 0x00
|
||||
#define ERASE_BITMASK_ALL 0x0F
|
||||
|
||||
#define IS_MEM_READY_MAX_RETRIES 10000
|
||||
|
||||
enum spif_default_instructions {
|
||||
|
@ -113,9 +107,9 @@ SPIFBlockDevice::SPIFBlockDevice(
|
|||
_write_dummy_and_mode_cycles = 0;
|
||||
_dummy_and_mode_cycles = _read_dummy_and_mode_cycles;
|
||||
|
||||
_min_common_erase_size = 0;
|
||||
_regions_count = 1;
|
||||
_region_erase_types_bitfield[0] = ERASE_BITMASK_NONE;
|
||||
_sfdp_info.smptbl.regions_min_common_erase_size = 0;
|
||||
_sfdp_info.smptbl.region_cnt = 1;
|
||||
_sfdp_info.smptbl.region_erase_types_bitfld[0] = SFDP_ERASE_BITMASK_NONE;
|
||||
|
||||
if (SPIF_BD_ERROR_OK != _spi_set_frequency(freq)) {
|
||||
tr_error("SPI Set Frequency Failed");
|
||||
|
@ -181,7 +175,7 @@ int SPIFBlockDevice::init()
|
|||
}
|
||||
|
||||
/**************************** Parse SFDP Header ***********************************/
|
||||
if (0 != _sfdp_parse_sfdp_headers(hdr_info)) {
|
||||
if (0 != sfdp_parse_headers(callback(this, &SPIFBlockDevice::_spi_send_read_sfdp_command), hdr_info)) {
|
||||
tr_error("init - Parse SFDP Headers Failed");
|
||||
status = SPIF_BD_ERROR_PARSING_FAILED;
|
||||
goto exit_point;
|
||||
|
@ -189,21 +183,22 @@ int SPIFBlockDevice::init()
|
|||
|
||||
|
||||
/**************************** Parse Basic Parameters Table ***********************************/
|
||||
if (0 != _sfdp_parse_basic_param_table(hdr_info.basic_table_addr, hdr_info.basic_table_size)) {
|
||||
if (0 != _sfdp_parse_basic_param_table(hdr_info.bptbl.addr, hdr_info.bptbl.size)) {
|
||||
tr_error("init - Parse Basic Param Table Failed");
|
||||
status = SPIF_BD_ERROR_PARSING_FAILED;
|
||||
goto exit_point;
|
||||
}
|
||||
|
||||
/**************************** Parse Sector Map Table ***********************************/
|
||||
_region_size_bytes[0] =
|
||||
_sfdp_info.smptbl.region_size[0] =
|
||||
_device_size_bytes; // If there's no region map, we have a single region sized the entire device size
|
||||
_region_high_boundary[0] = _device_size_bytes - 1;
|
||||
_sfdp_info.smptbl.region_high_boundary[0] = _device_size_bytes - 1;
|
||||
|
||||
if ((hdr_info.sector_map_table_addr != 0) && (0 != hdr_info.sector_map_table_size)) {
|
||||
tr_debug("init - Parsing Sector Map Table - addr: 0x%" PRIx32 "h, Size: %d", hdr_info.sector_map_table_addr,
|
||||
hdr_info.sector_map_table_size);
|
||||
if (0 != _sfdp_parse_sector_map_table(hdr_info.sector_map_table_addr, hdr_info.sector_map_table_size)) {
|
||||
if ((hdr_info.smptbl.addr != 0) && (0 != hdr_info.smptbl.size)) {
|
||||
tr_debug("init - Parsing Sector Map Table - addr: 0x%" PRIx32 "h, Size: %d", hdr_info.smptbl.addr,
|
||||
hdr_info.smptbl.size);
|
||||
if (sfdp_parse_sector_map_table(callback(this, &SPIFBlockDevice::_spi_send_read_sfdp_command),
|
||||
_sfdp_info.smptbl) < 0) {
|
||||
tr_error("init - Parse Sector Map Table Failed");
|
||||
status = SPIF_BD_ERROR_PARSING_FAILED;
|
||||
goto exit_point;
|
||||
|
@ -347,13 +342,13 @@ int SPIFBlockDevice::erase(bd_addr_t addr, bd_size_t in_size)
|
|||
bool erase_failed = false;
|
||||
int status = SPIF_BD_ERROR_OK;
|
||||
// Find region of erased address
|
||||
int region = _utils_find_addr_region(addr);
|
||||
int region = _utils_find_addr_region(addr, _sfdp_info.smptbl);
|
||||
if (region < 0) {
|
||||
tr_error("no region found for address %llu", addr);
|
||||
return SPIF_BD_ERROR_INVALID_ERASE_PARAMS;
|
||||
}
|
||||
// Erase Types of selected region
|
||||
uint8_t bitfield = _region_erase_types_bitfield[region];
|
||||
uint8_t bitfield = _sfdp_info.smptbl.region_erase_types_bitfld[region];
|
||||
|
||||
tr_debug("erase - addr: %llu, in_size: %llu", addr, in_size);
|
||||
|
||||
|
@ -372,10 +367,11 @@ int SPIFBlockDevice::erase(bd_addr_t addr, bd_size_t in_size)
|
|||
|
||||
// iterate to find next Largest erase type ( a. supported by region, b. smaller than size)
|
||||
// find the matching instruction and erase size chunk for that type.
|
||||
type = _utils_iterate_next_largest_erase_type(bitfield, size, (unsigned int)addr, _region_high_boundary[region]);
|
||||
cur_erase_inst = _erase_type_inst_arr[type];
|
||||
offset = addr % _erase_type_size_arr[type];
|
||||
chunk = ((offset + size) < _erase_type_size_arr[type]) ? size : (_erase_type_size_arr[type] - offset);
|
||||
type = _utils_iterate_next_largest_erase_type(bitfield, size, (unsigned int)addr, region, _sfdp_info.smptbl);
|
||||
cur_erase_inst = _sfdp_info.smptbl.erase_type_inst_arr[type];
|
||||
offset = addr % _sfdp_info.smptbl.erase_type_size_arr[type];
|
||||
chunk = ((offset + size) < _sfdp_info.smptbl.erase_type_size_arr[type]) ?
|
||||
size : (_sfdp_info.smptbl.erase_type_size_arr[type] - offset);
|
||||
|
||||
tr_debug("erase - addr: %llu, size:%d, Inst: 0x%xh, chunk: %" PRIu32 " , ",
|
||||
addr, size, cur_erase_inst, chunk);
|
||||
|
@ -396,10 +392,10 @@ int SPIFBlockDevice::erase(bd_addr_t addr, bd_size_t in_size)
|
|||
addr += chunk;
|
||||
size -= chunk;
|
||||
|
||||
if ((size > 0) && (addr > _region_high_boundary[region])) {
|
||||
if ((size > 0) && (addr > _sfdp_info.smptbl.region_high_boundary[region])) {
|
||||
// erase crossed to next region
|
||||
region++;
|
||||
bitfield = _region_erase_types_bitfield[region];
|
||||
bitfield = _sfdp_info.smptbl.region_erase_types_bitfld[region];
|
||||
}
|
||||
|
||||
if (false == _is_mem_ready()) {
|
||||
|
@ -435,17 +431,17 @@ bd_size_t SPIFBlockDevice::get_program_size() const
|
|||
bd_size_t SPIFBlockDevice::get_erase_size() const
|
||||
{
|
||||
// return minimal erase size supported by all regions (0 if none exists)
|
||||
return _min_common_erase_size;
|
||||
return _sfdp_info.smptbl.regions_min_common_erase_size;
|
||||
}
|
||||
|
||||
// Find minimal erase size supported by the region to which the address belongs to
|
||||
bd_size_t SPIFBlockDevice::get_erase_size(bd_addr_t addr) const
|
||||
{
|
||||
// Find region of current address
|
||||
int region = _utils_find_addr_region(addr);
|
||||
int region = _utils_find_addr_region(addr, _sfdp_info.smptbl);
|
||||
|
||||
unsigned int min_region_erase_size = _min_common_erase_size;
|
||||
int8_t type_mask = ERASE_BITMASK_TYPE1;
|
||||
unsigned int min_region_erase_size = _sfdp_info.smptbl.regions_min_common_erase_size;
|
||||
int8_t type_mask = SFDP_ERASE_BITMASK_TYPE1;
|
||||
int i_ind = 0;
|
||||
|
||||
if (region != -1) {
|
||||
|
@ -453,9 +449,9 @@ bd_size_t SPIFBlockDevice::get_erase_size(bd_addr_t addr) const
|
|||
|
||||
for (i_ind = 0; i_ind < 4; i_ind++) {
|
||||
// loop through erase types bitfield supported by region
|
||||
if (_region_erase_types_bitfield[region] & type_mask) {
|
||||
if (_sfdp_info.smptbl.region_erase_types_bitfld[region] & type_mask) {
|
||||
|
||||
min_region_erase_size = _erase_type_size_arr[i_ind];
|
||||
min_region_erase_size = _sfdp_info.smptbl.erase_type_size_arr[i_ind];
|
||||
break;
|
||||
}
|
||||
type_mask = type_mask << 1;
|
||||
|
@ -624,65 +620,6 @@ spif_bd_error SPIFBlockDevice::_spi_send_general_command(int instruction, bd_add
|
|||
/*********************************************************/
|
||||
/********** SFDP Parsing and Detection Functions *********/
|
||||
/*********************************************************/
|
||||
int SPIFBlockDevice::_sfdp_parse_sector_map_table(uint32_t sector_map_table_addr, size_t sector_map_table_size)
|
||||
{
|
||||
uint8_t sector_map_table[SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES]; /* Up To 16 DWORDS = 64 Bytes */
|
||||
uint32_t tmp_region_size = 0;
|
||||
int i_ind = 0;
|
||||
int prev_boundary = 0;
|
||||
// Default set to all type bits 1-4 are common
|
||||
int min_common_erase_type_bits = ERASE_BITMASK_ALL;
|
||||
|
||||
|
||||
spif_bd_error status = _spi_send_read_command(SPIF_SFDP, sector_map_table, sector_map_table_addr /*address*/,
|
||||
sector_map_table_size);
|
||||
if (status != SPIF_BD_ERROR_OK) {
|
||||
tr_error("init - Read SFDP First Table Failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Currently we support only Single Map Descriptor
|
||||
if (!((sector_map_table[0] & 0x3) == 0x03) && (sector_map_table[1] == 0x0)) {
|
||||
tr_error("Sector Map - Supporting Only Single! Map Descriptor (not map commands)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
_regions_count = sector_map_table[2] + 1;
|
||||
if (_regions_count > SPIF_MAX_REGIONS) {
|
||||
tr_error("Supporting up to %d regions, current setup to %d regions - fail",
|
||||
SPIF_MAX_REGIONS, _regions_count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Loop through Regions and set for each one: size, supported erase types, high boundary offset
|
||||
// Calculate minimum Common Erase Type for all Regions
|
||||
for (i_ind = 0; i_ind < _regions_count; i_ind++) {
|
||||
tmp_region_size = ((*((uint32_t *)§or_map_table[(i_ind + 1) * 4])) >> 8) & 0x00FFFFFF; // bits 9-32
|
||||
_region_size_bytes[i_ind] = (tmp_region_size + 1) * 256; // Region size is 0 based multiple of 256 bytes;
|
||||
_region_erase_types_bitfield[i_ind] = sector_map_table[(i_ind + 1) * 4] & 0x0F; // bits 1-4
|
||||
min_common_erase_type_bits &= _region_erase_types_bitfield[i_ind];
|
||||
_region_high_boundary[i_ind] = (_region_size_bytes[i_ind] - 1) + prev_boundary;
|
||||
prev_boundary = _region_high_boundary[i_ind] + 1;
|
||||
}
|
||||
|
||||
// Calc minimum Common Erase Size from min_common_erase_type_bits
|
||||
uint8_t type_mask = ERASE_BITMASK_TYPE1;
|
||||
for (i_ind = 0; i_ind < 4; i_ind++) {
|
||||
if (min_common_erase_type_bits & type_mask) {
|
||||
_min_common_erase_size = _erase_type_size_arr[i_ind];
|
||||
break;
|
||||
}
|
||||
type_mask = type_mask << 1;
|
||||
}
|
||||
|
||||
if (i_ind == 4) {
|
||||
// No common erase type was found between regions
|
||||
_min_common_erase_size = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SPIFBlockDevice::_sfdp_parse_basic_param_table(uint32_t basic_table_addr, size_t basic_table_size)
|
||||
{
|
||||
uint8_t param_table[SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES]; /* Up To 16 DWORDS = 64 Bytes */
|
||||
|
@ -719,8 +656,7 @@ int SPIFBlockDevice::_sfdp_parse_basic_param_table(uint32_t basic_table_addr, si
|
|||
_page_size_bytes = _sfdp_detect_page_size(param_table, basic_table_size);
|
||||
|
||||
// Detect and Set Erase Types
|
||||
_sfdp_detect_erase_types_inst_and_size(param_table, basic_table_size, _erase4k_inst, _erase_type_inst_arr,
|
||||
_erase_type_size_arr);
|
||||
_sfdp_detect_erase_types_inst_and_size(param_table, basic_table_size, _erase4k_inst, _sfdp_info.smptbl);
|
||||
_erase_instruction = _erase4k_inst;
|
||||
|
||||
// Detect and Set fastest Bus mode (default 1-1-1)
|
||||
|
@ -729,11 +665,6 @@ int SPIFBlockDevice::_sfdp_parse_basic_param_table(uint32_t basic_table_addr, si
|
|||
return 0;
|
||||
}
|
||||
|
||||
int SPIFBlockDevice::_sfdp_parse_sfdp_headers(sfdp_hdr_info &hdr_info)
|
||||
{
|
||||
return sfdp_parse_headers(callback(this, &SPIFBlockDevice::_spi_send_read_sfdp_command), hdr_info);
|
||||
}
|
||||
|
||||
unsigned int SPIFBlockDevice::_sfdp_detect_page_size(uint8_t *basic_param_table_ptr, int basic_param_table_size)
|
||||
{
|
||||
unsigned int page_size = SPIF_DEFAULT_PAGE_SIZE;
|
||||
|
@ -751,7 +682,7 @@ unsigned int SPIFBlockDevice::_sfdp_detect_page_size(uint8_t *basic_param_table_
|
|||
|
||||
int SPIFBlockDevice::_sfdp_detect_erase_types_inst_and_size(uint8_t *basic_param_table_ptr, int basic_param_table_size,
|
||||
int &erase4k_inst,
|
||||
int *erase_type_inst_arr, unsigned int *erase_type_size_arr)
|
||||
sfdp_smptbl_info &smptbl)
|
||||
{
|
||||
erase4k_inst = 0xff;
|
||||
bool found_4Kerase_type = false;
|
||||
|
@ -763,34 +694,36 @@ int SPIFBlockDevice::_sfdp_detect_erase_types_inst_and_size(uint8_t *basic_param
|
|||
if (basic_param_table_size > SPIF_BASIC_PARAM_ERASE_TYPE_1_SIZE_BYTE) {
|
||||
// Loop Erase Types 1-4
|
||||
for (int i_ind = 0; i_ind < 4; i_ind++) {
|
||||
erase_type_inst_arr[i_ind] = 0xff; //0xFF default for unsupported type
|
||||
erase_type_size_arr[i_ind] = local_math_power(2,
|
||||
basic_param_table_ptr[SPIF_BASIC_PARAM_ERASE_TYPE_1_SIZE_BYTE + 2 * i_ind]); // Size given as 2^N
|
||||
tr_debug("Erase Type(A) %d - Inst: 0x%xh, Size: %d", (i_ind + 1), erase_type_inst_arr[i_ind],
|
||||
erase_type_size_arr[i_ind]);
|
||||
if (erase_type_size_arr[i_ind] > 1) {
|
||||
smptbl.erase_type_inst_arr[i_ind] = 0xff; //0xFF default for unsupported type
|
||||
smptbl.erase_type_size_arr[i_ind] = local_math_power(
|
||||
2, basic_param_table_ptr[SPIF_BASIC_PARAM_ERASE_TYPE_1_SIZE_BYTE + 2 * i_ind]); // Size given as 2^N
|
||||
tr_debug("Erase Type(A) %d - Inst: 0x%xh, Size: %d", (i_ind + 1), smptbl.erase_type_inst_arr[i_ind],
|
||||
smptbl.erase_type_size_arr[i_ind]);
|
||||
if (smptbl.erase_type_size_arr[i_ind] > 1) {
|
||||
// if size==1 type is not supported
|
||||
erase_type_inst_arr[i_ind] = basic_param_table_ptr[SPIF_BASIC_PARAM_ERASE_TYPE_1_BYTE + 2 * i_ind];
|
||||
smptbl.erase_type_inst_arr[i_ind] =
|
||||
basic_param_table_ptr[SPIF_BASIC_PARAM_ERASE_TYPE_1_BYTE + 2 * i_ind];
|
||||
|
||||
if ((erase_type_size_arr[i_ind] < _min_common_erase_size) || (_min_common_erase_size == 0)) {
|
||||
if ((smptbl.erase_type_size_arr[i_ind] < smptbl.regions_min_common_erase_size)
|
||||
|| (smptbl.regions_min_common_erase_size == 0)) {
|
||||
//Set default minimal common erase for singal region
|
||||
_min_common_erase_size = erase_type_size_arr[i_ind];
|
||||
smptbl.regions_min_common_erase_size = smptbl.erase_type_size_arr[i_ind];
|
||||
}
|
||||
|
||||
// SFDP standard requires 4K Erase type to exist and its instruction to be identical to legacy field erase instruction
|
||||
if (erase_type_size_arr[i_ind] == 4096) {
|
||||
if (smptbl.erase_type_size_arr[i_ind] == 4096) {
|
||||
found_4Kerase_type = true;
|
||||
if (erase4k_inst != erase_type_inst_arr[i_ind]) {
|
||||
if (erase4k_inst != smptbl.erase_type_inst_arr[i_ind]) {
|
||||
//Verify 4KErase Type is identical to Legacy 4K erase type specified in Byte 1 of Param Table
|
||||
erase4k_inst = erase_type_inst_arr[i_ind];
|
||||
erase4k_inst = smptbl.erase_type_inst_arr[i_ind];
|
||||
tr_warning("_detectEraseTypesInstAndSize - Default 4K erase Inst is different than erase type Inst for 4K");
|
||||
|
||||
}
|
||||
}
|
||||
_region_erase_types_bitfield[0] |= bitfield; // If there's no region map, set region "0" types bitfield as defualt;
|
||||
smptbl.region_erase_types_bitfld[0] |= bitfield; // no region map, set region "0" types bitfield as default
|
||||
}
|
||||
tr_info("Erase Type %d - Inst: 0x%xh, Size: %d", (i_ind + 1),
|
||||
erase_type_inst_arr[i_ind], erase_type_size_arr[i_ind]);
|
||||
smptbl.erase_type_inst_arr[i_ind], smptbl.erase_type_size_arr[i_ind]);
|
||||
bitfield = bitfield << 1;
|
||||
}
|
||||
}
|
||||
|
@ -918,20 +851,20 @@ int SPIFBlockDevice::_set_write_enable()
|
|||
/*********************************************/
|
||||
/************* Utility Functions *************/
|
||||
/*********************************************/
|
||||
int SPIFBlockDevice::_utils_find_addr_region(bd_size_t offset) const
|
||||
int SPIFBlockDevice::_utils_find_addr_region(bd_size_t offset, const sfdp_smptbl_info &smptbl) const
|
||||
{
|
||||
//Find the region to which the given offset belong to
|
||||
if ((offset > _device_size_bytes) || (_regions_count == 0)) {
|
||||
if ((offset > _device_size_bytes) || (smptbl.region_cnt == 0)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_regions_count == 1) {
|
||||
if (smptbl.region_cnt == 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i_ind = _regions_count - 2; i_ind >= 0; i_ind--) {
|
||||
for (int i_ind = smptbl.region_cnt - 2; i_ind >= 0; i_ind--) {
|
||||
|
||||
if (offset > _region_high_boundary[i_ind]) {
|
||||
if (offset > smptbl.region_high_boundary[i_ind]) {
|
||||
return (i_ind + 1);
|
||||
}
|
||||
}
|
||||
|
@ -939,18 +872,23 @@ int SPIFBlockDevice::_utils_find_addr_region(bd_size_t offset) const
|
|||
|
||||
}
|
||||
|
||||
int SPIFBlockDevice::_utils_iterate_next_largest_erase_type(uint8_t &bitfield, int size, int offset, int boundry)
|
||||
int SPIFBlockDevice::_utils_iterate_next_largest_erase_type(uint8_t &bitfield,
|
||||
int size,
|
||||
int offset,
|
||||
int region,
|
||||
sfdp_smptbl_info &smptbl)
|
||||
{
|
||||
// Iterate on all supported Erase Types of the Region to which the offset belong to.
|
||||
// Iterates from highest type to lowest
|
||||
uint8_t type_mask = ERASE_BITMASK_TYPE4;
|
||||
uint8_t type_mask = SFDP_ERASE_BITMASK_TYPE4;
|
||||
int i_ind = 0;
|
||||
int largest_erase_type = 0;
|
||||
for (i_ind = 3; i_ind >= 0; i_ind--) {
|
||||
if (bitfield & type_mask) {
|
||||
largest_erase_type = i_ind;
|
||||
if ((size > (int)(_erase_type_size_arr[largest_erase_type])) &&
|
||||
((boundry - offset) > (int)(_erase_type_size_arr[largest_erase_type]))) {
|
||||
if ((size > (int)(smptbl.erase_type_size_arr[largest_erase_type])) &&
|
||||
((_sfdp_info.smptbl.region_high_boundary[region] - offset)
|
||||
> (int)(smptbl.erase_type_size_arr[largest_erase_type]))) {
|
||||
break;
|
||||
} else {
|
||||
bitfield &= ~type_mask;
|
||||
|
@ -960,10 +898,9 @@ int SPIFBlockDevice::_utils_iterate_next_largest_erase_type(uint8_t &bitfield, i
|
|||
}
|
||||
|
||||
if (i_ind == 4) {
|
||||
tr_error("no erase type was found for current region addr");
|
||||
tr_error("No erase type was found for current region addr");
|
||||
}
|
||||
return largest_erase_type;
|
||||
|
||||
}
|
||||
|
||||
/*********************************************/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 *)§or_map_table[(i_ind + 1) * 4])) >> 8) & 0x00FFFFFF; // bits 9-32
|
||||
smptbl.region_size[i_ind] = (tmp_region_size + 1) * 256; // Region size is 0 based multiple of 256 bytes;
|
||||
smptbl.region_erase_types_bitfld[i_ind] = sector_map_table[(i_ind + 1) * 4] & 0x0F; // bits 1-4
|
||||
min_common_erase_type_bits &= smptbl.region_erase_types_bitfld[i_ind];
|
||||
smptbl.region_high_boundary[i_ind] = (smptbl.region_size[i_ind] - 1) + prev_boundary;
|
||||
prev_boundary = smptbl.region_high_boundary[i_ind] + 1;
|
||||
}
|
||||
|
||||
// Calc minimum Common Erase Size from min_common_erase_type_bits
|
||||
uint8_t type_mask = SFDP_ERASE_BITMASK_TYPE1;
|
||||
for (i_ind = 0; i_ind < 4; i_ind++) {
|
||||
if (min_common_erase_type_bits & type_mask) {
|
||||
smptbl.regions_min_common_erase_size = smptbl.erase_type_size_arr[i_ind];
|
||||
break;
|
||||
}
|
||||
type_mask = type_mask << 1;
|
||||
}
|
||||
|
||||
if (i_ind == 4) {
|
||||
// No common erase type was found between regions
|
||||
smptbl.regions_min_common_erase_size = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} /* namespace mbed */
|
||||
#endif /* (DEVICE_SPI || DEVICE_QSPI) */
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
}
|
||||
},
|
||||
"target_overrides": {
|
||||
"NRF52840_DK": {
|
||||
"*": {
|
||||
"target.components_remove": ["QSPI", "QSPIF"],
|
||||
"target.components_add" : ["SPI", "SPIF"]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue