diff --git a/msm/dsi/dsi_ctrl.c b/msm/dsi/dsi_ctrl.c index 2f14904575..34d05b240e 100644 --- a/msm/dsi/dsi_ctrl.c +++ b/msm/dsi/dsi_ctrl.c @@ -826,18 +826,22 @@ int dsi_ctrl_pixel_format_to_bpp(enum dsi_pixel_format dst_format) } static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl, - struct dsi_host_config *config, void *clk_handle) + struct dsi_host_config *config, void *clk_handle, + struct dsi_display_mode *mode) { int rc = 0; u32 num_of_lanes = 0; - u32 bpp, refresh_rate = TICKS_IN_MICRO_SECOND; + u32 bpp, frame_time_us; u64 h_period, v_period, bit_rate, pclk_rate, bit_rate_per_lane, byte_clk_rate; struct dsi_host_common_cfg *host_cfg = &config->common_config; struct dsi_mode_info *timing = &config->video_timing; + u64 dsi_transfer_time_us = mode->priv_info->dsi_transfer_time_us; + u64 min_dsi_clk_hz = mode->priv_info->min_dsi_clk_hz; - /* Get bits per pxl in desitnation format */ + /* Get bits per pxl in destination format */ bpp = dsi_ctrl_pixel_format_to_bpp(host_cfg->dst_format); + frame_time_us = mult_frac(1000, 1000, (timing->refresh_rate)); if (host_cfg->data_lanes & DSI_DATA_LANE_0) num_of_lanes++; @@ -848,18 +852,20 @@ static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl, if (host_cfg->data_lanes & DSI_DATA_LANE_3) num_of_lanes++; - if (config->bit_clk_rate_hz_override == 0) { + config->common_config.num_data_lanes = num_of_lanes; + config->common_config.bpp = bpp; + + if (config->bit_clk_rate_hz_override != 0) { + bit_rate = config->bit_clk_rate_hz_override * num_of_lanes; + } else if (config->panel_mode == DSI_OP_CMD_MODE) { + /* Calculate the bit rate needed to match dsi transfer time */ + bit_rate = mult_frac(min_dsi_clk_hz, frame_time_us, + dsi_transfer_time_us); + bit_rate = bit_rate * num_of_lanes; + } else { h_period = DSI_H_TOTAL_DSC(timing); v_period = DSI_V_TOTAL(timing); - - if (config->panel_mode == DSI_OP_CMD_MODE) - do_div(refresh_rate, timing->mdp_transfer_time_us); - else - refresh_rate = timing->refresh_rate; - - bit_rate = h_period * v_period * refresh_rate * bpp; - } else { - bit_rate = config->bit_clk_rate_hz_override * num_of_lanes; + bit_rate = h_period * v_period * timing->refresh_rate * bpp; } bit_rate_per_lane = bit_rate; @@ -2865,7 +2871,8 @@ error: */ int dsi_ctrl_update_host_config(struct dsi_ctrl *ctrl, struct dsi_host_config *config, - int flags, void *clk_handle) + struct dsi_display_mode *mode, int flags, + void *clk_handle) { int rc = 0; @@ -2883,9 +2890,10 @@ int dsi_ctrl_update_host_config(struct dsi_ctrl *ctrl, } if (!(flags & (DSI_MODE_FLAG_SEAMLESS | DSI_MODE_FLAG_VRR))) { - rc = dsi_ctrl_update_link_freqs(ctrl, config, clk_handle); + rc = dsi_ctrl_update_link_freqs(ctrl, config, clk_handle, + mode); if (rc) { - pr_err("[%s] failed to update link frequencies, rc=%d\n", + pr_err("[%s] failed to update link frequency, rc=%d\n", ctrl->name, rc); goto error; } diff --git a/msm/dsi/dsi_ctrl.h b/msm/dsi/dsi_ctrl.h index 527cf073ee..5192c2926e 100644 --- a/msm/dsi/dsi_ctrl.h +++ b/msm/dsi/dsi_ctrl.h @@ -324,6 +324,7 @@ int dsi_ctrl_validate_timing(struct dsi_ctrl *dsi_ctrl, * dsi_ctrl_update_host_config() - update dsi host configuration * @dsi_ctrl: DSI controller handle. * @config: DSI host configuration. + * @mode: DSI host mode selected. * @flags: dsi_mode_flags modifying the behavior * @clk_handle: Clock handle for DSI clocks * @@ -335,7 +336,8 @@ int dsi_ctrl_validate_timing(struct dsi_ctrl *dsi_ctrl, */ int dsi_ctrl_update_host_config(struct dsi_ctrl *dsi_ctrl, struct dsi_host_config *config, - int flags, void *clk_handle); + struct dsi_display_mode *mode, int flags, + void *clk_handle); /** * dsi_ctrl_timing_db_update() - update only controller Timing DB diff --git a/msm/dsi/dsi_defs.h b/msm/dsi/dsi_defs.h index 9b081bd676..18e9b47f6b 100644 --- a/msm/dsi/dsi_defs.h +++ b/msm/dsi/dsi_defs.h @@ -28,6 +28,17 @@ value;\ }) +#define DSI_H_ACTIVE_DSC(t) \ + ({\ + u64 value;\ + if ((t)->dsc_enabled && (t)->dsc)\ + value = (t)->dsc->pclk_per_line;\ + else\ + value = (t)->h_active;\ + value;\ + }) + + #define DSI_DEBUG_NAME_LEN 32 #define display_for_each_ctrl(index, display) \ for (index = 0; (index < (display)->ctrl_count) &&\ @@ -370,8 +381,10 @@ struct dsi_panel_cmd_set { * @v_sync_polarity: Polarity of VSYNC (false is active low). * @refresh_rate: Refresh rate in Hz. * @clk_rate_hz: DSI bit clock rate per lane in Hz. + * @min_dsi_clk_hz: Min DSI bit clock to transfer in vsync time. * @mdp_transfer_time_us: Specifies the mdp transfer time for command mode * panels in microseconds. + * @dsi_transfer_time_us: Specifies dsi transfer time for command mode. * @dsc_enabled: DSC compression enabled. * @dsc: DSC compression configuration. * @roi_caps: Panel ROI capabilities. @@ -392,7 +405,9 @@ struct dsi_mode_info { u32 refresh_rate; u64 clk_rate_hz; + u64 min_dsi_clk_hz; u32 mdp_transfer_time_us; + u32 dsi_transfer_time_us; bool dsc_enabled; struct msm_display_dsc_info *dsc; struct msm_roi_caps roi_caps; @@ -402,6 +417,8 @@ struct dsi_mode_info { * struct dsi_host_common_cfg - Host configuration common to video and cmd mode * @dst_format: Destination pixel format. * @data_lanes: Physical data lanes to be enabled. + * @num_data_lanes: Number of physical data lanes. + * @bpp: Number of bits per pixel. * @en_crc_check: Enable CRC checks. * @en_ecc_check: Enable ECC checks. * @te_mode: Source for TE signalling. @@ -427,6 +444,8 @@ struct dsi_mode_info { struct dsi_host_common_cfg { enum dsi_pixel_format dst_format; enum dsi_data_lanes data_lanes; + u8 num_data_lanes; + u8 bpp; bool en_crc_check; bool en_ecc_check; enum dsi_te_mode te_mode; @@ -529,7 +548,9 @@ struct dsi_host_config { * @panel_prefill_lines: Panel prefill lines for RSC * @mdp_transfer_time_us: Specifies the mdp transfer time for command mode * panels in microseconds. + * @dsi_transfer_time_us: Specifies the dsi transfer time for cmd panels. * @clk_rate_hz: DSI bit clock per lane in hz. + * @min_dsi_clk_hz: Min dsi clk per lane to transfer frame in vsync time. * @topology: Topology selected for the panel * @dsc: DSC compression info * @dsc_enabled: DSC compression enabled @@ -545,7 +566,9 @@ struct dsi_display_mode_priv_info { u32 panel_jitter_denom; u32 panel_prefill_lines; u32 mdp_transfer_time_us; + u32 dsi_transfer_time_us; u64 clk_rate_hz; + u64 min_dsi_clk_hz; struct msm_display_topology topology; struct msm_display_dsc_info dsc; diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index f4f291e500..69e9beb240 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -4000,7 +4000,8 @@ static int dsi_display_set_mode_sub(struct dsi_display *display, display_for_each_ctrl(i, display) { ctrl = &display->ctrl[i]; rc = dsi_ctrl_update_host_config(ctrl->ctrl, &display->config, - mode->dsi_mode_flags, display->dsi_clk_handle); + mode, mode->dsi_mode_flags, + display->dsi_clk_handle); if (rc) { pr_err("[%s] failed to update ctrl config, rc=%d\n", display->name, rc); @@ -5547,13 +5548,30 @@ int dsi_display_get_modes(struct dsi_display *display, memset(&panel_mode, 0, sizeof(panel_mode)); rc = dsi_panel_get_mode(display->panel, mode_idx, - &panel_mode, topology_override); + &panel_mode, + topology_override); if (rc) { pr_err("[%s] failed to get mode idx %d from panel\n", display->name, mode_idx); goto error; } + /* Calculate dsi frame transfer time */ + if (display->panel->panel_mode == DSI_OP_CMD_MODE) { + dsi_panel_calc_dsi_transfer_time( + &display->panel->host_config, + &panel_mode.timing); + panel_mode.priv_info->dsi_transfer_time_us = + panel_mode.timing.dsi_transfer_time_us; + panel_mode.priv_info->min_dsi_clk_hz = + panel_mode.timing.min_dsi_clk_hz; + + panel_mode.priv_info->mdp_transfer_time_us = + panel_mode.priv_info->dsi_transfer_time_us; + panel_mode.timing.mdp_transfer_time_us = + 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; @@ -5894,6 +5912,7 @@ int dsi_display_set_mode(struct dsi_display *display, { int rc = 0; struct dsi_display_mode adj_mode; + struct dsi_mode_info timing; if (!display || !mode || !display->panel) { pr_err("Invalid params\n"); @@ -5903,6 +5922,7 @@ int dsi_display_set_mode(struct dsi_display *display, mutex_lock(&display->display_lock); adj_mode = *mode; + timing = adj_mode.timing; adjust_timing_by_ctrl_count(display, &adj_mode); /*For dynamic DSI setting, use specified clock rate */ @@ -5930,6 +5950,11 @@ int dsi_display_set_mode(struct dsi_display *display, } } + pr_info("mdp_transfer_time_us=%d us\n", + adj_mode.priv_info->mdp_transfer_time_us); + pr_info("hactive= %d,vactive= %d,fps=%d",timing.h_active, + timing.v_active,timing.refresh_rate); + memcpy(display->panel->cur_mode, &adj_mode, sizeof(adj_mode)); error: mutex_unlock(&display->display_lock); diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index 14d26201b1..8e6386a960 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -873,6 +873,8 @@ static int dsi_panel_parse_pixel_format(struct dsi_host_common_cfg *host, return rc; } + host->bpp = bpp; + switch (bpp) { case 3: fmt = DSI_PIXEL_FORMAT_RGB111; @@ -913,6 +915,7 @@ static int dsi_panel_parse_lane_states(struct dsi_host_common_cfg *host, { int rc = 0; bool lane_enabled; + u32 num_of_lanes = 0; lane_enabled = utils->read_bool(utils->data, "qcom,mdss-dsi-lane-0-state"); @@ -930,6 +933,17 @@ static int dsi_panel_parse_lane_states(struct dsi_host_common_cfg *host, "qcom,mdss-dsi-lane-3-state"); host->data_lanes |= (lane_enabled ? DSI_DATA_LANE_3 : 0); + if (host->data_lanes & DSI_DATA_LANE_0) + num_of_lanes++; + if (host->data_lanes & DSI_DATA_LANE_1) + num_of_lanes++; + if (host->data_lanes & DSI_DATA_LANE_2) + num_of_lanes++; + if (host->data_lanes & DSI_DATA_LANE_3) + num_of_lanes++; + + host->num_data_lanes = num_of_lanes; + if (host->data_lanes == 0) { pr_err("[%s] No data lanes are enabled, rc=%d\n", name, rc); rc = -EINVAL; @@ -3294,6 +3308,55 @@ void dsi_panel_put_mode(struct dsi_display_mode *mode) kfree(mode->priv_info); } +void dsi_panel_calc_dsi_transfer_time(struct dsi_host_common_cfg *config, + struct dsi_mode_info *timing) +{ + u32 frame_time_us,nslices; + u64 min_bitclk, total_active_pixels, bits_per_line; + struct msm_display_dsc_info *dsc = timing->dsc; + + /* Packet overlead in bits,2 bytes header + 2 bytes checksum + * + 1 byte dcs data command. + */ + const u32 packet_overhead = 56; + + /* Default time between pingpong done to TE in microsecs */ + const u32 max_tx_threshold_time = 2166; + + frame_time_us = mult_frac(1000, 1000, (timing->refresh_rate)); + + if (timing->dsc_enabled) { + nslices = (timing->h_active)/(dsc->slice_width); + /* (slice width x bit-per-pixel + packet overhead) x + * number of slices x height x fps / lane + */ + bits_per_line = ((dsc->slice_width * dsc->bpp) + + packet_overhead) * nslices; + bits_per_line = bits_per_line / (config->num_data_lanes); + + min_bitclk = (bits_per_line * timing->v_active * + timing->refresh_rate); + } else { + total_active_pixels = ((DSI_H_ACTIVE_DSC(timing) + * timing->v_active)); + /* calculate the actual bitclk needed to transfer the frame */ + min_bitclk = (total_active_pixels * (timing->refresh_rate) * + (config->bpp)) / (config->num_data_lanes); + } + + timing->min_dsi_clk_hz = min_bitclk; + + if (timing->clk_rate_hz) { + /* adjust the transfer time proportionately for bit clk*/ + timing->dsi_transfer_time_us = mult_frac(frame_time_us, + min_bitclk, timing->clk_rate_hz); + } else { + timing->dsi_transfer_time_us = frame_time_us - + max_tx_threshold_time; + } +} + + int dsi_panel_get_mode(struct dsi_panel *panel, u32 index, struct dsi_display_mode *mode, int topology_override) diff --git a/msm/dsi/dsi_panel.h b/msm/dsi/dsi_panel.h index 85be58839a..f9ad4c257f 100644 --- a/msm/dsi/dsi_panel.h +++ b/msm/dsi/dsi_panel.h @@ -299,4 +299,7 @@ int dsi_panel_parse_esd_reg_read_configs(struct dsi_panel *panel); void dsi_panel_ext_bridge_put(struct dsi_panel *panel); +void dsi_panel_calc_dsi_transfer_time(struct dsi_host_common_cfg *config, + struct dsi_mode_info *timing); + #endif /* _DSI_PANEL_H_ */