Skip to content

Commit

Permalink
SFDP: Add more parameters to the reader callback
Browse files Browse the repository at this point in the history
The SFDP functions parse SFDP data which is fetched by a callback
called `sfdp_reader` provided by {SPIF,QSPIF,OSPIF}BlockDevice.
Currently, this callback interface only takes a read address and an RX
buffer to store output data. This has been enough, because other SPI
parameters are always the same when fetching the SFDP table only -
they are just hardcoded in each reader.

But in the future we will add support for flash devices with multiple
configurations (in a subsequent commit), and to detect which
configuration is enabled, we will need to send detection commands
which require device-dependent SPI parameters:
* address size
* instruction
* dummy cycles

This commit
* turns the above SPI parameters from predefined/hardcoded values
into parameters of the callback
* lets the SFDP functions pass the above parameters to the callback
(Note: To read the SFDP table itself, those values are constants
defined by the standard, not tied to any particular device, so they
can be known to the SFDP functions)
* updates the callbacks implemented by {SPIF,QSPIF,OSPIF}BlockDevice
* updates the mock callback for unit tests and expectations
  • Loading branch information
LDong-Arm committed Sep 10, 2021
1 parent 2581254 commit b5e7dd9
Show file tree
Hide file tree
Showing 9 changed files with 227 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,9 @@ class OSPIFBlockDevice : public mbed::BlockDevice {
mbed::bd_size_t tx_length, const char *rx_buffer, mbed::bd_size_t rx_length);

// Send command to read from the SFDP table
int _ospi_send_read_sfdp_command(mbed::bd_addr_t addr, void *rx_buffer, mbed::bd_size_t rx_length);
int _ospi_send_read_sfdp_command(mbed::bd_addr_t addr, mbed::sfdp_cmd_addr_size_t addr_size,
uint8_t inst, uint8_t dummy_cycles,
void *rx_buffer, mbed::bd_size_t rx_length);

