summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIngrid Gallardo <ingridg@codeaurora.org>2016-03-16 17:56:56 -0700
committerKyle Yan <kyan@codeaurora.org>2016-04-28 16:43:58 -0700
commit950ed52656ea6859a035ebffd19640d01bb72447 (patch)
treedc0e98bfe42155a9fb8696464fc20699566ea6af
parent49765e580abe02bb5786170322e1f135e03c24f9 (diff)
msm: mdss: add support for amortized prefill
Starting with sde 3.0, prefill bandwidth can be amortized depending on the configuration. This change adds support for this feature. Change-Id: I501e11325365ec900a2ef8ee5bcbcd66f5647f64 Signed-off-by: Ingrid Gallardo <ingridg@codeaurora.org>
-rw-r--r--drivers/video/fbdev/msm/mdss.h5
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.c18
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.h7
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_ctl.c267
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_hwio.h3
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pipe.c286
6 files changed, 462 insertions, 124 deletions
diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h
index b5fd49de457b..a2046fd5b9cf 100644
--- a/drivers/video/fbdev/msm/mdss.h
+++ b/drivers/video/fbdev/msm/mdss.h
@@ -110,6 +110,10 @@ struct mdss_prefill_data {
u32 post_scaler_pixels;
u32 pp_pixels;
u32 fbc_lines;
+ u32 ts_threshold;
+ u32 ts_end;
+ u32 ts_overhead;
+ struct mult_factor ts_rate;
struct simplified_prefill_factors prefill_factors;
};
@@ -185,6 +189,7 @@ enum mdss_qos_settings {
MDSS_QOS_PER_PIPE_LUT,
MDSS_QOS_SIMPLIFIED_PREFILL,
MDSS_QOS_VBLANK_PANIC_CTRL,
+ MDSS_QOS_TS_PREFILL,
MDSS_QOS_MAX,
};
diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c
index 266fa8cc8192..253141072795 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp.c
@@ -1390,6 +1390,14 @@ void mdss_mdp_init_default_prefill_factors(struct mdss_data_type *mdata)
mdata->prefill_data.prefill_factors.fmt_linear_factor = 1;
mdata->prefill_data.prefill_factors.scale_factor = 1;
mdata->prefill_data.prefill_factors.xtra_ff_factor = 2;
+
+ if (test_bit(MDSS_QOS_TS_PREFILL, mdata->mdss_qos_map)) {
+ mdata->prefill_data.ts_threshold = 25;
+ mdata->prefill_data.ts_end = 8;
+ mdata->prefill_data.ts_rate.numer = 1;
+ mdata->prefill_data.ts_rate.denom = 4;
+ mdata->prefill_data.ts_overhead = 2;
+ }
}
static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata)
@@ -1514,7 +1522,7 @@ static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata)
mdata->per_pipe_ib_factor.denom = 5;
mdata->apply_post_scale_bytes = false;
mdata->hflip_buffer_reused = false;
- mdata->min_prefill_lines = 21;
+ mdata->min_prefill_lines = 25;
mdata->has_ubwc = true;
mdata->pixel_ram_size = 50 * 1024;
mdata->rects_per_sspp[MDSS_MDP_PIPE_TYPE_DMA] = 2;
@@ -1525,6 +1533,7 @@ static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata)
set_bit(MDSS_QOS_OTLIM, mdata->mdss_qos_map);
set_bit(MDSS_QOS_PER_PIPE_LUT, mdata->mdss_qos_map);
set_bit(MDSS_QOS_SIMPLIFIED_PREFILL, mdata->mdss_qos_map);
+ set_bit(MDSS_QOS_TS_PREFILL, mdata->mdss_qos_map);
set_bit(MDSS_CAPS_YUV_CONFIG, mdata->mdss_caps_map);
set_bit(MDSS_CAPS_SCM_RESTORE_NOT_REQUIRED,
mdata->mdss_caps_map);
@@ -1988,6 +1997,13 @@ ssize_t mdss_mdp_show_capabilities(struct device *dev,
mdata->prefill_data.prefill_factors.xtra_ff_factor);
}
+ if (test_bit(MDSS_QOS_TS_PREFILL, mdata->mdss_qos_map)) {
+ SPRINT("amortizable_threshold=%d\n",
+ mdata->prefill_data.ts_threshold);
+ SPRINT("system_overhead_lines=%d\n",
+ mdata->prefill_data.ts_overhead);
+ }
+
if (mdata->props)
SPRINT("props=%d\n", mdata->props);
if (mdata->max_bw_low)
diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h
index 6abe08111334..85945890a7a4 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.h
+++ b/drivers/video/fbdev/msm/mdss_mdp.h
@@ -1479,9 +1479,16 @@ int mdss_mdp_perf_bw_check(struct mdss_mdp_ctl *ctl,
struct mdss_mdp_pipe **right_plist, int right_cnt);
int mdss_mdp_perf_bw_check_pipe(struct mdss_mdp_perf_params *perf,
struct mdss_mdp_pipe *pipe);
+u32 mdss_mdp_get_pipe_overlap_bw(struct mdss_mdp_pipe *pipe,
+ struct mdss_rect *roi, u32 flags);
+int mdss_mdp_get_panel_params(struct mdss_mdp_pipe *pipe,
+ struct mdss_mdp_mixer *mixer, u32 *fps, u32 *v_total,
+ u32 *h_total, u32 *xres);
int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
struct mdss_mdp_perf_params *perf, struct mdss_rect *roi,
u32 flags);
+bool mdss_mdp_is_amortizable_pipe(struct mdss_mdp_pipe *pipe,
+ struct mdss_mdp_mixer *mixer, struct mdss_data_type *mdata);
u32 mdss_mdp_calc_latency_buf_bytes(bool is_yuv, bool is_bwc,
bool is_tile, u32 src_w, u32 bpp, bool use_latency_buf_percentage,
u32 smp_bytes, bool is_ubwc, bool is_nv12, bool is_hflip);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
index 46d8b4ccd3f4..8260a6ec38df 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
@@ -560,8 +560,13 @@ static u32 get_pipe_mdp_clk_rate(struct mdss_mdp_pipe *pipe,
struct mdss_mdp_mixer *mixer;
u32 rate, src_h;
+ /*
+ * when doing vertical decimation lines will be skipped, hence there is
+ * no need to account for these lines in MDP clock or request bus
+ * bandwidth to fetch them.
+ */
mixer = pipe->mixer_left;
- src_h = src.h >> pipe->vert_deci;
+ src_h = DECIMATED_DIMENSION(src.h, pipe->vert_deci);
if (mixer->rotator_mode) {
@@ -594,6 +599,144 @@ static u32 get_pipe_mdp_clk_rate(struct mdss_mdp_pipe *pipe,
return rate;
}
+static u32 mdss_mdp_get_rotator_fps(struct mdss_mdp_pipe *pipe)
+{
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+ u32 fps;
+
+ if (pipe->src.w >= 3840 || pipe->src.h >= 3840)
+ fps = ROTATOR_LOW_FRAME_RATE;
+ else if (mdata->traffic_shaper_en)
+ fps = DEFAULT_ROTATOR_FRAME_RATE;
+ else if (pipe->frame_rate)
+ fps = pipe->frame_rate;
+ else
+ fps = DEFAULT_FRAME_RATE;
+
+ pr_debug("rotator fps:%d\n", fps);
+
+ return fps;
+}
+
+int mdss_mdp_get_panel_params(struct mdss_mdp_pipe *pipe,
+ struct mdss_mdp_mixer *mixer, u32 *fps, u32 *v_total,
+ u32 *h_total, u32 *xres)
+{
+
+ if (mixer->rotator_mode) {
+ *fps = mdss_mdp_get_rotator_fps(pipe);
+ } else if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
+ struct mdss_panel_info *pinfo;
+
+ if (!mixer->ctl)
+ return -EINVAL;
+
+ pinfo = &mixer->ctl->panel_data->panel_info;
+ if (pinfo->type == MIPI_VIDEO_PANEL) {
+ *fps = pinfo->panel_max_fps;
+ *v_total = pinfo->panel_max_vtotal;
+ } else {
+ *fps = mdss_panel_get_framerate(pinfo);
+ *v_total = mdss_panel_get_vtotal(pinfo);
+ }
+ *xres = get_panel_width(mixer->ctl);
+ *h_total = mdss_panel_get_htotal(pinfo, false);
+
+ if (is_pingpong_split(mixer->ctl->mfd))
+ *h_total += mdss_panel_get_htotal(
+ &mixer->ctl->panel_data->next->panel_info,
+ false);
+ } else {
+ *v_total = mixer->height;
+ *xres = mixer->width;
+ *h_total = mixer->width;
+ }
+
+ return 0;
+}
+
+u32 mdss_mdp_get_pipe_overlap_bw(struct mdss_mdp_pipe *pipe,
+ struct mdss_rect *roi, u32 flags)
+{
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+ struct mdss_mdp_mixer *mixer = pipe->mixer_left;
+ struct mdss_rect src, dst;
+ u32 v_total, fps, h_total, xres;
+ u32 quota, src_h;
+
+ if (mdss_mdp_get_panel_params(pipe, mixer, &fps, &v_total,
+ &h_total, &xres)) {
+ pr_err(" error retreiving the panel params!\n");
+ return -EINVAL;
+ }
+
+ dst = pipe->dst;
+ src = pipe->src;
+
+ /* crop rectangles */
+ if (roi && !mixer->ctl->is_video_mode && !pipe->src_split_req)
+ mdss_mdp_crop_rect(&src, &dst, roi);
+
+ /*
+ * when doing vertical decimation lines will be skipped, hence there is
+ * no need to account for these lines in MDP clock or request bus
+ * bandwidth to fetch them.
+ */
+ src_h = DECIMATED_DIMENSION(src.h, pipe->vert_deci);
+
+ quota = fps * src.w * src_h;
+
+ if (pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_420)
+ /*
+ * with decimation, chroma is not downsampled, this means we
+ * need to allocate bw for extra lines that will be fetched
+ */
+ if (pipe->vert_deci)
+ quota *= 2;
+ else
+ quota = (quota * 3) / 2;
+ else
+ quota *= pipe->src_fmt->bpp;
+
+ if (mixer->rotator_mode) {
+ if (test_bit(MDSS_QOS_OVERHEAD_FACTOR,
+ mdata->mdss_qos_map)) {
+ /* rotator read */
+ quota = apply_comp_ratio_factor(quota,
+ pipe->src_fmt, &pipe->comp_ratio);
+ /*
+ * rotator write: here we are using src_fmt since
+ * current implementation only supports calculate
+ * bandwidth based in the source parameters.
+ * The correct fine-tuned calculation should use
+ * destination format and destination rectangles to
+ * calculate the bandwidth, but leaving this
+ * calculation as per current support.
+ */
+ quota += apply_comp_ratio_factor(quota,
+ pipe->src_fmt, &pipe->comp_ratio);
+ } else {
+ quota *= 2; /* bus read + write */
+ }
+ } else {
+
+ quota = mult_frac(quota, v_total, dst.h);
+ if (!mixer->ctl->is_video_mode)
+ quota = mult_frac(quota, h_total, xres);
+
+ if (test_bit(MDSS_QOS_OVERHEAD_FACTOR,
+ mdata->mdss_qos_map))
+ quota = apply_comp_ratio_factor(quota,
+ pipe->src_fmt, &pipe->comp_ratio);
+ }
+
+ pr_debug("quota:%d src.w:%d src.h%d comp:[%d, %d]\n",
+ quota, src.w, src_h, pipe->comp_ratio.numer,
+ pipe->comp_ratio.denom);
+
+ return quota;
+}
+
static inline bool validate_comp_ratio(struct mult_factor *factor)
{
return factor->numer && factor->denom;
@@ -617,25 +760,6 @@ u32 apply_comp_ratio_factor(u32 quota,
return quota;
}
-static u32 mdss_mdp_get_rotator_fps(struct mdss_mdp_pipe *pipe)
-{
- struct mdss_data_type *mdata = mdss_mdp_get_mdata();
- u32 fps = DEFAULT_FRAME_RATE;
-
- if (pipe->frame_rate)
- fps = pipe->frame_rate;
-
- if (mdata->traffic_shaper_en)
- fps = DEFAULT_ROTATOR_FRAME_RATE;
-
- if (pipe->src.w >= 3840 || pipe->src.h >= 3840)
- fps = ROTATOR_LOW_FRAME_RATE;
-
- pr_debug("rotator fps:%d\n", fps);
-
- return fps;
-}
-
u64 mdss_mdp_perf_calc_simplified_prefill(struct mdss_mdp_pipe *pipe,
u32 v_total, u32 fps, struct mdss_mdp_ctl *ctl)
{
@@ -712,13 +836,14 @@ exit:
* fetches (bandwidth requirement) and processes data through MDP pipeline
* (MDP clock requirement) based on frame size and scaling requirements.
*/
+
int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
struct mdss_mdp_perf_params *perf, struct mdss_rect *roi,
u32 flags)
{
struct mdss_mdp_mixer *mixer;
int fps = DEFAULT_FRAME_RATE;
- u32 quota, v_total = 0, src_h, xres = 0, h_total = 0;
+ u32 v_total = 0, src_h, xres = 0, h_total = 0;
struct mdss_rect src, dst;
bool is_fbc = false;
struct mdss_mdp_prefill_params prefill_params;
@@ -733,105 +858,45 @@ int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
dst = pipe->dst;
src = pipe->src;
- if (mixer->rotator_mode) {
- fps = mdss_mdp_get_rotator_fps(pipe);
- } else if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
- struct mdss_panel_info *pinfo;
+ /*
+ * when doing vertical decimation lines will be skipped, hence there is
+ * no need to account for these lines in MDP clock or request bus
+ * bandwidth to fetch them.
+ */
+ src_h = DECIMATED_DIMENSION(src.h, pipe->vert_deci);
+
+ if (mdss_mdp_get_panel_params(pipe, mixer, &fps, &v_total,
+ &h_total, &xres)) {
+ pr_err(" error retreiving the panel params!\n");
+ return -EINVAL;
+ }
+ if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
if (!mixer->ctl)
return -EINVAL;
-
- pinfo = &mixer->ctl->panel_data->panel_info;
- if (pinfo->type == MIPI_VIDEO_PANEL) {
- fps = pinfo->panel_max_fps;
- v_total = pinfo->panel_max_vtotal;
- } else {
- fps = mdss_panel_get_framerate(pinfo);
- v_total = mdss_panel_get_vtotal(pinfo);
- }
- xres = get_panel_width(mixer->ctl);
- is_fbc = pinfo->fbc.enabled;
- h_total = mdss_panel_get_htotal(pinfo, false);
-
- if (is_pingpong_split(mixer->ctl->mfd))
- h_total += mdss_panel_get_htotal(
- &mixer->ctl->panel_data->next->panel_info,
- false);
- } else {
- v_total = mixer->height;
- xres = mixer->width;
- h_total = mixer->width;
+ is_fbc = mixer->ctl->panel_data->panel_info.fbc.enabled;
}
mixer->ctl->frame_rate = fps;
+ /* crop rectangles */
if (roi && !mixer->ctl->is_video_mode && !pipe->src_split_req)
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
- * bandwidth to fetch them.
- */
- src_h = DECIMATED_DIMENSION(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
- * need to allocate bw for extra lines that will be fetched
- */
- if (pipe->vert_deci)
- quota *= 2;
- else
- quota = (quota * 3) / 2;
- else
- quota *= pipe->src_fmt->bpp;
-
- if (mixer->rotator_mode) {
- if (test_bit(MDSS_QOS_OVERHEAD_FACTOR,
- mdata->mdss_qos_map)) {
- /* rotator read */
- quota = apply_comp_ratio_factor(quota,
- pipe->src_fmt, &pipe->comp_ratio);
- /*
- * rotator write: here we are using src_fmt since
- * current implementation only supports calculate
- * bandwidth based in the source parameters.
- * The correct fine-tuned calculation should use
- * destination format and destination rectangles to
- * calculate the bandwidth, but leaving this
- * calculation as per current support.
- */
- quota += apply_comp_ratio_factor(quota,
- pipe->src_fmt, &pipe->comp_ratio);
- } else {
- quota *= 2; /* bus read + write */
- }
- } else {
-
- quota = mult_frac(quota, v_total, dst.h);
- if (!mixer->ctl->is_video_mode)
- quota = mult_frac(quota, h_total, xres);
-
- if (test_bit(MDSS_QOS_OVERHEAD_FACTOR,
- mdata->mdss_qos_map))
- quota = apply_comp_ratio_factor(quota,
- pipe->src_fmt, &pipe->comp_ratio);
- }
-
- perf->bw_overlap = quota;
+ perf->bw_overlap = mdss_mdp_get_pipe_overlap_bw(pipe, roi,
+ flags);
perf->mdp_clk_rate = get_pipe_mdp_clk_rate(pipe, src, dst,
fps, v_total, flags);
+ pr_debug("bw:%llu clk:%d\n", perf->bw_overlap,
+ perf->mdp_clk_rate);
+
if (pipe->flags & MDP_SOLID_FILL) {
perf->bw_overlap = 0;
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_hwio.h b/drivers/video/fbdev/msm/mdss_mdp_hwio.h
index 7669a0be21c5..6c1a286b5d7e 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_hwio.h
+++ b/drivers/video/fbdev/msm/mdss_mdp_hwio.h
@@ -250,6 +250,9 @@ enum mdss_mdp_sspp_chroma_samp_type {
#define MDSS_MDP_REG_SSPP_QOS_CTRL 0x06C
#define MDSS_MDP_REG_SSPP_CDP_CTRL 0x134
#define MDSS_MDP_REG_SSPP_UBWC_ERROR_STATUS 0x138
+#define MDSS_MDP_REG_SSPP_TRAFFIC_SHAPER 0x130
+#define MDSS_MDP_REG_SSPP_TRAFFIC_SHAPER_PREFILL 0x150
+#define MDSS_MDP_REG_SSPP_TRAFFIC_SHAPER_REC1_PREFILL 0x154
#define MDSS_MDP_REG_SSPP_MULTI_REC_OP_MODE 0x170
#define MDSS_MDP_REG_SSPP_OUT_SIZE_REC1 0x160
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pipe.c b/drivers/video/fbdev/msm/mdss_mdp_pipe.c
index 39d5666db4bf..a47477e2c9ef 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pipe.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pipe.c
@@ -39,8 +39,8 @@
#define PANIC_LUT_NRT_READ 0x0
#define ROBUST_LUT_NRT_READ 0xFFFF
-/* Priority 2, no panic */
-#define VBLANK_PANIC_DEFAULT_CONFIG 0x200000
+#define VBLANK_PANIC_DEFAULT_CONFIG 0x200000 /* Priority 2, no panic */
+#define VBLANK_PANIC_CREQ_MASK 0x300030
#define QSEED3_DEFAULT_PRELAOD_H 0x4
#define QSEED3_DEFAULT_PRELAOD_V 0x3
@@ -60,6 +60,20 @@ static u32 mdss_mdp_calc_per_plane_num_blks(u32 ystride,
struct mdss_mdp_pipe *pipe);
static int mdss_mdp_pipe_program_pixel_extn(struct mdss_mdp_pipe *pipe);
+/**
+ * enum mdss_mdp_pipe_qos - Different qos configurations for each pipe
+ *
+ * @MDSS_MDP_PIPE_QOS_VBLANK_CTRL: Setup VBLANK qos for the pipe.
+ * @MDSS_MDP_PIPE_QOS_VBLANK_AMORTIZE: Enables Amortization within pipe.
+ * this configuration is mutually exclusive from VBLANK_CTRL.
+ * @MDSS_MDP_PIPE_QOS_PANIC_CTRL: Setup panic for the pipe.
+ */
+enum mdss_mdp_pipe_qos {
+ MDSS_MDP_PIPE_QOS_VBLANK_CTRL = BIT(0),
+ MDSS_MDP_PIPE_QOS_VBLANK_AMORTIZE = BIT(1),
+ MDSS_MDP_PIPE_QOS_PANIC_CTRL = BIT(2),
+};
+
static inline void mdss_mdp_pipe_write(struct mdss_mdp_pipe *pipe,
u32 reg, u32 val)
{
@@ -222,6 +236,39 @@ static void mdss_mdp_config_pipe_panic_lut(struct mdss_mdp_pipe *pipe)
panic_lut, robust_lut);
}
+static void mdss_mdp_pipe_qos_ctrl(struct mdss_mdp_pipe *pipe,
+ bool enable, u32 flags)
+{
+ u32 per_pipe_qos;
+
+ per_pipe_qos = mdss_mdp_pipe_read(pipe, MDSS_MDP_REG_SSPP_QOS_CTRL);
+
+ if (flags & MDSS_MDP_PIPE_QOS_VBLANK_CTRL) {
+ per_pipe_qos |= VBLANK_PANIC_DEFAULT_CONFIG;
+
+ if (enable)
+ per_pipe_qos |= BIT(16);
+ else
+ per_pipe_qos &= ~BIT(16);
+ }
+
+ if (flags & MDSS_MDP_PIPE_QOS_VBLANK_AMORTIZE) {
+ /* this feature overrules previous VBLANK_CTRL */
+ per_pipe_qos &= ~BIT(16);
+ per_pipe_qos &= ~VBLANK_PANIC_CREQ_MASK; /* clear vblank bits */
+ }
+
+ if (flags & MDSS_MDP_PIPE_QOS_PANIC_CTRL) {
+ if (enable)
+ per_pipe_qos |= BIT(0);
+ else
+ per_pipe_qos &= ~BIT(0);
+ }
+
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_QOS_CTRL,
+ per_pipe_qos);
+}
+
/**
* @mdss_mdp_pipe_panic_vblank_signal_ctrl -
* @pipe: pointer to a pipe
@@ -233,7 +280,6 @@ static void mdss_mdp_config_pipe_panic_lut(struct mdss_mdp_pipe *pipe)
static int mdss_mdp_pipe_panic_vblank_signal_ctrl(struct mdss_mdp_pipe *pipe,
bool enable)
{
- uint32_t panic_ctrl;
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
if (!mdata->has_panic_ctrl)
@@ -247,17 +293,7 @@ static int mdss_mdp_pipe_panic_vblank_signal_ctrl(struct mdss_mdp_pipe *pipe,
mutex_lock(&mdata->reg_lock);
- panic_ctrl = mdss_mdp_pipe_read(pipe,
- MDSS_MDP_REG_SSPP_QOS_CTRL);
-
- panic_ctrl |= VBLANK_PANIC_DEFAULT_CONFIG;
-
- if (enable)
- panic_ctrl |= BIT(16);
- else
- panic_ctrl &= ~BIT(16);
- mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_QOS_CTRL,
- panic_ctrl);
+ mdss_mdp_pipe_qos_ctrl(pipe, enable, MDSS_MDP_PIPE_QOS_VBLANK_CTRL);
mutex_unlock(&mdata->reg_lock);
@@ -292,14 +328,10 @@ int mdss_mdp_pipe_panic_signal_ctrl(struct mdss_mdp_pipe *pipe, bool enable)
break;
case MDSS_MDP_PANIC_PER_PIPE_CFG:
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
- panic_robust_ctrl = mdss_mdp_pipe_read(pipe,
- MDSS_MDP_REG_SSPP_QOS_CTRL);
- if (enable)
- panic_robust_ctrl |= BIT(0);
- else
- panic_robust_ctrl &= ~BIT(0);
- mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_QOS_CTRL,
- panic_robust_ctrl);
+
+ mdss_mdp_pipe_qos_ctrl(pipe, enable,
+ MDSS_MDP_PIPE_QOS_PANIC_CTRL);
+
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
break;
}
@@ -2305,6 +2337,215 @@ static void mdss_mdp_set_ot_limit_pipe(struct mdss_mdp_pipe *pipe)
mdss_mdp_set_ot_limit(&ot_params);
}
+bool mdss_mdp_is_amortizable_pipe(struct mdss_mdp_pipe *pipe,
+ struct mdss_mdp_mixer *mixer, struct mdss_data_type *mdata)
+{
+ /* do not apply for rotator or WB */
+ return ((pipe->src.y > mdata->prefill_data.ts_threshold) &&
+ (mixer->type == MDSS_MDP_MIXER_TYPE_INTF));
+}
+
+static inline void __get_ordered_rects(struct mdss_mdp_pipe *pipe,
+ struct mdss_mdp_pipe **low_pipe,
+ struct mdss_mdp_pipe **high_pipe)
+{
+ *low_pipe = pipe;
+
+ if (pipe->multirect.mode == MDSS_MDP_PIPE_MULTIRECT_NONE) {
+ *high_pipe = NULL;
+ return;
+ }
+
+ *high_pipe = pipe->multirect.next;
+
+ /* if pipes are not in order, order them according to position */
+ if ((*low_pipe)->src.y > (*high_pipe)->src.y) {
+ *low_pipe = pipe->multirect.next;
+ *high_pipe = pipe;
+ }
+}
+
+static u32 __get_ts_count(struct mdss_mdp_pipe *pipe,
+ struct mdss_mdp_mixer *mixer, bool is_low_pipe)
+{
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+ u32 ts_diff, ts_ypos;
+ struct mdss_mdp_pipe *low_pipe, *high_pipe;
+ u32 ts_count = 0;
+ u32 v_total, fps, h_total, xres;
+
+ if (mdss_mdp_get_panel_params(pipe, mixer, &fps, &v_total,
+ &h_total, &xres)) {
+ pr_err(" error retreiving the panel params!\n");
+ return -EINVAL;
+ }
+
+ if (is_low_pipe) {
+ /* only calculate count if lower pipe is amortizable */
+ if (mdss_mdp_is_amortizable_pipe(pipe, mixer, mdata)) {
+ ts_diff = mdata->prefill_data.ts_threshold -
+ mdata->prefill_data.ts_end;
+ ts_ypos = pipe->src.y - ts_diff;
+ ts_count = mult_frac(ts_ypos, 19200000, fps * v_total);
+ }
+ } else { /* high pipe */
+
+ /* only calculate count for high pipe in serial mode */
+ if (pipe &&
+ pipe->multirect.mode == MDSS_MDP_PIPE_MULTIRECT_SERIAL) {
+ __get_ordered_rects(pipe, &low_pipe, &high_pipe);
+ ts_count = high_pipe->src.y - low_pipe->src.y - 1;
+ ts_count = mult_frac(ts_count, 19200000, fps * v_total);
+ }
+ }
+
+ return ts_count;
+}
+
+static u32 __calc_ts_bytes(struct mdss_rect *src, u32 fps, u32 bpp)
+{
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+ u32 ts_bytes;
+
+ ts_bytes = src->h * src->w *
+ bpp * fps;
+ ts_bytes = mult_frac(ts_bytes,
+ mdata->prefill_data.ts_rate.numer,
+ mdata->prefill_data.ts_rate.denom);
+ ts_bytes /= 19200000;
+
+ return ts_bytes;
+}
+
+static u32 __get_ts_bytes(struct mdss_mdp_pipe *pipe,
+ struct mdss_mdp_mixer *mixer)
+{
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+ struct mdss_mdp_pipe *low_pipe, *high_pipe;
+ u32 v_total, fps, h_total, xres;
+ u32 low_pipe_bw, high_pipe_bw;
+ u32 ts_bytes_low, ts_bytes_high;
+ u64 ts_bytes = 0;
+
+ if (mdss_mdp_get_panel_params(pipe, mixer, &fps, &v_total,
+ &h_total, &xres)) {
+ pr_err(" error retreiving the panel params!\n");
+ return -EINVAL;
+ }
+
+ switch (pipe->multirect.mode) {
+ case MDSS_MDP_PIPE_MULTIRECT_NONE:
+
+ /* do not amortize if pipe is not amortizable */
+ if (!mdss_mdp_is_amortizable_pipe(pipe, mixer, mdata)) {
+ ts_bytes = 0;
+ goto exit;
+ }
+
+ ts_bytes = __calc_ts_bytes(&pipe->src, fps,
+ pipe->src_fmt->bpp);
+
+ break;
+ case MDSS_MDP_PIPE_MULTIRECT_PARALLEL:
+
+ __get_ordered_rects(pipe, &low_pipe, &high_pipe);
+
+ /* do not amortize if low_pipe is not amortizable */
+ if (!mdss_mdp_is_amortizable_pipe(low_pipe, mixer, mdata)) {
+ ts_bytes = 0;
+ goto exit;
+ }
+
+ /* calculate ts bytes as the sum of both rects */
+ ts_bytes_low = __calc_ts_bytes(&low_pipe->src, fps,
+ low_pipe->src_fmt->bpp);
+ ts_bytes_high = __calc_ts_bytes(&low_pipe->src, fps,
+ high_pipe->src_fmt->bpp);
+
+ ts_bytes = ts_bytes_low + ts_bytes_high;
+ break;
+ case MDSS_MDP_PIPE_MULTIRECT_SERIAL:
+
+ __get_ordered_rects(pipe, &low_pipe, &high_pipe);
+
+ /* calculate amortization using per-pipe bw */
+ low_pipe_bw = mdss_mdp_get_pipe_overlap_bw(low_pipe,
+ &low_pipe->mixer_left->roi, 0);
+ high_pipe_bw = mdss_mdp_get_pipe_overlap_bw(high_pipe,
+ &high_pipe->mixer_left->roi, 0);
+
+ /* amortize depending on the lower pipe amortization */
+ if (mdss_mdp_is_amortizable_pipe(low_pipe, mixer, mdata))
+ ts_bytes = max(low_pipe_bw, high_pipe_bw) /
+ 19200000;
+ else
+ ts_bytes = high_pipe_bw / 19200000;
+ break;
+ default:
+ pr_err("unknown multirect mode!\n");
+ goto exit;
+ break;
+ };
+
+ ts_bytes &= 0xFF;
+ ts_bytes |= BIT(27) | BIT(31);
+exit:
+ return (u32) ts_bytes;
+}
+
+static int mdss_mdp_set_ts_pipe(struct mdss_mdp_pipe *pipe)
+{
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+ struct mdss_mdp_mixer *mixer;
+ u32 ts_count_low = 0, ts_count_high = 0;
+ u32 ts_rec0, ts_rec1;
+ u32 ts_bytes = 0;
+ struct mdss_mdp_pipe *low_pipe = NULL;
+ struct mdss_mdp_pipe *high_pipe = NULL;
+
+ if (!test_bit(MDSS_QOS_TS_PREFILL, mdata->mdss_qos_map))
+ return 0;
+
+ mixer = pipe->mixer_left;
+ if (!mixer)
+ return -EINVAL;
+
+ if (!mixer->ctl)
+ return -EINVAL;
+
+ if (!mdata->prefill_data.ts_threshold ||
+ (mdata->prefill_data.ts_threshold < mdata->prefill_data.ts_end)) {
+ pr_err("invalid ts data!\n");
+ return -EINVAL;
+ }
+
+ /* high pipe will be null for non-multi rect cases */
+ __get_ordered_rects(pipe, &low_pipe, &high_pipe);
+
+ ts_count_low = __get_ts_count(low_pipe, mixer, true);
+ ts_count_high = __get_ts_count(high_pipe, mixer, false);
+ ts_bytes = __get_ts_bytes(pipe, mixer);
+
+ if (low_pipe->multirect.num == MDSS_MDP_PIPE_RECT0) {
+ ts_rec0 = ts_count_low;
+ ts_rec1 = ts_count_high;
+ } else {
+ ts_rec0 = ts_count_high;
+ ts_rec1 = ts_count_low;
+ }
+
+ mdss_mdp_pipe_qos_ctrl(pipe, false, MDSS_MDP_PIPE_QOS_VBLANK_AMORTIZE);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_TRAFFIC_SHAPER, ts_bytes);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_TRAFFIC_SHAPER_PREFILL,
+ ts_rec0);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_TRAFFIC_SHAPER_REC1_PREFILL,
+ ts_rec1);
+ MDSS_XLOG(pipe->num, ts_bytes, ts_rec0, ts_rec1);
+ pr_debug("ts: pipe:%d bytes=0x%x count0=0x%x count1=0x%x\n",
+ pipe->num, ts_bytes, ts_rec0, ts_rec1);
+ return 0;
+}
+
int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe,
struct mdss_mdp_data *src_data)
{
@@ -2432,6 +2673,7 @@ int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe,
mdss_mdp_pipe_panic_vblank_signal_ctrl(pipe, 1);
mdss_mdp_pipe_panic_signal_ctrl(pipe, true);
mdss_mdp_set_ot_limit_pipe(pipe);
+ mdss_mdp_set_ts_pipe(pipe);
}
}
}