From f28b596aacb02f733aaa0478f4b560b9c56b5010 Mon Sep 17 00:00:00 2001 From: Vara Reddy Date: Thu, 2 May 2019 13:42:06 -0700 Subject: [PATCH] drm/msm/dsi-staging: update dsi clock calculations Change updates dsi clock calculations for command mode as per recommendation. Now dsi clocks are tied to frame transer time. Propagate correct frame transfer time to hal to update mdp clocks and bandwidth needed accordingly. Change-Id: I46f9038622ddd47cc53c5f3d54229f69a7008c8a Signed-off-by: Vara Reddy --- msm/dsi/dsi_ctrl.c | 40 ++++++++++++++++----------- msm/dsi/dsi_ctrl.h | 4 ++- msm/dsi/dsi_defs.h | 23 ++++++++++++++++ msm/dsi/dsi_display.c | 29 ++++++++++++++++++-- msm/dsi/dsi_panel.c | 63 +++++++++++++++++++++++++++++++++++++++++++ msm/dsi/dsi_panel.h | 3 +++ 6 files changed, 143 insertions(+), 19 deletions(-) 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_ */