drivers: flash: stm32 ospi: implement non busy wait polling
HAL_OSPI_AutoPolling is checking is the status match happened in a busy loop. That CPU intensive operation can cause starvation of other tasks especially on flash erase operations which can take seconds to complete. So, replace the use of HAL_OSPI_AutoPolling with HAL_OSPI_AutoPolling_IT. The match results HAL_OSPI_StatusMatchCallback being called. Signed-off-by: Miika Karanki <miika.karanki@vaisala.com>
This commit is contained in:
parent
b803e06099
commit
5d9acf52a5
|
@ -522,14 +522,38 @@ static bool ospi_address_is_valid(const struct device *dev, off_t addr,
|
|||
return (addr >= 0) && ((uint64_t)addr + (uint64_t)size <= flash_size);
|
||||
}
|
||||
|
||||
static int stm32_ospi_wait_auto_polling(struct flash_stm32_ospi_data *dev_data,
|
||||
OSPI_AutoPollingTypeDef *s_config, uint32_t timeout_ms)
|
||||
{
|
||||
dev_data->cmd_status = 0;
|
||||
if (HAL_OSPI_AutoPolling_IT(&dev_data->hospi, s_config) != HAL_OK) {
|
||||
LOG_ERR("OSPI AutoPoll failed");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (k_sem_take(&dev_data->sync, K_MSEC(timeout_ms)) != 0) {
|
||||
LOG_ERR("OSPI AutoPoll wait failed");
|
||||
HAL_OSPI_Abort(&dev_data->hospi);
|
||||
k_sem_reset(&dev_data->sync);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* HAL_OSPI_AutoPolling_IT enables transfer error interrupt which sets
|
||||
* cmd_status.
|
||||
*/
|
||||
return dev_data->cmd_status;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function Polls the WEL (write enable latch) bit to become to 0
|
||||
* When the Chip Erase Cycle is completed, the Write Enable Latch (WEL) bit is cleared.
|
||||
* in nor_mode SPI/OPI OSPI_SPI_MODE or OSPI_OPI_MODE
|
||||
* and nor_rate transfer STR/DTR OSPI_STR_TRANSFER or OSPI_DTR_TRANSFER
|
||||
*/
|
||||
static int stm32_ospi_mem_erased(OSPI_HandleTypeDef *hospi, uint8_t nor_mode, uint8_t nor_rate)
|
||||
static int stm32_ospi_mem_erased(struct flash_stm32_ospi_data *dev_data,
|
||||
uint8_t nor_mode, uint8_t nor_rate)
|
||||
{
|
||||
OSPI_HandleTypeDef *hospi = &dev_data->hospi;
|
||||
OSPI_AutoPollingTypeDef s_config = {0};
|
||||
OSPI_RegularCmdTypeDef s_command = ospi_prepare_cmd(nor_mode, nor_rate);
|
||||
|
||||
|
@ -566,12 +590,8 @@ static int stm32_ospi_mem_erased(OSPI_HandleTypeDef *hospi, uint8_t nor_mode, ui
|
|||
}
|
||||
|
||||
/* Start Automatic-Polling mode to wait until the memory is totally erased */
|
||||
if (HAL_OSPI_AutoPolling(hospi, &s_config, STM32_OSPI_BULK_ERASE_MAX_TIME) != HAL_OK) {
|
||||
LOG_ERR("OSPI AutoPoll (WEL) failed");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return stm32_ospi_wait_auto_polling(dev_data,
|
||||
&s_config, STM32_OSPI_BULK_ERASE_MAX_TIME);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -579,8 +599,10 @@ static int stm32_ospi_mem_erased(OSPI_HandleTypeDef *hospi, uint8_t nor_mode, ui
|
|||
* in nor_mode SPI/OPI OSPI_SPI_MODE or OSPI_OPI_MODE
|
||||
* and nor_rate transfer STR/DTR OSPI_STR_TRANSFER or OSPI_DTR_TRANSFER
|
||||
*/
|
||||
static int stm32_ospi_mem_ready(OSPI_HandleTypeDef *hospi, uint8_t nor_mode, uint8_t nor_rate)
|
||||
static int stm32_ospi_mem_ready(struct flash_stm32_ospi_data *dev_data, uint8_t nor_mode,
|
||||
uint8_t nor_rate)
|
||||
{
|
||||
OSPI_HandleTypeDef *hospi = &dev_data->hospi;
|
||||
OSPI_AutoPollingTypeDef s_config = {0};
|
||||
OSPI_RegularCmdTypeDef s_command = ospi_prepare_cmd(nor_mode, nor_rate);
|
||||
|
||||
|
@ -616,17 +638,14 @@ static int stm32_ospi_mem_ready(OSPI_HandleTypeDef *hospi, uint8_t nor_mode, uin
|
|||
}
|
||||
|
||||
/* Start Automatic-Polling mode to wait until the memory is ready WIP=0 */
|
||||
if (HAL_OSPI_AutoPolling(hospi, &s_config, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
|
||||
LOG_ERR("OSPI AutoPoll failed");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return stm32_ospi_wait_auto_polling(dev_data, &s_config, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
|
||||
}
|
||||
|
||||
/* Enables writing to the memory sending a Write Enable and wait it is effective */
|
||||
static int stm32_ospi_write_enable(OSPI_HandleTypeDef *hospi, uint8_t nor_mode, uint8_t nor_rate)
|
||||
static int stm32_ospi_write_enable(struct flash_stm32_ospi_data *dev_data,
|
||||
uint8_t nor_mode, uint8_t nor_rate)
|
||||
{
|
||||
OSPI_HandleTypeDef *hospi = &dev_data->hospi;
|
||||
OSPI_AutoPollingTypeDef s_config = {0};
|
||||
OSPI_RegularCmdTypeDef s_command = ospi_prepare_cmd(nor_mode, nor_rate);
|
||||
|
||||
|
@ -679,12 +698,7 @@ static int stm32_ospi_write_enable(OSPI_HandleTypeDef *hospi, uint8_t nor_mode,
|
|||
s_config.Interval = SPI_NOR_AUTO_POLLING_INTERVAL;
|
||||
s_config.AutomaticStop = HAL_OSPI_AUTOMATIC_STOP_ENABLE;
|
||||
|
||||
if (HAL_OSPI_AutoPolling(hospi, &s_config, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
|
||||
LOG_ERR("OSPI config auto polling failed");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return stm32_ospi_wait_auto_polling(dev_data, &s_config, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
|
||||
}
|
||||
|
||||
/* Write Flash configuration register 2 with new dummy cycles */
|
||||
|
@ -796,7 +810,7 @@ static int stm32_ospi_config_mem(const struct device *dev)
|
|||
/* Going to set the OPI mode (STR or DTR transfer rate) */
|
||||
LOG_DBG("OSPI configuring OctoSPI mode");
|
||||
|
||||
if (stm32_ospi_write_enable(&dev_data->hospi,
|
||||
if (stm32_ospi_write_enable(dev_data,
|
||||
OSPI_SPI_MODE, OSPI_STR_TRANSFER) != 0) {
|
||||
LOG_ERR("OSPI write Enable failed");
|
||||
return -EIO;
|
||||
|
@ -808,12 +822,12 @@ static int stm32_ospi_config_mem(const struct device *dev)
|
|||
LOG_ERR("OSPI write CFGR2 failed");
|
||||
return -EIO;
|
||||
}
|
||||
if (stm32_ospi_mem_ready(&dev_data->hospi,
|
||||
if (stm32_ospi_mem_ready(dev_data,
|
||||
OSPI_SPI_MODE, OSPI_STR_TRANSFER) != 0) {
|
||||
LOG_ERR("OSPI autopolling failed");
|
||||
return -EIO;
|
||||
}
|
||||
if (stm32_ospi_write_enable(&dev_data->hospi,
|
||||
if (stm32_ospi_write_enable(dev_data,
|
||||
OSPI_SPI_MODE, OSPI_STR_TRANSFER) != 0) {
|
||||
LOG_ERR("OSPI write Enable 2 failed");
|
||||
return -EIO;
|
||||
|
@ -841,7 +855,7 @@ static int stm32_ospi_config_mem(const struct device *dev)
|
|||
}
|
||||
|
||||
if (dev_cfg->data_rate == OSPI_STR_TRANSFER) {
|
||||
if (stm32_ospi_mem_ready(&dev_data->hospi,
|
||||
if (stm32_ospi_mem_ready(dev_data,
|
||||
OSPI_OPI_MODE, OSPI_STR_TRANSFER) != 0) {
|
||||
/* Check Flash busy ? */
|
||||
LOG_ERR("OSPI flash busy failed");
|
||||
|
@ -859,7 +873,7 @@ static int stm32_ospi_config_mem(const struct device *dev)
|
|||
}
|
||||
|
||||
if (dev_cfg->data_rate == OSPI_DTR_TRANSFER) {
|
||||
if (stm32_ospi_mem_ready(&dev_data->hospi,
|
||||
if (stm32_ospi_mem_ready(dev_data,
|
||||
OSPI_OPI_MODE, OSPI_DTR_TRANSFER) != 0) {
|
||||
/* Check Flash busy ? */
|
||||
LOG_ERR("OSPI flash busy failed");
|
||||
|
@ -1004,7 +1018,7 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr,
|
|||
|
||||
ospi_lock_thread(dev);
|
||||
|
||||
if (stm32_ospi_mem_ready(&dev_data->hospi,
|
||||
if (stm32_ospi_mem_ready(dev_data,
|
||||
dev_cfg->data_mode, dev_cfg->data_rate) != 0) {
|
||||
ospi_unlock_thread(dev);
|
||||
LOG_ERR("Erase failed : flash busy");
|
||||
|
@ -1023,7 +1037,7 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr,
|
|||
|
||||
while ((size > 0) && (ret == 0)) {
|
||||
|
||||
ret = stm32_ospi_write_enable(&dev_data->hospi,
|
||||
ret = stm32_ospi_write_enable(dev_data,
|
||||
dev_cfg->data_mode, dev_cfg->data_rate);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Erase failed : write enable");
|
||||
|
@ -1044,7 +1058,7 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr,
|
|||
|
||||
size -= dev_cfg->flash_size;
|
||||
/* Chip (Bulk) erase started, wait until WEL becomes 0 */
|
||||
ret = stm32_ospi_mem_erased(&dev_data->hospi,
|
||||
ret = stm32_ospi_mem_erased(dev_data,
|
||||
dev_cfg->data_mode, dev_cfg->data_rate);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Chip Erase failed");
|
||||
|
@ -1112,8 +1126,8 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr,
|
|||
size -= SPI_NOR_SECTOR_SIZE;
|
||||
}
|
||||
|
||||
ret = stm32_ospi_mem_ready(&dev_data->hospi,
|
||||
dev_cfg->data_mode, dev_cfg->data_rate);
|
||||
ret = stm32_ospi_mem_ready(dev_data, dev_cfg->data_mode,
|
||||
dev_cfg->data_rate);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1275,7 +1289,7 @@ static int flash_stm32_ospi_write(const struct device *dev, off_t addr,
|
|||
LOG_DBG("OSPI: write %zu data", size);
|
||||
ospi_lock_thread(dev);
|
||||
|
||||
ret = stm32_ospi_mem_ready(&dev_data->hospi,
|
||||
ret = stm32_ospi_mem_ready(dev_data,
|
||||
dev_cfg->data_mode, dev_cfg->data_rate);
|
||||
if (ret != 0) {
|
||||
ospi_unlock_thread(dev);
|
||||
|
@ -1285,7 +1299,7 @@ static int flash_stm32_ospi_write(const struct device *dev, off_t addr,
|
|||
|
||||
while ((size > 0) && (ret == 0)) {
|
||||
to_write = size;
|
||||
ret = stm32_ospi_write_enable(&dev_data->hospi,
|
||||
ret = stm32_ospi_write_enable(dev_data,
|
||||
dev_cfg->data_mode, dev_cfg->data_rate);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("OSPI: write not enabled");
|
||||
|
@ -1315,7 +1329,7 @@ static int flash_stm32_ospi_write(const struct device *dev, off_t addr,
|
|||
addr += to_write;
|
||||
|
||||
/* Configure automatic polling mode to wait for end of program */
|
||||
ret = stm32_ospi_mem_ready(&dev_data->hospi,
|
||||
ret = stm32_ospi_mem_ready(dev_data,
|
||||
dev_cfg->data_mode, dev_cfg->data_rate);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("OSPI: write PP not ready");
|
||||
|
@ -1660,7 +1674,7 @@ static int stm32_ospi_enable_qe(const struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
ret = stm32_ospi_write_enable(&data->hospi, OSPI_SPI_MODE, OSPI_STR_TRANSFER);
|
||||
ret = stm32_ospi_write_enable(data, OSPI_SPI_MODE, OSPI_STR_TRANSFER);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
@ -1672,7 +1686,7 @@ static int stm32_ospi_enable_qe(const struct device *dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = stm32_ospi_mem_ready(&data->hospi, OSPI_SPI_MODE, OSPI_STR_TRANSFER);
|
||||
ret = stm32_ospi_mem_ready(data, OSPI_SPI_MODE, OSPI_STR_TRANSFER);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
@ -2133,6 +2147,13 @@ static int flash_stm32_ospi_init(const struct device *dev)
|
|||
|
||||
#endif /* CONFIG_SOC_SERIES_STM32H5X */
|
||||
|
||||
/* Initialize semaphores */
|
||||
k_sem_init(&dev_data->sem, 1, 1);
|
||||
k_sem_init(&dev_data->sync, 0, 1);
|
||||
|
||||
/* Run IRQ init */
|
||||
dev_cfg->irq_config(dev);
|
||||
|
||||
/* Reset NOR flash memory : still with the SPI/STR config for the NOR */
|
||||
if (stm32_ospi_mem_reset(dev) != 0) {
|
||||
LOG_ERR("OSPI reset failed");
|
||||
|
@ -2142,7 +2163,7 @@ static int flash_stm32_ospi_init(const struct device *dev)
|
|||
LOG_DBG("Reset Mem (SPI/STR)");
|
||||
|
||||
/* Check if memory is ready in the SPI/STR mode */
|
||||
if (stm32_ospi_mem_ready(&dev_data->hospi,
|
||||
if (stm32_ospi_mem_ready(dev_data,
|
||||
OSPI_SPI_MODE, OSPI_STR_TRANSFER) != 0) {
|
||||
LOG_ERR("OSPI memory not ready");
|
||||
return -EIO;
|
||||
|
@ -2165,12 +2186,7 @@ static int flash_stm32_ospi_init(const struct device *dev)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
/* Initialize semaphores */
|
||||
k_sem_init(&dev_data->sem, 1, 1);
|
||||
k_sem_init(&dev_data->sync, 0, 1);
|
||||
|
||||
/* Run IRQ init */
|
||||
dev_cfg->irq_config(dev);
|
||||
|
||||
/* Send the instruction to read the SFDP */
|
||||
const uint8_t decl_nph = 2;
|
||||
|
|
|
@ -38,7 +38,9 @@
|
|||
#define HAL_OSPI_Transmit_DMA HAL_XSPI_Transmit_DMA
|
||||
#define HAL_OSPI_Transmit_IT HAL_XSPI_Transmit_IT
|
||||
#define HAL_OSPI_AutoPolling HAL_XSPI_AutoPolling
|
||||
#define HAL_OSPI_AutoPolling_IT HAL_XSPI_AutoPolling_IT
|
||||
#define HAL_OSPI_IRQHandler HAL_XSPI_IRQHandler
|
||||
#define HAL_OSPI_Abort HAL_XSPI_Abort
|
||||
|
||||
#define HAL_OSPI_ErrorCallback HAL_XSPI_ErrorCallback
|
||||
#define HAL_OSPI_CmdCpltCallback HAL_XSPI_CmdCpltCallback
|
||||
|
|
Loading…
Reference in a new issue