drm/msm/dsi-staging: add dsc support to dsi driver

Patch adds display stream compression support to dsi driver
for both video and command modes. Calculates dsc parameters
and sends PPS to the panel. Provides dsc configuration
settings to msm drm driver.

Change-Id: Ib5baf52e8ba5f5c3c9b6e439f86efd6d7c6397d1
Signed-off-by: Alexander Beykun <abeykun@codeaurora.org>
Signed-off-by: Jeykumar Sankaran <jsanka@codeaurora.org>
Signed-off-by: Padmanabhan Komanduru <pkomandu@codeaurora.org>
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c
index dc1fddf..76a1e43 100644
--- a/drivers/gpu/drm/drm_mipi_dsi.c
+++ b/drivers/gpu/drm/drm_mipi_dsi.c
@@ -393,6 +393,7 @@ bool mipi_dsi_packet_format_is_short(u8 type)
 	case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
 	case MIPI_DSI_DCS_READ:
 	case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
+	case MIPI_DSI_COMPRESSION_MODE:
 		return true;
 	}
 
@@ -424,6 +425,7 @@ bool mipi_dsi_packet_format_is_long(u8 type)
 	case MIPI_DSI_PACKED_PIXEL_STREAM_18:
 	case MIPI_DSI_PIXEL_STREAM_3BYTE_18:
 	case MIPI_DSI_PACKED_PIXEL_STREAM_24:
+	case MIPI_DSI_PPS:
 		return true;
 	}
 
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
index 1f0df0a..4a6a934 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
@@ -139,9 +139,8 @@ void dsi_ctrl_hw_cmn_ctrl_en(struct dsi_ctrl_hw *ctrl, bool on);
 void dsi_ctrl_hw_cmn_cmd_engine_en(struct dsi_ctrl_hw *ctrl, bool on);
 
 void dsi_ctrl_hw_cmn_setup_cmd_stream(struct dsi_ctrl_hw *ctrl,
-				     u32 width_in_pixels,
+				     struct dsi_mode_info *mode,
 				     u32 h_stride,
-				     u32 height_in_lines,
 				     u32 vc_id);
 void dsi_ctrl_hw_cmn_phy_sw_reset(struct dsi_ctrl_hw *ctrl);
 void dsi_ctrl_hw_cmn_soft_reset(struct dsi_ctrl_hw *ctrl);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index e9fe5c0..341f5cb 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -751,7 +751,7 @@ static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl,
 	if (host_cfg->data_lanes & DSI_DATA_LANE_3)
 		num_of_lanes++;
 
-	h_period = DSI_H_TOTAL(timing);
+	h_period = DSI_H_TOTAL_DSC(timing);
 	v_period = DSI_V_TOTAL(timing);
 
 	bit_rate = h_period * v_period * timing->refresh_rate * bpp * 8;
@@ -1576,9 +1576,8 @@ int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl)
 					&dsi_ctrl->host_config.u.cmd_engine);
 
 		dsi_ctrl->hw.ops.setup_cmd_stream(&dsi_ctrl->hw,
-				dsi_ctrl->host_config.video_timing.h_active,
+				&dsi_ctrl->host_config.video_timing,
 				dsi_ctrl->host_config.video_timing.h_active * 3,
-				dsi_ctrl->host_config.video_timing.v_active,
 				0x0);
 		dsi_ctrl->hw.ops.cmd_engine_en(&dsi_ctrl->hw, true);
 	} else {
@@ -1659,9 +1658,8 @@ int dsi_ctrl_host_init(struct dsi_ctrl *dsi_ctrl)
 					&dsi_ctrl->host_config.u.cmd_engine);
 
 		dsi_ctrl->hw.ops.setup_cmd_stream(&dsi_ctrl->hw,
-				dsi_ctrl->host_config.video_timing.h_active,
+				&dsi_ctrl->host_config.video_timing,
 				dsi_ctrl->host_config.video_timing.h_active * 3,
-				dsi_ctrl->host_config.video_timing.v_active,
 				0x0);
 	} else {
 		dsi_ctrl->hw.ops.video_engine_setup(&dsi_ctrl->hw,
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
index 89c5cda..161024a 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
@@ -308,18 +308,16 @@ struct dsi_ctrl_hw_ops {
 
 	/**
 	 * setup_cmd_stream() - set up parameters for command pixel streams
-	 * @ctrl:          Pointer to controller host hardware.
-	 * @width_in_pixels:   Width of the stream in pixels.
+	 * @ctrl:              Pointer to controller host hardware.
+	 * @mode:              Pointer to mode information.
 	 * @h_stride:          Horizontal stride in bytes.
-	 * @height_inLines:    Number of lines in the stream.
 	 * @vc_id:             stream_id.
 	 *
 	 * Setup parameters for command mode pixel stream size.
 	 */
 	void (*setup_cmd_stream)(struct dsi_ctrl_hw *ctrl,
-				 u32 width_in_pixels,
+				 struct dsi_mode_info *mode,
 				 u32 h_stride,
-				 u32 height_in_lines,
 				 u32 vc_id);
 
 	/**
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
index b7d8f59..8605338 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
@@ -159,14 +159,36 @@ void dsi_ctrl_hw_cmn_set_video_timing(struct dsi_ctrl_hw *ctrl,
 {
 	u32 reg = 0;
 	u32 hs_start = 0;
-	u32 hs_end, active_h_start, active_h_end, h_total;
+	u32 hs_end, active_h_start, active_h_end, h_total, width = 0;
 	u32 vs_start = 0, vs_end = 0;
 	u32 vpos_start = 0, vpos_end, active_v_start, active_v_end, v_total;
 
+	if (mode->dsc_enabled && mode->dsc) {
+		width = mode->dsc->pclk_per_line;
+		reg = mode->dsc->bytes_per_pkt << 16;
+		reg |= (0x0b << 8);    /* dtype of compressed image */
+		/*
+		 * pkt_per_line:
+		 * 0 == 1 pkt
+		 * 1 == 2 pkt
+		 * 2 == 4 pkt
+		 * 3 pkt is not support
+		 */
+		if (mode->dsc->pkt_per_line == 4)
+			reg |= (mode->dsc->pkt_per_line - 2) << 6;
+		else
+			reg |= (mode->dsc->pkt_per_line - 1) << 6;
+		reg |= mode->dsc->eol_byte_num << 4;
+		reg |= 1;
+		DSI_W32(ctrl, DSI_VIDEO_COMPRESSION_MODE_CTRL, reg);
+	} else {
+		width = mode->h_active;
+	}
+
 	hs_end = mode->h_sync_width;
 	active_h_start = mode->h_sync_width + mode->h_back_porch;
-	active_h_end = active_h_start + mode->h_active;
-	h_total = (mode->h_sync_width + mode->h_back_porch + mode->h_active +
+	active_h_end = active_h_start + width;
+	h_total = (mode->h_sync_width + mode->h_back_porch + width +
 		   mode->h_front_porch) - 1;
 
 	vpos_end = mode->v_sync_width;
@@ -202,29 +224,66 @@ void dsi_ctrl_hw_cmn_set_video_timing(struct dsi_ctrl_hw *ctrl,
 
 /**
  * setup_cmd_stream() - set up parameters for command pixel streams
- * @ctrl:          Pointer to controller host hardware.
- * @width_in_pixels:   Width of the stream in pixels.
+ * @ctrl:              Pointer to controller host hardware.
+ * @mode:              Pointer to mode information.
  * @h_stride:          Horizontal stride in bytes.
- * @height_inLines:    Number of lines in the stream.
  * @vc_id:             stream_id
  *
  * Setup parameters for command mode pixel stream size.
  */
 void dsi_ctrl_hw_cmn_setup_cmd_stream(struct dsi_ctrl_hw *ctrl,
-				     u32 width_in_pixels,
+				     struct dsi_mode_info *mode,
 				     u32 h_stride,
-				     u32 height_in_lines,
 				     u32 vc_id)
 {
 	u32 reg = 0;
+	u32 width_final, stride_final;
 
-	reg = (h_stride + 1) << 16;
+	if (mode->dsc_enabled && mode->dsc) {
+		u32 offset = 0;
+		u32 reg_ctrl, reg_ctrl2;
+
+		if (vc_id != 0)
+			offset = 16;
+		reg_ctrl = DSI_R32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL);
+		reg_ctrl2 = DSI_R32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL2);
+		width_final = mode->dsc->pclk_per_line;
+		stride_final = width_final * (h_stride / mode->h_active);
+
+		reg = 0x39 << 8;
+		/*
+		 * pkt_per_line:
+		 * 0 == 1 pkt
+		 * 1 == 2 pkt
+		 * 2 == 4 pkt
+		 * 3 pkt is not support
+		 */
+		if (mode->dsc->pkt_per_line == 4)
+			reg |= (mode->dsc->pkt_per_line - 2) << 6;
+		else
+			reg |= (mode->dsc->pkt_per_line - 1) << 6;
+		reg |= mode->dsc->eol_byte_num << 4;
+		reg |= 1;
+
+		reg_ctrl &= ~(0xFFFF << offset);
+		reg_ctrl |= (reg << offset);
+		reg_ctrl2 &= ~(0xFFFF << offset);
+		reg_ctrl2 |= (mode->dsc->bytes_in_slice << offset);
+		DSI_W32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL, reg_ctrl);
+		DSI_W32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL2, reg_ctrl2);
+	} else {
+		width_final = mode->h_active;
+		stride_final = h_stride;
+	}
+
+	reg = (stride_final + 1) << 16;
 	reg |= (vc_id & 0x3) << 8;
 	reg |= 0x39; /* packet data type */
+
 	DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM0_CTRL, reg);
 	DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM1_CTRL, reg);
 
