summaryrefslogtreecommitdiff
path: root/drivers/video/fbdev
diff options
context:
space:
mode:
authorUjwal Patel <ujwalp@codeaurora.org>2014-01-14 15:58:57 -0800
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 20:26:06 -0700
commit0200b868d3c15e58505fc84151c7561fe36f5d45 (patch)
tree43ae2ca81729e2fa2fa73c00c296e61d24908602 /drivers/video/fbdev
parent2d4281186f40503908727e30e71a420a229c68f8 (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.c43
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.h13
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pipe.c35
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);
}