From 34db8723244dae54dbb25aacc15be854896fd186 Mon Sep 17 00:00:00 2001 From: Nikodem Kastelik Date: Wed, 12 Jun 2024 12:33:35 +0200 Subject: [PATCH 1/3] [nrf fromlist] drivers: spi: nrfx_spim: use dmm Some nRF SoCs (i.e. nRF54H20) can peform DMA transfers only from specific memory regions - `dmm` facilitates that. Upstream PR #: 93487 Signed-off-by: Nikodem Kastelik --- drivers/spi/spi_nrfx_spim.c | 75 ++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/drivers/spi/spi_nrfx_spim.c b/drivers/spi/spi_nrfx_spim.c index 438a1b22999..5d5d0b4ad95 100644 --- a/drivers/spi/spi_nrfx_spim.c +++ b/drivers/spi/spi_nrfx_spim.c @@ -16,6 +16,7 @@ #ifdef CONFIG_SOC_NRF54H20_GPD #include #endif +#include #ifdef CONFIG_SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58 #include #endif @@ -123,9 +124,6 @@ struct spi_nrfx_config { #endif uint32_t wake_pin; nrfx_gpiote_t wake_gpiote; -#ifdef CONFIG_DCACHE - uint32_t mem_attr; -#endif #ifdef USE_CLOCK_REQUESTS const struct device *clk_dev; struct nrf_clock_spec clk_spec; @@ -134,6 +132,7 @@ struct spi_nrfx_config { bool cross_domain; int8_t default_port; #endif + void *mem_reg; }; static void event_handler(const nrfx_spim_evt_t *p_event, void *p_context); @@ -504,11 +503,6 @@ static void transfer_next_chunk(const struct device *dev) } memcpy(dev_data->tx_buffer, tx_buf, chunk_len); -#ifdef CONFIG_DCACHE - if (dev_config->mem_attr & DT_MEM_CACHEABLE) { - sys_cache_data_flush_range(dev_data->tx_buffer, chunk_len); - } -#endif tx_buf = dev_data->tx_buffer; } @@ -525,10 +519,20 @@ static void transfer_next_chunk(const struct device *dev) dev_data->chunk_len = chunk_len; - xfer.p_tx_buffer = tx_buf; - xfer.tx_length = spi_context_tx_buf_on(ctx) ? chunk_len : 0; - xfer.p_rx_buffer = rx_buf; - xfer.rx_length = spi_context_rx_buf_on(ctx) ? chunk_len : 0; + xfer.tx_length = spi_context_tx_buf_on(ctx) ? chunk_len : 0; + xfer.rx_length = spi_context_rx_buf_on(ctx) ? chunk_len : 0; + + error = dmm_buffer_out_prepare(dev_config->mem_reg, tx_buf, xfer.tx_length, + (void **)&xfer.p_tx_buffer); + if (error != 0) { + goto out_alloc_failed; + } + + error = dmm_buffer_in_prepare(dev_config->mem_reg, rx_buf, xfer.rx_length, + (void **)&xfer.p_rx_buffer); + if (error != 0) { + goto in_alloc_failed; + } #ifdef CONFIG_SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58 if (xfer.rx_length == 1 && xfer.tx_length <= 1) { @@ -551,6 +555,13 @@ static void transfer_next_chunk(const struct device *dev) anomaly_58_workaround_clear(dev_data); #endif } + + /* On nrfx_spim_xfer() error */ + dmm_buffer_in_release(dev_config->mem_reg, rx_buf, xfer.rx_length, + (void **)&xfer.p_rx_buffer); +in_alloc_failed: + dmm_buffer_out_release(dev_config->mem_reg, (void **)&xfer.p_tx_buffer); +out_alloc_failed: } finish_transaction(dev, error); @@ -560,9 +571,7 @@ static void event_handler(const nrfx_spim_evt_t *p_event, void *p_context) { const struct device *dev = p_context; struct spi_nrfx_data *dev_data = dev->data; -#ifdef CONFIG_DCACHE const struct spi_nrfx_config *dev_config = dev->config; -#endif if (p_event->type == NRFX_SPIM_EVENT_DONE) { /* Chunk length is set to 0 when a transaction is aborted @@ -576,15 +585,21 @@ static void event_handler(const nrfx_spim_evt_t *p_event, void *p_context) #ifdef CONFIG_SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58 anomaly_58_workaround_clear(dev_data); #endif + + if (spi_context_tx_buf_on(&dev_data->ctx)) { + dmm_buffer_out_release(dev_config->mem_reg, + (void **)p_event->xfer_desc.p_tx_buffer); + } + + if (spi_context_rx_buf_on(&dev_data->ctx)) { + dmm_buffer_in_release(dev_config->mem_reg, dev_data->ctx.rx_buf, + dev_data->chunk_len, p_event->xfer_desc.p_rx_buffer); + } + #ifdef SPI_BUFFER_IN_RAM if (spi_context_rx_buf_on(&dev_data->ctx) && p_event->xfer_desc.p_rx_buffer != NULL && p_event->xfer_desc.p_rx_buffer != dev_data->ctx.rx_buf) { -#ifdef CONFIG_DCACHE - if (dev_config->mem_attr & DT_MEM_CACHEABLE) { - sys_cache_data_invd_range(dev_data->rx_buffer, dev_data->chunk_len); - } -#endif (void)memcpy(dev_data->ctx.rx_buf, dev_data->rx_buffer, dev_data->chunk_len); @@ -878,8 +893,6 @@ static int spi_nrfx_deinit(const struct device *dev) return 0; } -#define SPIM_MEM_REGION(idx) DT_PHANDLE(SPIM(idx), memory_regions) - #define SPI_NRFX_SPIM_EXTENDED_CONFIG(idx) \ IF_ENABLED(NRFX_SPIM_EXTENDED_ENABLED, \ (.dcx_pin = NRF_SPIM_PIN_NOT_CONNECTED, \ @@ -888,13 +901,6 @@ static int spi_nrfx_deinit(const struct device *dev) ()) \ )) -#define SPIM_GET_MEM_ATTR(idx) \ - COND_CODE_1(SPIM_HAS_PROP(idx, memory_regions), \ - (COND_CODE_1(DT_NODE_HAS_PROP(SPIM_MEM_REGION(idx), zephyr_memory_attr), \ - (DT_PROP(SPIM_MEM_REGION(idx), zephyr_memory_attr)), \ - (0))), \ - (0)) - /* Fast instances depend on the global HSFLL clock controller (as they need * to request the highest frequency from it to operate correctly), so they * must be initialized after that controller driver, hence the default SPI @@ -921,10 +927,10 @@ static int spi_nrfx_deinit(const struct device *dev) IF_ENABLED(SPI_BUFFER_IN_RAM, \ (static uint8_t spim_##idx##_tx_buffer \ [CONFIG_SPI_NRFX_RAM_BUFFER_SIZE] \ - SPIM_MEMORY_SECTION(idx); \ + DMM_MEMORY_SECTION(SPIM(idx)); \ static uint8_t spim_##idx##_rx_buffer \ [CONFIG_SPI_NRFX_RAM_BUFFER_SIZE] \ - SPIM_MEMORY_SECTION(idx);)) \ + DMM_MEMORY_SECTION(SPIM(idx));)) \ static struct spi_nrfx_data spi_##idx##_data = { \ IF_ENABLED(CONFIG_MULTITHREADING, \ (SPI_CONTEXT_INIT_LOCK(spi_##idx##_data, ctx),)) \ @@ -961,8 +967,6 @@ static int spi_nrfx_deinit(const struct device *dev) .wake_pin = NRF_DT_GPIOS_TO_PSEL_OR(SPIM(idx), wake_gpios, \ WAKE_PIN_NOT_USED), \ .wake_gpiote = WAKE_GPIOTE_INSTANCE(SPIM(idx)), \ - IF_ENABLED(CONFIG_DCACHE, \ - (.mem_attr = SPIM_GET_MEM_ATTR(idx),)) \ IF_ENABLED(USE_CLOCK_REQUESTS, \ (.clk_dev = SPIM_REQUESTS_CLOCK(SPIM(idx)) \ ? DEVICE_DT_GET(DT_CLOCKS_CTLR(SPIM(idx))) \ @@ -975,6 +979,7 @@ static int spi_nrfx_deinit(const struct device *dev) .default_port = \ DT_PROP_OR(DT_PHANDLE(SPIM(idx), \ default_gpio_port), port, -1),)) \ + .mem_reg = DMM_DEV_TO_REG(SPIM(idx)), \ }; \ BUILD_ASSERT(!SPIM_HAS_PROP(idx, wake_gpios) || \ !(DT_GPIO_FLAGS(SPIM(idx), wake_gpios) & GPIO_ACTIVE_LOW),\ @@ -989,12 +994,6 @@ static int spi_nrfx_deinit(const struct device *dev) POST_KERNEL, SPIM_INIT_PRIORITY(idx), \ &spi_nrfx_driver_api) -#define SPIM_MEMORY_SECTION(idx) \ - COND_CODE_1(SPIM_HAS_PROP(idx, memory_regions), \ - (__attribute__((__section__(LINKER_DT_NODE_REGION_NAME( \ - SPIM_MEM_REGION(idx)))))), \ - ()) - #define COND_NRF_SPIM_DEVICE(unused, prefix, i, _) \ IF_ENABLED(CONFIG_HAS_HW_NRF_SPIM##prefix##i, (SPI_NRFX_SPIM_DEFINE(prefix##i);)) From fa83283138014787005cb5aab2fe9529784622d6 Mon Sep 17 00:00:00 2001 From: Nikodem Kastelik Date: Wed, 12 Jun 2024 13:45:18 +0200 Subject: [PATCH 2/3] [nrf fromlist] tests: drivers: spi: controller_peripheral: add direct variant Direct variant of this test disables intermediate buffer in the nRF SPI driver and verifies whether devices like nRF54H20, which can peform DMA transcations only from specific memory regions, are handled properly. Upstream PR #: 93487 Signed-off-by: Nikodem Kastelik --- tests/drivers/spi/spi_controller_peripheral/Kconfig | 7 +++++++ .../drivers/spi/spi_controller_peripheral/src/main.c | 9 ++++++--- .../spi/spi_controller_peripheral/testcase.yaml | 11 +++++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/tests/drivers/spi/spi_controller_peripheral/Kconfig b/tests/drivers/spi/spi_controller_peripheral/Kconfig index f6472dae4ab..c98c3a27ff2 100644 --- a/tests/drivers/spi/spi_controller_peripheral/Kconfig +++ b/tests/drivers/spi/spi_controller_peripheral/Kconfig @@ -11,4 +11,11 @@ config TESTED_SPI_MODE 2: CPOL 1 (Active low), CPHA 0 (leading) 3: CPOL 1 (Active low), CPHA 1 (trailing) +config PREALLOC_BUFFERS + bool "Preallocate buffers" + default y + help + Preallocate buffers used for transaction + using `memory-region` property. + source "Kconfig.zephyr" diff --git a/tests/drivers/spi/spi_controller_peripheral/src/main.c b/tests/drivers/spi/spi_controller_peripheral/src/main.c index 04c6c27d11a..7e15bb32536 100644 --- a/tests/drivers/spi/spi_controller_peripheral/src/main.c +++ b/tests/drivers/spi/spi_controller_peripheral/src/main.c @@ -41,9 +41,12 @@ static struct k_poll_event async_evt_spim = K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL, K_POLL_MODE_NOTIFY_ONLY, &async_sig_spim); #define MEMORY_SECTION(node) \ - COND_CODE_1(DT_NODE_HAS_PROP(node, memory_regions), \ - (__attribute__((__section__( \ - LINKER_DT_NODE_REGION_NAME(DT_PHANDLE(node, memory_regions)))))), \ + COND_CODE_1(IS_ENABLED(CONFIG_PREALLOC_BUFFERS), \ + (COND_CODE_1(DT_NODE_HAS_PROP(node, memory_regions), \ + (__attribute__((__section__( \ + LINKER_DT_NODE_REGION_NAME(DT_PHANDLE(node, \ + memory_regions)))))), \ + ())), \ ()) static uint8_t spim_buffer[32] MEMORY_SECTION(DT_BUS(DT_NODELABEL(dut_spi_dt))); diff --git a/tests/drivers/spi/spi_controller_peripheral/testcase.yaml b/tests/drivers/spi/spi_controller_peripheral/testcase.yaml index f385c3073e9..5f243dd6cf6 100644 --- a/tests/drivers/spi/spi_controller_peripheral/testcase.yaml +++ b/tests/drivers/spi/spi_controller_peripheral/testcase.yaml @@ -117,3 +117,14 @@ tests: - nrf54h20dk/nrf54h20/cpuppr - nrf54l20pdk/nrf54l20/cpuapp - ophelia4ev/nrf54l15/cpuapp + + drivers.spi.direct_xfer: + extra_configs: + - CONFIG_SPI_NRFX_RAM_BUFFER_SIZE=0 + filter: CONFIG_SOC_FAMILY_NORDIC_NRF + + drivers.spi.direct_xfer.no_prealloc: + extra_configs: + - CONFIG_SPI_NRFX_RAM_BUFFER_SIZE=0 + - CONFIG_PREALLOC_BUFFERS=n + filter: CONFIG_SOC_FAMILY_NORDIC_NRF From afb79934e252557fa1a272c729dc91b5eafb2a0e Mon Sep 17 00:00:00 2001 From: Nikodem Kastelik Date: Thu, 24 Jul 2025 16:40:01 +0200 Subject: [PATCH 3/3] [nrf fromlist] drivers: spi: nrfx_spis: fix buffer freeing on error Bounce buffers should be freed rather than user buffers. Upstream PR #: 93487 Signed-off-by: Nikodem Kastelik --- drivers/spi/spi_nrfx_spis.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi_nrfx_spis.c b/drivers/spi/spi_nrfx_spis.c index daa75d7e7ff..c6e551eafc3 100644 --- a/drivers/spi/spi_nrfx_spis.c +++ b/drivers/spi/spi_nrfx_spis.c @@ -243,9 +243,9 @@ static int prepare_for_transfer(const struct device *dev, return 0; buffers_set_failed: - dmm_buffer_in_release(dev_config->mem_reg, rx_buf, rx_buf_len, rx_buf); + dmm_buffer_in_release(dev_config->mem_reg, rx_buf, rx_buf_len, dmm_rx_buf); in_alloc_failed: - dmm_buffer_out_release(dev_config->mem_reg, (void *)tx_buf); + dmm_buffer_out_release(dev_config->mem_reg, (void *)dmm_tx_buf); out_alloc_failed: return err; }