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

Commit e9c93285 authored by Ritesh Kumar's avatar Ritesh Kumar Committed by Gerrit - the friendly Code Review server
Browse files

drm: msm: dsi-staging: Add support for C-PHY dynamic clock switch



This change adds support for C-PHY dynamic clock switch feature.
Also add support for phy ver 3.0 C-PHY timing parameters calculation
to be used for clock switch.

Change-Id: I8292860fd8c93a7ba7988ec8c44ea9683f45b6e6
Signed-off-by: default avatarRitesh Kumar <riteshk@codeaurora.org>
parent 361f74dd
Loading
Loading
Loading
Loading
+5 −4
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
@@ -67,6 +67,7 @@ int dsi_phy_timing_calc_init(struct dsi_phy_hw *phy,
 * @host:       DSI host configuration.
 * @timing:     DSI phy lane configurations.
 * @use_mode_bit_clk: Boolean to indicate whether to recalculate bit clk.
 * @is_cphy:	Boolean to indicate whether cphy mode.
 *
 * This function setups the catalog information in the dsi_phy_hw object.
 *
@@ -76,7 +77,7 @@ int dsi_phy_hw_calculate_timing_params(struct dsi_phy_hw *phy,
				       struct dsi_mode_info *mode,
				       struct dsi_host_common_cfg *host,
				       struct dsi_phy_per_lane_cfgs *timing,
				       bool use_mode_bit_clk);
				       bool use_mode_bit_clk, bool is_cphy);

/* Definitions for 14nm PHY hardware driver */
void dsi_phy_hw_v2_0_regulator_enable(struct dsi_phy_hw *phy,
@@ -91,7 +92,7 @@ int dsi_phy_hw_timing_val_v2_0(struct dsi_phy_per_lane_cfgs *timing_cfg,
void dsi_phy_hw_v2_0_clamp_ctrl(struct dsi_phy_hw *phy, bool enable);
void dsi_phy_hw_v2_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset);
void dsi_phy_hw_v2_0_dyn_refresh_config(struct dsi_phy_hw *phy,
		struct dsi_phy_cfg *cfg, bool is_master);
		struct dsi_phy_cfg *cfg, bool is_master, bool is_cphy);
void dsi_phy_hw_v2_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy,
		struct dsi_dyn_clk_delay *delay);
int dsi_phy_hw_v2_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings,
@@ -262,7 +263,7 @@ void dsi_ctrl_hw_cmn_hs_req_sel(struct dsi_ctrl_hw *ctrl, bool sel_phy);
/* dynamic refresh specific functions */
void dsi_phy_hw_v3_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset);
void dsi_phy_hw_v3_0_dyn_refresh_config(struct dsi_phy_hw *phy,
				struct dsi_phy_cfg *cfg, bool is_master);
		struct dsi_phy_cfg *cfg, bool is_master, bool is_cphy);
void dsi_phy_hw_v3_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy,
					    struct dsi_dyn_clk_delay *delay);

+64 −20
Original line number Diff line number Diff line
@@ -3018,11 +3018,15 @@ static int dsi_display_clocks_init(struct dsi_display *display)
	const char *mux_byte = "mux_byte", *mux_pixel = "mux_pixel";
	const char *cphy_byte = "cphy_byte", *cphy_pixel = "cphy_pixel";
	const char *shadow_byte = "shadow_byte", *shadow_pixel = "shadow_pixel";
	const char *shadow_cphybyte = "shadow_cphybyte",
				*shadow_cphypixel = "shadow_cphypixel";
	struct clk *dsi_clk;
	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 *cphy = &display->clock_info.cphy_clks;
	struct dsi_clk_link_set *shadow = &display->clock_info.shadow_clks;
	struct dsi_clk_link_set *shadow_cphy =
					&display->clock_info.shadow_cphy_clks;
	struct dsi_clk_link_set *xo = &display->clock_info.xo_clks;
	struct dsi_dyn_clk_caps *dyn_clk_caps = &(display->panel->dyn_clk_caps);

@@ -3079,6 +3083,12 @@ static int dsi_display_clocks_init(struct dsi_display *display)
				if (dsi_display_check_prefix(shadow_pixel,
							clk_name))
					shadow->pixel_clk = NULL;
				if (dsi_display_check_prefix(shadow_cphybyte,
							clk_name))
					shadow_cphy->byte_clk = NULL;
				if (dsi_display_check_prefix(shadow_cphypixel,
							clk_name))
					shadow_cphy->pixel_clk = NULL;

				dyn_clk_caps->dyn_clk_support = false;
			}
@@ -3123,6 +3133,16 @@ static int dsi_display_clocks_init(struct dsi_display *display)
			shadow->pixel_clk = dsi_clk;
			continue;
		}

		if (dsi_display_check_prefix(shadow_cphybyte, clk_name)) {
			shadow_cphy->byte_clk = dsi_clk;
			continue;
		}

		if (dsi_display_check_prefix(shadow_cphypixel, clk_name)) {
			shadow_cphy->pixel_clk = dsi_clk;
			continue;
		}
	}

	return 0;
