drm/msm/dp: add support for HDR10+

Add support for sending HDR10+ VSIF formatted dynamic metadata
to compatible external displays via DP protocol's secondary
data packets.

Change-Id: I24e90eb9b5273f13aa9dbc24bbe3551bb8f51be5
Signed-off-by: Steve Cohen <cohens@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 4cacdea..f1ba16b 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -64,6 +64,11 @@
 	{0xFF, 0xFF, 0xFF, 0xFF}  /* sw1, 1.2 v, optional */
 };
 
+enum dp_flush_bit {
+	DP_PPS_FLUSH,
+	DP_DHDR_FLUSH,
+};
+
 struct dp_catalog_io {
 	struct dp_io_data *dp_ahb;
 	struct dp_io_data *dp_aux;
@@ -572,14 +577,16 @@
 			DUMP_PREFIX_NONE, 16, 4, buf, off, false);
 }
 
-static void dp_catalog_panel_config_hdr(struct dp_catalog_panel *panel, bool en)
+static void dp_catalog_panel_config_hdr(struct dp_catalog_panel *panel, bool en,
+		u32 dhdr_max_pkts)
 {
 	struct dp_catalog_private *catalog;
 	struct dp_io_data *io_data;
-	u32 cfg, cfg2, misc;
+	u32 cfg, cfg2, cfg4, misc;
 	u32 sdp_cfg_off = 0;
 	u32 sdp_cfg2_off = 0;
 	u32 sdp_cfg3_off = 0;
+	u32 sdp_cfg4_off = 0;
 	u32 misc1_misc0_off = 0;
 
 	if (!panel) {
@@ -599,6 +606,7 @@
 		sdp_cfg_off = MMSS_DP1_SDP_CFG - MMSS_DP_SDP_CFG;
 		sdp_cfg2_off = MMSS_DP1_SDP_CFG2 - MMSS_DP_SDP_CFG2;
 		sdp_cfg3_off = MMSS_DP1_SDP_CFG3 - MMSS_DP_SDP_CFG3;
+		sdp_cfg4_off = MMSS_DP1_SDP_CFG4 - MMSS_DP_SDP_CFG4;
 		misc1_misc0_off = DP1_MISC1_MISC0 - DP_MISC1_MISC0;
 	}
 
@@ -620,6 +628,13 @@
 		dp_write(catalog->exe_mode, io_data,
 				MMSS_DP_SDP_CFG2 + sdp_cfg2_off, cfg2);
 
+		/* DHDR_EN, DHDR_PACKET_LIMIT */
+		if (dhdr_max_pkts) {
+			cfg4 = (dhdr_max_pkts << 1) | BIT(0);
+			dp_write(catalog->exe_mode, io_data, MMSS_DP_SDP_CFG4
+					+ sdp_cfg4_off, cfg4);
+		}
+
 		dp_catalog_panel_setup_vsc_sdp(panel);
 		dp_catalog_panel_setup_infoframe_sdp(panel);
 
@@ -641,6 +656,11 @@
 		dp_write(catalog->exe_mode, io_data,
 				MMSS_DP_SDP_CFG2 + sdp_cfg2_off, cfg2);
 
+		/* DHDR_EN, DHDR_PACKET_LIMIT */
+		cfg4 = 0;
+		dp_write(catalog->exe_mode, io_data, MMSS_DP_SDP_CFG4
+				+ sdp_cfg4_off, cfg4);
+
 		/* switch back to MSA */
 		misc &= ~BIT(14);
 
@@ -1192,7 +1212,8 @@
 			reg, panel->stream_id);
 }
 
-static void dp_catalog_panel_pps_flush(struct dp_catalog_panel *panel)
+static void dp_catalog_panel_dp_flush(struct dp_catalog_panel *panel,
+		enum dp_flush_bit flush_bit)
 {
 	struct dp_catalog_private *catalog;
 	struct dp_io_data *io_data;
@@ -1217,12 +1238,47 @@
 		offset = MMSS_DP1_FLUSH - MMSS_DP_FLUSH;
 
 	dp_flush = dp_read(catalog->exe_mode, io_data, MMSS_DP_FLUSH + offset);
-	dp_flush |= BIT(0);
+	dp_flush |= BIT(flush_bit);
 	dp_write(catalog->exe_mode, io_data, MMSS_DP_FLUSH + offset, dp_flush);
+}
 
