diff options
| author | Ujwal Patel <ujwalp@codeaurora.org> | 2014-01-14 15:58:57 -0800 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:26:06 -0700 |
| commit | 0200b868d3c15e58505fc84151c7561fe36f5d45 (patch) | |
| tree | 43ae2ca81729e2fa2fa73c00c296e61d24908602 /drivers/video/fbdev | |
| parent | 2d4281186f40503908727e30e71a420a229c68f8 (diff) | |
msm: mdss: add sw_reset support for source pipes
In certain use-cases when under-run happens and simultaneously pipe is
un-staged from the mixer, pipe goes to bad state. In certain chip-sets,
sw_reset sequence is available to bring back pipe in a good state. Add
support for this sw_reset sequence.
Change-Id: I819a0ed4073d72571f3f663164a41823e947b71f
Signed-off-by: Ujwal Patel <ujwalp@codeaurora.org>
Diffstat (limited to 'drivers/video/fbdev')
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp.c | 43 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp.h | 13 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_pipe.c | 35 |
3 files changed, 90 insertions, 1 deletions
diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c index 5e16b31fc2fa..fc63e6ef8ba5 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.c +++ b/drivers/video/fbdev/msm/mdss_mdp.c @@ -1590,6 +1590,34 @@ static int mdss_mdp_parse_dt(struct platform_device *pdev) return 0; } +static void mdss_mdp_parse_dt_pipe_sw_reset(struct platform_device *pdev, + u32 reg_off, char *prop_name, struct mdss_mdp_pipe *pipe_list, + u32 npipes) +{ + size_t len; + const u32 *arr; + + arr = of_get_property(pdev->dev.of_node, prop_name, &len); + if (arr) { + int i; + + len /= sizeof(u32); + if (len != npipes) { + pr_err("%s: invalid sw_reset entries req:%d found:%d\n", + prop_name, len, npipes); + return; + } + + for (i = 0; i < len; i++) { + pipe_list[i].sw_reset.reg_off = reg_off; + pipe_list[i].sw_reset.bit_off = be32_to_cpu(arr[i]); + + pr_debug("%s[%d]: sw_reset: reg_off:0x%x bit_off:%d\n", + prop_name, i, reg_off, be32_to_cpu(arr[i])); + } + } +} + static int mdss_mdp_parse_dt_pipe_clk_ctrl(struct platform_device *pdev, char *prop_name, struct mdss_mdp_pipe *pipe_list, u32 npipes) { @@ -1652,6 +1680,7 @@ static int mdss_mdp_parse_dt_pipe(struct platform_device *pdev) int rc = 0; u32 nfids = 0, setup_cnt = 0, len, nxids = 0; u32 *offsets = NULL, *ftch_id = NULL, *xin_id = NULL; + u32 sw_reset_offset = 0; struct mdss_data_type *mdata = platform_get_drvdata(pdev); @@ -1855,6 +1884,20 @@ static int mdss_mdp_parse_dt_pipe(struct platform_device *pdev) goto parse_fail; + mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-pipe-sw-reset-off", + &sw_reset_offset, 1); + if (sw_reset_offset) { + mdss_mdp_parse_dt_pipe_sw_reset(pdev, sw_reset_offset, + "qcom,mdss-pipe-vig-sw-reset-map", mdata->vig_pipes, + mdata->nvig_pipes); + mdss_mdp_parse_dt_pipe_sw_reset(pdev, sw_reset_offset, + "qcom,mdss-pipe-rgb-sw-reset-map", mdata->rgb_pipes, + mdata->nrgb_pipes); + mdss_mdp_parse_dt_pipe_sw_reset(pdev, sw_reset_offset, + "qcom,mdss-pipe-dma-sw-reset-map", mdata->dma_pipes, + mdata->ndma_pipes); + } + goto parse_done; parse_fail: diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index 223e5f9224c3..67f55d425bc8 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -345,6 +345,7 @@ struct mdss_mdp_pipe { u32 xin_id; struct mdss_mdp_shared_reg_ctrl clk_ctrl; struct mdss_mdp_shared_reg_ctrl clk_status; + struct mdss_mdp_shared_reg_ctrl sw_reset; atomic_t ref_cnt; u32 play_cnt; @@ -500,6 +501,18 @@ static inline u32 mdss_mdp_pingpong_read(struct mdss_mdp_mixer *mixer, u32 reg) return readl_relaxed(mixer->pingpong_base + reg); } +static inline int mdss_mdp_pipe_is_sw_reset_available( + struct mdss_data_type *mdata) +{ + switch (mdata->mdp_rev) { + case MDSS_MDP_HW_REV_101_2: + case MDSS_MDP_HW_REV_103_1: + return true; + default: + return false; + } +} + irqreturn_t mdss_mdp_isr(int irq, void *ptr); int mdss_iommu_attach(struct mdss_data_type *mdata); int mdss_iommu_dettach(struct mdss_data_type *mdata); diff --git a/drivers/video/fbdev/msm/mdss_mdp_pipe.c b/drivers/video/fbdev/msm/mdss_mdp_pipe.c index c37c9636dac1..a53177899dff 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pipe.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pipe.c @@ -513,7 +513,7 @@ static struct mdss_mdp_pipe *mdss_mdp_pipe_init(struct mdss_mdp_mixer *mixer, struct mdss_mdp_pipe *pipe_pool = NULL; u32 npipes; bool pipe_share = false; - u32 i; + u32 i, reg_val, force_off_mask; if (!mixer || !mixer->ctl || !mixer->ctl->mdata) return NULL; @@ -561,6 +561,18 @@ static struct mdss_mdp_pipe *mdss_mdp_pipe_init(struct mdss_mdp_mixer *mixer, return NULL; } + if (mdss_mdp_pipe_is_sw_reset_available(mdata)) { + force_off_mask = + BIT(pipe->clk_ctrl.bit_off + CLK_FORCE_OFF_OFFSET); + reg_val = readl_relaxed(mdata->mdp_base + + pipe->clk_ctrl.reg_off); + if (reg_val & force_off_mask) { + reg_val &= ~force_off_mask; + writel_relaxed(reg_val, + mdata->mdp_base + pipe->clk_ctrl.reg_off); + } + } + if (pipe) { pr_debug("type=%x pnum=%d\n", pipe->type, pipe->num); mutex_init(&pipe->pp_res.hist.hist_mutex); @@ -770,6 +782,9 @@ static int mdss_mdp_pipe_fetch_halt(struct mdss_mdp_pipe *pipe) int rc = 0; u32 reg_val, idle_mask, status; struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + bool sw_reset_avail = mdss_mdp_pipe_is_sw_reset_available(mdata); + u32 sw_reset_off = pipe->sw_reset.reg_off; + u32 clk_ctrl_off = pipe->clk_ctrl.reg_off; is_idle = mdss_mdp_is_pipe_idle(pipe, true); if (!is_idle) { @@ -784,6 +799,16 @@ static int mdss_mdp_pipe_fetch_halt(struct mdss_mdp_pipe *pipe) MMSS_VBIF_XIN_HALT_CTRL0); writel_relaxed(reg_val | BIT(pipe->xin_id), mdata->vbif_base + MMSS_VBIF_XIN_HALT_CTRL0); + + if (sw_reset_avail) { + reg_val = readl_relaxed(mdata->mdp_base + sw_reset_off); + writel_relaxed(reg_val | BIT(pipe->sw_reset.bit_off), + mdata->mdp_base + sw_reset_off); + wmb(); + writel_relaxed(reg_val & ~BIT(pipe->sw_reset.bit_off), + mdata->mdp_base + sw_reset_off); + wmb(); + } mutex_unlock(&mdata->reg_lock); rc = readl_poll_timeout(mdata->vbif_base + @@ -801,6 +826,14 @@ static int mdss_mdp_pipe_fetch_halt(struct mdss_mdp_pipe *pipe) writel_relaxed(reg_val & ~BIT(pipe->xin_id), mdata->vbif_base + MMSS_VBIF_XIN_HALT_CTRL0); + if (sw_reset_avail) { + reg_val = readl_relaxed(mdata->mdp_base + clk_ctrl_off); + reg_val |= BIT(pipe->clk_ctrl.bit_off + + CLK_FORCE_OFF_OFFSET); + writel_relaxed(reg_val, + mdata->mdp_base + clk_ctrl_off); + } + mutex_unlock(&mdata->reg_lock); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); } |
