From 44e856703c34f7112003a91ee0a41680f89cc62b Mon Sep 17 00:00:00 2001 From: morris Date: Fri, 1 Dec 2023 10:48:43 +0800 Subject: [PATCH] feat(dsi): add mipi dsi hal+ll layer driver --- components/hal/CMakeLists.txt | 4 + .../hal/esp32p4/include/hal/clk_gate_ll.h | 11 - components/hal/esp32p4/include/hal/lcd_ll.h | 7 +- .../hal/esp32p4/include/hal/mipi_dsi_brg_ll.h | 270 ++++++ .../esp32p4/include/hal/mipi_dsi_host_ll.h | 769 ++++++++++++++++++ .../hal/esp32p4/include/hal/mipi_dsi_ll.h | 175 ++++ .../hal/esp32p4/include/hal/mipi_dsi_phy_ll.h | 234 ++++++ components/hal/esp32s3/include/hal/lcd_ll.h | 7 +- components/hal/include/hal/color_types.h | 1 + components/hal/include/hal/lcd_types.h | 9 + components/hal/include/hal/mipi_dsi_hal.h | 158 ++++ components/hal/include/hal/mipi_dsi_types.h | 83 ++ components/hal/mipi_dsi_hal.c | 164 ++++ .../soc/esp32p4/include/soc/clk_tree_defs.h | 34 + .../include/soc/mipi_dsi_bridge_struct.h | 4 +- .../include/soc/mipi_dsi_host_struct.h | 4 +- components/soc/esp32p4/include/soc/soc_caps.h | 1 + 17 files changed, 1918 insertions(+), 17 deletions(-) create mode 100644 components/hal/esp32p4/include/hal/mipi_dsi_brg_ll.h create mode 100644 components/hal/esp32p4/include/hal/mipi_dsi_host_ll.h create mode 100644 components/hal/esp32p4/include/hal/mipi_dsi_ll.h create mode 100644 components/hal/esp32p4/include/hal/mipi_dsi_phy_ll.h create mode 100644 components/hal/include/hal/mipi_dsi_hal.h create mode 100644 components/hal/include/hal/mipi_dsi_types.h create mode 100644 components/hal/mipi_dsi_hal.c diff --git a/components/hal/CMakeLists.txt b/components/hal/CMakeLists.txt index d4a21d3612..6de6bcb5cf 100644 --- a/components/hal/CMakeLists.txt +++ b/components/hal/CMakeLists.txt @@ -163,6 +163,10 @@ if(NOT BOOTLOADER_BUILD) list(APPEND srcs "lcd_hal.c") endif() + if(CONFIG_SOC_MIPI_DSI_SUPPORTED) + list(APPEND srcs "mipi_dsi_hal.c") + endif() + if(CONFIG_SOC_ECC_SUPPORTED) list(APPEND srcs "ecc_hal.c") endif() diff --git a/components/hal/esp32p4/include/hal/clk_gate_ll.h b/components/hal/esp32p4/include/hal/clk_gate_ll.h index 80337edcbf..5349e06eec 100644 --- a/components/hal/esp32p4/include/hal/clk_gate_ll.h +++ b/components/hal/esp32p4/include/hal/clk_gate_ll.h @@ -23,11 +23,6 @@ static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph) switch (periph) { case PERIPH_EMAC_MODULE: return LP_CLKRST_HP_PAD_EMAC_TXRX_CLK_EN | LP_CLKRST_HP_PAD_EMAC_RX_CLK_EN | LP_CLKRST_HP_PAD_EMAC_TX_CLK_EN; - case PERIPH_MIPI_DSI_MODULE: - return HP_SYS_CLKRST_REG_MIPI_DSI_DPICLK_EN; - // IDF-6500 - case PERIPH_MIPI_CSI_MODULE: - return 0; case PERIPH_I3C_MODULE: return HP_SYS_CLKRST_REG_I3C_MST_CLK_EN; case PERIPH_SARADC_MODULE: @@ -63,10 +58,6 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en switch (periph) { case PERIPH_PVT_MODULE: return HP_SYS_CLKRST_REG_RST_EN_PVT_TOP; - case PERIPH_MIPI_DSI_MODULE: - return HP_SYS_CLKRST_REG_RST_EN_DSI_BRG; - case PERIPH_MIPI_CSI_MODULE: - return HP_SYS_CLKRST_REG_RST_EN_CSI_BRG; case PERIPH_ISP_MODULE: return HP_SYS_CLKRST_REG_RST_EN_ISP; case PERIPH_DMA2D_MODULE: @@ -124,8 +115,6 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en static inline uint32_t periph_ll_get_clk_en_reg(periph_module_t periph) { switch (periph) { - case PERIPH_MIPI_DSI_MODULE: - return HP_SYS_CLKRST_PERI_CLK_CTRL03_REG; case PERIPH_I3C_MODULE: case PERIPH_SARADC_MODULE: return HP_SYS_CLKRST_PERI_CLK_CTRL22_REG; diff --git a/components/hal/esp32p4/include/hal/lcd_ll.h b/components/hal/esp32p4/include/hal/lcd_ll.h index 67256aa4a0..58bfeb34ec 100644 --- a/components/hal/esp32p4/include/hal/lcd_ll.h +++ b/components/hal/esp32p4/include/hal/lcd_ll.h @@ -42,9 +42,10 @@ typedef enum { } lcd_ll_swizzle_mode_t; /** - * @brief Enable or disable the bus clock for the LCD module + * @brief Enable the bus clock for LCD module * - * @param set_bit True to set bit, false to clear bit + * @param group_id Group ID + * @param enable true to enable, false to disable */ static inline void lcd_ll_enable_bus_clock(int group_id, bool enable) { @@ -58,6 +59,8 @@ static inline void lcd_ll_enable_bus_clock(int group_id, bool enable) /** * @brief Reset the LCD module + * + * @param group_id Group ID */ static inline void lcd_ll_reset_register(int group_id) { diff --git a/components/hal/esp32p4/include/hal/mipi_dsi_brg_ll.h b/components/hal/esp32p4/include/hal/mipi_dsi_brg_ll.h new file mode 100644 index 0000000000..faf84355d7 --- /dev/null +++ b/components/hal/esp32p4/include/hal/mipi_dsi_brg_ll.h @@ -0,0 +1,270 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "hal/assert.h" +#include "soc/mipi_dsi_bridge_struct.h" +#include "hal/mipi_dsi_types.h" +#include "hal/lcd_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + MIPI_DSI_LL_FLOW_CONTROLLER_DMA, ///< DMA controller as the flow controller + MIPI_DSI_LL_FLOW_CONTROLLER_BRIDGE, ///< DSI bridge is the flow controller +} mipi_dsi_ll_flow_controller_t; + +/** + * @brief Enable the DSI bridge + * + * @param dev Pointer to the DSI bridge controller register base address + * @param en True to enable, false to disable + */ +static inline void mipi_dsi_brg_ll_enable(dsi_brg_dev_t *dev, bool en) +{ + dev->en.dsi_en = en; +} + +/** + * @brief Set the number of 64-bit words in one dma burst transfer + * + * @note valid only when dsi_bridge is the flow controller + * + * @param dev Pointer to the DSI bridge controller register base address + * @param burst_len Number of 64-bit words in one dma burst transfer + */ +static inline void mipi_dsi_brg_ll_set_burst_len(dsi_brg_dev_t *dev, uint32_t burst_len) +{ + dev->dma_req_cfg.dma_burst_len = burst_len; +} + +/** + * @brief Set the number of pixel bits in total + * + * @note valid only when dsi_bridge is the flow controller + * + * @param dev Pointer to the DSI bridge controller register base address + * @param num_pixel_bits Number of pixel bits, must be aligned to 64 + */ +static inline void mipi_dsi_brg_ll_set_num_pixel_bits(dsi_brg_dev_t *dev, uint32_t num_pixel_bits) +{ + dev->raw_num_cfg.raw_num_total = num_pixel_bits / 64; + // reload the value into internal counter + dev->raw_num_cfg.raw_num_total_set = 1; +} + +/** + * @brief Set the threshold whether the dsi_bridge FIFO can receive one more 64-bit + * + * @note valid only when dsi_bridge is the flow controller + * + * @param dev Pointer to the DSI bridge controller register base address + * @param threshold Threshold value + */ +static inline void mipi_dsi_brg_ll_credit_set_threshold(dsi_brg_dev_t *dev, uint32_t threshold) +{ + dev->raw_buf_credit_ctl.credit_thrd = threshold; +} + +/** + * @brief Set the threshold whether the dsi_bridge FIFO can receive one more DMA burst + * + * @note valid only when dsi_bridge is the flow controller + * + * @param dev Pointer to the DSI bridge controller register base address + * @param threshold Threshold value + */ +static inline void mipi_dsi_brg_ll_credit_set_burst_threshold(dsi_brg_dev_t *dev, uint32_t threshold) +{ + dev->raw_buf_credit_ctl.credit_burst_thrd = threshold; +} + +/** + * @brief Reset the credit counter of the DSI bridge + * + * @note valid only when dsi_bridge is the flow controller + * + * @param dev Pointer to the DSI bridge controller register base address + */ +static inline void mipi_dsi_brg_ll_credit_reset(dsi_brg_dev_t *dev) +{ + dev->raw_buf_credit_ctl.credit_reset = 1; +} + +/** + * @brief Set the color coding for the bridge controller + * + * @param dev Pointer to the DSI bridge controller register base address + * @param pixel_format Color coding + * @param sub_config Sub configuration + */ +static inline void mipi_dsi_brg_ll_set_pixel_format(dsi_brg_dev_t *dev, lcd_color_rgb_pixel_format_t pixel_format, uint32_t sub_config) +{ + switch (pixel_format) { + case LCD_COLOR_PIXEL_FORMAT_RGB565: + dev->pixel_type.raw_type = 2; + break; + case LCD_COLOR_PIXEL_FORMAT_RGB666: + dev->pixel_type.raw_type = 1; + break; + case LCD_COLOR_PIXEL_FORMAT_RGB888: + dev->pixel_type.raw_type = 0; + break; + default: + abort(); + } + dev->pixel_type.dpi_config = sub_config; +} + +/** + * @brief Set the color space for input color data + * + * @param dev Pointer to the DSI bridge controller register base address + * @param color_space Color space type + */ +static inline void mipi_dsi_brg_ll_set_input_color_space(dsi_brg_dev_t *dev, lcd_color_space_t color_space) +{ + switch (color_space) { + case LCD_COLOR_SPACE_RGB: + dev->pixel_type.data_in_type = 0; + break; + case LCD_COLOR_SPACE_YUV: + dev->pixel_type.data_in_type = 1; + break; + default: + abort(); + } +} + +/** + * @brief Set the vertical timing parameters for the bridge controller + * + * @param dev Pointer to the DSI bridge controller register base address + * @param vsw Vertical sync width + * @param vbp Vertical back porch + * @param active_height Active height + * @param vfp Vertical front porch + */ +static inline void mipi_dsi_brg_ll_set_vertical_timing(dsi_brg_dev_t *dev, uint32_t vsw, uint32_t vbp, uint32_t active_height, uint32_t vfp) +{ + dev->dpi_v_cfg0.vdisp = active_height; + dev->dpi_v_cfg0.vtotal = vsw + vbp + active_height + vfp; + dev->dpi_v_cfg1.vsync = vsw; + dev->dpi_v_cfg1.vbank = vbp; +} + +/** + * @brief Set the horizontal timing parameters for the bridge controller + * + * @param dev Pointer to the DSI bridge controller register base address + * @param hsw Horizontal sync width + * @param hbp Horizontal back porch + * @param active_width Active width + * @param hfp Horizontal front porch + */ +static inline void mipi_dsi_brg_ll_set_horizontal_timing(dsi_brg_dev_t *dev, uint32_t hsw, uint32_t hbp, uint32_t active_width, uint32_t hfp) +{ + dev->dpi_h_cfg0.hdisp = active_width; + dev->dpi_h_cfg0.htotal = hsw + hbp + active_width + hfp; + dev->dpi_h_cfg1.hsync = hsw; + dev->dpi_h_cfg1.hbank = hbp; +} + +/** + * @brief Set the under run discard count for the bridge controller + * + * @param dev Pointer to the DSI bridge controller register base address + * @param under_run_discard_count Under run discard count + */ +static inline void mipi_dsi_brg_ll_set_underrun_discard_count(dsi_brg_dev_t *dev, uint32_t under_run_discard_count) +{ + dev->dpi_misc_config.fifo_underrun_discard_vcnt = under_run_discard_count; +} + +/** + * @brief Enable the DPI output + * + * @param dev Pointer to the DSI bridge controller register base address + * @param en True to enable, false to disable + */ +static inline void mipi_dsi_brg_ll_enable_dpi_output(dsi_brg_dev_t *dev, bool en) +{ + dev->dpi_misc_config.dpi_en = en; +} + +/** + * @brief Update the configuration of DSI bridge + * + * @param dev Pointer to the DSI bridge controller register base address + */ +static inline void mipi_dsi_brg_ll_update_config(dsi_brg_dev_t *dev) +{ + dev->dpi_config_update.dpi_config_update = 1; +} + +/** + * @brief Enable the refclk and cfg_clk of dsi host + * + * @param dev Pointer to the DSI bridge controller register base address + * @param en True to enable, false to disable + */ +static inline void mipi_dsi_brg_ll_enable_ref_clock(dsi_brg_dev_t *dev, bool en) +{ + dev->host_ctrl.dsi_cfg_ref_clk_en = en; +} + +/** + * @brief Set the flow controller of DMA transfer + * + * @param dev Pointer to the DSI bridge controller register base address + * @param controller Flow controller + */ +static inline void mipi_dsi_brg_ll_set_flow_controller(dsi_brg_dev_t* dev, mipi_dsi_ll_flow_controller_t controller) +{ + dev->dma_flow_ctrl.dsi_dma_flow_controller = controller; +} + +/** + * @brief Set the number of blocks when multi-block transfer is enabled + * + * @note only valid when DMAC is the flow controller + * + * @param dev Pointer to the DSI bridge controller register base address + * @param number Number of blocks + */ +static inline void mipi_dsi_brg_ll_set_multi_block_number(dsi_brg_dev_t* dev, uint32_t number) +{ + dev->dma_flow_ctrl.dma_flow_multiblk_num = number; +} + +/** + * @brief Set the YUV-RGB conversion standard + * + * @param dev Pointer to the DSI bridge controller register base address + * @param std YUV-RGB conversion standard + */ +static inline void mipi_dsi_brg_ll_set_yuv_convert_std(dsi_brg_dev_t* dev, lcd_yuv_conv_std_t std) +{ + switch (std) { + case LCD_YUV_CONV_STD_BT601: + dev->yuv_cfg.protocal = 0; + break; + case LCD_YUV_CONV_STD_BT709: + dev->yuv_cfg.protocal = 1; + break; + default: + abort(); + } +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32p4/include/hal/mipi_dsi_host_ll.h b/components/hal/esp32p4/include/hal/mipi_dsi_host_ll.h new file mode 100644 index 0000000000..a76bbb3134 --- /dev/null +++ b/components/hal/esp32p4/include/hal/mipi_dsi_host_ll.h @@ -0,0 +1,769 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "hal/assert.h" +#include "hal/misc.h" +#include "soc/mipi_dsi_host_struct.h" +#include "hal/mipi_dsi_types.h" +#include "hal/lcd_types.h" + +#define MIPI_DSI_LL_MAX_DPI_CLK_DIV 256 + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief MIPI DSI transmission speed mode + */ +typedef enum { + MIPI_DSI_LL_TRANS_SPEED_HS, /*!< High speed transmission */ + MIPI_DSI_LL_TRANS_SPEED_LP, /*!< Low power transmission */ +} mipi_dsi_ll_trans_speed_mode_t; + +/** + * @brief Color coding type (depth and pixel configuration) + */ +typedef enum { + MIPI_DSI_LL_COLOR_CODE_16BIT_CONFIG1 = 0, // 16-bit configuration 1 + MIPI_DSI_LL_COLOR_CODE_16BIT_CONFIG2 = 1, // 16-bit configuration 2 + MIPI_DSI_LL_COLOR_CODE_16BIT_CONFIG3 = 2, // 16-bit configuration 3 + MIPI_DSI_LL_COLOR_CODE_18BIT_CONFIG1 = 3, // 18-bit configuration 1 + MIPI_DSI_LL_COLOR_CODE_18BIT_CONFIG2 = 4, // 18-bit configuration 2 + MIPI_DSI_LL_COLOR_CODE_24BIT = 5, // 24-bit +} mipi_dsi_ll_color_coding_t; + +/** + * @brief The kind of test pattern that can be generated by the DSI Host controller + */ +typedef enum { + MIPI_DSI_LL_PATTERN_BAR_VERTICAL, // Vertical bar pattern + MIPI_DSI_LL_PATTERN_BAR_HORIZONTAL, // Horizontal bar pattern + MIPI_DSI_LL_PATTERN_BER_VERTICAL, // Vertical ber pattern +} mipi_dsi_ll_pattern_type_t; + +/** + * @brief MIPI DSI Video mode burst type + */ +typedef enum { + MIPI_DSI_LL_VIDEO_NON_BURST_WITH_SYNC_PULSES, // Non-burst mode with sync pulses + MIPI_DSI_LL_VIDEO_NON_BURST_WITH_SYNC_EVENTS, // Non-burst mode with sync events + MIPI_DSI_LL_VIDEO_BURST_WITH_SYNC_PULSES, // Burst mode with sync pulses +} mipi_dsi_ll_video_burst_type_t; + +/** + * @brief Set the DSI Host controller power state + * + * @param dev Pointer to the DSI Host controller register base address + * @param True to turn on, False to turn off + */ +static inline void mipi_dsi_host_ll_power_on_off(dsi_host_dev_t *dev, bool on) +{ + dev->pwr_up.shutdownz = on; +} + +/** + * @brief Set the division factor for the Time Out clock + * + * @note The Time Out clock is the clock used as the timing unit in the configuration of HS->LP and LP->HS transition error. + * @note Time out clock source is lane byte clock + * + * @param dev Pointer to the DSI Host controller register base address + * @param div Division factor for the Time Out clock + */ +static inline void mipi_dsi_host_ll_set_timeout_clock_division(dsi_host_dev_t *dev, uint32_t div) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->clkmgr_cfg, to_clk_division, div - 1); +} + +/** + * @brief Set the division factor for the Escape clock + * + * @note TX Escape clock source is lane byte clock + * + * @param dev Pointer to the DSI Host controller register base address + * @param div Division factor for the Escape clock + */ +static inline void mipi_dsi_host_ll_set_escape_clock_division(dsi_host_dev_t *dev, uint32_t div) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->clkmgr_cfg, tx_esc_clk_division, div - 1); +} + +/** + * @brief Set the timeout counts for various operations + * + * @param dev Pointer to the DSI Host controller register base address + * @param hs_tx Timeout count for HS transmission, measured in TO_CLK_DIVISION cycles + * @param lp_rx Timeout count for LP reception, measured in TO_CLK_DIVISION cycles + * @param hs_rd Timeout count for HS read, measured in lane byte clock cycles + * @param lp_rd Timeout count for LP read, measured in lane byte clock cycles + * @param hs_wr Timeout count for HS write, measured in lane byte clock cycles + * @param lp_wr Timeout count for LP write, measured in lane byte clock cycles + * @param bta Timeout count for BTA, measured in lane byte clock cycles + */ +static inline void mipi_dsi_host_ll_set_timeout_count(dsi_host_dev_t *dev, uint32_t hs_tx, uint32_t lp_rx, uint32_t hs_rd, uint32_t lp_rd, uint32_t hs_wr, uint32_t lp_wr, uint32_t bta) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->to_cnt_cfg, hstx_to_cnt, hs_tx); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->to_cnt_cfg, lprx_to_cnt, lp_rx); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->hs_rd_to_cnt, hs_rd_to_cnt, hs_rd); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->lp_rd_to_cnt, lp_rd_to_cnt, lp_rd); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->hs_wr_to_cnt, hs_wr_to_cnt, hs_wr); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->lp_wr_to_cnt, lp_wr_to_cnt, lp_wr); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->bta_to_cnt, bta_to_cnt, bta); +} + +/** + * @brief Enable the automatic mechanism to stop providing clock in the clock lane when time allows + * + * @param dev Pointer to the DSI Host controller register base address + * @param enable True to enable, False to disable + */ +static inline void mipi_dsi_host_ll_enable_non_continuous_clock(dsi_host_dev_t *dev, bool enable) +{ + dev->lpclk_ctrl.auto_clklane_ctrl = enable; +} + +/** + * @brief Request the PHY module to start transmission of high speed clock + * + * @param dev Pointer to the DSI Host controller register base address + * @param enable True to enable, False to disable + */ +static inline void mipi_dsi_host_ll_enable_hs_clock(dsi_host_dev_t *dev, bool enable) +{ + dev->lpclk_ctrl.phy_txrequestclkhs = enable; +} + +////////////////////////////////////////////DPI Interface/////////////////////////////// + +/** + * @brief Set DPI virtual channel ID that will be indexed to the video mode packets + * + * @param dev Pointer to the DSI Host controller register base address + * @param vcid Virtual channel ID + */ +static inline void mipi_dsi_host_ll_dpi_set_vcid(dsi_host_dev_t *dev, uint32_t vcid) +{ + dev->dpi_vcid.dpi_vcid = vcid; +} + +/** + * @brief Set DPI video color coding + * + * @param dev Pointer to the DSI Host controller register base address + * @param color_coding Color coding value + * @param sub_config Sub configuration value + */ +static inline void mipi_dsi_host_ll_dpi_set_color_coding(dsi_host_dev_t *dev, lcd_color_rgb_pixel_format_t color_coding, uint32_t sub_config) +{ + switch (color_coding) { + case LCD_COLOR_PIXEL_FORMAT_RGB565: + dev->dpi_color_coding.dpi_color_coding = MIPI_DSI_LL_COLOR_CODE_16BIT_CONFIG1 + sub_config; + break; + case LCD_COLOR_PIXEL_FORMAT_RGB666: + dev->dpi_color_coding.dpi_color_coding = MIPI_DSI_LL_COLOR_CODE_18BIT_CONFIG1 + sub_config; + break; + case LCD_COLOR_PIXEL_FORMAT_RGB888: + dev->dpi_color_coding.dpi_color_coding = MIPI_DSI_LL_COLOR_CODE_24BIT; + break; + default: + HAL_ASSERT(false); + break; + } +} + +/** + * @brief Enable DPI loosely packetization video (used only when color depth = 18) + * + * @param dev Pointer to the DSI Host controller register base address + * @param en True to enable, False to disable + */ +static inline void mipi_dsi_host_ll_dpi_enable_loosely18_packet(dsi_host_dev_t *dev, bool en) +{ + dev->dpi_color_coding.loosely18_en = en; +} + +/** + * @brief Set DPI timing signal polarity + * + * @param dev Pointer to the DSI Host controller register base address + * @param hsync_active_low If the HSYNC signal is active low + * @param vsync_active_low If the VSYNC signal is active low + * @param de_active_low If the DE signal is active low + * @param shut_down_active_low If the SHUTDOWNZ signal is active low + * @param color_mode_active_low If the COLORM active low + */ +static inline void mipi_dsi_host_ll_dpi_set_timing_polarity(dsi_host_dev_t *dev, bool hsync_active_low, bool vsync_active_low, bool de_active_low, bool shut_down_active_low, bool color_mode_active_low) +{ + dev->dpi_cfg_pol.hsync_active_low = hsync_active_low; + dev->dpi_cfg_pol.vsync_active_low = vsync_active_low; + dev->dpi_cfg_pol.dataen_active_low = de_active_low; + dev->dpi_cfg_pol.shutd_active_low = shut_down_active_low; + dev->dpi_cfg_pol.colorm_active_low = color_mode_active_low; +} + +/** + * @brief Enable frame BTA acknowledgement + * + * @param dev Pointer to the DSI Host controller register base address + * @param enable True to enable, False to disable + */ +static inline void mipi_dsi_host_ll_dpi_enable_frame_ack(dsi_host_dev_t *dev, bool en) +{ + dev->vid_mode_cfg.frame_bta_ack_en = en; +} + +/** + * @brief Enable return to low power mode inside horizontal front/back porch periods when timing allows + * + * @param dev Pointer to the DSI Host controller register base address + * @param en_hbp True to enable, False to disable + * @param en_hfp True to enable, False to disable + */ +static inline void mipi_dsi_host_ll_dpi_enable_lp_horizontal_timing(dsi_host_dev_t *dev, bool en_hbp, bool en_hfp) +{ + dev->vid_mode_cfg.lp_hbp_en = en_hbp; + dev->vid_mode_cfg.lp_hfp_en = en_hfp; +} + +/** + * @brief Enable return to low power mode inside vertical timing periods (e.g. vbp) when timing allows + * + * @param dev Pointer to the DSI Host controller register base address + * @param en_vsync True to enable, False to disable + * @param en_vbp True to enable, False to disable + * @param en_vfp True to enable, False to disable + * @param en_vact True to enable, False to disable + */ +static inline void mipi_dsi_host_ll_dpi_enable_lp_vertical_timing(dsi_host_dev_t *dev, bool en_vsync, bool en_vbp, bool en_vfp, bool en_vact) +{ + dev->vid_mode_cfg.lp_vsa_en = en_vsync; + dev->vid_mode_cfg.lp_vbp_en = en_vbp; + dev->vid_mode_cfg.lp_vfp_en = en_vfp; + dev->vid_mode_cfg.lp_vact_en = en_vact; +} + +/** + * @brief Enable the command transmission in LP mode + * + * @param dev Pointer to the DSI Host controller register base address + * @param enable True to enable, False to disable + */ +static inline void mipi_dsi_host_ll_dpi_enable_lp_command(dsi_host_dev_t *dev, bool enable) +{ + dev->vid_mode_cfg.lp_cmd_en = enable; +} + +/** + * @brief Set MIPI DSI video burst type + * + * @param dev Pointer to the DSI Host controller register base address + * @param mode Video mode type + */ +static inline void mipi_dsi_host_ll_dpi_set_video_burst_type(dsi_host_dev_t *dev, mipi_dsi_ll_video_burst_type_t type) +{ + dev->vid_mode_cfg.vid_mode_type = type; +} + +/** + * @brief Set the kind of the pattern to be generated by the DSI Host controller + * + * @param dev Pointer to the DSI Host controller register base address + * @param type Pattern type + */ +static inline void mipi_dsi_host_ll_dpi_set_pattern_type(dsi_host_dev_t *dev, mipi_dsi_ll_pattern_type_t type) +{ + switch (type) { + case MIPI_DSI_LL_PATTERN_BAR_HORIZONTAL: + dev->vid_mode_cfg.vpg_mode = 0; + dev->vid_mode_cfg.vpg_orientation = 1; + break; + case MIPI_DSI_LL_PATTERN_BAR_VERTICAL: + dev->vid_mode_cfg.vpg_mode = 0; + dev->vid_mode_cfg.vpg_orientation = 0; + break; + case MIPI_DSI_LL_PATTERN_BER_VERTICAL: + dev->vid_mode_cfg.vpg_mode = 1; + dev->vid_mode_cfg.vpg_orientation = 0; + break; + default: + HAL_ASSERT(false); + break; + } +} + +/** + * @brief Enable pattern generation + * + * @param dev Pointer to the DSI Host controller register base address + * @param enable True to enable, False to disable + */ +static inline void mipi_dsi_host_ll_dpi_enable_pattern(dsi_host_dev_t *dev, bool enable) +{ + dev->vid_mode_cfg.vpg_en = enable; +} + +/** + * @brief Enable / Disable DPI video mode + * + * @note Commands can still be sent by the generic interface while in video mode + * + * @param dev Pointer to the DSI Host controller register base address + * @param en True to enable, False to disable + */ +static inline void mipi_dsi_host_ll_dpi_enable_video_mode(dsi_host_dev_t *dev, bool en) +{ + dev->mode_cfg.cmd_video_mode = !en; +} + +/** + * @brief Set the number of bytes inside a null packet + * + * @param dev Pointer to the DSI Host controller register base address + * @param packet_size Number of bytes inside a null packet, 0 means to disable the null packet + */ +static inline void mipi_dsi_host_ll_dpi_set_null_packet_size(dsi_host_dev_t *dev, uint32_t packet_size) +{ + dev->vid_null_size.vid_null_size = packet_size; +} + +/** + * @brief Se the number of chunks to be transmitted during a Line period + * + * @note A trunk is pair of video packet and null packet + * @note The data in each chunk is set in `mipi_dsi_host_ll_dpi_set_video_packet_pixel_num` + * + * @param dev Pointer to the DSI Host controller register base address + * @param trunk_num Number of chunks. 0 - video line is transmitted in a single packet + * 1 - video line is transmitted in a single packet, followed by a null packet + * Others - Multiple chunks are used to transmit each video line + */ +static inline void mipi_dsi_host_ll_dpi_set_trunks_num(dsi_host_dev_t *dev, uint32_t trunks_num) +{ + dev->vid_num_chunks.vid_num_chunks = trunks_num; +} + +/** + * @brief Set the number of pixels in a signal video packet + * + * @note For 18-bit not loosely packed data types, the size must be a multiple of 4 + * @note For YUV data types, the size must be a multiple of 2 + * + * @param dev Pointer to the DSI Host controller register base address + * @param packet_pixels Number of pixels in a signal video packet + */ +static inline void mipi_dsi_host_ll_dpi_set_video_packet_pixel_num(dsi_host_dev_t *dev, uint32_t packet_pixels) +{ + dev->vid_pkt_size.vid_pkt_size = packet_pixels; +} + +/** + * @brief Set vertical timing parameters of video mode + * + * @param dev Pointer to the DSI Host controller register base address + * @param vsw Vertical Synchronization Width, in lines + * @param vbp Vertical Back Porch period, in lines + * @param active_height Vertical active height, in lines + * @param vfp Vertical Front Porch period, in lines + */ +static inline void mipi_dsi_host_ll_dpi_set_vertical_timing(dsi_host_dev_t *dev, uint32_t vsw, uint32_t vbp, uint32_t active_height, uint32_t vfp) +{ + dev->vid_vsa_lines.vsa_lines = vsw; + dev->vid_vbp_lines.vbp_lines = vbp; + dev->vid_vactive_lines.v_active_lines = active_height; + dev->vid_vfp_lines.vfp_lines = vfp; +} + +/** + * @brief Set horizontal timing parameters of video mode + * + * @param dev Pointer to the DSI Host controller register base address + * @param hsw Horizontal Synchronization Width, in lane byte clock cycles + * @param hbp Horizontal Back Porch period, in lane byte clock cycles + * @param active_width Horizontal active width, in lane byte clock cycles + * @param hfp Horizontal Front Porch period, in lane byte clock cycles + */ +static inline void mipi_dsi_host_ll_dpi_set_horizontal_timing(dsi_host_dev_t *dev, uint32_t hsw, uint32_t hbp, uint32_t active_width, uint32_t hfp) +{ + dev->vid_hsa_time.vid_hsa_time = hsw; + dev->vid_hbp_time.vid_hbp_time = hbp; + // the vid_hline_time here is the overall time for each video line + dev->vid_hline_time.vid_hline_time = active_width + hsw + hbp + hfp; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Enable the tearing effect acknowledge + * + * @param dev Pointer to the DSI Host controller register base address + * @param enable True to enable, False to disable + */ +static inline void mipi_dsi_host_ll_enable_te_ack(dsi_host_dev_t *dev, bool en) +{ + dev->cmd_mode_cfg.tear_fx_en = en; +} + +/** + * @brief Enable the acknowledge request after each packet transmission + * + * @param dev Pointer to the DSI Host controller register base address + * @param enable True to enable, False to disable + */ +static inline void mipi_dsi_host_ll_enable_cmd_ack(dsi_host_dev_t *dev, bool enable) +{ + dev->cmd_mode_cfg.ack_rqst_en = enable; +} + +/** + * @brief Set the speed mode when transmitting DCS short write commands + * + * @param dev Pointer to the DSI Host controller register base address + * @param num_of_params Number of parameters in the DCS command + * @param speed Speed mode + */ +static inline void mipi_dsi_host_ll_set_dcs_short_wr_speed_mode(dsi_host_dev_t *dev, uint8_t num_of_params, mipi_dsi_ll_trans_speed_mode_t speed) +{ + switch (num_of_params) { + case 0: // DCS short write command with no parameter + dev->cmd_mode_cfg.dcs_sw_0p_tx = speed; + break; + case 1: // DCS short write command with one parameter + dev->cmd_mode_cfg.dcs_sw_1p_tx = speed; + break; + default: + HAL_ASSERT(false); + break; + } +} + +/** + * @brief Set the speed mode when transmitting DCS long write commands + * + * @param dev Pointer to the DSI Host controller register base address + * @param speed Speed mode + */ +static inline void mipi_dsi_host_ll_set_dcs_long_wr_speed_mode(dsi_host_dev_t *dev, mipi_dsi_ll_trans_speed_mode_t speed) +{ + dev->cmd_mode_cfg.dcs_lw_tx = speed; +} + +/** + * @brief Set the speed mode when transmitting DCS read commands + * + * @param dev Pointer to the DSI Host controller register base address + * @param num_of_params Number of parameters in the DCS command + * @param speed Speed mode + */ +static inline void mipi_dsi_host_ll_set_dcs_short_rd_speed_mode(dsi_host_dev_t *dev, uint8_t num_of_params, mipi_dsi_ll_trans_speed_mode_t speed) +{ + switch (num_of_params) { + case 0: // DCS short read with zero parameter + dev->cmd_mode_cfg.dcs_sr_0p_tx = speed; + break; + default: + HAL_ASSERT(false); + } +} + +/** + * @brief Set the speed mode when transmitting generic short write commands + * + * @param dev Pointer to the DSI Host controller register base address + * @param num_of_params Number of parameters in the generic command + * @param speed Speed mode + */ +static inline void mipi_dsi_host_ll_set_gen_short_wr_speed_mode(dsi_host_dev_t *dev, uint8_t num_of_params, mipi_dsi_ll_trans_speed_mode_t speed) +{ + switch (num_of_params) { + case 0: // Generic short write command with no parameter + dev->cmd_mode_cfg.gen_sw_0p_tx = speed; + break; + case 1: // Generic short write command with one parameter + dev->cmd_mode_cfg.gen_sw_1p_tx = speed; + break; + case 2: // Generic short write command with two parameters + dev->cmd_mode_cfg.gen_sw_2p_tx = speed; + break; + default: + HAL_ASSERT(false); + break; + } +} + +/** + * @brief Set the speed mode when transmitting generic long write commands + * + * @param dev Pointer to the DSI Host controller register base address + * @param speed Speed mode + */ +static inline void mipi_dsi_host_ll_set_gen_long_wr_speed_mode(dsi_host_dev_t *dev, mipi_dsi_ll_trans_speed_mode_t speed) +{ + dev->cmd_mode_cfg.gen_lw_tx = speed; +} + +/** + * @brief Set the speed mode when transmitting generic short read commands + * + * @param dev Pointer to the DSI Host controller register base address + * @param num_of_params Number of parameters in the generic command + * @param speed Speed mode + */ +static inline void mipi_dsi_host_ll_set_gen_short_rd_speed_mode(dsi_host_dev_t *dev, uint8_t num_of_params, mipi_dsi_ll_trans_speed_mode_t speed) +{ + switch (num_of_params) { + case 0: // Generic short read command with zero parameter + dev->cmd_mode_cfg.gen_sr_0p_tx = speed; + break; + case 1: // Generic short read command with one parameter + dev->cmd_mode_cfg.gen_sr_1p_tx = speed; + break; + case 2: // Generic short read command with two parameters + dev->cmd_mode_cfg.gen_sr_2p_tx = speed; + break; + default: + HAL_ASSERT(false); + } +} + +/** + * @brief Set the speed mode for the "Maximum Return Packet Size" command + * + * @param dev Pointer to the DSI Host controller register base address + * @param speed Speed mode + */ +static inline void mipi_dsi_host_ll_set_mrps_speed_mode(dsi_host_dev_t *dev, mipi_dsi_ll_trans_speed_mode_t speed) +{ + dev->cmd_mode_cfg.max_rd_pkt_size = speed; +} + +/** + * @brief Enable receive EoT packet + * + * @param dev Pointer to the DSI Host controller register base address + * @param enable True to enable, False to disable + */ +static inline void mipi_dsi_host_ll_enable_rx_eotp(dsi_host_dev_t *dev, bool en) +{ + dev->pckhdl_cfg.eotp_rx_en = en; +} + +/** + * @brief Enable transmit EoT packet + * + * @param dev Pointer to the DSI Host controller register base address + * @param enable_in_hs_mode True to enable, False to disable + * @param enable_in_lp_mode True to enable, False to disable + */ +static inline void mipi_dsi_host_ll_enable_tx_eotp(dsi_host_dev_t *dev, bool enable_in_hs_mode, bool enable_in_lp_mode) +{ + dev->pckhdl_cfg.eotp_tx_en = enable_in_hs_mode; + dev->pckhdl_cfg.eotp_tx_lp_en = enable_in_lp_mode; +} + +/** + * @brief Enable the CRC check for the received packets + * + * @param dev Pointer to the DSI Host controller register base address + * @param enable True to enable, False to disable + */ +static inline void mipi_dsi_host_ll_enable_rx_crc(dsi_host_dev_t *dev, bool enable) +{ + dev->pckhdl_cfg.crc_rx_en = enable; +} + +/** + * @brief Enable the ECC check for the received packets + * + * @param dev Pointer to the DSI Host controller register base address + * @param enable True to enable, False to disable + */ +static inline void mipi_dsi_host_ll_enable_rx_ecc(dsi_host_dev_t *dev, bool enable) +{ + dev->pckhdl_cfg.ecc_rx_en = enable; +} + +/** + * @brief Enable the Bus Turn Around (BTA) request + * + * @param dev Pointer to the DSI Host controller register base address + * @param enable True to enable, False to disable + */ +static inline void mipi_dsi_host_ll_enable_bta(dsi_host_dev_t *dev, bool enable) +{ + dev->pckhdl_cfg.bta_en = enable; +} + +/** + * @brief Set the timing for low power commands sent while in video mode + * + * @param dev Pointer to the DSI Host controller register base address + * @param in_vact largest packet size during VACT period, in bytes + * @param out_vact largest packet size during non-VACT period (VSA,VBP,VFP), in bytes + */ +static inline void mipi_dsi_host_ll_set_lp_largest_cmd_packet_size(dsi_host_dev_t *dev, uint32_t in_vact, uint32_t out_vact) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->dpi_lp_cmd_tim, invact_lpcmd_time, in_vact); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->dpi_lp_cmd_tim, outvact_lpcmd_time, out_vact); +} + +////////////////////////////////////////////Generic Interface/////////////////////////////// + +/** + * @brief Set the header for new packets sent using the Generic interface + * + * @param dev Pointer to the DSI Host controller register base address + * @param dt Data type + * @param vc_id Virtual channel ID + * @param ms_byte most significant byte of the word count for long packets or data1 for short packets + * @param ls_byte least significant byte of the word count for long packets or data0 for short packets + */ +static inline void mipi_dsi_host_ll_gen_set_packet_header(dsi_host_dev_t *dev, uint8_t vc_id, + mipi_dsi_data_type_t dt, uint8_t ms_byte, uint8_t ls_byte) +{ + dev->gen_hdr.val = (ms_byte << 16) | (ls_byte << 8) | ((vc_id << 6) | dt); +} + +/** + * @brief Set the payload for packets sent using the generic interface + * + * @param dev Pointer to the DSI Host controller register base address + * @param payload Payload data + */ +static inline void mipi_dsi_host_ll_gen_write_payload_fifo(dsi_host_dev_t *dev, uint32_t payload) +{ + dev->gen_pld_data.val = payload; +} + +/** + * @brief When using the generic interface, return the contents of READ responses + * + * @param dev Pointer to the DSI Host controller register base address + * @return payload data + */ +static inline uint32_t mipi_dsi_host_ll_gen_read_payload_fifo(dsi_host_dev_t *dev) +{ + return dev->gen_pld_data.val; +} + +/** + * @brief Is the read command of the generic interface busy? + * + * @param dev Pointer to the DSI Host controller register base address + * @return True if busy, False if not + */ +static inline bool mipi_dsi_host_ll_gen_is_read_cmd_busy(dsi_host_dev_t *dev) +{ + return dev->cmd_pkt_status.gen_rd_cmd_busy; +} + +/** + * @brief Is the read payload FIFO of the generic interface full? + * + * @param dev Pointer to the DSI Host controller register base address + * @return True if full, False if not + */ +static inline bool mipi_dsi_host_ll_gen_is_read_fifo_full(dsi_host_dev_t *dev) +{ + return dev->cmd_pkt_status.gen_pld_r_full; +} + +/** + * @brief Is the read payload FIFO of the generic interface empty? + * + * @param dev Pointer to the DSI Host controller register base address + * @return True if empty, False if not + */ +static inline bool mipi_dsi_host_ll_gen_is_read_fifo_empty(dsi_host_dev_t *dev) +{ + return dev->cmd_pkt_status.gen_pld_r_empty; +} + +/** + * @brief Is the write payload FIFO of generic interface full? + * + * @param dev Pointer to the DSI Host controller register base address + * @return True if full, False if not + */ +static inline bool mipi_dsi_host_ll_gen_is_write_fifo_full(dsi_host_dev_t *dev) +{ + return dev->cmd_pkt_status.gen_pld_w_full; +} + +/** + * @brief Is the write payload FIFO of generic interface empty? + * + * @param dev Pointer to the DSI Host controller register base address + * @return True if empty, False if not + */ +static inline bool mipi_dsi_host_ll_gen_is_write_fifo_empty(dsi_host_dev_t *dev) +{ + return dev->cmd_pkt_status.gen_pld_w_empty; +} + +/** + * @brief Is the command FIFO of generic interface full? + * + * @param dev Pointer to the DSI Host controller register base address + * @return True if full, False if not + */ +static inline bool mipi_dsi_host_ll_gen_is_cmd_fifo_full(dsi_host_dev_t *dev) +{ + return dev->cmd_pkt_status.gen_cmd_full; +} + +/** + * @brief Is the command FIFO of generic interface empty? + * + * @param dev Pointer to the DSI Host controller register base address + * @return True if empty, False if not + */ +static inline bool mipi_dsi_host_ll_gen_is_cmd_fifo_empty(dsi_host_dev_t *dev) +{ + return dev->cmd_pkt_status.gen_cmd_empty; +} + +/** + * @brief Set the ID of the virtual channel that for generic reading back + * + * @param dev Pointer to the DSI Host controller register base address + * @param vcid Virtual channel ID + */ +static inline void mipi_dsi_host_ll_gen_set_rx_vcid(dsi_host_dev_t *dev, uint32_t vcid) +{ + dev->gen_vcid.gen_vcid_rx = vcid; +} + +/** + * @brief Set the ID of the virtual channel that for tear effect + * + * @param dev Pointer to the DSI Host controller register base address + * @param vcid Virtual channel ID + */ +static inline void mipi_dsi_host_ll_gen_set_te_vcid(dsi_host_dev_t *dev, uint32_t vcid) +{ + dev->gen_vcid.gen_vcid_tear_auto = vcid; +} + +/** + * @brief Set the ID of the virtual channel that for automatically transmitting generic packets + * + * @param dev Pointer to the DSI Host controller register base address + * @param vcid Virtual channel ID + */ +static inline void mipi_dsi_host_ll_gen_set_tx_vcid(dsi_host_dev_t *dev, uint32_t vcid) +{ + dev->gen_vcid.gen_vcid_tx_auto = vcid; +} + +#ifdef __cplusplus + +} +#endif diff --git a/components/hal/esp32p4/include/hal/mipi_dsi_ll.h b/components/hal/esp32p4/include/hal/mipi_dsi_ll.h new file mode 100644 index 0000000000..9bf9b42d1c --- /dev/null +++ b/components/hal/esp32p4/include/hal/mipi_dsi_ll.h @@ -0,0 +1,175 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "soc/hp_sys_clkrst_struct.h" +#include "hal/misc.h" +#include "hal/mipi_dsi_host_ll.h" +#include "hal/mipi_dsi_brg_ll.h" +#include "hal/mipi_dsi_phy_ll.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Enable the bus clock for MIPI DSI module + * + * @param group_id Group ID + * @param enable true to enable, false to disable + */ +static inline void mipi_dsi_ll_enable_bus_clock(int group_id, bool enable) +{ + (void)group_id; + HP_SYS_CLKRST.soc_clk_ctrl1.reg_dsi_sys_clk_en = enable; +} + +/// 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_dsi_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; mipi_dsi_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset the MIPI DSI module + * + * @param group_id Group ID + */ +static inline void mipi_dsi_ll_reset_register(int group_id) +{ + (void)group_id; + HP_SYS_CLKRST.hp_rst_en0.reg_rst_en_dsi_brg = 1; + HP_SYS_CLKRST.hp_rst_en0.reg_rst_en_dsi_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_dsi_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; mipi_dsi_ll_reset_register(__VA_ARGS__) + +/** + * @brief Enable MIPI DSI DPI clock + * + * @param group_id Group ID + * @param enable true to enable, false to disable + */ +static inline void mipi_dsi_ll_enable_dpi_clock(int group_id, bool enable) +{ + (void)group_id; + HP_SYS_CLKRST.peri_clk_ctrl03.reg_mipi_dsi_dpiclk_en = enable; +} + +/// 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_dsi_ll_enable_dpi_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; mipi_dsi_ll_enable_dpi_clock(__VA_ARGS__) + +/** + * @brief Set the clock source for the DSI DPI interface + * + * @param group_id Group ID + * @param source Clock source + */ +static inline void mipi_dsi_ll_set_dpi_clock_source(int group_id, mipi_dsi_dpi_clock_source_t source) +{ + (void)group_id; + switch (source) { + case MIPI_DSI_DPI_CLK_SRC_XTAL: + HP_SYS_CLKRST.peri_clk_ctrl03.reg_mipi_dsi_dpiclk_src_sel = 0; + break; + case MIPI_DSI_DPI_CLK_SRC_PLL_F160M: + HP_SYS_CLKRST.peri_clk_ctrl03.reg_mipi_dsi_dpiclk_src_sel = 2; + break; + case MIPI_DSI_DPI_CLK_SRC_PLL_F240M: + HP_SYS_CLKRST.peri_clk_ctrl03.reg_mipi_dsi_dpiclk_src_sel = 1; + 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_dsi_ll_set_dpi_clock_source(...) (void)__DECLARE_RCC_ATOMIC_ENV; mipi_dsi_ll_set_dpi_clock_source(__VA_ARGS__) + +/** + * @brief Set the clock division factor for the DPI clock source + * + * @param group_id Group ID + * @param div Division factor + */ +static inline void mipi_dsi_ll_set_dpi_clock_div(int group_id, uint32_t div) +{ + (void)group_id; + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl03, reg_mipi_dsi_dpiclk_div_num, div - 1); +} + +/// 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_dsi_ll_set_dpi_clock_div(...) (void)__DECLARE_RCC_ATOMIC_ENV; mipi_dsi_ll_set_dpi_clock_div(__VA_ARGS__) + +/** + * @brief Enable MIPI DSI PHY configuration clock + * + * @param group_id Group ID + * @param enable true to enable, false to disable + */ +static inline void mipi_dsi_ll_enable_phy_config_clock(int group_id, bool enable) +{ + (void)group_id; + HP_SYS_CLKRST.peri_clk_ctrl03.reg_mipi_dsi_dphy_cfg_clk_en = enable; +} + +/// 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_dsi_ll_enable_phy_config_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; mipi_dsi_ll_enable_phy_config_clock(__VA_ARGS__) + +/** + * @brief Enable MIPI DSI PHY PLL reference clock + * + * @param group_id Group ID + * @param enable true to enable, false to disable + */ +static inline void mipi_dsi_ll_enable_phy_reference_clock(int group_id, bool enable) +{ + (void)group_id; + HP_SYS_CLKRST.peri_clk_ctrl03.reg_mipi_dsi_dphy_pll_refclk_en = enable; +} + +/// 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_dsi_ll_enable_phy_reference_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; mipi_dsi_ll_enable_phy_reference_clock(__VA_ARGS__) + +/** + * @brief Set the clock source for the DSI PHY interface + * + * @param group_id Group ID + * @param source Clock source + */ +static inline void mipi_dsi_ll_set_phy_clock_source(int group_id, mipi_dsi_phy_clock_source_t source) +{ + (void)group_id; + switch (source) { + case MIPI_DSI_PHY_CLK_SRC_PLL_F20M: + HP_SYS_CLKRST.peri_clk_ctrl02.reg_mipi_dsi_dphy_clk_src_sel = 0; + break; + case MIPI_DSI_PHY_CLK_SRC_RC_FAST: + HP_SYS_CLKRST.peri_clk_ctrl02.reg_mipi_dsi_dphy_clk_src_sel = 1; + break; + case MIPI_DSI_PHY_CLK_SRC_PLL_F25M: + HP_SYS_CLKRST.peri_clk_ctrl02.reg_mipi_dsi_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_dsi_ll_set_phy_clock_source(...) (void)__DECLARE_RCC_ATOMIC_ENV; mipi_dsi_ll_set_phy_clock_source(__VA_ARGS__) + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32p4/include/hal/mipi_dsi_phy_ll.h b/components/hal/esp32p4/include/hal/mipi_dsi_phy_ll.h new file mode 100644 index 0000000000..c5de472eb0 --- /dev/null +++ b/components/hal/esp32p4/include/hal/mipi_dsi_phy_ll.h @@ -0,0 +1,234 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "hal/assert.h" +#include "hal/misc.h" +#include "soc/mipi_dsi_host_struct.h" +#include "hal/mipi_dsi_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Enable the PHY clock lane + * + * @param dev Pointer to the DSI Host controller register base address + * @param enable True to enable, False to disable + */ +static inline void mipi_dsi_phy_ll_enable_clock_lane(dsi_host_dev_t *dev, bool enable) +{ + dev->phy_rstz.phy_enableclk = enable; +} + +/** + * @brief Reset the digital section of the PHY + * + * @param dev Pointer to the DSI Host controller register base address + * @param enable True to place the PHY in the reset state, False to release the reset + */ +static inline void mipi_dsi_phy_ll_reset(dsi_host_dev_t *dev) +{ + dev->phy_rstz.phy_rstz = 0; + dev->phy_rstz.phy_rstz = 1; +} + +/** + * @brief Shutdown the PHY + * + * @param dev Pointer to the DSI Host controller register base address + * @param on_off True to power up, false to shut down + */ +static inline void mipi_dsi_phy_ll_power_on_off(dsi_host_dev_t *dev, bool on_off) +{ + dev->phy_rstz.phy_shutdownz = on_off; +} + +/** + * @brief Force the PHY to stay on while in ULPS + * + * @note To follow the programming model, use wakeup_pll function + * + * @param dev Pointer to the DSI Host controller register base address + * @param enable True to enable, False to disable + */ +static inline void mipi_dsi_phy_ll_force_pll(dsi_host_dev_t *dev, bool force) +{ + dev->phy_rstz.phy_forcepll = force; +} + +/** + * @brief Check if the PHY PLL is locked + * + * @param dev Pointer to the DSI Host controller register base address + * @return True if the PLL is locked, False otherwise + */ +static inline bool mipi_dsi_phy_ll_is_pll_locked(dsi_host_dev_t *dev) +{ + return dev->phy_status.phy_lock; +} + +/** + * @brief Check if the Lane0 in stop state + * + * @param dev Pointer to the DSI Host controller register base address + * @return True if the Lane0 in stop state, False otherwise + */ +static inline bool mipi_dsi_phy_ll_is_lane0_stoped(dsi_host_dev_t *dev) +{ + return dev->phy_status.phy_stopstate0lane; +} + +/** + * @brief Set the number of active data lanes + * + * @param dev Pointer to the DSI Host controller register base address + * @param lane_num Number of lanes used in the DSI link + */ +static inline void mipi_dsi_phy_ll_set_data_lane_number(dsi_host_dev_t *dev, uint32_t lane_num) +{ + dev->phy_if_cfg.n_lanes = lane_num - 1; +} + +/** + * @brief Set the minimum time PHY needs to stay in Stop state before requesting an HS transmission + * + * @param dev Pointer to the DSI Host controller register base address + * @param wait_time Time in lane byte clock cycles + */ +static inline void mipi_dsi_phy_ll_set_stop_wait_time(dsi_host_dev_t *dev, uint32_t wait_time) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->phy_if_cfg, phy_stop_wait_time, wait_time); +} + +/** + * @brief Set the maximum time required to perform a read command in lane byte clock cycles + * + * @note This can only be modified when no read command is in progress + * + * @param dev Pointer to the DSI Host controller register base address + * @param max_time Maximum time required to perform a read command in lane byte clock cycles + */ +static inline void mipi_dsi_phy_ll_set_max_read_time(dsi_host_dev_t *dev, uint32_t max_time) +{ + dev->phy_tmr_rd_cfg.max_rd_time = max_time; +} + +/** + * @brief ULPS mode request on all active data lanes + * + * @param dev Pointer to the DSI Host controller register base address + */ +static inline void mipi_dsi_phy_ll_data_enter_ulps(dsi_host_dev_t *dev) +{ + dev->phy_ulps_ctrl.phy_txrequlpslan = 1; +} + +/** + * @brief ULPS mode exit on all active data lanes + * + * @param dev Pointer to the DSI Host controller register base address + */ +static inline void mipi_dsi_phy_ll_data_exit_ulps(dsi_host_dev_t *dev) +{ + dev->phy_ulps_ctrl.phy_txexitulpslan = 1; +} + +/** + * @brief ULPS mode request on clock lane + * + * @param dev Pointer to the DSI Host controller register base address + */ +static inline void mipi_dsi_phy_ll_clk_enter_ulps(dsi_host_dev_t *dev) +{ + dev->phy_ulps_ctrl.phy_txrequlpsclk = 1; +} + +/** + * @brief ULPS mode exit on clock lane + * + * @param dev Pointer to the DSI Host controller register base address + */ +static inline void mipi_dsi_phy_ll_clk_exit_ulps(dsi_host_dev_t *dev) +{ + dev->phy_ulps_ctrl.phy_txexitulpsclk = 1; +} + +/** + * @brief Control the internal interface (clock and pins) between the DSI Host and the D-PHY + * + * @param dev Pointer to the DSI 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_dsi_phy_ll_write_clock(dsi_host_dev_t *dev, uint32_t clock_level, bool clear) +{ + dev->phy_tst_ctrl0.val = clock_level << 1 | clear; +} + +/** + * @brief Write the PHY register via internal interface (so-called the test interface) + * + * @param dev Pointer to the DSI Host controller register base address + * @param reg_addr Address of the PHY register + */ +static inline void mipi_dsi_phy_ll_write_reg_addr(dsi_host_dev_t *dev, uint8_t reg_addr) +{ + dev->phy_tst_ctrl1.val = (1 << 16) | (reg_addr & 0xFF); +} + +/** + * @brief Write the PHY register value via internal interface (so-called the test interface) + * + * @param dev Pointer to the DSI Host controller register base address + * @param reg_val Value to write to the PHY register + */ +static inline void mipi_dsi_phy_ll_write_reg_val(dsi_host_dev_t *dev, uint8_t reg_val) +{ + dev->phy_tst_ctrl1.val = reg_val & 0xFF; +} + +/** + * @brief Send trigger transmission + * + * @note Only one bit of the trigger_request is asserted at a time + * @note Only call this function when the PHY is not in LPDT or ULPS modes + * + * @param dev Pointer to the DSI Host controller register base address + * @param trigger_request Trigger request + */ +static inline void mipi_dsi_phy_ll_escape_trigger(dsi_host_dev_t *dev, uint8_t trigger_request) +{ + dev->phy_tx_triggers.phy_tx_triggers = trigger_request; + while (dev->phy_status.phy_stopstate0lane == 0); + dev->phy_tx_triggers.phy_tx_triggers = 0; +} + +/** + * @brief Set the time to switch between HS and LP + * + * @param dev Pointer to the DSI Host controller register base address + * @param data_hs2lp Time to switch data lane from HS to LP, in lane byte clock cycles + * @param data_lp2hs Time to switch data lane from LP to HS, in lane byte clock cycles + * @param clk_hs2lp Time to switch clock lane from HS to LP, in lane byte clock cycles + * @param clk_lp2hs Time to switch clock lane from LP to HS, in lane byte clock cycles + */ +static inline void mipi_dsi_phy_ll_set_switch_time(dsi_host_dev_t *dev, uint32_t data_hs2lp, uint32_t data_lp2hs, uint32_t clk_hs2lp, uint32_t clk_lp2hs) +{ + dev->phy_tmr_cfg.phy_hs2lp_time = data_hs2lp; + dev->phy_tmr_cfg.phy_lp2hs_time = data_lp2hs; + dev->phy_tmr_lpclk_cfg.phy_clkhs2lp_time = clk_hs2lp; + dev->phy_tmr_lpclk_cfg.phy_clklp2hs_time = clk_lp2hs; +} + +#ifdef __cplusplus + +} +#endif diff --git a/components/hal/esp32s3/include/hal/lcd_ll.h b/components/hal/esp32s3/include/hal/lcd_ll.h index 3fd1a50ec4..284d9c3258 100644 --- a/components/hal/esp32s3/include/hal/lcd_ll.h +++ b/components/hal/esp32s3/include/hal/lcd_ll.h @@ -37,9 +37,10 @@ typedef enum { } lcd_ll_swizzle_mode_t; /** - * @brief Enable or disable the bus clock for the LCD module + * @brief Enable the bus clock for LCD module * - * @param set_bit True to set bit, false to clear bit + * @param group_id Group ID + * @param enable true to enable, false to disable */ static inline void lcd_ll_enable_bus_clock(int group_id, bool enable) { @@ -53,6 +54,8 @@ static inline void lcd_ll_enable_bus_clock(int group_id, bool enable) /** * @brief Reset the LCD module + * + * @param group_id Group ID */ static inline void lcd_ll_reset_register(int group_id) { diff --git a/components/hal/include/hal/color_types.h b/components/hal/include/hal/color_types.h index b9cdc60344..36f4323849 100644 --- a/components/hal/include/hal/color_types.h +++ b/components/hal/include/hal/color_types.h @@ -42,6 +42,7 @@ typedef enum { */ typedef enum { COLOR_PIXEL_RGB888, ///< 24 bits, 8 bits per R/G/B value + COLOR_PIXEL_RGB666, ///< 18 bits, 6 bits per R/G/B value COLOR_PIXEL_RGB565, ///< 16 bits, 5 bits per R/B value, 6 bits for G value } color_pixel_rgb_format_t; diff --git a/components/hal/include/hal/lcd_types.h b/components/hal/include/hal/lcd_types.h index 7c709b5766..e25ff40ac5 100644 --- a/components/hal/include/hal/lcd_types.h +++ b/components/hal/include/hal/lcd_types.h @@ -39,6 +39,15 @@ typedef enum { LCD_COLOR_SPACE_YUV = COLOR_SPACE_YUV, /*!< Color space: YUV */ } lcd_color_space_t; +/** + * @brief LCD color pixel format in RGB color space + */ +typedef enum { + LCD_COLOR_PIXEL_FORMAT_RGB565 = COLOR_PIXEL_RGB565, /*!< 16 bits, 5 bits per R/B value, 6 bits for G value */ + LCD_COLOR_PIXEL_FORMAT_RGB666 = COLOR_PIXEL_RGB666, /*!< 18 bits, 6 bits per R/G/B value */ + LCD_COLOR_PIXEL_FORMAT_RGB888 = COLOR_PIXEL_RGB888, /*!< 24 bits, 8 bits per R/G/B value */ +} lcd_color_rgb_pixel_format_t; + /** * @brief LCD color range */ diff --git a/components/hal/include/hal/mipi_dsi_hal.h b/components/hal/include/hal/mipi_dsi_hal.h new file mode 100644 index 0000000000..41005971ab --- /dev/null +++ b/components/hal/include/hal/mipi_dsi_hal.h @@ -0,0 +1,158 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "hal/lcd_types.h" +#include "hal/mipi_dsi_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief MIPI DSI SOC layer representation of the host controller + */ +typedef struct dsi_host_dev_t *mipi_dsi_host_soc_handle_t; + +/** + * @brief MIPI DSI SOC layer representation of the bridge controller + */ +typedef struct dsi_brg_dev_t *mipi_dsi_bridge_soc_handle_t; + +/** + * @brief MIPI DSI HAL driver context + */ +typedef struct { + mipi_dsi_host_soc_handle_t host; /*!< Pointer to the host controller registers */ + mipi_dsi_bridge_soc_handle_t bridge; /*!< Pointer to the bridge controller registers */ + float dpi2lane_clk_ratio; /*!< Ratio between DPI clock and lane byte clock */ +} mipi_dsi_hal_context_t; + +/** + * @brief MIPI DSI HAL driver configuration + */ +typedef struct { + uint32_t lane_byte_clk_hz; /*!< Lane byte clock frequency */ + uint32_t dpi_clk_hz; /*!< DPI clock frequency */ +} mipi_dsi_hal_config_t; + +/** + * @brief Initialize MIPI DSI Hal driver context + * + * @note Caller should malloc the memory for the hal context + * + * @param hal Pointer to the HAL driver context + * @param config Pointer to the HAL driver configuration + */ +void mipi_dsi_hal_init(mipi_dsi_hal_context_t *hal, const mipi_dsi_hal_config_t *config); + +/** + * @brief Write a value to a PHY register via internal bus (so-called test interface) + * + * @param hal Pointer to the HAL driver context + * @param reg_addr Address of the PHY register + * @param reg_val Value to be written to the PHY register + */ +void mipi_dsi_hal_phy_write_register(mipi_dsi_hal_context_t *hal, uint8_t reg_addr, uint8_t reg_val); + +/** + * @brief Send a DCS command with parameters via the generic interface + * + * @note The command itself and the parameters are sent in one packet. For simplicity, we use the same + * DCS_LONG_WRITE type to send all different commands. + * + * @param hal Pointer to the HAL driver context + * @param vc Virtual channel number + * @param command DCS command + * @param command_bytes Number of bytes of the command + * @param param Pointer to the parameters + * @param param_size Number of bytes of the parameters + */ +void mipi_dsi_hal_host_gen_write_dcs_command(mipi_dsi_hal_context_t *hal, uint8_t vc, + uint32_t command, uint32_t command_bytes, const void *param, uint16_t param_size); + +/** + * @brief Send a DCS command and return the associated parameters via the generic interface + * + * @param hal Pointer to the HAL driver context + * @param vc Virtual channel number + * @param command DCS command + * @param command_bytes Number of bytes of the command + * @param ret_param Pointer to the buffer to store the returned parameters + * @param param_buf_size Size of the buffer to store the returned parameters + */ +void mipi_dsi_hal_host_gen_read_dcs_command(mipi_dsi_hal_context_t *hal, uint8_t vc, uint32_t command, uint32_t command_bytes, void *ret_param, uint16_t param_buf_size); + +/** + * @brief Send a long packet via the generic interface + * + * @param hal Pointer to the HAL driver context + * @param vc Virtual channel number + * @param dt Data type + * @param buffer Pointer to the buffer + * @param buffer_size Number of bytes to be sent + */ +void mipi_dsi_hal_host_gen_write_long_packet(mipi_dsi_hal_context_t *hal, uint8_t vc, mipi_dsi_data_type_t dt, const void *buffer, uint16_t buffer_size); + +/** + * @brief Send a short packet via the generic interface + * + * @param hal Pointer to the HAL driver context + * @param vc Virtual channel number + * @param dt Data type + * @param header_data Data to be sent, filled into the DSI packet header + */ +void mipi_dsi_hal_host_gen_write_short_packet(mipi_dsi_hal_context_t *hal, uint8_t vc, mipi_dsi_data_type_t dt, uint16_t header_data); + +/** + * @brief Send a short packet via the generic interface and return the associated data + * + * @param hal Pointer to the HAL driver context + * @param vc Virtual channel number + * @param dt Data type + * @param header_data Data to be filled into the DSI packet header + * @param ret_buffer Pointer to the buffer to store the returned data + * @param buffer_size Size of the buffer to store the returned data + */ +void mipi_dsi_hal_host_gen_read_short_packet(mipi_dsi_hal_context_t *hal, uint8_t vc, mipi_dsi_data_type_t dt, uint16_t header_data, void *ret_buffer, uint16_t buffer_size); + +/** + * @brief Set DPI color coding + * + * @param hal Pointer to the HAL driver context + * @param color_coding Color coding + * @param sub_config Sub configuration + */ +void mipi_dsi_hal_host_dpi_set_color_coding(mipi_dsi_hal_context_t *hal, lcd_color_rgb_pixel_format_t color_coding, uint32_t sub_config); + +/** + * @brief Set horizontal timing parameters for DPI + * + * @param hal Pointer to the HAL driver context + * @param hsw Horizontal Synchronization Width + * @param hbp Horizontal Back Porch + * @param active_width Active Width + * @param hfp Horizontal Front Porch + */ +void mipi_dsi_hal_host_dpi_set_horizontal_timing(mipi_dsi_hal_context_t *hal, uint32_t hsw, uint32_t hbp, uint32_t active_width, uint32_t hfp); + +/** + * @brief Set vertical timing parameters for DPI + * + * @param hal Pointer to the HAL driver context + * @param vsw Vertical Synchronization Width + * @param vbp Vertical Back Porch + * @param active_height Active Height + * @param vfp Vertical Front Porch + */ +void mipi_dsi_hal_host_dpi_set_vertical_timing(mipi_dsi_hal_context_t *hal, uint32_t vsw, uint32_t vbp, uint32_t active_height, uint32_t vfp); + +#ifdef __cplusplus + +} +#endif diff --git a/components/hal/include/hal/mipi_dsi_types.h b/components/hal/include/hal/mipi_dsi_types.h new file mode 100644 index 0000000000..68c666ad21 --- /dev/null +++ b/components/hal/include/hal/mipi_dsi_types.h @@ -0,0 +1,83 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "soc/clk_tree_defs.h" +#include "esp_assert.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief MIPI DSI Data Type (DT) + */ +typedef enum { + MIPI_DSI_DT_VSYNC_START = 0x01, /*!< V Sync Start */ + MIPI_DSI_DT_VSYNC_END = 0x11, /*!< V Sync End */ + MIPI_DSI_DT_HSYNC_START = 0x21, /*!< H Sync Start */ + MIPI_DSI_DT_HSYNC_END = 0x31, /*!< H Sync End */ + MIPI_DSI_DT_EOT_PACKET = 0x08, /*!< End of Transmission */ + MIPI_DSI_DT_COLOR_MODE_OFF = 0x02, /*!< Color Mode Off */ + MIPI_DSI_DT_COLOR_MODE_ON = 0x12, /*!< Color Mode On */ + MIPI_DSI_DT_SHUTDOWN_PERIPHERAL = 0x22, /*!< Shutdown Peripheral */ + MIPI_DSI_DT_TURN_ON_PERIPHERAL = 0x32, /*!< Turn On Peripheral */ + MIPI_DSI_DT_GENERIC_SHORT_WRITE_0 = 0x03, /*!< Generic Short Write, with no parameter */ + MIPI_DSI_DT_GENERIC_SHORT_WRITE_1 = 0x13, /*!< Generic Short Write, with 1 byte parameter */ + MIPI_DSI_DT_GENERIC_SHORT_WRITE_2 = 0x23, /*!< Generic Short Write, with 2 byte parameter */ + MIPI_DSI_DT_GENERIC_READ_REQUEST_0 = 0x04, /*!< Generic Read Request, with no parameter */ + MIPI_DSI_DT_GENERIC_READ_REQUEST_1 = 0x14, /*!< Generic Read Request, with 1 byte parameter */ + MIPI_DSI_DT_GENERIC_READ_REQUEST_2 = 0x24, /*!< Generic Read Request, with 2 byte parameter */ + MIPI_DSI_DT_DCS_SHORT_WRITE_0 = 0x05, /*!< DCS Short Write, with no parameter */ + MIPI_DSI_DT_DCS_SHORT_WRITE_1 = 0x15, /*!< DCS Short Write, with 1 byte parameter */ + MIPI_DSI_DT_DCS_READ_0 = 0x06, /*!< DCS Read, with no parameter */ + MIPI_DSI_DT_SET_MAXIMUM_RETURN_PKT = 0x37, /*!< Set Maximum Return Packet Size */ + MIPI_DSI_DT_NULL_PACKET = 0x09, /*!< Null Packet, no data */ + MIPI_DSI_DT_BLANKING_PACKET = 0x19, /*!< Blanking Packet, no data */ + MIPI_DSI_DT_GENERIC_LONG_WRITE = 0x29, /*!< Generic Long Write */ + MIPI_DSI_DT_DCS_LONG_WRITE = 0x39, /*!< DCS Long Write */ + MIPI_DSI_DT_PACKED_PIXEL_STREAM_RGB_16 = 0x0E, /*!< Packed Pixel Stream, RGB565 */ + MIPI_DSI_DT_PACKED_PIXEL_STREAM_RGB_18 = 0x1E, /*!< Packed Pixel Stream, RGB666 */ + MIPI_DSI_DT_LOOSELY_PIXEL_STREAM_RGB_18 = 0x2E, /*!< Loosely Pixel Stream, RGB666 */ + MIPI_DSI_DT_PACKED_PIXEL_STREAM_RGB_24 = 0x3E, /*!< Packed Pixel Stream, RGB888 */ +} __attribute__((packed)) mipi_dsi_data_type_t; + +/** + * @brief MIPI DSI packet + */ +typedef struct { + mipi_dsi_data_type_t dt: 6; /*!< Data Type */ + uint8_t vc: 2; /*!< Virtual Channel */ + union { + uint16_t word_count; /*!< Word count, in bytes */ + uint8_t data[2]; /*!< Data of short packet */ + }; + uint8_t ecc; /*!< ECC */ + uint8_t payload[0]; /*!< Payload of long packet */ +} __attribute__((packed)) mipi_dsi_packet_t; + +ESP_STATIC_ASSERT(sizeof(mipi_dsi_packet_t) == 4, "Invalid size of mipi_dsi_packet_t structure"); + +#if SOC_MIPI_DSI_SUPPORTED +/** + * @brief MIPI DSI PHY clock source + */ +typedef soc_periph_mipi_dsi_phy_clk_src_t mipi_dsi_phy_clock_source_t; + +/** + * @brief MIPI DSI DPI clock source + */ +typedef soc_periph_mipi_dsi_dpi_clk_src_t mipi_dsi_dpi_clock_source_t; +#else +typedef int mipi_dsi_phy_clock_source_t; +typedef int mipi_dsi_dpi_clock_source_t; +#endif // SOC_MIPI_DSI_SUPPORTED + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/mipi_dsi_hal.c b/components/hal/mipi_dsi_hal.c new file mode 100644 index 0000000000..74a677f4b3 --- /dev/null +++ b/components/hal/mipi_dsi_hal.c @@ -0,0 +1,164 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "hal/mipi_dsi_hal.h" +#include "hal/mipi_dsi_ll.h" + +void mipi_dsi_hal_init(mipi_dsi_hal_context_t *hal, const mipi_dsi_hal_config_t *config) +{ + hal->host = &MIPI_DSI_HOST; + hal->bridge = &MIPI_DSI_BRIDGE; + hal->dpi2lane_clk_ratio = ((float)config->lane_byte_clk_hz) / config->dpi_clk_hz; +} + +void mipi_dsi_hal_phy_write_register(mipi_dsi_hal_context_t *hal, uint8_t reg_addr, uint8_t reg_val) +{ + // disable the test clear pin, enable the interface to write values to the PHY internal registers + mipi_dsi_phy_ll_write_clock(hal->host, 0, false); + // load PHY register address + mipi_dsi_phy_ll_write_reg_addr(hal->host, reg_addr); + // the address write operation is set on the falling edge of the test clock + mipi_dsi_phy_ll_write_clock(hal->host, 1, false); + mipi_dsi_phy_ll_write_clock(hal->host, 0, false); + // load PHY register value + mipi_dsi_phy_ll_write_reg_val(hal->host, reg_val); + // the data write operation is set on the rising edge of the test clock + mipi_dsi_phy_ll_write_clock(hal->host, 1, false); + mipi_dsi_phy_ll_write_clock(hal->host, 0, false); +} + +void mipi_dsi_hal_host_gen_write_dcs_command(mipi_dsi_hal_context_t *hal, uint8_t vc, + uint32_t command, uint32_t command_bytes, const void *param, uint16_t param_size) +{ + const uint8_t *payload = param; + // the payload size is the command size plus the parameter size + uint32_t payload_size = command_bytes + param_size; + + // merge the command and some bytes of parameters into one 32-bit word + uint32_t temp = command & ((1 << (8 * command_bytes)) - 1); + uint16_t merged_size = MIN(4 - command_bytes, param_size); + for (int i = 0; i < merged_size; i++) { + temp |= payload[i] << (8 * (i + command_bytes)); + } + while (mipi_dsi_host_ll_gen_is_write_fifo_full(hal->host)); + mipi_dsi_host_ll_gen_write_payload_fifo(hal->host, temp); + + // write the remaining parameters into FIFO + payload += merged_size; + uint32_t remain_size = param_size - merged_size; + while (remain_size >= 4) { + temp = *(uint32_t *)payload; + while (mipi_dsi_host_ll_gen_is_write_fifo_full(hal->host)); + mipi_dsi_host_ll_gen_write_payload_fifo(hal->host, temp); + payload += 4; + remain_size -= 4; + } + if (remain_size) { + temp = *(uint32_t *)payload; + temp &= (1 << (8 * remain_size)) - 1; + while (mipi_dsi_host_ll_gen_is_write_fifo_full(hal->host)); + mipi_dsi_host_ll_gen_write_payload_fifo(hal->host, temp); + } + + uint8_t wc_msb = (payload_size >> 8) & 0xFF; + uint8_t wc_lsb = payload_size & 0xFF; + while (mipi_dsi_host_ll_gen_is_cmd_fifo_full(hal->host)); + mipi_dsi_host_ll_gen_set_packet_header(hal->host, vc, MIPI_DSI_DT_DCS_LONG_WRITE, wc_msb, wc_lsb); +} + +void mipi_dsi_hal_host_gen_write_short_packet(mipi_dsi_hal_context_t *hal, uint8_t vc, mipi_dsi_data_type_t dt, uint16_t header_data) +{ + uint8_t msb = (header_data >> 8) & 0xFF; + uint8_t lsb = header_data & 0xFF; + while (mipi_dsi_host_ll_gen_is_cmd_fifo_full(hal->host)); + mipi_dsi_host_ll_gen_set_packet_header(hal->host, vc, dt, msb, lsb); +} + +void mipi_dsi_hal_host_gen_write_long_packet(mipi_dsi_hal_context_t *hal, uint8_t vc, mipi_dsi_data_type_t dt, const void *buffer, uint16_t buffer_size) +{ + const uint8_t *payload = buffer; + uint32_t remain_size = buffer_size; + uint32_t temp = 0; + while (remain_size >= 4) { + temp = *(uint32_t *)payload; + while (mipi_dsi_host_ll_gen_is_write_fifo_full(hal->host)); + mipi_dsi_host_ll_gen_write_payload_fifo(hal->host, temp); + payload += 4; + remain_size -= 4; + } + if (remain_size) { + temp = *(uint32_t *)payload; + temp &= (1 << (8 * remain_size)) - 1; + while (mipi_dsi_host_ll_gen_is_write_fifo_full(hal->host)); + mipi_dsi_host_ll_gen_write_payload_fifo(hal->host, temp); + } + + uint8_t wc_msb = (buffer_size >> 8) & 0xFF; + uint8_t wc_lsb = buffer_size & 0xFF; + while (mipi_dsi_host_ll_gen_is_cmd_fifo_full(hal->host)); + mipi_dsi_host_ll_gen_set_packet_header(hal->host, vc, dt, wc_msb, wc_lsb); +} + +void mipi_dsi_hal_host_gen_read_short_packet(mipi_dsi_hal_context_t *hal, uint8_t vc, mipi_dsi_data_type_t dt, uint16_t header_data, void *ret_buffer, uint16_t buffer_size) +{ + uint8_t *receive_buffer = (uint8_t *)ret_buffer; + // set the maximum returned data size, it should equal to the parameter size of the read command + mipi_dsi_hal_host_gen_write_short_packet(hal, vc, MIPI_DSI_DT_SET_MAXIMUM_RETURN_PKT, buffer_size); + // make sure command mode is on + mipi_dsi_host_ll_dpi_enable_video_mode(hal->host, false); + // make sure receiving is enabled + mipi_dsi_host_ll_enable_bta(hal->host, true); + // listen to the same virtual channel as the one sent to + mipi_dsi_host_ll_gen_set_rx_vcid(hal->host, vc); + mipi_dsi_hal_host_gen_write_short_packet(hal, vc, dt, header_data); + while (mipi_dsi_host_ll_gen_is_read_cmd_busy(hal->host)); + // wait data to come into the fifo + while (mipi_dsi_host_ll_gen_is_read_fifo_empty(hal->host)); + uint32_t temp = 0; + uint32_t counter = 0; + while (!mipi_dsi_host_ll_gen_is_read_fifo_empty(hal->host)) { + temp = mipi_dsi_host_ll_gen_read_payload_fifo(hal->host); + for (int i = 0; i < 4; i++) { + if ((counter + i) < buffer_size) { + receive_buffer[counter + i] = (temp >> (8 * i)) & 0xFF; + } + counter++; + } + } +} + +void mipi_dsi_hal_host_gen_read_dcs_command(mipi_dsi_hal_context_t *hal, uint8_t vc, uint32_t command, uint32_t command_bytes, void *ret_param, uint16_t param_buf_size) +{ + uint16_t header_data = command & ((1 << (8 * command_bytes)) - 1); + mipi_dsi_hal_host_gen_read_short_packet(hal, vc, MIPI_DSI_DT_DCS_READ_0, header_data, ret_param, param_buf_size); +} + +void mipi_dsi_hal_host_dpi_set_color_coding(mipi_dsi_hal_context_t *hal, lcd_color_rgb_pixel_format_t color_coding, uint32_t sub_config) +{ + mipi_dsi_host_ll_dpi_set_color_coding(hal->host, color_coding, sub_config); + mipi_dsi_brg_ll_set_pixel_format(hal->bridge, color_coding, sub_config); + // please note, we need to call bridge_update to make the new configuration take effect +} + +void mipi_dsi_hal_host_dpi_set_horizontal_timing(mipi_dsi_hal_context_t *hal, uint32_t hsw, uint32_t hbp, uint32_t active_width, uint32_t hfp) +{ + mipi_dsi_host_ll_dpi_set_horizontal_timing(hal->host, + hsw * hal->dpi2lane_clk_ratio, + hbp * hal->dpi2lane_clk_ratio, + active_width * hal->dpi2lane_clk_ratio, + hfp * hal->dpi2lane_clk_ratio); + mipi_dsi_brg_ll_set_horizontal_timing(hal->bridge, hsw, hbp, active_width, hfp); + // please note, we need to call bridge_update to make the new configuration take effect +} + +void mipi_dsi_hal_host_dpi_set_vertical_timing(mipi_dsi_hal_context_t *hal, uint32_t vsw, uint32_t vbp, uint32_t active_height, uint32_t vfp) +{ + mipi_dsi_host_ll_dpi_set_vertical_timing(hal->host, vsw, vbp, active_height, vfp); + mipi_dsi_brg_ll_set_vertical_timing(hal->bridge, vsw, vbp, active_height, vfp); + // please note, we need to call bridge_update to make the new configuration take effect +} diff --git a/components/soc/esp32p4/include/soc/clk_tree_defs.h b/components/soc/esp32p4/include/soc/clk_tree_defs.h index 797f10e694..a9366f0bb1 100644 --- a/components/soc/esp32p4/include/soc/clk_tree_defs.h +++ b/components/soc/esp32p4/include/soc/clk_tree_defs.h @@ -141,6 +141,8 @@ typedef enum { SOC_MOD_CLK_RTC_FAST, /*!< RTC_FAST_CLK can be sourced from XTAL, RC_FAST, or LP_PLL by configuring soc_rtc_fast_clk_src_t */ SOC_MOD_CLK_RTC_SLOW, /*!< RTC_SLOW_CLK can be sourced from RC_SLOW, XTAL32K, RC32K, or OSC_SLOW by configuring soc_rtc_slow_clk_src_t */ // For digital domain: peripherals + SOC_MOD_CLK_PLL_F20M, /*!< PLL_F20M_CLK is derived from SPLL (clock gating + fixed divider of 24), it has a fixed frequency of 20MHz */ + SOC_MOD_CLK_PLL_F25M, /*!< PLL_F25M_CLK is derived from MPLL (clock gating + fixed divider of 20), it has a fixed frequency of 25MHz */ SOC_MOD_CLK_PLL_F80M, /*!< PLL_F80M_CLK is derived from SPLL (clock gating + fixed divider of 6), it has a fixed frequency of 80MHz */ SOC_MOD_CLK_PLL_F160M, /*!< PLL_F160M_CLK is derived from SPLL (clock gating + fixed divider of 3), it has a fixed frequency of 160MHz */ SOC_MOD_CLK_PLL_F200M, /*!< PLL_F200M_CLK is derived from SPLL (clock gating + fixed divider of 3), it has a fixed frequency of 200MHz */ @@ -389,6 +391,38 @@ typedef enum { LCD_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default choice */ } soc_periph_lcd_clk_src_t; +/////////////////////////////////////////////////MIPI/////////////////////////////////////////////////////////////////// + +/** + * @brief Array initializer for all supported clock sources of MIPI DSI DPI interface + */ +#define SOC_MIPI_DSI_DPI_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_PLL_F160M, SOC_MOD_CLK_PLL_F240M} + +/** + * @brief Type of MIPI DSI DPI clock source + */ +typedef enum { + MIPI_DSI_DPI_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as MIPI DSI DPI source clock */ + MIPI_DSI_DPI_CLK_SRC_PLL_F160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as MIPI DSI DPI source clock */ + MIPI_DSI_DPI_CLK_SRC_PLL_F240M = SOC_MOD_CLK_PLL_F240M, /*!< Select PLL_F240M as MIPI DSI DPI source clock */ + MIPI_DSI_DPI_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F240M, /*!< Select PLL_F240M as default clock */ +} soc_periph_mipi_dsi_dpi_clk_src_t; + +/** + * @brief Array initializer for all supported clock sources of MIPI DSI PHY interface + */ +#define SOC_MIPI_DSI_PHY_CLKS {SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_PLL_F25M, SOC_MOD_CLK_PLL_F20M} + +/** + * @brief Type of MIPI DSI PHY clock source + */ +typedef enum { + MIPI_DSI_PHY_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as MIPI DSI PHY source clock */ + MIPI_DSI_PHY_CLK_SRC_PLL_F25M = SOC_MOD_CLK_PLL_F25M, /*!< Select PLL_F25M as MIPI DSI PHY source clock */ + MIPI_DSI_PHY_CLK_SRC_PLL_F20M = SOC_MOD_CLK_PLL_F20M, /*!< Select PLL_F20M as MIPI DSI PHY source clock */ + MIPI_DSI_PHY_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F25M, /*!< Select PLL_F25M as default clock */ +} soc_periph_mipi_dsi_phy_clk_src_t; + /////////////////////////////////////////////////I2C//////////////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32p4/include/soc/mipi_dsi_bridge_struct.h b/components/soc/esp32p4/include/soc/mipi_dsi_bridge_struct.h index ef2d9feec7..33d8beeef6 100644 --- a/components/soc/esp32p4/include/soc/mipi_dsi_bridge_struct.h +++ b/components/soc/esp32p4/include/soc/mipi_dsi_bridge_struct.h @@ -764,7 +764,7 @@ typedef union { } dsi_brg_int_st_reg_t; -typedef struct { +typedef struct dsi_brg_dev_t { volatile dsi_brg_clk_en_reg_t clk_en; volatile dsi_brg_en_reg_t en; volatile dsi_brg_dma_req_cfg_reg_t dma_req_cfg; @@ -811,6 +811,8 @@ typedef struct { _Static_assert(sizeof(dsi_brg_dev_t) == 0xa0, "Invalid size of dsi_brg_dev_t structure"); #endif +extern dsi_brg_dev_t MIPI_DSI_BRIDGE; + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32p4/include/soc/mipi_dsi_host_struct.h b/components/soc/esp32p4/include/soc/mipi_dsi_host_struct.h index d086b4073e..8cd55877c2 100644 --- a/components/soc/esp32p4/include/soc/mipi_dsi_host_struct.h +++ b/components/soc/esp32p4/include/soc/mipi_dsi_host_struct.h @@ -1911,7 +1911,7 @@ typedef union { } dsi_host_int_force1_reg_t; -typedef struct { +typedef struct dsi_host_dev_t { volatile dsi_host_version_reg_t version; volatile dsi_host_pwr_up_reg_t pwr_up; volatile dsi_host_clkmgr_cfg_reg_t clkmgr_cfg; @@ -2001,6 +2001,8 @@ typedef struct { _Static_assert(sizeof(dsi_host_dev_t) == 0x194, "Invalid size of dsi_host_dev_t structure"); #endif +extern dsi_host_dev_t MIPI_DSI_HOST; + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index c58bbc87a8..1f0fabd927 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -28,6 +28,7 @@ #define SOC_GPTIMER_SUPPORTED 1 #define SOC_PCNT_SUPPORTED 1 // #define SOC_LCDCAM_SUPPORTED 1 // TODO: IDF-7465 +// #define SOC_MIPI_DSI_SUPPORTED 1 // TODO: IDF-7085 #define SOC_MCPWM_SUPPORTED 1 #define SOC_TWAI_SUPPORTED 1 #define SOC_ETM_SUPPORTED 1