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 =