From baf375f8cbbe3cba72701fd67d6c15bae2273ff3 Mon Sep 17 00:00:00 2001 From: Matthew Macovsky Date: Fri, 6 Sep 2019 18:09:21 +0100 Subject: [PATCH 1/3] Allow for arbitrary QSPI alt sizes The QSPI spec allows alt to be any size that is a multiple of the number of data lines. For example, Micron's N25Q128A uses only a single alt cycle for all read modes (1, 2, or 4 bits depending on how many data lines are in use). --- TESTS/mbed_hal/qspi/qspi_test_utils.h | 8 +- .../COMPONENT_QSPIF/QSPIFBlockDevice.cpp | 13 +- drivers/QSPI.h | 2 +- drivers/source/QSPI.cpp | 29 +++- .../direct_access_devicekey_test/main.cpp | 2 +- hal/qspi_api.h | 7 +- .../TARGET_Cypress/TARGET_PSOC6/cy_qspi_api.c | 17 +- .../psoc6csp/hal/include/cyhal_qspi.h | 11 +- .../psoc6csp/hal/src/cyhal_qspi.c | 123 +++++++++++--- targets/TARGET_STM/qspi_api.c | 154 +++++++++++++----- .../TARGET_EFM32/qspi_api.c | 6 +- 11 files changed, 266 insertions(+), 106 deletions(-) diff --git a/TESTS/mbed_hal/qspi/qspi_test_utils.h b/TESTS/mbed_hal/qspi/qspi_test_utils.h index 08f16f42c9..0c29232e51 100644 --- a/TESTS/mbed_hal/qspi/qspi_test_utils.h +++ b/TESTS/mbed_hal/qspi/qspi_test_utils.h @@ -102,10 +102,10 @@ struct Qspi { #define ADDR_SIZE_24 QSPI_CFG_ADDR_SIZE_24 #define ADDR_SIZE_32 QSPI_CFG_ADDR_SIZE_32 -#define ALT_SIZE_8 QSPI_CFG_ALT_SIZE_8 -#define ALT_SIZE_16 QSPI_CFG_ALT_SIZE_16 -#define ALT_SIZE_24 QSPI_CFG_ALT_SIZE_24 -#define ALT_SIZE_32 QSPI_CFG_ALT_SIZE_32 +#define ALT_SIZE_8 8u +#define ALT_SIZE_16 16u +#define ALT_SIZE_24 24u +#define ALT_SIZE_32 32u #define STATUS_REG QSPI_CMD_RDSR #define CONFIG_REG0 QSPI_CMD_RDCR0 diff --git a/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.cpp b/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.cpp index 7010b22cfb..bc0d424188 100644 --- a/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.cpp +++ b/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.cpp @@ -247,7 +247,7 @@ int QSPIFBlockDevice::init() // Configure BUS Mode to 1_1_1 for all commands other than Read _qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE, - QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_SINGLE, 0); + 0, QSPI_CFG_BUS_SINGLE, 0); _is_initialized = true; @@ -303,7 +303,7 @@ int QSPIFBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size) // Configure Bus for Reading _qspi_configure_format(_inst_width, _address_width, _address_size, QSPI_CFG_BUS_SINGLE, - QSPI_CFG_ALT_SIZE_8, _data_width, _dummy_and_mode_cycles); + 0, _data_width, _dummy_and_mode_cycles); if (QSPI_STATUS_OK != _qspi_send_read_command(_read_instruction, buffer, addr, size)) { status = QSPIF_BD_ERROR_DEVICE_ERROR; @@ -312,7 +312,7 @@ int QSPIFBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size) // All commands other than Read use default 1-1-1 Bus mode (Program/Erase are constrained by flash memory performance less than that of the bus) _qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE, - QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_SINGLE, 0); + 0, QSPI_CFG_BUS_SINGLE, 0); _mutex.unlock(); return status; @@ -718,7 +718,7 @@ int QSPIFBlockDevice::_sfdp_parse_sfdp_headers(uint32_t &basic_table_addr, size_ // Set 1-1-1 bus mode for SFDP header parsing _qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE, - QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_SINGLE, 8); + 0, QSPI_CFG_BUS_SINGLE, 8); qspi_status_t status = _qspi_send_read_command(QSPIF_SFDP, (char *)sfdp_header, addr /*address*/, data_length); if (status != QSPI_STATUS_OK) { @@ -885,7 +885,7 @@ int QSPIFBlockDevice::_sfdp_set_quad_enabled(uint8_t *basic_param_table_ptr) // Configure BUS Mode to 1_1_1 for all commands other than Read _qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE, - QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_SINGLE, 0); + 0, QSPI_CFG_BUS_SINGLE, 0); // Read Status Register if (QSPI_STATUS_OK == _qspi_send_general_command(_read_register_inst, QSPI_NO_ADDRESS_COMMAND, NULL, 0, @@ -1206,7 +1206,7 @@ int QSPIFBlockDevice::_enable_fast_mdoe() // Configure BUS Mode to 1_1_1 for all commands other than Read _qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE, - QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_SINGLE, 0); + 0, QSPI_CFG_BUS_SINGLE, 0); // Read Status Register if (QSPI_STATUS_OK == _qspi_send_general_command(read_conf_register_inst, QSPI_NO_ADDRESS_COMMAND, NULL, 0, @@ -1306,7 +1306,6 @@ int QSPIFBlockDevice::_utils_iterate_next_largest_erase_type(uint8_t &bitfield, tr_error("No erase type was found for current region addr"); } return largest_erase_type; - } /***************************************************/ diff --git a/drivers/QSPI.h b/drivers/QSPI.h index 4ab356a009..657be50726 100644 --- a/drivers/QSPI.h +++ b/drivers/QSPI.h @@ -106,7 +106,7 @@ public: * @param address_width Bus width used by address phase(Valid values are QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_DUAL, QSPI_CFG_BUS_QUAD) * @param address_size Size in bits used by address phase(Valid values are QSPI_CFG_ADDR_SIZE_8, QSPI_CFG_ADDR_SIZE_16, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_ADDR_SIZE_32) * @param alt_width Bus width used by alt phase(Valid values are QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_DUAL, QSPI_CFG_BUS_QUAD) - * @param alt_size Size in bits used by alt phase(Valid values are QSPI_CFG_ALT_SIZE_8, QSPI_CFG_ALT_SIZE_16, QSPI_CFG_ALT_SIZE_24, QSPI_CFG_ALT_SIZE_32) + * @param alt_size Size in bits used by alt phase (must be a multiple of the number of bus lines indicated in alt_width) * @param data_width Bus width used by data phase(Valid values are QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_DUAL, QSPI_CFG_BUS_QUAD) * @param dummy_cycles Number of dummy clock cycles to be used after alt phase * diff --git a/drivers/source/QSPI.cpp b/drivers/source/QSPI.cpp index c79c949e3b..839c2f1e63 100644 --- a/drivers/source/QSPI.cpp +++ b/drivers/source/QSPI.cpp @@ -26,6 +26,21 @@ namespace mbed { QSPI *QSPI::_owner = NULL; SingletonPtr QSPI::_mutex; +uint8_t convert_bus_width_to_line_count(qspi_bus_width_t width) +{ + switch (width) { + case QSPI_CFG_BUS_SINGLE: + return 1; + case QSPI_CFG_BUS_DUAL: + return 2; + case QSPI_CFG_BUS_QUAD: + return 4; + default: + // Unrecognized bus width + return 0; + } +} + QSPI::QSPI(PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, PinName ssel, int mode) : _qspi() { _qspi_io0 = io0; @@ -38,7 +53,7 @@ QSPI::QSPI(PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, Pin _address_width = QSPI_CFG_BUS_SINGLE; _address_size = QSPI_CFG_ADDR_SIZE_24; _alt_width = QSPI_CFG_BUS_SINGLE; - _alt_size = QSPI_CFG_ALT_SIZE_8; + _alt_size = 0; _data_width = QSPI_CFG_BUS_SINGLE; _num_dummy_cycles = 0; _mode = mode; @@ -52,7 +67,14 @@ QSPI::QSPI(PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, Pin qspi_status_t QSPI::configure_format(qspi_bus_width_t inst_width, qspi_bus_width_t address_width, qspi_address_size_t address_size, qspi_bus_width_t alt_width, qspi_alt_size_t alt_size, qspi_bus_width_t data_width, int dummy_cycles) { - qspi_status_t ret_status = QSPI_STATUS_OK; + // Check that alt_size/alt_width are a valid combination + uint8_t alt_lines = convert_bus_width_to_line_count(alt_width); + if (alt_lines == 0) { + return QSPI_STATUS_ERROR; + } else if (alt_size % alt_lines != 0) { + // Invalid alt size/width combination (alt size is not a multiple of the number of bus lines used to transmit it) + return QSPI_STATUS_ERROR; + } lock(); _inst_width = inst_width; @@ -62,10 +84,9 @@ qspi_status_t QSPI::configure_format(qspi_bus_width_t inst_width, qspi_bus_width _alt_size = alt_size; _data_width = data_width; _num_dummy_cycles = dummy_cycles; - unlock(); - return ret_status; + return QSPI_STATUS_OK; } qspi_status_t QSPI::set_frequency(int hz) diff --git a/features/storage/TESTS/kvstore/direct_access_devicekey_test/main.cpp b/features/storage/TESTS/kvstore/direct_access_devicekey_test/main.cpp index ba3fb6bb63..cf6a60f9f8 100644 --- a/features/storage/TESTS/kvstore/direct_access_devicekey_test/main.cpp +++ b/features/storage/TESTS/kvstore/direct_access_devicekey_test/main.cpp @@ -255,7 +255,7 @@ void test_direct_access_to_device_inject_root() ret = devkey.device_inject_root_of_trust(key, DEVICE_KEY_16BYTE); TEST_ASSERT_EQUAL_INT(DEVICEKEY_SUCCESS, ret); - // Now use Direct Access To DeviceKey to retrieve it */ + // Now use Direct Access To DeviceKey to retrieve it uint32_t internal_start_address; uint32_t internal_rbp_size; bool is_conf_tdb_internal = false; diff --git a/hal/qspi_api.h b/hal/qspi_api.h index 8464c2d6b2..8314c5bb7f 100644 --- a/hal/qspi_api.h +++ b/hal/qspi_api.h @@ -60,12 +60,7 @@ typedef enum qspi_address_size { /** Alternative size in bits */ -typedef enum qspi_alt_size { - QSPI_CFG_ALT_SIZE_8, - QSPI_CFG_ALT_SIZE_16, - QSPI_CFG_ALT_SIZE_24, - QSPI_CFG_ALT_SIZE_32, -} qspi_alt_size_t; +typedef uint8_t qspi_alt_size_t; /** QSPI command * diff --git a/targets/TARGET_Cypress/TARGET_PSOC6/cy_qspi_api.c b/targets/TARGET_Cypress/TARGET_PSOC6/cy_qspi_api.c index cd28b08844..3404dcc75d 100644 --- a/targets/TARGET_Cypress/TARGET_PSOC6/cy_qspi_api.c +++ b/targets/TARGET_Cypress/TARGET_PSOC6/cy_qspi_api.c @@ -69,21 +69,6 @@ static inline cyhal_qspi_size_t cyhal_qspi_convert_addr_size(qspi_address_size_t } } -static inline cyhal_qspi_size_t cyhal_qspi_convert_alt_size(qspi_alt_size_t size) -{ - switch (size) { - case QSPI_CFG_ALT_SIZE_8: - return CYHAL_QSPI_CFG_SIZE_8; - case QSPI_CFG_ALT_SIZE_16: - return CYHAL_QSPI_CFG_SIZE_16; - case QSPI_CFG_ALT_SIZE_24: - return CYHAL_QSPI_CFG_SIZE_24; - default: // fallthrough - case QSPI_CFG_ALT_SIZE_32: - return CYHAL_QSPI_CFG_SIZE_32; - } -} - static void cyhal_qspi_convert_command(const qspi_command_t *from, cyhal_qspi_command_t *to) { to->instruction.bus_width = cyhal_qspi_convert_width(from->instruction.bus_width); @@ -94,7 +79,7 @@ static void cyhal_qspi_convert_command(const qspi_command_t *from, cyhal_qspi_co to->address.value = from->address.value; to->address.disabled = from->address.disabled; to->mode_bits.bus_width = cyhal_qspi_convert_width(from->alt.bus_width); - to->mode_bits.size = cyhal_qspi_convert_alt_size(from->alt.size); + to->mode_bits.size = from->alt.size; to->mode_bits.value = from->alt.value; to->mode_bits.disabled = from->alt.disabled; to->dummy_count = from->dummy_count; diff --git a/targets/TARGET_Cypress/TARGET_PSOC6/psoc6csp/hal/include/cyhal_qspi.h b/targets/TARGET_Cypress/TARGET_PSOC6/psoc6csp/hal/include/cyhal_qspi.h index b3ba4d9123..bf67b38452 100644 --- a/targets/TARGET_Cypress/TARGET_PSOC6/psoc6csp/hal/include/cyhal_qspi.h +++ b/targets/TARGET_Cypress/TARGET_PSOC6/psoc6csp/hal/include/cyhal_qspi.h @@ -71,9 +71,12 @@ typedef enum { } cyhal_qspi_event_t; #define CYHAL_QSPI_RSLT_ERR_BUS_WIDTH (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_QSPI, 0)) /**< Bus width Error. >*/ -#define CYHAL_QSPI_RSLT_ERR_PIN (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_QSPI, 1)) /**< Pin related Error. >*/ -#define CYHAL_QSPI_RSLT_ERR_DATA_SEL (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_QSPI, 2)) /**< Data select Error. >*/ -#define CYHAL_QSPI_RSLT_ERR_INSTANCE (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_QSPI, 3)) /**< QSPI instance related Error. >*/ +#define CYHAL_QSPI_RSLT_ERR_SIZE (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_QSPI, 1)) /**< Size Error. >*/ +#define CYHAL_QSPI_RSLT_ERR_PIN (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_QSPI, 2)) /**< Pin related Error. >*/ +#define CYHAL_QSPI_RSLT_ERR_DATA_SEL (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_QSPI, 3)) /**< Data select Error. >*/ +#define CYHAL_QSPI_RSLT_ERR_INSTANCE (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_QSPI, 4)) /**< QSPI instance related Error. >*/ +#define CYHAL_QSPI_RSLT_ERR_ALT_SIZE_WIDTH_MISMATCH (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_QSPI, 5)) /**< Provided alt size is incompatible with provided alt width. >*/ +#define CYHAL_QSPI_RSLT_ERR_ALT_SIZE_DUMMY_CYCLES_MISMATCH (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_QSPI, 6)) /**< Provided alt size is incompatible with provided number of dummy cycles (due to device-specific restrictions). >*/ /** @brief QSPI command settings */ typedef struct cyhal_qspi_command { @@ -90,7 +93,7 @@ typedef struct cyhal_qspi_command { } address; struct { cyhal_qspi_bus_width_t bus_width; /**< Bus width for mode bits >*/ - cyhal_qspi_size_t size; /**< Mode bits size >*/ + uint8_t size; /**< Mode bits size >*/ uint32_t value; /**< Mode bits value >*/ bool disabled; /**< Mode bits phase skipped if disabled is set to true >*/ } mode_bits; diff --git a/targets/TARGET_Cypress/TARGET_PSOC6/psoc6csp/hal/src/cyhal_qspi.c b/targets/TARGET_Cypress/TARGET_PSOC6/psoc6csp/hal/src/cyhal_qspi.c index 2842e62347..5c4c852a6d 100644 --- a/targets/TARGET_Cypress/TARGET_PSOC6/psoc6csp/hal/src/cyhal_qspi.c +++ b/targets/TARGET_Cypress/TARGET_PSOC6/psoc6csp/hal/src/cyhal_qspi.c @@ -292,16 +292,45 @@ static inline uint32_t get_size(cyhal_qspi_size_t hal_size) return ((uint32_t)hal_size >> 3); /* convert bits to bytes */ } +/* cyhal_qspi_bus_width_t to number of bus lines used */ +static uint8_t get_lines(cyhal_qspi_bus_width_t hal_width) +{ + uint8_t lines; + + switch (hal_width) + { + case CYHAL_QSPI_CFG_BUS_SINGLE: + lines = 1; + break; + case CYHAL_QSPI_CFG_BUS_DUAL: + lines = 2; + break; + case CYHAL_QSPI_CFG_BUS_QUAD: + lines = 4; + break; + case CYHAL_QSPI_CFG_BUS_OCTAL: + lines = 8; + break; + default: + lines = 0; + } + + return lines; +} + /* Sends QSPI command with certain set of data */ /* Address passed through 'command' is not used, instead the value in 'addr' is used. */ static cy_rslt_t qspi_command_transfer(cyhal_qspi_t *obj, const cyhal_qspi_command_t *command, - uint32_t addr, bool endOfTransfer) + uint32_t addr, bool endOfTransfer, uint8_t *dummy_cycles) { /* max address size is 4 bytes and max mode bits size is 4 bytes */ uint8_t cmd_param[8] = {0}; uint32_t start_pos = 0; uint32_t addr_size = 0; - uint32_t mode_bits_size = 0; + uint32_t mode_size = 0; + uint8_t leftover_bits = 0; + uint8_t lines = 0; + uint8_t integrated_dummy_cycles = 0; cy_en_smif_txfr_width_t bus_width = CY_SMIF_WIDTH_SINGLE; cy_stc_smif_mem_cmd_t cyhal_cmd_config; cy_rslt_t result = CY_RSLT_SUCCESS; @@ -332,22 +361,67 @@ static cy_rslt_t qspi_command_transfer(cyhal_qspi_t *obj, const cyhal_qspi_comma if (!command->address.disabled) { addr_size = get_size(command->address.size); - uint32_to_byte_array(addr, cmd_param, start_pos, addr_size); - start_pos += addr_size; - bus_width = cyhal_cmd_config.addrWidth; + if (addr_size == 0) + { + result = CYHAL_QSPI_RSLT_ERR_SIZE; + } + else + { + uint32_to_byte_array(addr, cmd_param, start_pos, addr_size); + start_pos += addr_size; + bus_width = cyhal_cmd_config.addrWidth; + } } if (!command->mode_bits.disabled) { - mode_bits_size = get_size(command->mode_bits.size); - uint32_to_byte_array(cyhal_cmd_config.mode, cmd_param, start_pos, mode_bits_size); - bus_width = cyhal_cmd_config.modeWidth; + // Mode size must be a multiple of the number of bus lines used (i.e. a whole number of cycles) + lines = get_lines(command->mode_bits.bus_width); + if (lines == 0) + { + result = CYHAL_QSPI_RSLT_ERR_BUS_WIDTH; + } + else if (command->mode_bits.size % lines != 0) + { + result = CYHAL_QSPI_RSLT_ERR_ALT_SIZE_WIDTH_MISMATCH; + } + else + { + // Round mode size up to nearest byte - unused parts of byte act as dummy cycles + mode_size = get_size(command->mode_bits.size - 1) + 1; + + // Unused bits in most significant byte of mode + leftover_bits = (mode_size << 3) - command->mode_bits.size; + if (leftover_bits != 0) + { + // Account for dummy cycles that will be spent in the mode portion of the command + integrated_dummy_cycles = (8 - (command->mode_bits.size % 8)) / lines; + if (*dummy_cycles < integrated_dummy_cycles) + { + // Not enough dummy cycles to account for a short mode + result = CYHAL_QSPI_RSLT_ERR_ALT_SIZE_DUMMY_CYCLES_MISMATCH; + } + else + { + *dummy_cycles -= integrated_dummy_cycles; + } + + // Align mode value to the end of the most significant byte + cyhal_cmd_config.mode <<= leftover_bits; + } + + uint32_to_byte_array(cyhal_cmd_config.mode, cmd_param, start_pos, mode_size); + bus_width = cyhal_cmd_config.modeWidth; + } } - uint32_t cmpltTxfr = ((endOfTransfer) ? 1UL : 0UL); - result = (cy_rslt_t)Cy_SMIF_TransmitCommand(obj->base, cyhal_cmd_config.command, - cyhal_cmd_config.cmdWidth, cmd_param, (addr_size + mode_bits_size), - bus_width, obj->slave_select, cmpltTxfr, &obj->context); + if (CY_RSLT_SUCCESS == result) + { + uint32_t cmpltTxfr = ((endOfTransfer) ? 1UL : 0UL); + result = (cy_rslt_t)Cy_SMIF_TransmitCommand(obj->base, cyhal_cmd_config.command, + cyhal_cmd_config.cmdWidth, cmd_param, (addr_size + mode_size), + bus_width, obj->slave_select, cmpltTxfr, &obj->context); + } } return result; } @@ -810,6 +884,7 @@ cy_rslt_t cyhal_qspi_read(cyhal_qspi_t *obj, const cyhal_qspi_command_t *command uint32_t chunk = 0; size_t read_bytes = *length; uint32_t addr = command->address.value; + uint8_t dummy_cycles = command->dummy_count; /* SMIF can read only up to 65536 bytes in one go. Split the larger read into multiple chunks */ while (read_bytes > 0) @@ -823,11 +898,11 @@ cy_rslt_t cyhal_qspi_read(cyhal_qspi_t *obj, const cyhal_qspi_command_t *command * to create a copy of the command object. Instead of copying the object, the address is * passed separately. */ - status = qspi_command_transfer(obj, command, addr, false); + status = qspi_command_transfer(obj, command, addr, false, &dummy_cycles); if (CY_RSLT_SUCCESS == status) { - if (command->dummy_count > 0u) + if (dummy_cycles > 0u) { status = (cy_rslt_t)Cy_SMIF_SendDummyCycles(obj->base, command->dummy_count); } @@ -852,13 +927,15 @@ cy_rslt_t cyhal_qspi_read(cyhal_qspi_t *obj, const cyhal_qspi_command_t *command cy_rslt_t cyhal_qspi_read_async(cyhal_qspi_t *obj, const cyhal_qspi_command_t *command, void *data, size_t *length) { - cy_rslt_t status = qspi_command_transfer(obj, command, command->address.value, false); - + cy_rslt_t status = CY_RSLT_SUCCESS; + uint32_t addr = command->address.value; + uint8_t dummy_cycles = command->dummy_count; + status = qspi_command_transfer(obj, command, addr, false, &dummy_cycles); if (CY_RSLT_SUCCESS == status) { if (command->dummy_count > 0u) { - status = (cy_rslt_t)Cy_SMIF_SendDummyCycles(obj->base, command->dummy_count); + status = (cy_rslt_t)Cy_SMIF_SendDummyCycles(obj->base, dummy_cycles); } if (CY_RSLT_SUCCESS == status) @@ -873,13 +950,14 @@ cy_rslt_t cyhal_qspi_read_async(cyhal_qspi_t *obj, const cyhal_qspi_command_t *c /* length can be up to 65536. */ cy_rslt_t cyhal_qspi_write(cyhal_qspi_t *obj, const cyhal_qspi_command_t *command, const void *data, size_t *length) { - cy_rslt_t status = qspi_command_transfer(obj, command, command->address.value, false); + uint8_t dummy_cycles = command->dummy_count; + cy_rslt_t status = qspi_command_transfer(obj, command, command->address.value, false, &dummy_cycles); if (CY_RSLT_SUCCESS == status) { if (command->dummy_count > 0u) { - status = (cy_rslt_t)Cy_SMIF_SendDummyCycles(obj->base, command->dummy_count); + status = (cy_rslt_t)Cy_SMIF_SendDummyCycles(obj->base, dummy_cycles); } if ((CY_SMIF_SUCCESS == status) && (*length > 0)) @@ -895,13 +973,14 @@ cy_rslt_t cyhal_qspi_write(cyhal_qspi_t *obj, const cyhal_qspi_command_t *comman /* length can be up to 65536. */ cy_rslt_t cyhal_qspi_write_async(cyhal_qspi_t *obj, const cyhal_qspi_command_t *command, const void *data, size_t *length) { - cy_rslt_t status = qspi_command_transfer(obj, command, command->address.value, false); + uint8_t dummy_cycles = command->dummy_count; + cy_rslt_t status = qspi_command_transfer(obj, command, command->address.value, false, &dummy_cycles); if (CY_RSLT_SUCCESS == status) { if (command->dummy_count > 0u) { - status = (cy_rslt_t)Cy_SMIF_SendDummyCycles(obj->base, command->dummy_count); + status = (cy_rslt_t)Cy_SMIF_SendDummyCycles(obj->base, dummy_cycles); } if ((CY_SMIF_SUCCESS == status) && (*length > 0)) @@ -922,7 +1001,7 @@ cy_rslt_t cyhal_qspi_transfer( if ((tx_data == NULL || tx_size == 0) && (rx_data == NULL || rx_size == 0)) { /* only command, no rx or tx */ - status = qspi_command_transfer(obj, command, command->address.value, true); + status = qspi_command_transfer(obj, command, command->address.value, true, NULL); } else { diff --git a/targets/TARGET_STM/qspi_api.c b/targets/TARGET_STM/qspi_api.c index 789bdaba49..e0e4fc759b 100644 --- a/targets/TARGET_STM/qspi_api.c +++ b/targets/TARGET_STM/qspi_api.c @@ -43,7 +43,7 @@ #define QSPI_FLASH_SIZE_DEFAULT 0x80000000 #if defined(OCTOSPI1) -void qspi_prepare_command(const qspi_command_t *command, OSPI_RegularCmdTypeDef *st_command) +qspi_status_t qspi_prepare_command(const qspi_command_t *command, OSPI_RegularCmdTypeDef *st_command) { debug_if(qspi_api_c_debug, "qspi_prepare_command In: instruction.value %x dummy_count %x address.bus_width %x address.disabled %x address.value %x address.size %x\n", command->instruction.value, command->dummy_count, command->address.bus_width, command->address.disabled, command->address.value, command->address.size); @@ -66,8 +66,8 @@ void qspi_prepare_command(const qspi_command_t *command, OSPI_RegularCmdTypeDef st_command->InstructionMode = HAL_OSPI_INSTRUCTION_4_LINES; break; default: - error("Command param error: wrong istruction format\n"); - break; + error("Command param error: wrong instruction format\n"); + return QSPI_STATUS_ERROR; } } @@ -99,7 +99,7 @@ void qspi_prepare_command(const qspi_command_t *command, OSPI_RegularCmdTypeDef break; default: error("Command param error: wrong address size\n"); - break; + return QSPI_STATUS_ERROR; } switch(command->address.size) { case QSPI_CFG_ADDR_SIZE_8: @@ -116,7 +116,7 @@ void qspi_prepare_command(const qspi_command_t *command, OSPI_RegularCmdTypeDef break; default: error("Command param error: wrong address size\n"); - break; + return QSPI_STATUS_ERROR; } } @@ -124,39 +124,62 @@ void qspi_prepare_command(const qspi_command_t *command, OSPI_RegularCmdTypeDef st_command->AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; st_command->AlternateBytesSize = 0; } else { - st_command->AlternateBytes = command->alt.value; + uint8_t alt_lines = 0; switch (command->alt.bus_width) { case QSPI_CFG_BUS_SINGLE: st_command->AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_1_LINE; + alt_lines = 1; break; case QSPI_CFG_BUS_DUAL: st_command->AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_2_LINES; + alt_lines = 2; break; case QSPI_CFG_BUS_QUAD: st_command->AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_4_LINES; + alt_lines = 4; break; default: st_command->AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; - break; + error("Command param error: invalid alt bytes mode\n"); + return QSPI_STATUS_ERROR; } - switch(command->alt.size) { - case QSPI_CFG_ALT_SIZE_8: - st_command->AlternateBytesSize = HAL_OSPI_ALTERNATE_BYTES_8_BITS; - break; - case QSPI_CFG_ALT_SIZE_16: - st_command->AlternateBytesSize = HAL_OSPI_ALTERNATE_BYTES_16_BITS; - break; - case QSPI_CFG_ALT_SIZE_24: - st_command->AlternateBytesSize = HAL_OSPI_ALTERNATE_BYTES_24_BITS; - break; - case QSPI_CFG_ALT_SIZE_32: - st_command->AlternateBytesSize = HAL_OSPI_ALTERNATE_BYTES_32_BITS; - break; - default: - st_command->AlternateBytesSize = 0; - printf("Command param error: wrong address size\n"); - break; + + // Alt size must be a multiple of the number of bus lines used (i.e. a whole number of cycles) + if (command->alt.size % alt_lines != 0) { + error("Command param error: incompatible alt size and alt bus width\n"); + return QSPI_STATUS_ERROR; } + + // Round up to nearest byte - unused parts of byte act as dummy cycles + uint32_t rounded_size = ((command->alt.size - 1) >> 3) + 1; + // Maximum of 4 alt bytes + if (rounded_size > 4) { + error("Command param error: alt size exceeds maximum of 32 bits\n"); + return QSPI_STATUS_ERROR; + } + + // Unused bits in most significant byte of alt + uint8_t leftover_bits = (rounded_size << 3) - command->alt.size; + if (leftover_bits != 0) { + // Account for dummy cycles that will be spent in the alt portion of the command + uint8_t integrated_dummy_cycles = leftover_bits / alt_lines; + if (st_command->DummyCycles < integrated_dummy_cycles) + { + // Not enough dummy cycles to account for a short alt + error("Command param error: not enough dummy cycles to make up for given alt size\n"); + return QSPI_STATUS_ERROR; + } + st_command->DummyCycles -= integrated_dummy_cycles; + + // Align alt value to the end of the most significant byte + st_command->AlternateBytes = command->alt.value << leftover_bits; + } else { + st_command->AlternateBytes = command->alt.value; + } + + /* command->AlternateBytesSize needs to be shifted by OCTOSPI_CCR_ABSIZE_Pos */ + // 0b00 = 1 byte, 0b01 = 2 bytes, 0b10 = 3 bytes, 0b11 = 4 bytes + st_command->AlternateBytesSize = ((rounded_size - 1) << OCTOSPI_CCR_ABSIZE_Pos) & OCTOSPI_CCR_ABSIZE_Msk; } switch (command->data.bus_width) { @@ -176,9 +199,11 @@ void qspi_prepare_command(const qspi_command_t *command, OSPI_RegularCmdTypeDef debug_if(qspi_api_c_debug, "qspi_prepare_command Out: InstructionMode %x Instruction %x AddressMode %x AddressSize %x Address %x DataMode %x\n", st_command->InstructionMode, st_command->Instruction, st_command->AddressMode, st_command->AddressSize, st_command->Address, st_command->DataMode); + + return QSPI_STATUS_OK; } #else /* OCTOSPI */ -void qspi_prepare_command(const qspi_command_t *command, QSPI_CommandTypeDef *st_command) +qspi_status_t qspi_prepare_command(const qspi_command_t *command, QSPI_CommandTypeDef *st_command) { debug_if(qspi_api_c_debug, "qspi_prepare_command In: instruction.value %x dummy_count %x address.bus_width %x address.disabled %x address.value %x address.size %x\n", command->instruction.value, command->dummy_count, command->address.bus_width, command->address.disabled, command->address.value, command->address.size); @@ -230,15 +255,19 @@ void qspi_prepare_command(const qspi_command_t *command, QSPI_CommandTypeDef *st st_command->AddressSize = (command->address.size << QUADSPI_CCR_ADSIZE_Pos) & QUADSPI_CCR_ADSIZE_Msk; } + uint8_t alt_lines = 0; switch (command->alt.bus_width) { case QSPI_CFG_BUS_SINGLE: st_command->AlternateByteMode = QSPI_ALTERNATE_BYTES_1_LINE; + alt_lines = 1; break; case QSPI_CFG_BUS_DUAL: st_command->AlternateByteMode = QSPI_ALTERNATE_BYTES_2_LINES; + alt_lines = 2; break; case QSPI_CFG_BUS_QUAD: st_command->AlternateByteMode = QSPI_ALTERNATE_BYTES_4_LINES; + alt_lines = 4; break; default: st_command->AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; @@ -249,10 +278,40 @@ void qspi_prepare_command(const qspi_command_t *command, QSPI_CommandTypeDef *st st_command->AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; st_command->AlternateBytesSize = 0; } else { - st_command->AlternateBytes = command->alt.value; + // Alt size must be a multiple of the number of bus lines used (i.e. a whole number of cycles) + if ((alt_lines == 0) || (command->alt.size % alt_lines != 0)) { + return QSPI_STATUS_ERROR; + } + + // Round up to nearest byte - unused parts of byte act as dummy cycles + uint32_t rounded_size = ((command->alt.size - 1) >> 3) + 1; + // Maximum of 4 alt bytes + if (rounded_size > 4) { + return QSPI_STATUS_ERROR; + } + + // Unused bits in most significant byte of alt + uint8_t leftover_bits = (rounded_size << 3) - command->alt.size; + if (leftover_bits != 0) { + // Account for dummy cycles that will be spent in the alt portion of the command + uint8_t integrated_dummy_cycles = leftover_bits / alt_lines; + if (st_command->DummyCycles < integrated_dummy_cycles) + { + // Not enough dummy cycles to account for a short alt + return QSPI_STATUS_ERROR; + } + st_command->DummyCycles -= integrated_dummy_cycles; + + // Align alt value to the end of the most significant byte + st_command->AlternateBytes = command->alt.value << leftover_bits; + } else { + rounded_size -= 1; + st_command->AlternateBytes = command->alt.value; + } + /* command->AlternateBytesSize needs to be shifted by QUADSPI_CCR_ABSIZE_Pos */ - st_command->AlternateBytesSize = (command->alt.size << QUADSPI_CCR_ABSIZE_Pos) & QUADSPI_CCR_ABSIZE_Msk; - st_command->AlternateBytesSize = command->alt.size; + // 0b00 = 1 byte, 0b01 = 2 bytes, 0b10 = 3 bytes, 0b11 = 4 bytes + st_command->AlternateBytesSize = ((rounded_size - 1) << QUADSPI_CCR_ABSIZE_Pos) & QUADSPI_CCR_ABSIZE_Msk; } switch (command->data.bus_width) { @@ -271,8 +330,11 @@ void qspi_prepare_command(const qspi_command_t *command, QSPI_CommandTypeDef *st } st_command->NbData = 0; + debug_if(qspi_api_c_debug, "qspi_prepare_command Out: InstructionMode %x Instruction %x AddressMode %x AddressSize %x Address %x DataMode %x\n", st_command->InstructionMode, st_command->Instruction, st_command->AddressMode, st_command->AddressSize, st_command->Address, st_command->DataMode); + + return QSPI_STATUS_OK; } #endif /* OCTOSPI */ @@ -586,10 +648,12 @@ qspi_status_t qspi_write(qspi_t *obj, const qspi_command_t *command, const void debug_if(qspi_api_c_debug, "qspi_write size %u\n", *length); OSPI_RegularCmdTypeDef st_command; - qspi_prepare_command(command, &st_command); + qspi_status_t status = qspi_prepare_command(command, &st_command); + if (status != QSPI_STATUS_OK) { + return status; + } st_command.NbData = *length; - qspi_status_t status = QSPI_STATUS_OK; if (HAL_OSPI_Command(&obj->handle, &st_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { debug_if(qspi_api_c_debug, "HAL_OSPI_Command error\n"); @@ -607,10 +671,12 @@ qspi_status_t qspi_write(qspi_t *obj, const qspi_command_t *command, const void qspi_status_t qspi_write(qspi_t *obj, const qspi_command_t *command, const void *data, size_t *length) { QSPI_CommandTypeDef st_command; - qspi_prepare_command(command, &st_command); + qspi_status_t status = qspi_prepare_command(command, &st_command); + if (status != QSPI_STATUS_OK) { + return status; + } st_command.NbData = *length; - qspi_status_t status = QSPI_STATUS_OK; if (HAL_QSPI_Command(&obj->handle, &st_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { status = QSPI_STATUS_ERROR; @@ -631,10 +697,12 @@ qspi_status_t qspi_write(qspi_t *obj, const qspi_command_t *command, const void qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, size_t *length) { OSPI_RegularCmdTypeDef st_command; - qspi_prepare_command(command, &st_command); + qspi_status_t status = qspi_prepare_command(command, &st_command); + if (status != QSPI_STATUS_OK) { + return status; + } st_command.NbData = *length; - qspi_status_t status = QSPI_STATUS_OK; if (HAL_OSPI_Command(&obj->handle, &st_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { debug_if(qspi_api_c_debug, "HAL_OSPI_Command error\n"); @@ -654,10 +722,12 @@ qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, size_t *length) { QSPI_CommandTypeDef st_command; - qspi_prepare_command(command, &st_command); - + qspi_status_t status = qspi_prepare_command(command, &st_command); + if (status != QSPI_STATUS_OK) { + return status; + } + st_command.NbData = *length; - qspi_status_t status = QSPI_STATUS_OK; if (HAL_QSPI_Command(&obj->handle, &st_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { status = QSPI_STATUS_ERROR; @@ -683,7 +753,10 @@ qspi_status_t qspi_command_transfer(qspi_t *obj, const qspi_command_t *command, if ((tx_data == NULL || tx_size == 0) && (rx_data == NULL || rx_size == 0)) { // only command, no rx or tx OSPI_RegularCmdTypeDef st_command; - qspi_prepare_command(command, &st_command); + status = qspi_prepare_command(command, &st_command); + if (status != QSPI_STATUS_OK) { + return status; + } st_command.NbData = 1; st_command.DataMode = HAL_OSPI_DATA_NONE; /* Instruction only */ @@ -720,7 +793,10 @@ qspi_status_t qspi_command_transfer(qspi_t *obj, const qspi_command_t *command, if ((tx_data == NULL || tx_size == 0) && (rx_data == NULL || rx_size == 0)) { // only command, no rx or tx QSPI_CommandTypeDef st_command; - qspi_prepare_command(command, &st_command); + status = qspi_prepare_command(command, &st_command); + if (status != QSPI_STATUS_OK) { + return status; + } st_command.NbData = 1; st_command.DataMode = QSPI_DATA_NONE; /* Instruction only */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/qspi_api.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/qspi_api.c index 1435751b1b..75f988b6a4 100644 --- a/targets/TARGET_Silicon_Labs/TARGET_EFM32/qspi_api.c +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/qspi_api.c @@ -33,6 +33,8 @@ #include "PeripheralPins.h" #include "pinmap_function.h" +#define SUPPORTED_ALT_SIZE 8u + qspi_status_t qspi_init(qspi_t *obj, PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, PinName ssel, uint32_t hz, uint8_t mode) { @@ -268,7 +270,7 @@ qspi_status_t qspi_command_transfer(qspi_t *obj, const qspi_command_t *command, cfg.modeBitEnable = true; obj->instance->MODEBITCONFIG = command->alt.value & _QSPI_MODEBITCONFIG_MODE_MASK; - if(command->alt.size != QSPI_CFG_ALT_SIZE_8) { + if(command->alt.size != SUPPORTED_ALT_SIZE) { //do not support 'alt' bigger than 8 bit return QSPI_STATUS_INVALID_PARAMETER; } @@ -338,7 +340,7 @@ qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, obj->instance->DEVINSTRRDCONFIG |= QSPI_DEVINSTRRDCONFIG_MODEBITENABLE; obj->instance->MODEBITCONFIG = command->alt.value & _QSPI_MODEBITCONFIG_MODE_MASK; - if(command->alt.size != QSPI_CFG_ALT_SIZE_8) { + if(command->alt.size != SUPPORTED_ALT_SIZE) { // Do not support 'alt' bigger than 8 bit return QSPI_STATUS_INVALID_PARAMETER; } From 9b32c0f316f6d0bbe4a9a99c8ed76d8df5573356 Mon Sep 17 00:00:00 2001 From: Kyle Kearney Date: Mon, 30 Sep 2019 16:00:24 -0700 Subject: [PATCH 2/3] Fix possible negative QSPI alt count on STM Remove an extraneous decrement operation in cases where the alt bits size is a multiple of 8. --- targets/TARGET_STM/qspi_api.c | 1 - 1 file changed, 1 deletion(-) diff --git a/targets/TARGET_STM/qspi_api.c b/targets/TARGET_STM/qspi_api.c index e0e4fc759b..8528968c74 100644 --- a/targets/TARGET_STM/qspi_api.c +++ b/targets/TARGET_STM/qspi_api.c @@ -305,7 +305,6 @@ qspi_status_t qspi_prepare_command(const qspi_command_t *command, QSPI_CommandTy // Align alt value to the end of the most significant byte st_command->AlternateBytes = command->alt.value << leftover_bits; } else { - rounded_size -= 1; st_command->AlternateBytes = command->alt.value; } From 6bba46e48fe8f1430bc787835fa2b1cd7880a953 Mon Sep 17 00:00:00 2001 From: Matthew Macovsky Date: Thu, 22 Aug 2019 18:13:58 -0500 Subject: [PATCH 3/3] Differentiate alt and dummy cycles in QSPIF Propagate separate alt cycle and dummy cycle counts from QSPIFBlockDevice down to the qspi driver, so that drivers which handle the two separately have enough information to do so. --- .../COMPONENT_QSPIF/QSPIFBlockDevice.cpp | 44 +++++++++++-------- .../COMPONENT_QSPIF/QSPIFBlockDevice.h | 6 ++- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.cpp b/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.cpp index bc0d424188..daebef73d4 100644 --- a/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.cpp +++ b/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.cpp @@ -36,6 +36,7 @@ using namespace mbed; #define UINT64_MAX -1 #endif #define QSPI_NO_ADDRESS_COMMAND UINT64_MAX +#define QSPI_ALT_DEFAULT_VALUE 0 // Status Register Bits #define QSPIF_STATUS_BIT_WIP 0x1 //Write In Progress #define QSPIF_STATUS_BIT_WEL 0x2 // Write Enable Latch @@ -168,12 +169,12 @@ int QSPIFBlockDevice::init() _inst_width = QSPI_CFG_BUS_SINGLE; _address_width = QSPI_CFG_BUS_SINGLE; _address_size = QSPI_CFG_ADDR_SIZE_24; + _alt_size = 0; + _dummy_cycles = 0; _data_width = QSPI_CFG_BUS_SINGLE; - _dummy_and_mode_cycles = 0; _write_register_inst = QSPIF_WRSR; _read_register_inst = QSPIF_RDSR; - if (QSPI_STATUS_OK != _qspi_set_frequency(_freq)) { tr_error("QSPI Set Frequency Failed"); status = QSPIF_BD_ERROR_DEVICE_ERROR; @@ -302,15 +303,15 @@ int QSPIFBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size) _mutex.lock(); // Configure Bus for Reading - _qspi_configure_format(_inst_width, _address_width, _address_size, QSPI_CFG_BUS_SINGLE, - 0, _data_width, _dummy_and_mode_cycles); + _qspi_configure_format(_inst_width, _address_width, _address_size, _address_width, // Alt width == address width + _alt_size, _data_width, _dummy_cycles); if (QSPI_STATUS_OK != _qspi_send_read_command(_read_instruction, buffer, addr, size)) { status = QSPIF_BD_ERROR_DEVICE_ERROR; tr_error("Read Command failed"); } - // All commands other than Read use default 1-1-1 Bus mode (Program/Erase are constrained by flash memory performance less than that of the bus) + // All commands other than Read use default 1-1-1 Bus mode (Program/Erase are constrained by flash memory performance more than bus performance) _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, 0); @@ -1024,8 +1025,9 @@ int QSPIFBlockDevice::_sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table read_inst = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_444_READ_INST_BYTE]; set_quad_enable = true; is_qpi_mode = true; - _dummy_and_mode_cycles = (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_444_READ_INST_BYTE - 1] >> 5) - + (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_444_READ_INST_BYTE - 1] & 0x1F); + _dummy_cycles = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_444_READ_INST_BYTE - 1] & 0x1F; + uint8_t mode_cycles = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_444_READ_INST_BYTE - 1] >> 5; + _alt_size = mode_cycles * 4; tr_debug("Read Bus Mode set to 4-4-4, Instruction: 0x%xh", _read_instruction); //_inst_width = QSPI_CFG_BUS_QUAD; _address_width = QSPI_CFG_BUS_QUAD; @@ -1038,9 +1040,9 @@ int QSPIFBlockDevice::_sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table // Fast Read 1-4-4 Supported read_inst = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_144_READ_INST_BYTE]; set_quad_enable = true; - // dummy cycles + mode cycles = Dummy Cycles - _dummy_and_mode_cycles = (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_144_READ_INST_BYTE - 1] >> 5) - + (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_144_READ_INST_BYTE - 1] & 0x1F); + _dummy_cycles = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_144_READ_INST_BYTE - 1] & 0x1F; + uint8_t mode_cycles = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_144_READ_INST_BYTE - 1] >> 5; + _alt_size = mode_cycles * 4; _address_width = QSPI_CFG_BUS_QUAD; _data_width = QSPI_CFG_BUS_QUAD; tr_debug("Read Bus Mode set to 1-4-4, Instruction: 0x%xh", _read_instruction); @@ -1051,8 +1053,9 @@ int QSPIFBlockDevice::_sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table // Fast Read 1-1-4 Supported read_inst = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_114_READ_INST_BYTE]; set_quad_enable = true; - _dummy_and_mode_cycles = (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_114_READ_INST_BYTE - 1] >> 5) - + (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_114_READ_INST_BYTE - 1] & 0x1F); + _dummy_cycles = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_114_READ_INST_BYTE - 1] & 0x1F; + uint8_t mode_cycles = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_114_READ_INST_BYTE - 1] >> 5; + _alt_size = mode_cycles; _data_width = QSPI_CFG_BUS_QUAD; tr_debug("Read Bus Mode set to 1-1-4, Instruction: 0x%xh", _read_instruction); break; @@ -1061,8 +1064,9 @@ int QSPIFBlockDevice::_sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table if (examined_byte & 0x01) { // Fast Read 2-2-2 Supported read_inst = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE]; - _dummy_and_mode_cycles = (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE - 1] >> 5) - + (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE - 1] & 0x1F); + _dummy_cycles = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE - 1] & 0x1F; + uint8_t mode_cycles = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE - 1] >> 5; + _alt_size = mode_cycles * 2; _address_width = QSPI_CFG_BUS_DUAL; _data_width = QSPI_CFG_BUS_DUAL; tr_debug("Read Bus Mode set to 2-2-2, Instruction: 0x%xh", _read_instruction); @@ -1073,8 +1077,9 @@ int QSPIFBlockDevice::_sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table if (examined_byte & 0x10) { // Fast Read 1-2-2 Supported read_inst = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE]; - _dummy_and_mode_cycles = (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE - 1] >> 5) - + (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE - 1] & 0x1F); + _dummy_cycles = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE - 1] & 0x1F; + uint8_t mode_cycles = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE - 1] >> 5; + _alt_size = mode_cycles * 2; _address_width = QSPI_CFG_BUS_DUAL; _data_width = QSPI_CFG_BUS_DUAL; tr_debug("Read Bus Mode set to 1-2-2, Instruction: 0x%xh", _read_instruction); @@ -1083,8 +1088,9 @@ int QSPIFBlockDevice::_sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table if (examined_byte & 0x01) { // Fast Read 1-1-2 Supported read_inst = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE]; - _dummy_and_mode_cycles = (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE - 1] >> 5) - + (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE - 1] & 0x1F); + _dummy_cycles = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE - 1] & 0x1F; + uint8_t mode_cycles = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE - 1] >> 5; + _alt_size = mode_cycles; _data_width = QSPI_CFG_BUS_DUAL; tr_debug("Read Bus Mode set to 1-1-2, Instruction: 0x%xh", _read_instruction); break; @@ -1322,7 +1328,7 @@ qspi_status_t QSPIFBlockDevice::_qspi_send_read_command(unsigned int read_inst, // Send Read command to device driver size_t buf_len = size; - if (_qspi.read(read_inst, -1, (unsigned int)addr, (char *)buffer, &buf_len) != QSPI_STATUS_OK) { + if (_qspi.read(read_inst, (_alt_size == 0) ? -1 : QSPI_ALT_DEFAULT_VALUE, (unsigned int)addr, (char *)buffer, &buf_len) != QSPI_STATUS_OK) { tr_error("Read failed"); return QSPI_STATUS_ERROR; } diff --git a/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.h b/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.h index b009bd97b2..5f78b0cafa 100644 --- a/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.h +++ b/components/storage/blockdevice/COMPONENT_QSPIF/QSPIFBlockDevice.h @@ -357,9 +357,11 @@ private: // Bus speed configuration qspi_bus_width_t _inst_width; //Bus width for Instruction phase qspi_bus_width_t _address_width; //Bus width for Address phase - qspi_address_size_t _address_size; // number of bytes for address + qspi_address_size_t _address_size; //Number of bits for address + qspi_alt_size_t _alt_size; //Number of bits for alt + bool _alt_enabled; //Whether alt is enabled + uint8_t _dummy_cycles; //Number of Dummy cycles required by Current Bus Mode qspi_bus_width_t _data_width; //Bus width for Data phase - int _dummy_and_mode_cycles; // Number of Dummy and Mode Bits required by Current Bus Mode uint32_t _init_ref_count; bool _is_initialized;