summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/video/fbdev/msm/mdss.h15
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.c5
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.h6
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_ctl.c5
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c4
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_overlay.c9
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp.c156
7 files changed, 189 insertions, 11 deletions
diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h
index 5044c7332283..4219395883b6 100644
--- a/drivers/video/fbdev/msm/mdss.h
+++ b/drivers/video/fbdev/msm/mdss.h
@@ -71,6 +71,19 @@ struct mdss_fudge_factor {
u32 denom;
};
+#define MDSS_IRQ_SUSPEND -1
+#define MDSS_IRQ_RESUME 1
+#define MDSS_IRQ_REQ 0
+
+struct mdss_intr {
+ /* requested intr */
+ u32 req;
+ /* currently enabled intr */
+ u32 curr;
+ int state;
+ spinlock_t lock;
+};
+
struct mdss_data_type {
u32 mdp_rev;
struct clk *mdp_clk[MDSS_MAX_CLK];
@@ -149,6 +162,8 @@ struct mdss_data_type {
u32 nad_cfgs;
struct workqueue_struct *ad_calc_wq;
+ struct mdss_intr hist_intr;
+
struct ion_client *iclient;
int iommu_attached;
struct mdss_iommu_map_type *iommu_map;
diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c
index be587ef4e9e5..c31f176af475 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp.c
@@ -1010,6 +1010,11 @@ static u32 mdss_mdp_res_init(struct mdss_data_type *mdata)
if (rc)
return rc;
+ mdata->hist_intr.req = 0;
+ mdata->hist_intr.curr = 0;
+ mdata->hist_intr.state = 0;
+ spin_lock_init(&mdata->hist_intr.lock);
+
mdata->iclient = msm_ion_client_create(-1, mdata->pdev->name);
if (IS_ERR_OR_NULL(mdata->iclient)) {
pr_err("msm_ion_client_create() return error (%p)\n",
diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h
index e06e712860d3..1afc7d894eb6 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.h
+++ b/drivers/video/fbdev/msm/mdss_mdp.h
@@ -582,8 +582,10 @@ int mdss_mdp_hist_lut_config(struct mdp_hist_lut_data *config, u32 *copyback);
int mdss_mdp_dither_config(struct mdp_dither_cfg_data *config, u32 *copyback);
int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, u32 *copyback);
-int mdss_mdp_histogram_start(struct mdp_histogram_start_req *req);
-int mdss_mdp_histogram_stop(u32 block);
+int mdss_mdp_hist_intr_req(struct mdss_intr *intr, u32 bits, bool en);
+int mdss_mdp_hist_intr_setup(struct mdss_intr *intr, int state);
+int mdss_mdp_hist_start(struct mdp_histogram_start_req *req);
+int mdss_mdp_hist_stop(u32 block);
int mdss_mdp_hist_collect(struct mdp_histogram_data *hist);
void mdss_mdp_hist_intr_done(u32 isr);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
index f45324c7ddf7..4701e7fc5989 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
@@ -1128,6 +1128,7 @@ static int mdss_mdp_ctl_start_sub(struct mdss_mdp_ctl *ctl)
int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl)
{
struct mdss_mdp_ctl *sctl;
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
int ret = 0;
if (ctl->power_on) {
@@ -1174,6 +1175,7 @@ int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl)
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_PACK_3D, 0);
}
}
+ mdss_mdp_hist_intr_setup(&mdata->hist_intr, MDSS_IRQ_RESUME);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
error:
@@ -1186,6 +1188,7 @@ int mdss_mdp_ctl_stop(struct mdss_mdp_ctl *ctl)
{
struct mdss_mdp_ctl *sctl;
int ret = 0;
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
u32 off;
if (!ctl->power_on) {
@@ -1201,6 +1204,8 @@ int mdss_mdp_ctl_stop(struct mdss_mdp_ctl *ctl)
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ mdss_mdp_hist_intr_setup(&mdata->hist_intr, MDSS_IRQ_SUSPEND);
+
if (ctl->stop_fnc)
ret = ctl->stop_fnc(ctl);
else
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
index c490862df453..76a64090db19 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
@@ -176,12 +176,14 @@ static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_ctl *ctl)
static inline void mdss_mdp_cmd_clk_on(struct mdss_mdp_cmd_ctx *ctx)
{
unsigned long flags;
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
mutex_lock(&ctx->clk_mtx);
if (!ctx->clk_enabled) {
ctx->clk_enabled = 1;
mdss_mdp_ctl_intf_event
(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)1);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ mdss_mdp_hist_intr_setup(&mdata->hist_intr, MDSS_IRQ_RESUME);
}
spin_lock_irqsave(&ctx->clk_lock, flags);
if (!ctx->rdptr_enabled)
@@ -194,6 +196,7 @@ static inline void mdss_mdp_cmd_clk_on(struct mdss_mdp_cmd_ctx *ctx)
static inline void mdss_mdp_cmd_clk_off(struct mdss_mdp_cmd_ctx *ctx)
{
unsigned long flags;
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
int set_clk_off = 0;
mutex_lock(&ctx->clk_mtx);
@@ -204,6 +207,7 @@ static inline void mdss_mdp_cmd_clk_off(struct mdss_mdp_cmd_ctx *ctx)
if (ctx->clk_enabled && set_clk_off) {
ctx->clk_enabled = 0;
+ mdss_mdp_hist_intr_setup(&mdata->hist_intr, MDSS_IRQ_SUSPEND);
mdss_mdp_ctl_intf_event
(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)0);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
index 4b9030774b22..43a0be5ad662 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
@@ -546,11 +546,10 @@ static int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd,
pipe->pp_cfg.hist_cfg.frame_cnt;
hist.bit_mask = pipe->pp_cfg.hist_cfg.bit_mask;
hist.num_bins = pipe->pp_cfg.hist_cfg.num_bins;
- mdss_mdp_histogram_start(&hist);
+ mdss_mdp_hist_start(&hist);
} else if (pipe->pp_cfg.hist_cfg.ops &
MDP_PP_OPS_DISABLE) {
- mdss_mdp_histogram_stop(
- pipe->pp_cfg.hist_cfg.block);
+ mdss_mdp_hist_stop(pipe->pp_cfg.hist_cfg.block);
}
}
len = pipe->pp_cfg.hist_lut_cfg.len;
@@ -2065,7 +2064,7 @@ static int mdss_mdp_histo_ioctl(struct msm_fb_data_type *mfd, u32 cmd,
if (ret)
return ret;
- ret = mdss_mdp_histogram_start(&hist_req);
+ ret = mdss_mdp_hist_start(&hist_req);
break;
case MSMFB_HISTOGRAM_STOP:
@@ -2073,7 +2072,7 @@ static int mdss_mdp_histo_ioctl(struct msm_fb_data_type *mfd, u32 cmd,
if (ret)
return ret;
- ret = mdss_mdp_histogram_stop(block);
+ ret = mdss_mdp_hist_stop(block);
if (ret)
return ret;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c
index e7f209e64448..c7cc825070cc 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c
@@ -2758,6 +2758,8 @@ static int pp_histogram_enable(struct pp_hist_col_info *hist_info,
{
unsigned long flag;
int ret = 0;
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+
mutex_lock(&hist_info->hist_mutex);
/* check if it is idle */
if (hist_info->col_en) {
@@ -2777,7 +2779,7 @@ static int pp_histogram_enable(struct pp_hist_col_info *hist_info,
hist_info->col_en = true;
spin_unlock_irqrestore(&hist_info->hist_lock, flag);
hist_info->is_kick_ready = true;
- mdss_mdp_hist_irq_enable(3 << shift_bit);
+ mdss_mdp_hist_intr_req(&mdata->hist_intr, 3 << shift_bit, true);
writel_relaxed(req->frame_cnt, ctl_base + 8);
/* Kick out reset start */
writel_relaxed(1, ctl_base + 4);
@@ -2786,7 +2788,7 @@ exit:
return ret;
}
-int mdss_mdp_histogram_start(struct mdp_histogram_start_req *req)
+int mdss_mdp_hist_start(struct mdp_histogram_start_req *req)
{
u32 done_shift_bit;
char __iomem *ctl_base;
@@ -2869,6 +2871,8 @@ static int pp_histogram_disable(struct pp_hist_col_info *hist_info,
{
int ret = 0;
unsigned long flag;
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+
mutex_lock(&hist_info->hist_mutex);
if (hist_info->col_en == false) {
pr_debug("Histogram already disabled (%d)", (u32) ctl_base);
@@ -2881,7 +2885,7 @@ static int pp_histogram_disable(struct pp_hist_col_info *hist_info,
hist_info->col_state = HIST_UNKNOWN;
spin_unlock_irqrestore(&hist_info->hist_lock, flag);
hist_info->is_kick_ready = false;
- mdss_mdp_hist_irq_disable(done_bit);
+ mdss_mdp_hist_intr_req(&mdata->hist_intr, done_bit, false);
writel_relaxed(BIT(1), ctl_base);/* cancel */
ret = 0;
exit:
@@ -2889,7 +2893,7 @@ exit:
return ret;
}
-int mdss_mdp_histogram_stop(u32 block)
+int mdss_mdp_hist_stop(u32 block)
{
int i, ret = 0;
char __iomem *ctl_base;
@@ -2966,6 +2970,150 @@ hist_stop_exit:
return ret;
}
+/**
+ * mdss_mdp_hist_intr_req() - Request changes the histogram interupts
+ * @intr: structure containting state of interrupt register
+ * @bits: the bits on interrupt register that should be changed
+ * @en: true if bits should be set, false if bits should be cleared
+ *
+ * Adds or removes the bits from the interrupt request.
+ *
+ * Does not store reference count for each bit. I.e. a bit with multiple
+ * enable requests can be disabled with a single disable request.
+ *
+ * Return: 0 if uneventful, errno on invalid input
+ */
+int mdss_mdp_hist_intr_req(struct mdss_intr *intr, u32 bits, bool en)
+{
+ unsigned long flag;
+ int ret = 0;
+ if (!intr) {
+ pr_err("NULL addr passed, %p", intr);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&intr->lock, flag);
+ if (en)
+ intr->req |= bits;
+ else
+ intr->req &= ~bits;
+ spin_unlock_irqrestore(&intr->lock, flag);
+
+ mdss_mdp_hist_intr_setup(intr, MDSS_IRQ_REQ);
+
+ return ret;
+}
+
+
+#define MDSS_INTR_STATE_ACTIVE 1
+#define MDSS_INTR_STATE_NULL 0
+#define MDSS_INTR_STATE_SUSPEND -1
+
+/**
+ * mdss_mdp_hist_intr_setup() - Manage intr and clk depending on requests.
+ * @intr: structure containting state of intr reg
+ * @state: MDSS_IRQ_SUSPEND if suspend is needed,
+ * MDSS_IRQ_RESUME if resume is needed,
+ * MDSS_IRQ_REQ if neither (i.e. requesting an interrupt)
+ *
+ * This function acts as a gatekeeper for the interrupt, making sure that the
+ * MDP clocks are enabled while the interrupts are enabled to prevent
+ * unclocked accesses.
+ *
+ * To reduce code repetition, 4 state transitions have been encoded here. Each
+ * transition updates the interrupt's state structure (mdss_intr) to reflect
+ * the which bits have been requested (intr->req), are currently enabled
+ * (intr->curr), as well as defines which interrupt bits need to be enabled or
+ * disabled ('en' and 'dis' respectively). The 4th state is not explicity
+ * coded in the if/else chain, but is for MDSS_IRQ_REQ's when the interrupt
+ * is in suspend, in which case, the only change required (intr->req being
+ * updated) has already occured in the calling function.
+ *
+ * To control the clock, which can't be requested while holding the spinlock,
+ * the inital state is compared with the exit state to detect when the
+ * interrupt needs a clock.
+ *
+ * The clock requests surrounding the majority of this function serve to
+ * enable the register writes to change the interrupt register, as well as to
+ * prevent a race condition that could keep the clocks on (due to mdp_clk_cnt
+ * never being decremented below 0) when a enable/disable occurs but the
+ * disable requests the clocks disabled before the enable is able to request
+ * the clocks enabled.
+ *
+ * Return: 0 if uneventful, errno on repeated action or invalid input
+ */
+int mdss_mdp_hist_intr_setup(struct mdss_intr *intr, int type)
+{
+ unsigned long flag;
+ int ret = 0, req_clk = 0;
+ u32 en = 0, dis = 0;
+ u32 diff, init_curr;
+ int init_state;
+ if (!intr) {
+ WARN(1, "NULL intr pointer");
+ return -EINVAL;
+ }
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ spin_lock_irqsave(&intr->lock, flag);
+
+ init_state = intr->state;
+ init_curr = intr->curr;
+
+ if (type == MDSS_IRQ_RESUME) {
+ /* resume intrs */
+ if (intr->state == MDSS_INTR_STATE_ACTIVE) {
+ ret = -EPERM;
+ goto exit;
+ }
+ en = intr->req;
+ dis = 0;
+ intr->curr = intr->req;
+ intr->state = intr->curr ?
+ MDSS_INTR_STATE_ACTIVE : MDSS_INTR_STATE_NULL;
+ } else if (type == MDSS_IRQ_SUSPEND) {
+ /* suspend intrs */
+ if (intr->state == MDSS_INTR_STATE_SUSPEND) {
+ ret = -EPERM;
+ goto exit;
+ }
+ en = 0;
+ dis = intr->curr;
+ intr->curr = 0;
+ intr->state = MDSS_INTR_STATE_SUSPEND;
+ } else if (intr->state != MDSS_IRQ_SUSPEND) {
+ /* Not resuming/suspending or in suspend state */
+ diff = intr->req ^ intr->curr;
+ en = diff & ~intr->curr;
+ dis = diff & ~intr->req;
+ intr->curr = intr->req;
+ intr->state = intr->curr ?
+ MDSS_INTR_STATE_ACTIVE : MDSS_INTR_STATE_NULL;
+ }
+
+ if (en)
+ mdss_mdp_hist_irq_enable(en);
+ if (dis)
+ mdss_mdp_hist_irq_disable(dis);
+
+ if ((init_state != MDSS_INTR_STATE_ACTIVE) &&
+ (intr->state == MDSS_INTR_STATE_ACTIVE))
+ req_clk = 1;
+ else if ((init_state == MDSS_INTR_STATE_ACTIVE) &&
+ (intr->state != MDSS_INTR_STATE_ACTIVE))
+ req_clk = -1;
+
+exit:
+ spin_unlock_irqrestore(&intr->lock, flag);
+ if (req_clk < 0)
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ else if (req_clk > 0)
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ return ret;
+}
+
static int pp_hist_collect(struct mdp_histogram_data *hist,
struct pp_hist_col_info *hist_info,
char __iomem *ctl_base)