+static void dp_catalog_panel_pps_flush(struct dp_catalog_panel *panel)
+{
+	dp_catalog_panel_dp_flush(panel, DP_PPS_FLUSH);
 	pr_debug("pps flush for stream:%d\n", panel->stream_id);
 }
 
+static void dp_catalog_panel_dhdr_flush(struct dp_catalog_panel *panel)
+{
+	dp_catalog_panel_dp_flush(panel, DP_DHDR_FLUSH);
+	pr_debug("dhdr flush for stream:%d\n", panel->stream_id);
+}
+
+
+static bool dp_catalog_panel_dhdr_busy(struct dp_catalog_panel *panel)
+{
+	struct dp_catalog_private *catalog;
+	struct dp_io_data *io_data;
+	u32 dp_flush, offset;
+
+	if (panel->stream_id >= DP_STREAM_MAX) {
+		pr_err("invalid stream_id:%d\n", panel->stream_id);
+		return false;
+	}
+
+	catalog = dp_catalog_get_priv(panel);
+	io_data = catalog->io.dp_link;
+
+	if (panel->stream_id == DP_STREAM_0)
+		offset = 0;
+	else
+		offset = MMSS_DP1_FLUSH - MMSS_DP_FLUSH;
+
+	dp_flush = dp_read(catalog->exe_mode, io_data, MMSS_DP_FLUSH + offset);
+
+	return dp_flush & BIT(DP_DHDR_FLUSH) ? true : false;
+}
+
 static void dp_catalog_ctrl_reset(struct dp_catalog_ctrl *ctrl)
 {
 	u32 sw_reset;
@@ -2479,6 +2535,8 @@
 		.config_dto = dp_catalog_panel_config_dto,
 		.dsc_cfg = dp_catalog_panel_dsc_cfg,
 		.pps_flush = dp_catalog_panel_pps_flush,
+		.dhdr_flush = dp_catalog_panel_dhdr_flush,
+		.dhdr_busy = dp_catalog_panel_dhdr_busy,
 	};
 
 	if (!dev || !parser) {
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 1ef4f23..9d536b4 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -217,7 +217,8 @@
 	struct dp_dsc_cfg_data dsc;
 
 	int (*timing_cfg)(struct dp_catalog_panel *panel);
-	void (*config_hdr)(struct dp_catalog_panel *panel, bool en);
+	void (*config_hdr)(struct dp_catalog_panel *panel, bool en,
+			u32 dhdr_max_pkts);
 	void (*tpg_config)(struct dp_catalog_panel *panel, bool enable);
 	void (*config_spd)(struct dp_catalog_panel *panel);
 	void (*config_misc)(struct dp_catalog_panel *panel);
@@ -228,6 +229,8 @@
 	void (*config_dto)(struct dp_catalog_panel *panel, bool ack);
 	void (*dsc_cfg)(struct dp_catalog_panel *panel);
 	void (*pps_flush)(struct dp_catalog_panel *panel);
+	void (*dhdr_flush)(struct dp_catalog_panel *panel);
+	bool (*dhdr_busy)(struct dp_catalog_panel *panel);
 };
 
 struct dp_catalog;
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index bc9eddc..75a2f16 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -944,6 +944,7 @@
 
 	y_frac_enum = (u32)((temp1 == temp2) ? temp1 : temp1 + 1);
 
+	panel->mst_target_sc = raw_target_sc;
 	*p_x_int = x_int;
 	*p_y_frac_enum = y_frac_enum;
 
diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c
index 1145858..e5f1b3e 100644
--- a/drivers/gpu/drm/msm/dp/dp_debug.c
+++ b/drivers/gpu/drm/msm/dp/dp_debug.c
@@ -1279,7 +1279,7 @@
 		len = -EINVAL;
 	}
 
-	debug->panel->setup_hdr(debug->panel, &c_state->hdr_meta);
+	debug->panel->setup_hdr(debug->panel, &c_state->hdr_meta, false, 0);
 end:
 	return len;
 }
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 13acf31..ccfa611f 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1497,7 +1497,7 @@
 			struct dp_panel *dp_panel)
 {
 	dp_panel->spd_config(dp_panel);
-	dp_panel->setup_hdr(dp_panel, NULL);
+	dp_panel->setup_hdr(dp_panel, NULL, false, 0);
 }
 
 static int dp_display_post_enable(struct dp_display *dp_display, void *panel)
