|
@@ -1643,14 +1643,12 @@ static int dsi_display_debugfs_deinit(struct dsi_display *display)
|
|
|
static void adjust_timing_by_ctrl_count(const struct dsi_display *display,
|
|
|
struct dsi_display_mode *mode)
|
|
|
{
|
|
|
- if (display->ctrl_count > 1) {
|
|
|
- mode->timing.h_active /= display->ctrl_count;
|
|
|
- mode->timing.h_front_porch /= display->ctrl_count;
|
|
|
- mode->timing.h_sync_width /= display->ctrl_count;
|
|
|
- mode->timing.h_back_porch /= display->ctrl_count;
|
|
|
- mode->timing.h_skew /= display->ctrl_count;
|
|
|
- mode->pixel_clk_khz /= display->ctrl_count;
|
|
|
- }
|
|
|
+ mode->timing.h_active /= display->ctrl_count;
|
|
|
+ mode->timing.h_front_porch /= display->ctrl_count;
|
|
|
+ mode->timing.h_sync_width /= display->ctrl_count;
|
|
|
+ mode->timing.h_back_porch /= display->ctrl_count;
|
|
|
+ mode->timing.h_skew /= display->ctrl_count;
|
|
|
+ mode->pixel_clk_khz /= display->ctrl_count;
|
|
|
}
|
|
|
|
|
|
static int dsi_display_is_ulps_req_valid(struct dsi_display *display,
|
|
@@ -2271,7 +2269,7 @@ static int dsi_display_set_clk_src(struct dsi_display *display)
|
|
|
m_ctrl = &display->ctrl[display->clk_master_idx];
|
|
|
|
|
|
rc = dsi_ctrl_set_clock_source(m_ctrl->ctrl,
|
|
|
- &display->clock_info.src_clks);
|
|
|
+ &display->clock_info.mux_clks);
|
|
|
if (rc) {
|
|
|
pr_err("[%s] failed to set source clocks for master, rc=%d\n",
|
|
|
display->name, rc);
|
|
@@ -2285,7 +2283,7 @@ static int dsi_display_set_clk_src(struct dsi_display *display)
|
|
|
continue;
|
|
|
|
|
|
rc = dsi_ctrl_set_clock_source(ctrl->ctrl,
|
|
|
- &display->clock_info.src_clks);
|
|
|
+ &display->clock_info.mux_clks);
|
|
|
if (rc) {
|
|
|
pr_err("[%s] failed to set source clocks, rc=%d\n",
|
|
|
display->name, rc);
|
|
@@ -2956,6 +2954,7 @@ static int dsi_display_clocks_init(struct dsi_display *display)
|
|
|
struct dsi_clk_link_set *src = &display->clock_info.src_clks;
|
|
|
struct dsi_clk_link_set *mux = &display->clock_info.mux_clks;
|
|
|
struct dsi_clk_link_set *shadow = &display->clock_info.shadow_clks;
|
|
|
+ struct dsi_dyn_clk_caps *dyn_clk_caps = &(display->panel->dyn_clk_caps);
|
|
|
char *dsi_clock_name;
|
|
|
|
|
|
if (!strcmp(display->display_type, "primary"))
|
|
@@ -2978,7 +2977,32 @@ static int dsi_display_clocks_init(struct dsi_display *display)
|
|
|
rc = PTR_ERR(dsi_clk);
|
|
|
|
|
|
pr_err("failed to get %s, rc=%d\n", clk_name, rc);
|
|
|
- goto error;
|
|
|
+
|
|
|
+ if (dsi_display_check_prefix(mux_byte, clk_name)) {
|
|
|
+ mux->byte_clk = NULL;
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ if (dsi_display_check_prefix(mux_pixel, clk_name)) {
|
|
|
+ mux->pixel_clk = NULL;
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dyn_clk_caps->dyn_clk_support) {
|
|
|
+ if (dsi_display_check_prefix(src_byte,
|
|
|
+ clk_name))
|
|
|
+ src->byte_clk = NULL;
|
|
|
+ if (dsi_display_check_prefix(src_pixel,
|
|
|
+ clk_name))
|
|
|
+ src->pixel_clk = NULL;
|
|
|
+ if (dsi_display_check_prefix(shadow_byte,
|
|
|
+ clk_name))
|
|
|
+ shadow->byte_clk = NULL;
|
|
|
+ if (dsi_display_check_prefix(shadow_pixel,
|
|
|
+ clk_name))
|
|
|
+ shadow->pixel_clk = NULL;
|
|
|
+
|
|
|
+ dyn_clk_caps->dyn_clk_support = false;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if (dsi_display_check_prefix(src_byte, clk_name)) {
|
|
@@ -3762,6 +3786,305 @@ static bool dsi_display_is_seamless_dfps_possible(
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+static int dsi_display_update_dsi_bitrate(struct dsi_display *display,
|
|
|
+ u32 bit_clk_rate)
|
|
|
+{
|
|
|
+ int rc = 0;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ pr_debug("%s:bit rate:%d\n", __func__, bit_clk_rate);
|
|
|
+ if (!display->panel) {
|
|
|
+ pr_err("Invalid params\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (bit_clk_rate == 0) {
|
|
|
+ pr_err("Invalid bit clock rate\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ display->config.bit_clk_rate_hz = bit_clk_rate;
|
|
|
+
|
|
|
+ for (i = 0; i < display->ctrl_count; i++) {
|
|
|
+ struct dsi_display_ctrl *dsi_disp_ctrl = &display->ctrl[i];
|
|
|
+ struct dsi_ctrl *ctrl = dsi_disp_ctrl->ctrl;
|
|
|
+ u32 num_of_lanes = 0, bpp;
|
|
|
+ u64 bit_rate, pclk_rate, bit_rate_per_lane, byte_clk_rate;
|
|
|
+ struct dsi_host_common_cfg *host_cfg;
|
|
|
+
|
|
|
+ mutex_lock(&ctrl->ctrl_lock);
|
|
|
+
|
|
|
+ host_cfg = &display->panel->host_config;
|
|
|
+ if (host_cfg->data_lanes & DSI_DATA_LANE_0)
|
|
|
+ num_of_lanes++;
|
|
|
+ if (host_cfg->data_lanes & DSI_DATA_LANE_1)
|
|
|
+ num_of_lanes++;
|
|
|
+ if (host_cfg->data_lanes & DSI_DATA_LANE_2)
|
|
|
+ num_of_lanes++;
|
|
|
+ if (host_cfg->data_lanes & DSI_DATA_LANE_3)
|
|
|
+ num_of_lanes++;
|
|
|
+
|
|
|
+ if (num_of_lanes == 0) {
|
|
|
+ pr_err("Invalid lane count\n");
|
|
|
+ rc = -EINVAL;
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+
|
|
|
+ bpp = dsi_pixel_format_to_bpp(host_cfg->dst_format);
|
|
|
+
|
|
|
+ bit_rate = display->config.bit_clk_rate_hz * num_of_lanes;
|
|
|
+ bit_rate_per_lane = bit_rate;
|
|
|
+ do_div(bit_rate_per_lane, num_of_lanes);
|
|
|
+ pclk_rate = bit_rate;
|
|
|
+ do_div(pclk_rate, bpp);
|
|
|
+ byte_clk_rate = bit_rate_per_lane;
|
|
|
+ do_div(byte_clk_rate, 8);
|
|
|
+ pr_debug("bit_clk_rate = %llu, bit_clk_rate_per_lane = %llu\n",
|
|
|
+ bit_rate, bit_rate_per_lane);
|
|
|
+ pr_debug("byte_clk_rate = %llu, pclk_rate = %llu\n",
|
|
|
+ byte_clk_rate, pclk_rate);
|
|
|
+
|
|
|
+ ctrl->clk_freq.byte_clk_rate = byte_clk_rate;
|
|
|
+ ctrl->clk_freq.pix_clk_rate = pclk_rate;
|
|
|
+ rc = dsi_clk_set_link_frequencies(display->dsi_clk_handle,
|
|
|
+ ctrl->clk_freq, ctrl->cell_index);
|
|
|
+ if (rc) {
|
|
|
+ pr_err("Failed to update link frequencies\n");
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+
|
|
|
+ ctrl->host_config.bit_clk_rate_hz = bit_clk_rate;
|
|
|
+error:
|
|
|
+ mutex_unlock(&ctrl->ctrl_lock);
|
|
|
+
|
|
|
+ /* TODO: recover ctrl->clk_freq in case of failure */
|
|
|
+ if (rc)
|
|
|
+ return rc;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void _dsi_display_calc_pipe_delay(struct dsi_display *display,
|
|
|
+ struct dsi_dyn_clk_delay *delay,
|
|
|
+ struct dsi_display_mode *mode)
|
|
|
+{
|
|
|
+ u32 esc_clk_rate_hz;
|
|
|
+ u32 pclk_to_esc_ratio, byte_to_esc_ratio, hr_bit_to_esc_ratio;
|
|
|
+ u32 hsync_period = 0;
|
|
|
+ struct dsi_display_ctrl *m_ctrl;
|
|
|
+ struct dsi_ctrl *dsi_ctrl;
|
|
|
+ struct dsi_phy_cfg *cfg;
|
|
|
+
|
|
|
+ m_ctrl = &display->ctrl[display->clk_master_idx];
|
|
|
+ dsi_ctrl = m_ctrl->ctrl;
|
|
|
+
|
|
|
+ cfg = &(m_ctrl->phy->cfg);
|
|
|
+
|
|
|
+ esc_clk_rate_hz = dsi_ctrl->clk_freq.esc_clk_rate * 1000;
|
|
|
+ pclk_to_esc_ratio = ((dsi_ctrl->clk_freq.pix_clk_rate * 1000) /
|
|
|
+ esc_clk_rate_hz);
|
|
|
+ byte_to_esc_ratio = ((dsi_ctrl->clk_freq.byte_clk_rate * 1000) /
|
|
|
+ esc_clk_rate_hz);
|
|
|
+ hr_bit_to_esc_ratio = ((dsi_ctrl->clk_freq.byte_clk_rate * 4 * 1000) /
|
|
|
+ esc_clk_rate_hz);
|
|
|
+
|
|
|
+ hsync_period = DSI_H_TOTAL_DSC(&mode->timing);
|
|
|
+ delay->pipe_delay = (hsync_period + 1) / pclk_to_esc_ratio;
|
|
|
+ if (!display->panel->video_config.eof_bllp_lp11_en)
|
|
|
+ delay->pipe_delay += (17 / pclk_to_esc_ratio) +
|
|
|
+ ((21 + (display->config.common_config.t_clk_pre + 1) +
|
|
|
+ (display->config.common_config.t_clk_post + 1)) /
|
|
|
+ byte_to_esc_ratio) +
|
|
|
+ ((((cfg->timing.lane_v3[8] >> 1) + 1) +
|
|
|
+ ((cfg->timing.lane_v3[6] >> 1) + 1) +
|
|
|
+ ((cfg->timing.lane_v3[3] * 4) +
|
|
|
+ (cfg->timing.lane_v3[5] >> 1) + 1) +
|
|
|
+ ((cfg->timing.lane_v3[7] >> 1) + 1) +
|
|
|
+ ((cfg->timing.lane_v3[1] >> 1) + 1) +
|
|
|
+ ((cfg->timing.lane_v3[4] >> 1) + 1)) /
|
|
|
+ hr_bit_to_esc_ratio);
|
|
|
+
|
|
|
+ delay->pipe_delay2 = 0;
|
|
|
+ if (display->panel->host_config.force_hs_clk_lane)
|
|
|
+ delay->pipe_delay2 = (6 / byte_to_esc_ratio) +
|
|
|
+ ((((cfg->timing.lane_v3[1] >> 1) + 1) +
|
|
|
+ ((cfg->timing.lane_v3[4] >> 1) + 1)) /
|
|
|
+ hr_bit_to_esc_ratio);
|
|
|
+
|
|
|
+ /* 130 us pll delay recommended by h/w doc */
|
|
|
+ delay->pll_delay = ((130 * esc_clk_rate_hz) / 1000000) * 2;
|
|
|
+}
|
|
|
+
|
|
|
+static int _dsi_display_dyn_update_clks(struct dsi_display *display,
|
|
|
+ struct link_clk_freq *bkp_freq)
|
|
|
+{
|
|
|
+ int rc = 0, i;
|
|
|
+ struct dsi_display_ctrl *m_ctrl, *ctrl;
|
|
|
+
|
|
|
+ m_ctrl = &display->ctrl[display->clk_master_idx];
|
|
|
+
|
|
|
+ dsi_clk_prepare_enable(&display->clock_info.src_clks);
|
|
|
+
|
|
|
+ rc = dsi_clk_update_parent(&display->clock_info.shadow_clks,
|
|
|
+ &display->clock_info.mux_clks);
|
|
|
+ if (rc) {
|
|
|
+ pr_err("failed update mux parent to shadow\n");
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; (i < display->ctrl_count) &&
|
|
|
+ (i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
|
|
|
+ ctrl = &display->ctrl[i];
|
|
|
+ if (!ctrl->ctrl)
|
|
|
+ continue;
|
|
|
+ rc = dsi_clk_set_byte_clk_rate(display->dsi_clk_handle,
|
|
|
+ ctrl->ctrl->clk_freq.byte_clk_rate, i);
|
|
|
+ if (rc) {
|
|
|
+ pr_err("failed to set byte rate for index:%d\n", i);
|
|
|
+ goto recover_byte_clk;
|
|
|
+ }
|
|
|
+ rc = dsi_clk_set_pixel_clk_rate(display->dsi_clk_handle,
|
|
|
+ ctrl->ctrl->clk_freq.pix_clk_rate, i);
|
|
|
+ if (rc) {
|
|
|
+ pr_err("failed to set pix rate for index:%d\n", i);
|
|
|
+ goto recover_pix_clk;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; (i < display->ctrl_count) &&
|
|
|
+ (i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
|
|
|
+ ctrl = &display->ctrl[i];
|
|
|
+ if (ctrl == m_ctrl)
|
|
|
+ continue;
|
|
|
+ dsi_phy_dynamic_refresh_trigger(ctrl->phy, false);
|
|
|
+ }
|
|
|
+ dsi_phy_dynamic_refresh_trigger(m_ctrl->phy, true);
|
|
|
+
|
|
|
+ /* wait for dynamic refresh done */
|
|
|
+ for (i = 0; (i < display->ctrl_count) &&
|
|
|
+ (i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
|
|
|
+ ctrl = &display->ctrl[i];
|
|
|
+ rc = dsi_ctrl_wait4dynamic_refresh_done(ctrl->ctrl);
|
|
|
+ if (rc) {
|
|
|
+ pr_err("wait4dynamic refresh failed for dsi:%d\n", i);
|
|
|
+ goto recover_pix_clk;
|
|
|
+ } else {
|
|
|
+ pr_info("dynamic refresh done on dsi: %s\n",
|
|
|
+ i ? "slave" : "master");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; (i < display->ctrl_count) &&
|
|
|
+ (i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
|
|
|
+ ctrl = &display->ctrl[i];
|
|
|
+ dsi_phy_dynamic_refresh_clear(ctrl->phy);
|
|
|
+ }
|
|
|
+
|
|
|
+ rc = dsi_clk_update_parent(&display->clock_info.src_clks,
|
|
|
+ &display->clock_info.mux_clks);
|
|
|
+ if (rc)
|
|
|
+ pr_err("could not switch back to src clks %d\n", rc);
|
|
|
+
|
|
|
+ dsi_clk_disable_unprepare(&display->clock_info.src_clks);
|
|
|
+
|
|
|
+ return rc;
|
|
|
+
|
|
|
+recover_pix_clk:
|
|
|
+ for (i = 0; (i < display->ctrl_count) &&
|
|
|
+ (i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
|
|
|
+ ctrl = &display->ctrl[i];
|
|
|
+ if (!ctrl->ctrl)
|
|
|
+ continue;
|
|
|
+ dsi_clk_set_pixel_clk_rate(display->dsi_clk_handle,
|
|
|
+ bkp_freq->pix_clk_rate, i);
|
|
|
+ }
|
|
|
+
|
|
|
+recover_byte_clk:
|
|
|
+ for (i = 0; (i < display->ctrl_count) &&
|
|
|
+ (i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
|
|
|
+ ctrl = &display->ctrl[i];
|
|
|
+ if (!ctrl->ctrl)
|
|
|
+ continue;
|
|
|
+ dsi_clk_set_byte_clk_rate(display->dsi_clk_handle,
|
|
|
+ bkp_freq->byte_clk_rate, i);
|
|
|
+ }
|
|
|
+
|
|
|
+exit:
|
|
|
+ dsi_clk_disable_unprepare(&display->clock_info.src_clks);
|
|
|
+
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+static int dsi_display_dynamic_clk_switch(struct dsi_display *display,
|
|
|
+ struct dsi_display_mode *mode)
|
|
|
+{
|
|
|
+ int rc = 0, mask, i;
|
|
|
+ struct dsi_display_ctrl *m_ctrl, *ctrl;
|
|
|
+ struct dsi_dyn_clk_delay delay;
|
|
|
+ struct link_clk_freq bkp_freq;
|
|
|
+
|
|
|
+ dsi_panel_acquire_panel_lock(display->panel);
|
|
|
+
|
|
|
+ m_ctrl = &display->ctrl[display->clk_master_idx];
|
|
|
+
|
|
|
+ dsi_display_clk_ctrl(display->dsi_clk_handle, DSI_ALL_CLKS, DSI_CLK_ON);
|
|
|
+
|
|
|
+ /* mask PLL unlock, FIFO overflow and underflow errors */
|
|
|
+ mask = BIT(DSI_PLL_UNLOCK_ERR) | BIT(DSI_FIFO_UNDERFLOW) |
|
|
|
+ BIT(DSI_FIFO_OVERFLOW);
|
|
|
+ dsi_display_mask_ctrl_error_interrupts(display, mask, true);
|
|
|
+
|
|
|
+ /* update the phy timings based on new mode */
|
|
|
+ for (i = 0; i < display->ctrl_count; i++) {
|
|
|
+ ctrl = &display->ctrl[i];
|
|
|
+ dsi_phy_update_phy_timings(ctrl->phy, &display->config);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* back up existing rates to handle failure case */
|
|
|
+ bkp_freq.byte_clk_rate = m_ctrl->ctrl->clk_freq.byte_clk_rate;
|
|
|
+ bkp_freq.pix_clk_rate = m_ctrl->ctrl->clk_freq.pix_clk_rate;
|
|
|
+ bkp_freq.esc_clk_rate = m_ctrl->ctrl->clk_freq.esc_clk_rate;
|
|
|
+
|
|
|
+ rc = dsi_display_update_dsi_bitrate(display, mode->timing.clk_rate_hz);
|
|
|
+ if (rc) {
|
|
|
+ pr_err("failed set link frequencies %d\n", rc);
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* calculate pipe delays */
|
|
|
+ _dsi_display_calc_pipe_delay(display, &delay, mode);
|
|
|
+
|
|
|
+ /* configure dynamic refresh ctrl registers */
|
|
|
+ for (i = 0; i < display->ctrl_count; i++) {
|
|
|
+ ctrl = &display->ctrl[i];
|
|
|
+ if (!ctrl->phy)
|
|
|
+ continue;
|
|
|
+ if (ctrl == m_ctrl)
|
|
|
+ dsi_phy_config_dynamic_refresh(ctrl->phy, &delay, true);
|
|
|
+ else
|
|
|
+ dsi_phy_config_dynamic_refresh(ctrl->phy, &delay,
|
|
|
+ false);
|
|
|
+ }
|
|
|
+
|
|
|
+ rc = _dsi_display_dyn_update_clks(display, &bkp_freq);
|
|
|
+
|
|
|
+exit:
|
|
|
+ dsi_display_mask_ctrl_error_interrupts(display, mask, false);
|
|
|
+
|
|
|
+ dsi_display_clk_ctrl(display->dsi_clk_handle, DSI_ALL_CLKS,
|
|
|
+ DSI_CLK_OFF);
|
|
|
+
|
|
|
+ /* store newly calculated phy timings in mode private info */
|
|
|
+ dsi_phy_dyn_refresh_cache_phy_timings(m_ctrl->phy,
|
|
|
+ mode->priv_info->phy_timing_val,
|
|
|
+ mode->priv_info->phy_timing_len);
|
|
|
+
|
|
|
+ dsi_panel_release_panel_lock(display->panel);
|
|
|
+
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
static int dsi_display_dfps_update(struct dsi_display *display,
|
|
|
struct dsi_display_mode *dsi_mode)
|
|
|
{
|
|
@@ -4031,6 +4354,16 @@ static int dsi_display_set_mode_sub(struct dsi_display *display,
|
|
|
display->name, rc);
|
|
|
goto error;
|
|
|
}
|
|
|
+ } else if (mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK) {
|
|
|
+ rc = dsi_display_dynamic_clk_switch(display, mode);
|
|
|
+ if (rc)
|
|
|
+ pr_err("dynamic clk change failed %d\n", rc);
|
|
|
+ /*
|
|
|
+ * skip rest of the opearations since
|
|
|
+ * dsi_display_dynamic_clk_switch() already takes
|
|
|
+ * care of them.
|
|
|
+ */
|
|
|
+ return rc;
|
|
|
}
|
|
|
|
|
|
display_for_each_ctrl(i, display) {
|
|
@@ -4261,208 +4594,6 @@ static int dsi_display_force_update_dsi_clk(struct dsi_display *display)
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
-static int dsi_display_request_update_dsi_bitrate(struct dsi_display *display,
|
|
|
- u32 bit_clk_rate)
|
|
|
-{
|
|
|
- int rc = 0;
|
|
|
- int i;
|
|
|
-
|
|
|
- pr_debug("%s:bit rate:%d\n", __func__, bit_clk_rate);
|
|
|
- if (!display->panel) {
|
|
|
- pr_err("Invalid params\n");
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- if (bit_clk_rate == 0) {
|
|
|
- pr_err("Invalid bit clock rate\n");
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- display->config.bit_clk_rate_hz_override = bit_clk_rate;
|
|
|
-
|
|
|
- display_for_each_ctrl(i, display) {
|
|
|
- struct dsi_display_ctrl *dsi_disp_ctrl = &display->ctrl[i];
|
|
|
- struct dsi_ctrl *ctrl = dsi_disp_ctrl->ctrl;
|
|
|
- u32 num_of_lanes = 0;
|
|
|
- u32 bpp = 3;
|
|
|
- u64 bit_rate, pclk_rate, bit_rate_per_lane, byte_clk_rate;
|
|
|
- struct dsi_host_common_cfg *host_cfg;
|
|
|
-
|
|
|
- mutex_lock(&ctrl->ctrl_lock);
|
|
|
-
|
|
|
- host_cfg = &display->panel->host_config;
|
|
|
- if (host_cfg->data_lanes & DSI_DATA_LANE_0)
|
|
|
- num_of_lanes++;
|
|
|
- if (host_cfg->data_lanes & DSI_DATA_LANE_1)
|
|
|
- num_of_lanes++;
|
|
|
- if (host_cfg->data_lanes & DSI_DATA_LANE_2)
|
|
|
- num_of_lanes++;
|
|
|
- if (host_cfg->data_lanes & DSI_DATA_LANE_3)
|
|
|
- num_of_lanes++;
|
|
|
-
|
|
|
- if (num_of_lanes == 0) {
|
|
|
- pr_err("Invalid lane count\n");
|
|
|
- rc = -EINVAL;
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- bit_rate = display->config.bit_clk_rate_hz_override *
|
|
|
- num_of_lanes;
|
|
|
- bit_rate_per_lane = bit_rate;
|
|
|
- do_div(bit_rate_per_lane, num_of_lanes);
|
|
|
- pclk_rate = bit_rate;
|
|
|
- do_div(pclk_rate, (8 * bpp));
|
|
|
- byte_clk_rate = bit_rate_per_lane;
|
|
|
- do_div(byte_clk_rate, 8);
|
|
|
- pr_debug("bit_clk_rate = %llu, bit_clk_rate_per_lane = %llu\n",
|
|
|
- bit_rate, bit_rate_per_lane);
|
|
|
- pr_debug("byte_clk_rate = %llu, pclk_rate = %llu\n",
|
|
|
- byte_clk_rate, pclk_rate);
|
|
|
-
|
|
|
- ctrl->clk_freq.byte_clk_rate = byte_clk_rate;
|
|
|
- ctrl->clk_freq.pix_clk_rate = pclk_rate;
|
|
|
- rc = dsi_clk_set_link_frequencies(display->dsi_clk_handle,
|
|
|
- ctrl->clk_freq, ctrl->cell_index);
|
|
|
- if (rc) {
|
|
|
- pr_err("Failed to update link frequencies\n");
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- ctrl->host_config.bit_clk_rate_hz_override = bit_clk_rate;
|
|
|
-error:
|
|
|
- mutex_unlock(&ctrl->ctrl_lock);
|
|
|
-
|
|
|
- /* TODO: recover ctrl->clk_freq in case of failure */
|
|
|
- if (rc)
|
|
|
- return rc;
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static ssize_t dynamic_dsi_clock_show(struct device *dev,
|
|
|
- struct device_attribute *attr, char *buf)
|
|
|
-{
|
|
|
- int rc = 0;
|
|
|
- struct dsi_display *display;
|
|
|
- struct dsi_display_ctrl *m_ctrl;
|
|
|
- struct dsi_ctrl *ctrl;
|
|
|
-
|
|
|
- display = dev_get_drvdata(dev);
|
|
|
- if (!display) {
|
|
|
- pr_err("Invalid display\n");
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- mutex_lock(&display->display_lock);
|
|
|
-
|
|
|
- m_ctrl = &display->ctrl[display->cmd_master_idx];
|
|
|
- ctrl = m_ctrl->ctrl;
|
|
|
- if (ctrl)
|
|
|
- display->cached_clk_rate = ctrl->clk_freq.byte_clk_rate
|
|
|
- * 8;
|
|
|
-
|
|
|
- rc = snprintf(buf, PAGE_SIZE, "%d\n", display->cached_clk_rate);
|
|
|
- pr_debug("%s: read dsi clk rate %d\n", __func__,
|
|
|
- display->cached_clk_rate);
|
|
|
-
|
|
|
- mutex_unlock(&display->display_lock);
|
|
|
-
|
|
|
- return rc;
|
|
|
-}
|
|
|
-
|
|
|
-static ssize_t dynamic_dsi_clock_store(struct device *dev,
|
|
|
- struct device_attribute *attr, const char *buf, size_t count)
|
|
|
-{
|
|
|
- int rc = 0;
|
|
|
- int clk_rate;
|
|
|
- struct dsi_display *display;
|
|
|
-
|
|
|
- display = dev_get_drvdata(dev);
|
|
|
- if (!display) {
|
|
|
- pr_err("Invalid display\n");
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- rc = kstrtoint(buf, DSI_CLOCK_BITRATE_RADIX, &clk_rate);
|
|
|
- if (rc) {
|
|
|
- pr_err("%s: kstrtoint failed. rc=%d\n", __func__, rc);
|
|
|
- return rc;
|
|
|
- }
|
|
|
-
|
|
|
- if (clk_rate <= 0) {
|
|
|
- pr_err("%s: bitrate should be greater than 0\n", __func__);
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- if (clk_rate == display->cached_clk_rate) {
|
|
|
- pr_info("%s: ignore duplicated DSI clk setting\n", __func__);
|
|
|
- return count;
|
|
|
- }
|
|
|
-
|
|
|
- pr_info("%s: bitrate param value: '%d'\n", __func__, clk_rate);
|
|
|
-
|
|
|
- mutex_lock(&display->display_lock);
|
|
|
-
|
|
|
- display->cached_clk_rate = clk_rate;
|
|
|
- rc = dsi_display_request_update_dsi_bitrate(display, clk_rate);
|
|
|
- if (!rc) {
|
|
|
- pr_info("%s: bit clk is ready to be configured to '%d'\n",
|
|
|
- __func__, clk_rate);
|
|
|
- } else {
|
|
|
- pr_err("%s: Failed to prepare to configure '%d'. rc = %d\n",
|
|
|
- __func__, clk_rate, rc);
|
|
|
- /*Caching clock failed, so don't go on doing so.*/
|
|
|
- atomic_set(&display->clkrate_change_pending, 0);
|
|
|
- display->cached_clk_rate = 0;
|
|
|
-
|
|
|
- mutex_unlock(&display->display_lock);
|
|
|
-
|
|
|
- return rc;
|
|
|
- }
|
|
|
- atomic_set(&display->clkrate_change_pending, 1);
|
|
|
-
|
|
|
- mutex_unlock(&display->display_lock);
|
|
|
-
|
|
|
- return count;
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-static DEVICE_ATTR_RW(dynamic_dsi_clock);
|
|
|
-
|
|
|
-static struct attribute *dynamic_dsi_clock_fs_attrs[] = {
|
|
|
- &dev_attr_dynamic_dsi_clock.attr,
|
|
|
- NULL,
|
|
|
-};
|
|
|
-static struct attribute_group dynamic_dsi_clock_fs_attrs_group = {
|
|
|
- .attrs = dynamic_dsi_clock_fs_attrs,
|
|
|
-};
|
|
|
-
|
|
|
-static int dsi_display_sysfs_init(struct dsi_display *display)
|
|
|
-{
|
|
|
- int rc = 0;
|
|
|
- struct device *dev = &display->pdev->dev;
|
|
|
-
|
|
|
- if (display->panel->panel_mode == DSI_OP_CMD_MODE)
|
|
|
- rc = sysfs_create_group(&dev->kobj,
|
|
|
- &dynamic_dsi_clock_fs_attrs_group);
|
|
|
-
|
|
|
- return rc;
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-static int dsi_display_sysfs_deinit(struct dsi_display *display)
|
|
|
-{
|
|
|
- struct device *dev = &display->pdev->dev;
|
|
|
-
|
|
|
- if (display->panel->panel_mode == DSI_OP_CMD_MODE)
|
|
|
- sysfs_remove_group(&dev->kobj,
|
|
|
- &dynamic_dsi_clock_fs_attrs_group);
|
|
|
-
|
|
|
- return 0;
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
/**
|
|
|
* dsi_display_bind - bind dsi device with controlling device
|
|
|
* @dev: Pointer to base of platform device
|
|
@@ -4514,12 +4645,6 @@ static int dsi_display_bind(struct device *dev,
|
|
|
atomic_set(&display->clkrate_change_pending, 0);
|
|
|
display->cached_clk_rate = 0;
|
|
|
|
|
|
- rc = dsi_display_sysfs_init(display);
|
|
|
- if (rc) {
|
|
|
- pr_err("[%s] sysfs init failed, rc=%d\n", display->name, rc);
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
memset(&info, 0x0, sizeof(info));
|
|
|
|
|
|
display_for_each_ctrl(i, display) {
|
|
@@ -4665,7 +4790,6 @@ error_ctrl_deinit:
|
|
|
(void)dsi_phy_drv_deinit(display_ctrl->phy);
|
|
|
(void)dsi_ctrl_drv_deinit(display_ctrl->ctrl);
|
|
|
}
|
|
|
- (void)dsi_display_sysfs_deinit(display);
|
|
|
(void)dsi_display_debugfs_deinit(display);
|
|
|
error:
|
|
|
mutex_unlock(&display->display_lock);
|
|
@@ -4725,7 +4849,6 @@ static void dsi_display_unbind(struct device *dev,
|
|
|
}
|
|
|
|
|
|
atomic_set(&display->clkrate_change_pending, 0);
|
|
|
- (void)dsi_display_sysfs_deinit(display);
|
|
|
(void)dsi_display_debugfs_deinit(display);
|
|
|
|
|
|
mutex_unlock(&display->display_lock);
|
|
@@ -5480,7 +5603,8 @@ static int dsi_display_get_mode_count_no_lock(struct dsi_display *display,
|
|
|
u32 *count)
|
|
|
{
|
|
|
struct dsi_dfps_capabilities dfps_caps;
|
|
|
- int num_dfps_rates, rc = 0;
|
|
|
+ struct dsi_dyn_clk_caps *dyn_clk_caps;
|
|
|
+ int num_dfps_rates, num_bit_clks, rc = 0;
|
|
|
|
|
|
if (!display || !display->panel) {
|
|
|
pr_err("invalid display:%d panel:%d\n", display != NULL,
|
|
@@ -5497,12 +5621,16 @@ static int dsi_display_get_mode_count_no_lock(struct dsi_display *display,
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
- num_dfps_rates = !dfps_caps.dfps_support ? 1 :
|
|
|
- dfps_caps.max_refresh_rate -
|
|
|
- dfps_caps.min_refresh_rate + 1;
|
|
|
+ num_dfps_rates = !dfps_caps.dfps_support ? 1 : dfps_caps.dfps_list_len;
|
|
|
|
|
|
- /* Inflate num_of_modes by fps in dfps */
|
|
|
- *count = display->panel->num_timing_nodes * num_dfps_rates;
|
|
|
+ dyn_clk_caps = &(display->panel->dyn_clk_caps);
|
|
|
+
|
|
|
+ num_bit_clks = !dyn_clk_caps->dyn_clk_support ? 1 :
|
|
|
+ dyn_clk_caps->bit_clk_list_len;
|
|
|
+
|
|
|
+ /* Inflate num_of_modes by fps and bit clks in dfps */
|
|
|
+ *count = display->panel->num_timing_nodes *
|
|
|
+ num_dfps_rates * num_bit_clks;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -5525,6 +5653,73 @@ int dsi_display_get_mode_count(struct dsi_display *display,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static void _dsi_display_populate_bit_clks(struct dsi_display *display,
|
|
|
+ int start, int end, u32 *mode_idx)
|
|
|
+{
|
|
|
+ struct dsi_dyn_clk_caps *dyn_clk_caps;
|
|
|
+ struct dsi_display_mode *src, *dst;
|
|
|
+ struct dsi_host_common_cfg *cfg;
|
|
|
+ int i, j, total_modes, bpp, lanes = 0;
|
|
|
+
|
|
|
+ if (!display || !mode_idx)
|
|
|
+ return;
|
|
|
+
|
|
|
+ dyn_clk_caps = &(display->panel->dyn_clk_caps);
|
|
|
+ if (!dyn_clk_caps->dyn_clk_support)
|
|
|
+ return;
|
|
|
+
|
|
|
+ cfg = &(display->panel->host_config);
|
|
|
+ bpp = dsi_pixel_format_to_bpp(cfg->dst_format);
|
|
|
+
|
|
|
+ if (cfg->data_lanes & DSI_DATA_LANE_0)
|
|
|
+ lanes++;
|
|
|
+ if (cfg->data_lanes & DSI_DATA_LANE_1)
|
|
|
+ lanes++;
|
|
|
+ if (cfg->data_lanes & DSI_DATA_LANE_2)
|
|
|
+ lanes++;
|
|
|
+ if (cfg->data_lanes & DSI_DATA_LANE_3)
|
|
|
+ lanes++;
|
|
|
+
|
|
|
+ dsi_display_get_mode_count_no_lock(display, &total_modes);
|
|
|
+
|
|
|
+ for (i = start; i < end; i++) {
|
|
|
+ src = &display->modes[i];
|
|
|
+ if (!src)
|
|
|
+ return;
|
|
|
+ /*
|
|
|
+ * TODO: currently setting the first bit rate in
|
|
|
+ * the list as preferred rate. But ideally should
|
|
|
+ * be based on user or device tree preferrence.
|
|
|
+ */
|
|
|
+ src->timing.clk_rate_hz = dyn_clk_caps->bit_clk_list[0];
|
|
|
+ src->pixel_clk_khz =
|
|
|
+ div_u64(src->timing.clk_rate_hz * lanes, bpp);
|
|
|
+ src->pixel_clk_khz /= 1000;
|
|
|
+ src->pixel_clk_khz *= display->ctrl_count;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 1; i < dyn_clk_caps->bit_clk_list_len; i++) {
|
|
|
+ if (*mode_idx >= total_modes)
|
|
|
+ return;
|
|
|
+ for (j = start; j < end; j++) {
|
|
|
+ src = &display->modes[j];
|
|
|
+ dst = &display->modes[*mode_idx];
|
|
|
+
|
|
|
+ if (!src || !dst) {
|
|
|
+ pr_err("invalid mode index\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ memcpy(dst, src, sizeof(struct dsi_display_mode));
|
|
|
+ dst->timing.clk_rate_hz = dyn_clk_caps->bit_clk_list[i];
|
|
|
+ dst->pixel_clk_khz =
|
|
|
+ div_u64(dst->timing.clk_rate_hz * lanes, bpp);
|
|
|
+ dst->pixel_clk_khz /= 1000;
|
|
|
+ dst->pixel_clk_khz *= display->ctrl_count;
|
|
|
+ (*mode_idx)++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
void dsi_display_put_mode(struct dsi_display *display,
|
|
|
struct dsi_display_mode *mode)
|
|
|
{
|
|
@@ -5537,7 +5732,8 @@ int dsi_display_get_modes(struct dsi_display *display,
|
|
|
struct dsi_dfps_capabilities dfps_caps;
|
|
|
u32 num_dfps_rates, panel_mode_count, total_mode_count;
|
|
|
u32 mode_idx, array_idx = 0;
|
|
|
- int i, rc = -EINVAL;
|
|
|
+ struct dsi_dyn_clk_caps *dyn_clk_caps;
|
|
|
+ int i, start, end, rc = -EINVAL;
|
|
|
|
|
|
if (!display || !out_modes) {
|
|
|
pr_err("Invalid params\n");
|
|
@@ -5569,9 +5765,9 @@ int dsi_display_get_modes(struct dsi_display *display,
|
|
|
goto error;
|
|
|
}
|
|
|
|
|
|
- num_dfps_rates = !dfps_caps.dfps_support ? 1 :
|
|
|
- dfps_caps.max_refresh_rate -
|
|
|
- dfps_caps.min_refresh_rate + 1;
|
|
|
+ dyn_clk_caps = &(display->panel->dyn_clk_caps);
|
|
|
+
|
|
|
+ num_dfps_rates = !dfps_caps.dfps_support ? 1 : dfps_caps.dfps_list_len;
|
|
|
|
|
|
panel_mode_count = display->panel->num_timing_nodes;
|
|
|
|
|
@@ -5609,14 +5805,14 @@ int dsi_display_get_modes(struct dsi_display *display,
|
|
|
panel_mode.timing.dsi_transfer_time_us;
|
|
|
}
|
|
|
|
|
|
- if (display->ctrl_count > 1) { /* TODO: remove if */
|
|
|
- panel_mode.timing.h_active *= display->ctrl_count;
|
|
|
- panel_mode.timing.h_front_porch *= display->ctrl_count;
|
|
|
- panel_mode.timing.h_sync_width *= display->ctrl_count;
|
|
|
- panel_mode.timing.h_back_porch *= display->ctrl_count;
|
|
|
- panel_mode.timing.h_skew *= display->ctrl_count;
|
|
|
- panel_mode.pixel_clk_khz *= display->ctrl_count;
|
|
|
- }
|
|
|
+ panel_mode.timing.h_active *= display->ctrl_count;
|
|
|
+ panel_mode.timing.h_front_porch *= display->ctrl_count;
|
|
|
+ panel_mode.timing.h_sync_width *= display->ctrl_count;
|
|
|
+ panel_mode.timing.h_back_porch *= display->ctrl_count;
|
|
|
+ panel_mode.timing.h_skew *= display->ctrl_count;
|
|
|
+ panel_mode.pixel_clk_khz *= display->ctrl_count;
|
|
|
+
|
|
|
+ start = array_idx;
|
|
|
|
|
|
for (i = 0; i < num_dfps_rates; i++) {
|
|
|
struct dsi_display_mode *sub_mode =
|
|
@@ -5630,24 +5826,23 @@ int dsi_display_get_modes(struct dsi_display *display,
|
|
|
}
|
|
|
|
|
|
memcpy(sub_mode, &panel_mode, sizeof(panel_mode));
|
|
|
+ array_idx++;
|
|
|
|
|
|
- if (dfps_caps.dfps_support) {
|
|
|
- curr_refresh_rate =
|
|
|
- sub_mode->timing.refresh_rate;
|
|
|
- sub_mode->timing.refresh_rate =
|
|
|
- dfps_caps.min_refresh_rate +
|
|
|
- (i % num_dfps_rates);
|
|
|
+ if (!dfps_caps.dfps_support)
|
|
|
+ continue;
|
|
|
|
|
|
- dsi_display_get_dfps_timing(display,
|
|
|
- sub_mode, curr_refresh_rate);
|
|
|
+ curr_refresh_rate = sub_mode->timing.refresh_rate;
|
|
|
+ sub_mode->timing.refresh_rate = dfps_caps.dfps_list[i];
|
|
|
|
|
|
- sub_mode->pixel_clk_khz =
|
|
|
- (DSI_H_TOTAL_DSC(&sub_mode->timing) *
|
|
|
- DSI_V_TOTAL(&sub_mode->timing) *
|
|
|
- sub_mode->timing.refresh_rate) / 1000;
|
|
|
- }
|
|
|
- array_idx++;
|
|
|
+ dsi_display_get_dfps_timing(display, sub_mode,
|
|
|
+ curr_refresh_rate);
|
|
|
}
|
|
|
+ end = array_idx;
|
|
|
+ /*
|
|
|
+ * if dynamic clk switch is supported then update all the bit
|
|
|
+ * clk rates.
|
|
|
+ */
|
|
|
+ _dsi_display_populate_bit_clks(display, start, end, &array_idx);
|
|
|
}
|
|
|
|
|
|
exit:
|
|
@@ -5771,7 +5966,8 @@ int dsi_display_find_mode(struct dsi_display *display,
|
|
|
if (cmp->timing.v_active == m->timing.v_active &&
|
|
|
cmp->timing.h_active == m->timing.h_active &&
|
|
|
cmp->timing.refresh_rate == m->timing.refresh_rate &&
|
|
|
- cmp->panel_mode == m->panel_mode) {
|
|
|
+ cmp->panel_mode == m->panel_mode &&
|
|
|
+ cmp->pixel_clk_khz == m->pixel_clk_khz) {
|
|
|
*out_mode = m;
|
|
|
rc = 0;
|
|
|
break;
|
|
@@ -5780,9 +5976,10 @@ int dsi_display_find_mode(struct dsi_display *display,
|
|
|
mutex_unlock(&display->display_lock);
|
|
|
|
|
|
if (!*out_mode) {
|
|
|
- pr_err("[%s] failed to find mode for v_active %u h_active %u rate %u\n",
|
|
|
+ pr_err("[%s] failed to find mode for v_active %u h_active %u fps %u pclk %u\n",
|
|
|
display->name, cmp->timing.v_active,
|
|
|
- cmp->timing.h_active, cmp->timing.refresh_rate);
|
|
|
+ cmp->timing.h_active, cmp->timing.refresh_rate,
|
|
|
+ cmp->pixel_clk_khz);
|
|
|
rc = -ENOENT;
|
|
|
}
|
|
|
|
|
@@ -5790,7 +5987,7 @@ int dsi_display_find_mode(struct dsi_display *display,
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * dsi_display_validate_mode_vrr() - Validate if varaible refresh case.
|
|
|
+ * dsi_display_validate_mode_change() - Validate if varaible refresh case.
|
|
|
* @display: DSI display handle.
|
|
|
* @cur_dsi_mode: Current DSI mode.
|
|
|
* @mode: Mode value structure to be validated.
|
|
@@ -5798,16 +5995,15 @@ int dsi_display_find_mode(struct dsi_display *display,
|
|
|
* is change in fps but vactive and hactive are same.
|
|
|
* Return: error code.
|
|
|
*/
|
|
|
-int dsi_display_validate_mode_vrr(struct dsi_display *display,
|
|
|
- struct dsi_display_mode *cur_dsi_mode,
|
|
|
- struct dsi_display_mode *mode)
|
|
|
+int dsi_display_validate_mode_change(struct dsi_display *display,
|
|
|
+ struct dsi_display_mode *cur_mode,
|
|
|
+ struct dsi_display_mode *adj_mode)
|
|
|
{
|
|
|
int rc = 0;
|
|
|
- struct dsi_display_mode adj_mode, cur_mode;
|
|
|
struct dsi_dfps_capabilities dfps_caps;
|
|
|
- u32 curr_refresh_rate;
|
|
|
+ struct dsi_dyn_clk_caps *dyn_clk_caps;
|
|
|
|
|
|
- if (!display || !mode) {
|
|
|
+ if (!display || !adj_mode) {
|
|
|
pr_err("Invalid params\n");
|
|
|
return -EINVAL;
|
|
|
}
|
|
@@ -5819,65 +6015,43 @@ int dsi_display_validate_mode_vrr(struct dsi_display *display,
|
|
|
|
|
|
mutex_lock(&display->display_lock);
|
|
|
|
|
|
- adj_mode = *mode;
|
|
|
- cur_mode = *cur_dsi_mode;
|
|
|
-
|
|
|
- if ((cur_mode.timing.refresh_rate != adj_mode.timing.refresh_rate) &&
|
|
|
- (cur_mode.timing.v_active == adj_mode.timing.v_active) &&
|
|
|
- (cur_mode.timing.h_active == adj_mode.timing.h_active)) {
|
|
|
-
|
|
|
- curr_refresh_rate = cur_mode.timing.refresh_rate;
|
|
|
- rc = dsi_panel_get_dfps_caps(display->panel, &dfps_caps);
|
|
|
- if (rc) {
|
|
|
- pr_err("[%s] failed to get dfps caps from panel\n",
|
|
|
- display->name);
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- cur_mode.timing.refresh_rate =
|
|
|
- adj_mode.timing.refresh_rate;
|
|
|
-
|
|
|
- rc = dsi_display_get_dfps_timing(display,
|
|
|
- &cur_mode, curr_refresh_rate);
|
|
|
- if (rc) {
|
|
|
- pr_err("[%s] seamless vrr not possible rc=%d\n",
|
|
|
- display->name, rc);
|
|
|
- goto error;
|
|
|
+ if ((cur_mode->timing.v_active == adj_mode->timing.v_active) &&
|
|
|
+ (cur_mode->timing.h_active == adj_mode->timing.h_active)) {
|
|
|
+ /* dfps change use case */
|
|
|
+ if (cur_mode->timing.refresh_rate !=
|
|
|
+ adj_mode->timing.refresh_rate) {
|
|
|
+ dsi_panel_get_dfps_caps(display->panel, &dfps_caps);
|
|
|
+ if (!dfps_caps.dfps_support) {
|
|
|
+ pr_err("invalid mode dfps not supported\n");
|
|
|
+ rc = -ENOTSUPP;
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ pr_debug("Mode switch is seamless variable refresh\n");
|
|
|
+ adj_mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR;
|
|
|
+ SDE_EVT32(cur_mode->timing.refresh_rate,
|
|
|
+ adj_mode->timing.refresh_rate,
|
|
|
+ cur_mode->timing.h_front_porch,
|
|
|
+ adj_mode->timing.h_front_porch);
|
|
|
}
|
|
|
- switch (dfps_caps.type) {
|
|
|
- /*
|
|
|
- * Ignore any round off factors in porch calculation.
|
|
|
- * Worse case is set to 5.
|
|
|
- */
|
|
|
- case DSI_DFPS_IMMEDIATE_VFP:
|
|
|
- if (abs(DSI_V_TOTAL(&cur_mode.timing) -
|
|
|
- DSI_V_TOTAL(&adj_mode.timing)) > 5)
|
|
|
- pr_err("Mismatch vfp fps:%d new:%d given:%d\n",
|
|
|
- adj_mode.timing.refresh_rate,
|
|
|
- cur_mode.timing.v_front_porch,
|
|
|
- adj_mode.timing.v_front_porch);
|
|
|
- break;
|
|
|
-
|
|
|
- case DSI_DFPS_IMMEDIATE_HFP:
|
|
|
- if (abs(DSI_H_TOTAL_DSC(&cur_mode.timing) -
|
|
|
- DSI_H_TOTAL_DSC(&adj_mode.timing)) > 5)
|
|
|
- pr_err("Mismatch hfp fps:%d new:%d given:%d\n",
|
|
|
- adj_mode.timing.refresh_rate,
|
|
|
- cur_mode.timing.h_front_porch,
|
|
|
- adj_mode.timing.h_front_porch);
|
|
|
- break;
|
|
|
|
|
|
- default:
|
|
|
- pr_err("Unsupported DFPS mode %d\n",
|
|
|
- dfps_caps.type);
|
|
|
- rc = -ENOTSUPP;
|
|
|
+ /* dynamic clk change use case */
|
|
|
+ if (cur_mode->pixel_clk_khz != adj_mode->pixel_clk_khz) {
|
|
|
+ dyn_clk_caps = &(display->panel->dyn_clk_caps);
|
|
|
+ if (!dyn_clk_caps->dyn_clk_support) {
|
|
|
+ pr_err("dyn clk change not supported\n");
|
|
|
+ rc = -ENOTSUPP;
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ if (adj_mode->dsi_mode_flags & DSI_MODE_FLAG_VRR) {
|
|
|
+ pr_err("dfps and dyn clk not supported in same commit\n");
|
|
|
+ rc = -ENOTSUPP;
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ pr_debug("dynamic clk change detected\n");
|
|
|
+ adj_mode->dsi_mode_flags |= DSI_MODE_FLAG_DYN_CLK;
|
|
|
+ SDE_EVT32(cur_mode->pixel_clk_khz,
|
|
|
+ adj_mode->pixel_clk_khz);
|
|
|
}
|
|
|
-
|
|
|
- pr_debug("Mode switch is seamless variable refresh\n");
|
|
|
- mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR;
|
|
|
- SDE_EVT32(curr_refresh_rate, adj_mode.timing.refresh_rate,
|
|
|
- cur_mode.timing.h_front_porch,
|
|
|
- adj_mode.timing.h_front_porch);
|
|
|
}
|
|
|
|
|
|
error:
|