diff --git a/components/driver/include/esp_private/spi_common_internal.h b/components/driver/include/esp_private/spi_common_internal.h index 6cc711b522..38f0f00500 100644 --- a/components/driver/include/esp_private/spi_common_internal.h +++ b/components/driver/include/esp_private/spi_common_internal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2010-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,6 +12,7 @@ #include "driver/spi_common.h" #include "freertos/FreeRTOS.h" #include "hal/spi_types.h" +#include "hal/dma_types.h" #include "esp_pm.h" #if SOC_GDMA_SUPPORTED #include "esp_private/gdma.h" @@ -45,6 +46,13 @@ extern "C" #define BUS_LOCK_DEBUG_EXECUTE_CHECK(x) #endif +#if SOC_GPSPI_SUPPORTED && (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AXI) +#define DMA_DESC_MEM_ALIGN_SIZE 8 +typedef dma_descriptor_align8_t spi_dma_desc_t; +#else +#define DMA_DESC_MEM_ALIGN_SIZE 4 +typedef dma_descriptor_align4_t spi_dma_desc_t; +#endif struct spi_bus_lock_t; struct spi_bus_lock_dev_t; @@ -56,22 +64,21 @@ typedef struct spi_bus_lock_dev_t* spi_bus_lock_dev_handle_t; /// Background operation control function typedef void (*bg_ctrl_func_t)(void*); -typedef struct lldesc_s lldesc_t; - /// Attributes of an SPI bus typedef struct { - spi_bus_config_t bus_cfg; ///< Config used to initialize the bus - uint32_t flags; ///< Flags (attributes) of the bus - int max_transfer_sz; ///< Maximum length of bytes available to send - bool dma_enabled; ///< To enable DMA or not - int tx_dma_chan; ///< TX DMA channel, on ESP32 and ESP32S2, tx_dma_chan and rx_dma_chan are same - int rx_dma_chan; ///< RX DMA channel, on ESP32 and ESP32S2, tx_dma_chan and rx_dma_chan are same - int dma_desc_num; ///< DMA descriptor number of dmadesc_tx or dmadesc_rx. - lldesc_t *dmadesc_tx; ///< DMA descriptor array for TX - lldesc_t *dmadesc_rx; ///< DMA descriptor array for RX + spi_bus_config_t bus_cfg; ///< Config used to initialize the bus + uint32_t flags; ///< Flags (attributes) of the bus + int max_transfer_sz; ///< Maximum length of bytes available to send + bool dma_enabled; ///< To enable DMA or not + uint16_t internal_mem_align_size; ///< Buffer align byte requirement for internal memory + int tx_dma_chan; ///< TX DMA channel, on ESP32 and ESP32S2, tx_dma_chan and rx_dma_chan are same + int rx_dma_chan; ///< RX DMA channel, on ESP32 and ESP32S2, tx_dma_chan and rx_dma_chan are same + int dma_desc_num; ///< DMA descriptor number of dmadesc_tx or dmadesc_rx. + spi_dma_desc_t *dmadesc_tx; ///< DMA descriptor array for TX + spi_dma_desc_t *dmadesc_rx; ///< DMA descriptor array for RX spi_bus_lock_handle_t lock; #ifdef CONFIG_PM_ENABLE - esp_pm_lock_handle_t pm_lock; ///< Power management lock + esp_pm_lock_handle_t pm_lock; ///< Power management lock #endif } spi_bus_attr_t; diff --git a/components/driver/spi/gpspi/spi_common.c b/components/driver/spi/gpspi/spi_common.c index f8fb9af13d..72a2ab3a77 100644 --- a/components/driver/spi/gpspi/spi_common.c +++ b/components/driver/spi/gpspi/spi_common.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,7 +13,6 @@ #include "esp_check.h" #include "esp_rom_gpio.h" #include "esp_heap_caps.h" -#include "soc/lldesc.h" #include "soc/spi_periph.h" #include "driver/gpio.h" #include "driver/spi_master.h" @@ -26,6 +25,14 @@ #endif #if SOC_GDMA_SUPPORTED #include "esp_private/gdma.h" +#include "hal/cache_hal.h" +#include "hal/cache_ll.h" +#endif + +#if SOC_PERIPH_CLK_CTRL_SHARED +#define SPI_COMMON_RCC_CLOCK_ATOMIC() PERIPH_RCC_ATOMIC() +#else +#define SPI_COMMON_RCC_CLOCK_ATOMIC() #endif static const char *SPI_TAG = "spi"; @@ -100,7 +107,15 @@ bool spicommon_periph_claim(spi_host_device_t host, const char* source) bool ret = atomic_compare_exchange_strong(&spi_periph_claimed[host], &false_var, true); if (ret) { spi_claiming_func[host] = source; +#if CONFIG_IDF_TARGET_ESP32P4 //deprecate clk_gate_ll start from p4, others in TODO: IDF-8159 + SPI_COMMON_RCC_CLOCK_ATOMIC() { + spi_ll_enable_bus_clock(host, true); + spi_ll_reset_register(host); + spi_ll_enable_clock(host, true); + } +#else periph_module_enable(spi_periph_signal[host].module); +#endif } else { ESP_EARLY_LOGE(SPI_TAG, "SPI%d already claimed by %s.", host+1, spi_claiming_func[host]); } @@ -117,7 +132,15 @@ bool spicommon_periph_free(spi_host_device_t host) { bool true_var = true; bool ret = atomic_compare_exchange_strong(&spi_periph_claimed[host], &true_var, false); - if (ret) periph_module_disable(spi_periph_signal[host].module); + if (ret) { +#if CONFIG_IDF_TARGET_ESP32P4 + SPI_COMMON_RCC_CLOCK_ATOMIC() { + spi_ll_enable_bus_clock(host, false); + } +#else + periph_module_disable(spi_periph_signal[host].module); +#endif + } return ret; } @@ -218,6 +241,12 @@ static esp_err_t alloc_dma_chan(spi_host_device_t host_id, spi_dma_chan_t dma_ch } #else //SOC_GDMA_SUPPORTED + +#if (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AHB) +static esp_err_t (*spi_gdma_chan_allocator)(const gdma_channel_alloc_config_t *, gdma_channel_handle_t *) = gdma_new_ahb_channel; +#elif (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AXI) +static esp_err_t (*spi_gdma_chan_allocator)(const gdma_channel_alloc_config_t *, gdma_channel_handle_t *) = gdma_new_axi_channel; +#endif static esp_err_t alloc_dma_chan(spi_host_device_t host_id, spi_dma_chan_t dma_chan, uint32_t *out_actual_tx_dma_chan, uint32_t *out_actual_rx_dma_chan) { assert(is_valid_host(host_id)); @@ -231,19 +260,13 @@ static esp_err_t alloc_dma_chan(spi_host_device_t host_id, spi_dma_chan_t dma_ch .flags.reserve_sibling = 1, .direction = GDMA_CHANNEL_DIRECTION_TX, }; - ret = gdma_new_channel(&tx_alloc_config, &ctx->tx_channel); - if (ret != ESP_OK) { - return ret; - } + ESP_RETURN_ON_ERROR(spi_gdma_chan_allocator(&tx_alloc_config, &ctx->tx_channel), SPI_TAG, "alloc gdma tx failed"); gdma_channel_alloc_config_t rx_alloc_config = { .direction = GDMA_CHANNEL_DIRECTION_RX, .sibling_chan = ctx->tx_channel, }; - ret = gdma_new_channel(&rx_alloc_config, &ctx->rx_channel); - if (ret != ESP_OK) { - return ret; - } + ESP_RETURN_ON_ERROR(spi_gdma_chan_allocator(&rx_alloc_config, &ctx->rx_channel), SPI_TAG, "alloc gdma rx failed"); if (host_id == SPI2_HOST) { gdma_connect(ctx->rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SPI, 2)); @@ -802,17 +825,22 @@ esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t * bus_attr->tx_dma_chan = actual_tx_dma_chan; bus_attr->rx_dma_chan = actual_rx_dma_chan; - int dma_desc_ct = lldesc_get_required_num(bus_config->max_transfer_sz); + int dma_desc_ct = (bus_config->max_transfer_sz + DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED - 1) / DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED; if (dma_desc_ct == 0) dma_desc_ct = 1; //default to 4k when max is not given - bus_attr->max_transfer_sz = dma_desc_ct * LLDESC_MAX_NUM_PER_DESC; - bus_attr->dmadesc_tx = heap_caps_malloc(sizeof(lldesc_t) * dma_desc_ct, MALLOC_CAP_DMA); - bus_attr->dmadesc_rx = heap_caps_malloc(sizeof(lldesc_t) * dma_desc_ct, MALLOC_CAP_DMA); + bus_attr->max_transfer_sz = dma_desc_ct * DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED; + bus_attr->dmadesc_tx = heap_caps_aligned_alloc(DMA_DESC_MEM_ALIGN_SIZE, sizeof(spi_dma_desc_t) * dma_desc_ct, MALLOC_CAP_DMA); + bus_attr->dmadesc_rx = heap_caps_aligned_alloc(DMA_DESC_MEM_ALIGN_SIZE, sizeof(spi_dma_desc_t) * dma_desc_ct, MALLOC_CAP_DMA); if (bus_attr->dmadesc_tx == NULL || bus_attr->dmadesc_rx == NULL) { err = ESP_ERR_NO_MEM; goto cleanup; } bus_attr->dma_desc_num = dma_desc_ct; +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + bus_attr->internal_mem_align_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); +#else + bus_attr->internal_mem_align_size = 4; +#endif } else { bus_attr->dma_enabled = 0; bus_attr->max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE; diff --git a/components/driver/spi/gpspi/spi_master.c b/components/driver/spi/gpspi/spi_master.c index a3178346f7..0a47c4bddc 100644 --- a/components/driver/spi/gpspi/spi_master.c +++ b/components/driver/spi/gpspi/spi_master.c @@ -112,6 +112,7 @@ We have two bits to control the interrupt: #include #include +#include "esp_private/periph_ctrl.h" #include "esp_private/spi_common_internal.h" #include "driver/spi_master.h" #include "esp_clk_tree.h" @@ -126,6 +127,9 @@ We have two bits to control the interrupt: #include "hal/spi_hal.h" #include "hal/spi_ll.h" #include "esp_heap_caps.h" +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE +#include "esp_cache.h" +#endif typedef struct spi_device_t spi_device_t; @@ -172,6 +176,11 @@ static spi_host_t* bus_driver_ctx[SOC_SPI_PERIPH_NUM] = {}; static const char *SPI_TAG = "spi_master"; #define SPI_CHECK(a, str, ret_val) ESP_RETURN_ON_FALSE_ISR(a, ret_val, SPI_TAG, str) +#if SOC_PERIPH_CLK_CTRL_SHARED +#define SPI_MASTER_RCC_CLOCK_ATOMIC() PERIPH_RCC_ATOMIC() +#else +#define SPI_MASTER_RCC_CLOCK_ATOMIC() +#endif static void spi_intr(void *arg); static void spi_bus_intr_enable(void *host); @@ -547,6 +556,9 @@ static SPI_MASTER_ISR_ATTR void spi_setup_device(spi_device_t *dev) if (spi_bus_lock_touch(dev_lock)) { /* Configuration has not been applied yet. */ spi_hal_setup_device(hal, hal_dev); + SPI_MASTER_RCC_CLOCK_ATOMIC() { + spi_ll_set_clk_source(hal->hw, hal_dev->timing_conf.clock_source); + } } } @@ -680,13 +692,24 @@ static void SPI_MASTER_ISR_ATTR spi_intr(void *arg) const int cs = host->cur_cs; //Tell common code DMA workaround that our DMA channel is idle. If needed, the code will do a DMA reset. -#if CONFIG_IDF_TARGET_ESP32 if (bus_attr->dma_enabled) { +#if CONFIG_IDF_TARGET_ESP32 //This workaround is only for esp32, where tx_dma_chan and rx_dma_chan are always same spicommon_dmaworkaround_idle(bus_attr->tx_dma_chan); - } #endif //#if CONFIG_IDF_TARGET_ESP32 +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE //invalidate here to let user access rx data in post_cb if possible + if (host->cur_trans_buf.buffer_to_rcv) { + uint16_t alignment = bus_attr->internal_mem_align_size; + uint32_t buffer_byte_len = (host->cur_trans_buf.trans->rxlength + 7) / 8; + buffer_byte_len = (buffer_byte_len + alignment - 1) & (~(alignment - 1)); + // invalidate priv_trans.buffer_to_rcv anyway, only user provide aligned buffer can rcv correct data in post_cb + esp_err_t ret = esp_cache_msync((void *)host->cur_trans_buf.buffer_to_rcv, buffer_byte_len, ESP_CACHE_MSYNC_FLAG_DIR_M2C); + assert(ret == ESP_OK); + } +#endif + } + //cur_cs is changed to DEV_NUM_MAX here spi_post_trans(host); @@ -824,9 +847,7 @@ static SPI_MASTER_ISR_ATTR void uninstall_priv_desc(spi_trans_priv_t* trans_buf) free((void *)trans_buf->buffer_to_send); //force free, ignore const } // copy data from temporary DMA-capable buffer back to IRAM buffer and free the temporary one. - if (trans_buf->buffer_to_rcv && - (void *)trans_buf->buffer_to_rcv != &trans_desc->rx_data[0] && - trans_buf->buffer_to_rcv != trans_desc->rx_buffer) { // NOLINT(clang-analyzer-unix.Malloc) + if (trans_buf->buffer_to_rcv && (void *)trans_buf->buffer_to_rcv != &trans_desc->rx_data[0] && trans_buf->buffer_to_rcv != trans_desc->rx_buffer) { // NOLINT(clang-analyzer-unix.Malloc) if (trans_desc->flags & SPI_TRANS_USE_RXDATA) { memcpy((uint8_t *) & trans_desc->rx_data[0], trans_buf->buffer_to_rcv, (trans_desc->rxlength + 7) / 8); } else { @@ -836,9 +857,11 @@ static SPI_MASTER_ISR_ATTR void uninstall_priv_desc(spi_trans_priv_t* trans_buf) } } -static SPI_MASTER_ISR_ATTR esp_err_t setup_priv_desc(spi_transaction_t *trans_desc, spi_trans_priv_t* new_desc, bool isdma) +static SPI_MASTER_ISR_ATTR esp_err_t setup_priv_desc(spi_host_t *host, spi_trans_priv_t* priv_desc) { - *new_desc = (spi_trans_priv_t) { .trans = trans_desc, }; + spi_transaction_t *trans_desc = priv_desc->trans; + const spi_bus_attr_t *bus_attr = host->bus_attr; + uint16_t alignment = bus_attr->internal_mem_align_size; // rx memory assign uint32_t* rcv_ptr; @@ -848,13 +871,6 @@ static SPI_MASTER_ISR_ATTR esp_err_t setup_priv_desc(spi_transaction_t *trans_de //if not use RXDATA neither rx_buffer, buffer_to_rcv assigned to NULL rcv_ptr = trans_desc->rx_buffer; } - if (rcv_ptr && isdma && (!esp_ptr_dma_capable(rcv_ptr) || ((int)rcv_ptr % 4 != 0))) { - //if rxbuf in the desc not DMA-capable, malloc a new one. The rx buffer need to be length of multiples of 32 bits to avoid heap corruption. - ESP_LOGD(SPI_TAG, "Allocate RX buffer for DMA" ); - rcv_ptr = heap_caps_malloc(((trans_desc->rxlength + 31) / 32) * 4, MALLOC_CAP_DMA); - if (rcv_ptr == NULL) goto clean_up; - } - new_desc->buffer_to_rcv = rcv_ptr; // tx memory assign const uint32_t *send_ptr; @@ -864,21 +880,53 @@ static SPI_MASTER_ISR_ATTR esp_err_t setup_priv_desc(spi_transaction_t *trans_de //if not use TXDATA neither tx_buffer, tx data assigned to NULL send_ptr = trans_desc->tx_buffer ; } - if (send_ptr && isdma && !esp_ptr_dma_capable( send_ptr )) { - //if txbuf in the desc not DMA-capable, malloc a new one - ESP_LOGD(SPI_TAG, "Allocate TX buffer for DMA" ); - uint32_t *temp = heap_caps_malloc((trans_desc->length + 7) / 8, MALLOC_CAP_DMA); - if (temp == NULL) goto clean_up; - memcpy( temp, send_ptr, (trans_desc->length + 7) / 8 ); - send_ptr = temp; + uint32_t tx_byte_len = (trans_desc->length + 7) / 8; + uint32_t rx_byte_len = (trans_desc->rxlength + 7) / 8; +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + bool tx_un_align = ((((uint32_t)send_ptr) | tx_byte_len) & (alignment - 1)); + bool rx_un_align = ((((uint32_t)rcv_ptr) | rx_byte_len) & (alignment - 1)); +#else + bool tx_un_align = false; //tx don't need align on addr or length, for other chips + bool rx_un_align = (((uint32_t)rcv_ptr) & (alignment - 1)); +#endif + + if (send_ptr && bus_attr->dma_enabled) { + if ((!esp_ptr_dma_capable(send_ptr) || tx_un_align )) { + ESP_RETURN_ON_FALSE(!(trans_desc->flags & SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL), ESP_ERR_INVALID_ARG, SPI_TAG, "Set flag SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL but TX buffer addr&len not align to %d, or not dma_capable", alignment); + //if txbuf in the desc not DMA-capable, or not bytes aligned to alignment, malloc a new one + ESP_EARLY_LOGD(SPI_TAG, "Allocate TX buffer for DMA" ); + tx_byte_len = (tx_byte_len + alignment - 1) & (~(alignment - 1)); // up align alignment + uint32_t *temp = heap_caps_aligned_alloc(alignment, tx_byte_len, MALLOC_CAP_DMA); + if (temp == NULL) { + goto clean_up; + } + + memcpy( temp, send_ptr, (trans_desc->length + 7) / 8 ); + send_ptr = temp; + } +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + esp_err_t ret = esp_cache_msync((void *)send_ptr, tx_byte_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M); + assert(ret == ESP_OK); +#endif } - new_desc->buffer_to_send = send_ptr; + if (rcv_ptr && bus_attr->dma_enabled && (!esp_ptr_dma_capable(rcv_ptr) || rx_un_align )) { + ESP_RETURN_ON_FALSE(!(trans_desc->flags & SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL), ESP_ERR_INVALID_ARG, SPI_TAG, "Set flag SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL but RX buffer addr&len not align to %d, or not dma_capable", alignment); + //if rxbuf in the desc not DMA-capable, or not aligned to alignment, malloc a new one + ESP_EARLY_LOGD(SPI_TAG, "Allocate RX buffer for DMA" ); + rx_byte_len = (rx_byte_len + alignment - 1) & (~(alignment - 1)); // up align alignment + rcv_ptr = heap_caps_aligned_alloc(alignment, rx_byte_len, MALLOC_CAP_DMA); + if (rcv_ptr == NULL) { + goto clean_up; + } + } + priv_desc->buffer_to_send = send_ptr; + priv_desc->buffer_to_rcv = rcv_ptr; return ESP_OK; clean_up: - uninstall_priv_desc(new_desc); + uninstall_priv_desc(priv_desc); return ESP_ERR_NO_MEM; } @@ -897,8 +945,8 @@ esp_err_t SPI_MASTER_ATTR spi_device_queue_trans(spi_device_handle_t handle, spi return ESP_ERR_INVALID_ARG; } - spi_trans_priv_t trans_buf; - ret = setup_priv_desc(trans_desc, &trans_buf, (host->bus_attr->dma_enabled)); + spi_trans_priv_t trans_buf = { .trans = trans_desc, }; + ret = setup_priv_desc(host, &trans_buf); if (ret != ESP_OK) return ret; #ifdef CONFIG_PM_ENABLE @@ -935,6 +983,7 @@ esp_err_t SPI_MASTER_ATTR spi_device_get_trans_result(spi_device_handle_t handle BaseType_t r; spi_trans_priv_t trans_buf; SPI_CHECK(handle!=NULL, "invalid dev handle", ESP_ERR_INVALID_ARG); + bool use_dma = handle->host->bus_attr->dma_enabled; //if SPI_DEVICE_NO_RETURN_RESULT is set, ret_queue will always be empty SPI_CHECK(!(handle->cfg.flags & SPI_DEVICE_NO_RETURN_RESULT), "API not Supported!", ESP_ERR_NOT_SUPPORTED); @@ -947,8 +996,10 @@ esp_err_t SPI_MASTER_ATTR spi_device_get_trans_result(spi_device_handle_t handle // Every in-flight transaction request occupies internal memory as DMA buffer if needed. return ESP_ERR_TIMEOUT; } - //release temporary buffers - uninstall_priv_desc(&trans_buf); + //release temporary buffers used by dma + if (use_dma) { + uninstall_priv_desc(&trans_buf); + } (*trans_desc) = trans_buf.trans; return ESP_OK; @@ -1043,8 +1094,8 @@ esp_err_t SPI_MASTER_ISR_ATTR spi_device_polling_start(spi_device_handle_t handl SPI_CHECK(!spi_bus_device_is_polling(handle), "Cannot send polling transaction while the previous polling transaction is not terminated.", ESP_ERR_INVALID_STATE ); spi_host_t *host = handle->host; - spi_trans_priv_t priv_polling_trans; - ret = setup_priv_desc(trans_desc, &priv_polling_trans, (host->bus_attr->dma_enabled)); + spi_trans_priv_t priv_polling_trans = { .trans = trans_desc, }; + ret = setup_priv_desc(host, &priv_polling_trans); if (ret!=ESP_OK) return ret; /* If device_acquiring_lock is set to handle, it means that the user has already @@ -1065,6 +1116,7 @@ esp_err_t SPI_MASTER_ISR_ATTR spi_device_polling_start(spi_device_handle_t handl ESP_LOGE(SPI_TAG, "polling can't get buslock"); return ret; } + //After holding the buslock, common resource can be accessed !! //Polling, no interrupt is used. host->polling = true; diff --git a/components/driver/spi/gpspi/spi_slave.c b/components/driver/spi/gpspi/spi_slave.c index 1991b56a35..af9ca699d9 100644 --- a/components/driver/spi/gpspi/spi_slave.c +++ b/components/driver/spi/gpspi/spi_slave.c @@ -163,6 +163,9 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b bool use_dma = (dma_chan != SPI_DMA_DISABLED); spihost[host]->dma_enabled = use_dma; if (use_dma) { +#if CONFIG_IDF_TARGET_ESP32P4 + abort(); //will supported in IDF-7503 +#endif ret = spicommon_dma_chan_alloc(host, dma_chan, &actual_tx_dma_chan, &actual_rx_dma_chan); if (ret != ESP_OK) { goto cleanup; diff --git a/components/driver/spi/include/driver/spi_master.h b/components/driver/spi/include/driver/spi_master.h index d5c6bcbc59..305d6beadd 100644 --- a/components/driver/spi/include/driver/spi_master.h +++ b/components/driver/spi/include/driver/spi_master.h @@ -115,6 +115,7 @@ typedef struct { #define SPI_TRANS_MULTILINE_CMD (1<<9) ///< The data lines used at command phase is the same as data phase (otherwise, only one data line is used at command phase) #define SPI_TRANS_MODE_OCT (1<<10) ///< Transmit/receive data in 8-bit mode #define SPI_TRANS_MULTILINE_ADDR SPI_TRANS_MODE_DIOQIO_ADDR ///< The data lines used at address phase is the same as data phase (otherwise, only one data line is used at address phase) +#define SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL (1<<11) ///< By default driver will automatically re-alloc dma buffer if it doesn't meet hardware alignment or dma_capable requirements, this flag is for you to disable this feature, you will need to take care of the alignment otherwise driver will return you error ESP_ERR_INVALID_ARG /** * This structure describes one SPI transaction. The descriptor should not be modified until the transaction finishes. @@ -208,6 +209,7 @@ esp_err_t spi_bus_remove_device(spi_device_handle_t handle); * @return * - ESP_ERR_INVALID_ARG if parameter is invalid. This can happen if SPI_TRANS_CS_KEEP_ACTIVE flag is specified while * the bus was not acquired (`spi_device_acquire_bus()` should be called first) + * or set flag SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL but tx or rx buffer not DMA-capable, or addr&len not align to cache line size * - ESP_ERR_TIMEOUT if there was no room in the queue before ticks_to_wait expired * - ESP_ERR_NO_MEM if allocating DMA-capable temporary buffer failed * - ESP_ERR_INVALID_STATE if previous transactions are not finished @@ -273,6 +275,7 @@ esp_err_t spi_device_transmit(spi_device_handle_t handle, spi_transaction_t *tra * @return * - ESP_ERR_INVALID_ARG if parameter is invalid. This can happen if SPI_TRANS_CS_KEEP_ACTIVE flag is specified while * the bus was not acquired (`spi_device_acquire_bus()` should be called first) + * or set flag SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL but tx or rx buffer not DMA-capable, or addr&len not align to cache line size * - ESP_ERR_TIMEOUT if the device cannot get control of the bus before ``ticks_to_wait`` expired * - ESP_ERR_NO_MEM if allocating DMA-capable temporary buffer failed * - ESP_ERR_INVALID_STATE if previous transactions are not finished diff --git a/components/hal/esp32/include/hal/spi_ll.h b/components/hal/esp32/include/hal/spi_ll.h index b5cad9a92a..42a64fa0cc 100644 --- a/components/hal/esp32/include/hal/spi_ll.h +++ b/components/hal/esp32/include/hal/spi_ll.h @@ -63,6 +63,7 @@ typedef spi_dev_t spi_dma_dev_t; * @param hw Beginning address of the peripheral registers. * @param clk_source clock source to select, see valid sources in type `spi_clock_source_t` */ +__attribute__((always_inline)) static inline void spi_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_source) { //empty, keep this for compatibility diff --git a/components/hal/esp32c2/include/hal/spi_ll.h b/components/hal/esp32c2/include/hal/spi_ll.h index e16c8c7055..7bad336400 100644 --- a/components/hal/esp32c2/include/hal/spi_ll.h +++ b/components/hal/esp32c2/include/hal/spi_ll.h @@ -97,6 +97,7 @@ typedef enum { * @param hw Beginning address of the peripheral registers. * @param clk_source clock source to select, see valid sources in type `spi_clock_source_t` */ +__attribute__((always_inline)) static inline void spi_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_source){ switch (clk_source) { diff --git a/components/hal/esp32c3/include/hal/spi_ll.h b/components/hal/esp32c3/include/hal/spi_ll.h index 0cd6d8fc3c..7f202ddc52 100644 --- a/components/hal/esp32c3/include/hal/spi_ll.h +++ b/components/hal/esp32c3/include/hal/spi_ll.h @@ -99,6 +99,7 @@ typedef enum { * @param hw Beginning address of the peripheral registers. * @param clk_source clock source to select, see valid sources in type `spi_clock_source_t` */ +__attribute__((always_inline)) static inline void spi_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_source){ switch (clk_source) { diff --git a/components/hal/esp32c6/include/hal/spi_ll.h b/components/hal/esp32c6/include/hal/spi_ll.h index 6599f0e1bf..effcdd505e 100644 --- a/components/hal/esp32c6/include/hal/spi_ll.h +++ b/components/hal/esp32c6/include/hal/spi_ll.h @@ -98,6 +98,7 @@ typedef enum { * @param hw Beginning address of the peripheral registers. * @param clk_source clock source to select, see valid sources in type `spi_clock_source_t` */ +__attribute__((always_inline)) static inline void spi_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_source) { switch (clk_source) diff --git a/components/hal/esp32h2/include/hal/spi_ll.h b/components/hal/esp32h2/include/hal/spi_ll.h index 1bdf297ab3..d18bb36638 100644 --- a/components/hal/esp32h2/include/hal/spi_ll.h +++ b/components/hal/esp32h2/include/hal/spi_ll.h @@ -100,6 +100,7 @@ typedef enum { * @param hw Beginning address of the peripheral registers. * @param clk_source clock source to select, see valid sources in type `spi_clock_source_t` */ +__attribute__((always_inline)) static inline void spi_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_source) { switch (clk_source) diff --git a/components/hal/esp32p4/include/hal/cache_ll.h b/components/hal/esp32p4/include/hal/cache_ll.h index 2054bebf5d..2452fb93ee 100644 --- a/components/hal/esp32p4/include/hal/cache_ll.h +++ b/components/hal/esp32p4/include/hal/cache_ll.h @@ -23,7 +23,7 @@ extern "C" { * @brief Given a L2MEM cached address, get the corresponding non-cacheable address * @example 0x4FF0_0000 => 0x8FF0_0000 */ -#define CACHE_LL_L2MEM_NON_CACHE_ADDR(addr) ((intptr_t)(addr) + 0x40000000) +#define CACHE_LL_L2MEM_NON_CACHE_ADDR(addr) ((intptr_t)(addr) + SOC_NON_CACHEABLE_OFFSET) /** * Cache capabilities diff --git a/components/hal/esp32p4/include/hal/clk_gate_ll.h b/components/hal/esp32p4/include/hal/clk_gate_ll.h index 8b21f7dfbb..20a5c86f33 100644 --- a/components/hal/esp32p4/include/hal/clk_gate_ll.h +++ b/components/hal/esp32p4/include/hal/clk_gate_ll.h @@ -54,12 +54,6 @@ static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph) return HP_SYS_CLKRST_REG_TWAI1_CLK_EN; case PERIPH_TWAI2_MODULE: return HP_SYS_CLKRST_REG_TWAI2_CLK_EN; - case PERIPH_GPSPI_MODULE: - return HP_SYS_CLKRST_REG_GPSPI2_HS_CLK_EN; - case PERIPH_GPSPI2_MODULE: - return HP_SYS_CLKRST_REG_GPSPI2_MST_CLK_EN; - case PERIPH_GPSPI3_MODULE: - return HP_SYS_CLKRST_REG_GPSPI3_MST_CLK_EN; case PERIPH_I3C_MODULE: return HP_SYS_CLKRST_REG_I3C_MST_CLK_EN; case PERIPH_CAM_MODULE: @@ -145,10 +139,6 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en return HP_SYS_CLKRST_REG_RST_EN_CAN2; case PERIPH_LEDC_MODULE: return HP_SYS_CLKRST_REG_RST_EN_LEDC; - case PERIPH_GPSPI2_MODULE: - return HP_SYS_CLKRST_REG_RST_EN_SPI2; - case PERIPH_GPSPI3_MODULE: - return HP_SYS_CLKRST_REG_RST_EN_SPI3; case PERIPH_LCD_MODULE: return HP_SYS_CLKRST_REG_RST_EN_LCDCAM; case PERIPH_SARADC_MODULE: @@ -224,10 +214,6 @@ static inline uint32_t periph_ll_get_clk_en_reg(periph_module_t periph) case PERIPH_TWAI1_MODULE: case PERIPH_TWAI2_MODULE: return HP_SYS_CLKRST_PERI_CLK_CTRL116_REG; - case PERIPH_GPSPI_MODULE: - case PERIPH_GPSPI2_MODULE: - case PERIPH_GPSPI3_MODULE: - return HP_SYS_CLKRST_PERI_CLK_CTRL117_REG; case PERIPH_I3C_MODULE: case PERIPH_CAM_MODULE: return HP_SYS_CLKRST_PERI_CLK_CTRL119_REG; @@ -282,8 +268,6 @@ static inline uint32_t periph_ll_get_rst_en_reg(periph_module_t periph) case PERIPH_TWAI1_MODULE: case PERIPH_TWAI2_MODULE: case PERIPH_LEDC_MODULE: - case PERIPH_GPSPI2_MODULE: - case PERIPH_GPSPI3_MODULE: case PERIPH_CAM_MODULE: case PERIPH_SARADC_MODULE: case PERIPH_AES_MODULE: diff --git a/components/hal/esp32p4/include/hal/spi_ll.h b/components/hal/esp32p4/include/hal/spi_ll.h new file mode 100644 index 0000000000..923c4ec00b --- /dev/null +++ b/components/hal/esp32p4/include/hal/spi_ll.h @@ -0,0 +1,1279 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/******************************************************************************* + * NOTICE + * The hal is not public api, don't use in application code. + * See readme.md in soc/include/hal/readme.md + ******************************************************************************/ + +// The LL layer for SPI register operations + +#pragma once + +#include //for abs() +#include +#include "esp_types.h" +#include "soc/spi_periph.h" +#include "soc/spi_struct.h" +#include "soc/lldesc.h" +#include "hal/assert.h" +#include "hal/misc.h" +#include "hal/spi_types.h" +#include "soc/hp_sys_clkrst_struct.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/// Interrupt not used. Don't use in app. +#define SPI_LL_UNUSED_INT_MASK (SPI_TRANS_DONE_INT_ENA | SPI_SLV_WR_DMA_DONE_INT_ENA | SPI_SLV_RD_DMA_DONE_INT_ENA | SPI_SLV_WR_BUF_DONE_INT_ENA | SPI_SLV_RD_BUF_DONE_INT_ENA) +/// These 2 masks together will set SPI transaction to one line mode +#define SPI_LL_ONE_LINE_CTRL_MASK (SPI_FREAD_QUAD | SPI_FREAD_DUAL | SPI_FCMD_QUAD | SPI_FCMD_DUAL | SPI_FADDR_QUAD | SPI_FADDR_DUAL) +#define SPI_LL_ONE_LINE_USER_MASK (SPI_FWRITE_QUAD | SPI_FWRITE_DUAL) +/// Swap the bit order to its correct place to send +#define HAL_SPI_SWAP_DATA_TX(data, len) HAL_SWAP32((uint32_t)(data) << (32 - len)) +#define SPI_LL_GET_HW(ID) ((ID)==0? ({abort();NULL;}):((ID)==1? &GPSPI2 : &GPSPI3)) + +#define SPI_LL_DMA_MAX_BIT_LEN (1 << 18) //reg len: 18 bits +#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words + +/** + * The data structure holding calculated clock configuration. Since the + * calculation needs long time, it should be calculated during initialization and + * stored somewhere to be quickly used. + */ +typedef uint32_t spi_ll_clock_val_t; +typedef spi_dev_t spi_dma_dev_t; + +// Type definition of all supported interrupts +typedef enum { + SPI_LL_INTR_TRANS_DONE = BIT(0), ///< A transaction has done + SPI_LL_INTR_RDBUF = BIT(6), ///< Has received RDBUF command. Only available in slave HD. + SPI_LL_INTR_WRBUF = BIT(7), ///< Has received WRBUF command. Only available in slave HD. + SPI_LL_INTR_RDDMA = BIT(8), ///< Has received RDDMA command. Only available in slave HD. + SPI_LL_INTR_WRDMA = BIT(9), ///< Has received WRDMA command. Only available in slave HD. + SPI_LL_INTR_CMD7 = BIT(10), ///< Has received CMD7 command. Only available in slave HD. + SPI_LL_INTR_CMD8 = BIT(11), ///< Has received CMD8 command. Only available in slave HD. + SPI_LL_INTR_CMD9 = BIT(12), ///< Has received CMD9 command. Only available in slave HD. + SPI_LL_INTR_CMDA = BIT(13), ///< Has received CMDA command. Only available in slave HD. + SPI_LL_INTR_SEG_DONE = BIT(14), +} spi_ll_intr_t; + +// Flags for conditions under which the transaction length should be recorded +typedef enum { + SPI_LL_TRANS_LEN_COND_WRBUF = BIT(0), ///< WRBUF length will be recorded + SPI_LL_TRANS_LEN_COND_RDBUF = BIT(1), ///< RDBUF length will be recorded + SPI_LL_TRANS_LEN_COND_WRDMA = BIT(2), ///< WRDMA length will be recorded + SPI_LL_TRANS_LEN_COND_RDDMA = BIT(3), ///< RDDMA length will be recorded +} spi_ll_trans_len_cond_t; + +// SPI base command +typedef enum { + /* Slave HD Only */ + SPI_LL_BASE_CMD_HD_WRBUF = 0x01, + SPI_LL_BASE_CMD_HD_RDBUF = 0x02, + SPI_LL_BASE_CMD_HD_WRDMA = 0x03, + SPI_LL_BASE_CMD_HD_RDDMA = 0x04, + SPI_LL_BASE_CMD_HD_SEG_END = 0x05, + SPI_LL_BASE_CMD_HD_EN_QPI = 0x06, + SPI_LL_BASE_CMD_HD_WR_END = 0x07, + SPI_LL_BASE_CMD_HD_INT0 = 0x08, + SPI_LL_BASE_CMD_HD_INT1 = 0x09, + SPI_LL_BASE_CMD_HD_INT2 = 0x0A, +} spi_ll_base_command_t; +/*------------------------------------------------------------------------------ + * Control + *----------------------------------------------------------------------------*/ + +/** + * Enable peripheral register clock + * + * @param host_id Peripheral index number, see `spi_host_device_t` + * @param enable Enable/Disable + */ +static inline void spi_ll_enable_bus_clock(spi_host_device_t host_id, bool enable) { + switch (host_id) + { + case SPI2_HOST: + HP_SYS_CLKRST.soc_clk_ctrl1.reg_gpspi2_sys_clk_en = enable; + HP_SYS_CLKRST.soc_clk_ctrl2.reg_gpspi2_apb_clk_en = enable; + break; + case SPI3_HOST: + HP_SYS_CLKRST.soc_clk_ctrl1.reg_gpspi3_sys_clk_en = enable; + HP_SYS_CLKRST.soc_clk_ctrl2.reg_gpspi3_apb_clk_en = enable; + break; + default: HAL_ASSERT(false); + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define spi_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; spi_ll_enable_bus_clock(__VA_ARGS__) + +/** + * Reset whole peripheral register to init value defined by HW design + * + * @param host_id Peripheral index number, see `spi_host_device_t` + */ +static inline void spi_ll_reset_register(spi_host_device_t host_id) { + switch (host_id) + { + case SPI2_HOST: + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_spi2 = 1; + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_spi2 = 0; + break; + case SPI3_HOST: + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_spi3 = 1; + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_spi3 = 0; + break; + default: HAL_ASSERT(false); + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define spi_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; spi_ll_reset_register(__VA_ARGS__) + +/** + * Enable functional output clock within peripheral + * + * @param host_id Peripheral index number, see `spi_host_device_t` + * @param enable Enable/Disable + */ +static inline void spi_ll_enable_clock(spi_host_device_t host_id, bool enable) +{ + switch (host_id) + { + case SPI2_HOST: + HP_SYS_CLKRST.peri_clk_ctrl116.reg_gpspi2_hs_clk_en = enable; + HP_SYS_CLKRST.peri_clk_ctrl116.reg_gpspi2_mst_clk_en = enable; + break; + case SPI3_HOST: + HP_SYS_CLKRST.peri_clk_ctrl116.reg_gpspi3_hs_clk_en = enable; + HP_SYS_CLKRST.peri_clk_ctrl117.reg_gpspi3_mst_clk_en = enable; + break; + default: HAL_ASSERT(false); + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define spi_ll_enable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; spi_ll_enable_clock(__VA_ARGS__) + +/** + * Select SPI peripheral clock source (master). + * + * @param hw Beginning address of the peripheral registers. + * @param clk_source clock source to select, see valid sources in type `spi_clock_source_t` + */ +__attribute__((always_inline)) +static inline void spi_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_source) +{ + uint32_t clk_id = 0; + switch (clk_source) { + case SPI_CLK_SRC_XTAL: + clk_id = 0; + break; + default: + HAL_ASSERT(false); + } + + if (hw == &GPSPI2) { + HP_SYS_CLKRST.peri_clk_ctrl116.reg_gpspi2_clk_src_sel = clk_id; + } else if (hw == &GPSPI3) { + HP_SYS_CLKRST.peri_clk_ctrl116.reg_gpspi3_clk_src_sel = clk_id; + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define spi_ll_set_clk_source(...) (void)__DECLARE_RCC_ATOMIC_ENV; spi_ll_set_clk_source(__VA_ARGS__) + +/** + * Initialize SPI peripheral (master). + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_master_init(spi_dev_t *hw) +{ + //Reset timing + hw->user1.cs_setup_time = 0; + hw->user1.cs_hold_time = 0; + + //use all 64 bytes of the buffer + hw->user.usr_miso_highpart = 0; + hw->user.usr_mosi_highpart = 0; + + //Disable unneeded ints + hw->slave.val = 0; + hw->user.val = 0; + + hw->dma_conf.val = 0; + hw->dma_conf.slv_tx_seg_trans_clr_en = 1; + hw->dma_conf.slv_rx_seg_trans_clr_en = 1; + hw->dma_conf.dma_slv_seg_trans_en = 0; +} + +/** + * Initialize SPI peripheral (slave). + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_slave_init(spi_dev_t *hw) +{ + //Configure slave + hw->clock.val = 0; + hw->user.val = 0; + hw->ctrl.val = 0; + hw->user.doutdin = 1; //we only support full duplex + hw->user.sio = 0; + hw->slave.slave_mode = 1; + hw->slave.soft_reset = 1; + hw->slave.soft_reset = 0; + //use all 64 bytes of the buffer + hw->user.usr_miso_highpart = 0; + hw->user.usr_mosi_highpart = 0; + + // Configure DMA In-Link to not be terminated when transaction bit counter exceeds + hw->dma_conf.rx_eof_en = 0; + hw->dma_conf.dma_slv_seg_trans_en = 0; + + //Disable unneeded ints + hw->dma_int_ena.val &= ~SPI_LL_UNUSED_INT_MASK; +} + +/** + * Initialize SPI peripheral (slave half duplex mode) + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_slave_hd_init(spi_dev_t *hw) +{ + hw->clock.val = 0; + hw->user.val = 0; + hw->ctrl.val = 0; + hw->user.doutdin = 0; + hw->user.sio = 0; + + hw->slave.soft_reset = 1; + hw->slave.soft_reset = 0; + hw->slave.slave_mode = 1; +} + +/** + * Check whether user-defined transaction is done. + * + * @param hw Beginning address of the peripheral registers. + * + * @return True if transaction is done, otherwise false. + */ +static inline bool spi_ll_usr_is_done(spi_dev_t *hw) +{ + return hw->dma_int_raw.trans_done_int; +} + +/** + * Apply the register configurations and wait until it's done + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_apply_config(spi_dev_t *hw) +{ + hw->cmd.update = 1; + while (hw->cmd.update); //waiting config applied +} + +/** + * Trigger start of user-defined transaction. + * The synchronization between two clock domains is required in ESP32-S3 + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_user_start(spi_dev_t *hw) +{ + hw->cmd.usr = 1; +} + +/** + * Get current running command bit-mask. (Preview) + * + * @param hw Beginning address of the peripheral registers. + * + * @return Bitmask of running command, see ``SPI_CMD_REG``. 0 if no in-flight command. + */ +static inline uint32_t spi_ll_get_running_cmd(spi_dev_t *hw) +{ + return hw->cmd.usr; +} + +/** + * Reset the slave peripheral before next transaction. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_slave_reset(spi_dev_t *hw) +{ + hw->slave.soft_reset = 1; + hw->slave.soft_reset = 0; +} + +/** + * Reset SPI CPU TX FIFO + * + * On P4, this function is not seperated + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_cpu_tx_fifo_reset(spi_dev_t *hw) +{ + hw->dma_conf.buf_afifo_rst = 1; + hw->dma_conf.buf_afifo_rst = 0; +} + +/** + * Reset SPI CPU RX FIFO + * + * On P4, this function is not seperated + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_cpu_rx_fifo_reset(spi_dev_t *hw) +{ + hw->dma_conf.rx_afifo_rst = 1; + hw->dma_conf.rx_afifo_rst = 0; +} + +/** + * Reset SPI DMA TX FIFO + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_dma_tx_fifo_reset(spi_dev_t *hw) +{ + hw->dma_conf.dma_afifo_rst = 1; + hw->dma_conf.dma_afifo_rst = 0; +} + +/** + * Reset SPI DMA RX FIFO + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_dma_rx_fifo_reset(spi_dev_t *hw) +{ + hw->dma_conf.rx_afifo_rst = 1; + hw->dma_conf.rx_afifo_rst = 0; +} + +/** + * Clear in fifo full error + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_infifo_full_clr(spi_dev_t *hw) +{ + hw->dma_int_clr.dma_infifo_full_err_int = 1; +} + +/** + * Clear out fifo empty error + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_outfifo_empty_clr(spi_dev_t *hw) +{ + hw->dma_int_clr.dma_outfifo_empty_err_int = 1; +} + +/*------------------------------------------------------------------------------ + * DMA + *----------------------------------------------------------------------------*/ +/** + * Enable/Disable RX DMA (Peripherals->DMA->RAM) + * + * @param hw Beginning address of the peripheral registers. + * @param enable 1: enable; 2: disable + */ +static inline void spi_ll_dma_rx_enable(spi_dev_t *hw, bool enable) +{ + hw->dma_conf.dma_rx_ena = enable; +} + +/** + * Enable/Disable TX DMA (RAM->DMA->Peripherals) + * + * @param hw Beginning address of the peripheral registers. + * @param enable 1: enable; 2: disable + */ +static inline void spi_ll_dma_tx_enable(spi_dev_t *hw, bool enable) +{ + hw->dma_conf.dma_tx_ena = enable; +} + +/** + * Configuration of RX DMA EOF interrupt generation way + * + * @param hw Beginning address of the peripheral registers. + * @param enable 1: spi_dma_inlink_eof is set when the number of dma pushed data bytes is equal to the value of spi_slv/mst_dma_rd_bytelen[19:0] in spi dma transition. 0: spi_dma_inlink_eof is set by spi_trans_done in non-seg-trans or spi_dma_seg_trans_done in seg-trans. + */ +static inline void spi_ll_dma_set_rx_eof_generation(spi_dev_t *hw, bool enable) +{ + hw->dma_conf.rx_eof_en = enable; +} + +/*------------------------------------------------------------------------------ + * Buffer + *----------------------------------------------------------------------------*/ +/** + * Write to SPI hardware data buffer. + * + * @param hw Beginning address of the peripheral registers. + * @param buffer_to_send Address of the data to be written to the hardware data buffer. + * @param bitlen Length to write, in bits. + */ +static inline void spi_ll_write_buffer(spi_dev_t *hw, const uint8_t *buffer_to_send, size_t bitlen) +{ + for (int x = 0; x < bitlen; x += 32) { + //Use memcpy to get around alignment issues for txdata + uint32_t word; + memcpy(&word, &buffer_to_send[x / 8], 4); + hw->data_buf[(x / 32)].buf = word; + } +} + +/** + * Write to SPI hardware data buffer by buffer ID (address) + * + * @param hw Beginning address of the peripheral registers + * @param byte_id Start ID (address) of the hardware buffer to be written + * @param data Address of the data to be written to the hardware data buffer. + * @param len Length to write, in bytes. + */ +static inline void spi_ll_write_buffer_byte(spi_dev_t *hw, int byte_id, uint8_t *data, int len) +{ + HAL_ASSERT(byte_id + len <= 64); + HAL_ASSERT(len > 0); + HAL_ASSERT(byte_id >= 0); + + while (len > 0) { + uint32_t word; + int offset = byte_id % 4; + int copy_len = 4 - offset; + if (copy_len > len) { + copy_len = len; + } + + //read-modify-write + if (copy_len != 4) { + word = hw->data_buf[byte_id / 4].buf; //read + } + memcpy(((uint8_t *)&word) + offset, data, copy_len); //modify + hw->data_buf[byte_id / 4].buf = word; //write + + data += copy_len; + byte_id += copy_len; + len -= copy_len; + } +} + +/** + * Read from SPI hardware data buffer. + * + * @param hw Beginning address of the peripheral registers. + * @param buffer_to_rcv Address of a buffer to read data from hardware data buffer + * @param bitlen Length to read, in bits. + */ +static inline void spi_ll_read_buffer(spi_dev_t *hw, uint8_t *buffer_to_rcv, size_t bitlen) +{ + for (int x = 0; x < bitlen; x += 32) { + //Do a memcpy to get around possible alignment issues in rx_buffer + uint32_t word = hw->data_buf[x / 32].buf; + int len = bitlen - x; + if (len > 32) { + len = 32; + } + memcpy(&buffer_to_rcv[x / 8], &word, (len + 7) / 8); + } +} + +/** + * Read from SPI hardware data buffer by buffer ID (address) + * + * @param hw Beginning address of the peripheral registers + * @param byte_id Start ID (address) of the hardware buffer to be read + * @param data Address of a buffer to read data from hardware data buffer + * @param len Length to read, in bytes. + */ +static inline void spi_ll_read_buffer_byte(spi_dev_t *hw, int byte_id, uint8_t *out_data, int len) +{ + while (len > 0) { + uint32_t word = hw->data_buf[byte_id / 4].buf; + int offset = byte_id % 4; + int copy_len = 4 - offset; + if (copy_len > len) { + copy_len = len; + } + + memcpy(out_data, ((uint8_t *)&word) + offset, copy_len); + byte_id += copy_len; + out_data += copy_len; + len -= copy_len; + } +} + +/*------------------------------------------------------------------------------ + * Configs: mode + *----------------------------------------------------------------------------*/ +/** + * Enable/disable the postive-cs feature. + * + * @param hw Beginning address of the peripheral registers. + * @param cs One of the CS (0-2) to enable/disable the feature. + * @param pos_cs True to enable the feature, otherwise disable (default). + */ +static inline void spi_ll_master_set_pos_cs(spi_dev_t *hw, int cs, uint32_t pos_cs) +{ + if (pos_cs) { + hw->misc.master_cs_pol |= (1 << cs); + } else { + hw->misc.master_cs_pol &= ~(1 << cs); + } +} + +/** + * Enable/disable the LSBFIRST feature for TX data. + * + * @param hw Beginning address of the peripheral registers. + * @param lsbfirst True if LSB of TX data to be sent first, otherwise MSB is sent first (default). + */ +static inline void spi_ll_set_tx_lsbfirst(spi_dev_t *hw, bool lsbfirst) +{ + hw->ctrl.wr_bit_order = lsbfirst; +} + +/** + * Enable/disable the LSBFIRST feature for RX data. + * + * @param hw Beginning address of the peripheral registers. + * @param lsbfirst True if first bit received as LSB, otherwise as MSB (default). + */ +static inline void spi_ll_set_rx_lsbfirst(spi_dev_t *hw, bool lsbfirst) +{ + hw->ctrl.rd_bit_order = lsbfirst; +} + +/** + * Set SPI mode for the peripheral as master. + * + * @param hw Beginning address of the peripheral registers. + * @param mode SPI mode to work at, 0-3. + */ +static inline void spi_ll_master_set_mode(spi_dev_t *hw, uint8_t mode) +{ + //Configure polarity + if (mode == 0) { + hw->misc.ck_idle_edge = 0; + hw->user.ck_out_edge = 0; + } else if (mode == 1) { + hw->misc.ck_idle_edge = 0; + hw->user.ck_out_edge = 1; + } else if (mode == 2) { + hw->misc.ck_idle_edge = 1; + hw->user.ck_out_edge = 1; + } else if (mode == 3) { + hw->misc.ck_idle_edge = 1; + hw->user.ck_out_edge = 0; + } +} + +/** + * Set SPI mode for the peripheral as slave. + * + * @param hw Beginning address of the peripheral registers. + * @param mode SPI mode to work at, 0-3. + */ +static inline void spi_ll_slave_set_mode(spi_dev_t *hw, const int mode, bool dma_used) +{ + if (mode == 0) { + hw->misc.ck_idle_edge = 0; + hw->user.rsck_i_edge = 0; + hw->user.tsck_i_edge = 0; + hw->slave.clk_mode_13 = 0; + } else if (mode == 1) { + hw->misc.ck_idle_edge = 0; + hw->user.rsck_i_edge = 1; + hw->user.tsck_i_edge = 1; + hw->slave.clk_mode_13 = 1; + } else if (mode == 2) { + hw->misc.ck_idle_edge = 1; + hw->user.rsck_i_edge = 1; + hw->user.tsck_i_edge = 1; + hw->slave.clk_mode_13 = 0; + } else if (mode == 3) { + hw->misc.ck_idle_edge = 1; + hw->user.rsck_i_edge = 0; + hw->user.tsck_i_edge = 0; + hw->slave.clk_mode_13 = 1; + } + hw->slave.rsck_data_out = 0; +} + +/** + * Set SPI to work in full duplex or half duplex mode. + * + * @param hw Beginning address of the peripheral registers. + * @param half_duplex True to work in half duplex mode, otherwise in full duplex mode. + */ +static inline void spi_ll_set_half_duplex(spi_dev_t *hw, bool half_duplex) +{ + hw->user.doutdin = !half_duplex; +} + +/** + * Set SPI to work in SIO mode or not. + * + * SIO is a mode which MOSI and MISO share a line. The device MUST work in half-duplexmode. + * + * @param hw Beginning address of the peripheral registers. + * @param sio_mode True to work in SIO mode, otherwise false. + */ +static inline void spi_ll_set_sio_mode(spi_dev_t *hw, int sio_mode) +{ + hw->user.sio = sio_mode; +} + +/** + * Configure the SPI transaction line mode for the master to use. + * + * @param hw Beginning address of the peripheral registers. + * @param line_mode SPI transaction line mode to use, see ``spi_line_mode_t``. + */ +static inline void spi_ll_master_set_line_mode(spi_dev_t *hw, spi_line_mode_t line_mode) +{ + hw->ctrl.val &= ~SPI_LL_ONE_LINE_CTRL_MASK; + hw->user.val &= ~SPI_LL_ONE_LINE_USER_MASK; + hw->ctrl.fcmd_dual = (line_mode.cmd_lines == 2); + hw->ctrl.fcmd_quad = (line_mode.cmd_lines == 4); + hw->ctrl.faddr_dual = (line_mode.addr_lines == 2); + hw->ctrl.faddr_quad = (line_mode.addr_lines == 4); + hw->ctrl.fread_dual = (line_mode.data_lines == 2); + hw->user.fwrite_dual = (line_mode.data_lines == 2); + hw->ctrl.fread_quad = (line_mode.data_lines == 4); + hw->user.fwrite_quad = (line_mode.data_lines == 4); +} + +/** + * Set the SPI slave to work in segment transaction mode + * + * @param hw Beginning address of the peripheral registers. + * @param seg_trans True to work in seg mode, otherwise false. + */ +static inline void spi_ll_slave_set_seg_mode(spi_dev_t *hw, bool seg_trans) +{ + hw->dma_conf.dma_slv_seg_trans_en = seg_trans; +} + +/** + * Select one of the CS to use in current transaction. + * + * @param hw Beginning address of the peripheral registers. + * @param cs_id The cs to use, 0-2, otherwise none of them is used. + */ +static inline void spi_ll_master_select_cs(spi_dev_t *hw, int cs_id) +{ + hw->misc.cs0_dis = (cs_id == 0) ? 0 : 1; + hw->misc.cs1_dis = (cs_id == 1) ? 0 : 1; + hw->misc.cs2_dis = (cs_id == 2) ? 0 : 1; + hw->misc.cs3_dis = (cs_id == 3) ? 0 : 1; + hw->misc.cs4_dis = (cs_id == 4) ? 0 : 1; + hw->misc.cs5_dis = (cs_id == 5) ? 0 : 1; +} + +/** + * Keep Chip Select activated after the current transaction. + * + * @param hw Beginning address of the peripheral registers. + * @param keep_active if 0 don't keep CS activated, else keep CS activated + */ +static inline void spi_ll_master_keep_cs(spi_dev_t *hw, int keep_active) +{ + hw->misc.cs_keep_active = (keep_active != 0) ? 1 : 0; +} + +/*------------------------------------------------------------------------------ + * Configs: parameters + *----------------------------------------------------------------------------*/ +/** + * Set the clock for master by stored value. + * + * @param hw Beginning address of the peripheral registers. + * @param val Stored clock configuration calculated before (by ``spi_ll_cal_clock``). + */ +static inline void spi_ll_master_set_clock_by_reg(spi_dev_t *hw, const spi_ll_clock_val_t *val) +{ + hw->clock.val = *(uint32_t *)val; +} + +/** + * Get the frequency of given dividers. Don't use in app. + * + * @param fapb APB clock of the system. + * @param pre Pre devider. + * @param n Main divider. + * + * @return Frequency of given dividers. + */ +static inline int spi_ll_freq_for_pre_n(int fapb, int pre, int n) +{ + return (fapb / (pre * n)); +} + +/** + * Calculate the nearest frequency avaliable for master. + * + * @param fapb APB clock of the system. + * @param hz Frequncy desired. + * @param duty_cycle Duty cycle desired. + * @param out_reg Output address to store the calculated clock configurations for the return frequency. + * + * @return Actual (nearest) frequency. + */ +static inline int spi_ll_master_cal_clock(int fapb, int hz, int duty_cycle, spi_ll_clock_val_t *out_reg) +{ + typeof(GPSPI2.clock) reg; + int eff_clk; + + //In hw, n, h and l are 1-64, pre is 1-8K. Value written to register is one lower than used value. + if (hz > ((fapb / 4) * 3)) { + //Using Fapb directly will give us the best result here. + reg.clkcnt_l = 0; + reg.clkcnt_h = 0; + reg.clkcnt_n = 0; + reg.clkdiv_pre = 0; + reg.clk_equ_sysclk = 1; + eff_clk = fapb; + } else { + //For best duty cycle resolution, we want n to be as close to 32 as possible, but + //we also need a pre/n combo that gets us as close as possible to the intended freq. + //To do this, we bruteforce n and calculate the best pre to go along with that. + //If there's a choice between pre/n combos that give the same result, use the one + //with the higher n. + int pre, n, h, l; + int bestn = -1; + int bestpre = -1; + int besterr = 0; + int errval; + for (n = 2; n <= 64; n++) { //Start at 2: we need to be able to set h/l so we have at least one high and one low pulse. + //Effectively, this does pre=round((fapb/n)/hz). + pre = ((fapb / n) + (hz / 2)) / hz; + if (pre <= 0) { + pre = 1; + } + if (pre > 16) { + pre = 16; + } + errval = abs(spi_ll_freq_for_pre_n(fapb, pre, n) - hz); + if (bestn == -1 || errval <= besterr) { + besterr = errval; + bestn = n; + bestpre = pre; + } + } + + n = bestn; + pre = bestpre; + l = n; + //This effectively does round((duty_cycle*n)/256) + h = (duty_cycle * n + 127) / 256; + if (h <= 0) { + h = 1; + } + + reg.clk_equ_sysclk = 0; + reg.clkcnt_n = n - 1; + reg.clkdiv_pre = pre - 1; + reg.clkcnt_h = h - 1; + reg.clkcnt_l = l - 1; + eff_clk = spi_ll_freq_for_pre_n(fapb, pre, n); + } + if (out_reg != NULL) { + *(uint32_t *)out_reg = reg.val; + } + return eff_clk; +} + +/** + * Calculate and set clock for SPI master according to desired parameters. + * + * This takes long, suggest to calculate the configuration during + * initialization by ``spi_ll_master_cal_clock`` and store the result, then + * configure the clock by stored value when used by + * ``spi_ll_msater_set_clock_by_reg``. + * + * @param hw Beginning address of the peripheral registers. + * @param fapb APB clock of the system. + * @param hz Frequncy desired. + * @param duty_cycle Duty cycle desired. + * + * @return Actual frequency that is used. + */ +static inline int spi_ll_master_set_clock(spi_dev_t *hw, int fapb, int hz, int duty_cycle) +{ + spi_ll_clock_val_t reg_val; + int freq = spi_ll_master_cal_clock(fapb, hz, duty_cycle, ®_val); + spi_ll_master_set_clock_by_reg(hw, ®_val); + return freq; +} + +/** + * Set the mosi delay after the output edge to the signal. (Preview) + * + * The delay mode/num is a Espressif conception, may change in the new chips. + * + * @param hw Beginning address of the peripheral registers. + * @param delay_mode Delay mode, see TRM. + * @param delay_num APB clocks to delay. + */ +static inline void spi_ll_set_mosi_delay(spi_dev_t *hw, int delay_mode, int delay_num) +{ +} + +/** + * Set the miso delay applied to the input signal before the internal peripheral. (Preview) + * + * The delay mode/num is a Espressif conception, may change in the new chips. + * + * @param hw Beginning address of the peripheral registers. + * @param delay_mode Delay mode, see TRM. + * @param delay_num APB clocks to delay. + */ +static inline void spi_ll_set_miso_delay(spi_dev_t *hw, int delay_mode, int delay_num) +{ +} + +/** + * Set the delay of SPI clocks before the CS inactive edge after the last SPI clock. + * + * @param hw Beginning address of the peripheral registers. + * @param hold Delay of SPI clocks after the last clock, 0 to disable the hold phase. + */ +static inline void spi_ll_master_set_cs_hold(spi_dev_t *hw, int hold) +{ + hw->user1.cs_hold_time = hold; + hw->user.cs_hold = hold ? 1 : 0; +} + +/** + * Set the delay of SPI clocks before the first SPI clock after the CS active edge. + * + * Note ESP32 doesn't support to use this feature when command/address phases + * are used in full duplex mode. + * + * @param hw Beginning address of the peripheral registers. + * @param setup Delay of SPI clocks after the CS active edge, 0 to disable the setup phase. + */ +static inline void spi_ll_master_set_cs_setup(spi_dev_t *hw, uint8_t setup) +{ + hw->user1.cs_setup_time = setup - 1; + hw->user.cs_setup = setup ? 1 : 0; +} + +/*------------------------------------------------------------------------------ + * Configs: data + *----------------------------------------------------------------------------*/ +/** + * Set the output length (master). + * This should be called before master setting MISO(input) length + * + * @param hw Beginning address of the peripheral registers. + * @param bitlen output length, in bits. + */ +static inline void spi_ll_set_mosi_bitlen(spi_dev_t *hw, size_t bitlen) +{ + if (bitlen > 0) { + hw->ms_dlen.ms_data_bitlen = bitlen - 1; + } +} + +/** + * Set the input length (master). + * + * @param hw Beginning address of the peripheral registers. + * @param bitlen input length, in bits. + */ +static inline void spi_ll_set_miso_bitlen(spi_dev_t *hw, size_t bitlen) +{ + if (bitlen > 0) { + hw->ms_dlen.ms_data_bitlen = bitlen - 1; + } +} + +/** + * Set the maximum input length (slave). + * + * @param hw Beginning address of the peripheral registers. + * @param bitlen Input length, in bits. + */ +static inline void spi_ll_slave_set_rx_bitlen(spi_dev_t *hw, size_t bitlen) +{ + //This is not used in P4 +} + +/** + * Set the maximum output length (slave). + * + * @param hw Beginning address of the peripheral registers. + * @param bitlen Output length, in bits. + */ +static inline void spi_ll_slave_set_tx_bitlen(spi_dev_t *hw, size_t bitlen) +{ + //This is not used in P4 +} + +/** + * Set the length of command phase. + * + * When in 4-bit mode, the SPI cycles of the phase will be shorter. E.g. 16-bit + * command phases takes 4 cycles in 4-bit mode. + * + * @param hw Beginning address of the peripheral registers. + * @param bitlen Length of command phase, in bits. 0 to disable the command phase. + */ +static inline void spi_ll_set_command_bitlen(spi_dev_t *hw, int bitlen) +{ + hw->user2.usr_command_bitlen = bitlen - 1; + hw->user.usr_command = bitlen ? 1 : 0; +} + +/** + * Set the length of address phase. + * + * When in 4-bit mode, the SPI cycles of the phase will be shorter. E.g. 16-bit + * address phases takes 4 cycles in 4-bit mode. + * + * @param hw Beginning address of the peripheral registers. + * @param bitlen Length of address phase, in bits. 0 to disable the address phase. + */ +static inline void spi_ll_set_addr_bitlen(spi_dev_t *hw, int bitlen) +{ + hw->user1.usr_addr_bitlen = bitlen - 1; + hw->user.usr_addr = bitlen ? 1 : 0; +} + +/** + * Set the address value in an intuitive way. + * + * The length and lsbfirst is required to shift and swap the address to the right place. + * + * @param hw Beginning address of the peripheral registers. + * @param address Address to set + * @param addrlen Length of the address phase + * @param lsbfirst Whether the LSB first feature is enabled. + */ +static inline void spi_ll_set_address(spi_dev_t *hw, uint64_t addr, int addrlen, uint32_t lsbfirst) +{ + if (lsbfirst) { + /* The output address start from the LSB of the highest byte, i.e. + * addr[24] -> addr[31] + * ... + * addr[0] -> addr[7] + * So swap the byte order to let the LSB sent first. + */ + addr = HAL_SWAP32(addr); + //otherwise only addr register is sent + hw->addr.val = addr; + } else { + // shift the address to MSB of addr register. + // output address will be sent from MSB to LSB of addr register + hw->addr.val = addr << (32 - addrlen); + } +} + +/** + * Set the command value in an intuitive way. + * + * The length and lsbfirst is required to shift and swap the command to the right place. + * + * @param hw Beginning command of the peripheral registers. + * @param command Command to set + * @param addrlen Length of the command phase + * @param lsbfirst Whether the LSB first feature is enabled. + */ +static inline void spi_ll_set_command(spi_dev_t *hw, uint16_t cmd, int cmdlen, bool lsbfirst) +{ + if (lsbfirst) { + // The output command start from bit0 to bit 15, kept as is. + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->user2, usr_command_value, cmd); + } else { + /* Output command will be sent from bit 7 to 0 of command_value, and + * then bit 15 to 8 of the same register field. Shift and swap to send + * more straightly. + */ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->user2, usr_command_value, HAL_SPI_SWAP_DATA_TX(cmd, cmdlen)); + } +} + +/** + * Set dummy clocks to output before RX phase (master), or clocks to skip + * before the data phase and after the address phase (slave). + * + * Note this phase is also used to compensate RX timing in half duplex mode. + * + * @param hw Beginning address of the peripheral registers. + * @param dummy_n Dummy cycles used. 0 to disable the dummy phase. + */ +static inline void spi_ll_set_dummy(spi_dev_t *hw, int dummy_n) +{ + hw->user.usr_dummy = dummy_n ? 1 : 0; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->user1, usr_dummy_cyclelen, dummy_n - 1); +} + +/** + * Enable/disable the RX data phase. + * + * @param hw Beginning address of the peripheral registers. + * @param enable True if RX phase exist, otherwise false. + */ +static inline void spi_ll_enable_miso(spi_dev_t *hw, int enable) +{ + hw->user.usr_miso = enable; +} + +/** + * Enable/disable the TX data phase. + * + * @param hw Beginning address of the peripheral registers. + * @param enable True if TX phase exist, otherwise false. + */ +static inline void spi_ll_enable_mosi(spi_dev_t *hw, int enable) +{ + hw->user.usr_mosi = enable; +} + +/** + * Get the received bit length of the slave. + * + * @param hw Beginning address of the peripheral registers. + * + * @return Received bits of the slave. + */ +static inline uint32_t spi_ll_slave_get_rcv_bitlen(spi_dev_t *hw) +{ + return hw->slave1.slv_data_bitlen; +} + +/*------------------------------------------------------------------------------ + * Interrupts + *----------------------------------------------------------------------------*/ +//helper macros to generate code for each interrupts +#define FOR_EACH_ITEM(op, list) do { list(op) } while(0) +#define INTR_LIST(item) \ + item(SPI_LL_INTR_TRANS_DONE, dma_int_ena.trans_done_int, dma_int_raw.trans_done_int, dma_int_clr.trans_done_int, dma_int_set.trans_done_int) \ + item(SPI_LL_INTR_RDBUF, dma_int_ena.slv_rd_buf_done_int, dma_int_raw.slv_rd_buf_done_int, dma_int_clr.slv_rd_buf_done_int, dma_int_set.slv_rd_buf_done_int) \ + item(SPI_LL_INTR_WRBUF, dma_int_ena.slv_wr_buf_done_int, dma_int_raw.slv_wr_buf_done_int, dma_int_clr.slv_wr_buf_done_int, dma_int_set.slv_wr_buf_done_int) \ + item(SPI_LL_INTR_RDDMA, dma_int_ena.slv_rd_dma_done_int, dma_int_raw.slv_rd_dma_done_int, dma_int_clr.slv_rd_dma_done_int, dma_int_set.slv_rd_dma_done_int) \ + item(SPI_LL_INTR_WRDMA, dma_int_ena.slv_wr_dma_done_int, dma_int_raw.slv_wr_dma_done_int, dma_int_clr.slv_wr_dma_done_int, dma_int_set.slv_wr_dma_done_int) \ + item(SPI_LL_INTR_SEG_DONE, dma_int_ena.dma_seg_trans_done_int, dma_int_raw.dma_seg_trans_done_int, dma_int_clr.dma_seg_trans_done_int, dma_int_set.dma_seg_trans_done_int) \ + item(SPI_LL_INTR_CMD7, dma_int_ena.slv_cmd7_int, dma_int_raw.slv_cmd7_int, dma_int_clr.slv_cmd7_int, dma_int_set.slv_cmd7_int) \ + item(SPI_LL_INTR_CMD8, dma_int_ena.slv_cmd8_int, dma_int_raw.slv_cmd8_int, dma_int_clr.slv_cmd8_int, dma_int_set.slv_cmd8_int) \ + item(SPI_LL_INTR_CMD9, dma_int_ena.slv_cmd9_int, dma_int_raw.slv_cmd9_int, dma_int_clr.slv_cmd9_int, dma_int_set.slv_cmd9_int) \ + item(SPI_LL_INTR_CMDA, dma_int_ena.slv_cmda_int, dma_int_raw.slv_cmda_int, dma_int_clr.slv_cmda_int, dma_int_set.slv_cmda_int) + + +static inline void spi_ll_enable_intr(spi_dev_t *hw, spi_ll_intr_t intr_mask) +{ +#define ENA_INTR(intr_bit, en_reg, ...) if (intr_mask & (intr_bit)) hw->en_reg = 1; + FOR_EACH_ITEM(ENA_INTR, INTR_LIST); +#undef ENA_INTR +} + +static inline void spi_ll_disable_intr(spi_dev_t *hw, spi_ll_intr_t intr_mask) +{ +#define DIS_INTR(intr_bit, en_reg, ...) if (intr_mask & (intr_bit)) hw->en_reg = 0; + FOR_EACH_ITEM(DIS_INTR, INTR_LIST); +#undef DIS_INTR +} + +static inline void spi_ll_set_intr(spi_dev_t *hw, spi_ll_intr_t intr_mask) +{ +#define SET_INTR(intr_bit, _, __, ___, set_reg) if (intr_mask & (intr_bit)) hw->set_reg = 1; + FOR_EACH_ITEM(SET_INTR, INTR_LIST); +#undef SET_INTR +} + +static inline void spi_ll_clear_intr(spi_dev_t *hw, spi_ll_intr_t intr_mask) +{ +#define CLR_INTR(intr_bit, _, __, clr_reg, ...) if (intr_mask & (intr_bit)) hw->clr_reg = 1; + FOR_EACH_ITEM(CLR_INTR, INTR_LIST); +#undef CLR_INTR +} + +static inline bool spi_ll_get_intr(spi_dev_t *hw, spi_ll_intr_t intr_mask) +{ +#define GET_INTR(intr_bit, _, sta_reg, ...) if (intr_mask & (intr_bit) && hw->sta_reg) return true; + FOR_EACH_ITEM(GET_INTR, INTR_LIST); + return false; +#undef GET_INTR +} + +#undef FOR_EACH_ITEM +#undef INTR_LIST + +/** + * Disable the trans_done interrupt. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_disable_int(spi_dev_t *hw) +{ + hw->dma_int_ena.trans_done_int = 0; +} + +/** + * Clear the trans_done interrupt. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_clear_int_stat(spi_dev_t *hw) +{ + hw->dma_int_clr.trans_done_int = 1; +} + +/** + * Set the trans_done interrupt. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_set_int_stat(spi_dev_t *hw) +{ + hw->dma_int_set.trans_done_int = 1; +} + +/** + * Enable the trans_done interrupt. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_enable_int(spi_dev_t *hw) +{ + hw->dma_int_ena.trans_done_int = 1; +} + +/*------------------------------------------------------------------------------ + * Slave HD + *----------------------------------------------------------------------------*/ +static inline void spi_ll_slave_hd_set_len_cond(spi_dev_t *hw, spi_ll_trans_len_cond_t cond_mask) +{ + hw->slave.slv_rdbuf_bitlen_en = (cond_mask & SPI_LL_TRANS_LEN_COND_RDBUF) ? 1 : 0; + hw->slave.slv_wrbuf_bitlen_en = (cond_mask & SPI_LL_TRANS_LEN_COND_WRBUF) ? 1 : 0; + hw->slave.slv_rddma_bitlen_en = (cond_mask & SPI_LL_TRANS_LEN_COND_RDDMA) ? 1 : 0; + hw->slave.slv_wrdma_bitlen_en = (cond_mask & SPI_LL_TRANS_LEN_COND_WRDMA) ? 1 : 0; +} + +static inline int spi_ll_slave_get_rx_byte_len(spi_dev_t *hw) +{ + return hw->slave1.slv_data_bitlen / 8; +} + +static inline uint32_t spi_ll_slave_hd_get_last_addr(spi_dev_t *hw) +{ + return hw->slave1.slv_last_addr; +} + +#undef SPI_LL_RST_MASK +#undef SPI_LL_UNUSED_INT_MASK + +/** + * Get the base spi command + * + * @param cmd_t Command value + */ +static inline uint8_t spi_ll_get_slave_hd_base_command(spi_command_t cmd_t) +{ + uint8_t cmd_base = 0x00; + switch (cmd_t) + { + case SPI_CMD_HD_WRBUF: + cmd_base = SPI_LL_BASE_CMD_HD_WRBUF; + break; + case SPI_CMD_HD_RDBUF: + cmd_base = SPI_LL_BASE_CMD_HD_RDBUF; + break; + case SPI_CMD_HD_WRDMA: + cmd_base = SPI_LL_BASE_CMD_HD_WRDMA; + break; + case SPI_CMD_HD_RDDMA: + cmd_base = SPI_LL_BASE_CMD_HD_RDDMA; + break; + case SPI_CMD_HD_SEG_END: + cmd_base = SPI_LL_BASE_CMD_HD_SEG_END; + break; + case SPI_CMD_HD_EN_QPI: + cmd_base = SPI_LL_BASE_CMD_HD_EN_QPI; + break; + case SPI_CMD_HD_WR_END: + cmd_base = SPI_LL_BASE_CMD_HD_WR_END; + break; + case SPI_CMD_HD_INT0: + cmd_base = SPI_LL_BASE_CMD_HD_INT0; + break; + case SPI_CMD_HD_INT1: + cmd_base = SPI_LL_BASE_CMD_HD_INT1; + break; + case SPI_CMD_HD_INT2: + cmd_base = SPI_LL_BASE_CMD_HD_INT2; + break; + default: + HAL_ASSERT(cmd_base); + } + return cmd_base; +} + +/** + * Get the spi communication command + * + * @param cmd_t Base command value + * @param line_mode Line mode of SPI transaction phases: CMD, ADDR, DOUT/DIN. + */ +static inline uint16_t spi_ll_get_slave_hd_command(spi_command_t cmd_t, spi_line_mode_t line_mode) +{ + uint8_t cmd_base = spi_ll_get_slave_hd_base_command(cmd_t); + uint8_t cmd_mod = 0x00; //CMD:1-bit, ADDR:1-bit, DATA:1-bit + + if (line_mode.data_lines == 2) { + if (line_mode.addr_lines == 2) { + cmd_mod = 0x50; //CMD:1-bit, ADDR:2-bit, DATA:2-bit + } else { + cmd_mod = 0x10; //CMD:1-bit, ADDR:1-bit, DATA:2-bit + } + } else if (line_mode.data_lines == 4) { + if (line_mode.addr_lines == 4) { + cmd_mod = 0xA0; //CMD:1-bit, ADDR:4-bit, DATA:4-bit + } else { + cmd_mod = 0x20; //CMD:1-bit, ADDR:1-bit, DATA:4-bit + } + } + if (cmd_base == SPI_LL_BASE_CMD_HD_SEG_END || cmd_base == SPI_LL_BASE_CMD_HD_EN_QPI) { + cmd_mod = 0x00; + } + + return cmd_base | cmd_mod; +} + +/** + * Get the dummy bits + * + * @param line_mode Line mode of SPI transaction phases: CMD, ADDR, DOUT/DIN. + */ +static inline int spi_ll_get_slave_hd_dummy_bits(spi_line_mode_t line_mode) +{ + return 8; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32s2/include/hal/spi_ll.h b/components/hal/esp32s2/include/hal/spi_ll.h index ab78bf421b..8c525a05d1 100644 --- a/components/hal/esp32s2/include/hal/spi_ll.h +++ b/components/hal/esp32s2/include/hal/spi_ll.h @@ -107,6 +107,7 @@ typedef enum { * @param hw Beginning address of the peripheral registers. * @param clk_source clock source to select, see valid sources in type `spi_clock_source_t` */ +__attribute__((always_inline)) static inline void spi_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_source) { //empty, keep this for compatibility diff --git a/components/hal/esp32s3/include/hal/spi_ll.h b/components/hal/esp32s3/include/hal/spi_ll.h index 5d3e3ed17d..590198029c 100644 --- a/components/hal/esp32s3/include/hal/spi_ll.h +++ b/components/hal/esp32s3/include/hal/spi_ll.h @@ -99,6 +99,7 @@ typedef enum { * @param hw Beginning address of the peripheral registers. * @param clk_source clock source to select, see valid sources in type `spi_clock_source_t` */ +__attribute__((always_inline)) static inline void spi_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_source){ switch (clk_source) { diff --git a/components/hal/include/hal/spi_hal.h b/components/hal/include/hal/spi_hal.h index ad4ad8a319..b19d4ad446 100644 --- a/components/hal/include/hal/spi_hal.h +++ b/components/hal/include/hal/spi_hal.h @@ -29,9 +29,9 @@ #include "esp_err.h" #include "soc/soc_caps.h" #include "hal/spi_types.h" +#include "hal/dma_types.h" #if SOC_GPSPI_SUPPORTED #include "hal/spi_ll.h" -#include "soc/lldesc.h" #endif #ifdef __cplusplus @@ -40,6 +40,12 @@ extern "C" { #if SOC_GPSPI_SUPPORTED +#if SOC_GPSPI_SUPPORTED && (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AXI) +typedef dma_descriptor_align8_t spi_dma_desc_t; +#else +typedef dma_descriptor_align4_t spi_dma_desc_t; +#endif + /** * Input parameters to the ``spi_hal_cal_clock_conf`` to calculate the timing configuration */ @@ -76,11 +82,11 @@ typedef struct { spi_dma_dev_t *dma_in; ///< Input DMA(DMA -> RAM) peripheral register address spi_dma_dev_t *dma_out; ///< Output DMA(RAM -> DMA) peripheral register address bool dma_enabled; ///< Whether the DMA is enabled, do not update after initialization - lldesc_t *dmadesc_tx; /**< Array of DMA descriptor used by the TX DMA. + spi_dma_desc_t *dmadesc_tx; /**< Array of DMA descriptor used by the TX DMA. * The amount should be larger than dmadesc_n. The driver should ensure that * the data to be sent is shorter than the descriptors can hold. */ - lldesc_t *dmadesc_rx; /**< Array of DMA descriptor used by the RX DMA. + spi_dma_desc_t *dmadesc_rx; /**< Array of DMA descriptor used by the RX DMA. * The amount should be larger than dmadesc_n. The driver should ensure that * the data to be sent is shorter than the descriptors can hold. */ @@ -112,11 +118,11 @@ typedef struct { */ typedef struct { /* These two need to be malloced by the driver first */ - lldesc_t *dmadesc_tx; /**< Array of DMA descriptor used by the TX DMA. + spi_dma_desc_t *dmadesc_tx; /**< Array of DMA descriptor used by the TX DMA. * The amount should be larger than dmadesc_n. The driver should ensure that * the data to be sent is shorter than the descriptors can hold. */ - lldesc_t *dmadesc_rx; /**< Array of DMA descriptor used by the RX DMA. + spi_dma_desc_t *dmadesc_rx; /**< Array of DMA descriptor used by the RX DMA. * The amount should be larger than dmadesc_n. The driver should ensure that * the data to be sent is shorter than the descriptors can hold. */ diff --git a/components/hal/spi_hal.c b/components/hal/spi_hal.c index e5bddfdf87..d928fe997e 100644 --- a/components/hal/spi_hal.c +++ b/components/hal/spi_hal.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,17 +13,27 @@ #include "soc/clk_tree_defs.h" //This GDMA related part will be introduced by GDMA dedicated APIs in the future. Here we temporarily use macros. -#if SOC_AHB_GDMA_VERSION == 1 +#if SOC_GDMA_SUPPORTED +#if (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AHB) && (SOC_AHB_GDMA_VERSION == 1) #include "soc/gdma_struct.h" #include "hal/gdma_ll.h" - #define spi_dma_ll_rx_enable_burst_data(dev, chan, enable) gdma_ll_rx_enable_data_burst(&GDMA, chan, enable); #define spi_dma_ll_tx_enable_burst_data(dev, chan, enable) gdma_ll_tx_enable_data_burst(&GDMA, chan, enable); #define spi_dma_ll_rx_enable_burst_desc(dev, chan, enable) gdma_ll_rx_enable_descriptor_burst(&GDMA, chan, enable); #define spi_dma_ll_tx_enable_burst_desc(dev, chan, enable) gdma_ll_tx_enable_descriptor_burst(&GDMA, chan, enable); #define spi_dma_ll_enable_out_auto_wrback(dev, chan, enable) gdma_ll_tx_enable_auto_write_back(&GDMA, chan, enable); #define spi_dma_ll_set_out_eof_generation(dev, chan, enable) gdma_ll_tx_set_eof_mode(&GDMA, chan, enable); + +#elif (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AXI) //TODO: IDF-6152, refactor spi hal layer +#include "hal/axi_dma_ll.h" +#define spi_dma_ll_rx_enable_burst_data(dev, chan, enable) axi_dma_ll_rx_enable_data_burst(&AXI_DMA, chan, enable); +#define spi_dma_ll_tx_enable_burst_data(dev, chan, enable) axi_dma_ll_tx_enable_data_burst(&AXI_DMA, chan, enable); +#define spi_dma_ll_rx_enable_burst_desc(dev, chan, enable) axi_dma_ll_rx_enable_descriptor_burst(&AXI_DMA, chan, enable); +#define spi_dma_ll_tx_enable_burst_desc(dev, chan, enable) axi_dma_ll_tx_enable_descriptor_burst(&AXI_DMA, chan, enable); +#define spi_dma_ll_enable_out_auto_wrback(dev, chan, enable) axi_dma_ll_tx_enable_auto_write_back(&AXI_DMA, chan, enable); +#define spi_dma_ll_set_out_eof_generation(dev, chan, enable) axi_dma_ll_tx_set_eof_mode(&AXI_DMA, chan, enable); #endif +#endif //SOC_GDMA_SUPPORTED /* The tag may be unused if log level is set to NONE */ static const __attribute__((unused)) char SPI_HAL_TAG[] = "spi_hal"; diff --git a/components/hal/spi_hal_iram.c b/components/hal/spi_hal_iram.c index b005f7943d..790cbc7ad0 100644 --- a/components/hal/spi_hal_iram.c +++ b/components/hal/spi_hal_iram.c @@ -9,13 +9,14 @@ #include "hal/spi_hal.h" #include "hal/assert.h" +#include "soc/ext_mem_defs.h" #include "soc/soc_caps.h" //This GDMA related part will be introduced by GDMA dedicated APIs in the future. Here we temporarily use macros. -#if SOC_AHB_GDMA_VERSION == 1 +#if SOC_GDMA_SUPPORTED +#if (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AHB) && (SOC_AHB_GDMA_VERSION == 1) #include "soc/gdma_struct.h" #include "hal/gdma_ll.h" - #define spi_dma_ll_rx_reset(dev, chan) gdma_ll_rx_reset_channel(&GDMA, chan) #define spi_dma_ll_tx_reset(dev, chan) gdma_ll_tx_reset_channel(&GDMA, chan); #define spi_dma_ll_rx_start(dev, chan, addr) do {\ @@ -26,7 +27,21 @@ gdma_ll_tx_set_desc_addr(&GDMA, chan, (uint32_t)addr);\ gdma_ll_tx_start(&GDMA, chan);\ } while (0) + +#elif (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AXI) //TODO: IDF-6152, refactor spi hal layer +#include "hal/axi_dma_ll.h" +#define spi_dma_ll_rx_reset(dev, chan) axi_dma_ll_rx_reset_channel(&AXI_DMA, chan) +#define spi_dma_ll_tx_reset(dev, chan) axi_dma_ll_tx_reset_channel(&AXI_DMA, chan); +#define spi_dma_ll_rx_start(dev, chan, addr) do {\ + axi_dma_ll_rx_set_desc_addr(&AXI_DMA, chan, (uint32_t)addr);\ + axi_dma_ll_rx_start(&AXI_DMA, chan);\ + } while (0) +#define spi_dma_ll_tx_start(dev, chan, addr) do {\ + axi_dma_ll_tx_set_desc_addr(&AXI_DMA, chan, (uint32_t)addr);\ + axi_dma_ll_tx_start(&AXI_DMA, chan);\ + } while (0) #endif +#endif //SOC_GDMA_SUPPORTED void spi_hal_setup_device(spi_hal_context_t *hal, const spi_hal_dev_config_t *dev) { @@ -37,7 +52,6 @@ void spi_hal_setup_device(spi_hal_context_t *hal, const spi_hal_dev_config_t *de #endif spi_ll_master_set_pos_cs(hw, dev->cs_pin_id, dev->positive_cs); spi_ll_master_set_clock_by_reg(hw, &dev->timing_conf.clock_reg); - spi_ll_set_clk_source(hw, dev->timing_conf.clock_source); //Configure bit order spi_ll_set_rx_lsbfirst(hw, dev->rx_lsbfirst); spi_ll_set_tx_lsbfirst(hw, dev->tx_lsbfirst); @@ -131,6 +145,43 @@ void spi_hal_setup_trans(spi_hal_context_t *hal, const spi_hal_dev_config_t *dev memcpy(&hal->trans_config, trans, sizeof(spi_hal_trans_config_t)); } +#if SOC_NON_CACHEABLE_OFFSET +#define ADDR_DMA_2_CPU(addr) ((typeof(addr))((uint32_t)(addr) + SOC_NON_CACHEABLE_OFFSET)) +#define ADDR_CPU_2_DMA(addr) ((typeof(addr))((uint32_t)(addr) - SOC_NON_CACHEABLE_OFFSET)) +#else +#define ADDR_DMA_2_CPU(addr) (addr) +#define ADDR_CPU_2_DMA(addr) (addr) +#endif +//TODO: IDF-6152, refactor spi hal layer +static void s_spi_hal_dma_desc_setup_link(spi_dma_desc_t *dmadesc, const void *data, int len, bool is_rx) +{ + dmadesc = ADDR_DMA_2_CPU(dmadesc); + int n = 0; + while (len) { + int dmachunklen = len; + if (dmachunklen > DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED) { + dmachunklen = DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED; + } + if (is_rx) { + //Receive needs DMA length rounded to next 32-bit boundary + dmadesc[n].dw0.size = (dmachunklen + 3) & (~3); + dmadesc[n].dw0.length = (dmachunklen + 3) & (~3); + } else { + dmadesc[n].dw0.size = dmachunklen; + dmadesc[n].dw0.length = dmachunklen; + } + dmadesc[n].buffer = (uint8_t *)data; + dmadesc[n].dw0.suc_eof = 0; + dmadesc[n].dw0.owner = 1; + dmadesc[n].next = ADDR_CPU_2_DMA(&dmadesc[n + 1]); + len -= dmachunklen; + data += dmachunklen; + n++; + } + dmadesc[n - 1].dw0.suc_eof = 1; //Mark last DMA desc as end of stream. + dmadesc[n - 1].next = NULL; +} + void spi_hal_prepare_data(spi_hal_context_t *hal, const spi_hal_dev_config_t *dev, const spi_hal_trans_config_t *trans) { spi_dev_t *hw = hal->hw; @@ -140,13 +191,13 @@ void spi_hal_prepare_data(spi_hal_context_t *hal, const spi_hal_dev_config_t *de if (!hal->dma_enabled) { //No need to setup anything; we'll copy the result out of the work registers directly later. } else { - lldesc_setup_link(hal->dmadesc_rx, trans->rcv_buffer, ((trans->rx_bitlen + 7) / 8), true); + s_spi_hal_dma_desc_setup_link(hal->dmadesc_rx, trans->rcv_buffer, ((trans->rx_bitlen + 7) / 8), true); spi_dma_ll_rx_reset(hal->dma_in, hal->rx_dma_chan); spi_ll_dma_rx_fifo_reset(hal->hw); spi_ll_infifo_full_clr(hal->hw); spi_ll_dma_rx_enable(hal->hw, 1); - spi_dma_ll_rx_start(hal->dma_in, hal->rx_dma_chan, hal->dmadesc_rx); + spi_dma_ll_rx_start(hal->dma_in, hal->rx_dma_chan, (lldesc_t *)hal->dmadesc_rx); } } @@ -165,13 +216,13 @@ void spi_hal_prepare_data(spi_hal_context_t *hal, const spi_hal_dev_config_t *de //Need to copy data to registers manually spi_ll_write_buffer(hw, trans->send_buffer, trans->tx_bitlen); } else { - lldesc_setup_link(hal->dmadesc_tx, trans->send_buffer, (trans->tx_bitlen + 7) / 8, false); + s_spi_hal_dma_desc_setup_link(hal->dmadesc_tx, trans->send_buffer, (trans->tx_bitlen + 7) / 8, false); spi_dma_ll_tx_reset(hal->dma_out, hal->tx_dma_chan); spi_ll_dma_tx_fifo_reset(hal->hw); spi_ll_outfifo_empty_clr(hal->hw); spi_ll_dma_tx_enable(hal->hw, 1); - spi_dma_ll_tx_start(hal->dma_out, hal->tx_dma_chan, hal->dmadesc_tx); + spi_dma_ll_tx_start(hal->dma_out, hal->tx_dma_chan, (lldesc_t *)hal->dmadesc_tx); } } diff --git a/components/hal/spi_slave_hal.c b/components/hal/spi_slave_hal.c index fd4297c21a..7c437a0b3f 100644 --- a/components/hal/spi_slave_hal.c +++ b/components/hal/spi_slave_hal.c @@ -3,17 +3,27 @@ #include "soc/soc_caps.h" //This GDMA related part will be introduced by GDMA dedicated APIs in the future. Here we temporarily use macros. -#if SOC_AHB_GDMA_VERSION == 1 +#if SOC_GDMA_SUPPORTED +#if (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AHB) && (SOC_AHB_GDMA_VERSION == 1) #include "soc/gdma_struct.h" #include "hal/gdma_ll.h" - #define spi_dma_ll_rx_enable_burst_data(dev, chan, enable) gdma_ll_rx_enable_data_burst(&GDMA, chan, enable); #define spi_dma_ll_tx_enable_burst_data(dev, chan, enable) gdma_ll_tx_enable_data_burst(&GDMA, chan, enable); #define spi_dma_ll_rx_enable_burst_desc(dev, chan, enable) gdma_ll_rx_enable_descriptor_burst(&GDMA, chan, enable); #define spi_dma_ll_tx_enable_burst_desc(dev, chan, enable) gdma_ll_tx_enable_descriptor_burst(&GDMA, chan, enable); #define spi_dma_ll_enable_out_auto_wrback(dev, chan, enable) gdma_ll_tx_enable_auto_write_back(&GDMA, chan, enable); #define spi_dma_ll_set_out_eof_generation(dev, chan, enable) gdma_ll_tx_set_eof_mode(&GDMA, chan, enable); + +#elif (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AXI) //TODO: IDF-6152, refactor spi hal layer +#include "hal/axi_dma_ll.h" +#define spi_dma_ll_rx_enable_burst_data(dev, chan, enable) axi_dma_ll_rx_enable_data_burst(&AXI_DMA, chan, enable); +#define spi_dma_ll_tx_enable_burst_data(dev, chan, enable) axi_dma_ll_tx_enable_data_burst(&AXI_DMA, chan, enable); +#define spi_dma_ll_rx_enable_burst_desc(dev, chan, enable) axi_dma_ll_rx_enable_descriptor_burst(&AXI_DMA, chan, enable); +#define spi_dma_ll_tx_enable_burst_desc(dev, chan, enable) axi_dma_ll_tx_enable_descriptor_burst(&AXI_DMA, chan, enable); +#define spi_dma_ll_enable_out_auto_wrback(dev, chan, enable) axi_dma_ll_tx_enable_auto_write_back(&AXI_DMA, chan, enable); +#define spi_dma_ll_set_out_eof_generation(dev, chan, enable) axi_dma_ll_tx_set_eof_mode(&AXI_DMA, chan, enable); #endif +#endif //SOC_GDMA_SUPPORTED static void s_spi_slave_hal_dma_init_config(const spi_slave_hal_context_t *hal) { diff --git a/components/hal/spi_slave_hal_iram.c b/components/hal/spi_slave_hal_iram.c index 473e147389..07c58d4045 100644 --- a/components/hal/spi_slave_hal_iram.c +++ b/components/hal/spi_slave_hal_iram.c @@ -1,12 +1,13 @@ #include "hal/spi_slave_hal.h" #include "hal/spi_ll.h" +#include "soc/ext_mem_defs.h" #include "soc/soc_caps.h" //This GDMA related part will be introduced by GDMA dedicated APIs in the future. Here we temporarily use macros. -#if SOC_AHB_GDMA_VERSION == 1 +#if SOC_GDMA_SUPPORTED +#if (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AHB) && (SOC_AHB_GDMA_VERSION == 1) #include "soc/gdma_struct.h" #include "hal/gdma_ll.h" - #define spi_dma_ll_rx_reset(dev, chan) gdma_ll_rx_reset_channel(&GDMA, chan) #define spi_dma_ll_tx_reset(dev, chan) gdma_ll_tx_reset_channel(&GDMA, chan); #define spi_dma_ll_rx_start(dev, chan, addr) do {\ @@ -17,7 +18,21 @@ gdma_ll_tx_set_desc_addr(&GDMA, chan, (uint32_t)addr);\ gdma_ll_tx_start(&GDMA, chan);\ } while (0) + +#elif (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AXI) //TODO: IDF-6152, refactor spi hal layer +#include "hal/axi_dma_ll.h" +#define spi_dma_ll_rx_reset(dev, chan) axi_dma_ll_rx_reset_channel(&AXI_DMA, chan) +#define spi_dma_ll_tx_reset(dev, chan) axi_dma_ll_tx_reset_channel(&AXI_DMA, chan); +#define spi_dma_ll_rx_start(dev, chan, addr) do {\ + axi_dma_ll_rx_set_desc_addr(&AXI_DMA, chan, (uint32_t)addr);\ + axi_dma_ll_rx_start(&AXI_DMA, chan);\ + } while (0) +#define spi_dma_ll_tx_start(dev, chan, addr) do {\ + axi_dma_ll_tx_set_desc_addr(&AXI_DMA, chan, (uint32_t)addr);\ + axi_dma_ll_tx_start(&AXI_DMA, chan);\ + } while (0) #endif +#endif //SOC_GDMA_SUPPORTED bool spi_slave_hal_usr_is_done(spi_slave_hal_context_t* hal) { @@ -45,10 +60,11 @@ void spi_slave_hal_prepare_data(const spi_slave_hal_context_t *hal) spi_ll_infifo_full_clr(hal->hw); spi_ll_dma_rx_enable(hal->hw, 1); - spi_dma_ll_rx_start(hal->dma_in, hal->rx_dma_chan, &hal->dmadesc_rx[0]); + spi_dma_ll_rx_start(hal->dma_in, hal->rx_dma_chan, hal->dmadesc_rx); } if (hal->tx_buffer) { lldesc_setup_link(hal->dmadesc_tx, hal->tx_buffer, (hal->bitlen + 7) / 8, false); + //reset dma outlink, this should be reset before spi related reset spi_dma_ll_tx_reset(hal->dma_out, hal->tx_dma_chan); spi_ll_dma_tx_fifo_reset(hal->dma_out); @@ -56,7 +72,7 @@ void spi_slave_hal_prepare_data(const spi_slave_hal_context_t *hal) spi_ll_outfifo_empty_clr(hal->hw); spi_ll_dma_tx_enable(hal->hw, 1); - spi_dma_ll_tx_start(hal->dma_out, hal->tx_dma_chan, (&hal->dmadesc_tx[0])); + spi_dma_ll_tx_start(hal->dma_out, hal->tx_dma_chan, hal->dmadesc_tx); } } else { //No DMA. Turn off SPI and copy data to transmit buffers. diff --git a/components/idf_test/include/esp32p4/idf_performance_target.h b/components/idf_test/include/esp32p4/idf_performance_target.h index f2c4877096..4dc137b1c1 100644 --- a/components/idf_test/include/esp32p4/idf_performance_target.h +++ b/components/idf_test/include/esp32p4/idf_performance_target.h @@ -3,3 +3,10 @@ * * SPDX-License-Identifier: Apache-2.0 */ + +//TODO: IDF-8313 update after chips back and PLL setup +#define IDF_PERFORMANCE_MAX_SPI_CLK_FREQ 10*1000*1000 +#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING 1000 +#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_POLLING 1000 +#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING_NO_DMA 1000 +#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_POLLING_NO_DMA 1000 diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 36583829ab..00e0130e2d 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -71,6 +71,10 @@ config SOC_I2S_SUPPORTED bool default y +config SOC_GPSPI_SUPPORTED + bool + default y + config SOC_I2C_SUPPORTED bool default y @@ -801,25 +805,21 @@ config SOC_SDM_CLK_SUPPORT_XTAL config SOC_SPI_PERIPH_NUM int - default 2 + default 3 config SOC_SPI_MAX_CS_NUM int default 6 -config SOC_MEMSPI_IS_INDEPENDENT - bool - default y - config SOC_SPI_MAXIMUM_BUFFER_SIZE int default 64 -config SOC_SPI_SUPPORT_DDRCLK +config SOC_SPI_SLAVE_SUPPORT_SEG_TRANS bool default y -config SOC_SPI_SLAVE_SUPPORT_SEG_TRANS +config SOC_SPI_SUPPORT_DDRCLK bool default y @@ -827,23 +827,15 @@ config SOC_SPI_SUPPORT_CD_SIG bool default y -config SOC_SPI_SUPPORT_CONTINUOUS_TRANS +config SOC_SPI_SUPPORT_OCT bool default y -config SOC_SPI_SUPPORT_SLAVE_HD_VER2 - bool - default n - config SOC_SPI_SUPPORT_CLK_XTAL bool default y -config SOC_SPI_SUPPORT_CLK_PLL_F80M - bool - default y - -config SOC_SPI_SUPPORT_CLK_RC_FAST +config SOC_MEMSPI_IS_INDEPENDENT bool default y diff --git a/components/soc/esp32p4/include/soc/clk_tree_defs.h b/components/soc/esp32p4/include/soc/clk_tree_defs.h index 664e5d4b7b..21d51dfc25 100644 --- a/components/soc/esp32p4/include/soc/clk_tree_defs.h +++ b/components/soc/esp32p4/include/soc/clk_tree_defs.h @@ -370,16 +370,20 @@ typedef enum { /** * @brief Array initializer for all supported clock sources of SPI */ -#define SOC_SPI_CLKS {SOC_MOD_CLK_PLL_F80M, SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST} +#define SOC_SPI_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_SPLL} /** * @brief Type of SPI clock source. */ typedef enum { - SPI_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_80M as SPI source clock */ - SPI_CLK_SRC_PLL_F80M = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_80M as SPI source clock */ SPI_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as SPI source clock */ - SPI_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as SPI source clock */ +#if SOC_CLK_TREE_SUPPORTED + SPI_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, + SPI_CLK_SRC_SPLL_480 = SOC_MOD_CLK_SPLL, + SPI_CLK_SRC_DEFAULT = SPI_CLK_SRC_SPLL_480, /*!< Select SPLL_480M as SPI source clock */ +#else + SPI_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Select XTAL as SPI source clock */ +#endif } soc_periph_spi_clk_src_t; /////////////////////////////////////////////////PSRAM//////////////////////////////////////////////////////////////////// diff --git a/components/soc/esp32p4/include/soc/ext_mem_defs.h b/components/soc/esp32p4/include/soc/ext_mem_defs.h index 0e428d116e..8f25270d19 100644 --- a/components/soc/esp32p4/include/soc/ext_mem_defs.h +++ b/components/soc/esp32p4/include/soc/ext_mem_defs.h @@ -57,6 +57,7 @@ extern "C" { #define SOC_MMU_FLASH_SENSITIVE BIT(13) #define SOC_MMU_PSRAM_SENSITIVE BIT(12) +#define SOC_NON_CACHEABLE_OFFSET 0x40000000 /** * MMU entry valid bit mask for mapping value. diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 857fdf8dff..af1072472d 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -52,7 +52,7 @@ #define SOC_I2S_SUPPORTED 1 // #define SOC_RMT_SUPPORTED 1 //TODO: IDF-7476 // #define SOC_SDM_SUPPORTED 1 //TODO: IDF-7551 -// #define SOC_GPSPI_SUPPORTED 1 //TODO: IDF-7502, TODO: IDF-7503 +#define SOC_GPSPI_SUPPORTED 1 // #define SOC_LEDC_SUPPORTED 1 //TODO: IDF-6510 #define SOC_I2C_SUPPORTED 1 //TODO: IDF-6507, TODO: IDF-7491 #define SOC_SYSTIMER_SUPPORTED 1 @@ -377,29 +377,29 @@ #define SOC_SDM_CLK_SUPPORT_PLL_F80M 1 #define SOC_SDM_CLK_SUPPORT_XTAL 1 -// TODO: IDF-5334 (Copy from esp32c3, need check) /*-------------------------- SPI CAPS ----------------------------------------*/ -#define SOC_SPI_PERIPH_NUM 2 -#define SOC_SPI_PERIPH_CS_NUM(i) 6 -#define SOC_SPI_MAX_CS_NUM 6 - -#define SOC_MEMSPI_IS_INDEPENDENT 1 +#define SOC_SPI_PERIPH_NUM 3 +#define SOC_SPI_PERIPH_CS_NUM(i) (((i)==0)? 2: (((i)==1)? 6: 3)) +#define SOC_SPI_MAX_CS_NUM 6 #define SOC_SPI_MAXIMUM_BUFFER_SIZE 64 -#define SOC_SPI_SUPPORT_DDRCLK 1 +// #define SOC_SPI_SUPPORT_SLAVE_HD_VER2 1 //TODO: IDF-7505 #define SOC_SPI_SLAVE_SUPPORT_SEG_TRANS 1 +#define SOC_SPI_SUPPORT_DDRCLK 1 #define SOC_SPI_SUPPORT_CD_SIG 1 -#define SOC_SPI_SUPPORT_CONTINUOUS_TRANS 1 -#define SOC_SPI_SUPPORT_SLAVE_HD_VER2 0 +#define SOC_SPI_SUPPORT_OCT 1 #define SOC_SPI_SUPPORT_CLK_XTAL 1 -#define SOC_SPI_SUPPORT_CLK_PLL_F80M 1 -#define SOC_SPI_SUPPORT_CLK_RC_FAST 1 +// #define SOC_SPI_SUPPORT_CLK_RC_FAST 1 //bellow clks are waiting for clock tree +// #define SOC_SPI_SUPPORT_CLK_SPLL_F480M 1 //super pll +// #define SOC_SPI_SUPPORT_CLK_SDIO 1 //sdio pll +// #define SOC_SPI_SUPPORT_CLK_APLL 1 //audio pll // Peripheral supports DIO, DOUT, QIO, or QOUT // host_id = 0 -> SPI0/SPI1, host_id = 1 -> SPI2, #define SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(host_id) ({(void)host_id; 1;}) -#define SOC_SPI_MAX_PRE_DIVIDER 16 +#define SOC_MEMSPI_IS_INDEPENDENT 1 +#define SOC_SPI_MAX_PRE_DIVIDER 16 /*-------------------------- SPI MEM CAPS ---------------------------------------*/ #define SOC_SPI_MEM_SUPPORT_AUTO_WAIT_IDLE (1) diff --git a/components/soc/esp32p4/include/soc/spi_pins.h b/components/soc/esp32p4/include/soc/spi_pins.h index d2aa55b41e..48b98b0169 100644 --- a/components/soc/esp32p4/include/soc/spi_pins.h +++ b/components/soc/esp32p4/include/soc/spi_pins.h @@ -5,3 +5,27 @@ */ #pragma once + +// Normal IOMUX pins +#define SPI2_FUNC_NUM 3 +#define SPI2_IOMUX_PIN_NUM_HD 6 +#define SPI2_IOMUX_PIN_NUM_CS 7 +#define SPI2_IOMUX_PIN_NUM_MOSI 8 +#define SPI2_IOMUX_PIN_NUM_CLK 9 +#define SPI2_IOMUX_PIN_NUM_MISO 10 +#define SPI2_IOMUX_PIN_NUM_WP 11 + +// When using Octal SPI, we make use of SPI2_FUNC_NUM_OCT to route them as follows. +#define SPI2_FUNC_NUM_OCT 2 +#define SPI2_IOMUX_PIN_NUM_HD_OCT 32 +#define SPI2_IOMUX_PIN_NUM_CS_OCT 28 +#define SPI2_IOMUX_PIN_NUM_MOSI_OCT 29 +#define SPI2_IOMUX_PIN_NUM_CLK_OCT 30 +#define SPI2_IOMUX_PIN_NUM_MISO_OCT 31 +#define SPI2_IOMUX_PIN_NUM_WP_OCT 33 +#define SPI2_IOMUX_PIN_NUM_IO4_OCT 34 +#define SPI2_IOMUX_PIN_NUM_IO5_OCT 35 +#define SPI2_IOMUX_PIN_NUM_IO6_OCT 36 +#define SPI2_IOMUX_PIN_NUM_IO7_OCT 37 + +//SPI3 have no iomux pins diff --git a/components/soc/esp32p4/include/soc/spi_struct.h b/components/soc/esp32p4/include/soc/spi_struct.h index 48d72046f2..66929cd3a0 100644 --- a/components/soc/esp32p4/include/soc/spi_struct.h +++ b/components/soc/esp32p4/include/soc/spi_struct.h @@ -839,198 +839,8 @@ typedef union { uint32_t val; } spi_dout_mode_reg_t; - -/** Group: Interrupt registers */ -/** Type of dma_int_ena register - * SPI interrupt enable register - */ -typedef union { - struct { - /** dma_infifo_full_err_int_ena : R/W; bitpos: [0]; default: 0; - * The enable bit for SPI_DMA_INFIFO_FULL_ERR_INT interrupt. - */ - uint32_t dma_infifo_full_err_int_ena:1; - /** dma_outfifo_empty_err_int_ena : R/W; bitpos: [1]; default: 0; - * The enable bit for SPI_DMA_OUTFIFO_EMPTY_ERR_INT interrupt. - */ - uint32_t dma_outfifo_empty_err_int_ena:1; - /** slv_ex_qpi_int_ena : R/W; bitpos: [2]; default: 0; - * The enable bit for SPI slave Ex_QPI interrupt. - */ - uint32_t slv_ex_qpi_int_ena:1; - /** slv_en_qpi_int_ena : R/W; bitpos: [3]; default: 0; - * The enable bit for SPI slave En_QPI interrupt. - */ - uint32_t slv_en_qpi_int_ena:1; - /** slv_cmd7_int_ena : R/W; bitpos: [4]; default: 0; - * The enable bit for SPI slave CMD7 interrupt. - */ - uint32_t slv_cmd7_int_ena:1; - /** slv_cmd8_int_ena : R/W; bitpos: [5]; default: 0; - * The enable bit for SPI slave CMD8 interrupt. - */ - uint32_t slv_cmd8_int_ena:1; - /** slv_cmd9_int_ena : R/W; bitpos: [6]; default: 0; - * The enable bit for SPI slave CMD9 interrupt. - */ - uint32_t slv_cmd9_int_ena:1; - /** slv_cmda_int_ena : R/W; bitpos: [7]; default: 0; - * The enable bit for SPI slave CMDA interrupt. - */ - uint32_t slv_cmda_int_ena:1; - /** slv_rd_dma_done_int_ena : R/W; bitpos: [8]; default: 0; - * The enable bit for SPI_SLV_RD_DMA_DONE_INT interrupt. - */ - uint32_t slv_rd_dma_done_int_ena:1; - /** slv_wr_dma_done_int_ena : R/W; bitpos: [9]; default: 0; - * The enable bit for SPI_SLV_WR_DMA_DONE_INT interrupt. - */ - uint32_t slv_wr_dma_done_int_ena:1; - /** slv_rd_buf_done_int_ena : R/W; bitpos: [10]; default: 0; - * The enable bit for SPI_SLV_RD_BUF_DONE_INT interrupt. - */ - uint32_t slv_rd_buf_done_int_ena:1; - /** slv_wr_buf_done_int_ena : R/W; bitpos: [11]; default: 0; - * The enable bit for SPI_SLV_WR_BUF_DONE_INT interrupt. - */ - uint32_t slv_wr_buf_done_int_ena:1; - /** trans_done_int_ena : R/W; bitpos: [12]; default: 0; - * The enable bit for SPI_TRANS_DONE_INT interrupt. - */ - uint32_t trans_done_int_ena:1; - /** dma_seg_trans_done_int_ena : R/W; bitpos: [13]; default: 0; - * The enable bit for SPI_DMA_SEG_TRANS_DONE_INT interrupt. - */ - uint32_t dma_seg_trans_done_int_ena:1; - /** seg_magic_err_int_ena : R/W; bitpos: [14]; default: 0; - * The enable bit for SPI_SEG_MAGIC_ERR_INT interrupt. - */ - uint32_t seg_magic_err_int_ena:1; //this field is only for GPSPI2 - /** slv_buf_addr_err_int_ena : R/W; bitpos: [15]; default: 0; - * The enable bit for SPI_SLV_BUF_ADDR_ERR_INT interrupt. - */ - uint32_t slv_buf_addr_err_int_ena:1; - /** slv_cmd_err_int_ena : R/W; bitpos: [16]; default: 0; - * The enable bit for SPI_SLV_CMD_ERR_INT interrupt. - */ - uint32_t slv_cmd_err_int_ena:1; - /** mst_rx_afifo_wfull_err_int_ena : R/W; bitpos: [17]; default: 0; - * The enable bit for SPI_MST_RX_AFIFO_WFULL_ERR_INT interrupt. - */ - uint32_t mst_rx_afifo_wfull_err_int_ena:1; - /** mst_tx_afifo_rempty_err_int_ena : R/W; bitpos: [18]; default: 0; - * The enable bit for SPI_MST_TX_AFIFO_REMPTY_ERR_INT interrupt. - */ - uint32_t mst_tx_afifo_rempty_err_int_ena:1; - /** app2_int_ena : R/W; bitpos: [19]; default: 0; - * The enable bit for SPI_APP2_INT interrupt. - */ - uint32_t app2_int_ena:1; - /** app1_int_ena : R/W; bitpos: [20]; default: 0; - * The enable bit for SPI_APP1_INT interrupt. - */ - uint32_t app1_int_ena:1; - uint32_t reserved_21:11; - }; - uint32_t val; -} spi_dma_int_ena_reg_t; - -/** Type of dma_int_clr register - * SPI interrupt clear register - */ -typedef union { - struct { - /** dma_infifo_full_err_int_clr : WT; bitpos: [0]; default: 0; - * The clear bit for SPI_DMA_INFIFO_FULL_ERR_INT interrupt. - */ - uint32_t dma_infifo_full_err_int_clr:1; - /** dma_outfifo_empty_err_int_clr : WT; bitpos: [1]; default: 0; - * The clear bit for SPI_DMA_OUTFIFO_EMPTY_ERR_INT interrupt. - */ - uint32_t dma_outfifo_empty_err_int_clr:1; - /** slv_ex_qpi_int_clr : WT; bitpos: [2]; default: 0; - * The clear bit for SPI slave Ex_QPI interrupt. - */ - uint32_t slv_ex_qpi_int_clr:1; - /** slv_en_qpi_int_clr : WT; bitpos: [3]; default: 0; - * The clear bit for SPI slave En_QPI interrupt. - */ - uint32_t slv_en_qpi_int_clr:1; - /** slv_cmd7_int_clr : WT; bitpos: [4]; default: 0; - * The clear bit for SPI slave CMD7 interrupt. - */ - uint32_t slv_cmd7_int_clr:1; - /** slv_cmd8_int_clr : WT; bitpos: [5]; default: 0; - * The clear bit for SPI slave CMD8 interrupt. - */ - uint32_t slv_cmd8_int_clr:1; - /** slv_cmd9_int_clr : WT; bitpos: [6]; default: 0; - * The clear bit for SPI slave CMD9 interrupt. - */ - uint32_t slv_cmd9_int_clr:1; - /** slv_cmda_int_clr : WT; bitpos: [7]; default: 0; - * The clear bit for SPI slave CMDA interrupt. - */ - uint32_t slv_cmda_int_clr:1; - /** slv_rd_dma_done_int_clr : WT; bitpos: [8]; default: 0; - * The clear bit for SPI_SLV_RD_DMA_DONE_INT interrupt. - */ - uint32_t slv_rd_dma_done_int_clr:1; - /** slv_wr_dma_done_int_clr : WT; bitpos: [9]; default: 0; - * The clear bit for SPI_SLV_WR_DMA_DONE_INT interrupt. - */ - uint32_t slv_wr_dma_done_int_clr:1; - /** slv_rd_buf_done_int_clr : WT; bitpos: [10]; default: 0; - * The clear bit for SPI_SLV_RD_BUF_DONE_INT interrupt. - */ - uint32_t slv_rd_buf_done_int_clr:1; - /** slv_wr_buf_done_int_clr : WT; bitpos: [11]; default: 0; - * The clear bit for SPI_SLV_WR_BUF_DONE_INT interrupt. - */ - uint32_t slv_wr_buf_done_int_clr:1; - /** trans_done_int_clr : WT; bitpos: [12]; default: 0; - * The clear bit for SPI_TRANS_DONE_INT interrupt. - */ - uint32_t trans_done_int_clr:1; - /** dma_seg_trans_done_int_clr : WT; bitpos: [13]; default: 0; - * The clear bit for SPI_DMA_SEG_TRANS_DONE_INT interrupt. - */ - uint32_t dma_seg_trans_done_int_clr:1; - /** seg_magic_err_int_clr : WT; bitpos: [14]; default: 0; - * The clear bit for SPI_SEG_MAGIC_ERR_INT interrupt. - */ - uint32_t seg_magic_err_int_clr:1; //this field is only for GPSPI2 - /** slv_buf_addr_err_int_clr : WT; bitpos: [15]; default: 0; - * The clear bit for SPI_SLV_BUF_ADDR_ERR_INT interrupt. - */ - uint32_t slv_buf_addr_err_int_clr:1; - /** slv_cmd_err_int_clr : WT; bitpos: [16]; default: 0; - * The clear bit for SPI_SLV_CMD_ERR_INT interrupt. - */ - uint32_t slv_cmd_err_int_clr:1; - /** mst_rx_afifo_wfull_err_int_clr : WT; bitpos: [17]; default: 0; - * The clear bit for SPI_MST_RX_AFIFO_WFULL_ERR_INT interrupt. - */ - uint32_t mst_rx_afifo_wfull_err_int_clr:1; - /** mst_tx_afifo_rempty_err_int_clr : WT; bitpos: [18]; default: 0; - * The clear bit for SPI_MST_TX_AFIFO_REMPTY_ERR_INT interrupt. - */ - uint32_t mst_tx_afifo_rempty_err_int_clr:1; - /** app2_int_clr : WT; bitpos: [19]; default: 0; - * The clear bit for SPI_APP2_INT interrupt. - */ - uint32_t app2_int_clr:1; - /** app1_int_clr : WT; bitpos: [20]; default: 0; - * The clear bit for SPI_APP1_INT interrupt. - */ - uint32_t app1_int_clr:1; - uint32_t reserved_21:11; - }; - uint32_t val; -} spi_dma_int_clr_reg_t; - -/** Type of dma_int_raw register - * SPI interrupt raw register +/** Type of dma_int register + * SPI interrupt raw/ena/clr/sta/set register */ typedef union { struct { @@ -1038,301 +848,112 @@ typedef union { * 1: The current data rate of DMA Rx is smaller than that of SPI, which will lose the * receive data. 0: Others. */ - uint32_t dma_infifo_full_err_int_raw:1; + uint32_t dma_infifo_full_err_int:1; /** dma_outfifo_empty_err_int_raw : R/WTC/SS; bitpos: [1]; default: 0; * 1: The current data rate of DMA TX is smaller than that of SPI. SPI will stop in * master mode and send out all 0 in slave mode. 0: Others. */ - uint32_t dma_outfifo_empty_err_int_raw:1; + uint32_t dma_outfifo_empty_err_int:1; /** slv_ex_qpi_int_raw : R/WTC/SS; bitpos: [2]; default: 0; * The raw bit for SPI slave Ex_QPI interrupt. 1: SPI slave mode Ex_QPI transmission * is ended. 0: Others. */ - uint32_t slv_ex_qpi_int_raw:1; + uint32_t slv_ex_qpi_int:1; /** slv_en_qpi_int_raw : R/WTC/SS; bitpos: [3]; default: 0; * The raw bit for SPI slave En_QPI interrupt. 1: SPI slave mode En_QPI transmission * is ended. 0: Others. */ - uint32_t slv_en_qpi_int_raw:1; + uint32_t slv_en_qpi_int:1; /** slv_cmd7_int_raw : R/WTC/SS; bitpos: [4]; default: 0; * The raw bit for SPI slave CMD7 interrupt. 1: SPI slave mode CMD7 transmission is * ended. 0: Others. */ - uint32_t slv_cmd7_int_raw:1; + uint32_t slv_cmd7_int:1; /** slv_cmd8_int_raw : R/WTC/SS; bitpos: [5]; default: 0; * The raw bit for SPI slave CMD8 interrupt. 1: SPI slave mode CMD8 transmission is * ended. 0: Others. */ - uint32_t slv_cmd8_int_raw:1; + uint32_t slv_cmd8_int:1; /** slv_cmd9_int_raw : R/WTC/SS; bitpos: [6]; default: 0; * The raw bit for SPI slave CMD9 interrupt. 1: SPI slave mode CMD9 transmission is * ended. 0: Others. */ - uint32_t slv_cmd9_int_raw:1; + uint32_t slv_cmd9_int:1; /** slv_cmda_int_raw : R/WTC/SS; bitpos: [7]; default: 0; * The raw bit for SPI slave CMDA interrupt. 1: SPI slave mode CMDA transmission is * ended. 0: Others. */ - uint32_t slv_cmda_int_raw:1; + uint32_t slv_cmda_int:1; /** slv_rd_dma_done_int_raw : R/WTC/SS; bitpos: [8]; default: 0; * The raw bit for SPI_SLV_RD_DMA_DONE_INT interrupt. 1: SPI slave mode Rd_DMA * transmission is ended. 0: Others. */ - uint32_t slv_rd_dma_done_int_raw:1; + uint32_t slv_rd_dma_done_int:1; /** slv_wr_dma_done_int_raw : R/WTC/SS; bitpos: [9]; default: 0; * The raw bit for SPI_SLV_WR_DMA_DONE_INT interrupt. 1: SPI slave mode Wr_DMA * transmission is ended. 0: Others. */ - uint32_t slv_wr_dma_done_int_raw:1; + uint32_t slv_wr_dma_done_int:1; /** slv_rd_buf_done_int_raw : R/WTC/SS; bitpos: [10]; default: 0; * The raw bit for SPI_SLV_RD_BUF_DONE_INT interrupt. 1: SPI slave mode Rd_BUF * transmission is ended. 0: Others. */ - uint32_t slv_rd_buf_done_int_raw:1; + uint32_t slv_rd_buf_done_int:1; /** slv_wr_buf_done_int_raw : R/WTC/SS; bitpos: [11]; default: 0; * The raw bit for SPI_SLV_WR_BUF_DONE_INT interrupt. 1: SPI slave mode Wr_BUF * transmission is ended. 0: Others. */ - uint32_t slv_wr_buf_done_int_raw:1; + uint32_t slv_wr_buf_done_int:1; /** trans_done_int_raw : R/WTC/SS; bitpos: [12]; default: 0; * The raw bit for SPI_TRANS_DONE_INT interrupt. 1: SPI master mode transmission is * ended. 0: others. */ - uint32_t trans_done_int_raw:1; + uint32_t trans_done_int:1; /** dma_seg_trans_done_int_raw : R/WTC/SS; bitpos: [13]; default: 0; * The raw bit for SPI_DMA_SEG_TRANS_DONE_INT interrupt. 1: spi master DMA * full-duplex/half-duplex seg-conf-trans ends or slave half-duplex seg-trans ends. * And data has been pushed to corresponding memory. 0: seg-conf-trans or seg-trans * is not ended or not occurred. */ - uint32_t dma_seg_trans_done_int_raw:1; + uint32_t dma_seg_trans_done_int:1; /** seg_magic_err_int_raw : R/WTC/SS; bitpos: [14]; default: 0; * The raw bit for SPI_SEG_MAGIC_ERR_INT interrupt. 1: The magic value in CONF buffer * is error in the DMA seg-conf-trans. 0: others. */ - uint32_t seg_magic_err_int_raw:1; //this field is only for GPSPI2 + uint32_t seg_magic_err_int_raw:1; //this field is only forPI2 /** slv_buf_addr_err_int_raw : R/WTC/SS; bitpos: [15]; default: 0; * The raw bit for SPI_SLV_BUF_ADDR_ERR_INT interrupt. 1: The accessing data address * of the current SPI slave mode CPU controlled FD, Wr_BUF or Rd_BUF transmission is * bigger than 63. 0: Others. */ - uint32_t slv_buf_addr_err_int_raw:1; + uint32_t slv_buf_addr_err_int:1; /** slv_cmd_err_int_raw : R/WTC/SS; bitpos: [16]; default: 0; * The raw bit for SPI_SLV_CMD_ERR_INT interrupt. 1: The slave command value in the * current SPI slave HD mode transmission is not supported. 0: Others. */ - uint32_t slv_cmd_err_int_raw:1; + uint32_t slv_cmd_err_int:1; /** mst_rx_afifo_wfull_err_int_raw : R/WTC/SS; bitpos: [17]; default: 0; * The raw bit for SPI_MST_RX_AFIFO_WFULL_ERR_INT interrupt. 1: There is a RX AFIFO * write-full error when SPI inputs data in master mode. 0: Others. */ - uint32_t mst_rx_afifo_wfull_err_int_raw:1; + uint32_t mst_rx_afifo_wfull_err_int:1; /** mst_tx_afifo_rempty_err_int_raw : R/WTC/SS; bitpos: [18]; default: 0; * The raw bit for SPI_MST_TX_AFIFO_REMPTY_ERR_INT interrupt. 1: There is a TX BUF * AFIFO read-empty error when SPI outputs data in master mode. 0: Others. */ - uint32_t mst_tx_afifo_rempty_err_int_raw:1; + uint32_t mst_tx_afifo_rempty_err_int:1; /** app2_int_raw : R/WTC/SS; bitpos: [19]; default: 0; * The raw bit for SPI_APP2_INT interrupt. The value is only controlled by software. */ - uint32_t app2_int_raw:1; + uint32_t app2_int:1; /** app1_int_raw : R/WTC/SS; bitpos: [20]; default: 0; * The raw bit for SPI_APP1_INT interrupt. The value is only controlled by software. */ - uint32_t app1_int_raw:1; + uint32_t app1_int:1; uint32_t reserved_21:11; }; uint32_t val; -} spi_dma_int_raw_reg_t; - -/** Type of dma_int_st register - * SPI interrupt status register - */ -typedef union { - struct { - /** dma_infifo_full_err_int_st : RO; bitpos: [0]; default: 0; - * The status bit for SPI_DMA_INFIFO_FULL_ERR_INT interrupt. - */ - uint32_t dma_infifo_full_err_int_st:1; - /** dma_outfifo_empty_err_int_st : RO; bitpos: [1]; default: 0; - * The status bit for SPI_DMA_OUTFIFO_EMPTY_ERR_INT interrupt. - */ - uint32_t dma_outfifo_empty_err_int_st:1; - /** slv_ex_qpi_int_st : RO; bitpos: [2]; default: 0; - * The status bit for SPI slave Ex_QPI interrupt. - */ - uint32_t slv_ex_qpi_int_st:1; - /** slv_en_qpi_int_st : RO; bitpos: [3]; default: 0; - * The status bit for SPI slave En_QPI interrupt. - */ - uint32_t slv_en_qpi_int_st:1; - /** slv_cmd7_int_st : RO; bitpos: [4]; default: 0; - * The status bit for SPI slave CMD7 interrupt. - */ - uint32_t slv_cmd7_int_st:1; - /** slv_cmd8_int_st : RO; bitpos: [5]; default: 0; - * The status bit for SPI slave CMD8 interrupt. - */ - uint32_t slv_cmd8_int_st:1; - /** slv_cmd9_int_st : RO; bitpos: [6]; default: 0; - * The status bit for SPI slave CMD9 interrupt. - */ - uint32_t slv_cmd9_int_st:1; - /** slv_cmda_int_st : RO; bitpos: [7]; default: 0; - * The status bit for SPI slave CMDA interrupt. - */ - uint32_t slv_cmda_int_st:1; - /** slv_rd_dma_done_int_st : RO; bitpos: [8]; default: 0; - * The status bit for SPI_SLV_RD_DMA_DONE_INT interrupt. - */ - uint32_t slv_rd_dma_done_int_st:1; - /** slv_wr_dma_done_int_st : RO; bitpos: [9]; default: 0; - * The status bit for SPI_SLV_WR_DMA_DONE_INT interrupt. - */ - uint32_t slv_wr_dma_done_int_st:1; - /** slv_rd_buf_done_int_st : RO; bitpos: [10]; default: 0; - * The status bit for SPI_SLV_RD_BUF_DONE_INT interrupt. - */ - uint32_t slv_rd_buf_done_int_st:1; - /** slv_wr_buf_done_int_st : RO; bitpos: [11]; default: 0; - * The status bit for SPI_SLV_WR_BUF_DONE_INT interrupt. - */ - uint32_t slv_wr_buf_done_int_st:1; - /** trans_done_int_st : RO; bitpos: [12]; default: 0; - * The status bit for SPI_TRANS_DONE_INT interrupt. - */ - uint32_t trans_done_int_st:1; - /** dma_seg_trans_done_int_st : RO; bitpos: [13]; default: 0; - * The status bit for SPI_DMA_SEG_TRANS_DONE_INT interrupt. - */ - uint32_t dma_seg_trans_done_int_st:1; - /** seg_magic_err_int_st : RO; bitpos: [14]; default: 0; - * The status bit for SPI_SEG_MAGIC_ERR_INT interrupt. - */ - uint32_t seg_magic_err_int_st:1; //this field is only for GPSPI2 - /** slv_buf_addr_err_int_st : RO; bitpos: [15]; default: 0; - * The status bit for SPI_SLV_BUF_ADDR_ERR_INT interrupt. - */ - uint32_t slv_buf_addr_err_int_st:1; - /** slv_cmd_err_int_st : RO; bitpos: [16]; default: 0; - * The status bit for SPI_SLV_CMD_ERR_INT interrupt. - */ - uint32_t slv_cmd_err_int_st:1; - /** mst_rx_afifo_wfull_err_int_st : RO; bitpos: [17]; default: 0; - * The status bit for SPI_MST_RX_AFIFO_WFULL_ERR_INT interrupt. - */ - uint32_t mst_rx_afifo_wfull_err_int_st:1; - /** mst_tx_afifo_rempty_err_int_st : RO; bitpos: [18]; default: 0; - * The status bit for SPI_MST_TX_AFIFO_REMPTY_ERR_INT interrupt. - */ - uint32_t mst_tx_afifo_rempty_err_int_st:1; - /** app2_int_st : RO; bitpos: [19]; default: 0; - * The status bit for SPI_APP2_INT interrupt. - */ - uint32_t app2_int_st:1; - /** app1_int_st : RO; bitpos: [20]; default: 0; - * The status bit for SPI_APP1_INT interrupt. - */ - uint32_t app1_int_st:1; - uint32_t reserved_21:11; - }; - uint32_t val; -} spi_dma_int_st_reg_t; - -/** Type of dma_int_set register - * SPI interrupt software set register - */ -typedef union { - struct { - /** dma_infifo_full_err_int_set : WT; bitpos: [0]; default: 0; - * The software set bit for SPI_DMA_INFIFO_FULL_ERR_INT interrupt. - */ - uint32_t dma_infifo_full_err_int_set:1; - /** dma_outfifo_empty_err_int_set : WT; bitpos: [1]; default: 0; - * The software set bit for SPI_DMA_OUTFIFO_EMPTY_ERR_INT interrupt. - */ - uint32_t dma_outfifo_empty_err_int_set:1; - /** slv_ex_qpi_int_set : WT; bitpos: [2]; default: 0; - * The software set bit for SPI slave Ex_QPI interrupt. - */ - uint32_t slv_ex_qpi_int_set:1; - /** slv_en_qpi_int_set : WT; bitpos: [3]; default: 0; - * The software set bit for SPI slave En_QPI interrupt. - */ - uint32_t slv_en_qpi_int_set:1; - /** slv_cmd7_int_set : WT; bitpos: [4]; default: 0; - * The software set bit for SPI slave CMD7 interrupt. - */ - uint32_t slv_cmd7_int_set:1; - /** slv_cmd8_int_set : WT; bitpos: [5]; default: 0; - * The software set bit for SPI slave CMD8 interrupt. - */ - uint32_t slv_cmd8_int_set:1; - /** slv_cmd9_int_set : WT; bitpos: [6]; default: 0; - * The software set bit for SPI slave CMD9 interrupt. - */ - uint32_t slv_cmd9_int_set:1; - /** slv_cmda_int_set : WT; bitpos: [7]; default: 0; - * The software set bit for SPI slave CMDA interrupt. - */ - uint32_t slv_cmda_int_set:1; - /** slv_rd_dma_done_int_set : WT; bitpos: [8]; default: 0; - * The software set bit for SPI_SLV_RD_DMA_DONE_INT interrupt. - */ - uint32_t slv_rd_dma_done_int_set:1; - /** slv_wr_dma_done_int_set : WT; bitpos: [9]; default: 0; - * The software set bit for SPI_SLV_WR_DMA_DONE_INT interrupt. - */ - uint32_t slv_wr_dma_done_int_set:1; - /** slv_rd_buf_done_int_set : WT; bitpos: [10]; default: 0; - * The software set bit for SPI_SLV_RD_BUF_DONE_INT interrupt. - */ - uint32_t slv_rd_buf_done_int_set:1; - /** slv_wr_buf_done_int_set : WT; bitpos: [11]; default: 0; - * The software set bit for SPI_SLV_WR_BUF_DONE_INT interrupt. - */ - uint32_t slv_wr_buf_done_int_set:1; - /** trans_done_int_set : WT; bitpos: [12]; default: 0; - * The software set bit for SPI_TRANS_DONE_INT interrupt. - */ - uint32_t trans_done_int_set:1; - /** dma_seg_trans_done_int_set : WT; bitpos: [13]; default: 0; - * The software set bit for SPI_DMA_SEG_TRANS_DONE_INT interrupt. - */ - uint32_t dma_seg_trans_done_int_set:1; - /** seg_magic_err_int_set : WT; bitpos: [14]; default: 0; - * The software set bit for SPI_SEG_MAGIC_ERR_INT interrupt. - */ - uint32_t seg_magic_err_int_set:1; //this field is only for GPSPI2 - /** slv_buf_addr_err_int_set : WT; bitpos: [15]; default: 0; - * The software set bit for SPI_SLV_BUF_ADDR_ERR_INT interrupt. - */ - uint32_t slv_buf_addr_err_int_set:1; - /** slv_cmd_err_int_set : WT; bitpos: [16]; default: 0; - * The software set bit for SPI_SLV_CMD_ERR_INT interrupt. - */ - uint32_t slv_cmd_err_int_set:1; - /** mst_rx_afifo_wfull_err_int_set : WT; bitpos: [17]; default: 0; - * The software set bit for SPI_MST_RX_AFIFO_WFULL_ERR_INT interrupt. - */ - uint32_t mst_rx_afifo_wfull_err_int_set:1; - /** mst_tx_afifo_rempty_err_int_set : WT; bitpos: [18]; default: 0; - * The software set bit for SPI_MST_TX_AFIFO_REMPTY_ERR_INT interrupt. - */ - uint32_t mst_tx_afifo_rempty_err_int_set:1; - /** app2_int_set : WT; bitpos: [19]; default: 0; - * The software set bit for SPI_APP2_INT interrupt. - */ - uint32_t app2_int_set:1; - /** app1_int_set : WT; bitpos: [20]; default: 0; - * The software set bit for SPI_APP1_INT interrupt. - */ - uint32_t app1_int_set:1; - uint32_t reserved_21:11; - }; - uint32_t val; -} spi_dma_int_set_reg_t; - +} spi_dma_int_reg_t; /** Type of wn register * SPI CPU-controlled buffer @@ -1378,11 +999,11 @@ typedef struct { volatile spi_din_num_reg_t din_num; volatile spi_dout_mode_reg_t dout_mode; volatile spi_dma_conf_reg_t dma_conf; - volatile spi_dma_int_ena_reg_t dma_int_ena; - volatile spi_dma_int_clr_reg_t dma_int_clr; - volatile spi_dma_int_raw_reg_t dma_int_raw; - volatile spi_dma_int_st_reg_t dma_int_st; - volatile spi_dma_int_set_reg_t dma_int_set; + volatile spi_dma_int_reg_t dma_int_ena; + volatile spi_dma_int_reg_t dma_int_clr; + volatile spi_dma_int_reg_t dma_int_raw; + volatile spi_dma_int_reg_t dma_int_sta; + volatile spi_dma_int_reg_t dma_int_set; uint32_t reserved_048[20]; volatile spi_wn_reg_t data_buf[16]; uint32_t reserved_0d8[2]; diff --git a/components/soc/esp32p4/spi_periph.c b/components/soc/esp32p4/spi_periph.c index 3534bb9428..90f30522d9 100644 --- a/components/soc/esp32p4/spi_periph.c +++ b/components/soc/esp32p4/spi_periph.c @@ -11,5 +11,88 @@ Bunch of constants for every SPI peripheral: GPIO signals, irqs, hw addr of registers etc */ const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM] = { - + { + // MSPI on P4 has dedicated iomux pins + .spiclk_out = -1, + .spiclk_in = -1, + .spid_out = -1, + .spiq_out = -1, + .spiwp_out = -1, + .spihd_out = -1, + .spid_in = -1, + .spiq_in = -1, + .spiwp_in = -1, + .spihd_in = -1, + .spics_out = {-1}, + .spics_in = -1, + .spiclk_iomux_pin = -1, + .spid_iomux_pin = -1, + .spiq_iomux_pin = -1, + .spiwp_iomux_pin = -1, + .spihd_iomux_pin = -1, + .spics0_iomux_pin = -1, + .irq = -1, + .irq_dma = -1, + .module = -1, + .hw = NULL, + .func = -1, + }, { + .spiclk_out = SPI2_CK_PAD_OUT_IDX, + .spiclk_in = SPI2_CK_PAD_IN_IDX, + .spid_out = SPI2_D_PAD_OUT_IDX, + .spiq_out = SPI2_Q_PAD_OUT_IDX, + .spiwp_out = SPI2_WP_PAD_OUT_IDX, + .spihd_out = SPI2_HOLD_PAD_OUT_IDX, + .spid4_out = SPI2_IO4_PAD_OUT_IDX, + .spid5_out = SPI2_IO5_PAD_OUT_IDX, + .spid6_out = SPI2_IO6_PAD_OUT_IDX, + .spid7_out = SPI2_IO7_PAD_OUT_IDX, + .spid_in = SPI2_D_PAD_IN_IDX, + .spiq_in = SPI2_Q_PAD_IN_IDX, + .spiwp_in = SPI2_WP_PAD_IN_IDX, + .spihd_in = SPI2_HOLD_PAD_IN_IDX, + .spid4_in = SPI2_IO4_PAD_IN_IDX, + .spid5_in = SPI2_IO5_PAD_IN_IDX, + .spid6_in = SPI2_IO6_PAD_IN_IDX, + .spid7_in = SPI2_IO7_PAD_IN_IDX, + .spics_out = {SPI2_CS_PAD_OUT_IDX, SPI2_CS1_PAD_OUT_IDX, SPI2_CS2_PAD_OUT_IDX, SPI2_CS3_PAD_OUT_IDX, SPI2_CS4_PAD_OUT_IDX, SPI2_CS5_PAD_OUT_IDX}, + .spics_in = SPI2_CS_PAD_IN_IDX, + .spiclk_iomux_pin = SPI2_IOMUX_PIN_NUM_CLK, + .spid_iomux_pin = SPI2_IOMUX_PIN_NUM_MOSI, + .spiq_iomux_pin = SPI2_IOMUX_PIN_NUM_MISO, + .spiwp_iomux_pin = SPI2_IOMUX_PIN_NUM_WP, + .spihd_iomux_pin = SPI2_IOMUX_PIN_NUM_HD, + .spics0_iomux_pin = SPI2_IOMUX_PIN_NUM_CS, + .irq = ETS_SPI2_INTR_SOURCE, + .irq_dma = -1, + .module = PERIPH_GPSPI2_MODULE, + .hw = &GPSPI2, + .func = SPI2_FUNC_NUM, + }, { + .spiclk_out = SPI3_CK_PAD_OUT_IDX, + .spiclk_in = SPI3_CK_PAD_IN_IDX, + .spid_out = SPI3_D_PAD_OUT_IDX, + .spiq_out = SPI3_QO_PAD_OUT_IDX, + //SPI3 doesn't have wp and hd signals + .spiwp_out = SPI3_WP_PAD_OUT_IDX, + .spihd_out = SPI3_HOLD_PAD_OUT_IDX, + .spid_in = SPI3_D_PAD_IN_IDX, + .spiq_in = SPI3_Q_PAD_IN_IDX, + .spiwp_in = SPI3_WP_PAD_IN_IDX, + .spihd_in = SPI3_HOLD_PAD_IN_IDX, + .spics_out = {SPI3_CS_PAD_OUT_IDX, SPI3_CS1_PAD_OUT_IDX, SPI3_CS2_PAD_OUT_IDX}, + .spics_in = SPI3_CS_PAD_IN_IDX, + //SPI3 doesn't have iomux pins + .spiclk_iomux_pin = -1, + .spid_iomux_pin = -1, + .spiq_iomux_pin = -1, + .spiwp_iomux_pin = -1, + .spihd_iomux_pin = -1, + .spics0_iomux_pin = -1, + .irq = ETS_SPI3_INTR_SOURCE, + .irq_dma = -1, + .module = PERIPH_GPSPI3_MODULE, + .hw = &GPSPI3, + .func = -1, + } }; diff --git a/examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm/README.md b/examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm/README.md index 97254f4f6d..00f001896c 100644 --- a/examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm/README.md +++ b/examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | -------- | -------- | # I2S TDM Example -- ES7210 4-Ch ADC Codec