Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fa50032c authored by Vara Reddy's avatar Vara Reddy Committed by Ray Zhang
Browse files

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: default avatarVara Reddy <varar@codeaurora.org>
Signed-off-by: default avatarRay Zhang <rayz@codeaurora.org>
parent 12f72767
Loading
Loading
Loading
Loading
+23 −22
Original line number Diff line number Diff line
@@ -840,21 +840,24 @@ 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;
	u64 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, byte_intf_clk_rate;
	struct dsi_host_common_cfg *host_cfg = &config->common_config;
	struct dsi_split_link_config *split_link = &host_cfg->split_link;
	struct dsi_mode_info *timing = &config->video_timing;
	u32 bits_per_symbol = 16, num_of_symbols = 7; /* For Cphy */
	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 desitination 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++;
@@ -868,25 +871,20 @@ static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl,
	if (split_link->split_link_enabled)
		num_of_lanes = split_link->lanes_per_sublink;

	if (config->bit_clk_rate_hz_override == 0) {
		if (config->panel_mode == DSI_OP_CMD_MODE) {
			h_period = DSI_H_ACTIVE_DSC(timing);
			h_period += timing->overlap_pixels;
			v_period = timing->v_active;
	config->common_config.num_data_lanes = num_of_lanes;
	config->common_config.bpp = bpp;

			do_div(refresh_rate, timing->mdp_transfer_time_us);
	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 = min_dsi_clk_hz * frame_time_us;
		do_div(bit_rate, 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);
			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;
		if (host_cfg->phy_type == DSI_PHY_TYPE_CPHY) {
			bit_rate *= bits_per_symbol;
			do_div(bit_rate, num_of_symbols);
		}
		bit_rate = h_period * v_period * timing->refresh_rate * bpp;
	}

	pclk_rate = bit_rate;
@@ -2935,6 +2933,7 @@ int dsi_ctrl_host_deinit(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
 *
 * Updates driver with new Host configuration to use for host initialization.
@@ -2945,6 +2944,7 @@ int dsi_ctrl_host_deinit(struct dsi_ctrl *dsi_ctrl)
 */
int dsi_ctrl_update_host_config(struct dsi_ctrl *ctrl,
				struct dsi_host_config *config,
				struct dsi_display_mode *mode,
				int flags, void *clk_handle)
{
	int rc = 0;
@@ -2968,7 +2968,8 @@ int dsi_ctrl_update_host_config(struct dsi_ctrl *ctrl,
		 * for dynamic clk switch case link frequence would
		 * be updated dsi_display_dynamic_clk_switch().
		 */
		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",
			       ctrl->name, rc);
+3 −1
Original line number Diff line number Diff line
/*
 * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -352,6 +352,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
 *
@@ -363,6 +364,7 @@ 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,
				struct dsi_display_mode *mode,
				int flags, void *clk_handle);

/**
+12 −0
Original line number Diff line number Diff line
@@ -410,8 +410,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.
 * @overlap_pixels:   overlap pixels for certain panels.
 * @dsc_enabled:      DSC compression enabled.
 * @dsc:              DSC compression configuration.
@@ -433,7 +435,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;
	u32 overlap_pixels;
	bool dsc_enabled;
	struct msm_display_dsc_info *dsc;
@@ -456,6 +460,8 @@ struct dsi_split_link_config {
 * 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.
@@ -485,6 +491,8 @@ struct dsi_split_link_config {
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;
@@ -589,7 +597,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.
 * @overlap_pixels:       overlap pixels for certain panels.
 * @topology:             Topology selected for the panel
 * @dsc:                  DSC compression info
@@ -606,7 +616,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;
	u32 overlap_pixels;

	struct msm_display_topology topology;
+26 −2
Original line number Diff line number Diff line
@@ -4570,7 +4570,7 @@ 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->config, mode, mode->dsi_mode_flags,
				display->dsi_clk_handle);
			if (rc) {
				pr_err("failed to update ctrl config\n");
@@ -4618,7 +4618,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);
@@ -6328,6 +6329,22 @@ int dsi_display_get_modes(struct dsi_display *display,
		num_dfps_rates = ((!dfps_caps.dfps_support ||
				is_cmd_mode) ? 1 : dfps_caps.dfps_list_len);

		/* Calculate dsi frame transfer time */
		if (is_cmd_mode) {
			dsi_panel_calc_dsi_transfer_time(
				&display->panel->host_config,
				&display_mode.timing);
			display_mode.priv_info->dsi_transfer_time_us =
				display_mode.timing.dsi_transfer_time_us;
			display_mode.priv_info->min_dsi_clk_hz =
				display_mode.timing.min_dsi_clk_hz;

			display_mode.priv_info->mdp_transfer_time_us =
				display_mode.priv_info->dsi_transfer_time_us;
			display_mode.timing.mdp_transfer_time_us =
				display_mode.timing.dsi_transfer_time_us;
		}

		is_split_link = host->split_link.split_link_enabled;
		sublinks_count = host->split_link.num_sublinks;
		if (is_split_link && sublinks_count > 1) {
@@ -6656,6 +6673,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");
@@ -6665,6 +6683,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 */
@@ -6692,6 +6711,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);
+65 −0
Original line number Diff line number Diff line
@@ -967,6 +967,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;
@@ -1007,6 +1009,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");
@@ -1024,6 +1027,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;
@@ -3616,6 +3630,57 @@ 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,
		dsi_transfer_time_us;
	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));
		do_div(min_bitclk, config->num_data_lanes);
	}

	timing->min_dsi_clk_hz = min_bitclk;

	if (timing->clk_rate_hz) {
		/* adjust the transfer time proportionately for bit clk*/
		dsi_transfer_time_us = frame_time_us * min_bitclk;
		do_div(dsi_transfer_time_us, timing->clk_rate_hz);
		timing->dsi_transfer_time_us = dsi_transfer_time_us;
	} 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)
Loading