@@ -1903,23 +1903,27 @@
 }
 
 static int dp_display_config_hdr(struct dp_display *dp_display, void *panel,
-			struct drm_msm_ext_hdr_metadata *hdr)
+			struct drm_msm_ext_hdr_metadata *hdr, bool dhdr_update)
 {
-	int rc = 0;
-	struct dp_display_private *dp;
 	struct dp_panel *dp_panel;
+	struct dp_display_private *dp;
+	u64 core_clk_rate;
 
 	if (!dp_display || !panel) {
 		pr_err("invalid input\n");
 		return -EINVAL;
 	}
 
-	dp = container_of(dp_display, struct dp_display_private, dp_display);
 	dp_panel = panel;
+	dp = container_of(dp_display, struct dp_display_private, dp_display);
 
-	rc = dp_panel->setup_hdr(dp_panel, hdr);
+	core_clk_rate = dp->power->clk_get_rate(dp->power, "core_clk");
+	if (!core_clk_rate) {
+		pr_err("invalid rate for core_clk\n");
+		return -EINVAL;
+	}
 
-	return rc;
+	return dp_panel->setup_hdr(dp_panel, hdr, dhdr_update, core_clk_rate);
 }
 
 static int dp_display_create_workqueue(struct dp_display_private *dp)
diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h
index 00adbbd..410cee7 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.h
+++ b/drivers/gpu/drm/msm/dp/dp_display.h
@@ -87,7 +87,8 @@
 	struct dp_debug *(*get_debug)(struct dp_display *dp_display);
 	void (*post_open)(struct dp_display *dp_display);
 	int (*config_hdr)(struct dp_display *dp_display, void *panel,
-				struct drm_msm_ext_hdr_metadata *hdr_meta);
+				struct drm_msm_ext_hdr_metadata *hdr_meta,
+				bool dhdr_update);
 	int (*post_init)(struct dp_display *dp_display);
 	int (*mst_install)(struct dp_display *dp_display,
 			struct dp_mst_drm_install_info *mst_install_info);
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 40406cd..9b3bb24 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -324,7 +324,8 @@
 		return -EINVAL;
 	}
 
-	return dp->config_hdr(dp, sde_conn->drv_panel, &c_state->hdr_meta);
+	return dp->config_hdr(dp, sde_conn->drv_panel, &c_state->hdr_meta,
+			c_state->dyn_hdr_meta.dynamic_hdr_update);
 }
 
 int dp_connector_post_init(struct drm_connector *connector, void *display)
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
index 2a9bbb8..a486a32 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -17,6 +17,7 @@
 #define VSC_SDP_EXTENSION_FOR_COLORIMETRY_SUPPORTED BIT(3)
 #define VSC_EXT_VESA_SDP_SUPPORTED BIT(4)
 #define VSC_EXT_VESA_SDP_CHAINING_SUPPORTED BIT(5)
+#define SEQ_INCREMENT_FOR_CHAINED_PACKETS BIT(6)
 
 enum dp_panel_hdr_pixel_encoding {
 	RGB,
@@ -99,6 +100,17 @@
 static const u8 product_desc[16] = {83, 110, 97, 112, 100, 114, 97, 103,
 	111, 110, 0, 0, 0, 0, 0, 0};
 
+struct dp_dhdr_maxpkt_calc_input {
+	u32 mdp_clk;
+	u32 lclk;
+	u32 pclk;
+	u32 h_active;
+	u32 nlanes;
+	s64 mst_target_sc;
+	bool mst_en;
+	bool fec_en;
+};
+
 struct tu_algo_data {
 	s64 lclk_fp;
 	s64 pclk_fp;
@@ -2362,8 +2374,10 @@
 	connector->hdr_avg_luminance = 0;
 	connector->hdr_min_luminance = 0;
 	connector->hdr_supported = false;
+	connector->hdr_plus_app_ver = 0;
 
 	memset(&c_state->hdr_meta, 0, sizeof(c_state->hdr_meta));
+	memset(&c_state->dyn_hdr_meta, 0, sizeof(c_state->dyn_hdr_meta));
 
 	return rc;
 }
@@ -2409,12 +2423,97 @@
 		(panel->minor >= 4 || panel->vscext_supported);
 }
 
