mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-31 06:12:42 +00:00
220 lines
7.6 KiB
C
220 lines
7.6 KiB
C
/*
|
|
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdatomic.h>
|
|
#include <sys/cdefs.h>
|
|
#include <sys/param.h>
|
|
#include <sys/lock.h>
|
|
#include "sdkconfig.h"
|
|
#if CONFIG_PARLIO_ENABLE_DEBUG_LOG
|
|
// The local log level must be defined before including esp_log.h
|
|
// Set the maximum log level for this source file
|
|
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
|
|
#endif
|
|
#include "esp_log.h"
|
|
#include "esp_check.h"
|
|
#include "esp_attr.h"
|
|
#include "esp_err.h"
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
#include "freertos/queue.h"
|
|
#include "freertos/idf_additions.h"
|
|
#include "soc/soc_caps.h"
|
|
#include "soc/gdma_channel.h"
|
|
#include "soc/parlio_periph.h"
|
|
#include "hal/parlio_types.h"
|
|
#include "hal/parlio_hal.h"
|
|
#include "hal/parlio_ll.h"
|
|
#include "hal/cache_hal.h"
|
|
#include "hal/cache_ll.h"
|
|
#include "rom/cache.h"
|
|
#include "esp_heap_caps.h"
|
|
#include "driver/parlio_types.h"
|
|
#include "driver/bitscrambler.h"
|
|
#include "esp_cache.h"
|
|
#include "esp_clk_tree.h"
|
|
#include "esp_pm.h"
|
|
#include "esp_memory_utils.h"
|
|
#include "esp_private/periph_ctrl.h"
|
|
#include "esp_private/esp_gpio_reserve.h"
|
|
#include "esp_private/gpio.h"
|
|
#include "esp_private/sleep_retention.h"
|
|
#include "esp_private/esp_clk_tree_common.h"
|
|
#include "esp_private/gdma.h"
|
|
#include "esp_private/gdma_link.h"
|
|
#include "esp_private/esp_dma_utils.h"
|
|
|
|
#if CONFIG_PARLIO_OBJ_CACHE_SAFE
|
|
#define PARLIO_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
|
#else
|
|
#define PARLIO_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
|
|
#endif
|
|
|
|
#if SOC_PARLIO_TX_RX_SHARE_INTERRUPT
|
|
#define PARLIO_INTR_ALLOC_FLAG_SHARED ESP_INTR_FLAG_SHARED
|
|
#else
|
|
#define PARLIO_INTR_ALLOC_FLAG_SHARED 0
|
|
#endif
|
|
|
|
#if CONFIG_PARLIO_TX_ISR_CACHE_SAFE
|
|
#define PARLIO_TX_INTR_ALLOC_FLAG (ESP_INTR_FLAG_LOWMED | PARLIO_INTR_ALLOC_FLAG_SHARED | ESP_INTR_FLAG_IRAM)
|
|
#else
|
|
#define PARLIO_TX_INTR_ALLOC_FLAG (ESP_INTR_FLAG_LOWMED | PARLIO_INTR_ALLOC_FLAG_SHARED)
|
|
#endif
|
|
|
|
// Use retention link only when the target supports sleep retention is enabled
|
|
#define PARLIO_USE_RETENTION_LINK (SOC_PARLIO_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP)
|
|
|
|
#define PARLIO_DMA_DESCRIPTOR_BUFFER_MAX_SIZE 4095
|
|
|
|
#if defined(SOC_GDMA_TRIG_PERIPH_PARLIO0_BUS) // Parlio uses GDMA
|
|
#if defined(SOC_GDMA_BUS_AHB) && (SOC_GDMA_TRIG_PERIPH_PARLIO0_BUS == SOC_GDMA_BUS_AHB)
|
|
#define PARLIO_DMA_DESC_ALIGNMENT 4
|
|
#define PARLIO_GDMA_NEW_CHANNEL gdma_new_ahb_channel
|
|
#elif defined(SOC_GDMA_BUS_AXI) && (SOC_GDMA_TRIG_PERIPH_PARLIO0_BUS == SOC_GDMA_BUS_AXI)
|
|
#define PARLIO_DMA_DESC_ALIGNMENT 8
|
|
#define PARLIO_GDMA_NEW_CHANNEL gdma_new_axi_channel
|
|
#endif
|
|
#endif // defined(SOC_GDMA_TRIG_PERIPH_PARLIO0_BUS)
|
|
|
|
// loop transmission requires ping-pong link to prevent data tearing.
|
|
#define PARLIO_DMA_LINK_NUM 2
|
|
|
|
#if SOC_PERIPH_CLK_CTRL_SHARED
|
|
#define PARLIO_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC()
|
|
#else
|
|
#define PARLIO_CLOCK_SRC_ATOMIC()
|
|
#endif
|
|
|
|
#if !SOC_RCC_IS_INDEPENDENT
|
|
// Reset and Clock Control registers are mixing with other peripherals, so we need to use a critical section
|
|
#define PARLIO_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
|
|
#else
|
|
#define PARLIO_RCC_ATOMIC()
|
|
#endif // SOC_RCC_IS_INDEPENDENT
|
|
|
|
///!< Logging settings
|
|
#define TAG "parlio"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
typedef enum {
|
|
PARLIO_TX_QUEUE_READY,
|
|
PARLIO_TX_QUEUE_PROGRESS,
|
|
PARLIO_TX_QUEUE_COMPLETE,
|
|
PARLIO_TX_QUEUE_MAX,
|
|
} parlio_tx_queue_status_t;
|
|
|
|
typedef enum {
|
|
PARLIO_DIR_TX,
|
|
PARLIO_DIR_RX,
|
|
} parlio_dir_t;
|
|
|
|
typedef enum {
|
|
PARLIO_TX_FSM_INIT,
|
|
PARLIO_TX_FSM_ENABLE,
|
|
PARLIO_TX_FSM_RUN,
|
|
PARLIO_TX_FSM_WAIT,
|
|
} parlio_tx_fsm_t;
|
|
|
|
typedef struct parlio_unit_t *parlio_unit_base_handle_t;
|
|
|
|
typedef struct parlio_group_t {
|
|
int group_id; // group ID, index from 0
|
|
portMUX_TYPE spinlock; // to protect per-group register level concurrent access
|
|
parlio_hal_context_t hal; // hal layer context
|
|
uint32_t dma_align; // DMA buffer alignment
|
|
parlio_unit_base_handle_t tx_units[SOC_PARLIO_TX_UNITS_PER_GROUP]; // tx unit handles
|
|
parlio_unit_base_handle_t rx_units[SOC_PARLIO_RX_UNITS_PER_GROUP]; // rx unit handles
|
|
} parlio_group_t;
|
|
|
|
/**
|
|
* @brief The common field of rx and tx unit structure
|
|
*/
|
|
struct parlio_unit_t {
|
|
int unit_id; // unit id
|
|
parlio_dir_t dir; // direction
|
|
parlio_group_t *group; // group handle
|
|
};
|
|
|
|
typedef struct {
|
|
uint32_t idle_value; // Parallel IO bus idle value
|
|
const void *payload; // payload to be transmitted
|
|
size_t payload_bits; // payload size in bits
|
|
int dma_link_idx; // index of DMA link list
|
|
const void *bitscrambler_program; // bitscrambler program binary
|
|
struct {
|
|
uint32_t loop_transmission : 1; // whether the transmission is in loop mode
|
|
} flags; // Extra configuration flags
|
|
} parlio_tx_trans_desc_t;
|
|
|
|
// original function pointer type definition
|
|
|
|
typedef esp_err_t (*parlio_tx_bs_enable_fn_t)(parlio_tx_unit_handle_t tx_unit, parlio_tx_trans_desc_t *t);
|
|
typedef esp_err_t (*parlio_tx_bs_disable_fn_t)(parlio_tx_unit_handle_t tx_unit);
|
|
|
|
typedef struct parlio_tx_unit_t {
|
|
struct parlio_unit_t base; // base unit
|
|
size_t data_width; // data width
|
|
intr_handle_t intr; // allocated interrupt handle
|
|
gdma_channel_handle_t dma_chan; // DMA channel
|
|
gdma_link_list_handle_t dma_link[PARLIO_DMA_LINK_NUM]; // DMA link list handle
|
|
size_t int_mem_align; // Alignment for internal memory
|
|
size_t ext_mem_align; // Alignment for external memory
|
|
#if CONFIG_PM_ENABLE
|
|
esp_pm_lock_handle_t pm_lock; // power management lock
|
|
#endif
|
|
portMUX_TYPE spinlock; // prevent resource accessing by user and interrupt concurrently
|
|
uint32_t out_clk_freq_hz; // output clock frequency
|
|
parlio_clock_source_t clk_src; // Parallel IO internal clock source
|
|
size_t max_transfer_bits; // maximum transfer size in bits
|
|
size_t queue_depth; // size of transaction queue
|
|
size_t num_trans_inflight; // indicates the number of transactions that are undergoing but not recycled to ready_queue
|
|
QueueHandle_t trans_queues[PARLIO_TX_QUEUE_MAX]; // transaction queues
|
|
parlio_tx_trans_desc_t *cur_trans; // points to current transaction
|
|
uint32_t idle_value_mask; // mask of idle value
|
|
_Atomic parlio_tx_fsm_t fsm; // Driver FSM state
|
|
parlio_tx_done_callback_t on_trans_done; // callback function when the transmission is done
|
|
void *user_data; // user data passed to the callback function
|
|
bitscrambler_handle_t bs_handle; // bitscrambler handle
|
|
parlio_tx_bs_enable_fn_t bs_enable_fn; // bitscrambler enable function
|
|
parlio_tx_bs_disable_fn_t bs_disable_fn; // bitscrambler disable function
|
|
parlio_tx_trans_desc_t trans_desc_pool[]; // transaction descriptor pool
|
|
} parlio_tx_unit_t;
|
|
|
|
/**
|
|
* @brief Register the rx or tx unit to the parlio group
|
|
*
|
|
* @param[in] unit The TX/RX unit base handle
|
|
* @return
|
|
* - ESP_ERR_NO_MEM No memory for the unit
|
|
* - ESP_ERR_NOT_FOUND No available unit found on this group
|
|
* - ESP_OK Success to register the unit on the group
|
|
*/
|
|
esp_err_t parlio_register_unit_to_group(parlio_unit_base_handle_t unit);
|
|
|
|
/**
|
|
* @brief Unregister the rx or tx unit from the parlio group
|
|
*
|
|
* @param[in] unit The TX/RX unit base handle
|
|
*/
|
|
void parlio_unregister_unit_from_group(parlio_unit_base_handle_t unit);
|
|
|
|
#if PARLIO_USE_RETENTION_LINK
|
|
esp_err_t parlio_create_sleep_retention_link_cb(void *arg);
|
|
void parlio_create_retention_module(parlio_group_t *group);
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|