summaryrefslogtreecommitdiff
path: root/drivers/video/fbdev
diff options
context:
space:
mode:
authorCarl Vanderlip <carlv@codeaurora.org>2013-03-18 10:18:47 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 20:16:02 -0700
commitd8ae3672df310fd70067ae5bebb27b94da586fa8 (patch)
treeeb58ce5e7bb61156d84bfa7f25d9ea1eaf48cc23 /drivers/video/fbdev
parentbe454c3eacb603ded83fabb2439e4069c6e56798 (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.h5
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_overlay.c30
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pipe.c12
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp.c753
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);
}
};
}