-static int dp_panel_setup_hdr(struct dp_panel *dp_panel,
-		struct drm_msm_ext_hdr_metadata *hdr_meta)
+static u32 dp_panel_calc_dhdr_pkt_limit(struct dp_panel *dp_panel,
+		struct dp_dhdr_maxpkt_calc_input *input)
 {
-	int rc = 0;
+	s64 mdpclk_fp = drm_fixp_from_fraction(input->mdp_clk, 1000000);
+	s64 lclk_fp = drm_fixp_from_fraction(input->lclk, 1000);
+	s64 pclk_fp = drm_fixp_from_fraction(input->pclk, 1000);
+	s64 nlanes_fp = drm_int2fixp(input->nlanes);
+	s64 target_sc = input->mst_target_sc;
+	s64 hactive_fp = drm_int2fixp(input->h_active);
+	const s64 i1_fp = DRM_FIXED_ONE;
+	const s64 i2_fp = drm_int2fixp(2);
+	const s64 i10_fp = drm_int2fixp(10);
+	const s64 i56_fp = drm_int2fixp(56);
+	const s64 i64_fp = drm_int2fixp(64);
+	s64 mst_bw_fp = i1_fp;
+	s64 fec_factor_fp = i1_fp;
+	s64 mst_bw64_fp, mst_bw64_ceil_fp, nlanes56_fp;
+	u32 f1, f2, f3, f4, f5, deploy_period, target_period;
+	s64 f3_f5_slot_fp;
+	u32 calc_pkt_limit;
+	const u32 max_pkt_limit = 64;
+
+	if (input->fec_en && input->mst_en)
+		fec_factor_fp = drm_fixp_from_fraction(64000, 65537);
+
+	if (input->mst_en)
+		mst_bw_fp = drm_fixp_div(target_sc, i64_fp);
+
+	f1 = drm_fixp2int_ceil(drm_fixp_div(drm_fixp_mul(i10_fp, lclk_fp),
+			mdpclk_fp));
+	f2 = drm_fixp2int_ceil(drm_fixp_div(drm_fixp_mul(i2_fp, lclk_fp),
+			mdpclk_fp)) + drm_fixp2int_ceil(drm_fixp_div(
+			drm_fixp_mul(i1_fp, lclk_fp), mdpclk_fp));
+
+	mst_bw64_fp = drm_fixp_mul(mst_bw_fp, i64_fp);
+	if (drm_fixp2int(mst_bw64_fp) == 0)
+		f3_f5_slot_fp = drm_fixp_div(i1_fp, drm_int2fixp(
+				drm_fixp2int_ceil(drm_fixp_div(
+				i1_fp, mst_bw64_fp))));
+	else
+		f3_f5_slot_fp = drm_int2fixp(drm_fixp2int(mst_bw_fp));
+
+	mst_bw64_ceil_fp = drm_int2fixp(drm_fixp2int_ceil(mst_bw64_fp));
+	f3 = drm_fixp2int(drm_fixp_mul(drm_int2fixp(drm_fixp2int(
+				drm_fixp_div(i2_fp, f3_f5_slot_fp)) + 1),
+				(i64_fp - mst_bw64_ceil_fp))) + 2;
+
+	if (!input->mst_en) {
+		f4 = 1 + drm_fixp2int(drm_fixp_div(drm_int2fixp(50),
+				nlanes_fp)) + drm_fixp2int(drm_fixp_div(
+				nlanes_fp, i2_fp));
+		f5 = 0;
+	} else {
+		f4 = 0;
+		nlanes56_fp = drm_fixp_div(i56_fp, nlanes_fp);
+		f5 = drm_fixp2int(drm_fixp_mul(drm_int2fixp(drm_fixp2int(
+				drm_fixp_div(i1_fp + nlanes56_fp,
+				f3_f5_slot_fp)) + 1), (i64_fp -
+				mst_bw64_ceil_fp + i1_fp + nlanes56_fp)));
+	}
+
+	deploy_period = f1 + f2 + f3 + f4 + f5 + 19;
+	target_period = drm_fixp2int(drm_fixp_mul(fec_factor_fp, drm_fixp_mul(
+			hactive_fp, drm_fixp_div(lclk_fp, pclk_fp))));
+
+	calc_pkt_limit = target_period / deploy_period;
+
+	pr_debug("input: %d, %d, %d, %d, %d, 0x%llx, %d, %d\n",
+		input->mdp_clk, input->lclk, input->pclk, input->h_active,
+		input->nlanes, input->mst_target_sc, input->mst_en ? 1 : 0,
+		input->fec_en ? 1 : 0);
+	pr_debug("factors: %d, %d, %d, %d, %d\n", f1, f2, f3, f4, f5);
+	pr_debug("d_p: %d, t_p: %d, maxPkts: %d%s\n", deploy_period,
+		target_period, calc_pkt_limit, calc_pkt_limit > max_pkt_limit ?
+		" CAPPED" : "");
+
+	if (calc_pkt_limit > max_pkt_limit)
+		calc_pkt_limit = max_pkt_limit;
+
+	pr_debug("packet limit per line = %d\n", calc_pkt_limit);
+	return calc_pkt_limit;
+}
+
+static int dp_panel_setup_hdr(struct dp_panel *dp_panel,
+		struct drm_msm_ext_hdr_metadata *hdr_meta,
+		bool dhdr_update, u64 core_clk_rate)
+{
+	int rc = 0, max_pkts = 0;
 	struct dp_panel_private *panel;
 	struct dp_catalog_hdr_data *hdr;
+	struct dp_dhdr_maxpkt_calc_input input;
 
 	if (!dp_panel) {
 		pr_err("invalid input\n");
@@ -2470,9 +2569,29 @@
 	else
 		memset(&hdr->hdr_meta, 0, sizeof(hdr->hdr_meta));
 cached:
+	if (dhdr_update) {
+		hdr->vscext_header_byte2 |= SEQ_INCREMENT_FOR_CHAINED_PACKETS;
+
+		input.mdp_clk = core_clk_rate;
+		input.lclk = dp_panel->link_info.rate;
+		input.nlanes = dp_panel->link_info.num_lanes;
+		input.pclk = dp_panel->pinfo.pixel_clk_khz;
+		input.h_active = dp_panel->pinfo.h_active;
+		input.mst_target_sc = dp_panel->mst_target_sc;
+		input.mst_en = dp_panel->mst_state;
+		input.fec_en = dp_panel->fec_en;
+		max_pkts = dp_panel_calc_dhdr_pkt_limit(dp_panel, &input);
+	}
+
 	if (panel->panel_on) {
 		panel->catalog->stream_id = dp_panel->stream_id;
-		panel->catalog->config_hdr(panel->catalog, panel->hdr_state);
+		panel->catalog->config_hdr(panel->catalog, panel->hdr_state,
+				max_pkts);
+		if (dhdr_update) {
+			panel->catalog->dhdr_flush(panel->catalog);
+			hdr->vscext_header_byte2 &=
+					~SEQ_INCREMENT_FOR_CHAINED_PACKETS;
+		}
 	}
 end:
 	return rc;
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
index 8bcce99..90d5346 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.h
+++ b/drivers/gpu/drm/msm/dp/dp_panel.h
@@ -101,6 +101,7 @@
 
 	u32 vic;
 	u32 max_pclk_khz;
+	s64 mst_target_sc;
 
 	/* debug */
 	u32 max_bw_code;
@@ -145,7 +146,8 @@
 	int (*set_edid)(struct dp_panel *dp_panel, u8 *edid);
 	int (*set_dpcd)(struct dp_panel *dp_panel, u8 *dpcd);
 	int (*setup_hdr)(struct dp_panel *dp_panel,
-		struct drm_msm_ext_hdr_metadata *hdr_meta);
+		struct drm_msm_ext_hdr_metadata *hdr_meta,
+		bool dhdr_update, u64 core_clk_rate);
 	void (*tpg_config)(struct dp_panel *dp_panel, bool enable);
 	int (*spd_config)(struct dp_panel *dp_panel);
 	bool (*hdr_supported)(struct dp_panel *dp_panel);
diff --git a/drivers/gpu/drm/msm/dp/dp_power.c b/drivers/gpu/drm/msm/dp/dp_power.c
index 0f32a10..d6f2f41 100644
--- a/drivers/gpu/drm/msm/dp/dp_power.c
+++ b/drivers/gpu/drm/msm/dp/dp_power.c
@@ -544,6 +544,44 @@
 	return rc;
 }
 
