diff options
| author | Carl Vanderlip <carlv@codeaurora.org> | 2013-03-18 10:18:47 -0700 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:16:02 -0700 |
| commit | d8ae3672df310fd70067ae5bebb27b94da586fa8 (patch) | |
| tree | eb58ce5e7bb61156d84bfa7f25d9ea1eaf48cc23 /drivers/video/fbdev | |
| parent | be454c3eacb603ded83fabb2439e4069c6e56798 (diff) | |
msm: mdss: Adding Source Histogram implementation
Source side histogram start/stop requests can be enabled through Overlay
API, and collected through MSMFB_HISTOGRAM ioctl. All requests take
updated 'block' parameter that lets multiple pipes be configured at once
to simplify userspace post processing calls in dual pipe case.
Change-Id: Ib2b8f4f8e2ec864e774f34a0b788a9949ce7513d
Signed-off-by: Carl Vanderlip <carlv@codeaurora.org>
Diffstat (limited to 'drivers/video/fbdev')
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp.h | 5 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_overlay.c | 30 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_pipe.c | 12 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_pp.c | 753 |
4 files changed, 565 insertions, 235 deletions
diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index 25c5871f6fc3..2701cda95412 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -438,13 +438,14 @@ int mdss_mdp_histogram_start(struct mdss_mdp_ctl *ctl, struct mdp_histogram_start_req *req); int mdss_mdp_histogram_stop(struct mdss_mdp_ctl *ctl, u32 block); int mdss_mdp_hist_collect(struct mdss_mdp_ctl *ctl, - struct mdp_histogram_data *hist, - u32 *hist_data_addr); + struct mdp_histogram_data *hist); void mdss_mdp_hist_intr_done(u32 isr); struct mdss_mdp_pipe *mdss_mdp_pipe_alloc(struct mdss_mdp_mixer *mixer, u32 type); struct mdss_mdp_pipe *mdss_mdp_pipe_get(struct mdss_data_type *mdata, u32 ndx); +struct mdss_mdp_pipe *mdss_mdp_pipe_search(struct mdss_data_type *mdata, + u32 ndx); int mdss_mdp_pipe_map(struct mdss_mdp_pipe *pipe); void mdss_mdp_pipe_unmap(struct mdss_mdp_pipe *pipe); struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_dma(struct mdss_mdp_mixer *mixer); diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index dae3e0547330..8bb5ce10e440 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -243,6 +243,7 @@ static int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd, struct mdss_mdp_mixer *mixer = NULL; u32 pipe_type, mixer_mux, len, src_format; struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); + struct mdp_histogram_start_req hist; int ret; if (mdp5_data->ctl == NULL) @@ -389,6 +390,21 @@ static int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd, pipe->pp_res.igc_c0_c1; pipe->pp_cfg.igc_cfg.c2_data = pipe->pp_res.igc_c2; } + if (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_HIST_CFG) { + if (pipe->pp_cfg.hist_cfg.ops & MDP_PP_OPS_ENABLE) { + hist.block = pipe->pp_cfg.hist_cfg.block; + hist.frame_cnt = + 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(pipe->mixer->ctl, + &hist); + } else if (pipe->pp_cfg.hist_cfg.ops & + MDP_PP_OPS_DISABLE) { + mdss_mdp_histogram_stop(pipe->mixer->ctl, + pipe->pp_cfg.hist_cfg.block); + } + } } if (pipe->flags & MDP_DEINTERLACE) { @@ -1457,7 +1473,7 @@ static int mdss_mdp_histo_ioctl(struct msm_fb_data_type *mfd, u32 cmd, int ret = -ENOSYS; struct mdp_histogram_data hist; struct mdp_histogram_start_req hist_req; - u32 block, hist_data_addr = 0; + u32 block; struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); switch (cmd) { @@ -1488,15 +1504,9 @@ static int mdss_mdp_histo_ioctl(struct msm_fb_data_type *mfd, u32 cmd, if (ret) return ret; - ret = mdss_mdp_hist_collect(mdp5_data->ctl, &hist, - &hist_data_addr); - if ((ret == 0) && hist_data_addr) { - ret = copy_to_user(hist.c0, (u32 *)hist_data_addr, - sizeof(u32) * hist.bin_cnt); - if (ret == 0) - ret = copy_to_user(argp, &hist, - sizeof(hist)); - } + ret = mdss_mdp_hist_collect(mdp5_data->ctl, &hist); + if (!ret) + ret = copy_to_user(argp, &hist, sizeof(hist)); break; default: break; diff --git a/drivers/video/fbdev/msm/mdss_mdp_pipe.c b/drivers/video/fbdev/msm/mdss_mdp_pipe.c index b169c439fed9..b8020c418b6d 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pipe.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pipe.c @@ -27,8 +27,6 @@ static DEFINE_MUTEX(mdss_mdp_sspp_lock); static DEFINE_MUTEX(mdss_mdp_smp_lock); static DECLARE_BITMAP(mdss_mdp_smp_mmb_pool, MDSS_MDP_SMP_MMB_BLOCKS); -static struct mdss_mdp_pipe *mdss_mdp_pipe_search(struct mdss_data_type *mdata, - u32 ndx); static int mdss_mdp_pipe_free(struct mdss_mdp_pipe *pipe); static inline void mdss_mdp_pipe_write(struct mdss_mdp_pipe *pipe, @@ -257,9 +255,11 @@ static struct mdss_mdp_pipe *mdss_mdp_pipe_init(struct mdss_mdp_mixer *mixer, pipe = NULL; } - if (pipe) - pr_debug("type=%x pnum=%d\n", pipe->type, pipe->num); - else + if (pipe) { + pr_info("type=%x pnum=%d\n", pipe->type, pipe->num); + mutex_init(&pipe->pp_res.hist.hist_mutex); + spin_lock_init(&pipe->pp_res.hist.hist_lock); + } else pr_err("no %d type pipes available\n", type); return pipe; @@ -318,7 +318,7 @@ struct mdss_mdp_pipe *mdss_mdp_pipe_get(struct mdss_data_type *mdata, u32 ndx) return pipe; } -static struct mdss_mdp_pipe *mdss_mdp_pipe_search(struct mdss_data_type *mdata, +struct mdss_mdp_pipe *mdss_mdp_pipe_search(struct mdss_data_type *mdata, u32 ndx) { u32 i; diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c index 2e20eb6b57b8..9fb4e1eefc7d 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c @@ -78,7 +78,7 @@ struct mdp_csc_cfg mdp_csc_convert[MDSS_MDP_MAX_CSC] = { #define MDSS_BLOCK_DISP_NUM (MDP_BLOCK_MAX - MDP_LOGICAL_BLOCK_DISP_0) -#define HIST_WAIT_TIMEOUT(frame) ((60 * HZ * (frame)) / 1000) +#define HIST_WAIT_TIMEOUT(frame) ((75 * HZ * (frame)) / 1000) /* hist collect state */ enum { HIST_UNKNOWN, @@ -154,11 +154,13 @@ struct mdss_pp_res_type { }; static DEFINE_MUTEX(mdss_pp_mutex); -static DEFINE_SPINLOCK(mdss_hist_lock); -static DEFINE_MUTEX(mdss_mdp_hist_mutex); static struct mdss_pp_res_type *mdss_pp_res; -static void pp_hist_read(u32 v_base, struct pp_hist_col_info *hist_info); +static void pp_hist_read(char __iomem *v_base, + struct pp_hist_col_info *hist_info); +static int pp_histogram_setup(u32 *op, u32 block, struct mdss_mdp_mixer *mix); +static int pp_histogram_disable(struct pp_hist_col_info *hist_info, + u32 done_bit, char __iomem *ctl_base); static void pp_update_pcc_regs(u32 offset, struct mdp_pcc_cfg_data *cfg_ptr); static void pp_update_igc_lut(struct mdp_igc_lut_data *cfg, @@ -452,6 +454,8 @@ static int pp_vig_pipe_setup(struct mdss_mdp_pipe *pipe, u32 *op) } } + pp_histogram_setup(&opmode, MDSS_PP_SSPP_CFG | pipe->num, pipe->mixer); + if (pipe->flags & MDP_OVERLAY_PP_CFG_EN) { if (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_PA_CFG) { flags = PP_FLAGS_DIRTY_PA; @@ -692,6 +696,17 @@ int mdss_mdp_pipe_pp_setup(struct mdss_mdp_pipe *pipe, u32 *op) void mdss_mdp_pipe_sspp_term(struct mdss_mdp_pipe *pipe) { + u32 done_bit; + struct pp_hist_col_info *hist_info; + char __iomem *ctl_base; + + if (!pipe && pipe->pp_res.hist.col_en) { + done_bit = 3 << (pipe->num * 4); + hist_info = &pipe->pp_res.hist; + ctl_base = pipe->base + + MDSS_MDP_REG_VIG_HIST_CTL_BASE; + pp_histogram_disable(hist_info, done_bit, ctl_base); + } memset(&pipe->pp_cfg, 0, sizeof(struct mdp_overlay_pp_params)); memset(&pipe->pp_res, 0, sizeof(struct mdss_pipe_pp_res)); } @@ -784,16 +799,86 @@ static int pp_mixer_setup(u32 disp_num, struct mdss_mdp_ctl *ctl, return 0; } +static char __iomem *mdss_mdp_get_dspp_addr_off(u32 dspp_num) +{ + struct mdss_data_type *mdata; + struct mdss_mdp_mixer *mixer; + + mdata = mdss_mdp_get_mdata(); + if (mdata->nmixers_intf <= dspp_num) { + pr_err("Invalid dspp_num=%d", dspp_num); + return ERR_PTR(-EINVAL); + } + mixer = mdata->mixer_intf + dspp_num; + return mixer->dspp_base; +} + +/* Assumes that function will be called from within clock enabled space*/ +static int pp_histogram_setup(u32 *op, u32 block, struct mdss_mdp_mixer *mix) +{ + int ret = -EINVAL; + char __iomem *base; + u32 op_flags, kick_base, col_state; + struct mdss_data_type *mdata; + struct mdss_mdp_pipe *pipe; + struct pp_hist_col_info *hist_info; + unsigned long flag; + + if (mix && (PP_LOCAT(block) == MDSS_PP_DSPP_CFG)) { + /* HIST_EN & AUTO_CLEAR */ + op_flags = BIT(16) | BIT(17); + hist_info = &mdss_pp_res->dspp_hist[mix->num]; + base = mdss_mdp_get_dspp_addr_off(PP_BLOCK(block)); + kick_base = MDSS_MDP_REG_DSPP_HIST_CTL_BASE; + } else if (PP_LOCAT(block) == MDSS_PP_SSPP_CFG) { + mdata = mdss_mdp_get_mdata(); + pipe = mdss_mdp_pipe_get(mdata, BIT(PP_BLOCK(block))); + if (IS_ERR_OR_NULL(pipe)) { + pr_debug("pipe DNE (%d)", (u32) BIT(PP_BLOCK(block))); + ret = -ENODEV; + goto error; + } + /* HIST_EN & AUTO_CLEAR */ + op_flags = BIT(8) + BIT(9); + hist_info = &pipe->pp_res.hist; + base = pipe->base; + kick_base = MDSS_MDP_REG_VIG_HIST_CTL_BASE; + mdss_mdp_pipe_unmap(pipe); + } else { + pr_warn("invalid histogram location (%d)", block); + goto error; + } + + if (hist_info->col_en) { + *op |= op_flags; + mutex_lock(&hist_info->hist_mutex); + spin_lock_irqsave(&hist_info->hist_lock, flag); + col_state = hist_info->col_state; + if (hist_info->is_kick_ready && + ((col_state == HIST_IDLE) || + ((false == hist_info->read_request) && + col_state == HIST_READY))) { + /* Kick off collection */ + writel_relaxed(1, base + kick_base); + hist_info->col_state = HIST_START; + } + spin_unlock_irqrestore(&hist_info->hist_lock, flag); + mutex_unlock(&hist_info->hist_mutex); + } + ret = 0; +error: + return ret; +} + static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_ctl *ctl, struct mdss_mdp_mixer *mixer) { u32 flags, base, offset, dspp_num, opmode = 0; struct mdp_dither_cfg_data *dither_cfg; - struct pp_hist_col_info *hist_info; struct mdp_pgc_lut_data *pgc_config; struct pp_sts_type *pp_sts; - u32 data, col_state; - unsigned long flag; + u32 data; + char __iomem *basel; int i, ret = 0; if (!mixer || !ctl) @@ -805,28 +890,13 @@ static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_ctl *ctl, (dspp_num >= MDSS_MDP_MAX_DSPP)) return -EINVAL; base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num); - hist_info = &mdss_pp_res->dspp_hist[dspp_num]; + basel = mdss_mdp_get_dspp_addr_off(dspp_num); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); - if (hist_info->col_en) { - /* HIST_EN & AUTO_CLEAR */ - opmode |= (1 << 16) | (1 << 17); - mutex_lock(&mdss_mdp_hist_mutex); - spin_lock_irqsave(&mdss_hist_lock, flag); - col_state = hist_info->col_state; - if (hist_info->is_kick_ready && - ((col_state == HIST_IDLE) || - ((false == hist_info->read_request) && - col_state == HIST_READY))) { - /* Kick off collection */ - MDSS_MDP_REG_WRITE(base + - MDSS_MDP_REG_DSPP_HIST_CTL_BASE, 1); - hist_info->col_state = HIST_START; - } - spin_unlock_irqrestore(&mdss_hist_lock, flag); - mutex_unlock(&mdss_mdp_hist_mutex); - } + ret = pp_histogram_setup(&opmode, MDSS_PP_DSPP_CFG | dspp_num, mixer); + if (ret) + goto dspp_exit; if (disp_num < MDSS_BLOCK_DISP_NUM) flags = mdss_pp_res->pp_disp_flags[disp_num]; @@ -834,7 +904,7 @@ static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_ctl *ctl, flags = 0; /* nothing to update */ - if ((!flags) && (!(hist_info->col_en))) + if ((!flags) && (!(opmode))) goto dspp_exit; pp_sts = &mdss_pp_res->pp_dspp_sts[dspp_num]; @@ -922,7 +992,7 @@ static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_ctl *ctl, if (pp_sts->pgc_sts & PP_STS_ENABLE) opmode |= (1 << 22); - MDSS_MDP_REG_WRITE(base + MDSS_MDP_REG_DSPP_OP_MODE, opmode); + writel_relaxed(opmode, basel + MDSS_MDP_REG_DSPP_OP_MODE); mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, BIT(13 + dspp_num)); wmb(); dspp_exit: @@ -1056,7 +1126,9 @@ int mdss_mdp_pp_resume(u32 mixer_num) int mdss_mdp_pp_init(struct device *dev) { - int ret = 0; + int i, ret = 0; + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + struct mdss_mdp_pipe *vig; mutex_lock(&mdss_pp_mutex); if (!mdss_pp_res) { @@ -1066,6 +1138,18 @@ int mdss_mdp_pp_init(struct device *dev) pr_err("%s mdss_pp_res allocation failed!", __func__); ret = -ENOMEM; } + + for (i = 0; i < MDSS_MDP_MAX_DSPP; i++) { + mutex_init(&mdss_pp_res->dspp_hist[i].hist_mutex); + spin_lock_init(&mdss_pp_res->dspp_hist[i].hist_lock); + } + } + if (mdata) { + vig = mdata->vig_pipes; + for (i = 0; i < mdata->nvig_pipes; i++) { + mutex_init(&vig[i].pp_res.hist.hist_mutex); + spin_lock_init(&vig[i].pp_res.hist.hist_lock); + } } mutex_unlock(&mdss_pp_mutex); return ret; @@ -1562,7 +1646,7 @@ int mdss_mdp_argc_config(struct mdss_mdp_ctl *ctl, mutex_lock(&mdss_pp_mutex); disp_num = PP_BLOCK(config->block) - MDP_LOGICAL_BLOCK_DISP_0; - switch (config->block & MDSS_PP_LOCATION_MASK) { + switch (PP_LOCAT(config->block)) { case MDSS_PP_LM_CFG: argc_offset = MDSS_MDP_REG_LM_OFFSET(dspp_num) + MDSS_MDP_REG_LM_GC_LUT_BASE; @@ -1658,12 +1742,12 @@ int mdss_mdp_hist_lut_config(struct mdss_mdp_ctl *ctl, if (!ctl) return -EINVAL; - if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) || - (config->block >= MDP_BLOCK_MAX)) + if ((PP_BLOCK(config->block) < MDP_LOGICAL_BLOCK_DISP_0) || + (PP_BLOCK(config->block) >= MDP_BLOCK_MAX)) return -EINVAL; mutex_lock(&mdss_pp_mutex); - disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0; + disp_num = PP_BLOCK(config->block) - MDP_LOGICAL_BLOCK_DISP_0; if (config->ops & MDP_PP_OPS_READ) { ret = pp_get_dspp_num(disp_num, &dspp_num); @@ -1821,124 +1905,205 @@ gamut_config_exit: mdss_mdp_pp_setup(ctl); return ret; } -static void pp_hist_read(u32 v_base, struct pp_hist_col_info *hist_info) +static void pp_hist_read(char __iomem *v_base, + struct pp_hist_col_info *hist_info) { int i, i_start; u32 data; - data = MDSS_MDP_REG_READ(v_base); + data = readl_relaxed(v_base); i_start = data >> 24; hist_info->data[i_start] = data & 0xFFFFFF; for (i = i_start + 1; i < HIST_V_SIZE; i++) - hist_info->data[i] = MDSS_MDP_REG_READ(v_base) & 0xFFFFFF; + hist_info->data[i] = readl_relaxed(v_base) & 0xFFFFFF; for (i = 0; i < i_start - 1; i++) - hist_info->data[i] = MDSS_MDP_REG_READ(v_base) & 0xFFFFFF; + hist_info->data[i] = readl_relaxed(v_base) & 0xFFFFFF; hist_info->hist_cnt_read++; } +/* Assumes that relevant clocks are enabled */ +static int pp_histogram_enable(struct pp_hist_col_info *hist_info, + struct mdp_histogram_start_req *req, + u32 shift_bit, char __iomem *ctl_base) +{ + unsigned long flag; + int ret = 0; + mutex_lock(&hist_info->hist_mutex); + /* check if it is idle */ + if (hist_info->col_en) { + pr_info("%s Hist collection has already been enabled %d", + __func__, (u32) ctl_base); + ret = -EINVAL; + goto exit; + } + hist_info->frame_cnt = req->frame_cnt; + init_completion(&hist_info->comp); + hist_info->hist_cnt_read = 0; + hist_info->hist_cnt_sent = 0; + hist_info->hist_cnt_time = 0; + spin_lock_irqsave(&hist_info->hist_lock, flag); + hist_info->read_request = false; + hist_info->col_state = HIST_RESET; + hist_info->col_en = true; + spin_unlock_irqrestore(&hist_info->hist_lock, flag); + hist_info->is_kick_ready = false; + mdss_mdp_hist_irq_enable(3 << shift_bit); + writel_relaxed(req->frame_cnt, ctl_base + 8); + /* Kick out reset start */ + writel_relaxed(1, ctl_base + 4); +exit: + mutex_unlock(&hist_info->hist_mutex); + return ret; +} + int mdss_mdp_histogram_start(struct mdss_mdp_ctl *ctl, - struct mdp_histogram_start_req *req) + struct mdp_histogram_start_req *req) { - u32 ctl_base, done_shift_bit; + u32 done_shift_bit; + char __iomem *ctl_base; struct pp_hist_col_info *hist_info; int i, ret = 0; u32 disp_num, dspp_num = 0; u32 mixer_cnt, mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER]; - unsigned long flag; - + struct mdss_mdp_pipe *pipe; + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); if (!ctl) return -EINVAL; - if ((req->block < MDP_LOGICAL_BLOCK_DISP_0) || - (req->block >= MDP_BLOCK_MAX)) + if ((PP_BLOCK(req->block) < MDP_LOGICAL_BLOCK_DISP_0) || + (PP_BLOCK(req->block) >= MDP_BLOCK_MAX)) return -EINVAL; - mutex_lock(&mdss_mdp_hist_mutex); - disp_num = req->block - MDP_LOGICAL_BLOCK_DISP_0; + disp_num = PP_BLOCK(req->block) - MDP_LOGICAL_BLOCK_DISP_0; mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id); if (!mixer_cnt) { pr_err("%s, no dspp connects to disp %d", __func__, disp_num); ret = -EPERM; - goto hist_start_exit; + goto hist_exit; } if (mixer_cnt >= MDSS_MDP_MAX_DSPP) { pr_err("%s, Too many dspp connects to disp %d", __func__, mixer_cnt); ret = -EPERM; - goto hist_start_exit; + goto hist_exit; } mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); - for (i = 0; i < mixer_cnt; i++) { - dspp_num = mixer_id[i]; - hist_info = &mdss_pp_res->dspp_hist[dspp_num]; - done_shift_bit = (dspp_num * 4) + 12; - /* check if it is idle */ - if (hist_info->col_en) { - mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); - pr_info("%s Hist collection has already been enabled %d", - __func__, dspp_num); - goto hist_start_exit; - } - spin_lock_irqsave(&mdss_hist_lock, flag); - hist_info->frame_cnt = req->frame_cnt; - init_completion(&hist_info->comp); - hist_info->hist_cnt_read = 0; - hist_info->hist_cnt_sent = 0; - hist_info->read_request = false; - hist_info->col_state = HIST_RESET; - hist_info->col_en = true; - hist_info->is_kick_ready = false; - spin_unlock_irqrestore(&mdss_hist_lock, flag); - mdss_pp_res->hist_col[disp_num][i] = - &mdss_pp_res->dspp_hist[dspp_num]; - mdss_mdp_hist_irq_enable(3 << done_shift_bit); - ctl_base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) + - MDSS_MDP_REG_DSPP_HIST_CTL_BASE; - MDSS_MDP_REG_WRITE(ctl_base + 8, req->frame_cnt); - /* Kick out reset start */ - MDSS_MDP_REG_WRITE(ctl_base + 4, 1); - } - for (i = mixer_cnt; i < MDSS_MDP_MAX_DSPP; i++) - mdss_pp_res->hist_col[disp_num][i] = 0; - mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_HIST_COL; + + if (PP_LOCAT(req->block) == MDSS_PP_SSPP_CFG) { + i = MDSS_PP_ARG_MASK & req->block; + if (!i) { + ret = -EINVAL; + pr_warn("Must pass pipe arguments, %d", i); + goto hist_exit; + } + + for (i = 0; i < MDSS_PP_ARG_NUM; i++) { + if (!PP_ARG(i, req->block)) + continue; + pipe = mdss_mdp_pipe_get(mdata, BIT(i)); + if (IS_ERR_OR_NULL(pipe)) + continue; + if (!pipe || pipe->num > MDSS_MDP_SSPP_VIG2) { + ret = -EINVAL; + pr_warn("Invalid Hist pipe (%d)", i); + goto hist_exit; + } + done_shift_bit = (pipe->num * 4); + hist_info = &pipe->pp_res.hist; + ctl_base = pipe->base + + MDSS_MDP_REG_VIG_HIST_CTL_BASE; + ret = pp_histogram_enable(hist_info, req, + done_shift_bit, ctl_base); + mdss_mdp_pipe_unmap(pipe); + } + } else if (PP_LOCAT(req->block) == MDSS_PP_DSPP_CFG) { + for (i = 0; i < mixer_cnt; i++) { + dspp_num = mixer_id[i]; + done_shift_bit = (dspp_num * 4) + 12; + hist_info = &mdss_pp_res->dspp_hist[dspp_num]; + ctl_base = mdss_mdp_get_dspp_addr_off(dspp_num) + + MDSS_MDP_REG_DSPP_HIST_CTL_BASE; + ret = pp_histogram_enable(hist_info, req, + done_shift_bit, ctl_base); + mdss_pp_res->pp_disp_flags[disp_num] |= + PP_FLAGS_DIRTY_HIST_COL; + } + } mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); -hist_start_exit: - mutex_unlock(&mdss_mdp_hist_mutex); - if (!ret) { + +hist_exit: + if (!ret && (PP_LOCAT(req->block) == MDSS_PP_DSPP_CFG)) { mdss_mdp_pp_setup(ctl); /* wait for a frame to let histrogram enable itself */ + /* TODO add hysteresis value to be able to remove this sleep */ usleep(41666); for (i = 0; i < mixer_cnt; i++) { dspp_num = mixer_id[i]; hist_info = &mdss_pp_res->dspp_hist[dspp_num]; - mutex_lock(&mdss_mdp_hist_mutex); - spin_lock_irqsave(&mdss_hist_lock, flag); + mutex_lock(&hist_info->hist_mutex); hist_info->is_kick_ready = true; - spin_unlock_irqrestore(&mdss_hist_lock, flag); - mutex_unlock(&mdss_mdp_hist_mutex); + mutex_unlock(&hist_info->hist_mutex); + } + } else if (!ret) { + for (i = 0; i < MDSS_PP_ARG_NUM; i++) { + if (!PP_ARG(i, req->block)) + continue; + pr_info("PP_ARG(%d) = %d", i, PP_ARG(i, req->block)); + pipe = mdss_mdp_pipe_get(mdata, BIT(i)); + if (IS_ERR_OR_NULL(pipe)) + continue; + hist_info = &pipe->pp_res.hist; + hist_info->is_kick_ready = true; + mdss_mdp_pipe_unmap(pipe); } } return ret; } +static int pp_histogram_disable(struct pp_hist_col_info *hist_info, + u32 done_bit, char __iomem *ctl_base) +{ + int ret = 0; + unsigned long flag; + mutex_lock(&hist_info->hist_mutex); + if (hist_info->col_en == false) { + pr_debug("Histogram already disabled (%d)", (u32) ctl_base); + ret = -EINVAL; + goto exit; + } + complete_all(&hist_info->comp); + spin_lock_irqsave(&hist_info->hist_lock, flag); + hist_info->col_en = false; + 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); + writel_relaxed(BIT(1), ctl_base);/* cancel */ + ret = 0; +exit: + mutex_unlock(&hist_info->hist_mutex); + return ret; +} + int mdss_mdp_histogram_stop(struct mdss_mdp_ctl *ctl, u32 block) { int i, ret = 0; - u32 dspp_num, disp_num, ctl_base, done_bit; + char __iomem *ctl_base; + u32 dspp_num, disp_num, done_bit; struct pp_hist_col_info *hist_info; u32 mixer_cnt, mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER]; - unsigned long flag; + struct mdss_mdp_pipe *pipe; + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); if (!ctl) return -EINVAL; - if ((block < MDP_LOGICAL_BLOCK_DISP_0) || - (block >= MDP_BLOCK_MAX)) + if ((PP_BLOCK(block) < MDP_LOGICAL_BLOCK_DISP_0) || + (PP_BLOCK(block) >= MDP_BLOCK_MAX)) return -EINVAL; - mutex_lock(&mdss_mdp_hist_mutex); - disp_num = block - MDP_LOGICAL_BLOCK_DISP_0; + disp_num = PP_BLOCK(block) - MDP_LOGICAL_BLOCK_DISP_0; mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id); if (!mixer_cnt) { @@ -1954,162 +2119,312 @@ int mdss_mdp_histogram_stop(struct mdss_mdp_ctl *ctl, u32 block) goto hist_stop_exit; } mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); - for (i = 0; i < mixer_cnt; i++) { - dspp_num = mixer_id[i]; - hist_info = &mdss_pp_res->dspp_hist[dspp_num]; - done_bit = 3 << ((dspp_num * 4) + 12); - ctl_base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) + - MDSS_MDP_REG_DSPP_HIST_CTL_BASE; - if (hist_info->col_en == false) { - mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); + if (PP_LOCAT(block) == MDSS_PP_SSPP_CFG) { + i = MDSS_PP_ARG_MASK & block; + if (!i) { + pr_warn("Must pass pipe arguments, %d", i); goto hist_stop_exit; } - complete_all(&hist_info->comp); - spin_lock_irqsave(&mdss_hist_lock, flag); - hist_info->col_en = false; - hist_info->col_state = HIST_UNKNOWN; - hist_info->is_kick_ready = false; - spin_unlock_irqrestore(&mdss_hist_lock, flag); - mdss_mdp_hist_irq_disable(done_bit); - MDSS_MDP_REG_WRITE(ctl_base, (1 << 1));/* cancel */ - } - for (i = 0; i < MDSS_MDP_MAX_DSPP; i++) - mdss_pp_res->hist_col[disp_num][i] = 0; - mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_HIST_COL; - mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); + + for (i = 0; i < MDSS_PP_ARG_NUM; i++) { + if (!PP_ARG(i, block)) + continue; + pipe = mdss_mdp_pipe_get(mdata, BIT(i)); + if (IS_ERR_OR_NULL(pipe) || + pipe->num > MDSS_MDP_SSPP_VIG2) { + pr_warn("Invalid Hist pipe (%d)", i); + continue; + } + done_bit = 3 << (pipe->num * 4); + hist_info = &pipe->pp_res.hist; + ctl_base = pipe->base + + MDSS_MDP_REG_VIG_HIST_CTL_BASE; + ret = pp_histogram_disable(hist_info, done_bit, + ctl_base); + mdss_mdp_pipe_unmap(pipe); + if (ret) + goto hist_stop_exit; + } + } else if (PP_LOCAT(block) == MDSS_PP_DSPP_CFG) { + for (i = 0; i < mixer_cnt; i++) { + dspp_num = mixer_id[i]; + done_bit = 3 << ((dspp_num * 4) + 12); + hist_info = &mdss_pp_res->dspp_hist[dspp_num]; + ctl_base = mdss_mdp_get_dspp_addr_off(dspp_num) + + MDSS_MDP_REG_DSPP_HIST_CTL_BASE; + ret = pp_histogram_disable(hist_info, done_bit, + ctl_base); + if (ret) + goto hist_stop_exit; + mdss_pp_res->pp_disp_flags[disp_num] |= + PP_FLAGS_DIRTY_HIST_COL; + } + } hist_stop_exit: - mutex_unlock(&mdss_mdp_hist_mutex); - if (!ret) + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); + if (!ret && (PP_LOCAT(block) == MDSS_PP_DSPP_CFG)) mdss_mdp_pp_setup(ctl); return ret; } +static int pp_hist_collect(struct mdss_mdp_ctl *ctl, + struct mdp_histogram_data *hist, + struct pp_hist_col_info *hist_info, + char __iomem *ctl_base) +{ + int wait_ret, ret = 0; + u32 timeout; + char __iomem *v_base; + unsigned long flag; + struct mdss_pipe_pp_res *res; + struct mdss_mdp_pipe *pipe; + + mutex_lock(&hist_info->hist_mutex); + if ((hist_info->col_en == 0) || + (hist_info->col_state == HIST_UNKNOWN)) { + ret = -EINVAL; + goto hist_collect_exit; + } + spin_lock_irqsave(&hist_info->hist_lock, flag); + /* wait for hist done if cache has no data */ + if (hist_info->col_state != HIST_READY) { + hist_info->read_request = true; + spin_unlock_irqrestore(&hist_info->hist_lock, flag); + timeout = HIST_WAIT_TIMEOUT(hist_info->frame_cnt); + mutex_unlock(&hist_info->hist_mutex); + /* flush updates before wait*/ + if (PP_LOCAT(hist->block) == MDSS_PP_DSPP_CFG) + mdss_mdp_pp_setup(ctl); + if (PP_LOCAT(hist->block) == MDSS_PP_SSPP_CFG) { + res = container_of(hist_info, struct mdss_pipe_pp_res, + hist); + pipe = container_of(res, struct mdss_mdp_pipe, pp_res); + pipe->params_changed++; + } + wait_ret = wait_for_completion_killable_timeout( + &(hist_info->comp), timeout); + + mutex_lock(&hist_info->hist_mutex); + if (wait_ret == 0) { + ret = -ETIMEDOUT; + spin_lock_irqsave(&hist_info->hist_lock, flag); + pr_debug("bin collection timedout, state %d", + hist_info->col_state); + /* + * When the histogram has timed out (usually + * underrun) change the SW state back to idle + * since histogram hardware will have done the + * same. Histogram data also needs to be + * cleared in this case, which is done by the + * histogram being read (triggered by READY + * state, which also moves the histogram SW back + * to IDLE). + */ + hist_info->hist_cnt_time++; + hist_info->col_state = HIST_READY; + spin_unlock_irqrestore(&hist_info->hist_lock, flag); + } else if (wait_ret < 0) { + ret = -EINTR; + pr_debug("%s: bin collection interrupted", + __func__); + goto hist_collect_exit; + } + if (hist_info->col_state != HIST_READY) { + ret = -ENODATA; + pr_debug("%s: state is not ready: %d", + __func__, hist_info->col_state); + goto hist_collect_exit; + } + } else { + spin_unlock_irqrestore(&hist_info->hist_lock, flag); + } + spin_lock_irqsave(&hist_info->hist_lock, flag); + if (hist_info->col_state == HIST_READY) { + spin_unlock_irqrestore(&hist_info->hist_lock, flag); + v_base = ctl_base + 0x1C; + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); + pp_hist_read(v_base, hist_info); + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); + spin_lock_irqsave(&hist_info->hist_lock, flag); + hist_info->read_request = false; + hist_info->col_state = HIST_IDLE; + } + spin_unlock_irqrestore(&hist_info->hist_lock, flag); +hist_collect_exit: + mutex_unlock(&hist_info->hist_mutex); + return ret; +} + int mdss_mdp_hist_collect(struct mdss_mdp_ctl *ctl, - struct mdp_histogram_data *hist, - u32 *hist_data_addr) + struct mdp_histogram_data *hist) { - int i, j, wait_ret, ret = 0; - u32 timeout, v_base; + int i, j, off, ret = 0; struct pp_hist_col_info *hist_info; - u32 dspp_num, disp_num, ctl_base; - u32 mixer_cnt, mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER]; - unsigned long flag; + u32 dspp_num, disp_num; + char __iomem *ctl_base; + u32 hist_cnt, mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER]; + u32 *hist_concat = NULL; + u32 *hist_data_addr; + u32 pipe_cnt = 0; + u32 pipe_num = MDSS_MDP_SSPP_VIG0; + struct mdss_mdp_pipe *pipe; + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); if (!ctl) return -EINVAL; - if ((hist->block < MDP_LOGICAL_BLOCK_DISP_0) || - (hist->block >= MDP_BLOCK_MAX)) + if ((PP_BLOCK(hist->block) < MDP_LOGICAL_BLOCK_DISP_0) || + (PP_BLOCK(hist->block) >= MDP_BLOCK_MAX)) return -EINVAL; - mutex_lock(&mdss_mdp_hist_mutex); - disp_num = hist->block - MDP_LOGICAL_BLOCK_DISP_0; - mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id); + disp_num = PP_BLOCK(hist->block) - MDP_LOGICAL_BLOCK_DISP_0; + hist_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id); - if (!mixer_cnt) { + if (!hist_cnt) { pr_err("%s, no dspp connects to disp %d", __func__, disp_num); ret = -EPERM; goto hist_collect_exit; } - if (mixer_cnt >= MDSS_MDP_MAX_DSPP) { + if (hist_cnt >= MDSS_MDP_MAX_DSPP) { pr_err("%s, Too many dspp connects to disp %d", - __func__, mixer_cnt); + __func__, hist_cnt); ret = -EPERM; goto hist_collect_exit; } - hist_info = &mdss_pp_res->dspp_hist[0]; - for (i = 0; i < mixer_cnt; i++) { - dspp_num = mixer_id[i]; - hist_info = &mdss_pp_res->dspp_hist[dspp_num]; - ctl_base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) + - MDSS_MDP_REG_DSPP_HIST_CTL_BASE; - if ((hist_info->col_en == 0) || - (hist_info->col_state == HIST_UNKNOWN)) { - ret = -EINVAL; + if (PP_LOCAT(hist->block) == MDSS_PP_DSPP_CFG) { + hist_info = &mdss_pp_res->dspp_hist[disp_num]; + for (i = 0; i < hist_cnt; i++) { + dspp_num = mixer_id[i]; + hist_info = &mdss_pp_res->dspp_hist[dspp_num]; + ctl_base = mdss_mdp_get_dspp_addr_off(dspp_num) + + MDSS_MDP_REG_DSPP_HIST_CTL_BASE; + ret = pp_hist_collect(ctl, hist, hist_info, ctl_base); + if (ret) + goto hist_collect_exit; + } + if (hist_cnt > 1) { + if (hist->bin_cnt != HIST_V_SIZE) { + pr_err("User not expecting size %d output", + HIST_V_SIZE); + ret = -EINVAL; + goto hist_collect_exit; + } + hist_concat = kmalloc(HIST_V_SIZE * sizeof(u32), + GFP_KERNEL); + if (!hist_concat) { + ret = -ENOMEM; + goto hist_collect_exit; + } + memset(hist_concat, 0, HIST_V_SIZE * sizeof(u32)); + for (i = 0; i < hist_cnt; i++) { + dspp_num = mixer_id[i]; + hist_info = &mdss_pp_res->dspp_hist[dspp_num]; + mutex_lock(&hist_info->hist_mutex); + for (j = 0; j < HIST_V_SIZE; j++) + hist_concat[i] += hist_info->data[i]; + mutex_unlock(&hist_info->hist_mutex); + } + hist_data_addr = hist_concat; + } else { + hist_data_addr = hist_info->data; + } + hist_info = &mdss_pp_res->dspp_hist[disp_num]; + hist_info->hist_cnt_sent++; + } else if (PP_LOCAT(hist->block) == MDSS_PP_SSPP_CFG) { + + hist_cnt = MDSS_PP_ARG_MASK & hist->block; + if (!hist_cnt) { + pr_warn("Must pass pipe arguments, %d", hist_cnt); goto hist_collect_exit; } - spin_lock_irqsave(&mdss_hist_lock, flag); - /* wait for hist done if cache has no data */ - if (hist_info->col_state != HIST_READY) { - hist_info->read_request = true; - spin_unlock_irqrestore(&mdss_hist_lock, flag); - timeout = HIST_WAIT_TIMEOUT(hist_info->frame_cnt); - mutex_unlock(&mdss_mdp_hist_mutex); - /* flush updates before wait*/ - mdss_mdp_pp_setup(ctl); - wait_ret = wait_for_completion_killable_timeout( - &(hist_info->comp), timeout); - - mutex_lock(&mdss_mdp_hist_mutex); - if (wait_ret == 0) { - ret = -ETIMEDOUT; - spin_lock_irqsave(&mdss_hist_lock, flag); - pr_debug("bin collection timedout, state %d", - hist_info->col_state); - /* - * When the histogram has timed out (usually - * underrun) change the SW state back to idle - * since histogram hardware will have done the - * same. Histogram data also needs to be - * cleared in this case, which is done by the - * histogram being read (triggered by READY - * state, which also moves the histogram SW back - * to IDLE). - */ - hist_info->col_state = HIST_READY; - spin_unlock_irqrestore(&mdss_hist_lock, flag); - } else if (wait_ret < 0) { - ret = -EINTR; - pr_debug("%s: bin collection interrupted", - __func__); + + /* Find the first pipe requested */ + for (i = 0; i < MDSS_PP_ARG_NUM; i++) { + if (PP_ARG(i, hist_cnt)) { + pipe_num = i; + break; + } + } + + pipe = mdss_mdp_pipe_get(mdata, BIT(pipe_num)); + if (IS_ERR_OR_NULL(pipe)) { + pr_warn("Invalid starting hist pipe, %d", pipe_num); + ret = -ENODEV; + goto hist_collect_exit; + } + hist_info = &pipe->pp_res.hist; + mdss_mdp_pipe_unmap(pipe); + for (i = pipe_num; i < MDSS_PP_ARG_NUM; i++) { + if (!PP_ARG(i, hist->block)) + continue; + pipe_cnt++; + pipe = mdss_mdp_pipe_get(mdata, BIT(i)); + if (IS_ERR_OR_NULL(pipe) || + pipe->num > MDSS_MDP_SSPP_VIG2) { + pr_warn("Invalid Hist pipe (%d)", i); + continue; + } + hist_info = &pipe->pp_res.hist; + ctl_base = pipe->base + + MDSS_MDP_REG_VIG_HIST_CTL_BASE; + ret = pp_hist_collect(ctl, hist, hist_info, ctl_base); + mdss_mdp_pipe_unmap(pipe); + if (ret) + goto hist_collect_exit; + } + if (pipe_cnt > 1) { + if (hist->bin_cnt != (HIST_V_SIZE * pipe_cnt)) { + pr_err("User not expecting size %d output", + pipe_cnt * HIST_V_SIZE); + ret = -EINVAL; goto hist_collect_exit; } - if (hist_info->col_state != HIST_READY) { - ret = -ENODATA; - pr_debug("%s: state is not ready: %d", - __func__, hist_info->col_state); + hist_concat = kmalloc(HIST_V_SIZE * pipe_cnt * + sizeof(u32), GFP_KERNEL); + if (!hist_concat) { + ret = -ENOMEM; goto hist_collect_exit; } + + memset(hist_concat, 0, pipe_cnt * HIST_V_SIZE * + sizeof(u32)); + for (i = pipe_num; i < MDSS_PP_ARG_NUM; i++) { + if (!PP_ARG(i, hist->block)) + continue; + pipe = mdss_mdp_pipe_get(mdata, BIT(i)); + hist_info = &pipe->pp_res.hist; + off = HIST_V_SIZE * i; + mutex_lock(&hist_info->hist_mutex); + for (j = off; j < off + HIST_V_SIZE; j++) + hist_concat[j] = + hist_info->data[j - off]; + hist_info->hist_cnt_sent++; + mutex_unlock(&hist_info->hist_mutex); + mdss_mdp_pipe_unmap(pipe); + } + + hist_data_addr = hist_concat; } else { - spin_unlock_irqrestore(&mdss_hist_lock, flag); - } - spin_lock_irqsave(&mdss_hist_lock, flag); - if (hist_info->col_state == HIST_READY) { - spin_unlock_irqrestore(&mdss_hist_lock, flag); - v_base = ctl_base + 0x1C; - mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); - pp_hist_read(v_base, hist_info); - mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); - spin_lock_irqsave(&mdss_hist_lock, flag); - hist_info->read_request = false; - hist_info->col_state = HIST_IDLE; - } - spin_unlock_irqrestore(&mdss_hist_lock, flag); - } - if (mixer_cnt > 1) { - memset(&mdss_pp_res->hist_data[disp_num][0], - 0, HIST_V_SIZE * sizeof(u32)); - for (i = 0; i < mixer_cnt; i++) { - dspp_num = mixer_id[i]; - hist_info = &mdss_pp_res->dspp_hist[dspp_num]; - for (j = 0; j < HIST_V_SIZE; j++) - mdss_pp_res->hist_data[disp_num][i] += - hist_info->data[i]; + hist_data_addr = hist_info->data; } - *hist_data_addr = (u32)&mdss_pp_res->hist_data[disp_num][0]; } else { - *hist_data_addr = (u32)hist_info->data; + pr_info("No Histogram at location %d", PP_LOCAT(hist->block)); + goto hist_collect_exit; } - hist_info->hist_cnt_sent++; + ret = copy_to_user(hist->c0, hist_data_addr, sizeof(u32) * + hist->bin_cnt); hist_collect_exit: - mutex_unlock(&mdss_mdp_hist_mutex); + kfree(hist_concat); + return ret; } void mdss_mdp_hist_intr_done(u32 isr) { u32 isr_blk, blk_idx; - struct pp_hist_col_info *hist_info; + struct pp_hist_col_info *hist_info = NULL; + struct mdss_mdp_pipe *pipe; + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); isr &= 0x333333; while (isr != 0) { if (isr & 0xFFF000) { @@ -2129,36 +2444,40 @@ void mdss_mdp_hist_intr_done(u32 isr) hist_info = &mdss_pp_res->dspp_hist[blk_idx]; } else { if (isr & 0x3) { - blk_idx = 0; + blk_idx = MDSS_MDP_SSPP_VIG0; isr_blk = isr & 0x3; isr &= ~0x3; } else if (isr & 0x30) { - blk_idx = 1; + blk_idx = MDSS_MDP_SSPP_VIG1; isr_blk = (isr >> 4) & 0x3; isr &= ~0x30; } else { - blk_idx = 2; + blk_idx = MDSS_MDP_SSPP_VIG2; isr_blk = (isr >> 8) & 0x3; isr &= ~0x300; } - /* SSPP block, not support yet*/ - continue; + pipe = mdss_mdp_pipe_search(mdata, BIT(blk_idx)); + if (IS_ERR_OR_NULL(pipe)) { + pr_debug("pipe DNE, %d", blk_idx); + continue; + } + hist_info = &pipe->pp_res.hist; } /* Histogram Done Interrupt */ - if ((isr_blk & 0x1) && + if (hist_info && (isr_blk & 0x1) && (hist_info->col_en)) { - spin_lock(&mdss_hist_lock); + spin_lock(&hist_info->hist_lock); hist_info->col_state = HIST_READY; - spin_unlock(&mdss_hist_lock); + spin_unlock(&hist_info->hist_lock); if (hist_info->read_request) complete(&hist_info->comp); } /* Histogram Reset Done Interrupt */ if ((isr_blk & 0x2) && (hist_info->col_en)) { - spin_lock(&mdss_hist_lock); + spin_lock(&hist_info->hist_lock); hist_info->col_state = HIST_IDLE; - spin_unlock(&mdss_hist_lock); + spin_unlock(&hist_info->hist_lock); } }; } |
