Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion drivers/internal/SFDP.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ int sfdp_find_addr_region(bd_size_t offset, const sfdp_hdr_info &sfdp_info);
* @param size Upper limit for region size
* @param offset Offset value
* @param region Region number
* @param smptbl Information about different erase types
* @param smptbl Information about different erase types
*
* @return Largest erase type
*/
Expand Down
173 changes: 117 additions & 56 deletions drivers/source/SFDP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@
*/

#include <algorithm>
#include <cstdint>
#include <cstring>
#include <memory>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include "platform/mbed_error.h"
#include "drivers/internal/SFDP.h"

#if (DEVICE_SPI || DEVICE_QSPI)
Expand Down Expand Up @@ -107,20 +111,69 @@ int sfdp_parse_single_param_header(sfdp_prm_hdr *phdr_ptr, sfdp_hdr_info &hdr_in
return -1;
}

if ((phdr_ptr->PID_LSB == 0) && (sfdp_get_param_id_msb(phdr_ptr->DWORD2) == 0xFF)) {
tr_debug("Parameter header: Basic Parameter Header");
hdr_info.bptbl.addr = sfdp_get_param_tbl_ptr(phdr_ptr->DWORD2);
hdr_info.bptbl.size = std::min((phdr_ptr->P_LEN * 4), SFDP_BASIC_PARAMS_TBL_SIZE);
int param_id_msb = sfdp_get_param_id_msb(phdr_ptr->DWORD2);

} else if ((phdr_ptr->PID_LSB == 0x81) && (sfdp_get_param_id_msb(phdr_ptr->DWORD2) == 0xFF)) {
tr_debug("Parameter header: Sector Map Parameter Header");
hdr_info.smptbl.addr = sfdp_get_param_tbl_ptr(phdr_ptr->DWORD2);
hdr_info.smptbl.size = phdr_ptr->P_LEN * 4;
/* MSB JEDEC ID */
if (param_id_msb == 0xFF) {

} else {
tr_debug("Parameter header: header vendor specific or unknown. Parameter ID LSB: 0x%" PRIX8 "; MSB: 0x%" PRIX8 "",
/* LSB JEDEC ID */
switch (phdr_ptr->PID_LSB) {
case 0x0:
tr_debug("Parameter header: JEDEC Basic Flash - Revision %" PRIX8 ".%" PRIX8 "",
phdr_ptr->P_MAJOR,
phdr_ptr->P_MINOR);
hdr_info.bptbl.addr = sfdp_get_param_tbl_ptr(phdr_ptr->DWORD2);
hdr_info.bptbl.size = std::min((phdr_ptr->P_LEN * 4), SFDP_BASIC_PARAMS_TBL_SIZE);
break;
case 0x81:
tr_info("Parameter header: Sector Map");
hdr_info.smptbl.addr = sfdp_get_param_tbl_ptr(phdr_ptr->DWORD2);
hdr_info.smptbl.size = phdr_ptr->P_LEN * 4;
break;
/* Unsupported */
case 0x03:
tr_info("UNSUPPORTED:Parameter header: Replay Protected Monotonic Counters");
break;
case 0x84:
tr_info("UNSUPPORTED:Parameter header: 4-byte Address Instruction");
break;
case 0x05:
tr_info("UNSUPPORTED:Parameter header: eXtended Serial Peripheral Interface (xSPI) Profile 1.0");
break;
case 0x06:
tr_info("UNSUPPORTED:Parameter header: eXtended Serial Peripheral Interface (xSPI) Profile 2.0");
break;
case 0x87:
tr_info("UNSUPPORTED:Parameter header: SCCR Map for SPI Memory Devices");
break;
case 0x88:
tr_info("UNSUPPORTED:Parameter header: SCCR Map Offsets for Multi-Chip SPI Memory Devices");
break;
case 0x09:
tr_info("UNSUPPORTED:Parameter header: SCCR Map for xSPI Profile 2.0 Memory Devices");
break;
case 0x0A:
tr_info("UNSUPPORTED:Parameter header: Command Sequences to Change to Octal DDR (8D-8D-8D) mode");
break;
case 0x0C:
tr_info("UNSUPPORTED:Parameter header: x4 Quad IO with DS");
break;
case 0x8D:
tr_info("UNSUPPORTED:Parameter header: Command Sequences to Change to Quad DDR (4S-4D-4D) mode");
break;
default:
tr_debug("Parameter header: unknown JEDEC header. Parameter ID LSB: 0x%" PRIX8 "; MSB: 0x%" PRIX8 "",
phdr_ptr->PID_LSB,
sfdp_get_param_id_msb(phdr_ptr->DWORD2));
}
} else if (param_id_msb >= 0x80) { // MSB JEDEC ID
tr_debug("Parameter header: unknown JEDEC header. Parameter ID LSB: 0x%" PRIX8 "; MSB: 0x%" PRIX8 "",
phdr_ptr->PID_LSB,
sfdp_get_param_id_msb(phdr_ptr->DWORD2));
} else { // MSB Vendor ID
tr_info("Parameter header: vendor specific header. Parameter ID LSB: 0x%" PRIX8 "; MSB: 0x%" PRIX8 "",
phdr_ptr->PID_LSB,
sfdp_get_param_id_msb(phdr_ptr->DWORD2));
}

return 0;
Expand Down Expand Up @@ -157,10 +210,10 @@ int sfdp_parse_headers(Callback<int(bd_addr_t, void *, bd_size_t)> sfdp_reader,
int hdr_status;

// Loop over Param Headers and parse them (currently supports Basic Param Table and Sector Region Map Table)
for (int i_ind = 0; i_ind < number_of_param_headers; i_ind++) {
for (int idx = 0; idx < number_of_param_headers; idx++) {
status = sfdp_reader(addr, param_header, data_length);
if (status < 0) {
tr_error("Retrieving a parameter header %d failed", i_ind + 1);
tr_error("Retrieving a parameter header %d failed", idx + 1);
return -1;
}

Expand All @@ -178,9 +231,8 @@ int sfdp_parse_headers(Callback<int(bd_addr_t, void *, bd_size_t)> sfdp_reader,

int sfdp_parse_sector_map_table(Callback<int(bd_addr_t, void *, bd_size_t)> sfdp_reader, sfdp_hdr_info &sfdp_info)
{
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;
uint8_t type_mask;
int prev_boundary = 0;
// Default set to all type bits 1-4 are common
int min_common_erase_type_bits = SFDP_ERASE_BITMASK_ALL;
Expand All @@ -191,25 +243,36 @@ int sfdp_parse_sector_map_table(Callback<int(bd_addr_t, void *, bd_size_t)> sfdp

if (!sfdp_info.smptbl.addr || !sfdp_info.smptbl.size) {
tr_debug("No Sector Map Table");
return 0;
return MBED_SUCCESS;
}

tr_debug("Parsing Sector Map Table - addr: 0x%" PRIx32 ", Size: %d", sfdp_info.smptbl.addr, sfdp_info.smptbl.size);
/* The number of
* - sector map configuration detection commands
* - configurations
* - regions in each configuration
* is variable -> the size of this table is variable
*/
auto smptbl_buff = std::make_unique<uint8_t[]>(sfdp_info.smptbl.size);
if (!smptbl_buff) {
tr_error("Failed to allocate memory");
return -1;
}

tr_debug("Parsing Sector Map Table - addr: 0x%" PRIx32 ", Size: %d", sfdp_info.smptbl.addr, sfdp_info.smptbl.size);

int status = sfdp_reader(sfdp_info.smptbl.addr, sector_map_table, sfdp_info.smptbl.size);
int status = sfdp_reader(sfdp_info.smptbl.addr, smptbl_buff.get(), sfdp_info.smptbl.size);
if (status < 0) {
tr_error("Sector Map: Table retrieval failed");
return -1;
}

// Currently we support only Single Map Descriptor
if (!((sector_map_table[0] & 0x3) == 0x03) && (sector_map_table[1] == 0x0)) {
if (!((smptbl_buff[0] & 0x3) == 0x03) && (smptbl_buff[1] == 0x0)) {
tr_error("Sector Map: Supporting Only Single Map Descriptor (not map commands)");
return -1;
}

sfdp_info.smptbl.region_cnt = sector_map_table[2] + 1;
sfdp_info.smptbl.region_cnt = smptbl_buff[2] + 1;
if (sfdp_info.smptbl.region_cnt > SFDP_SECTOR_MAP_MAX_REGIONS) {
tr_error("Sector Map: Supporting up to %d regions, current setup to %d regions - fail",
SFDP_SECTOR_MAP_MAX_REGIONS,
Expand All @@ -219,34 +282,31 @@ int sfdp_parse_sector_map_table(Callback<int(bd_addr_t, void *, bd_size_t)> sfdp

// 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 < sfdp_info.smptbl.region_cnt; i_ind++) {
tmp_region_size = ((*((uint32_t *)&sector_map_table[(i_ind + 1) * 4])) >> 8) & 0x00FFFFFF; // bits 9-32
sfdp_info.smptbl.region_size[i_ind] = (tmp_region_size + 1) * 256; // Region size is 0 based multiple of 256 bytes;
for (auto idx = 0; idx < sfdp_info.smptbl.region_cnt; idx++) {
tmp_region_size = ((*((uint32_t *)&smptbl_buff[(idx + 1) * 4])) >> 8) & 0x00FFFFFF; // bits 9-32
sfdp_info.smptbl.region_size[idx] = (tmp_region_size + 1) * 256; // Region size is 0 based multiple of 256 bytes;

sfdp_info.smptbl.region_erase_types_bitfld[i_ind] = sector_map_table[(i_ind + 1) * 4] & 0x0F; // bits 1-4
sfdp_info.smptbl.region_erase_types_bitfld[idx] = smptbl_buff[(idx + 1) * 4] & 0x0F; // bits 1-4

min_common_erase_type_bits &= sfdp_info.smptbl.region_erase_types_bitfld[i_ind];
min_common_erase_type_bits &= sfdp_info.smptbl.region_erase_types_bitfld[idx];

sfdp_info.smptbl.region_high_boundary[i_ind] = (sfdp_info.smptbl.region_size[i_ind] - 1) + prev_boundary;
sfdp_info.smptbl.region_high_boundary[idx] = (sfdp_info.smptbl.region_size[idx] - 1) + prev_boundary;

prev_boundary = sfdp_info.smptbl.region_high_boundary[i_ind] + 1;
prev_boundary = sfdp_info.smptbl.region_high_boundary[idx] + 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++) {
type_mask = SFDP_ERASE_BITMASK_TYPE1;
// If no common erase type is found between regions
sfdp_info.smptbl.regions_min_common_erase_size = 0;
for (auto idx = 0; idx < 4; idx++) {
if (min_common_erase_type_bits & type_mask) {
sfdp_info.smptbl.regions_min_common_erase_size = sfdp_info.smptbl.erase_type_size_arr[i_ind];
sfdp_info.smptbl.regions_min_common_erase_size = sfdp_info.smptbl.erase_type_size_arr[idx];
break;
}
type_mask = type_mask << 1;
}

if (i_ind == 4) {
// No common erase type was found between regions
sfdp_info.smptbl.regions_min_common_erase_size = 0;
}

return 0;
}

Expand Down Expand Up @@ -275,27 +335,27 @@ int sfdp_detect_erase_types_inst_and_size(uint8_t *bptbl_ptr, sfdp_hdr_info &sfd
// Erase 4K Inst is taken either from param table legacy 4K erase or superseded by erase Instruction for type of size 4K
if (sfdp_info.bptbl.size > SFDP_BASIC_PARAM_TABLE_ERASE_TYPE_1_SIZE_BYTE) {
// Loop Erase Types 1-4
for (int i_ind = 0; i_ind < 4; i_ind++) {
sfdp_info.smptbl.erase_type_inst_arr[i_ind] = -1; // Default for unsupported type
sfdp_info.smptbl.erase_type_size_arr[i_ind] = 1
<< bptbl_ptr[SFDP_BASIC_PARAM_TABLE_ERASE_TYPE_1_SIZE_BYTE + 2 * i_ind]; // Size is 2^N where N is the table value
tr_debug("Erase Type(A) %d - Inst: 0x%xh, Size: %d", (i_ind + 1), sfdp_info.smptbl.erase_type_inst_arr[i_ind],
sfdp_info.smptbl.erase_type_size_arr[i_ind]);
if (sfdp_info.smptbl.erase_type_size_arr[i_ind] > 1) {
for (int idx = 0; idx < 4; idx++) {
sfdp_info.smptbl.erase_type_inst_arr[idx] = -1; // Default for unsupported type
sfdp_info.smptbl.erase_type_size_arr[idx] = 1
<< bptbl_ptr[SFDP_BASIC_PARAM_TABLE_ERASE_TYPE_1_SIZE_BYTE + 2 * idx]; // Size is 2^N where N is the table value
tr_debug("Erase Type(A) %d - Inst: 0x%xh, Size: %d", (idx + 1), sfdp_info.smptbl.erase_type_inst_arr[idx],
sfdp_info.smptbl.erase_type_size_arr[idx]);
if (sfdp_info.smptbl.erase_type_size_arr[idx] > 1) {
// if size==1 type is not supported
sfdp_info.smptbl.erase_type_inst_arr[i_ind] = bptbl_ptr[SFDP_BASIC_PARAM_TABLE_ERASE_TYPE_1_BYTE
+ 2 * i_ind];
sfdp_info.smptbl.erase_type_inst_arr[idx] = bptbl_ptr[SFDP_BASIC_PARAM_TABLE_ERASE_TYPE_1_BYTE
+ 2 * idx];

if ((sfdp_info.smptbl.erase_type_size_arr[i_ind] < sfdp_info.smptbl.regions_min_common_erase_size)
if ((sfdp_info.smptbl.erase_type_size_arr[idx] < sfdp_info.smptbl.regions_min_common_erase_size)
|| (sfdp_info.smptbl.regions_min_common_erase_size == 0)) {
//Set default minimal common erase for signal region
sfdp_info.smptbl.regions_min_common_erase_size = sfdp_info.smptbl.erase_type_size_arr[i_ind];
sfdp_info.smptbl.regions_min_common_erase_size = sfdp_info.smptbl.erase_type_size_arr[idx];
}
sfdp_info.smptbl.region_erase_types_bitfld[0] |= bitfield; // If there's no region map, set region "0" types bitfield as default
}

tr_debug("Erase Type %d - Inst: 0x%xh, Size: %d", (i_ind + 1), sfdp_info.smptbl.erase_type_inst_arr[i_ind],
sfdp_info.smptbl.erase_type_size_arr[i_ind]);
tr_debug("Erase Type %d - Inst: 0x%xh, Size: %d", (idx + 1), sfdp_info.smptbl.erase_type_inst_arr[idx],
sfdp_info.smptbl.erase_type_size_arr[idx]);
bitfield = bitfield << 1;
}
} else {
Expand All @@ -321,10 +381,10 @@ int sfdp_find_addr_region(bd_size_t offset, const sfdp_hdr_info &sfdp_info)
return 0;
}

for (int i_ind = sfdp_info.smptbl.region_cnt - 2; i_ind >= 0; i_ind--) {
for (int idx = sfdp_info.smptbl.region_cnt - 2; idx >= 0; idx--) {

if (offset > sfdp_info.smptbl.region_high_boundary[i_ind]) {
return (i_ind + 1);
if (offset > sfdp_info.smptbl.region_high_boundary[idx]) {
return (idx + 1);
}
}
return -1;
Expand All @@ -338,11 +398,12 @@ int sfdp_iterate_next_largest_erase_type(uint8_t &bitfield,
const sfdp_smptbl_info &smptbl)
{
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--) {

int idx;
for (idx = 3; idx >= 0; idx--) {
if (bitfield & type_mask) {
largest_erase_type = i_ind;
largest_erase_type = idx;
if ((size > (int)(smptbl.erase_type_size_arr[largest_erase_type])) &&
((smptbl.region_high_boundary[region] - offset)
> (int)(smptbl.erase_type_size_arr[largest_erase_type]))) {
Expand All @@ -354,7 +415,7 @@ int sfdp_iterate_next_largest_erase_type(uint8_t &bitfield,
type_mask = type_mask >> 1;
}

if (i_ind == 4) {
if (idx == -1) {
tr_error("No erase type was found for current region addr");
}
return largest_erase_type;
Expand Down