msm: sde: Enable traffic shaping for 4k@30fps rotation

For 30fps rotation, it is only required to perform a commit every other
vsync for a 60fps refresh rate panel. Rotation time for a 4k resolution
will take approx 12ms including SW overhead, and leave very little room
to perform a frame commit in fb driver. One way is to delay the
rotation time by enabling traffic shaping for 4k@30fps content so that
the it will take approx 15ms to finish, and that will force the frame
commit into next vsync time slot and thus matching the cadence of
30fps commit time.

CRs-Fixed: 1100633
Change-Id: I0aecfe767cd77140f75bb13c4fe6f9267d4d911e
Signed-off-by: Benjamin Chan <bkchan@codeaurora.org>
Signed-off-by: Narendra Muppalla <NarendraM@codeaurora.org>
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
index 9240a32..85235e53 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, 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
@@ -36,6 +36,12 @@
 #include "sde_rotator_trace.h"
 #include "sde_rotator_debug.h"
 
+#define RES_UHD              (3840*2160)
+
+/* traffic shaping clock ticks = finish_time x 19.2MHz */
+#define TRAFFIC_SHAPE_CLKTICK_14MS   268800
+#define TRAFFIC_SHAPE_CLKTICK_12MS   230400
+
 /* XIN mapping */
 #define XIN_SSPP		0
 #define XIN_WRITEBACK		1
@@ -650,6 +656,20 @@
 		ctx->is_secure = false;
 	}
 
+	/*
+	 * Determine if traffic shaping is required. Only enable traffic
+	 * shaping when content is 4k@30fps. The actual traffic shaping
+	 * bandwidth calculation is done in output setup.
+	 */
+	if (((cfg->src_rect->w * cfg->src_rect->h) >= RES_UHD) &&
+			(cfg->fps <= 30)) {
+		SDEROT_DBG("Enable Traffic Shaper\n");
+		ctx->is_traffic_shaping = true;
+	} else {
+		SDEROT_DBG("Disable Traffic Shaper\n");
+		ctx->is_traffic_shaping = false;
+	}
+
 	/* Update command queue write ptr */
 	sde_hw_rotator_put_regdma_segment(ctx, wrptr);
 }
@@ -762,6 +782,36 @@
 	else
 		SDE_REGDMA_WRITE(wrptr, ROTTOP_OP_MODE, 0x1);
 
+	/* setup traffic shaper for 4k 30fps content */
+	if (ctx->is_traffic_shaping) {
+		u32 bw;
+
+		/*
+		 * Target to finish in 12ms, and we need to set number of bytes
+		 * per clock tick for traffic shaping.
+		 * Each clock tick run @ 19.2MHz, so we need we know total of
+		 * clock ticks in 14ms, i.e. 12ms/(1/19.2MHz) ==> 23040
+		 * Finally, calcualte the byte count per clock tick based on
+		 * resolution, bpp and compression ratio.
+		 */
+		bw = cfg->dst_rect->w * cfg->dst_rect->h;
+
+		if (fmt->chroma_sample == SDE_MDP_CHROMA_420)
+			bw = (bw * 3) / 2;
+		else
+			bw *= fmt->bpp;
+
+		bw /= TRAFFIC_SHAPE_CLKTICK_12MS;
+		if (bw > 0xFF)
+			bw = 0xFF;
+		SDE_REGDMA_WRITE(wrptr, ROT_WB_TRAFFIC_SHAPER_WR_CLIENT,
+				BIT(31) | bw);
+		SDEROT_DBG("Enable ROT_WB Traffic Shaper:%d\n", bw);
+	} else {
+		SDE_REGDMA_WRITE(wrptr, ROT_WB_TRAFFIC_SHAPER_WR_CLIENT, 0);
+		SDEROT_DBG("Disable ROT_WB Traffic Shaper\n");
+	}
+
 	/* Update command queue write ptr */
 	sde_hw_rotator_put_regdma_segment(ctx, wrptr);
 }
@@ -1580,6 +1630,8 @@
 
 	sspp_cfg.img_width = item->input.width;
 	sspp_cfg.img_height = item->input.height;
+	sspp_cfg.fps = entry->perf->config.frame_rate;
+	sspp_cfg.bw = entry->perf->bw;
 	sspp_cfg.fmt = sde_get_format_params(item->input.format);
 	if (!sspp_cfg.fmt) {
 		SDEROT_ERR("null format\n");
@@ -1599,6 +1651,8 @@
 
 	wb_cfg.img_width = item->output.width;
 	wb_cfg.img_height = item->output.height;
+	wb_cfg.fps = entry->perf->config.frame_rate;
+	wb_cfg.bw = entry->perf->bw;
 	wb_cfg.fmt = sde_get_format_params(item->output.format);
 	wb_cfg.dst_rect = &item->dst_rect;
 	wb_cfg.data = &entry->dst_buf;
@@ -1642,7 +1696,9 @@
 				MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0;
 		ot_params.bit_off_mdp_clk_ctrl =
 				MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0_XIN0;
-		ot_params.fmt = entry->perf->config.input.format;
+		ot_params.fmt = ctx->is_traffic_shaping ?
+			SDE_PIX_FMT_ABGR_8888 :
+			entry->perf->config.input.format;
 		sde_mdp_set_ot_limit(&ot_params);
 	}
 
@@ -1660,7 +1716,9 @@
 				MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0;
 		ot_params.bit_off_mdp_clk_ctrl =
 				MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0_XIN1;
-		ot_params.fmt = entry->perf->config.input.format;
+		ot_params.fmt = ctx->is_traffic_shaping ?
+			SDE_PIX_FMT_ABGR_8888 :
+			entry->perf->config.input.format;
 		sde_mdp_set_ot_limit(&ot_params);
 	}
 
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h
index e666f48..5502cc0 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, 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
@@ -73,6 +73,8 @@
 	struct sde_mdp_data          *data;
 	u32                           img_width;
 	u32                           img_height;
+	u32                           fps;
+	u64                           bw;
 };
 
 
@@ -93,6 +95,8 @@
 	u32                             img_height;
 	u32                             v_downscale_factor;
 	u32                             h_downscale_factor;
+	u32                             fps;
+	u64                             bw;
 };
 
 
@@ -214,6 +218,7 @@
 	u32    last_regdma_timestamp;
 	dma_addr_t ts_addr;
 	bool   is_secure;
+	bool   is_traffic_shaping;
 };
 
 /**