summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/video/fbdev/msm/mdss.h2
-rw-r--r--drivers/video/fbdev/msm/mdss_debug.c3
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_hwio.h1
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_video.c43
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pipe.c77
5 files changed, 118 insertions, 8 deletions
diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h
index f0ee85da196b..f815a9b40f32 100644
--- a/drivers/video/fbdev/msm/mdss.h
+++ b/drivers/video/fbdev/msm/mdss.h
@@ -167,6 +167,7 @@ enum mdss_qos_settings {
MDSS_QOS_OTLIM,
MDSS_QOS_PER_PIPE_LUT,
MDSS_QOS_SIMPLIFIED_PREFILL,
+ MDSS_QOS_VBLANK_PANIC_CTRL,
MDSS_QOS_MAX,
};
@@ -327,6 +328,7 @@ struct mdss_data_type {
u32 enable_bw_release;
u32 enable_rotator_bw_release;
u32 serialize_wait4pp;
+ u32 lines_before_active;
struct mdss_hw_settings *hw_settings;
diff --git a/drivers/video/fbdev/msm/mdss_debug.c b/drivers/video/fbdev/msm/mdss_debug.c
index 8228425f91ad..bd037da30e28 100644
--- a/drivers/video/fbdev/msm/mdss_debug.c
+++ b/drivers/video/fbdev/msm/mdss_debug.c
@@ -1062,6 +1062,9 @@ static int mdss_debugfs_perf_init(struct mdss_debug_data *mdd,
debugfs_create_file("threshold_bw_limit", 0644, mdd->perf,
(struct mdss_data_type *)mdata, &mdss_perf_bw_limit_fops);
+ debugfs_create_u32("lines_before_active", 0644, mdd->perf,
+ (u32 *)&mdata->lines_before_active);
+
return 0;
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_hwio.h b/drivers/video/fbdev/msm/mdss_mdp_hwio.h
index 82f085a15b82..fe6772049fe1 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_hwio.h
+++ b/drivers/video/fbdev/msm/mdss_mdp_hwio.h
@@ -545,6 +545,7 @@ enum mdss_mpd_intf_index {
#define MDSS_MDP_REG_INTF_TPG_BLK_WHITE_PATTERN_FRAMES 0x118
#define MDSS_MDP_REG_INTF_TPG_RGB_MAPPING 0x11C
#define MDSS_MDP_REG_INTF_PROG_FETCH_START 0x170
+#define MDSS_MDP_REG_INTF_VBLANK_END_CONF 0x264
#define MDSS_MDP_REG_INTF_FRAME_LINE_COUNT_EN 0x0A8
#define MDSS_MDP_REG_INTF_FRAME_COUNT 0x0AC
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
index 236b963a0af8..0bc74742aa0c 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
@@ -79,6 +79,9 @@ struct mdss_mdp_video_ctx {
static void mdss_mdp_fetch_start_config(struct mdss_mdp_video_ctx *ctx,
struct mdss_mdp_ctl *ctl);
+static void mdss_mdp_fetch_end_config(struct mdss_mdp_video_ctx *ctx,
+ struct mdss_mdp_ctl *ctl);
+
static inline void mdp_video_write(struct mdss_mdp_video_ctx *ctx,
u32 reg, u32 val)
{
@@ -985,6 +988,13 @@ static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl,
if (sctx)
mdss_mdp_fetch_start_config(sctx, ctl);
+ if (test_bit(MDSS_QOS_VBLANK_PANIC_CTRL,
+ mdata->mdss_qos_map)) {
+ mdss_mdp_fetch_end_config(ctx, ctl);
+ if (sctx)
+ mdss_mdp_fetch_end_config(sctx, ctl);
+ }
+
/*
* MDP INTF registers support DB on targets
* starting from MDP v1.5.
@@ -1162,6 +1172,35 @@ static void mdss_mdp_disable_prefill(struct mdss_mdp_ctl *ctl)
}
}
+static void mdss_mdp_fetch_end_config(struct mdss_mdp_video_ctx *ctx,
+ struct mdss_mdp_ctl *ctl)
+{
+ int fetch_stop, h_total;
+ struct mdss_panel_info *pinfo = &ctl->panel_data->panel_info;
+ u32 lines_before_active = ctl->mdata->lines_before_active ? : 2;
+ u32 vblank_lines = pinfo->lcdc.v_back_porch + pinfo->lcdc.v_pulse_width;
+ u32 vblank_end_enable;
+
+ if (vblank_lines <= lines_before_active) {
+ pr_debug("cannot support fetch end vblank:%d lines:%d\n",
+ vblank_lines, lines_before_active);
+ return;
+ }
+
+ /* Fetch should always be stopped before the active start */
+ h_total = mdss_panel_get_htotal(pinfo, true);
+ fetch_stop = (vblank_lines - lines_before_active) * h_total;
+
+ vblank_end_enable = mdp_video_read(ctx, MDSS_MDP_REG_INTF_CONFIG);
+ vblank_end_enable |= BIT(22);
+
+ pr_debug("ctl:%d fetch_stop:%d lines:%d\n",
+ ctl->num, fetch_stop, lines_before_active);
+
+ mdp_video_write(ctx, MDSS_MDP_REG_INTF_VBLANK_END_CONF, fetch_stop);
+ mdp_video_write(ctx, MDSS_MDP_REG_INTF_CONFIG, vblank_end_enable);
+}
+
static void mdss_mdp_fetch_start_config(struct mdss_mdp_video_ctx *ctx,
struct mdss_mdp_ctl *ctl)
{
@@ -1366,6 +1405,10 @@ static int mdss_mdp_video_ctx_setup(struct mdss_mdp_ctl *ctl,
return -EINVAL;
}
mdss_mdp_fetch_start_config(ctx, ctl);
+
+ if (test_bit(MDSS_QOS_VBLANK_PANIC_CTRL, mdata->mdss_qos_map))
+ mdss_mdp_fetch_end_config(ctx, ctl);
+
} else {
mdss_mdp_handoff_programmable_fetch(ctl, ctx);
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pipe.c b/drivers/video/fbdev/msm/mdss_mdp_pipe.c
index 339a85475261..35850d57989a 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pipe.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pipe.c
@@ -38,6 +38,9 @@
#define QOS_LUT_420_CHROMA 0x555557
#define QOS_LUT_LINEAR 0x55555B
+/* Priority 2, no panic */
+#define VBLANK_PANIC_DEFAULT_CONFIG 0x200000
+
static DEFINE_MUTEX(mdss_mdp_sspp_lock);
static DEFINE_MUTEX(mdss_mdp_smp_lock);
@@ -145,6 +148,49 @@ void mdss_mdp_config_pipe_panic_lut(struct mdss_data_type *mdata)
}
}
+/**
+ * @mdss_mdp_pipe_panic_vblank_signal_ctrl -
+ * @pipe: pointer to a pipe
+ * @enable: TRUE - enables feature FALSE - disables feature
+ *
+ * This function assumes that clocks are enabled, so it is callers
+ * responsibility to enable clocks before calling this function.
+ */
+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)
+ goto end;
+
+ if (!is_rt_pipe(pipe))
+ goto end;
+
+ if (!test_bit(MDSS_QOS_VBLANK_PANIC_CTRL, mdata->mdss_qos_map))
+ goto end;
+
+ 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);
+
+ mutex_unlock(&mdata->reg_lock);
+
+end:
+ return 0;
+}
+
int mdss_mdp_pipe_panic_signal_ctrl(struct mdss_mdp_pipe *pipe, bool enable)
{
uint32_t panic_robust_ctrl;
@@ -210,6 +256,14 @@ void mdss_mdp_bwcpanic_ctrl(struct mdss_data_type *mdata, bool enable)
mutex_unlock(&mdata->reg_lock);
}
+/**
+ * @mdss_mdp_pipe_nrt_vbif_setup -
+ * @mdata: pointer to global driver data.
+ * @pipe: pointer to a pipe
+ *
+ * This function assumes that clocks are enabled, so it is callers
+ * responsibility to enable clocks before calling this function.
+ */
static void mdss_mdp_pipe_nrt_vbif_setup(struct mdss_data_type *mdata,
struct mdss_mdp_pipe *pipe)
{
@@ -218,7 +272,6 @@ static void mdss_mdp_pipe_nrt_vbif_setup(struct mdss_data_type *mdata,
if (pipe->type != MDSS_MDP_PIPE_TYPE_DMA)
return;
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
nrt_vbif_client_sel = readl_relaxed(mdata->mdp_base +
MMSS_MDP_RT_NRT_VBIF_CLIENT_SEL);
if (mdss_mdp_is_nrt_vbif_client(mdata, pipe))
@@ -227,7 +280,6 @@ static void mdss_mdp_pipe_nrt_vbif_setup(struct mdss_data_type *mdata,
nrt_vbif_client_sel &= ~BIT(pipe->num - MDSS_MDP_SSPP_DMA0);
writel_relaxed(nrt_vbif_client_sel,
mdata->mdp_base + MMSS_MDP_RT_NRT_VBIF_CLIENT_SEL);
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
return;
}
@@ -839,6 +891,8 @@ int mdss_mdp_pipe_map(struct mdss_mdp_pipe *pipe)
* @pipe: Pointer to source pipe struct to get xin id's.
* @is_realtime: To determine if pipe's client is real or
* non real time.
+ * This function assumes that clocks are on, so it is caller responsibility to
+ * call this function with clocks enabled.
*/
static void mdss_mdp_qos_vbif_remapper_setup(struct mdss_data_type *mdata,
struct mdss_mdp_pipe *pipe, bool is_realtime)
@@ -849,7 +903,6 @@ static void mdss_mdp_qos_vbif_remapper_setup(struct mdss_data_type *mdata,
if (mdata->npriority_lvl == 0)
return;
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
for (i = 0; i < mdata->npriority_lvl; i++) {
reg_val = MDSS_VBIF_READ(mdata, MDSS_VBIF_QOS_REMAP_BASE + i*4,
is_nrt_vbif);
@@ -861,7 +914,6 @@ static void mdss_mdp_qos_vbif_remapper_setup(struct mdss_data_type *mdata,
MDSS_VBIF_WRITE(mdata, MDSS_VBIF_QOS_REMAP_BASE + i*4, reg_val,
is_nrt_vbif);
}
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
}
/**
@@ -871,6 +923,8 @@ static void mdss_mdp_qos_vbif_remapper_setup(struct mdss_data_type *mdata,
* @pipe: Pointer to source pipe struct to get xin id's.
* @is_realtime: To determine if pipe's client is real or
* non real time.
+ * This function assumes that clocks are on, so it is caller responsibility to
+ * call this function with clocks enabled.
*/
static void mdss_mdp_fixed_qos_arbiter_setup(struct mdss_data_type *mdata,
struct mdss_mdp_pipe *pipe, bool is_realtime)
@@ -881,7 +935,6 @@ static void mdss_mdp_fixed_qos_arbiter_setup(struct mdss_data_type *mdata,
if (!mdata->has_fixed_qos_arbiter_enabled)
return;
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
mutex_lock(&mdata->reg_lock);
reg_val = MDSS_VBIF_READ(mdata, MDSS_VBIF_FIXED_SORT_EN, is_nrt_vbif);
mask = 0x1 << pipe->xin_id;
@@ -903,7 +956,6 @@ static void mdss_mdp_fixed_qos_arbiter_setup(struct mdss_data_type *mdata,
/* Set the fixed_sort regs as per RT/NRT client */
MDSS_VBIF_WRITE(mdata, MDSS_VBIF_FIXED_SORT_SEL0, reg_val, is_nrt_vbif);
mutex_unlock(&mdata->reg_lock);
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
}
static int mdss_mdp_pipe_init_config(struct mdss_mdp_pipe *pipe,
@@ -913,6 +965,8 @@ static int mdss_mdp_pipe_init_config(struct mdss_mdp_pipe *pipe,
int rc = 0;
struct mdss_data_type *mdata;
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
+
if (pipe) {
rc = mdss_mdp_pipe_fetch_halt(pipe);
if (rc) {
@@ -924,6 +978,7 @@ static int mdss_mdp_pipe_init_config(struct mdss_mdp_pipe *pipe,
mdata = mixer->ctl->mdata;
+ mdss_mdp_pipe_panic_vblank_signal_ctrl(pipe, false);
mdss_mdp_pipe_panic_signal_ctrl(pipe, false);
if (pipe && mdss_mdp_pipe_is_sw_reset_available(mdata))
@@ -947,13 +1002,16 @@ static int mdss_mdp_pipe_init_config(struct mdss_mdp_pipe *pipe,
* shared as long as its attached to a writeback mixer
*/
pipe = mdata->dma_pipes + mixer->num;
- if (pipe->mixer_left->type != MDSS_MDP_MIXER_TYPE_WRITEBACK)
- return -EINVAL;
+ if (pipe->mixer_left->type != MDSS_MDP_MIXER_TYPE_WRITEBACK) {
+ rc = -EINVAL;
+ goto end;
+ }
kref_get(&pipe->kref);
pr_debug("pipe sharing for pipe=%d\n", pipe->num);
}
end:
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
return rc;
}
@@ -1197,7 +1255,9 @@ static void mdss_mdp_pipe_free(struct kref *kref)
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
+ mdss_mdp_pipe_panic_vblank_signal_ctrl(pipe, false);
mdss_mdp_pipe_panic_signal_ctrl(pipe, false);
+
if (pipe->play_cnt) {
mdss_mdp_pipe_fetch_halt(pipe);
mdss_mdp_pipe_pp_clear(pipe);
@@ -2054,6 +2114,7 @@ int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe,
mdss_mdp_pipe_qos_lut(pipe);
if (pipe->type != MDSS_MDP_PIPE_TYPE_CURSOR) {
+ mdss_mdp_pipe_panic_vblank_signal_ctrl(pipe, true);
mdss_mdp_pipe_panic_signal_ctrl(pipe, true);
mdss_mdp_set_ot_limit_pipe(pipe);
}