diff --git a/drivers/flash/flash_mspi_nor.c b/drivers/flash/flash_mspi_nor.c index a634b3d9118..03430401de0 100644 --- a/drivers/flash/flash_mspi_nor.c +++ b/drivers/flash/flash_mspi_nor.c @@ -237,7 +237,9 @@ static int acquire(const struct device *dev) struct flash_mspi_nor_data *dev_data = dev->data; int rc; +#if defined(CONFIG_MULTITHREADING) k_sem_take(&dev_data->acquired, K_FOREVER); +#endif rc = pm_device_runtime_get(dev_config->bus); if (rc < 0) { @@ -269,21 +271,27 @@ static int acquire(const struct device *dev) (void)pm_device_runtime_put(dev_config->bus); } +#if defined(CONFIG_MULTITHREADING) k_sem_give(&dev_data->acquired); +#endif + return rc; } static void release(const struct device *dev) { const struct flash_mspi_nor_config *dev_config = dev->config; - struct flash_mspi_nor_data *dev_data = dev->data; /* This releases the MSPI controller. */ (void)mspi_get_channel_status(dev_config->bus, 0); (void)pm_device_runtime_put(dev_config->bus); +#if defined(CONFIG_MULTITHREADING) + struct flash_mspi_nor_data *dev_data = dev->data; + k_sem_give(&dev_data->acquired); +#endif } static inline uint32_t dev_flash_size(const struct device *dev) @@ -1215,7 +1223,9 @@ static int drv_init(const struct device *dev) } } +#if defined(CONFIG_MULTITHREADING) k_sem_init(&dev_data->acquired, 1, K_SEM_MAX_LIMIT); +#endif return pm_device_driver_init(dev, dev_pm_action_cb); } diff --git a/drivers/flash/flash_mspi_nor.h b/drivers/flash/flash_mspi_nor.h index 480bccce472..86c824cf485 100644 --- a/drivers/flash/flash_mspi_nor.h +++ b/drivers/flash/flash_mspi_nor.h @@ -104,7 +104,9 @@ struct flash_mspi_nor_config { }; struct flash_mspi_nor_data { +#if defined(CONFIG_MULTITHREADING) struct k_sem acquired; +#endif struct mspi_xfer_packet packet; struct mspi_xfer xfer; struct jesd216_erase_type erase_types[JESD216_NUM_ERASE_TYPES]; diff --git a/drivers/mspi/mspi_dw.c b/drivers/mspi/mspi_dw.c index f1195314c6c..f7be2e33c9e 100644 --- a/drivers/mspi/mspi_dw.c +++ b/drivers/mspi/mspi_dw.c @@ -65,11 +65,16 @@ struct mspi_dw_data { bool standard_spi; bool suspended; +#if defined(CONFIG_MULTITHREADING) struct k_sem finished; /* For synchronization of API calls made from different contexts. */ struct k_sem ctx_lock; /* For locking of controller configuration. */ struct k_sem cfg_lock; +#else + volatile bool finished; + bool cfg_lock; +#endif struct mspi_xfer xfer; #if defined(CONFIG_MSPI_DW_HANDLE_FIFOS_IN_SYSTEM_WORKQUEUE) @@ -245,9 +250,12 @@ static bool read_rx_fifo(const struct device *dev, uint8_t *buf_pos = dev_data->buf_pos; const uint8_t *buf_end = &packet->data_buf[packet->num_bytes]; uint8_t bytes_per_frame_exp = dev_data->bytes_per_frame_exp; - /* See `room` in tx_data(). */ - uint32_t in_fifo = 1; uint32_t remaining_frames; + uint32_t in_fifo = FIELD_GET(RXFLR_RXTFL_MASK, read_rxflr(dev)); + + if (in_fifo == 0) { + return false; + } do { uint32_t data = read_dr(dev); @@ -322,28 +330,37 @@ static void handle_fifos(const struct device *dev) } } else { for (;;) { + /* Always read everything from the RX FIFO, regardless + * of the interrupt status. + * tx_dummy_bytes() subtracts the number of items that + * are present in the RX FIFO from the number of dummy + * bytes it is allowed to send, so it can potentially + * not fill the TX FIFO above its transfer start level + * in some iteration of this loop. If in such case the + * interrupt handler exited without emptying the RX FIFO + * (seeing the RXFIS flag not set due to not enough + * items in the RX FIFO), this could lead to a situation + * in which a transfer stopped temporarily (after the TX + * FIFO got empty) is not resumed (since the TX FIFO is + * not filled above its transfer start level), so no + * further dummy bytes are transmitted and the RX FIFO + * has no chance to get new entries, hence no further + * interrupts are generated and the transfer gets stuck. + */ + if (read_rx_fifo(dev, packet)) { + finished = true; + break; + } + /* Use RISR, not ISR, because when this function is * executed through the system workqueue, all interrupts * are masked (IMR is 0). */ uint32_t int_status = read_risr(dev); - if (int_status & RISR_RXFIR_BIT) { - if (read_rx_fifo(dev, packet)) { - finished = true; - break; - } - - if (int_status & RISR_RXOIR_BIT) { - finished = true; - break; - } - - /* Refresh interrupt status, as during reading - * from the RX FIFO, the TX FIFO status might - * have changed. - */ - int_status = read_risr(dev); + if (int_status & RISR_RXOIR_BIT) { + finished = true; + break; } if (dev_data->dummy_bytes == 0 || @@ -364,7 +381,11 @@ static void handle_fifos(const struct device *dev) if (finished) { set_imr(dev, 0); +#if defined(CONFIG_MULTITHREADING) k_sem_give(&dev_data->finished); +#else + dev_data->finished = true; +#endif } } @@ -816,8 +837,17 @@ static int api_dev_config(const struct device *dev, int rc; if (dev_id != dev_data->dev_id) { +#if defined(CONFIG_MULTITHREADING) rc = k_sem_take(&dev_data->cfg_lock, K_MSEC(CONFIG_MSPI_COMPLETION_TIMEOUT_TOLERANCE)); +#else + if (dev_data->cfg_lock) { + rc = -1; + } else { + dev_data->cfg_lock = true; + rc = 0; + } +#endif if (rc < 0) { LOG_ERR("Failed to switch controller to device"); return -EBUSY; @@ -831,15 +861,23 @@ static int api_dev_config(const struct device *dev, return 0; } +#if defined(CONFIG_MULTITHREADING) (void)k_sem_take(&dev_data->ctx_lock, K_FOREVER); +#endif rc = _api_dev_config(dev, param_mask, cfg); +#if defined(CONFIG_MULTITHREADING) k_sem_give(&dev_data->ctx_lock); +#endif if (rc < 0) { dev_data->dev_id = NULL; +#if defined(CONFIG_MULTITHREADING) k_sem_give(&dev_data->cfg_lock); +#else + dev_data->cfg_lock = false; +#endif } return rc; @@ -851,12 +889,17 @@ static int api_get_channel_status(const struct device *dev, uint8_t ch) struct mspi_dw_data *dev_data = dev->data; +#if defined(CONFIG_MULTITHREADING) (void)k_sem_take(&dev_data->ctx_lock, K_FOREVER); +#endif dev_data->dev_id = NULL; +#if defined(CONFIG_MULTITHREADING) k_sem_give(&dev_data->cfg_lock); - k_sem_give(&dev_data->ctx_lock); +#else + dev_data->cfg_lock = false; +#endif return 0; } @@ -1119,7 +1162,17 @@ static int start_next_packet(const struct device *dev, k_timeout_t timeout) /* Write SER to start transfer */ write_ser(dev, BIT(dev_data->dev_id->dev_idx)); +#if defined(CONFIG_MULTITHREADING) rc = k_sem_take(&dev_data->finished, timeout); +#else + if (!WAIT_FOR(dev_data->finished, + dev_data->xfer.timeout * USEC_PER_MSEC, + NULL)) { + rc = -ETIMEDOUT; + } + + dev_data->finished = false; +#endif if (read_risr(dev) & RISR_RXOIR_BIT) { LOG_ERR("RX FIFO overflow occurred"); rc = -EIO; @@ -1232,7 +1285,9 @@ static int api_transceive(const struct device *dev, return rc; } +#if defined(CONFIG_MULTITHREADING) (void)k_sem_take(&dev_data->ctx_lock, K_FOREVER); +#endif if (dev_data->suspended) { rc = -EFAULT; @@ -1240,7 +1295,9 @@ static int api_transceive(const struct device *dev, rc = _api_transceive(dev, req); } +#if defined(CONFIG_MULTITHREADING) k_sem_give(&dev_data->ctx_lock); +#endif rc2 = pm_device_runtime_put(dev); if (rc2 < 0) { @@ -1391,7 +1448,9 @@ static int api_xip_config(const struct device *dev, return rc; } +#if defined(CONFIG_MULTITHREADING) (void)k_sem_take(&dev_data->ctx_lock, K_FOREVER); +#endif if (dev_data->suspended) { rc = -EFAULT; @@ -1399,7 +1458,9 @@ static int api_xip_config(const struct device *dev, rc = _api_xip_config(dev, dev_id, cfg); } +#if defined(CONFIG_MULTITHREADING) k_sem_give(&dev_data->ctx_lock); +#endif rc2 = pm_device_runtime_put(dev); if (rc2 < 0) { @@ -1450,8 +1511,12 @@ static int dev_pm_action_cb(const struct device *dev, return rc; } #endif +#if defined(CONFIG_MULTITHREADING) if (xip_enabled || k_sem_take(&dev_data->ctx_lock, K_NO_WAIT) != 0) { +#else + if (xip_enabled) { +#endif LOG_ERR("Controller in use, cannot be suspended"); return -EBUSY; } @@ -1460,7 +1525,9 @@ static int dev_pm_action_cb(const struct device *dev, vendor_specific_suspend(dev); +#if defined(CONFIG_MULTITHREADING) k_sem_give(&dev_data->ctx_lock); +#endif return 0; } @@ -1470,7 +1537,6 @@ static int dev_pm_action_cb(const struct device *dev, static int dev_init(const struct device *dev) { - struct mspi_dw_data *dev_data = dev->data; const struct mspi_dw_config *dev_config = dev->config; const struct gpio_dt_spec *ce_gpio; int rc; @@ -1481,9 +1547,13 @@ static int dev_init(const struct device *dev) dev_config->irq_config(); +#if defined(CONFIG_MULTITHREADING) + struct mspi_dw_data *dev_data = dev->data; + k_sem_init(&dev_data->finished, 0, 1); k_sem_init(&dev_data->cfg_lock, 1, 1); k_sem_init(&dev_data->ctx_lock, 1, 1); +#endif #if defined(CONFIG_MSPI_DW_HANDLE_FIFOS_IN_SYSTEM_WORKQUEUE) dev_data->dev = dev; diff --git a/drivers/power_domain/Kconfig.nrfs_gdpwr b/drivers/power_domain/Kconfig.nrfs_gdpwr index bf9abd59aed..c5f05d88a7e 100644 --- a/drivers/power_domain/Kconfig.nrfs_gdpwr +++ b/drivers/power_domain/Kconfig.nrfs_gdpwr @@ -4,6 +4,7 @@ config POWER_DOMAIN_NRFS_GDPWR bool "NRFS Global Domain Power Request driver" depends on DT_HAS_NORDIC_NRFS_GDPWR_ENABLED + depends on MULTITHREADING select NRFS select NRFS_GDPWR_SERVICE_ENABLED default y diff --git a/tests/drivers/mspi/flash/testcase.yaml b/tests/drivers/mspi/flash/testcase.yaml index dba610a4023..ae1db5d4d6d 100644 --- a/tests/drivers/mspi/flash/testcase.yaml +++ b/tests/drivers/mspi/flash/testcase.yaml @@ -36,3 +36,9 @@ tests: - nrf54h20dk/nrf54h20/cpuapp extra_configs: - CONFIG_MSPI_DW_HANDLE_FIFOS_IN_SYSTEM_WORKQUEUE=y + drivers.mspi.flash.mspi_nor_no_multithreading: + filter: dt_alias_exists("mspi0") and CONFIG_FLASH_MSPI_NOR + integration_platforms: + - nrf54h20dk/nrf54h20/cpuapp + extra_configs: + - CONFIG_MULTITHREADING=n