diff options
| author | Ingrid Gallardo <ingridg@codeaurora.org> | 2015-05-07 11:33:44 -0700 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:43:43 -0700 |
| commit | 96007ec277d79b84abcdac7bdc6334dbb92f9b2d (patch) | |
| tree | 4fd4238cdb81321e573827bda085f71f28877443 /drivers/video/fbdev | |
| parent | bbdb824e975ddee32e19b5d397c08d3cee1b44ba (diff) | |
msm: mdss: add support to switchable qos during vblank
Starting with 8996 chipset, qos settings can be adjusted
to be different during vblank. This change adds support
for this feature.
Change-Id: Ifa25dd799a55396224f49c49a29fcc8f5a245bd0
Signed-off-by: Ingrid Gallardo <ingridg@codeaurora.org>
Diffstat (limited to 'drivers/video/fbdev')
| -rw-r--r-- | drivers/video/fbdev/msm/mdss.h | 2 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_debug.c | 3 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_hwio.h | 1 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_intf_video.c | 43 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_pipe.c | 77 |
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); } |
