feat(mipi_dsi): added DPHY PLL clock configuration

This commit is contained in:
morris
2024-01-16 17:41:46 +08:00
parent ad84b61e49
commit d3ebd6bc1c
11 changed files with 298 additions and 93 deletions
+81 -12
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
*/
@@ -8,12 +8,76 @@
#include <sys/param.h>
#include "hal/mipi_dsi_hal.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)
{
hal->host = &MIPI_DSI_HOST;
hal->bridge = &MIPI_DSI_BRIDGE;
hal->dpi2lane_clk_ratio = ((float)config->lane_byte_clk_hz) / config->dpi_clk_hz;
hal->host = MIPI_DSI_LL_GET_HOST(config->bus_id);
hal->bridge = MIPI_DSI_LL_GET_BRG(config->bus_id);
// 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)
@@ -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
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);
mipi_dsi_host_ll_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
@@ -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_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)
{
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,
hsw * hal->dpi2lane_clk_ratio,
hbp * hal->dpi2lane_clk_ratio,
active_width * hal->dpi2lane_clk_ratio,
hfp * hal->dpi2lane_clk_ratio);
hsw * dpi2lane_clk_ratio,
hbp * dpi2lane_clk_ratio,
active_width * dpi2lane_clk_ratio,
hfp * 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
}
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;
}