-	reg = (height_in_lines << 16) | width_in_pixels;
+	reg = (mode->v_active << 16) | width_final;
 	DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM0_TOTAL, reg);
 	DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM1_TOTAL, reg);
 }
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h b/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h
index fd64d6f..ee39ec7 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h
@@ -16,6 +16,7 @@
 #define _DSI_DEFS_H_
 
 #include <linux/types.h>
+#include "msm_drv.h"
 
 #define DSI_H_TOTAL(t) (((t)->h_active) + ((t)->h_back_porch) + \
 			((t)->h_sync_width) + ((t)->h_front_porch))
@@ -23,6 +24,18 @@
 #define DSI_V_TOTAL(t) (((t)->v_active) + ((t)->v_back_porch) + \
 			((t)->v_sync_width) + ((t)->v_front_porch))
 
+#define DSI_H_TOTAL_DSC(t) \
+	({\
+		u64 value;\
+		if ((t)->dsc_enabled && (t)->dsc)\
+			value = (t)->dsc->pclk_per_line;\
+		else\
+			value = (t)->h_active;\
+		value = value + (t)->h_back_porch + (t)->h_sync_width +\
+			(t)->h_front_porch;\
+		value;\
+	})
+
 /**
  * enum dsi_pixel_format - DSI pixel formats
  * @DSI_PIXEL_FORMAT_RGB565:
@@ -246,6 +259,8 @@ enum dsi_video_traffic_mode {
  * @v_front_porch:    Vertical front porch in lines.
  * @v_sync_polarity:  Polarity of VSYNC (false is active low).
  * @refresh_rate:     Refresh rate in Hz.
+ * @dsc_enabled:      DSC compression enabled.
+ * @dsc:              DSC compression configuration.
  */
 struct dsi_mode_info {
 	u32 h_active;
@@ -262,6 +277,9 @@ struct dsi_mode_info {
 	bool v_sync_polarity;
 
 	u32 refresh_rate;
+
+	bool dsc_enabled;
+	struct msm_display_dsc_info *dsc;
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index 5f380e3..d70693b 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -2700,7 +2700,13 @@ int dsi_display_get_info(struct msm_display_info *info, void *disp)
 	info->height_mm = phy_props.panel_height_mm;
 	info->max_width = 1920;
 	info->max_height = 1080;
-	info->compression = MSM_DISPLAY_COMPRESS_NONE;
+	info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE;
+
+	if (display->panel->dsc_enabled) {
+		info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_DSC;
+		memcpy(&info->comp_info.dsc_info, &display->panel->dsc,
+			sizeof(struct msm_display_dsc_info));
+	}
 
 	switch (display->panel->mode.panel_mode) {
 	case DSI_OP_VIDEO_MODE:
@@ -3027,6 +3033,16 @@ int dsi_display_enable(struct dsi_display *display)
 		goto error;
 	}
 
+	if (display->panel->dsc_enabled) {
+		display->panel->dsc.pic_width *= display->ctrl_count;
+		rc = dsi_panel_update_pps(display->panel);
+		if (rc) {
+			pr_err("[%s] panel pps cmd update failed, rc=%d\n",
+				display->name, rc);
+			goto error;
+		}
+	}
+
 	if (display->config.panel_mode == DSI_OP_VIDEO_MODE) {
 		rc = dsi_display_vid_engine_enable(display);
 		if (rc) {
@@ -3136,6 +3152,23 @@ int dsi_display_disable(struct dsi_display *display)
 	return rc;
 }
 
+int dsi_display_update_pps(char *pps_cmd, void *disp)
+{
+	struct dsi_display *display;
+
+	if (pps_cmd == NULL || disp == NULL) {
+		pr_err("Invalid parameter\n");
+		return -EINVAL;
+	}
+
+	display = disp;
+	mutex_lock(&display->display_lock);
+	memcpy(display->panel->dsc_pps_cmd, pps_cmd, DSI_CMD_PPS_SIZE);
+	mutex_unlock(&display->display_lock);
+
+	return 0;
+}
+
 int dsi_display_unprepare(struct dsi_display *display)
 {
 	int rc = 0;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
index 642ea40..89bba96 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
@@ -341,6 +341,17 @@ int dsi_pre_clkoff_cb(void *priv, enum dsi_clk_type clk_type,
 	enum dsi_clk_state new_state);
 
 /**
+ * dsi_display_update_pps() - update PPS buffer.
+ * @pps_cmd:             PPS buffer.
+ * @display:             Handle to display.
+ *
+ * Copies new PPS buffer into display structure.
+ *
+ * Return: error code.
+ */
+int dsi_display_update_pps(char *pps_cmd, void *display);
+
+/**
  * dsi_post_clkoff_cb() - Callback after clock is turned off
  * @priv: private data pointer.
  * @clk_type: clock which is being turned on.
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
index c6374db..4da92ee 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
@@ -28,6 +28,133 @@
 #define MAX_PANEL_JITTER		25
 #define DEFAULT_PANEL_PREFILL_LINES	16
 
+static u32 dsi_dsc_rc_buf_thresh[] = {0x0e, 0x1c, 0x2a, 0x38, 0x46, 0x54,
+		0x62, 0x69, 0x70, 0x77, 0x79, 0x7b, 0x7d, 0x7e};
+static char dsi_dsc_rc_range_min_qp_1_1[] = {0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5,
+		5, 5, 7, 13};
+static char dsi_dsc_rc_range_min_qp_1_1_scr1[] = {0, 0, 1, 1, 3, 3, 3, 3, 3, 3,
+		5, 5, 5, 9, 12};
+static char dsi_dsc_rc_range_max_qp_1_1[] = {4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 11,
+		12, 13, 13, 15};
+static char dsi_dsc_rc_range_max_qp_1_1_scr1[] = {4, 4, 5, 6, 7, 7, 7, 8, 9, 10,
+		11, 11, 12, 13};
+static char dsi_dsc_rc_range_bpg_offset[] = {2, 0, 0, -2, -4, -6, -8, -8,
+		-8, -10, -10, -12, -12, -12, -12};
+
+int dsi_dsc_create_pps_buf_cmd(struct msm_display_dsc_info *dsc, char *buf,
+				int pps_id)
+{
+	char *bp;
+	char data;
+	int i, bpp;
+	char *dbgbp;
+
+	dbgbp = buf;
+	bp = buf;
+	/* First 7 bytes are cmd header */
+	*bp++ = 0x0A;
+	*bp++ = 1;
+	*bp++ = 0;
+	*bp++ = 0;
+	*bp++ = 10;
+	*bp++ = 0;
+	*bp++ = 128;
+
+	*bp++ = (dsc->version & 0xff);		/* pps0 */
+	*bp++ = (pps_id & 0xff);		/* pps1 */
+	bp++;					/* pps2, reserved */
+
+	data = dsc->line_buf_depth & 0x0f;
+	data |= ((dsc->bpc & 0xf) << 4);
+	*bp++ = data;				/* pps3 */
+
+	bpp = dsc->bpp;
+	bpp <<= 4;				/* 4 fraction bits */
+	data = (bpp >> 8);
+	data &= 0x03;				/* upper two bits */
+	data |= ((dsc->block_pred_enable & 0x1) << 5);
+	data |= ((dsc->convert_rgb & 0x1) << 4);
+	data |= ((dsc->enable_422 & 0x1) << 3);
+	data |= ((dsc->vbr_enable & 0x1) << 2);
+	*bp++ = data;				/* pps4 */
+	*bp++ = (bpp & 0xff);			/* pps5 */
+
+	*bp++ = ((dsc->pic_height >> 8) & 0xff); /* pps6 */
+	*bp++ = (dsc->pic_height & 0x0ff);	/* pps7 */
+	*bp++ = ((dsc->pic_width >> 8) & 0xff);	/* pps8 */
+	*bp++ = (dsc->pic_width & 0x0ff);	/* pps9 */
+
+	*bp++ = ((dsc->slice_height >> 8) & 0xff);/* pps10 */
+	*bp++ = (dsc->slice_height & 0x0ff);	/* pps11 */
+	*bp++ = ((dsc->slice_width >> 8) & 0xff); /* pps12 */
+	*bp++ = (dsc->slice_width & 0x0ff);	/* pps13 */
+
+	*bp++ = ((dsc->chunk_size >> 8) & 0xff);/* pps14 */
+	*bp++ = (dsc->chunk_size & 0x0ff);	/* pps15 */
+
+	*bp++ = (dsc->initial_xmit_delay >> 8) & 0x3; /* pps16, bit 0, 1 */
+	*bp++ = (dsc->initial_xmit_delay & 0xff);/* pps17 */
+
+	*bp++ = ((dsc->initial_dec_delay >> 8) & 0xff); /* pps18 */
+	*bp++ = (dsc->initial_dec_delay & 0xff);/* pps19 */
+
+	bp++;					/* pps20, reserved */
+
+	*bp++ = (dsc->initial_scale_value & 0x3f); /* pps21 */
+
+	*bp++ = ((dsc->scale_increment_interval >> 8) & 0xff); /* pps22 */
+	*bp++ = (dsc->scale_increment_interval & 0xff); /* pps23 */
+
+	*bp++ = ((dsc->scale_decrement_interval >> 8) & 0xf); /* pps24 */
+	*bp++ = (dsc->scale_decrement_interval & 0x0ff);/* pps25 */
+
+	bp++;					/* pps26, reserved */
+
+	*bp++ = (dsc->first_line_bpg_offset & 0x1f);/* pps27 */
+
+	*bp++ = ((dsc->nfl_bpg_offset >> 8) & 0xff);/* pps28 */
+	*bp++ = (dsc->nfl_bpg_offset & 0x0ff);	/* pps29 */
+	*bp++ = ((dsc->slice_bpg_offset >> 8) & 0xff);/* pps30 */
+	*bp++ = (dsc->slice_bpg_offset & 0x0ff);/* pps31 */
+
+	*bp++ = ((dsc->initial_offset >> 8) & 0xff);/* pps32 */
+	*bp++ = (dsc->initial_offset & 0x0ff);	/* pps33 */
+
+	*bp++ = ((dsc->final_offset >> 8) & 0xff);/* pps34 */
+	*bp++ = (dsc->final_offset & 0x0ff);	/* pps35 */
+
+	*bp++ = (dsc->min_qp_flatness & 0x1f);	/* pps36 */
+	*bp++ = (dsc->max_qp_flatness & 0x1f);	/* pps37 */
+
+	*bp++ = ((dsc->rc_model_size >> 8) & 0xff);/* pps38 */
+	*bp++ = (dsc->rc_model_size & 0x0ff);	/* pps39 */
+
+	*bp++ = (dsc->edge_factor & 0x0f);	/* pps40 */
+
+	*bp++ = (dsc->quant_incr_limit0 & 0x1f);	/* pps41 */
+	*bp++ = (dsc->quant_incr_limit1 & 0x1f);	/* pps42 */
+
+	data = ((dsc->tgt_offset_hi & 0xf) << 4);
+	data |= (dsc->tgt_offset_lo & 0x0f);
+	*bp++ = data;				/* pps43 */
+
+	for (i = 0; i < 14; i++)
+		*bp++ = (dsc->buf_thresh[i] & 0xff); /* pps44 - pps57 */
+
+	for (i = 0; i < 15; i++) {		/* pps58 - pps87 */
+		data = (dsc->range_min_qp[i] & 0x1f);
+		data <<= 3;
+		data |= ((dsc->range_max_qp[i] >> 2) & 0x07);
+		*bp++ = data;
+		data = (dsc->range_max_qp[i] & 0x03);
+		data <<= 6;
+		data |= (dsc->range_bpg_offset[i] & 0x3f);
+		*bp++ = data;
+	}
+
+	return 128;
+}
+
 static int dsi_panel_vreg_get(struct dsi_panel *panel)
 {
 	int rc = 0;
@@ -1149,7 +1276,7 @@ static int dsi_panel_get_cmd_pkt_count(const char *data, u32 length, u32 *cnt)
 		tmp = ((data[5] << 8) | (data[6]));
 		packet_length += tmp;
 		if (packet_length > length) {
-			pr_err("FORMAT ERROR\n");
+			pr_err("format error\n");
 			return -EINVAL;
 		}
 		length -= packet_length;
@@ -1218,13 +1345,26 @@ static void dsi_panel_destroy_cmd_packets(struct dsi_panel_cmd_set *set)
 	kfree(set->cmds);
 }
 
+static int dsi_panel_alloc_cmd_packets(struct dsi_panel_cmd_set *cmd,
+					u32 packet_count)
+{
+	u32 size;
+
+	size = packet_count * sizeof(*cmd->cmds);
+	cmd->cmds = kzalloc(size, GFP_KERNEL);
+	if (!cmd->cmds)
+		return -ENOMEM;
+
+	cmd->count = packet_count;
+	return 0;
+}
+
 static int dsi_panel_parse_cmd_sets_sub(struct dsi_panel_cmd_set *cmd,
 					enum dsi_cmd_set_type type,
 					struct device_node *of_node)
 {
 	int rc = 0;
 	u32 length = 0;
-	u32 size;
 	const char *data;
 	const char *state;
 	u32 packet_count = 0;
@@ -1242,20 +1382,18 @@ static int dsi_panel_parse_cmd_sets_sub(struct dsi_panel_cmd_set *cmd,
 		goto error;
 	}
 	pr_debug("[%s] packet-count=%d, %d\n", cmd_set_prop_map[type],
-		 packet_count, length);
+		packet_count, length);
 
-	size = packet_count * sizeof(*cmd->cmds);
-	cmd->cmds = kzalloc(size, GFP_KERNEL);
-	if (!cmd->cmds) {
-		rc = -ENOMEM;
+	rc = dsi_panel_alloc_cmd_packets(cmd, packet_count);
+	if (rc) {
+		pr_err("failed to allocate cmd packets, rc=%d\n", rc);
 		goto error;
 	}
-	cmd->count = packet_count;
 
 	rc = dsi_panel_create_cmd_packets(data, length, packet_count,
 					  cmd->cmds);
 	if (rc) {
-		pr_err("Failed to create cmd packets, rc=%d\n", rc);
+		pr_err("failed to create cmd packets, rc=%d\n", rc);
 		goto error_free_mem;
 	}
 
@@ -1265,7 +1403,7 @@ static int dsi_panel_parse_cmd_sets_sub(struct dsi_panel_cmd_set *cmd,
 	} else if (!strcmp(state, "dsi_hs_mode")) {
 		cmd->state = DSI_CMD_SET_STATE_HS;
 	} else {
-		pr_err("[%s] Command state unrecognized-%s\n",
+		pr_err("[%s] command state unrecognized-%s\n",
 		       cmd_set_state_map[type], state);
 		goto error_free_mem;
 	}
@@ -1289,9 +1427,18 @@ static int dsi_panel_parse_cmd_sets(struct dsi_panel *panel,
 	for (i = DSI_CMD_SET_PRE_ON; i < DSI_CMD_SET_MAX; i++) {
 		set = &panel->cmd_sets[i];
 		set->type = i;
-		rc = dsi_panel_parse_cmd_sets_sub(set, i, of_node);
-		if (rc)
-			pr_err("[%s] failed to parse set %d\n", panel->name, i);
+		if (i == DSI_CMD_SET_PPS) {
+			rc = dsi_panel_alloc_cmd_packets(set, 1);
+			if (rc)
+				pr_err("[%s] failed to allocate cmd set %d, rc = %d\n",
+					panel->name, i, rc);
+			set->state = DSI_CMD_SET_STATE_LP;
+		} else {
+			rc = dsi_panel_parse_cmd_sets_sub(set, i, of_node);
+			if (rc)
+				pr_err("[%s] failed to parse set %d\n",
+					panel->name, i);
+		}
 	}
 
 	rc = 0;
@@ -1593,11 +1740,242 @@ static int dsi_panel_parse_bl_config(struct dsi_panel *panel,
 	return rc;
 }
 
+void dsi_dsc_pclk_param_calc(struct msm_display_dsc_info *dsc, int intf_width)
+{
+	int slice_per_pkt, slice_per_intf;
+	int bytes_in_slice, total_bytes_per_intf;
+
+	if (!dsc || !dsc->slice_width || !dsc->slice_per_pkt ||
+	    (intf_width < dsc->slice_width)) {
+		pr_err("invalid input, intf_width=%d slice_width=%d\n",
+			intf_width, dsc ? dsc->slice_width : -1);
+		return;
+	}
+
+	slice_per_pkt = dsc->slice_per_pkt;
+	slice_per_intf = DIV_ROUND_UP(intf_width, dsc->slice_width);
+
+	/*
+	 * If slice_per_pkt is greater than slice_per_intf then default to 1.
+	 * This can happen during partial update.
+	 */
+	if (slice_per_pkt > slice_per_intf)
+		slice_per_pkt = 1;
+
+	bytes_in_slice = DIV_ROUND_UP(dsc->slice_width * dsc->bpp, 8);
+	total_bytes_per_intf = bytes_in_slice * slice_per_intf;
+
+	dsc->eol_byte_num = total_bytes_per_intf % 3;
+	dsc->pclk_per_line =  DIV_ROUND_UP(total_bytes_per_intf, 3);
+	dsc->bytes_in_slice = bytes_in_slice;
+	dsc->bytes_per_pkt = bytes_in_slice * slice_per_pkt;
+	dsc->pkt_per_line = slice_per_intf / slice_per_pkt;
+}
+
+
+int dsi_dsc_populate_static_param(struct msm_display_dsc_info *dsc)
+{
+	int bpp, bpc;
+	int mux_words_size;
+	int groups_per_line, groups_total;
+	int min_rate_buffer_size;
+	int hrd_delay;
+	int pre_num_extra_mux_bits, num_extra_mux_bits;
+	int slice_bits;
+	int target_bpp_x16;
+	int data;
+	int final_value, final_scale;
+
+	dsc->version = 0x11;
+	dsc->scr_rev = 0;
+	dsc->rc_model_size = 8192;
+	if (dsc->version == 0x11 && dsc->scr_rev == 0x1)
+		dsc->first_line_bpg_offset = 15;
+	else
+		dsc->first_line_bpg_offset = 12;
+
+	dsc->min_qp_flatness = 3;
+	dsc->max_qp_flatness = 12;
+	dsc->line_buf_depth = 9;
+	dsc->edge_factor = 6;
+	dsc->quant_incr_limit0 = 11;
+	dsc->quant_incr_limit1 = 11;
+	dsc->tgt_offset_hi = 3;
+	dsc->tgt_offset_lo = 3;
+	dsc->enable_422 = 0;
+	dsc->convert_rgb = 1;
+	dsc->vbr_enable = 0;
+
+	dsc->buf_thresh = dsi_dsc_rc_buf_thresh;
+	if (dsc->version == 0x11 && dsc->scr_rev == 0x1) {
+		dsc->range_min_qp = dsi_dsc_rc_range_min_qp_1_1_scr1;
+		dsc->range_max_qp = dsi_dsc_rc_range_max_qp_1_1_scr1;
+	} else {
+		dsc->range_min_qp = dsi_dsc_rc_range_min_qp_1_1;
+		dsc->range_max_qp = dsi_dsc_rc_range_max_qp_1_1;
+	}
+	dsc->range_bpg_offset = dsi_dsc_rc_range_bpg_offset;
+
+	bpp = dsc->bpp;
+	bpc = dsc->bpc;
+
+	if (bpp == 8)
+		dsc->initial_offset = 6144;
+	else
+		dsc->initial_offset = 2048;	/* bpp = 12 */
+
+	if (bpc <= 8)
+		mux_words_size = 48;
+	else
+		mux_words_size = 64;	/* bpc == 12 */
+
+	dsc->slice_last_group_size = 3 - (dsc->slice_width % 3);
+
+	dsc->det_thresh_flatness = 7 + 2*(bpc - 8);
+
+	dsc->initial_xmit_delay = dsc->rc_model_size / (2 * bpp);
+
+	groups_per_line = DIV_ROUND_UP(dsc->slice_width, 3);
+
+	dsc->chunk_size = dsc->slice_width * bpp / 8;
+	if ((dsc->slice_width * bpp) % 8)
+		dsc->chunk_size++;
+
+	/* rbs-min */
+	min_rate_buffer_size =  dsc->rc_model_size - dsc->initial_offset +
+			dsc->initial_xmit_delay * bpp +
+			groups_per_line * dsc->first_line_bpg_offset;
+
+	hrd_delay = DIV_ROUND_UP(min_rate_buffer_size, bpp);
+
+	dsc->initial_dec_delay = hrd_delay - dsc->initial_xmit_delay;
+
+	dsc->initial_scale_value = 8 * dsc->rc_model_size /
+			(dsc->rc_model_size - dsc->initial_offset);
+
+	slice_bits = 8 * dsc->chunk_size * dsc->slice_height;
+
+	groups_total = groups_per_line * dsc->slice_height;
+
+	data = dsc->first_line_bpg_offset * 2048;
+
+	dsc->nfl_bpg_offset = DIV_ROUND_UP(data, (dsc->slice_height - 1));
+
+	pre_num_extra_mux_bits = 3 * (mux_words_size + (4 * bpc + 4) - 2);
+
+	num_extra_mux_bits = pre_num_extra_mux_bits - (mux_words_size -
+		((slice_bits - pre_num_extra_mux_bits) % mux_words_size));
+
+	data = 2048 * (dsc->rc_model_size - dsc->initial_offset
+		+ num_extra_mux_bits);
+	dsc->slice_bpg_offset = DIV_ROUND_UP(data, groups_total);
+
+	/* bpp * 16 + 0.5 */
+	data = bpp * 16;
+	data *= 2;
+	data++;
+	data /= 2;
+	target_bpp_x16 = data;
+
+	data = (dsc->initial_xmit_delay * target_bpp_x16) / 16;
+	final_value =  dsc->rc_model_size - data + num_extra_mux_bits;
+
+	final_scale = 8 * dsc->rc_model_size /
+		(dsc->rc_model_size - final_value);
+
+	dsc->final_offset = final_value;
+
+	data = (final_scale - 9) * (dsc->nfl_bpg_offset +
+		dsc->slice_bpg_offset);
+	dsc->scale_increment_interval = (2048 * dsc->final_offset) / data;
+
+	dsc->scale_decrement_interval = groups_per_line /
+		(dsc->initial_scale_value - 8);
+
+	return 0;
+}
+
+int dsi_panel_parse_dsc_params(struct dsi_panel *panel,
+				struct device_node *of_node)
+{
+	u32 data;
+	int rc = -EINVAL;
+	int intf_width;
+	struct device_node *dsc_np = NULL;
+
+	if (!panel->dsc_enabled)
+		return 0;
+
+	dsc_np = of_parse_phandle(of_node, "qcom,config-select", 0);
+	if (!dsc_np) {
+		pr_err("no dsc config found\n");
+		goto error;
+	}
+
+	rc = of_property_read_u32(dsc_np, "qcom,mdss-dsc-slice-height", &data);
+	if (rc) {
+		pr_err("failed to parse qcom,mdss-dsc-slice-height\n");
+		goto error;
+	}
+	panel->dsc.slice_height = data;
+
+	rc = of_property_read_u32(dsc_np, "qcom,mdss-dsc-slice-width", &data);
+	if (rc) {
+		pr_err("failed to parse qcom,mdss-dsc-slice-width\n");
+		goto error;
+	}
+	panel->dsc.slice_width = data;
+
+	intf_width = panel->mode.timing.h_active;
+	if (intf_width % panel->dsc.slice_width) {
+		pr_err("invalid slice width for the panel\n");
+		goto error;
+	}
+
+	panel->dsc.pic_width = panel->mode.timing.h_active;
+	panel->dsc.pic_height = panel->mode.timing.v_active;
+
+	rc = of_property_read_u32(dsc_np, "qcom,mdss-dsc-slice-per-pkt", &data);
+	if (rc) {
+		pr_err("failed to parse qcom,mdss-dsc-slice-per-pkt\n");
+		goto error;
+	}
+	panel->dsc.slice_per_pkt = data;
+
+	rc = of_property_read_u32(dsc_np, "qcom,mdss-dsc-bit-per-component",
+		&data);
+	if (rc) {
+		pr_err("failed to parse qcom,mdss-dsc-bit-per-component\n");
+		goto error;
+	}
+	panel->dsc.bpc = data;
+
+	rc = of_property_read_u32(dsc_np, "qcom,mdss-dsc-bit-per-pixel", &data);
+	if (rc) {
+		pr_err("failed to parse qcom,mdss-dsc-bit-per-pixel\n");
+		goto error;
+	}
+	panel->dsc.bpp = data;
+
+	panel->dsc.block_pred_enable = of_property_read_bool(dsc_np,
+		"qcom,mdss-dsc-block-prediction-enable");
+
+	panel->dsc.full_frame_slices = DIV_ROUND_UP(intf_width,
+		panel->dsc.slice_width);
+
+	dsi_dsc_populate_static_param(&panel->dsc);
+	dsi_dsc_pclk_param_calc(&panel->dsc, intf_width);
+
+error:
+	return rc;
+}
+
 struct dsi_panel *dsi_panel_get(struct device *parent,
 				struct device_node *of_node)
 {
 	struct dsi_panel *panel;
 	const char *data;
+	const char *compression;
 	u32 len = 0;
 	int rc = 0;
 
@@ -1610,12 +1988,23 @@ struct dsi_panel *dsi_panel_get(struct device *parent,
 	if (!panel->name)
 		panel->name = DSI_PANEL_DEFAULT_LABEL;
 
+	panel->dsc_enabled = false;
+	compression = of_get_property(of_node, "qcom,compression-mode", NULL);
+	if (compression && !strcmp(compression, "dsc"))
+		panel->dsc_enabled = true;
+
 	rc = dsi_panel_parse_timing(&panel->mode.timing, of_node);
 	if (rc) {
 		pr_err("failed to parse panel timing, rc=%d\n", rc);
 		goto error;
 	}
 
+	rc = dsi_panel_parse_dsc_params(panel, of_node);
+	if (rc) {
+		pr_err("failed to parse dsc params, rc=%d\n", rc);
+		goto error;
+	}
+
 	data = of_get_property(of_node,
 		"qcom,mdss-dsi-panel-phy-timings", &len);
 	if (!data) {
@@ -1710,7 +2099,7 @@ int dsi_panel_drv_init(struct dsi_panel *panel,
 	struct mipi_dsi_device *dev;
 
 	if (!panel || !host) {
-		pr_err("Invalid params\n");
+		pr_err("invalid params\n");
 		return -EINVAL;
 	}
 
@@ -1730,7 +2119,7 @@ int dsi_panel_drv_init(struct dsi_panel *panel,
 	panel->host = host;
 	rc = dsi_panel_vreg_get(panel);
 	if (rc) {
-		pr_err("[%s] Failed to get panel regulators, rc=%d\n",
+		pr_err("[%s] failed to get panel regulators, rc=%d\n",
 		       panel->name, rc);
 		goto exit;
 	}
@@ -1774,7 +2163,7 @@ int dsi_panel_drv_deinit(struct dsi_panel *panel)
 	int rc = 0;
 
 	if (!panel) {
-		pr_err("Invalid params\n");
+		pr_err("invalid params\n");
 		return -EINVAL;
 	}
 
@@ -1817,7 +2206,7 @@ int dsi_panel_get_mode_count(struct dsi_panel *panel, u32 *count)
 	int rc = 0;
 
 	if (!panel || !count) {
-		pr_err("Invalid params\n");
+		pr_err("invalid params\n");
 		return -EINVAL;
 	}
 
@@ -1835,7 +2224,7 @@ int dsi_panel_get_phy_props(struct dsi_panel *panel,
 	int rc = 0;
 
 	if (!panel || !phy_props) {
-		pr_err("Invalid params\n");
+		pr_err("invalid params\n");
 		return -EINVAL;
 	}
 
@@ -1853,7 +2242,7 @@ int dsi_panel_get_dfps_caps(struct dsi_panel *panel,
 	int rc = 0;
 
 	if (!panel || !dfps_caps) {
-		pr_err("Invalid params\n");
+		pr_err("invalid params\n");
 		return -EINVAL;
 	}
 
@@ -1872,7 +2261,7 @@ int dsi_panel_get_mode(struct dsi_panel *panel,
 	int rc = 0;
 
 	if (!panel || !mode) {
-		pr_err("Invalid params\n");
+		pr_err("invalid params\n");
 		return -EINVAL;
 	}
 
@@ -1893,7 +2282,7 @@ int dsi_panel_get_host_cfg_for_mode(struct dsi_panel *panel,
 	int rc = 0;
 
 	if (!panel || !mode || !config) {
-		pr_err("Invalid params\n");
+		pr_err("invalid params\n");
 		return -EINVAL;
 	}
 
@@ -1913,6 +2302,8 @@ int dsi_panel_get_host_cfg_for_mode(struct dsi_panel *panel,
 
 	memcpy(&config->video_timing, &mode->timing,
 	       sizeof(config->video_timing));
+	config->video_timing.dsc_enabled = panel->dsc_enabled;
+	config->video_timing.dsc = &panel->dsc;
 
 	config->esc_clk_rate_hz = 19200000;
 	mutex_unlock(&panel->panel_lock);
@@ -1924,7 +2315,7 @@ int dsi_panel_pre_prepare(struct dsi_panel *panel)
 	int rc = 0;
 
 	if (!panel) {
-		pr_err("Invalid params\n");
+		pr_err("invalid params\n");
 		return -EINVAL;
 	}
 
@@ -1936,7 +2327,41 @@ int dsi_panel_pre_prepare(struct dsi_panel *panel)
 
 	rc = dsi_panel_power_on(panel);
 	if (rc) {
-		pr_err("[%s] Panel power on failed, rc=%d\n", panel->name, rc);
+		pr_err("[%s] panel power on failed, rc=%d\n", panel->name, rc);
+		goto error;
+	}
+
+error:
+	mutex_unlock(&panel->panel_lock);
+	return rc;
+}
+
+int dsi_panel_update_pps(struct dsi_panel *panel)
+{
+	int rc = 0;
+	struct dsi_panel_cmd_set *set = NULL;
+
+	if (!panel) {
+		pr_err("invalid params\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&panel->panel_lock);
+
+	set = &panel->cmd_sets[DSI_CMD_SET_PPS];
+
+	dsi_dsc_create_pps_buf_cmd(&panel->dsc, panel->dsc_pps_cmd, 0);
+	rc = dsi_panel_create_cmd_packets(panel->dsc_pps_cmd,
+					  DSI_CMD_PPS_SIZE, 1, set->cmds);
+	if (rc) {
+		pr_err("failed to create cmd packets, rc=%d\n", rc);
+		goto error;
+	}
+
+	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_PPS);
+	if (rc) {
+		pr_err("[%s] failed to send DSI_CMD_SET_PPS cmds, rc=%d\n",
+			panel->name, rc);
 		goto error;
 	}
 
@@ -1950,7 +2375,7 @@ int dsi_panel_prepare(struct dsi_panel *panel)
 	int rc = 0;
 
 	if (!panel) {
-		pr_err("Invalid params\n");
+		pr_err("invalid params\n");
 		return -EINVAL;
 	}
 
@@ -2003,7 +2428,7 @@ int dsi_panel_post_enable(struct dsi_panel *panel)
 	int rc = 0;
 
 	if (!panel) {
-		pr_err("Invalid params\n");
+		pr_err("invalid params\n");
 		return -EINVAL;
 	}
 
@@ -2026,7 +2451,7 @@ int dsi_panel_pre_disable(struct dsi_panel *panel)
 	int rc = 0;
 
 	if (!panel) {
-		pr_err("Invalid params\n");
+		pr_err("invalid params\n");
 		return -EINVAL;
 	}
 
@@ -2049,7 +2474,7 @@ int dsi_panel_disable(struct dsi_panel *panel)
 	int rc = 0;
 
 	if (!panel) {
-		pr_err("Invalid params\n");
+		pr_err("invalid params\n");
 		return -EINVAL;
 	}
 
@@ -2071,7 +2496,7 @@ int dsi_panel_unprepare(struct dsi_panel *panel)
 	int rc = 0;
 
 	if (!panel) {
-		pr_err("Invalid params\n");
+		pr_err("invalid params\n");
 		return -EINVAL;
 	}
 
@@ -2102,7 +2527,7 @@ int dsi_panel_post_unprepare(struct dsi_panel *panel)
 	int rc = 0;
 
 	if (!panel) {
-		pr_err("Invalid params\n");
+		pr_err("invalid params\n");
 		return -EINVAL;
 	}
 
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
index 386e8a9..ab30e16 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
@@ -29,6 +29,7 @@
 #include "dsi_pwr.h"
 
 #define MAX_BL_LEVEL 4096
+#define DSI_CMD_PPS_SIZE 135
 
 enum dsi_panel_rotation {
 	DSI_PANEL_ROTATE_NONE = 0,
@@ -52,6 +53,7 @@ enum dsi_cmd_set_type {
 	DSI_CMD_SET_VID_TO_CMD_SWITCH,
 	DSI_CMD_SET_POST_VID_TO_CMD_SWITCH,
 	DSI_CMD_SET_PANEL_STATUS,
+	DSI_CMD_SET_PPS,
 	DSI_CMD_SET_MAX
 };
 
@@ -179,6 +181,10 @@ struct dsi_panel {
 	u32 panel_jitter;
 	u32 panel_prefill_lines;
 	bool panel_initialized;
+
+	bool dsc_enabled;
+	char dsc_pps_cmd[DSI_CMD_PPS_SIZE];
+	struct msm_display_dsc_info dsc;
 };
 
 static inline bool dsi_panel_ulps_feature_enabled(struct dsi_panel *panel)
@@ -230,4 +236,6 @@ int dsi_panel_unprepare(struct dsi_panel *panel);
 int dsi_panel_post_unprepare(struct dsi_panel *panel);
 
 int dsi_panel_set_backlight(struct dsi_panel *panel, u32 bl_lvl);
+
+int dsi_panel_update_pps(struct dsi_panel *panel);
 #endif /* _DSI_PANEL_H_ */
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index e86014d..817fcd2 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -166,15 +166,15 @@ struct msm_vblank_ctrl {
 #define MAX_H_TILES_PER_DISPLAY 2
 
 /**
- * enum msm_display_compression - compression method used for pixel stream
- * @MSM_DISPLAY_COMPRESS_NONE:     Pixel data is not compressed
- * @MSM_DISPLAY_COMPRESS_DSC:      DSC compresison is used
- * @MSM_DISPLAY_COMPRESS_FBC:      FBC compression is used
+ * enum msm_display_compression_type - compression method used for pixel stream
+ * @MSM_DISPLAY_COMPRESSION_NONE:     Pixel data is not compressed
+ * @MSM_DISPLAY_COMPRESSION_DSC:      DSC compresison is used
+ * @MSM_DISPLAY_COMPRESSION_FBC:      FBC compression is used
  */
-enum msm_display_compression {
-	MSM_DISPLAY_COMPRESS_NONE,
-	MSM_DISPLAY_COMPRESS_DSC,
-	MSM_DISPLAY_COMPRESS_FBC,
+enum msm_display_compression_type {
+	MSM_DISPLAY_COMPRESSION_NONE,
+	MSM_DISPLAY_COMPRESSION_DSC,
+	MSM_DISPLAY_COMPRESSION_FBC,
 };
 
 /**
@@ -192,6 +192,125 @@ enum msm_display_caps {
 };
 
 /**
+ * struct msm_display_dsc_info - defines dsc configuration
+ * @version:                 DSC version.
+ * @scr_rev:                 DSC revision.
+ * @pic_height:              Picture height in pixels.
+ * @pic_width:               Picture width in pixels.
+ * @initial_lines:           Number of initial lines stored in encoder.
+ * @pkt_per_line:            Number of packets per line.
+ * @bytes_in_slice:          Number of bytes in slice.
+ * @eol_byte_num:            Valid bytes at the end of line.
+ * @pclk_per_line:           Compressed width.
+ * @full_frame_slices:       Number of slice per interface.
+ * @slice_height:            Slice height in pixels.
+ * @slice_width:             Slice width in pixels.
+ * @chunk_size:              Chunk size in bytes for slice multiplexing.
+ * @slice_last_group_size:   Size of last group in pixels.
+ * @bpp:                     Target bits per pixel.
+ * @bpc:                     Number of bits per component.
+ * @line_buf_depth:          Line buffer bit depth.
+ * @block_pred_enable:       Block prediction enabled/disabled.
+ * @vbr_enable:              VBR mode.
+ * @enable_422:              Indicates if input uses 4:2:2 sampling.
+ * @convert_rgb:             DSC color space conversion.
+ * @input_10_bits:           10 bit per component input.
+ * @slice_per_pkt:           Number of slices per packet.
+ * @initial_dec_delay:       Initial decoding delay.
+ * @initial_xmit_delay:      Initial transmission delay.
+ * @initial_scale_value:     Scale factor value at the beginning of a slice.
+ * @scale_decrement_interval: Scale set up at the beginning of a slice.
+ * @scale_increment_interval: Scale set up at the end of a slice.
+ * @first_line_bpg_offset:   Extra bits allocated on the first line of a slice.
+ * @nfl_bpg_offset:          Slice specific settings.
+ * @slice_bpg_offset:        Slice specific settings.
+ * @initial_offset:          Initial offset at the start of a slice.
+ * @final_offset:            Maximum end-of-slice value.
+ * @rc_model_size:           Number of bits in RC model.
+ * @det_thresh_flatness:     Flatness threshold.
+ * @max_qp_flatness:         Maximum QP for flatness adjustment.
+ * @min_qp_flatness:         Minimum QP for flatness adjustment.
+ * @edge_factor:             Ratio to detect presence of edge.
+ * @quant_incr_limit0:       QP threshold.
+ * @quant_incr_limit1:       QP threshold.
+ * @tgt_offset_hi:           Upper end of variability range.
+ * @tgt_offset_lo:           Lower end of variability range.
+ * @buf_thresh:              Thresholds in RC model
+ * @range_min_qp:            Min QP allowed.
+ * @range_max_qp:            Max QP allowed.
+ * @range_bpg_offset:        Bits per group adjustment.
+ */
+struct msm_display_dsc_info {
+	u8 version;
+	u8 scr_rev;
+
+	int pic_height;
+	int pic_width;
+	int slice_height;
+	int slice_width;
+
+	int initial_lines;
+	int pkt_per_line;
+	int bytes_in_slice;
+	int bytes_per_pkt;
+	int eol_byte_num;
+	int pclk_per_line;
+	int full_frame_slices;
+	int slice_last_group_size;
+	int bpp;
+	int bpc;
+	int line_buf_depth;
+
+	int slice_per_pkt;
+	int chunk_size;
+	bool block_pred_enable;
+	int vbr_enable;
+	int enable_422;
+	int convert_rgb;
+	int input_10_bits;
+
+	int initial_dec_delay;
+	int initial_xmit_delay;
+	int initial_scale_value;
+	int scale_decrement_interval;
+	int scale_increment_interval;
+	int first_line_bpg_offset;
+	int nfl_bpg_offset;
+	int slice_bpg_offset;
+	int initial_offset;
+	int final_offset;
+
+	int rc_model_size;
+	int det_thresh_flatness;
+	int max_qp_flatness;
+	int min_qp_flatness;
+	int edge_factor;
+	int quant_incr_limit0;
+	int quant_incr_limit1;
+	int tgt_offset_hi;
+	int tgt_offset_lo;
+
+	u32 *buf_thresh;
+	char *range_min_qp;
+	char *range_max_qp;
+	char *range_bpg_offset;
+};
+
+/**
+ * struct msm_compression_info - defined panel compression
+ * @comp_type:        type of compression supported
+ * @dsc_info:         dsc configuration if the compression
+ *                    supported is DSC
+ */
+struct msm_compression_info {
+	enum msm_display_compression_type comp_type;
+
+	union{
+		struct msm_display_dsc_info dsc_info;
+	};
+};
+
+/**
  * struct msm_display_info - defines display properties
  * @intf_type:          DRM_MODE_CONNECTOR_ display type
  * @capabilities:       Bitmask of display flags
@@ -210,7 +329,7 @@ enum msm_display_caps {
  * @prefill_lines:	prefill lines based on porches.
  * @vtotal:		display vertical total
  * @jitter:		display jitter configuration
- * @compression:        Compression supported by the display
+ * @comp_info:          Compression supported by the display
  */
 struct msm_display_info {
 	int intf_type;
@@ -233,7 +352,7 @@ struct msm_display_info {
 	uint32_t vtotal;
 	uint32_t jitter;
 
-	enum msm_display_compression compression;
+	struct msm_compression_info comp_info;
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/sde/sde_wb.c b/drivers/gpu/drm/msm/sde/sde_wb.c
index ab4497b..4479e5e 100644
--- a/drivers/gpu/drm/msm/sde/sde_wb.c
+++ b/drivers/gpu/drm/msm/sde/sde_wb.c
@@ -282,7 +282,7 @@ int sde_wb_get_info(struct msm_display_info *info, void *display)
 			wb_dev->wb_cfg->sblk->maxlinewidth :
 			SDE_WB_MODE_MAX_WIDTH;
 	info->max_height = SDE_WB_MODE_MAX_HEIGHT;
-	info->compression = MSM_DISPLAY_COMPRESS_NONE;
+	info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE;
 	return 0;
 }
 
diff --git a/include/video/mipi_display.h b/include/video/mipi_display.h
index 19aa65a..00a2ad1 100644
--- a/include/video/mipi_display.h
+++ b/include/video/mipi_display.h
@@ -4,6 +4,7 @@
  *
  * Copyright (C) 2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
  * Copyright (C) 2006 Nokia Corporation
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
  * Author: Imre Deak <imre.deak@nokia.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -59,6 +60,9 @@ enum {
 	MIPI_DSI_PACKED_PIXEL_STREAM_18			= 0x1e,
 	MIPI_DSI_PIXEL_STREAM_3BYTE_18			= 0x2e,
 	MIPI_DSI_PACKED_PIXEL_STREAM_24			= 0x3e,
+
+	MIPI_DSI_COMPRESSION_MODE			= 0x07,
+	MIPI_DSI_PPS					= 0x0a,
 };
 
 /* MIPI DSI Peripheral-to-Processor transaction types */