feat(csi): added csi driver

This commit is contained in:
Armando
2024-02-04 19:06:11 +08:00
committed by Armando (Dou Yiwen)
parent 4c190c56e6
commit f918079e8e
35 changed files with 1657 additions and 9 deletions
+4
View File
@@ -177,6 +177,10 @@ if(NOT BOOTLOADER_BUILD)
list(APPEND srcs "mipi_dsi_hal.c")
endif()
if(CONFIG_SOC_MIPI_CSI_SUPPORTED)
list(APPEND srcs "mipi_csi_hal.c")
endif()
if(CONFIG_SOC_ECC_SUPPORTED)
list(APPEND srcs "ecc_hal.c")
endif()
@@ -377,7 +377,7 @@ static inline void dw_gdma_ll_channel_set_trans_block_size(dw_gdma_dev_t *dev, u
__attribute__((always_inline))
static inline void dw_gdma_ll_channel_set_src_master_port(dw_gdma_dev_t *dev, uint8_t channel, intptr_t mem_addr)
{
if (mem_addr == MIPI_CSI_MEM_BASE) {
if (mem_addr == MIPI_CSI_BRG_MEM_BASE) {
dev->ch[channel].ctl0.sms = DW_GDMA_LL_MASTER_PORT_MIPI_CSI;
} else {
dev->ch[channel].ctl0.sms = DW_GDMA_LL_MASTER_PORT_MEMORY;
@@ -394,7 +394,7 @@ static inline void dw_gdma_ll_channel_set_src_master_port(dw_gdma_dev_t *dev, ui
__attribute__((always_inline))
static inline void dw_gdma_ll_channel_set_dst_master_port(dw_gdma_dev_t *dev, uint8_t channel, intptr_t mem_addr)
{
if (mem_addr == MIPI_DSI_MEM_BASE) {
if (mem_addr == MIPI_DSI_BRG_MEM_BASE) {
dev->ch[channel].ctl0.dms = DW_GDMA_LL_MASTER_PORT_MIPI_DSI;
} else {
dev->ch[channel].ctl0.dms = DW_GDMA_LL_MASTER_PORT_MEMORY;
@@ -986,7 +986,7 @@ static inline void dw_gdma_ll_lli_set_dst_trans_width(dw_gdma_link_list_item_t *
__attribute__((always_inline))
static inline void dw_gdma_ll_lli_set_src_master_port(dw_gdma_link_list_item_t *lli, intptr_t mem_addr)
{
if (mem_addr == MIPI_CSI_MEM_BASE) {
if (mem_addr == MIPI_CSI_BRG_MEM_BASE) {
lli->ctrl_lo.sms = DW_GDMA_LL_MASTER_PORT_MIPI_CSI;
} else {
lli->ctrl_lo.sms = DW_GDMA_LL_MASTER_PORT_MEMORY;
@@ -1002,7 +1002,7 @@ static inline void dw_gdma_ll_lli_set_src_master_port(dw_gdma_link_list_item_t *
__attribute__((always_inline))
static inline void dw_gdma_ll_lli_set_dst_master_port(dw_gdma_link_list_item_t *lli, intptr_t mem_addr)
{
if (mem_addr == MIPI_DSI_MEM_BASE) {
if (mem_addr == MIPI_DSI_BRG_MEM_BASE) {
lli->ctrl_lo.dms = DW_GDMA_LL_MASTER_PORT_MIPI_DSI;
} else {
lli->ctrl_lo.dms = DW_GDMA_LL_MASTER_PORT_MEMORY;
@@ -10,6 +10,7 @@
#include "hal/misc.h"
#include "hal/assert.h"
#include "hal/hal_utils.h"
#include "hal/mipi_csi_types.h"
#include "soc/mipi_csi_bridge_struct.h"
#ifdef __cplusplus
@@ -65,6 +66,74 @@ static inline void mipi_csi_brg_ll_set_intput_data_v_row_num(csi_brg_dev_t *dev,
dev->frame_cfg.vadr_num = row_num;
}
/**
* @brief Set the buffer almost full threshold for the MIPI CSI bridge
*
* @param dev Pointer to the CSI bridge controller register base address
* @param afull_thrd full threshold
*/
static inline void mipi_csi_brg_ll_set_flow_ctl_buf_afull_thrd(csi_brg_dev_t *dev, size_t afull_thrd)
{
dev->buf_flow_ctl.csi_buf_afull_thrd = afull_thrd;
}
/**
* @brief Set the frame data whether contain hsync
*
* @param dev Pointer to the CSI bridge controller register base address
* @param en 0: frame data doesn't contain hsync. 1: frame data contains hsync.
*/
static inline void mipi_csi_brg_ll_enable_has_hsync(csi_brg_dev_t *dev, bool en)
{
dev->frame_cfg.has_hsync_e = en;
}
/**
* @brief Set the min value of data type used for pixel filter.
*
* @param dev Pointer to the CSI bridge controller register base address
* @param type_min The min data type allowed by bridge's pixel filter.
* The data type specifie the format and the content of the payload data.
*/
static inline void mipi_csi_brg_ll_set_data_type_min(csi_brg_dev_t *dev, uint16_t type_min)
{
dev->data_type_cfg.data_type_min = type_min;
}
/**
* @brief Set the the max value of data type used for pixel filter.
*
* @param dev Pointer to the CSI bridge controller register base address
* @param type_max The max data type allowed by bridge's pixel filter.
* The data type specifie the format and the content of the payload data.
*/
static inline void mipi_csi_brg_ll_set_data_type_max(csi_brg_dev_t *dev, uint16_t type_max)
{
dev->data_type_cfg.data_type_max = type_max;
}
/**
* @brief Set the DMA interval configuration.
*
* @param dev Pointer to the CSI bridge controller register base address
* @param interval 16'b1: 1 cycle. 16'b11: 2 cycle. ... ... 16'hFFFF: 16 cycle.
*/
static inline void mipi_csi_brg_ll_set_dma_req_interval(csi_brg_dev_t *dev, uint16_t interval)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(dev->dma_req_interval, dma_req_interval, interval);
}
/**
* @brief Set the data endianness order in bytes
*
* @param dev Pointer to the CSI bridge controller register base address
* @param byte_swap_en byte swap enable or not
*/
static inline void mipi_csi_brg_ll_set_byte_endian(csi_brg_dev_t *dev, bool byte_swap_en)
{
dev->endian_mode.byte_endian_order = byte_swap_en;
}
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,69 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include "hal/misc.h"
#include "hal/assert.h"
#include "soc/mipi_csi_host_struct.h"
#include "hal/mipi_csi_types.h"
#ifdef __cplusplus
extern "C" {
#endif
#define MIPI_CSI_HOST_LL_GET_HW(num) (((num) == 0) ? (&MIPI_CSI_HOST) : NULL)
#define MIPI_CSI_HOST_LL_LANE_NUM_MAX 2
/**
* @brief Enable CSI host reset output
*
* @param dev Pointer to the CSI Host controller register base address
* @param en True to enable, False to disable
*/
static inline void mipi_csi_host_ll_enable_reset_output(csi_host_dev_t *dev, bool en)
{
dev->csi2_resetn.csi2_resetn = !en; // host reset output, active low
}
/**
* @brief Set the MIPI CSI lane num
*
* @param dev Pointer to the CSI Host controller register base address
* @param lanes_num Number of MIPI CSI lanes
*/
static inline void mipi_csi_host_ll_set_active_lanes_num(csi_host_dev_t *dev, int lanes_num)
{
dev->n_lanes.n_lanes = lanes_num - 1;
}
/**
* @brief Enable the CSI virtual channel extension
*
* @param dev Pointer to the CSI Host controller register base address
* @param en True to enable, False to disable
*/
static inline void mipi_csi_host_ll_enable_virtual_channel_extension(csi_host_dev_t *dev, bool en)
{
dev->vc_extension.vcx = !en; // 0 is enable
}
/**
* @brief Enable the data de-scrambling on the controller side
*
* @param dev Pointer to the CSI Host controller register base address
* @param en True to enable, False to disable
*/
static inline void mipi_csi_host_ll_enable_scrambling(csi_host_dev_t *dev, bool en)
{
dev->scrambling.scramble_enable = en;
}
#ifdef __cplusplus
}
#endif
@@ -10,13 +10,18 @@
#include "hal/misc.h"
#include "hal/assert.h"
#include "hal/hal_utils.h"
#include "hal/mipi_csi_types.h"
#include "hal/mipi_csi_brg_ll.h"
#include "hal/mipi_csi_phy_ll.h"
#include "hal/mipi_csi_host_ll.h"
#include "soc/hp_sys_clkrst_struct.h"
#ifdef __cplusplus
extern "C" {
#endif
#define MIPI_CSI_LL_HOST_CTLR_NUMS 1
/*---------------------------------------------------------------
CSI Bridge
---------------------------------------------------------------*/
@@ -50,6 +55,88 @@ static inline void mipi_csi_ll_reset_brg_module_clock(int csi_bridge_id)
/// 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__)
/*---------------------------------------------------------------
CSI PHY
---------------------------------------------------------------*/
/**
* @brief Set the clock source for the MIPI CSI D-PHY
*
* @param group_id Group ID
* @param source Clock source
*/
static inline void mipi_csi_ll_set_phy_clock_source(int group_id, mipi_csi_phy_clock_source_t source)
{
(void)group_id;
switch (source) {
case MIPI_CSI_PHY_CLK_SRC_PLL_F20M:
HP_SYS_CLKRST.peri_clk_ctrl03.reg_mipi_csi_dphy_clk_src_sel = 0;
break;
case MIPI_CSI_PHY_CLK_SRC_RC_FAST:
HP_SYS_CLKRST.peri_clk_ctrl03.reg_mipi_csi_dphy_clk_src_sel = 1;
break;
case MIPI_CSI_PHY_CLK_SRC_PLL_F25M:
HP_SYS_CLKRST.peri_clk_ctrl03.reg_mipi_csi_dphy_clk_src_sel = 2;
break;
default:
abort();
}
}
/// 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_set_phy_clock_source(...) (void)__DECLARE_RCC_ATOMIC_ENV; mipi_csi_ll_set_phy_clock_source(__VA_ARGS__)
/**
* @brief Enable MIPI CSI PHY configuration clock
*
* @param group_id Group ID
* @param en true to enable, false to disable
*/
static inline void mipi_csi_ll_enable_phy_config_clock(int group_id, bool en)
{
(void)group_id;
HP_SYS_CLKRST.peri_clk_ctrl03.reg_mipi_csi_dphy_cfg_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_phy_config_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; mipi_csi_ll_enable_phy_config_clock(__VA_ARGS__)
/*---------------------------------------------------------------
CSI Host
---------------------------------------------------------------*/
/**
* @brief Enable the bus clock for MIPI CSI host
*
* @param group_id Group ID
* @param en true to enable, false to disable
*/
static inline void mipi_csi_ll_enable_host_bus_clock(int group_id, bool en)
{
(void)group_id;
HP_SYS_CLKRST.soc_clk_ctrl1.reg_csi_host_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_host_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; mipi_csi_ll_enable_host_bus_clock(__VA_ARGS__)
/**
* @brief Reset the MIPI CSI host CLK
*
* @param group_id Group ID
*/
static inline void mipi_csi_ll_reset_host_clock(int group_id)
{
(void)group_id;
HP_SYS_CLKRST.hp_rst_en0.reg_rst_en_csi_host = 1;
HP_SYS_CLKRST.hp_rst_en0.reg_rst_en_csi_host = 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_host_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; mipi_csi_ll_reset_host_clock(__VA_ARGS__)
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,76 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include "hal/misc.h"
#include "hal/assert.h"
#include "soc/mipi_csi_host_struct.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Control the internal interface (clock and pins) between the CSI Host and the d-PHY
*
* @param dev Pointer to the CSI Host controller register base address
* @param clock_level Level of the clock
* @param clear Whether to clear the pins of the PHY
*/
static inline void mipi_csi_phy_ll_write_clock(csi_host_dev_t *dev, uint32_t clock_level, bool clear)
{
dev->phy_test_ctrl0.val = clock_level << 1 | clear;
}
/**
* @brief Write the PHY register via test interface
*
* @param dev Pointer to the CSI Host controller register base address
* @param reg_addr Address of the PHY register
*/
static inline void mipi_csi_phy_ll_write_reg_addr(csi_host_dev_t *dev, uint8_t reg_addr)
{
dev->phy_test_ctrl1.val = (1 << 16) | (reg_addr & 0xFF);
}
/**
* @brief Write the PHY register value via test interface
*
* @param dev Pointer to the CSI Host controller register base address
* @param reg_val Value to write to the PHY register
*/
static inline void mipi_csi_phy_ll_write_reg_val(csi_host_dev_t *dev, uint8_t reg_val)
{
dev->phy_test_ctrl1.val = reg_val & 0xFF;
}
/**
* @brief Enable dphy shutdown input
*
* @param dev Pointer to the CSI Host controller register base address
* @param en True to enable, False to disable
*/
static inline void mipi_csi_phy_ll_enable_shutdown_input(csi_host_dev_t *dev, bool en)
{
dev->phy_shutdownz.phy_shutdownz = !en; // shutdown input, active low
}
/**
* @brief Enable dphy reset output
*
* @param dev Pointer to the CSI Host controller register base address
* @param en True to enable, False to disable
*/
static inline void mipi_csi_phy_ll_enable_reset_output(csi_host_dev_t *dev, bool en)
{
dev->dphy_rstz.dphy_rstz = !en; // phy reset output, active low
}
#ifdef __cplusplus
}
#endif
+59
View File
@@ -0,0 +1,59 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include "hal/mipi_csi_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief MIPI CSI SOC layer representation of the host controller
*/
typedef struct csi_host_dev_t *mipi_csi_host_soc_handle_t;
/**
* @brief MIPI CSI SOC layer representation of the bridge controller
*/
typedef struct csi_brg_dev_t *mipi_csi_bridge_soc_handle_t;
/**
* @brief MIPI CSI HAL driver context
*/
typedef struct {
mipi_csi_host_soc_handle_t host_dev;
mipi_csi_bridge_soc_handle_t bridge_dev;
} mipi_csi_hal_context_t;
/**
* @brief MIPI CSI HAL driver configuration
*/
typedef struct {
uint8_t lanes_num; ///< Lane num
uint32_t frame_width; ///< Frame width
uint32_t frame_height; ///< Frame height
uint32_t in_bpp; ///< In bits per pixel
uint32_t out_bpp; ///< Out bits per pixel
bool byte_swap_en; ///< Enable byte swap
int clk_freq_hz; ///< Clock frequency in hz
} mipi_csi_hal_config_t;
/**
* @brief MIPI CSI HAL layer initialization
*
* @param hal Pointer to the HAL driver context
* @param config Pointer to the HAL configuration
*/
void mipi_csi_hal_init(mipi_csi_hal_context_t *hal, const mipi_csi_hal_config_t *config);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,43 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_assert.h"
#include "soc/soc_caps.h"
#include "soc/clk_tree_defs.h"
#include "hal/color_types.h"
#ifdef __cplusplus
extern "C" {
#endif
#if SOC_MIPI_CSI_SUPPORTED
/**
* @brief MIPI CSI PHY clock source
*/
typedef soc_periph_mipi_csi_phy_clk_src_t mipi_csi_phy_clock_source_t;
#else
typedef int mipi_csi_phy_clock_source_t;
#endif // SOC_MIPI_CSI_SUPPORTED
/**
* @brief MIPI CSI Color Type
*/
typedef enum {
MIPI_CSI_COLOR_RAW8 = COLOR_TYPE_ID(COLOR_SPACE_RAW, COLOR_PIXEL_RAW8), ///< RAW8
MIPI_CSI_COLOR_RAW10 = COLOR_TYPE_ID(COLOR_SPACE_RAW, COLOR_PIXEL_RAW10), ///< RAW10
MIPI_CSI_COLOR_RAW12 = COLOR_TYPE_ID(COLOR_SPACE_RAW, COLOR_PIXEL_RAW12), ///< RAW12
MIPI_CSI_COLOR_RGB565 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB565), ///< RGB565
MIPI_CSI_COLOR_RGB666 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB666), ///< RGB666
MIPI_CSI_COLOR_RGB888 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB888), ///< RGB888
MIPI_CSI_COLOR_YUV420 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV420), ///< YUV420
MIPI_CSI_COLOR_YUV422 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV422), ///< YUV422
} mipi_csi_color_t;
#ifdef __cplusplus
}
#endif
+73
View File
@@ -0,0 +1,73 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "hal/log.h"
#include "hal/mipi_csi_hal.h"
#include "hal/mipi_csi_ll.h"
#include "soc/mipi_csi_periph.h"
void s_mipi_csi_hal_phy_write_register(mipi_csi_hal_context_t *hal, uint8_t reg_addr, uint8_t reg_val)
{
mipi_csi_phy_ll_write_clock(hal->host_dev, 0, false);
mipi_csi_phy_ll_write_reg_addr(hal->host_dev, reg_addr);
mipi_csi_phy_ll_write_clock(hal->host_dev, 1, false);
mipi_csi_phy_ll_write_clock(hal->host_dev, 0, false);
mipi_csi_phy_ll_write_reg_val(hal->host_dev, reg_val);
mipi_csi_phy_ll_write_clock(hal->host_dev, 1, false);
mipi_csi_phy_ll_write_clock(hal->host_dev, 0, false);
}
void mipi_csi_hal_init(mipi_csi_hal_context_t *hal, const mipi_csi_hal_config_t *config)
{
hal->bridge_dev = MIPI_CSI_BRG_LL_GET_HW(0);
hal->host_dev = MIPI_CSI_HOST_LL_GET_HW(0);
int csi_lane_rate = config->clk_freq_hz;
// reset PHY
mipi_csi_phy_ll_enable_shutdown_input(hal->host_dev, true);
mipi_csi_phy_ll_enable_reset_output(hal->host_dev, true);
mipi_csi_host_ll_enable_reset_output(hal->host_dev, true);
//reset reg addr to default value
mipi_csi_phy_ll_write_reg_addr(hal->host_dev, 0x0);
//reset reg val to default value
mipi_csi_phy_ll_write_clock(hal->host_dev, 0, 1);
mipi_csi_phy_ll_write_clock(hal->host_dev, 0, 0);
uint8_t hs_freq_sel = 0;
for (size_t i = 0; i < num_of_soc_mipi_csi_phy_pll_ranges; i++) {
if ((csi_lane_rate / 1000000) >= soc_mipi_csi_phy_pll_ranges[i].start_mbps &&
(csi_lane_rate / 1000000) <= soc_mipi_csi_phy_pll_ranges[i].end_mbps) {
hs_freq_sel = soc_mipi_csi_phy_pll_ranges[i].hs_freq_range_sel;
break;
}
}
s_mipi_csi_hal_phy_write_register(hal, 0x44, hs_freq_sel << 1);
HAL_LOGD("csi_hal", "CSI-DPHY lane_rate: %d Hz, hs_freq: 0x%x, lane_num: 0x%x", csi_lane_rate, hs_freq_sel, config->lanes_num);
mipi_csi_phy_ll_enable_shutdown_input(hal->host_dev, false);
mipi_csi_phy_ll_enable_reset_output(hal->host_dev, false);
mipi_csi_host_ll_enable_reset_output(hal->host_dev, false);
// Configure the host controller.
// Configure the number of active lanes.
mipi_csi_host_ll_set_active_lanes_num(hal->host_dev, config->lanes_num);
/**
* We ignore the virtual channel and virtual channel extension info, there is only one virtual channel.
* VC is by default there, VCX needs enable or disable.
* So we disable VCX here.
*/
mipi_csi_host_ll_enable_virtual_channel_extension(hal->host_dev, false);
// Set Scrambler.
mipi_csi_host_ll_enable_scrambling(hal->host_dev, false);
//CSI bridge
//TODO: IDF-9126, make csi bridge updates into `mipi_csi_share_hw_ctrl.c` and share with ISP
mipi_csi_brg_ll_set_intput_data_h_pixel_num(hal->bridge_dev, config->frame_height);
mipi_csi_brg_ll_set_intput_data_v_row_num(hal->bridge_dev, config->frame_width);
mipi_csi_brg_ll_set_flow_ctl_buf_afull_thrd(hal->bridge_dev, 960);
mipi_csi_brg_ll_set_data_type_min(hal->bridge_dev, 0x12);
mipi_csi_brg_ll_set_data_type_max(hal->bridge_dev, 0x2f);
mipi_csi_brg_ll_set_byte_endian(hal->bridge_dev, config->byte_swap_en);
}