+static u64 dp_power_clk_get_rate(struct dp_power *dp_power, char *clk_name)
+{
+	size_t i;
+	enum dp_pm_type j;
+	struct dss_module_power *mp;
+	struct dp_power_private *power;
+	bool clk_found = false;
+	u64 rate = 0;
+
+	if (!clk_name) {
+		pr_err("invalid pointer for clk_name\n");
+		return 0;
+	}
+
+	power = container_of(dp_power, struct dp_power_private, dp_power);
+	mp = &power->phandle->mp;
+	for (i = 0; i < mp->num_clk; i++) {
+		if (!strcmp(mp->clk_config[i].clk_name, clk_name)) {
+			rate = clk_get_rate(mp->clk_config[i].clk);
+			clk_found = true;
+			break;
+		}
+	}
+
+	for (j = DP_CORE_PM; j < DP_MAX_PM && !clk_found; j++) {
+		mp = &power->parser->mp[j];
+		for (i = 0; i < mp->num_clk; i++) {
+			if (!strcmp(mp->clk_config[i].clk_name, clk_name)) {
+				rate = clk_get_rate(mp->clk_config[i].clk);
+				clk_found = true;
+				break;
+			}
+		}
+	}
+
+	return rate;
+}
+
 static int dp_power_init(struct dp_power *dp_power, bool flip)
 {
 	int rc = 0;
@@ -660,6 +698,7 @@
 	dp_power->deinit = dp_power_deinit;
 	dp_power->clk_enable = dp_power_clk_enable;
 	dp_power->set_pixel_clk_parent = dp_power_set_pixel_clk_parent;
+	dp_power->clk_get_rate = dp_power_clk_get_rate;
 	dp_power->power_client_init = dp_power_client_init;
 	dp_power->power_client_deinit = dp_power_client_deinit;
 
diff --git a/drivers/gpu/drm/msm/dp/dp_power.h b/drivers/gpu/drm/msm/dp/dp_power.h
index 3f8943d..bd58166 100644
--- a/drivers/gpu/drm/msm/dp/dp_power.h
+++ b/drivers/gpu/drm/msm/dp/dp_power.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _DP_POWER_H_
@@ -16,6 +16,7 @@
  * @deinit: turns off the regulators/core clocks/GPIOs/pinctrl
  * @clk_enable: enable/disable the DP clocks
  * @set_pixel_clk_parent: set the parent of DP pixel clock
+ * @clk_get_rate: get the current rate for provided clk_name
  */
 struct dp_power {
 	int (*init)(struct dp_power *power, bool flip);
@@ -23,6 +24,7 @@
 	int (*clk_enable)(struct dp_power *power, enum dp_pm_type pm_type,
 				bool enable);
 	int (*set_pixel_clk_parent)(struct dp_power *power, u32 stream_id);
+	u64 (*clk_get_rate)(struct dp_power *power, char *clk_name);
 	int (*power_client_init)(struct dp_power *power,
 				struct sde_power_handle *phandle);
 	void (*power_client_deinit)(struct dp_power *power);
diff --git a/drivers/gpu/drm/msm/dp/dp_reg.h b/drivers/gpu/drm/msm/dp/dp_reg.h
index b2ff651..697d50d 100644
--- a/drivers/gpu/drm/msm/dp/dp_reg.h
+++ b/drivers/gpu/drm/msm/dp/dp_reg.h
@@ -132,6 +132,7 @@
 #define MMSS_DP_SDP_CFG				(0x00000228)
 #define MMSS_DP_SDP_CFG2			(0x0000022C)
 #define MMSS_DP_SDP_CFG3			(0x0000024C)
+#define MMSS_DP_SDP_CFG4			(0x000004EC)
 #define MMSS_DP_AUDIO_TIMESTAMP_0		(0x00000230)
 #define MMSS_DP_AUDIO_TIMESTAMP_1		(0x00000234)
 
@@ -212,6 +213,7 @@
 #define MMSS_DP1_SDP_CFG			(0x000004E0)
 #define MMSS_DP1_SDP_CFG2			(0x000004E4)
 #define MMSS_DP1_SDP_CFG3			(0x000004E8)
+#define MMSS_DP1_SDP_CFG4			(0x000004F0)
 
 #define DP1_COMPRESSION_MODE_CTRL		(0x00000560)
 #define DP1_PPS_HB_0_3				(0x00000564)