summaryrefslogtreecommitdiff
path: root/drivers/video/fbdev/msm
diff options
context:
space:
mode:
authorHuaibin Yang <huaibiny@codeaurora.org>2013-12-06 18:27:47 -0800
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 20:25:20 -0700
commit25652b0e474e7bfbf77028eb7bc3cade8ac74253 (patch)
tree828044b4830c8659551135ab60dc1e30631c1508 /drivers/video/fbdev/msm
parenteb236d6a2dd1a61db1a1da6b0657e45fa91bfaba (diff)
msm: mdss: add mdp overlap and prefill bandwidth calculations
This patch implements a set of new equations proposed by h/w team to calculate mdp bandwidth. MDP has bandwidth requests during both blanking and active periods. During blanking area, mdp needs to fill its internal buffers, such as latency buffer, outstanding buffer, pingpong buffer, etc. This bandwidth is called prefill bandwidth and it is determined by the total amount of bytes of buffers to be filled and the total amount of blanking time available. The bandwidth for the active peroid is called overlap bandwidth which is the max bandwidth request of all overlapped regions. The final vote from mdp would be the worst case of prefill bandwidth and overlap bandwidth. Change-Id: Ib83caf6a3e15c33a2cd71d14e8413b1d9049de29 Signed-off-by: Huaibin Yang <huaibiny@codeaurora.org>
Diffstat (limited to 'drivers/video/fbdev/msm')
-rw-r--r--drivers/video/fbdev/msm/mdss.h1
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.c26
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.h10
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_ctl.c417
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pipe.c20
5 files changed, 300 insertions, 174 deletions
diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h
index c51ef7bca9ee..1bea46769622 100644
--- a/drivers/video/fbdev/msm/mdss.h
+++ b/drivers/video/fbdev/msm/mdss.h
@@ -136,7 +136,6 @@ struct mdss_data_type {
struct mdss_fudge_factor ab_factor;
struct mdss_fudge_factor ib_factor;
- struct mdss_fudge_factor high_ib_factor;
struct mdss_fudge_factor clk_factor;
struct mdss_hw_settings *hw_settings;
diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c
index ea0ac74091eb..c6c148862204 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp.c
@@ -2118,14 +2118,11 @@ static void mdss_mdp_parse_dt_fudge_factors(struct platform_device *pdev,
char *prop_name, struct mdss_fudge_factor *ff)
{
int rc;
- u32 data[2] = {0, 0};
-
- ff->numer = 1;
- ff->denom = 1;
+ u32 data[2] = {1, 1};
rc = mdss_mdp_parse_dt_handler(pdev, prop_name, data, 2);
if (rc) {
- pr_debug("err reading %s\n", prop_name);
+ pr_err("err reading %s\n", prop_name);
} else {
ff->numer = data[0];
ff->denom = data[1];
@@ -2156,12 +2153,27 @@ static int mdss_mdp_parse_dt_misc(struct platform_device *pdev)
if (rc)
pr_debug("Could not read optional property: highest bank bit\n");
+ /*
+ * 2x factor on AB because bus driver will divide by 2
+ * due to 2x ports to BIMC
+ */
+ mdata->ab_factor.numer = 2;
+ mdata->ab_factor.denom = 1;
mdss_mdp_parse_dt_fudge_factors(pdev, "qcom,mdss-ab-factor",
&mdata->ab_factor);
+
+ /*
+ * 1.2 factor on ib as default value. This value is
+ * experimentally determined and should be tuned in device
+ * tree.
+ */
+ mdata->ib_factor.numer = 6;
+ mdata->ib_factor.denom = 5;
mdss_mdp_parse_dt_fudge_factors(pdev, "qcom,mdss-ib-factor",
&mdata->ib_factor);
- mdss_mdp_parse_dt_fudge_factors(pdev, "qcom,mdss-high-ib-factor",
- &mdata->high_ib_factor);
+
+ mdata->clk_factor.numer = 1;
+ mdata->clk_factor.denom = 1;
mdss_mdp_parse_dt_fudge_factors(pdev, "qcom,mdss-clk-factor",
&mdata->clk_factor);
diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h
index 15900a8b0ed3..88134a409c09 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.h
+++ b/drivers/video/fbdev/msm/mdss_mdp.h
@@ -141,8 +141,10 @@ enum mdss_mdp_wb_ctl_type {
};
struct mdss_mdp_perf_params {
- u64 ib_quota;
- u64 ab_quota;
+ u64 bw_overlap;
+ u64 bw_prefill;
+ u32 prefill_bytes;
+ u64 bw_ctl;
u32 mdp_clk_rate;
};
@@ -171,10 +173,7 @@ struct mdss_mdp_ctl {
u32 dst_format;
bool is_secure;
- u32 bus_ab_quota;
- u32 bus_ib_quota;
u32 clk_rate;
- u32 perf_changed;
int force_screen_state;
struct mdss_mdp_perf_params cur_perf;
struct mdss_mdp_perf_params new_perf;
@@ -625,6 +624,7 @@ int mdss_mdp_pipe_map(struct mdss_mdp_pipe *pipe);
void mdss_mdp_pipe_unmap(struct mdss_mdp_pipe *pipe);
struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_dma(struct mdss_mdp_mixer *mixer);
+u32 mdss_mdp_smp_get_size(struct mdss_mdp_pipe *pipe);
int mdss_mdp_smp_reserve(struct mdss_mdp_pipe *pipe);
void mdss_mdp_smp_unreserve(struct mdss_mdp_pipe *pipe);
void mdss_mdp_smp_release(struct mdss_mdp_pipe *pipe);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
index e323ead3b300..246d05a4b5c0 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
@@ -18,14 +18,11 @@
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
+#include <linux/sort.h>
#include "mdss_fb.h"
#include "mdss_mdp.h"
-/* truncate at 1k */
-#define MDSS_MDP_BUS_FACTOR_SHIFT 10
-#define MDSS_MDP_BUS_FLOOR_BW (1600000000ULL >> MDSS_MDP_BUS_FACTOR_SHIFT)
-
static inline u64 fudge_factor(u64 val, u32 numer, u32 denom)
{
u64 result = (val * (u64)numer);
@@ -39,16 +36,9 @@ static inline u64 fudge_factor(u64 val, u32 numer, u32 denom)
#define IB_FUDGE_FACTOR(val) fudge_factor((val), \
(mdss_res->ib_factor.numer), (mdss_res->ib_factor.denom))
-#define HIGH_IB_FUDGE_FACTOR(val) fudge_factor((val), \
- (mdss_res->high_ib_factor.numer), (mdss_res->high_ib_factor.denom))
-
#define CLK_FUDGE_FACTOR(val) fudge_factor((val), \
(mdss_res->clk_factor.numer), (mdss_res->clk_factor.denom))
-#define MDSS_MDP_PERF_UPDATE_CLK BIT(0)
-#define MDSS_MDP_PERF_UPDATE_BUS BIT(1)
-#define MDSS_MDP_PERF_UPDATE_ALL -1
-
static DEFINE_MUTEX(mdss_mdp_ctl_lock);
static int mdss_mdp_mixer_free(struct mdss_mdp_mixer *mixer);
@@ -82,113 +72,60 @@ static inline u32 mdss_mdp_clk_fudge_factor(struct mdss_mdp_mixer *mixer,
return rate;
}
-static u32 __mdss_mdp_ctrl_perf_ovrd_helper(struct mdss_mdp_mixer *mixer,
- u32 *npipe)
+struct mdss_mdp_prefill_params {
+ u32 smp_bytes;
+ u32 xres;
+ u32 src_w;
+ u32 src_h;
+ u32 dst_h;
+ u32 dst_y;
+ u32 bpp;
+ bool is_yuv;
+ bool is_caf;
+};
+
+static u32 mdss_mdp_perf_calc_pipe_prefill_bytes(struct mdss_mdp_prefill_params
+ *params)
{
- struct mdss_panel_info *pinfo;
- struct mdss_mdp_pipe *pipe;
- u32 mnum, ovrd = 0;
-
- if (!mixer || !mixer->ctl->panel_data)
- return 0;
+ u32 prefill_bytes = 0, pp_bytes = 0, ot_bytes = 8 * 128;
+ u32 y_buf_bytes = 4096;
+ u32 y_scaler_lines = 0, y_scaler_bytes = 0;
+ u32 pp_pixels = 4096, pp_lines;
- pinfo = &mixer->ctl->panel_data->panel_info;
- for (mnum = 0; mnum < MDSS_MDP_MAX_STAGE; mnum++) {
- pipe = mixer->stage_pipe[mnum];
- if (pipe && pinfo) {
- *npipe = *npipe + 1;
- if ((pipe->src.w >= pipe->src.h) &&
- (pipe->src.w >= pinfo->xres))
- ovrd = 1;
- }
- }
-
- return ovrd;
-}
-
-/**
- * mdss_mdp_ctrl_perf_ovrd() - Determines if performance override is needed
- * @mdata: Struct containing references to all MDP5 hardware structures
- * and status info such as interupts, target caps etc.
- * @ab_quota: Arbitrated bandwidth quota
- * @ib_quota: Instantaneous bandwidth quota
- *
- * Function calculates the minimum required MDP and BIMC clocks to avoid MDP
- * underflow during portrait video playback. The calculations are based on the
- * way MDP fetches (bandwidth requirement) and processes data through
- * MDP pipeline (MDP clock requirement) based on frame size and scaling
- * requirements.
- */
-static void __mdss_mdp_ctrl_perf_ovrd(struct mdss_data_type *mdata,
- u64 *ab_quota, u64 *ib_quota)
-{
- struct mdss_mdp_ctl *ctl;
- u32 i, npipe = 0, ovrd = 0;
-
- for (i = 0; i < mdata->nctl; i++) {
- ctl = mdata->ctl_off + i;
- if (!ctl->power_on)
- continue;
- ovrd |= __mdss_mdp_ctrl_perf_ovrd_helper(
- ctl->mixer_left, &npipe);
- ovrd |= __mdss_mdp_ctrl_perf_ovrd_helper(
- ctl->mixer_right, &npipe);
- }
-
- *ab_quota = AB_FUDGE_FACTOR(*ab_quota);
- if (npipe > 1)
- *ib_quota = HIGH_IB_FUDGE_FACTOR(*ib_quota);
- else
- *ib_quota = IB_FUDGE_FACTOR(*ib_quota);
+ /*
+ * 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;
- if (ovrd && (*ib_quota < MDSS_MDP_BUS_FLOOR_BW)) {
- *ib_quota = MDSS_MDP_BUS_FLOOR_BW;
- pr_debug("forcing the BIMC clock to 200 MHz : %llu bytes",
- *ib_quota);
+ 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;
} else {
- pr_debug("ib quota : %llu bytes", *ib_quota);
+ 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;
}
-}
-static int mdss_mdp_ctl_perf_commit(struct mdss_data_type *mdata, u32 flags)
-{
- struct mdss_mdp_ctl *ctl;
- int cnum;
- unsigned long clk_rate = 0;
- u64 bus_ab_quota = 0, bus_ib_quota = 0;
+ prefill_bytes += y_buf_bytes + y_scaler_bytes;
- if (!flags) {
- pr_err("nothing to update\n");
- return -EINVAL;
- }
+ 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;
- mutex_lock(&mdss_mdp_ctl_lock);
- for (cnum = 0; cnum < mdata->nctl; cnum++) {
- ctl = mdata->ctl_off + cnum;
- if (ctl->power_on) {
- struct mdss_mdp_perf_params *perf = &ctl->cur_perf;
+ prefill_bytes += pp_bytes;
- bus_ab_quota += perf->ab_quota;
- bus_ib_quota += perf->ib_quota;
+ 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);
- if (perf->mdp_clk_rate > clk_rate)
- clk_rate = perf->mdp_clk_rate;
- }
- }
- if (flags & MDSS_MDP_PERF_UPDATE_BUS) {
- bus_ab_quota = bus_ib_quota;
- __mdss_mdp_ctrl_perf_ovrd(mdata, &bus_ab_quota, &bus_ib_quota);
- pr_debug("update ab=%llu ib=%llu\n",
- bus_ab_quota, bus_ib_quota);
- mdss_mdp_bus_scale_set_quota(bus_ab_quota, bus_ib_quota);
- }
- if (flags & MDSS_MDP_PERF_UPDATE_CLK) {
- pr_debug("update clk rate = %lu HZ\n", clk_rate);
- mdss_mdp_set_clk_rate(clk_rate);
- }
- mutex_unlock(&mdss_mdp_ctl_lock);
-
- return 0;
+ return prefill_bytes;
}
/**
@@ -207,8 +144,9 @@ int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
{
struct mdss_mdp_mixer *mixer;
int fps = DEFAULT_FRAME_RATE;
- u32 quota, rate, v_total, src_h;
+ u32 quota, rate, v_total, src_h, xres = 0;
struct mdss_mdp_img_rect src, dst;
+ struct mdss_mdp_prefill_params prefill_params;
if (!pipe || !perf || !pipe->mixer)
return -EINVAL;
@@ -225,13 +163,17 @@ int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
pinfo = &mixer->ctl->panel_data->panel_info;
fps = mdss_panel_get_framerate(pinfo);
v_total = mdss_panel_get_vtotal(pinfo);
+ xres = pinfo->xres;
} else {
v_total = mixer->height;
+ xres = mixer->width;
}
if (roi)
mdss_mdp_crop_rect(&src, &dst, roi);
+ pr_debug("v_total=%d, xres=%d fps=%d\n", v_total, xres, fps);
+
/*
* when doing vertical decimation lines will be skipped, hence there is
* no need to account for these lines in MDP clock or request bus
@@ -240,6 +182,11 @@ int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
src_h = src.h >> pipe->vert_deci;
quota = fps * src.w * src_h;
+
+ pr_debug("src(w,h)(%d,%d) dst(w,h)(%d,%d) dst_y=%d bpp=%d yuv=%d\n",
+ pipe->src.w, src_h, pipe->dst.w, pipe->dst.h, pipe->dst.y,
+ pipe->src_fmt->bpp, pipe->src_fmt->is_yuv);
+
if (pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_420)
/*
* with decimation, chroma is not downsampled, this means we
@@ -260,33 +207,59 @@ int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
if (mixer->rotator_mode) {
rate /= 4; /* block mode fetch at 4 pix/clk */
quota *= 2; /* bus read + write */
- perf->ib_quota = quota;
+ perf->bw_overlap = quota;
} else {
- perf->ib_quota = (quota / dst.h) * v_total;
+ perf->bw_overlap = (quota / dst.h) * v_total;
}
- perf->ab_quota = quota;
- rate = mdss_mdp_clk_fudge_factor(mixer, rate);
- perf->mdp_clk_rate = rate;
+ perf->mdp_clk_rate = mdss_mdp_clk_fudge_factor(mixer, rate);
+
+ prefill_params.smp_bytes = mdss_mdp_smp_get_size(pipe);
+ prefill_params.xres = xres;
+ prefill_params.src_w = src.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;
- pr_debug("src(w,h)(%d,%d) dst(w,h)(%d,%d) v_total=%d v_deci=%d fps=%d\n",
- pipe->src.w, pipe->src.h, pipe->dst.w, pipe->dst.h, v_total,
- pipe->vert_deci, fps);
- pr_debug("mixer=%d pnum=%d clk_rate=%u bus ab=%llu ib=%llu\n",
- mixer->num, pipe->num, rate, perf->ab_quota, perf->ib_quota);
+ if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF)
+ perf->prefill_bytes =
+ mdss_mdp_perf_calc_pipe_prefill_bytes(&prefill_params);
+ else
+ perf->prefill_bytes = 0;
+
+ pr_debug("mixer=%d pnum=%d clk_rate=%u bw_overlap=%llu prefill=%d\n",
+ mixer->num, pipe->num, perf->mdp_clk_rate, perf->bw_overlap,
+ perf->prefill_bytes);
return 0;
}
+static inline int mdss_mdp_perf_is_overlap(u32 y00, u32 y01, u32 y10, u32 y11)
+{
+ return (y10 < y00 && y11 >= y01) || (y10 >= y00 && y10 <= y01);
+}
+
+static inline int cmpu32(const void *a, const void *b)
+{
+ return (*(u32 *)a < *(u32 *)b) ? -1 : 0;
+}
+
static void mdss_mdp_perf_calc_mixer(struct mdss_mdp_mixer *mixer,
struct mdss_mdp_perf_params *perf)
{
struct mdss_mdp_pipe *pipe;
struct mdss_panel_info *pinfo = NULL;
int fps = DEFAULT_FRAME_RATE;
- u32 v_total;
+ u32 v_total = 0;
int i;
- u32 max_clk_rate = 0, ab_total = 0, ib_total = 0;
+ u32 max_clk_rate = 0;
+ u64 bw_overlap_max = 0;
+ u64 bw_overlap[MDSS_MDP_MAX_STAGE];
+ u32 v_region[MDSS_MDP_MAX_STAGE * 2];
+ u32 prefill_bytes = 0;
memset(perf, 0, sizeof(*perf));
@@ -306,13 +279,14 @@ static void mdss_mdp_perf_calc_mixer(struct mdss_mdp_mixer *mixer,
perf->mdp_clk_rate =
mdss_mdp_clk_fudge_factor(mixer, perf->mdp_clk_rate);
- if (!pinfo) {
- /* perf for bus writeback */
- perf->ab_quota = fps * mixer->width * mixer->height * 3;
- perf->ib_quota = perf->ab_quota;
- }
+ if (!pinfo) /* perf for bus writeback */
+ perf->bw_overlap =
+ fps * mixer->width * mixer->height * 3;
}
+ memset(bw_overlap, 0, sizeof(u64) * MDSS_MDP_MAX_STAGE);
+ memset(v_region, 0, sizeof(u32) * MDSS_MDP_MAX_STAGE * 2);
+
for (i = 0; i < MDSS_MDP_MAX_STAGE; i++) {
struct mdss_mdp_perf_params tmp;
pipe = mixer->stage_pipe[i];
@@ -321,20 +295,73 @@ static void mdss_mdp_perf_calc_mixer(struct mdss_mdp_mixer *mixer,
if (mdss_mdp_perf_calc_pipe(pipe, &tmp, &mixer->roi))
continue;
-
- ab_total += tmp.ab_quota >> MDSS_MDP_BUS_FACTOR_SHIFT;
- ib_total += tmp.ib_quota >> MDSS_MDP_BUS_FACTOR_SHIFT;
+ prefill_bytes += tmp.prefill_bytes;
+ bw_overlap[i] = tmp.bw_overlap;
+ v_region[2*i] = pipe->dst.y;
+ v_region[2*i + 1] = pipe->dst.y + pipe->dst.h;
if (tmp.mdp_clk_rate > max_clk_rate)
max_clk_rate = tmp.mdp_clk_rate;
}
- perf->ab_quota += ab_total << MDSS_MDP_BUS_FACTOR_SHIFT;
- perf->ib_quota += ib_total << MDSS_MDP_BUS_FACTOR_SHIFT;
+ /*
+ * Sort the v_region array so the total display area can be
+ * divided into individual regions. Check how many pipes fetch
+ * data for each region and sum them up, then the worst case
+ * of all regions is ib request.
+ */
+ sort(v_region, MDSS_MDP_MAX_STAGE * 2, sizeof(u32), cmpu32, NULL);
+ for (i = 1; i < MDSS_MDP_MAX_STAGE * 2; i++) {
+ int j;
+ u64 bw_max_region = 0;
+ u32 y0, y1;
+ pr_debug("v_region[%d]%d\n", i, v_region[i]);
+ if (v_region[i] == v_region[i-1])
+ continue;
+ y0 = (v_region[i-1]) ? v_region[i-1] + 1 : 0;
+ y1 = v_region[i];
+ for (j = 0; j < MDSS_MDP_MAX_STAGE; j++) {
+ if (!bw_overlap[j])
+ continue;
+ pipe = mixer->stage_pipe[j];
+ if (mdss_mdp_perf_is_overlap(y0, y1, pipe->dst.y,
+ (pipe->dst.y + pipe->dst.h)))
+ bw_max_region += bw_overlap[j];
+ pr_debug("v[%d](%d,%d)pipe[%d](%d,%d)bw(%llu %llu)\n",
+ i, y0, y1, j, pipe->dst.y,
+ pipe->dst.y + pipe->dst.h, bw_overlap[j],
+ bw_max_region);
+ }
+ bw_overlap_max = max(bw_overlap_max, bw_max_region);
+ }
+
+ perf->bw_overlap += bw_overlap_max;
+ perf->prefill_bytes += prefill_bytes;
+
if (max_clk_rate > perf->mdp_clk_rate)
perf->mdp_clk_rate = max_clk_rate;
- pr_debug("final mixer=%d clk_rate=%u bus ab=%llu ib=%llu\n", mixer->num,
- perf->mdp_clk_rate, perf->ab_quota, perf->ib_quota);
+ pr_debug("final mixer=%d video=%d clk_rate=%u bw=%llu prefill=%d\n",
+ mixer->num, mixer->ctl->is_video_mode, perf->mdp_clk_rate,
+ perf->bw_overlap, perf->prefill_bytes);
+
+}
+
+static u32 mdss_mdp_get_vbp_factor(struct mdss_mdp_ctl *ctl)
+{
+ u32 fps, v_total, vbp, vbp_fac;
+ struct mdss_panel_info *pinfo;
+
+ if (!ctl || !ctl->panel_data)
+ return 0;
+
+ pinfo = &ctl->panel_data->panel_info;
+ fps = mdss_panel_get_framerate(pinfo);
+ v_total = mdss_panel_get_vtotal(pinfo);
+ vbp = pinfo->lcdc.v_back_porch + pinfo->lcdc.v_pulse_width;
+ vbp_fac = (vbp) ? fps * v_total / vbp : 0;
+ pr_debug("vbp_fac=%d vbp=%d v_total=%d\n", vbp_fac, vbp, v_total);
+
+ return vbp_fac;
}
static void mdss_mdp_perf_calc_ctl(struct mdss_mdp_ctl *ctl,
@@ -346,15 +373,15 @@ static void mdss_mdp_perf_calc_ctl(struct mdss_mdp_ctl *ctl,
if (ctl->mixer_left) {
mdss_mdp_perf_calc_mixer(ctl->mixer_left, &tmp);
- perf->ab_quota += tmp.ab_quota;
- perf->ib_quota += tmp.ib_quota;
+ perf->bw_overlap += tmp.bw_overlap;
+ perf->prefill_bytes += tmp.prefill_bytes;
perf->mdp_clk_rate = tmp.mdp_clk_rate;
}
if (ctl->mixer_right) {
mdss_mdp_perf_calc_mixer(ctl->mixer_right, &tmp);
- perf->ab_quota += tmp.ab_quota;
- perf->ib_quota += tmp.ib_quota;
+ perf->bw_overlap += tmp.bw_overlap;
+ perf->prefill_bytes += tmp.prefill_bytes;
if (tmp.mdp_clk_rate > perf->mdp_clk_rate)
perf->mdp_clk_rate = tmp.mdp_clk_rate;
@@ -368,46 +395,115 @@ static void mdss_mdp_perf_calc_ctl(struct mdss_mdp_ctl *ctl,
}
/* request minimum bandwidth to have bus clock on when display is on */
- if (perf->ib_quota == 0)
- perf->ib_quota = SZ_16M;
+ if (perf->bw_overlap == 0)
+ perf->bw_overlap = SZ_16M;
+
+ if (ctl->intf_type != MDSS_MDP_NO_INTF) {
+ u32 vbp_fac = mdss_mdp_get_vbp_factor(ctl);
+ perf->bw_prefill = perf->prefill_bytes;
+ /*
+ * Prefill bandwidth equals the amount of data (number
+ * of prefill_bytes) divided by the the amount time
+ * available (blanking period). It is equivalent that
+ * prefill bytes times a factor in unit Hz, which is
+ * the reciprocal of time.
+ */
+ perf->bw_prefill *= vbp_fac;
+ }
+
+ perf->bw_ctl = max(perf->bw_prefill, perf->bw_overlap);
+
+ if (ctl->is_video_mode)
+ perf->bw_ctl = IB_FUDGE_FACTOR(perf->bw_ctl);
- pr_debug("final ctl=%d clk_rate=%u bus ab=%llu ib=%llu\n", ctl->num,
- perf->mdp_clk_rate, perf->ab_quota, perf->ib_quota);
+ pr_debug("ctl=%d clk_rate=%u\n", ctl->num, perf->mdp_clk_rate);
+ pr_debug("bw_overlap=%llu bw_prefill=%llu prefill_byptes=%d\n",
+ perf->bw_overlap, perf->bw_prefill, perf->prefill_bytes);
}
static void mdss_mdp_ctl_perf_update(struct mdss_mdp_ctl *ctl,
int params_changed)
{
- u32 flags = 0;
struct mdss_mdp_perf_params *new, *old;
+ int update_bus = 0, update_clk = 0;
+ struct mdss_data_type *mdata;
+
+ if (!ctl || !ctl->mdata)
+ return;
+ mutex_lock(&mdss_mdp_ctl_lock);
+
+ mdata = ctl->mdata;
old = &ctl->cur_perf;
new = &ctl->new_perf;
- if (params_changed) {
- mdss_mdp_perf_calc_ctl(ctl, new);
+ if (ctl->power_on) {
+ if (params_changed)
+ mdss_mdp_perf_calc_ctl(ctl, new);
/*
- * if params have just changed delay the update until later
- * once the hw configuration has been flushed to MDP
+ * if params have just changed delay the update until
+ * later once the hw configuration has been flushed to
+ * MDP
*/
- if ((new->mdp_clk_rate <= old->mdp_clk_rate) &&
- (new->ib_quota <= old->ib_quota)) {
- pr_debug("perf req is decreasing, delay update\n");
- return;
+ if ((params_changed && (new->bw_ctl > old->bw_ctl)) ||
+ (!params_changed && (new->bw_ctl < old->bw_ctl))) {
+ pr_debug("c=%d p=%d new_bw=%llu,old_bw=%llu\n",
+ ctl->num, params_changed, new->bw_ctl,
+ old->bw_ctl);
+ old->bw_ctl = new->bw_ctl;
+ update_bus = 1;
+ }
+
+ if ((params_changed && (new->mdp_clk_rate > old->mdp_clk_rate))
+ || (!params_changed && (new->mdp_clk_rate <
+ old->mdp_clk_rate))) {
+ old->mdp_clk_rate = new->mdp_clk_rate;
+ update_clk = 1;
+ }
+ } else {
+ memset(old, 0, sizeof(old));
+ memset(new, 0, sizeof(new));
+ update_bus = 1;
+ update_clk = 1;
+ }
+
+ if (update_bus) {
+ u64 bw_sum_of_intfs = 0;
+ u64 bus_ab_quota = 0, bus_ib_quota = 0;
+ int i;
+
+ for (i = 0; i < mdata->nctl; i++) {
+ struct mdss_mdp_ctl *ctl;
+ ctl = mdata->ctl_off + i;
+ if (ctl->power_on) {
+ bw_sum_of_intfs += ctl->cur_perf.bw_ctl;
+ pr_debug("c=%d bw=%llu\n", ctl->num,
+ ctl->cur_perf.bw_ctl);
+ }
}
+ bus_ib_quota = bw_sum_of_intfs;
+ bus_ab_quota = AB_FUDGE_FACTOR(bw_sum_of_intfs);
+ mdss_mdp_bus_scale_set_quota(bus_ab_quota, bus_ib_quota);
+ pr_debug("ab=%llu ib=%llu\n", bus_ab_quota, bus_ib_quota);
}
- if ((old->ab_quota != new->ab_quota) ||
- (old->ib_quota != new->ib_quota))
- flags |= MDSS_MDP_PERF_UPDATE_BUS;
- if (old->mdp_clk_rate != new->mdp_clk_rate)
- flags |= MDSS_MDP_PERF_UPDATE_CLK;
+ if (update_clk) {
+ u32 clk_rate = 0;
+ int i;
- if (flags) {
- ctl->cur_perf = ctl->new_perf;
- mdss_mdp_ctl_perf_commit(ctl->mdata, flags);
+ for (i = 0; i < mdata->nctl; i++) {
+ struct mdss_mdp_ctl *ctl;
+ ctl = mdata->ctl_off + i;
+ if (ctl->power_on)
+ clk_rate = max(ctl->cur_perf.mdp_clk_rate,
+ clk_rate);
+ }
+ mdss_mdp_set_clk_rate(clk_rate);
+ pr_debug("update clk rate = %d HZ\n", clk_rate);
}
+
+ mutex_unlock(&mdss_mdp_ctl_lock);
}
static struct mdss_mdp_ctl *mdss_mdp_ctl_alloc(struct mdss_data_type *mdata,
@@ -650,7 +746,7 @@ int mdss_mdp_wb_mixer_destroy(struct mdss_mdp_mixer *mixer)
mdss_mdp_ctl_free(ctl);
- mdss_mdp_ctl_perf_commit(ctl->mdata, MDSS_MDP_PERF_UPDATE_ALL);
+ mdss_mdp_ctl_perf_update(ctl, 0);
return 0;
}
@@ -1291,8 +1387,7 @@ int mdss_mdp_ctl_stop(struct mdss_mdp_ctl *ctl)
ctl->power_on = false;
ctl->play_cnt = 0;
- memset(&ctl->cur_perf, 0, sizeof(ctl->cur_perf));
- mdss_mdp_ctl_perf_commit(ctl->mdata, MDSS_MDP_PERF_UPDATE_ALL);
+ mdss_mdp_ctl_perf_update(ctl, 0);
}
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pipe.c b/drivers/video/fbdev/msm/mdss_mdp_pipe.c
index d254c091ee5b..bd1b90001d7b 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pipe.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pipe.c
@@ -108,6 +108,26 @@ static void mdss_mdp_smp_mmb_free(unsigned long *smp, bool write)
}
}
+/**
+ * @mdss_mdp_smp_get_size - get allocated smp size for a pipe
+ * @pipe: pointer to a pipe
+ *
+ * Function counts number of blocks that are currently allocated for a
+ * pipe, then smp buffer size is number of blocks multiplied by block
+ * size.
+ */
+u32 mdss_mdp_smp_get_size(struct mdss_mdp_pipe *pipe)
+{
+ int i, mb_cnt = 0;
+
+ for (i = 0; i < MAX_PLANES; i++) {
+ mb_cnt += bitmap_weight(pipe->smp_map[i].allocated, SMP_MB_CNT);
+ mb_cnt += bitmap_weight(pipe->smp_map[i].fixed, SMP_MB_CNT);
+ }
+
+ return mb_cnt * SMP_MB_SIZE;
+}
+
static void mdss_mdp_smp_set_wm_levels(struct mdss_mdp_pipe *pipe, int mb_cnt)
{
u32 fetch_size, val, wm[3];