msm: mdss: support mdp prefill bandwith for multiple platforms

To calculate mdp prefill bandwidth, mdp driver needs to get h/w
dependent buffer constants from device tree. Also add h/w feature
dependent logic.

Conflicts:

	drivers/video/msm/mdss/mdss.h

Change-Id: I8d56ec502a6fd56eaae5b65a326ef966be46f14b
Signed-off-by: Huaibin Yang <huaibiny@codeaurora.org>
Signed-off-by: Ujwal Patel <ujwalp@codeaurora.org>
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index d1942f9..f8c4879 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -150,6 +150,46 @@
 				bare no logic except for the use-case 0 where ab
 				and ib values needs to be 0.
 
+- qcom,mdss-prefill-outstanding-buffer-bytes: The size of mdp outstanding buffer
+				in bytes. The buffer is filled during prefill
+				time and the buffer size shall be included in
+				prefill bandwidth calculation.
+- qcom,mdss-prefill-y-buffer-bytes: The size of mdp y plane buffer in bytes. The
+				buffer is filled during prefill time when format
+				is YUV and the buffer size shall be included in
+				prefill bandwidth calculation.
+- qcom,mdss-prefill-scaler-buffer-lines-bilinear: The value indicates how many lines
+				of scaler line buffer need to be filled during
+				prefill time. If bilinear scalar is enabled, then this
+				number of lines is used to determine how many bytes
+				of scaler buffer to be included in prefill bandwidth
+				calculation.
+- qcom,mdss-prefill-scaler-buffer-lines-caf: The value indicates how many lines of
+				of scaler line buffer need to be filled during
+				prefill time. If CAF mode filter is enabled, then
+				this number of lines is used to determine how many
+				bytes of scaler buffer to be included in prefill
+				bandwidth calculation.
+- qcom,mdss-prefill-post-scaler-buffer: The size of post scaler buffer in bytes.
+				The buffer is used to smooth the output of the
+				scaler. If the buffer is present in h/w, it is
+				filled during prefill time and the number of bytes
+				shall be included in prefill bandwidth calculation.
+- qcom,mdss-prefill-pingpong-buffer-pixels: The size of pingpong buffer in pixels.
+				The buffer is used to keep pixels flowing to the
+				panel interface. If the vertical start position of a
+				layer is in the beginning of the active area, pingpong
+				buffer must be filled during prefill time to generate
+				starting lines. The number of bytes to be filled is
+				determined by the line width, starting position,
+				byte per pixel and scaling ratio, this number shall be
+				included in prefill bandwidth calculation.
+- qcom,mdss-prefill-fbc-lines:  The value indicates how many lines are required to fill
+				fbc buffer during prefill time if FBC (Frame Buffer
+				Compressor) is enabled. The number of bytes to be filled
+				is determined by the line width, bytes per pixel and
+				scaling ratio, this number shall be included in prefill bandwidth
+				calculation.
 Optional properties:
 - vdd-cx-supply :	Phandle for vdd CX regulator device node.
 - batfet-supply :	Phandle for battery FET regulator device node.
@@ -329,6 +369,15 @@
 		qcom,mdss-intf-off = <0x00021100 0x00021300
 					   0x00021500 0x00021700>;
 
