feat(mipi_dsi): added DPHY PLL clock configuration

This commit is contained in:
morris 2024-01-11 18:43:19 +08:00
parent ad84b61e49
commit d3ebd6bc1c
11 changed files with 298 additions and 93 deletions

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -13,6 +13,8 @@
#include "hal/mipi_dsi_types.h" #include "hal/mipi_dsi_types.h"
#include "hal/lcd_types.h" #include "hal/lcd_types.h"
#define MIPI_DSI_LL_GET_BRG(bus_id) (bus_id == 0 ? &MIPI_DSI_BRIDGE : NULL)
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -46,6 +48,19 @@ static inline void mipi_dsi_brg_ll_set_burst_len(dsi_brg_dev_t *dev, uint32_t bu
dev->dma_req_cfg.dma_burst_len = burst_len; dev->dma_req_cfg.dma_burst_len = burst_len;
} }
/**
* @brief Set the fifo empty threshold
*
* @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_set_empty_threshold(dsi_brg_dev_t *dev, uint32_t threshold)
{
dev->raw_buf_almost_empty_thrd.dsi_raw_buf_almost_empty_thrd = threshold;
}
/** /**
* @brief Set the number of pixel bits in total * @brief Set the number of pixel bits in total
* *
@ -201,11 +216,11 @@ static inline void mipi_dsi_brg_ll_enable_dpi_output(dsi_brg_dev_t *dev, bool en
} }
/** /**
* @brief Update the configuration of DSI bridge * @brief Update the DPI configuration of DSI bridge
* *
* @param dev Pointer to the DSI bridge controller register base address * @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) static inline void mipi_dsi_brg_ll_update_dpi_config(dsi_brg_dev_t *dev)
{ {
dev->dpi_config_update.dpi_config_update = 1; dev->dpi_config_update.dpi_config_update = 1;
} }

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -14,6 +14,8 @@
#include "hal/mipi_dsi_types.h" #include "hal/mipi_dsi_types.h"
#include "hal/lcd_types.h" #include "hal/lcd_types.h"
#define MIPI_DSI_LL_GET_HOST(bus_id) (bus_id == 0 ? &MIPI_DSI_HOST : NULL)
#define MIPI_DSI_LL_MAX_DPI_CLK_DIV 256 #define MIPI_DSI_LL_MAX_DPI_CLK_DIV 256
#ifdef __cplusplus #ifdef __cplusplus
@ -28,6 +30,15 @@ typedef enum {
MIPI_DSI_LL_TRANS_SPEED_LP, /*!< Low power transmission */ MIPI_DSI_LL_TRANS_SPEED_LP, /*!< Low power transmission */
} mipi_dsi_ll_trans_speed_mode_t; } mipi_dsi_ll_trans_speed_mode_t;
/**
* @brief MIPI DSI clock lane state
*/
typedef enum {
MIPI_DSI_LL_CLOCK_LANE_STATE_AUTO, /*!< Clock lane state is automatic controlled by the DSI host */
MIPI_DSI_LL_CLOCK_LANE_STATE_HS, /*!< Clock lane state is in high speed */
MIPI_DSI_LL_CLOCK_LANE_STATE_LP, /*!< Clock lane state is in low power */
} mipi_dsi_ll_clock_lane_state_t;
/** /**
* @brief Color coding type (depth and pixel configuration) * @brief Color coding type (depth and pixel configuration)
*/ */
@ -40,15 +51,6 @@ typedef enum {
MIPI_DSI_LL_COLOR_CODE_24BIT = 5, // 24-bit MIPI_DSI_LL_COLOR_CODE_24BIT = 5, // 24-bit
} mipi_dsi_ll_color_coding_t; } 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 * @brief MIPI DSI Video mode burst type
*/ */
@ -120,25 +122,43 @@ static inline void mipi_dsi_host_ll_set_timeout_count(dsi_host_dev_t *dev, uint3
} }
/** /**
* @brief Enable the automatic mechanism to stop providing clock in the clock lane when time allows * @brief Set the state of the clock lane
* *
* @param dev Pointer to the DSI Host controller register base address * @param dev Pointer to the DSI Host controller register base address
* @param enable True to enable, False to disable * @param state Clock lane state
*/ */
static inline void mipi_dsi_host_ll_enable_non_continuous_clock(dsi_host_dev_t *dev, bool enable) static inline void mipi_dsi_host_ll_set_clock_lane_state(dsi_host_dev_t *dev, mipi_dsi_ll_clock_lane_state_t state)
{ {
dev->lpclk_ctrl.auto_clklane_ctrl = enable; switch (state) {
case MIPI_DSI_LL_CLOCK_LANE_STATE_AUTO:
dev->lpclk_ctrl.auto_clklane_ctrl = 1;
dev->lpclk_ctrl.phy_txrequestclkhs = 1;
break;
case MIPI_DSI_LL_CLOCK_LANE_STATE_HS:
dev->lpclk_ctrl.auto_clklane_ctrl = 0;
dev->lpclk_ctrl.phy_txrequestclkhs = 1;
break;
case MIPI_DSI_LL_CLOCK_LANE_STATE_LP:
dev->lpclk_ctrl.auto_clklane_ctrl = 0;
dev->lpclk_ctrl.phy_txrequestclkhs = 0;
break;
default:
HAL_ASSERT(false);
break;
}
} }
/** /**
* @brief Request the PHY module to start transmission of high speed clock * @brief Enable / Disable 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 dev Pointer to the DSI Host controller register base address
* @param enable True to enable, False to disable * @param en True to enable, False to disable
*/ */
static inline void mipi_dsi_host_ll_enable_hs_clock(dsi_host_dev_t *dev, bool enable) static inline void mipi_dsi_host_ll_enable_video_mode(dsi_host_dev_t *dev, bool en)
{ {
dev->lpclk_ctrl.phy_txrequestclkhs = enable; dev->mode_cfg.cmd_video_mode = !en;
} }
////////////////////////////////////////////DPI Interface/////////////////////////////// ////////////////////////////////////////////DPI Interface///////////////////////////////
@ -278,20 +298,26 @@ static inline void mipi_dsi_host_ll_dpi_set_video_burst_type(dsi_host_dev_t *dev
* @param dev Pointer to the DSI Host controller register base address * @param dev Pointer to the DSI Host controller register base address
* @param type Pattern type * @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) static inline void mipi_dsi_host_ll_dpi_set_pattern_type(dsi_host_dev_t *dev, mipi_dsi_pattern_type_t type)
{ {
switch (type) { switch (type) {
case MIPI_DSI_LL_PATTERN_BAR_HORIZONTAL: case MIPI_DSI_PATTERN_BAR_HORIZONTAL:
dev->vid_mode_cfg.vpg_mode = 0; dev->vid_mode_cfg.vpg_mode = 0;
dev->vid_mode_cfg.vpg_orientation = 1; dev->vid_mode_cfg.vpg_orientation = 1;
dev->vid_mode_cfg.vpg_en = 1;
break; break;
case MIPI_DSI_LL_PATTERN_BAR_VERTICAL: case MIPI_DSI_PATTERN_BAR_VERTICAL:
dev->vid_mode_cfg.vpg_mode = 0; dev->vid_mode_cfg.vpg_mode = 0;
dev->vid_mode_cfg.vpg_orientation = 0; dev->vid_mode_cfg.vpg_orientation = 0;
dev->vid_mode_cfg.vpg_en = 1;
break; break;
case MIPI_DSI_LL_PATTERN_BER_VERTICAL: case MIPI_DSI_PATTERN_BER_VERTICAL:
dev->vid_mode_cfg.vpg_mode = 1; dev->vid_mode_cfg.vpg_mode = 1;
dev->vid_mode_cfg.vpg_orientation = 0; dev->vid_mode_cfg.vpg_orientation = 0;
dev->vid_mode_cfg.vpg_en = 1;
break;
case MIPI_DSI_PATTERN_NONE:
dev->vid_mode_cfg.vpg_en = 0;
break; break;
default: default:
HAL_ASSERT(false); HAL_ASSERT(false);
@ -299,30 +325,6 @@ static inline void mipi_dsi_host_ll_dpi_set_pattern_type(dsi_host_dev_t *dev, mi
} }
} }
/**
* @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 * @brief Set the number of bytes inside a null packet
* *
@ -412,7 +414,7 @@ static inline void mipi_dsi_host_ll_enable_te_ack(dsi_host_dev_t *dev, bool en)
} }
/** /**
* @brief Enable the acknowledge request after each packet transmission * @brief Enable to request an acknowledgement from the DSI device after sending a command or data packet
* *
* @param dev Pointer to the DSI Host controller register base address * @param dev Pointer to the DSI Host controller register base address
* @param enable True to enable, False to disable * @param enable True to enable, False to disable

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -14,6 +14,8 @@
#include "hal/mipi_dsi_brg_ll.h" #include "hal/mipi_dsi_brg_ll.h"
#include "hal/mipi_dsi_phy_ll.h" #include "hal/mipi_dsi_phy_ll.h"
#define MIPI_DSI_LL_NUM_BUS 1 // 1 MIPI DSI bus
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -13,6 +13,9 @@
#include "soc/mipi_dsi_host_struct.h" #include "soc/mipi_dsi_host_struct.h"
#include "hal/mipi_dsi_types.h" #include "hal/mipi_dsi_types.h"
#define MIPI_DSI_LL_MIN_PHY_MBPS 80
#define MIPI_DSI_LL_MAX_PHY_MBPS 1500
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -32,7 +35,6 @@ static inline void mipi_dsi_phy_ll_enable_clock_lane(dsi_host_dev_t *dev, bool e
* @brief Reset the digital section of the PHY * @brief Reset the digital section of the PHY
* *
* @param dev Pointer to the DSI Host controller register base address * @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) static inline void mipi_dsi_phy_ll_reset(dsi_host_dev_t *dev)
{ {
@ -76,14 +78,16 @@ static inline bool mipi_dsi_phy_ll_is_pll_locked(dsi_host_dev_t *dev)
} }
/** /**
* @brief Check if the Lane0 in stop state * @brief Check if the all active lanes are in the stop state
* *
* @param dev Pointer to the DSI Host controller register base address * @param dev Pointer to the DSI Host controller register base address
* @return True if the Lane0 in stop state, False otherwise * @return True if the lanes are all in stop state, False otherwise
*/ */
static inline bool mipi_dsi_phy_ll_is_lane0_stoped(dsi_host_dev_t *dev) static inline bool mipi_dsi_phy_ll_are_lanes_stoped(dsi_host_dev_t *dev)
{ {
return dev->phy_status.phy_stopstate0lane; uint32_t status = dev->phy_status.val;
const uint32_t mask = 1 << 2 | 1 << 4 | 1 << 7;
return (status & mask) == mask;
} }
/** /**

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -30,15 +30,17 @@ typedef struct dsi_brg_dev_t *mipi_dsi_bridge_soc_handle_t;
typedef struct { typedef struct {
mipi_dsi_host_soc_handle_t host; /*!< Pointer to the host controller registers */ 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 */ 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 */ uint32_t lane_bit_rate_mbps; /*!< Lane bit rate in Mbps */
uint32_t dpi_clock_freq_mhz; /*!< DPI clock frequency in MHz */
} mipi_dsi_hal_context_t; } mipi_dsi_hal_context_t;
/** /**
* @brief MIPI DSI HAL driver configuration * @brief MIPI DSI HAL driver configuration
*/ */
typedef struct { typedef struct {
uint32_t lane_byte_clk_hz; /*!< Lane byte clock frequency */ int bus_id; /*!< MIPI DSI bus ID, index from 0 */
uint32_t dpi_clk_hz; /*!< DPI clock frequency */ uint32_t lane_bit_rate_mbps; /*!< Lane bit rate in Mbps */
uint8_t num_data_lanes; /*!< Number of data lanes */
} mipi_dsi_hal_config_t; } mipi_dsi_hal_config_t;
/** /**
@ -51,6 +53,22 @@ typedef struct {
*/ */
void mipi_dsi_hal_init(mipi_dsi_hal_context_t *hal, const mipi_dsi_hal_config_t *config); void mipi_dsi_hal_init(mipi_dsi_hal_context_t *hal, const mipi_dsi_hal_config_t *config);
/**
* @brief Deinitialize MIPI DSI Hal driver context
*
* @param hal Pointer to the HAL driver context
*/
void mipi_dsi_hal_deinit(mipi_dsi_hal_context_t *hal);
/**
* @brief Configure the PHY PLL
*
* @param hal Pointer to the HAL driver context
* @param phy_clk_src_freq_hz PHY clock source frequency in Hz
* @param lane_bit_rate_mbps Lane bit rate in Mbps
*/
void mipi_dsi_hal_configure_phy_pll(mipi_dsi_hal_context_t *hal, uint32_t phy_clk_src_freq_hz, uint32_t lane_bit_rate_mbps);
/** /**
* @brief Write a value to a PHY register via internal bus (so-called test interface) * @brief Write a value to a PHY register via internal bus (so-called test interface)
* *
@ -74,7 +92,7 @@ void mipi_dsi_hal_phy_write_register(mipi_dsi_hal_context_t *hal, uint8_t reg_ad
* @param param_size Number of bytes of 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, 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); 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 * @brief Send a DCS command and return the associated parameters via the generic interface
@ -86,7 +104,8 @@ void mipi_dsi_hal_host_gen_write_dcs_command(mipi_dsi_hal_context_t *hal, uint8_
* @param ret_param Pointer to the buffer to store the returned parameters * @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 * @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); 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 * @brief Send a long packet via the generic interface
@ -97,7 +116,8 @@ void mipi_dsi_hal_host_gen_read_dcs_command(mipi_dsi_hal_context_t *hal, uint8_t
* @param buffer Pointer to the buffer * @param buffer Pointer to the buffer
* @param buffer_size Number of bytes to be sent * @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); 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 * @brief Send a short packet via the generic interface
@ -107,7 +127,8 @@ void mipi_dsi_hal_host_gen_write_long_packet(mipi_dsi_hal_context_t *hal, uint8_
* @param dt Data type * @param dt Data type
* @param header_data Data to be sent, filled into the DSI packet header * @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); 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 * @brief Send a short packet via the generic interface and return the associated data
@ -119,7 +140,8 @@ void mipi_dsi_hal_host_gen_write_short_packet(mipi_dsi_hal_context_t *hal, uint8
* @param ret_buffer Pointer to the buffer to store the returned data * @param ret_buffer Pointer to the buffer to store the returned data
* @param buffer_size Size of 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); 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 * @brief Set DPI color coding
@ -152,6 +174,18 @@ void mipi_dsi_hal_host_dpi_set_horizontal_timing(mipi_dsi_hal_context_t *hal, ui
*/ */
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); 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);
/**
* @brief Calculate the divider for DPI clock
*
* @note This function will also update the real DPI clock frequency in the HAL context
*
* @param hal Pointer to the HAL driver context
* @param clk_src_mhz Clock source frequency in MHz
* @param expect_dpi_clk_mhz Expected DPI clock frequency in MHz
* @return Divider value
*/
uint32_t mipi_dsi_hal_host_dpi_calculate_divider(mipi_dsi_hal_context_t *hal, uint32_t clk_src_mhz, uint32_t expect_dpi_clk_mhz);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -48,20 +48,14 @@ typedef enum {
} __attribute__((packed)) mipi_dsi_data_type_t; } __attribute__((packed)) mipi_dsi_data_type_t;
/** /**
* @brief MIPI DSI packet * @brief The kind of test pattern that can be generated by the DSI Host controller
*/ */
typedef struct { typedef enum {
mipi_dsi_data_type_t dt: 6; /*!< Data Type */ MIPI_DSI_PATTERN_NONE, /*!< No pattern */
uint8_t vc: 2; /*!< Virtual Channel */ MIPI_DSI_PATTERN_BAR_VERTICAL, /*!< Vertical BAR pattern, with different colors */
union { MIPI_DSI_PATTERN_BAR_HORIZONTAL, /*!< Horizontal BAR pattern, with different colors */
uint16_t word_count; /*!< Word count, in bytes */ MIPI_DSI_PATTERN_BER_VERTICAL, /*!< Vertical Bit Error Rate(BER) pattern */
uint8_t data[2]; /*!< Data of short packet */ } mipi_dsi_pattern_type_t;
};
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 #if SOC_MIPI_DSI_SUPPORTED
/** /**

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -8,12 +8,76 @@
#include <sys/param.h> #include <sys/param.h>
#include "hal/mipi_dsi_hal.h" #include "hal/mipi_dsi_hal.h"
#include "hal/mipi_dsi_ll.h" #include "hal/mipi_dsi_ll.h"
#include "hal/assert.h"
#include "hal/log.h"
#include "soc/mipi_dsi_periph.h"
void mipi_dsi_hal_init(mipi_dsi_hal_context_t *hal, const mipi_dsi_hal_config_t *config) void mipi_dsi_hal_init(mipi_dsi_hal_context_t *hal, const mipi_dsi_hal_config_t *config)
{ {
hal->host = &MIPI_DSI_HOST; hal->host = MIPI_DSI_LL_GET_HOST(config->bus_id);
hal->bridge = &MIPI_DSI_BRIDGE; hal->bridge = MIPI_DSI_LL_GET_BRG(config->bus_id);
hal->dpi2lane_clk_ratio = ((float)config->lane_byte_clk_hz) / config->dpi_clk_hz; // set the data lane number
mipi_dsi_phy_ll_set_data_lane_number(hal->host, config->num_data_lanes);
// power on the host controller and PHY
mipi_dsi_host_ll_power_on_off(hal->host, true);
mipi_dsi_phy_ll_power_on_off(hal->host, true);
// reset the PHY and then enable the clock lane
mipi_dsi_phy_ll_reset(hal->host);
mipi_dsi_phy_ll_enable_clock_lane(hal->host, true);
mipi_dsi_phy_ll_force_pll(hal->host, true);
}
void mipi_dsi_hal_deinit(mipi_dsi_hal_context_t *hal)
{
// power off the host controller and PHY
mipi_dsi_phy_ll_power_on_off(hal->host, false);
mipi_dsi_host_ll_power_on_off(hal->host, false);
hal->host = NULL;
hal->bridge = NULL;
}
void mipi_dsi_hal_configure_phy_pll(mipi_dsi_hal_context_t *hal, uint32_t phy_clk_src_freq_hz, uint32_t lane_bit_rate_mbps)
{
// Formula: f_vco = M/N * f_ref
// where the M is Feedback Multiplication Ratio, N is Input Frequency Division Ratio
uint32_t ref_freq_mhz = phy_clk_src_freq_hz / 1000 / 1000;
uint32_t vco_freq_mhz = lane_bit_rate_mbps;
uint8_t pll_N = 1;
uint16_t pll_M = 0;
// 5MHz <= f_ref/N <= 40MHz
uint8_t min_N = MAX(1, ref_freq_mhz / 40);
uint8_t max_N = ref_freq_mhz / 5;
for (uint8_t n = min_N; n <= max_N; n++) {
uint16_t m = vco_freq_mhz * n / ref_freq_mhz;
// M must be even number
if ((m & 0x01) == 0) {
pll_M = m;
pll_N = n;
break;
}
}
HAL_ASSERT(pll_M && pll_N);
// search for the best PLL range
uint8_t hs_freq_sel = 0;
for (size_t i = 0; i < num_of_soc_mipi_dsi_phy_pll_ranges; i++) {
if (lane_bit_rate_mbps >= soc_mipi_dsi_phy_pll_ranges[i].start_mbps &&
lane_bit_rate_mbps <= soc_mipi_dsi_phy_pll_ranges[i].end_mbps) {
hs_freq_sel = soc_mipi_dsi_phy_pll_ranges[i].hs_freq_range_sel;
break;
}
}
mipi_dsi_hal_phy_write_register(hal, 0x44, hs_freq_sel << 1);
// make use of the N and M factors that configured in the 0x17 and 0x18
mipi_dsi_hal_phy_write_register(hal, 0x19, 0x30);
mipi_dsi_hal_phy_write_register(hal, 0x17, pll_N - 1);
mipi_dsi_hal_phy_write_register(hal, 0x18, ((pll_M - 1) & 0x1F));
mipi_dsi_hal_phy_write_register(hal, 0x18, 0x80 | (((pll_M - 1) >> 5) & 0x0F));
// update the real lane bit rate
hal->lane_bit_rate_mbps = ref_freq_mhz * pll_M / pll_N;
HAL_LOGD("dsi_hal", "phy pll: ref=%luHz, lane_bit_rate=%luMbps, M=%d, N=%d, hsfreqrange=%d",
phy_clk_src_freq_hz, hal->lane_bit_rate_mbps, pll_M, pll_N, hs_freq_sel);
} }
void mipi_dsi_hal_phy_write_register(mipi_dsi_hal_context_t *hal, uint8_t reg_addr, uint8_t reg_val) void mipi_dsi_hal_phy_write_register(mipi_dsi_hal_context_t *hal, uint8_t reg_addr, uint8_t reg_val)
@ -110,7 +174,7 @@ void mipi_dsi_hal_host_gen_read_short_packet(mipi_dsi_hal_context_t *hal, uint8_
// set the maximum returned data size, it should equal to the parameter size of the read command // 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); 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 // make sure command mode is on
mipi_dsi_host_ll_dpi_enable_video_mode(hal->host, false); mipi_dsi_host_ll_enable_video_mode(hal->host, false);
// make sure receiving is enabled // make sure receiving is enabled
mipi_dsi_host_ll_enable_bta(hal->host, true); mipi_dsi_host_ll_enable_bta(hal->host, true);
// listen to the same virtual channel as the one sent to // listen to the same virtual channel as the one sent to
@ -142,23 +206,28 @@ void mipi_dsi_hal_host_dpi_set_color_coding(mipi_dsi_hal_context_t *hal, lcd_col
{ {
mipi_dsi_host_ll_dpi_set_color_coding(hal->host, color_coding, 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); 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) 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)
{ {
float dpi2lane_clk_ratio = (float)hal->lane_bit_rate_mbps / hal->dpi_clock_freq_mhz / 8;
mipi_dsi_host_ll_dpi_set_horizontal_timing(hal->host, mipi_dsi_host_ll_dpi_set_horizontal_timing(hal->host,
hsw * hal->dpi2lane_clk_ratio, hsw * dpi2lane_clk_ratio,
hbp * hal->dpi2lane_clk_ratio, hbp * dpi2lane_clk_ratio,
active_width * hal->dpi2lane_clk_ratio, active_width * dpi2lane_clk_ratio,
hfp * hal->dpi2lane_clk_ratio); hfp * dpi2lane_clk_ratio);
mipi_dsi_brg_ll_set_horizontal_timing(hal->bridge, hsw, hbp, active_width, hfp); 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) 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_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); 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 }
uint32_t mipi_dsi_hal_host_dpi_calculate_divider(mipi_dsi_hal_context_t *hal, uint32_t clk_src_mhz, uint32_t expect_dpi_clk_mhz)
{
uint32_t div = clk_src_mhz / expect_dpi_clk_mhz;
hal->dpi_clock_freq_mhz = clk_src_mhz / div;
return div;
} }

View File

@ -75,6 +75,10 @@ if(CONFIG_SOC_LCDCAM_SUPPORTED OR CONFIG_SOC_LCD_I80_SUPPORTED)
list(APPEND srcs "${target}/lcd_periph.c") list(APPEND srcs "${target}/lcd_periph.c")
endif() endif()
if(CONFIG_SOC_MIPI_DSI_SUPPORTED)
list(APPEND srcs "${target}/mipi_dsi_periph.c")
endif()
if(CONFIG_SOC_PARLIO_SUPPORTED) if(CONFIG_SOC_PARLIO_SUPPORTED)
list(APPEND srcs "${target}/parlio_periph.c") list(APPEND srcs "${target}/parlio_periph.c")
endif() endif()

View File

@ -375,7 +375,7 @@ 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_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_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_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 */ MIPI_DSI_PHY_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F20M, /*!< Select PLL_F20M as default clock */
} soc_periph_mipi_dsi_phy_clk_src_t; } soc_periph_mipi_dsi_phy_clk_src_t;
/////////////////////////////////////////////////I2C//////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////I2C////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,51 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/mipi_dsi_periph.h"
const soc_mipi_dsi_phy_pll_freq_range_t soc_mipi_dsi_phy_pll_ranges[] = {
{80, 89, 0x00}, // [80,90) Mbps
{90, 99, 0x10}, // [90,100) Mbps
{100, 109, 0x20}, // [100,110) Mbps
{110, 129, 0x01}, // [110,130) Mbps
{130, 139, 0x11}, // [130,140) Mbps
{140, 149, 0x21}, // [140,150) Mbps
{150, 169, 0x02}, // [150,170) Mbps
{170, 179, 0x12}, // [170,180) Mbps
{180, 199, 0x22}, // [180,200) Mbps
{200, 219, 0x03}, // [200,220) Mbps
{220, 239, 0x13}, // [220,240) Mbps
{240, 249, 0x23}, // [240,250) Mbps
{250, 269, 0x04}, // [250,270) Mbps
{270, 299, 0x14}, // [270,300) Mbps
{300, 329, 0x05}, // [300,330) Mbps
{330, 359, 0x15}, // [330,360) Mbps
{360, 399, 0x25}, // [360,400) Mbps
{400, 449, 0x06}, // [400,450) Mbps
{450, 499, 0x16}, // [450,500) Mbps
{500, 549, 0x07}, // [500,550) Mbps
{550, 599, 0x17}, // [550,600) Mbps
{600, 649, 0x08}, // [600,650) Mbps
{650, 699, 0x18}, // [650,700) Mbps
{700, 749, 0x09}, // [700,750) Mbps
{750, 799, 0x19}, // [750,800) Mbps
{800, 849, 0x29}, // [800,850) Mbps
{850, 899, 0x39}, // [850,900) Mbps
{900, 949, 0x0A}, // [900,950) Mbps
{950, 999, 0x1A}, // [950,1000) Mbps
{1000, 1049, 0x2A}, // [1000,1050) Mbps
{1050, 1099, 0x3A}, // [1050,1100) Mbps
{1100, 1149, 0x0B}, // [1100,1150) Mbps
{1150, 1199, 0x1B}, // [1150,1200) Mbps
{1200, 1249, 0x2B}, // [1200,1250) Mbps
{1250, 1299, 0x3B}, // [1250,1300) Mbps
{1300, 1349, 0x0C}, // [1300,1350) Mbps
{1350, 1399, 0x1C}, // [1350,1400) Mbps
{1400, 1449, 0x2C}, // [1400,1450) Mbps
{1450, 1500, 0x3C}, // [1450,1500] Mbps
};
const size_t num_of_soc_mipi_dsi_phy_pll_ranges = sizeof(soc_mipi_dsi_phy_pll_ranges) / sizeof(soc_mipi_dsi_phy_pll_freq_range_t);

View File

@ -0,0 +1,30 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief MIPI DSI PHY PLL frequency range
*/
typedef struct {
uint32_t start_mbps; /*!< Start frequency of the range (included) */
uint32_t end_mbps; /*!< End frequency of the range (included) */
uint8_t hs_freq_range_sel; /*!< HS operating frequency range selection */
} soc_mipi_dsi_phy_pll_freq_range_t;
extern const soc_mipi_dsi_phy_pll_freq_range_t soc_mipi_dsi_phy_pll_ranges[];
extern const size_t num_of_soc_mipi_dsi_phy_pll_ranges;
#ifdef __cplusplus
}
#endif