@@ -3943,12 +3963,11 @@ static int dsi_display_update_dsi_bitrate(struct dsi_display *display,
			byte_intf_clk_rate = byte_clk_rate;
			do_div(byte_intf_clk_rate, 2);
		} else {
			do_div(bit_rate, bits_per_symbol);
			bit_rate *= num_of_symbols;
			bit_rate_per_lane = bit_rate;
			do_div(bit_rate_per_lane, num_of_lanes);
			byte_clk_rate = bit_rate_per_lane;
			do_div(byte_clk_rate, 7);
			bit_rate_per_lane = bit_clk_rate;
			pclk_rate *= bits_per_symbol;
			do_div(pclk_rate, num_of_symbols);
			byte_clk_rate = bit_clk_rate;
			do_div(byte_clk_rate, num_of_symbols);
			/* For CPHY, byte_intf_clk is same as byte_clk */
			byte_intf_clk_rate = byte_clk_rate;
		}
@@ -4040,6 +4059,17 @@ static int _dsi_display_dyn_update_clks(struct dsi_display *display,

	m_ctrl = &display->ctrl[display->clk_master_idx];

	if (display->panel->host_config.phy_type == DSI_PHY_TYPE_CPHY) {
		dsi_clk_prepare_enable(&display->clock_info.cphy_clks);

		rc = dsi_clk_update_parent(
					&display->clock_info.shadow_cphy_clks,
					&display->clock_info.mux_clks);
		if (rc) {
			pr_err("failed update mux parent to shadow\n");
			goto exit;
		}
	} else {
		dsi_clk_prepare_enable(&display->clock_info.src_clks);

		rc = dsi_clk_update_parent(&display->clock_info.shadow_clks,
@@ -4048,6 +4078,7 @@ static int _dsi_display_dyn_update_clks(struct dsi_display *display,
			pr_err("failed update mux parent to shadow\n");
			goto exit;
		}
	}

	display_for_each_ctrl(i, display) {
		ctrl = &display->ctrl[i];
@@ -4093,13 +4124,21 @@ static int _dsi_display_dyn_update_clks(struct dsi_display *display,
		ctrl = &display->ctrl[i];
		dsi_phy_dynamic_refresh_clear(ctrl->phy);
	}
	if (display->panel->host_config.phy_type == DSI_PHY_TYPE_CPHY) {
		rc = dsi_clk_update_parent(&display->clock_info.cphy_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.cphy_clks);
	} else {
		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;

@@ -4135,10 +4174,13 @@ static int dsi_display_dynamic_clk_switch_vid(struct dsi_display *display,
	struct dsi_display_ctrl *m_ctrl, *ctrl;
	struct dsi_dyn_clk_delay delay;
	struct link_clk_freq bkp_freq;
	bool is_cphy;

	dsi_panel_acquire_panel_lock(display->panel);

	m_ctrl = &display->ctrl[display->clk_master_idx];
	is_cphy = (display->panel->host_config.phy_type == DSI_PHY_TYPE_CPHY) ?
			true : false;

	dsi_display_clk_ctrl(display->dsi_clk_handle, DSI_ALL_CLKS, DSI_CLK_ON);

@@ -4150,7 +4192,8 @@ static int dsi_display_dynamic_clk_switch_vid(struct dsi_display *display,
	/* update the phy timings based on new mode */
	display_for_each_ctrl(i, display) {
		ctrl = &display->ctrl[i];
		dsi_phy_update_phy_timings(ctrl->phy, &display->config);
		dsi_phy_update_phy_timings(ctrl->phy, &display->config,
			is_cphy);
	}

	/* back up existing rates to handle failure case */
@@ -4174,10 +4217,11 @@ static int dsi_display_dynamic_clk_switch_vid(struct dsi_display *display,
		if (!ctrl->phy)
			continue;
		if (ctrl == m_ctrl)
			dsi_phy_config_dynamic_refresh(ctrl->phy, &delay, true);
			dsi_phy_config_dynamic_refresh(ctrl->phy, &delay,
				true, is_cphy);
		else
			dsi_phy_config_dynamic_refresh(ctrl->phy, &delay,
						       false);
				false, is_cphy);
	}

	rc = _dsi_display_dyn_update_clks(display, &bkp_freq);
+3 −1
Original line number Diff line number Diff line
@@ -114,7 +114,8 @@ struct dsi_display_boot_param {
 * struct dsi_display_clk_info - dsi display clock source information
 * @src_clks:          Source clocks for DSI display.
 * @mux_clks:          Mux clocks used for DFPS.
 * @shadow_clks:       Used for DFPS.
 * @shadow_clks:       Used for D-phy clock switch
 * @shadow_cphy_clks:  Used for C-phy clock switch
 * @xo_clks:           XO clocks for DSI display
 */
struct dsi_display_clk_info {
@@ -122,6 +123,7 @@ struct dsi_display_clk_info {
	struct dsi_clk_link_set mux_clks;
	struct dsi_clk_link_set cphy_clks;
	struct dsi_clk_link_set shadow_clks;
	struct dsi_clk_link_set shadow_cphy_clks;
	struct dsi_clk_link_set xo_clks;
};

+13 −7
Original line number Diff line number Diff line
/*
 * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2016-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
@@ -902,6 +902,7 @@ int dsi_phy_enable(struct msm_dsi_phy *phy,
		   bool is_cont_splash_enabled)
{
	int rc = 0;
	bool is_cphy = false;

	if (!phy || !config) {
		pr_err("Invalid params\n");
@@ -924,11 +925,14 @@ int dsi_phy_enable(struct msm_dsi_phy *phy,
	 * If PHY timing parameters are not present in panel dtsi file,
	 * then calculate them in the driver
	 */
	is_cphy = (config->common_config.phy_type == DSI_PHY_TYPE_CPHY) ?
			true : false;
	if (!phy->cfg.is_phy_timing_present)
		rc = phy->hw.ops.calculate_timing_params(&phy->hw,
						 &phy->mode,
						 &config->common_config,
						 &phy->cfg.timing, false);
						 &phy->cfg.timing, false,
						is_cphy);
	if (rc) {
		pr_err("[%s] failed to set timing, rc=%d\n", phy->name, rc);
		goto error;
@@ -948,7 +952,7 @@ int dsi_phy_enable(struct msm_dsi_phy *phy,

/* update dsi phy timings for dynamic clk switch use case */
int dsi_phy_update_phy_timings(struct msm_dsi_phy *phy,
			       struct dsi_host_config *config)
		struct dsi_host_config *config, bool is_cphy)
{
	int rc = 0;

@@ -960,7 +964,8 @@ int dsi_phy_update_phy_timings(struct msm_dsi_phy *phy,
	memcpy(&phy->mode, &config->video_timing, sizeof(phy->mode));
	rc = phy->hw.ops.calculate_timing_params(&phy->hw, &phy->mode,
					&config->common_config,
						 &phy->cfg.timing, true);
					&phy->cfg.timing, true,
					is_cphy);
	if (rc)
		pr_err("failed to calculate phy timings %d\n", rc);

@@ -1186,10 +1191,11 @@ int dsi_phy_conv_logical_to_phy_lane(
 * @phy:	DSI PHY handle
 * @delay:	pipe delays for dynamic refresh
 * @is_master:	Boolean to indicate if for master or slave.
 * @is_cphy:	Boolean to indicate cphy mode.
 */
void dsi_phy_config_dynamic_refresh(struct msm_dsi_phy *phy,
		struct dsi_dyn_clk_delay *delay,
		bool is_master)
		bool is_master, bool is_cphy)
{
	struct dsi_phy_cfg *cfg;

@@ -1201,7 +1207,7 @@ void dsi_phy_config_dynamic_refresh(struct msm_dsi_phy *phy,
	cfg = &phy->cfg;
	if (phy->hw.ops.dyn_refresh_ops.dyn_refresh_config)
		phy->hw.ops.dyn_refresh_ops.dyn_refresh_config(&phy->hw, cfg,
				is_master);
				is_master, is_cphy);
	if (phy->hw.ops.dyn_refresh_ops.dyn_refresh_pipe_delay)
		phy->hw.ops.dyn_refresh_ops.dyn_refresh_pipe_delay(
				&phy->hw, delay);
+6 −3
Original line number Diff line number Diff line
/*
 * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2016-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
@@ -302,21 +302,24 @@ void dsi_phy_drv_unregister(void);
 * dsi_phy_update_phy_timings() - Update dsi phy timings
 * @phy:	DSI PHY handle
 * @config:	DSI Host config parameters
 * @is_cphy:	Boolean to indicate cphy mode
 *
 * Return: error code.
 */
int dsi_phy_update_phy_timings(struct msm_dsi_phy *phy,
			       struct dsi_host_config *config);
				struct dsi_host_config *config,
				bool is_cphy);

/**
 * dsi_phy_config_dynamic_refresh() - Configure dynamic refresh registers
 * @phy:	DSI PHY handle
 * @delay:	pipe delays for dynamic refresh
 * @is_master:	Boolean to indicate if for master or slave
 * @is_cphy:	Boolean to indicate cphy mode
 */
void dsi_phy_config_dynamic_refresh(struct msm_dsi_phy *phy,
				    struct dsi_dyn_clk_delay *delay,
				    bool is_master);
				    bool is_master, bool is_cphy);
/**
 * dsi_phy_dynamic_refresh_trigger() - trigger dynamic refresh
 * @phy:	DSI PHY handle
Loading