+		/* buffer parameters to calculate prefill bandwidth */
+		qcom,mdss-prefill-outstanding-buffer-bytes = <1024>;
+		qcom,mdss-prefill-y-buffer-bytes = <4096>;
+		qcom,mdss-prefill-scaler-buffer-lines-bilinear = <2>;
+		qcom,mdss-prefill-scaler-buffer-lines-caf = <4>;
+		qcom,mdss-prefill-post-scaler-buffer-pixels = <2048>;
+		qcom,mdss-prefill-pingpong-buffer-pixels = <5120>;
+		qcom,mdss-prefill-fbc-lines = <2>;
+
 		mdss_fb0: qcom,mdss_fb_primary {
 			cell-index = <0>;
 			compatible = "qcom,mdss-fb";
diff --git a/arch/arm/boot/dts/apq8084-mdss.dtsi b/arch/arm/boot/dts/apq8084-mdss.dtsi
index 314f9a0..329ab32 100644
--- a/arch/arm/boot/dts/apq8084-mdss.dtsi
+++ b/arch/arm/boot/dts/apq8084-mdss.dtsi
@@ -74,6 +74,15 @@
 		qcom,mdss-has-bwc;
 		qcom,mdss-has-decimation;
 
+		/* buffer parameters to calculate prefill bandwidth */
+		qcom,mdss-prefill-outstanding-buffer-bytes = <1024>;
+		qcom,mdss-prefill-y-buffer-bytes = <4096>;
+		qcom,mdss-prefill-scaler-buffer-lines-bilinear = <2>;
+		qcom,mdss-prefill-scaler-buffer-lines-caf = <4>;
+		qcom,mdss-prefill-post-scaler-buffer-pixels = <2048>;
+		qcom,mdss-prefill-pingpong-buffer-pixels = <5120>;
+		qcom,mdss-prefill-fbc-lines = <2>;
+
 		mdss_fb0: qcom,mdss_fb_primary {
 			cell-index = <0>;
 			compatible = "qcom,mdss-fb";
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index 9f110d4..40576c9 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -67,6 +67,15 @@
 		qcom,mdp-settings = <0x02E0 0x000000A5>,
 				    <0x02E4 0x00000055>;
 
+		/* buffer parameters to calculate prefill bandwidth */
+		qcom,mdss-prefill-outstanding-buffer-bytes = <1024>;
+		qcom,mdss-prefill-y-buffer-bytes = <0>;
+		qcom,mdss-prefill-scaler-buffer-lines-bilinear = <2>;
+		qcom,mdss-prefill-scaler-buffer-lines-caf = <4>;
+		qcom,mdss-prefill-post-scaler-buffer-pixels = <0>;
+		qcom,mdss-prefill-pingpong-buffer-pixels = <4096>;
+		qcom,mdss-prefill-fbc-lines = <0>;
+
 		mdss_fb0: qcom,mdss_fb_primary {
 			cell-index = <0>;
 			compatible = "qcom,mdss-fb";
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index 19dac3d..89f4af8 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -81,6 +81,15 @@
 				    <0x04B0 0xCCCCC0C0>,
 				    <0x04B8 0xCCCCC000>;
 
+		/* buffer parameters to calculate prefill bandwidth */
+		qcom,mdss-prefill-outstanding-buffer-bytes = <1024>;
+		qcom,mdss-prefill-y-buffer-bytes = <4096>;
+		qcom,mdss-prefill-scaler-buffer-lines-bilinear = <2>;
+		qcom,mdss-prefill-scaler-buffer-lines-caf = <4>;
+		qcom,mdss-prefill-post-scaler-buffer-pixels = <0>;
+		qcom,mdss-prefill-pingpong-buffer-pixels = <4096>;
+		qcom,mdss-prefill-fbc-lines = <2>;
+
 		mdss_fb0: qcom,mdss_fb_primary {
 			cell-index = <0>;
 			compatible = "qcom,mdss-fb";
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index 7e6f3e4..8c2ac09 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -84,6 +84,16 @@
 	u32 denom;
 };
 
+struct mdss_prefill_data {
+	u32 ot_bytes;
+	u32 y_buf_bytes;
+	u32 y_scaler_lines_bilinear;
+	u32 y_scaler_lines_caf;
+	u32 post_scaler_pixels;
+	u32 pp_pixels;
+	u32 fbc_lines;
+};
+
 struct mdss_data_type {
 	u32 mdp_rev;
 	struct clk *mdp_clk[MDSS_MAX_CLK];
@@ -180,6 +190,7 @@
 	struct mdss_panel_cfg pan_cfg;
 
 	int handoff_pending;
+	struct mdss_prefill_data prefill_data;
 };
 extern struct mdss_data_type *mdss_res;
 
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 4a0da77..bc9a2a9 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -133,6 +133,7 @@
 static int mdss_mdp_parse_dt_prop_len(struct platform_device *pdev,
 				       char *prop_name);
 static int mdss_mdp_parse_dt_smp(struct platform_device *pdev);
+static int mdss_mdp_parse_dt_prefill(struct platform_device *pdev);
 static int mdss_mdp_parse_dt_misc(struct platform_device *pdev);
 static int mdss_mdp_parse_dt_ad_cfg(struct platform_device *pdev);
 static int mdss_mdp_parse_dt_bus_scale(struct platform_device *pdev);
@@ -1532,6 +1533,12 @@
 		return rc;
 	}
 
+	rc = mdss_mdp_parse_dt_prefill(pdev);
+	if (rc) {
+		pr_err("Error in device tree : prefill\n");
+		return rc;
+	}
+
 	rc = mdss_mdp_parse_dt_misc(pdev);
 	if (rc) {
 		pr_err("Error in device tree : misc\n");
@@ -2028,6 +2035,69 @@
 	}
 }
 
+static int mdss_mdp_parse_dt_prefill(struct platform_device *pdev)
+{
+	struct mdss_data_type *mdata = platform_get_drvdata(pdev);
+	struct mdss_prefill_data *prefill = &mdata->prefill_data;
+	int rc;
+
+	rc = of_property_read_u32(pdev->dev.of_node,
+		"qcom,mdss-prefill-outstanding-buffer-bytes",
+		&prefill->ot_bytes);
+	if (rc) {
+		pr_err("prefill outstanding buffer bytes not specified\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(pdev->dev.of_node,
+		"qcom,mdss-prefill-y-buffer-bytes", &prefill->y_buf_bytes);
+	if (rc) {
+		pr_err("prefill y buffer bytes not specified\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(pdev->dev.of_node,
+		"qcom,mdss-prefill-scaler-buffer-lines-bilinear",
+		&prefill->y_scaler_lines_bilinear);
+	if (rc) {
+		pr_err("prefill scaler lines for bilinear not specified\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(pdev->dev.of_node,
+		"qcom,mdss-prefill-scaler-buffer-lines-caf",
+		&prefill->y_scaler_lines_caf);
+	if (rc) {
+		pr_debug("prefill scaler lines for caf not specified\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(pdev->dev.of_node,
+		"qcom,mdss-prefill-post-scaler-buffer-pixels",
+		&prefill->post_scaler_pixels);
+	if (rc) {
+		pr_err("prefill post scaler buffer pixels not specified\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(pdev->dev.of_node,
+		"qcom,mdss-prefill-pingpong-buffer-pixels",
+		&prefill->pp_pixels);
+	if (rc) {
+		pr_err("prefill pingpong buffer lines not specified\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(pdev->dev.of_node,
+		"qcom,mdss-prefill-fbc-lines", &prefill->fbc_lines);
+	if (rc) {
+		pr_err("prefill FBC lines not specified\n");
+		return rc;
+	}
+
+	return 0;
+}
+
 static int mdss_mdp_parse_dt_misc(struct platform_device *pdev)
 {
 	struct mdss_data_type *mdata = platform_get_drvdata(pdev);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 9eda285..98944b5 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -82,54 +82,99 @@
 	u32 smp_bytes;
 	u32 xres;
 	u32 src_w;
+	u32 dst_w;
 	u32 src_h;
 	u32 dst_h;
 	u32 dst_y;
 	u32 bpp;
 	bool is_yuv;
 	bool is_caf;
+	bool is_fbc;
 };
 
+static inline bool mdss_mdp_perf_is_caf(struct mdss_mdp_pipe *pipe)
+{
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+
+	/*
+	 * CAF mode filter is enabled when format is yuv and
+	 * upscaling. Post processing had the decision to use CAF
+	 * under these conditions.
+	 */
+	return ((mdata->mdp_rev >= MDSS_MDP_HW_REV_102) &&
+		pipe->src_fmt->is_yuv && ((pipe->src.h >> pipe->vert_deci) <=
+			pipe->dst.h));
+}
+
 static u32 mdss_mdp_perf_calc_pipe_prefill_bytes(struct mdss_mdp_prefill_params
 	*params)
 {
-	u32 prefill_bytes = 0, pp_bytes = 0,  ot_bytes = 8 * 128;
-	u32 y_buf_bytes = 4096;
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+	struct mdss_prefill_data *prefill = &mdata->prefill_data;
+	u32 prefill_bytes;
+	u32 y_buf_bytes;
 	u32 y_scaler_lines = 0, y_scaler_bytes = 0;
-	u32 pp_pixels = 4096, pp_lines;
+	u32 pp_bytes = 0, pp_lines = 0;
+	u32 post_scaler_bytes;
+	u32 fbc_bytes = 0;
 
-	/*
-	 * todo:
-	 * 1. add post_scaler_bytes and fbc
-	 * 2. add h/w related buffer parameters in device tree
-	 * 3. do is_caf check
-	 */
-	prefill_bytes += ot_bytes + params->smp_bytes;
+	prefill_bytes = prefill->ot_bytes + params->smp_bytes;
 
 	if (params->is_yuv) {
-		y_scaler_lines = (params->is_caf) ? 4 : 2;
-		if (params->src_h != params->dst_h)
-			y_scaler_bytes += y_scaler_lines * params->src_w * 2;
+		y_buf_bytes = prefill->y_buf_bytes;
+		if (params->src_h != params->dst_h) {
+			y_scaler_lines = (params->is_caf) ?
+				prefill->y_scaler_lines_caf :
+				prefill->y_scaler_lines_bilinear;
+			/*
+			 * y is src_width, u is src_width/2 and v is
+			 * src_width/2, so the total is scaler_lines *
+			 * src_w * 2
+			 */
+			y_scaler_bytes = y_scaler_lines * params->src_w * 2;
+		}
 	} else {
-		y_buf_bytes = 0;
-		y_scaler_lines = (params->src_h != params->dst_h) ? 2 : 0;
-		y_scaler_bytes = y_scaler_lines * params->src_w * params->bpp;
+		y_buf_bytes = 0; /* alway 0 for single plane sources */
+		if (params->src_h != params->dst_h) {
+			y_scaler_lines = prefill->y_scaler_lines_bilinear;
+			y_scaler_bytes = y_scaler_lines * params->src_w *
+				params->bpp;
+		}
 	}
 
 	prefill_bytes += y_buf_bytes + y_scaler_bytes;
 
-	pp_lines = (params->xres) ? DIV_ROUND_UP(pp_pixels, params->xres) : 0;
-	if (params->xres && params->dst_h && (params->dst_y <= pp_lines))
-		pp_bytes = ((params->src_w * params->bpp * pp_pixels /
-				params->xres) * params->src_h) / params->dst_h;
-	else
-		pp_bytes = 0;
+	post_scaler_bytes = prefill->post_scaler_pixels * params->bpp;
+	if (params->dst_h)
+		post_scaler_bytes = mult_frac(post_scaler_bytes, params->src_h,
+			params->dst_h);
+	if (params->dst_w)
+		post_scaler_bytes = mult_frac(post_scaler_bytes, params->src_w,
+			params->dst_w);
+	prefill_bytes += post_scaler_bytes;
 
+	if (params->xres)
+		pp_lines = DIV_ROUND_UP(prefill->pp_pixels, params->xres);
+	if (params->xres && params->dst_h && (params->dst_y <= pp_lines))
+		pp_bytes = ((params->src_w * params->bpp * prefill->pp_pixels /
+				params->xres) * params->src_h) / params->dst_h;
 	prefill_bytes += pp_bytes;
 
+	if (params->is_fbc) {
+		fbc_bytes = prefill->fbc_lines * params->bpp;
+		if (params->dst_h)
+			fbc_bytes = mult_frac(fbc_bytes, params->src_h,
+				params->dst_h);
+		if (params->dst_w)
+			fbc_bytes = mult_frac(fbc_bytes, params->src_w,
+				params->dst_w);
+	}
+	prefill_bytes += fbc_bytes;
+
 	pr_debug("ot=%d smp=%d y_buf=%d y_sc_l=%d y_sc=%d pp_lines=%d pp=%d\n",
-		ot_bytes, params->smp_bytes, y_buf_bytes, y_scaler_lines,
-		y_scaler_bytes, pp_lines, pp_bytes);
+		prefill->ot_bytes, params->smp_bytes, y_buf_bytes,
+		y_scaler_lines,	y_scaler_bytes, pp_lines, pp_bytes);
+	pr_debug("post_sc=%d fbc_bytes=%d\n", post_scaler_bytes, fbc_bytes);
 
 	return prefill_bytes;
 }
@@ -152,6 +197,7 @@
 	int fps = DEFAULT_FRAME_RATE;
 	u32 quota, rate, v_total, src_h, xres = 0;
 	struct mdss_mdp_img_rect src, dst;
+	bool is_fbc = false;
 	struct mdss_mdp_prefill_params prefill_params;
 
 	if (!pipe || !perf || !pipe->mixer)
@@ -170,6 +216,7 @@
 		fps = mdss_panel_get_framerate(pinfo);
 		v_total = mdss_panel_get_vtotal(pinfo);
 		xres = pinfo->xres;
+		is_fbc = pinfo->fbc.enabled;
 	} else {
 		v_total = mixer->height;
 		xres = mixer->width;
@@ -223,12 +270,14 @@
 	prefill_params.smp_bytes = mdss_mdp_smp_get_size(pipe);
 	prefill_params.xres = xres;
 	prefill_params.src_w = src.w;
+	prefill_params.dst_w = dst.w;
 	prefill_params.src_h = src_h;
 	prefill_params.dst_h = dst.h;
 	prefill_params.dst_y = dst.y;
 	prefill_params.bpp = pipe->src_fmt->bpp;
 	prefill_params.is_yuv = pipe->src_fmt->is_yuv;
-	prefill_params.is_caf = false;
+	prefill_params.is_caf = mdss_mdp_perf_is_caf(pipe);
+	prefill_params.is_fbc = is_fbc;
 
 	if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF)
 		perf->prefill_bytes =