diff --git a/components/esp_hw_support/CMakeLists.txt b/components/esp_hw_support/CMakeLists.txt index 919c7d25a6..dec7467301 100644 --- a/components/esp_hw_support/CMakeLists.txt +++ b/components/esp_hw_support/CMakeLists.txt @@ -45,6 +45,10 @@ if(NOT BOOTLOADER_BUILD) list(APPEND srcs "adc_share_hw_ctrl.c") endif() + if(CONFIG_SOC_ISP_SHARE_CSI_BRG) + list(APPEND srcs "mipi_csi_share_hw_ctrl.c") + endif() + if(CONFIG_SOC_PM_SUPPORT_CPU_PD) list(APPEND srcs "sleep_cpu.c") endif() diff --git a/components/esp_hw_support/include/esp_private/mipi_csi_share_hw_ctrl.h b/components/esp_hw_support/include/esp_private/mipi_csi_share_hw_ctrl.h new file mode 100644 index 0000000000..2fc2c54235 --- /dev/null +++ b/components/esp_hw_support/include/esp_private/mipi_csi_share_hw_ctrl.h @@ -0,0 +1,46 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + MIPI_CSI_BRG_USER_CSI, ///< Used by CSI Host + MIPI_CSI_BRG_USER_ISP_DVP, ///< Used by ISP DVP + MIPI_CSI_BRG_USER_SHARE, ///< Don't care user, share the usage with other users +} mipi_csi_brg_user_t; + +/** + * @brief Claim MIPI CSI Bridge peripheral + * + * @param[in] user CSI Bridge user + * @param[out] out_id ID of the CSI Bridge + * + * @return + * - ESP_OK + * - ESP_ERR_NOT_FOUND No free CSI Bridge + */ +esp_err_t mipi_csi_brg_claim(mipi_csi_brg_user_t user, int *out_id); + +/** + * @brief Declaim MIPI CSI Bridge peripheral + * + * @param[in] id ID of the CSI Bridge + * + * @return + * - ESP_OK + * - ESP_ERR_INVALID_STATE CSI Bridge isn't claimed yet + */ +esp_err_t mipi_csi_brg_declaim(int id); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hw_support/mipi_csi_share_hw_ctrl.c b/components/esp_hw_support/mipi_csi_share_hw_ctrl.c new file mode 100644 index 0000000000..e5909802d7 --- /dev/null +++ b/components/esp_hw_support/mipi_csi_share_hw_ctrl.c @@ -0,0 +1,88 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sdkconfig.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "esp_private/periph_ctrl.h" +#include "esp_private/mipi_csi_share_hw_ctrl.h" +#include "soc/soc_caps.h" +#include "hal/mipi_csi_ll.h" + +#define MIPI_CSI_BRG_USER_NO_USER 99 + +typedef struct { + mipi_csi_brg_user_t user[MIPI_CSI_BRG_LL_BRG_NUMS]; + int ref_cnt[MIPI_CSI_BRG_LL_BRG_NUMS]; + portMUX_TYPE spinlock; +} csi_brg_share_ctx_t; + +static csi_brg_share_ctx_t s_ctx = { + .user[0 ...(MIPI_CSI_BRG_LL_BRG_NUMS - 1)] = MIPI_CSI_BRG_USER_NO_USER, + .ref_cnt[0 ...(MIPI_CSI_BRG_LL_BRG_NUMS - 1)] = 0, + .spinlock = portMUX_INITIALIZER_UNLOCKED, +}; + +static const char *TAG = "CSI_SHARE"; + +esp_err_t mipi_csi_brg_claim(mipi_csi_brg_user_t user, int *out_id) +{ + bool found = true; + portENTER_CRITICAL(&s_ctx.spinlock); + for (int i = 0; i < MIPI_CSI_BRG_LL_BRG_NUMS; i ++) { + bool user_is_shared = (s_ctx.user[i] == MIPI_CSI_BRG_USER_SHARE); + bool to_share = (user == MIPI_CSI_BRG_USER_SHARE); + bool duplicate_user = (s_ctx.user[i] == user); + + if (s_ctx.ref_cnt[i] == 0) { + PERIPH_RCC_ATOMIC() { + mipi_csi_ll_enable_brg_module_clock(i, true); + mipi_csi_ll_reset_brg_module_clock(i); + } + s_ctx.user[i] = user; + } else { + if (!user_is_shared && !to_share && !duplicate_user) { + found = false; + } + + if (user_is_shared) { + s_ctx.user[i] = user; + } + } + + if (found) { + s_ctx.ref_cnt[i]++; + *out_id = i; + break; + } + } + portEXIT_CRITICAL(&s_ctx.spinlock); + + if (!found) { + return ESP_ERR_NOT_FOUND; + } + return ESP_OK; +} + +esp_err_t mipi_csi_brg_declaim(int id) +{ + portENTER_CRITICAL(&s_ctx.spinlock); + + s_ctx.ref_cnt[id]--; + if (s_ctx.ref_cnt[id] < 0) { + portEXIT_CRITICAL(&s_ctx.spinlock); + ESP_LOGE(TAG, "%s called, but s_ctx.ref_cnt[%d] == 0", __func__, id); + return ESP_ERR_INVALID_STATE; + } else if (s_ctx.ref_cnt[id] == 0) { + PERIPH_RCC_ATOMIC() { + mipi_csi_ll_enable_brg_module_clock(id, false); + } + s_ctx.user[id] = MIPI_CSI_BRG_USER_NO_USER; + } + portEXIT_CRITICAL(&s_ctx.spinlock); + + return ESP_OK; +} diff --git a/components/hal/esp32p4/include/hal/mipi_csi_brg_ll.h b/components/hal/esp32p4/include/hal/mipi_csi_brg_ll.h new file mode 100644 index 0000000000..fceef8370c --- /dev/null +++ b/components/hal/esp32p4/include/hal/mipi_csi_brg_ll.h @@ -0,0 +1,70 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include +#include "hal/misc.h" +#include "hal/assert.h" +#include "hal/hal_utils.h" +#include "soc/mipi_csi_bridge_struct.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MIPI_CSI_BRG_LL_BRG_NUMS 1 +#define MIPI_CSI_BRG_LL_GET_HW(id) (((id) == 0) ? &MIPI_CSI_BRIDGE : NULL) + +/** + * @brief Enable the CSI bridge + * + * @param dev Pointer to the CSI bridge controller register base address + * @param en True to enable, false to disable + */ +static inline void mipi_csi_brg_ll_enable(csi_brg_dev_t *dev, bool en) +{ + dev->csi_en.csi_brg_en = en; +} + +/** + * @brief Set the number of 64-bit words in one dma burst transfer + * + * @note valid only when csi_bridge is the flow controller + * + * @param dev Pointer to the CSI bridge controller register base address + * @param burst_len Number of 64-bit words in one dma burst transfer + */ +static inline void mipi_csi_brg_ll_set_burst_len(csi_brg_dev_t *dev, uint32_t burst_len) +{ + dev->dma_req_cfg.dma_burst_len = burst_len; +} + +/** + * @brief Set horizontal pixel number + * + * @param[in] dev Pointer to the CSI bridge controller register base address + * @param[in] pixel_num number of pixels + */ +static inline void mipi_csi_brg_ll_set_intput_data_h_pixel_num(csi_brg_dev_t *dev, uint32_t pixel_num) +{ + dev->frame_cfg.hadr_num = pixel_num; +} + +/** + * @brief Set vertical row number + * + * @param[in] dev Pointer to the CSI bridge controller register base address + * @param[in] row_num number of rows + */ +static inline void mipi_csi_brg_ll_set_intput_data_v_row_num(csi_brg_dev_t *dev, uint32_t row_num) +{ + dev->frame_cfg.vadr_num = row_num; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32p4/include/hal/mipi_csi_ll.h b/components/hal/esp32p4/include/hal/mipi_csi_ll.h new file mode 100644 index 0000000000..6c3de4613a --- /dev/null +++ b/components/hal/esp32p4/include/hal/mipi_csi_ll.h @@ -0,0 +1,55 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include +#include "hal/misc.h" +#include "hal/assert.h" +#include "hal/hal_utils.h" +#include "hal/mipi_csi_brg_ll.h" +#include "soc/hp_sys_clkrst_struct.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*--------------------------------------------------------------- + CSI Bridge +---------------------------------------------------------------*/ +/** + * @brief Enable the bus clock for CSI Bridge module + * + * @param csi_bridge_id CSI Bridge ID + * @param en enable / disable + */ +static inline void mipi_csi_ll_enable_brg_module_clock(int csi_bridge_id, bool en) +{ + HP_SYS_CLKRST.soc_clk_ctrl1.reg_csi_brg_sys_clk_en = en; +} + +/// 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 mipi_csi_ll_enable_brg_module_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; mipi_csi_ll_enable_brg_module_clock(__VA_ARGS__) + +/** + * @brief Reset the CSI Bridge module + * + * @param csi_bridge_id CSI Bridge ID + */ +static inline void mipi_csi_ll_reset_brg_module_clock(int csi_bridge_id) +{ + HP_SYS_CLKRST.hp_rst_en0.reg_rst_en_csi_brg = 1; + HP_SYS_CLKRST.hp_rst_en0.reg_rst_en_csi_brg = 0; +} + +/// 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 mipi_csi_ll_reset_brg_module_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; mipi_csi_ll_reset_brg_module_clock(__VA_ARGS__) + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 096a99b443..d8fe822a7d 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -615,6 +615,10 @@ config SOC_ISP_AF_WINDOW_NUMS int default 3 +config SOC_ISP_SHARE_CSI_BRG + bool + default y + config SOC_LEDC_SUPPORT_PLL_DIV_CLOCK bool default y diff --git a/components/soc/esp32p4/include/soc/mipi_csi_bridge_struct.h b/components/soc/esp32p4/include/soc/mipi_csi_bridge_struct.h index a5fbf6d064..b2653111e2 100644 --- a/components/soc/esp32p4/include/soc/mipi_csi_bridge_struct.h +++ b/components/soc/esp32p4/include/soc/mipi_csi_bridge_struct.h @@ -343,7 +343,7 @@ typedef union { } csi_brg_host_ctrl_reg_t; -typedef struct { +typedef struct csi_brg_dev_t { volatile csi_brg_clk_en_reg_t clk_en; volatile csi_brg_csi_en_reg_t csi_en; volatile csi_brg_dma_req_cfg_reg_t dma_req_cfg; @@ -361,6 +361,7 @@ typedef struct { volatile csi_brg_host_ctrl_reg_t host_ctrl; } csi_brg_dev_t; +extern csi_brg_dev_t MIPI_CSI_BRIDGE; #ifndef __cplusplus _Static_assert(sizeof(csi_brg_dev_t) == 0x44, "Invalid size of csi_brg_dev_t structure"); diff --git a/components/soc/esp32p4/include/soc/mipi_csi_host_struct.h b/components/soc/esp32p4/include/soc/mipi_csi_host_struct.h index e1d19a85b4..d491dc4fd6 100644 --- a/components/soc/esp32p4/include/soc/mipi_csi_host_struct.h +++ b/components/soc/esp32p4/include/soc/mipi_csi_host_struct.h @@ -1815,7 +1815,7 @@ typedef union { } csi_host_phy_stopstate_reg_t; -typedef struct { +typedef struct csi_host_dev_t { volatile csi_host_version_reg_t version; volatile csi_host_n_lanes_reg_t n_lanes; volatile csi_host_csi2_resetn_reg_t csi2_resetn; @@ -1872,6 +1872,7 @@ typedef struct { volatile csi_host_scrambling_seed2_reg_t scrambling_seed2; } csi_host_dev_t; +extern csi_host_dev_t MIPI_CSI_HOST; #ifndef __cplusplus _Static_assert(sizeof(csi_host_dev_t) == 0x30c, "Invalid size of csi_host_dev_t structure"); diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index c181db4153..4121e1839a 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -275,6 +275,7 @@ #define SOC_ISP_AF_CTLR_NUMS 1U #define SOC_ISP_AF_ENV_DETECTOR_NUMS 1U #define SOC_ISP_AF_WINDOW_NUMS 3 +#define SOC_ISP_SHARE_CSI_BRG 1 /*-------------------------- LEDC CAPS ---------------------------------------*/ #define SOC_LEDC_SUPPORT_PLL_DIV_CLOCK (1)