// Read the contents of status registers 1 and 2 into a buffer (buffer must have a length of 2)
ospi_status_t _ospi_read_status_registers(uint8_t *reg_buffer);
Expand Down Expand Up @@ -366,11 +368,11 @@ class OSPIFBlockDevice : public mbed::BlockDevice {
/* SFDP Detection and Parsing Functions */
/****************************************/
// Parse and Detect required Basic Parameters from Table
int _sfdp_parse_basic_param_table(mbed::Callback<int(mbed::bd_addr_t, void *, mbed::bd_size_t)> sfdp_reader,
int _sfdp_parse_basic_param_table(mbed::Callback<int(mbed::bd_addr_t, mbed::sfdp_cmd_addr_size_t, uint8_t, uint8_t, void *, mbed::bd_size_t)> sfdp_reader,
mbed::sfdp_hdr_info &sfdp_info);

// Parse and Detect 4-Byte Address Instruction Parameters from Table
int _sfdp_parse_4_byte_inst_table(mbed::Callback<int(mbed::bd_addr_t, void *, mbed::bd_size_t)> sfdp_reader,
int _sfdp_parse_4_byte_inst_table(mbed::Callback<int(mbed::bd_addr_t, mbed::sfdp_cmd_addr_size_t, uint8_t, uint8_t, void *, mbed::bd_size_t)> sfdp_reader,
mbed::sfdp_hdr_info &sfdp_info);

// Detect the soft reset protocol and reset - returns error if soft reset is not supported
Expand Down
57 changes: 49 additions & 8 deletions storage/blockdevice/COMPONENT_OSPIF/source/OSPIFBlockDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -921,12 +921,19 @@ int OSPIFBlockDevice::remove_csel_instance(PinName csel)
/*********************************************************/
/********** SFDP Parsing and Detection Functions *********/
/*********************************************************/
int OSPIFBlockDevice::_sfdp_parse_basic_param_table(Callback<int(bd_addr_t, void *, bd_size_t)> sfdp_reader,
int OSPIFBlockDevice::_sfdp_parse_basic_param_table(Callback<int(bd_addr_t, mbed::sfdp_cmd_addr_size_t, uint8_t, uint8_t, void *, bd_size_t)> sfdp_reader,
sfdp_hdr_info &sfdp_info)
{
uint8_t param_table[SFDP_BASIC_PARAMS_TBL_SIZE]; /* Up To 20 DWORDS = 80 Bytes */

int status = sfdp_reader(sfdp_info.bptbl.addr, param_table, sfdp_info.bptbl.size);
int status = sfdp_reader(
sfdp_info.bptbl.addr,
SFDP_READ_CMD_ADDR_TYPE,
SFDP_READ_CMD_INST,
SFDP_READ_CMD_DUMMY_CYCLES,
param_table,
sfdp_info.bptbl.size
);
if (status != OSPI_STATUS_OK) {
tr_error("Init - Read SFDP First Table Failed");
return -1;
Expand Down Expand Up @@ -1383,12 +1390,19 @@ int OSPIFBlockDevice::_sfdp_detect_reset_protocol_and_reset(uint8_t *basic_param
return status;
}

int OSPIFBlockDevice::_sfdp_parse_4_byte_inst_table(Callback<int(bd_addr_t, void *, bd_size_t)> sfdp_reader,
int OSPIFBlockDevice::_sfdp_parse_4_byte_inst_table(Callback<int(mbed::bd_addr_t, mbed::sfdp_cmd_addr_size_t, uint8_t, uint8_t, void *, mbed::bd_size_t)> sfdp_reader,
sfdp_hdr_info &sfdp_info)
{
uint8_t four_byte_inst_table[SFDP_DEFAULT_4_BYTE_INST_TABLE_SIZE_BYTES]; /* Up To 2 DWORDS = 8 Bytes */

int status = sfdp_reader(sfdp_info.fbatbl.addr, four_byte_inst_table, sfdp_info.fbatbl.size);
int status = sfdp_reader(
sfdp_info.fbatbl.addr,
SFDP_READ_CMD_ADDR_TYPE,
SFDP_READ_CMD_INST,
SFDP_READ_CMD_DUMMY_CYCLES,
four_byte_inst_table,
sfdp_info.fbatbl.size
);
if (status != OSPI_STATUS_OK) {
tr_error("Init - Read SFDP Four Byte Inst Table Failed");
return -1;
Expand Down Expand Up @@ -1823,21 +1837,48 @@ ospi_status_t OSPIFBlockDevice::_ospi_send_general_command(ospi_inst_t instructi
return OSPI_STATUS_OK;
}

int OSPIFBlockDevice::_ospi_send_read_sfdp_command(bd_addr_t addr, void *rx_buffer, bd_size_t rx_length)
int OSPIFBlockDevice::_ospi_send_read_sfdp_command(mbed::bd_addr_t addr, mbed::sfdp_cmd_addr_size_t addr_size,
uint8_t inst, uint8_t dummy_cycles,
void *rx_buffer, mbed::bd_size_t rx_length)
{
size_t rx_len = rx_length;
uint8_t *rx_buffer_tmp = (uint8_t *)rx_buffer;

// Set default here to avoid uninitialized variable warning
ospi_address_size_t address_size = _address_size;
int address = addr;
switch (addr_size) {
case SFDP_CMD_ADDR_3_BYTE:
address_size = OSPI_CFG_ADDR_SIZE_24;
break;
case SFDP_CMD_ADDR_4_BYTE:
address_size = OSPI_CFG_ADDR_SIZE_32;
break;
case SFDP_CMD_ADDR_SIZE_VARIABLE: // use current setting
break;
case SFDP_CMD_ADDR_NONE: // no address in command
address = static_cast<int>(OSPI_NO_ADDRESS_COMMAND);
break;
default:
tr_error("Invalid SFDP command address size: 0x%02X", addr_size);
return -1;
}

if (dummy_cycles == SFDP_CMD_DUMMY_CYCLES_VARIABLE) {
// use current setting
dummy_cycles = _dummy_cycles;
}

// SFDP read instruction requires 1-1-1 bus mode with 8 dummy cycles and a 3-byte address
ospi_status_t status = _ospi.configure_format(OSPI_CFG_BUS_SINGLE, OSPI_CFG_INST_SIZE_8, OSPI_CFG_BUS_SINGLE, OSPI_CFG_ADDR_SIZE_24, OSPI_CFG_BUS_SINGLE, 0, OSPI_CFG_BUS_SINGLE, OSPIF_RSFDP_DUMMY_CYCLES);
ospi_status_t status = _ospi.configure_format(OSPI_CFG_BUS_SINGLE, OSPI_CFG_INST_SIZE_8, OSPI_CFG_BUS_SINGLE, address_size, OSPI_CFG_BUS_SINGLE, 0, OSPI_CFG_BUS_SINGLE, dummy_cycles);
if (OSPI_STATUS_OK != status) {
tr_error("_ospi_configure_format failed");
return status;
}

// Don't check the read status until after we've configured the format back to 1-1-1, to avoid leaving the interface in an
// incorrect state if the read fails.
status = _ospi.read(OSPIF_INST_RSFDP, -1, (unsigned int) addr, (char *) rx_buffer, &rx_len);
size_t rx_len = rx_length;
status = _ospi.read(inst, -1, address, static_cast<char *>(rx_buffer), &rx_len);

ospi_status_t format_status = _ospi.configure_format(OSPI_CFG_BUS_SINGLE, OSPI_CFG_INST_SIZE_8, OSPI_CFG_BUS_SINGLE, _address_size, OSPI_CFG_BUS_SINGLE, 0, OSPI_CFG_BUS_SINGLE, 0);
// All commands other than Read and RSFDP use default 1-1-1 bus mode (Program/Erase are constrained by flash memory performance more than bus performance)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,9 @@ class QSPIFBlockDevice : public mbed::BlockDevice {
mbed::bd_size_t tx_length, const char *rx_buffer, mbed::bd_size_t rx_length);

// Send command to read from the SFDP table
int _qspi_send_read_sfdp_command(mbed::bd_addr_t addr, void *rx_buffer, mbed::bd_size_t rx_length);
int _qspi_send_read_sfdp_command(mbed::bd_addr_t addr, mbed::sfdp_cmd_addr_size_t addr_size,
uint8_t inst, uint8_t dummy_cycles,
void *rx_buffer, mbed::bd_size_t rx_length);

// Read the contents of status registers 1 and 2 into a buffer (buffer must have a length of 2)
qspi_status_t _qspi_read_status_registers(uint8_t *reg_buffer);
Expand Down Expand Up @@ -313,7 +315,7 @@ class QSPIFBlockDevice : public mbed::BlockDevice {
/* SFDP Detection and Parsing Functions */
/****************************************/
// Parse and Detect required Basic Parameters from Table
int _sfdp_parse_basic_param_table(mbed::Callback<int(mbed::bd_addr_t, void *, mbed::bd_size_t)> sfdp_reader,
int _sfdp_parse_basic_param_table(mbed::Callback<int(bd_addr_t, mbed::sfdp_cmd_addr_size_t, uint8_t, uint8_t, void *, bd_size_t)> sfdp_reader,
mbed::sfdp_hdr_info &sfdp_info);

// Detect the soft reset protocol and reset - returns error if soft reset is not supported
Expand Down
59 changes: 48 additions & 11 deletions storage/blockdevice/COMPONENT_QSPIF/source/QSPIFBlockDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -614,12 +614,19 @@ int QSPIFBlockDevice::remove_csel_instance(PinName csel)
/*********************************************************/
/********** SFDP Parsing and Detection Functions *********/
/*********************************************************/
int QSPIFBlockDevice::_sfdp_parse_basic_param_table(Callback<int(bd_addr_t, void *, bd_size_t)> sfdp_reader,
int QSPIFBlockDevice::_sfdp_parse_basic_param_table(Callback<int(bd_addr_t, mbed::sfdp_cmd_addr_size_t, uint8_t, uint8_t, void *, bd_size_t)> sfdp_reader,
sfdp_hdr_info &sfdp_info)
{
uint8_t param_table[SFDP_BASIC_PARAMS_TBL_SIZE]; /* Up To 20 DWORDS = 80 Bytes */

int status = sfdp_reader(sfdp_info.bptbl.addr, param_table, sfdp_info.bptbl.size);
int status = sfdp_reader(
sfdp_info.bptbl.addr,
SFDP_READ_CMD_ADDR_TYPE,
SFDP_READ_CMD_INST,
SFDP_READ_CMD_DUMMY_CYCLES,
param_table,
sfdp_info.bptbl.size
);
if (status != QSPI_STATUS_OK) {
tr_error("Init - Read SFDP First Table Failed");
return -1;
Expand Down Expand Up @@ -1405,23 +1412,53 @@ qspi_status_t QSPIFBlockDevice::_qspi_send_general_command(qspi_inst_t instructi
return QSPI_STATUS_OK;
}

int QSPIFBlockDevice::_qspi_send_read_sfdp_command(bd_addr_t addr, void *rx_buffer, bd_size_t rx_length)
int QSPIFBlockDevice::_qspi_send_read_sfdp_command(mbed::bd_addr_t addr, mbed::sfdp_cmd_addr_size_t addr_size,
uint8_t inst, uint8_t dummy_cycles,
void *rx_buffer, mbed::bd_size_t rx_length)
{
size_t rx_len = rx_length;
// Set default here to avoid uninitialized variable warning
qspi_address_size_t address_size = _address_size;
int address = addr;
switch (addr_size) {
case SFDP_CMD_ADDR_3_BYTE:
address_size = QSPI_CFG_ADDR_SIZE_24;
break;
case SFDP_CMD_ADDR_4_BYTE:
address_size = QSPI_CFG_ADDR_SIZE_32;
break;
case SFDP_CMD_ADDR_SIZE_VARIABLE: // use current setting
break;
case SFDP_CMD_ADDR_NONE: // no address in command
address = static_cast<int>(QSPI_NO_ADDRESS_COMMAND);
break;
default:
tr_error("Invalid SFDP command address size: 0x%02X", addr_size);
return -1;
}

// SFDP read instruction requires 1-1-1 bus mode with 8 dummy cycles and a 3-byte address
qspi_status_t status = _qspi.configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE, 0, QSPI_CFG_BUS_SINGLE, QSPIF_RSFDP_DUMMY_CYCLES);
if (dummy_cycles == SFDP_CMD_DUMMY_CYCLES_VARIABLE) {
// use current setting
dummy_cycles = _dummy_cycles;
}

qspi_status_t status = _qspi.configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE,
address_size, QSPI_CFG_BUS_SINGLE,
0, QSPI_CFG_BUS_SINGLE, dummy_cycles);
if (QSPI_STATUS_OK != status) {
tr_error("_qspi_configure_format failed");
return status;
}

// Don't check the read status until after we've configured the format back to 1-1-1, to avoid leaving the interface in an
// incorrect state if the read fails.
status = _qspi.read(QSPIF_INST_RSFDP, -1, (unsigned int) addr, (char *) rx_buffer, &rx_len);
// Don't check the read status until after we've configured the format back to 1-1-1,
// to avoid leaving the interface in an incorrect state if the read fails.
size_t rx_len = rx_length;
status = _qspi.read(inst, -1, address, static_cast<char *>(rx_buffer), &rx_len);

qspi_status_t format_status = _qspi.configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, _address_size, QSPI_CFG_BUS_SINGLE, 0, QSPI_CFG_BUS_SINGLE, 0);
// All commands other than Read and RSFDP use default 1-1-1 bus mode (Program/Erase are constrained by flash memory performance more than bus performance)
qspi_status_t format_status = _qspi.configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE,
address_size, QSPI_CFG_BUS_SINGLE,
0, QSPI_CFG_BUS_SINGLE, 0);
// All commands other than Read and RSFDP use default 1-1-1 bus mode
// (Program/Erase are constrained by flash memory performance more than bus performance)
if (QSPI_STATUS_OK != format_status) {
tr_error("_qspi_configure_format failed");
return format_status;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,10 +221,12 @@ class SPIFBlockDevice : public mbed::BlockDevice {
/* 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);
int _spi_send_read_sfdp_command(mbed::bd_addr_t addr, mbed::sfdp_cmd_addr_size_t addr_size,
uint8_t inst, uint8_t dummy_cycles,
void *rx_buffer, mbed::bd_size_t rx_length);

// Parse and Detect required Basic Parameters from Table
int _sfdp_parse_basic_param_table(mbed::Callback<int(mbed::bd_addr_t, void *, mbed::bd_size_t)> sfdp_reader,
int _sfdp_parse_basic_param_table(mbed::Callback<int(bd_addr_t, mbed::sfdp_cmd_addr_size_t, uint8_t, uint8_t, void *, bd_size_t)> sfdp_reader,
mbed::sfdp_hdr_info &hdr_info);

// Detect fastest read Bus mode supported by device
Expand Down
42 changes: 34 additions & 8 deletions storage/blockdevice/COMPONENT_SPIF/source/SPIFBlockDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -497,13 +497,32 @@ spif_bd_error SPIFBlockDevice::_spi_send_read_command(int read_inst, uint8_t *bu
return SPIF_BD_ERROR_OK;
}

int SPIFBlockDevice::_spi_send_read_sfdp_command(bd_addr_t addr, void *rx_buffer, bd_size_t rx_length)
int SPIFBlockDevice::_spi_send_read_sfdp_command(mbed::bd_addr_t addr, mbed::sfdp_cmd_addr_size_t addr_size,
uint8_t inst, uint8_t dummy_cycles,
void *rx_buffer, mbed::bd_size_t rx_length)
{
// Set 1-1-1 bus mode for SFDP header parsing
// Initial SFDP read tables are read with 8 dummy cycles
_dummy_and_mode_cycles = 8;
switch (addr_size) {
case SFDP_CMD_ADDR_3_BYTE:
_address_size = SPIF_ADDR_SIZE_3_BYTES;
break;
case SFDP_CMD_ADDR_4_BYTE:
_address_size = SPIF_ADDR_SIZE_4_BYTES;
break;
case SFDP_CMD_ADDR_SIZE_VARIABLE: // use current setting
break;
case SFDP_CMD_ADDR_NONE: // no address in command
addr = static_cast<int>(SPI_NO_ADDRESS_COMMAND);
break;
default:
tr_error("Invalid SFDP command address size: 0x%02X", addr_size);
return -1;
}

if (dummy_cycles != SFDP_CMD_DUMMY_CYCLES_VARIABLE) {
_dummy_and_mode_cycles = dummy_cycles;
}

int status = _spi_send_read_command(SPIF_SFDP, (uint8_t *)rx_buffer, addr, rx_length);
int status = _spi_send_read_command(inst, static_cast<uint8_t *>(rx_buffer), addr, rx_length);
if (status < 0) {
tr_error("_spi_send_read_sfdp_command failed");
}
Expand Down Expand Up @@ -588,12 +607,19 @@ spif_bd_error SPIFBlockDevice::_spi_send_general_command(int instruction, bd_add
/*********************************************************/
/********** SFDP Parsing and Detection Functions *********/
/*********************************************************/
int SPIFBlockDevice::_sfdp_parse_basic_param_table(Callback<int(bd_addr_t, void *, bd_size_t)> sfdp_reader,
mbed::sfdp_hdr_info &sfdp_info)
int SPIFBlockDevice::_sfdp_parse_basic_param_table(Callback<int(bd_addr_t, mbed::sfdp_cmd_addr_size_t, uint8_t, uint8_t, void *, bd_size_t)> sfdp_reader,
sfdp_hdr_info &sfdp_info)
{
uint8_t param_table[SFDP_BASIC_PARAMS_TBL_SIZE]; /* Up To 20 DWORDS = 80 Bytes */

int status = sfdp_reader(sfdp_info.bptbl.addr, param_table, sfdp_info.bptbl.size);
int status = sfdp_reader(
sfdp_info.bptbl.addr,
SFDP_READ_CMD_ADDR_TYPE,
SFDP_READ_CMD_INST,
SFDP_READ_CMD_DUMMY_CYCLES,
param_table,
sfdp_info.bptbl.size
);
if (status != SPIF_BD_ERROR_OK) {
tr_error("init - Read SFDP First Table Failed");
return -1;
Expand Down
20 changes: 18 additions & 2 deletions storage/blockdevice/include/blockdevice/internal/SFDP.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,22 @@ constexpr int SFDP_ERASE_BITMASK_ALL = 0x0F; ///< Erase type All

constexpr int SFDP_MAX_NUM_OF_ERASE_TYPES = 4; ///< Maximum number of different erase types (erase granularity)

// Size of a command specified by SFDP
enum sfdp_cmd_addr_size_t {
SFDP_CMD_ADDR_NONE = 0x00, // No address in command
SFDP_CMD_ADDR_3_BYTE = 0x01, // 3-byte address
SFDP_CMD_ADDR_4_BYTE = 0x02, // 4-byte address
SFDP_CMD_ADDR_SIZE_VARIABLE = 0x03 // Address size from current setting
};

// Parameters for SFDP Read command
constexpr sfdp_cmd_addr_size_t SFDP_READ_CMD_ADDR_TYPE = SFDP_CMD_ADDR_3_BYTE; // Read SFDP has 3-byte address
constexpr uint8_t SFDP_READ_CMD_INST = 0x5A; // Read SFDP instruction
constexpr uint8_t SFDP_READ_CMD_DUMMY_CYCLES = 8; // READ SFDP dummy cycles

// Special value from SFDP for using dummy cycles from current setting
constexpr uint8_t SFDP_CMD_DUMMY_CYCLES_VARIABLE = 0xF;

/** JEDEC Basic Flash Parameter Table info */
struct sfdp_bptbl_info {
uint32_t addr; ///< Address
Expand Down Expand Up @@ -92,7 +108,7 @@ struct sfdp_hdr_info {
*
* @return MBED_SUCCESS on success, negative error code on failure
*/
int sfdp_parse_headers(Callback<int(bd_addr_t, void *, bd_size_t)> sfdp_reader, sfdp_hdr_info &sfdp_info);
int sfdp_parse_headers(Callback<int(bd_addr_t, sfdp_cmd_addr_size_t, uint8_t, uint8_t, void *, bd_size_t)> sfdp_reader, sfdp_hdr_info &sfdp_info);

/** Parse Sector Map Parameter Table
* Retrieves the table from a device and parses the information contained by the table
Expand All @@ -102,7 +118,7 @@ int sfdp_parse_headers(Callback<int(bd_addr_t, void *, bd_size_t)> sfdp_reader,
*
* @return MBED_SUCCESS 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_hdr_info &sfdp_info);
int sfdp_parse_sector_map_table(Callback<int(bd_addr_t, sfdp_cmd_addr_size_t, uint8_t, uint8_t, void *, bd_size_t)> sfdp_reader, sfdp_hdr_info &sfdp_info);

/** Detect page size used for writing on flash
*
Expand Down
Loading

0 comments on commit b5e7dd9

Please sign in to comment.