video: msm: Add Histogram collection framework for MDP blocks
Expand the previous histogram collection implementation to support the
addition of other MDP blocks that allow for histogram data collection.
Support the VG1, VG2, DMA-P, and DMA-S histograms using this new
framework (VG pipes only supplying the histogram of luminance).
Change-Id: I94088c1f714fa5d91256ae7b0f5548f8a0b81763
Signed-off-by: Carl Vanderlip <carlv@codeaurora.org>
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 603bad8..a339600 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -88,7 +88,6 @@
struct workqueue_struct *mdp_vsync_wq; /*mdp vsync wq */
struct workqueue_struct *mdp_hist_wq; /*mdp histogram wq */
-struct work_struct mdp_histogram_worker;
static struct workqueue_struct *mdp_pipe_ctrl_wq; /* mdp mdp pipe ctrl wq */
static struct delayed_work mdp_pipe_ctrl_worker;
@@ -460,7 +459,6 @@
return ret;
}
-
DEFINE_MUTEX(mdp_lut_push_sem);
static int mdp_lut_i;
static int mdp_lut_hw_update(struct fb_cmap *cmap)
@@ -554,308 +552,646 @@
#define MDP_REV42_HIST_MAX_BIN 128
#define MDP_REV41_HIST_MAX_BIN 32
-#ifdef CONFIG_FB_MSM_MDP40
-unsigned int mdp_hist_frame_cnt;
-#else
-static unsigned int mdp_hist_frame_cnt;
-#endif
-struct completion mdp_hist_comp;
-static DEFINE_MUTEX(mdp_hist_mutex);
-static boolean mdp_is_hist_data = FALSE;
-static boolean mdp_is_hist_start = FALSE;
-boolean mdp_is_hist_valid = FALSE;
-static boolean mdp_is_hist_init = FALSE;
-static uint32 mdp_hist_r[128];
-static uint32 mdp_hist_g[128];
-static uint32 mdp_hist_b[128];
+#define MDP_HIST_DATA32_R_OFF 0x0100
+#define MDP_HIST_DATA32_G_OFF 0x0200
+#define MDP_HIST_DATA32_B_OFF 0x0300
-void __mdp_histogram_kickoff()
+#define MDP_HIST_DATA128_R_OFF 0x0400
+#define MDP_HIST_DATA128_G_OFF 0x0800
+#define MDP_HIST_DATA128_B_OFF 0x0C00
+
+#define MDP_HIST_DATA_LUMA_OFF 0x0200
+
+#define MDP_HIST_EXTRA_DATA0_OFF 0x0028
+#define MDP_HIST_EXTRA_DATA1_OFF 0x002C
+
+struct mdp_hist_mgmt *mdp_hist_mgmt_array[MDP_HIST_MGMT_MAX];
+
+void __mdp_histogram_kickoff(struct mdp_hist_mgmt *mgmt)
{
- char *mdp_hist_base;
-
- if (mdp_rev >= MDP_REV_40)
- mdp_hist_base = MDP_BASE + 0x95000;
- else if (mdp_rev >= MDP_REV_30 && mdp_rev <= MDP_REV_31)
- mdp_hist_base = MDP_BASE + 0x94000;
- else {
- pr_err("%s(): Unsupported MDP rev. %u\n", __func__, mdp_rev);
- return ;
- }
-
- if (mdp_is_hist_data == TRUE) {
- MDP_OUTP(mdp_hist_base + 0x004, mdp_hist_frame_cnt);
+ char *mdp_hist_base = MDP_BASE + mgmt->base;
+ if (mgmt->mdp_is_hist_data == TRUE) {
+ MDP_OUTP(mdp_hist_base + 0x0004, mgmt->frame_cnt);
MDP_OUTP(mdp_hist_base, 1);
}
}
-void __mdp_histogram_reset()
+void __mdp_histogram_reset(struct mdp_hist_mgmt *mgmt)
{
- char *mdp_hist_base;
-
- if (mdp_rev >= MDP_REV_40)
- mdp_hist_base = MDP_BASE + 0x95000;
- else if (mdp_rev >= MDP_REV_30 && mdp_rev <= MDP_REV_31)
- mdp_hist_base = MDP_BASE + 0x94000;
- else {
- pr_err("%s(): Unsupported MDP rev %u\n", __func__, mdp_rev);
- return ;
- }
-
- MDP_OUTP(mdp_hist_base + 0x00C, 1);
+ char *mdp_hist_base = MDP_BASE + mgmt->base;
+ MDP_OUTP(mdp_hist_base + 0x000C, 1);
}
-static void mdp_hist_read_work(struct work_struct *data)
-{
- char *mdp_hist_base;
- uint32 r_data_offset = 0x100, g_data_offset = 0x200;
- uint32 b_data_offset = 0x300;
- int num_bins, i = 0;
+static void mdp_hist_read_work(struct work_struct *data);
- if (mdp_rev >= MDP_REV_42) {
- mdp_hist_base = MDP_BASE + 0x95000;
- r_data_offset = 0x400;
- g_data_offset = 0x800;
- b_data_offset = 0xc00;
- num_bins = 128;
- } else if (mdp_rev >= MDP_REV_40 && mdp_rev <= MDP_REV_41) {
- mdp_hist_base = MDP_BASE + 0x95000;
- num_bins = 32;
- } else if (mdp_rev >= MDP_REV_30 && mdp_rev <= MDP_REV_31) {
- mdp_hist_base = MDP_BASE + 0x94000;
- num_bins = 32;
- } else {
- pr_err("%s(): Unsupported MDP rev %u\n", __func__, mdp_rev);
- return ;
+static int mdp_hist_init_mgmt(struct mdp_hist_mgmt *mgmt, uint32_t block)
+{
+ uint32_t bins, extra, index, term = 0;
+ init_completion(&mgmt->mdp_hist_comp);
+ mutex_init(&mgmt->mdp_hist_mutex);
+ mutex_init(&mgmt->mdp_do_hist_mutex);
+ mgmt->block = block;
+ mgmt->base = mdp_block2base(block);
+ mgmt->mdp_is_hist_start = FALSE;
+ mgmt->mdp_is_hist_data = FALSE;
+ mgmt->mdp_is_hist_valid = FALSE;
+ mgmt->mdp_is_hist_init = FALSE;
+ mgmt->frame_cnt = 0;
+ mgmt->bit_mask = 0;
+ mgmt->num_bins = 0;
+ switch (block) {
+ case MDP_BLOCK_DMA_P:
+ term = MDP_HISTOGRAM_TERM_DMA_P;
+ bins = (mdp_rev >= MDP_REV_42) ? MDP_REV42_HIST_MAX_BIN :
+ MDP_REV41_HIST_MAX_BIN;
+ extra = 2;
+ mgmt->base += (mdp_rev >= MDP_REV_40) ? 0x5000 : 0x4000;
+ index = MDP_HIST_MGMT_DMA_P;
+ break;
+ case MDP_BLOCK_DMA_S:
+ term = MDP_HISTOGRAM_TERM_DMA_S;
+ bins = MDP_REV42_HIST_MAX_BIN;
+ extra = 2;
+ mgmt->base += 0x5000;
+ index = MDP_HIST_MGMT_DMA_S;
+ break;
+ case MDP_BLOCK_VG_1:
+ term = MDP_HISTOGRAM_TERM_VG_1;
+ bins = MDP_REV42_HIST_MAX_BIN;
+ extra = 1;
+ mgmt->base += 0x6000;
+ index = MDP_HIST_MGMT_VG_1;
+ break;
+ case MDP_BLOCK_VG_2:
+ term = MDP_HISTOGRAM_TERM_VG_2;
+ bins = MDP_REV42_HIST_MAX_BIN;
+ extra = 1;
+ mgmt->base += 0x6000;
+ index = MDP_HIST_MGMT_VG_2;
+ break;
+ default:
+ term = MDP_HISTOGRAM_TERM_DMA_P;
+ bins = (mdp_rev >= MDP_REV_42) ? MDP_REV42_HIST_MAX_BIN :
+ MDP_REV41_HIST_MAX_BIN;
+ extra = 2;
+ mgmt->base += (mdp_rev >= MDP_REV_40) ? 0x5000 : 0x4000;
+ index = MDP_HIST_MGMT_DMA_P;
+ }
+ mgmt->irq_term = term;
+
+ mgmt->c0 = kmalloc(bins * sizeof(uint32_t), GFP_KERNEL);
+ if (mgmt->c0 == NULL)
+ goto error;
+
+ mgmt->c1 = kmalloc(bins * sizeof(uint32_t), GFP_KERNEL);
+ if (mgmt->c1 == NULL)
+ goto error_1;
+
+ mgmt->c2 = kmalloc(bins * sizeof(uint32_t), GFP_KERNEL);
+ if (mgmt->c2 == NULL)
+ goto error_2;
+
+ mgmt->extra_info = kmalloc(extra * sizeof(uint32_t), GFP_KERNEL);
+ if (mgmt->extra_info == NULL)
+ goto error_extra;
+
+ INIT_WORK(&mgmt->mdp_histogram_worker, mdp_hist_read_work);
+
+ mdp_hist_mgmt_array[index] = mgmt;
+ return 0;
+
+error_extra:
+ kfree(mgmt->c2);
+error_2:
+ kfree(mgmt->c1);
+error_1:
+ kfree(mgmt->c0);
+error:
+ return -ENOMEM;
+}
+
+static void mdp_hist_del_mgmt(struct mdp_hist_mgmt *mgmt)
+{
+ kfree(mgmt->extra_info);
+ kfree(mgmt->c2);
+ kfree(mgmt->c1);
+ kfree(mgmt->c0);
+}
+
+static int mdp_histogram_init(void)
+{
+ struct mdp_hist_mgmt *temp;
+ int i, ret;
+ mdp_hist_wq = alloc_workqueue("mdp_hist_wq", WQ_UNBOUND, 0);
+
+ for (i = 0; i < MDP_HIST_MGMT_MAX; i++)
+ mdp_hist_mgmt_array[i] = NULL;
+
+ if (mdp_rev >= MDP_REV_30) {
+ temp = kmalloc(sizeof(struct mdp_hist_mgmt), GFP_KERNEL);
+ if (!temp)
+ goto exit;
+ ret = mdp_hist_init_mgmt(temp, MDP_BLOCK_DMA_P);
+ if (ret) {
+ kfree(temp);
+ goto exit;
+ }
}
- mutex_lock(&mdp_hist_mutex);
- if (mdp_is_hist_data == FALSE) {
- pr_debug("%s, Histogram disabled before read.\n", __func__);
- goto error;
+ if (mdp_rev >= MDP_REV_40) {
+ temp = kmalloc(sizeof(struct mdp_hist_mgmt), GFP_KERNEL);
+ if (!temp)
+ goto exit_list;
+ ret = mdp_hist_init_mgmt(temp, MDP_BLOCK_VG_1);
+ if (ret)
+ goto exit_list;
+
+ temp = kmalloc(sizeof(struct mdp_hist_mgmt), GFP_KERNEL);
+ if (!temp)
+ goto exit_list;
+ ret = mdp_hist_init_mgmt(temp, MDP_BLOCK_VG_2);
+ if (ret)
+ goto exit_list;
+ }
+
+ if (mdp_rev >= MDP_REV_42) {
+ temp = kmalloc(sizeof(struct mdp_hist_mgmt), GFP_KERNEL);
+ if (!temp)
+ goto exit_list;
+ ret = mdp_hist_init_mgmt(temp, MDP_BLOCK_DMA_S);
+ if (ret)
+ goto exit_list;
+ }
+
+ return 0;
+
+exit_list:
+ for (i = 0; i < MDP_HIST_MGMT_MAX; i++) {
+ temp = mdp_hist_mgmt_array[i];
+ if (!temp)
+ continue;
+ mdp_hist_del_mgmt(temp);
+ kfree(temp);
+ mdp_hist_mgmt_array[i] = NULL;
+ }
+exit:
+ return -ENOMEM;
+}
+
+int mdp_histogram_block2mgmt(uint32_t block, struct mdp_hist_mgmt **mgmt)
+{
+ struct mdp_hist_mgmt *temp, *output;
+ int i, ret = 0;
+
+ output = NULL;
+
+ for (i = 0; i < MDP_HIST_MGMT_MAX; i++) {
+ temp = mdp_hist_mgmt_array[i];
+ if (!temp)
+ continue;
+
+ if (temp->block == block) {
+ output = temp;
+ break;
+ }
+ }
+
+ if (output == NULL)
+ ret = -EINVAL;
+ else
+ *mgmt = output;
+
+ return ret;
+}
+
+static int mdp_histogram_enable(struct mdp_hist_mgmt *mgmt)
+{
+ uint32_t base;
+ if (mgmt->mdp_is_hist_data == TRUE) {
+ pr_err("%s histogram already started\n", __func__);
+ return -EINVAL;
}
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- for (i = 0; i < num_bins; i++) {
- mdp_hist_r[i] = inpdw(mdp_hist_base + r_data_offset + (4*i));
- mdp_hist_g[i] = inpdw(mdp_hist_base + g_data_offset + (4*i));
- mdp_hist_b[i] = inpdw(mdp_hist_base + b_data_offset + (4*i));
+ mdp_enable_irq(mgmt->irq_term);
+ INIT_COMPLETION(mgmt->mdp_hist_comp);
+
+ base = (uint32_t) (MDP_BASE + mgmt->base);
+ MDP_OUTP(base + 0x0018, INTR_HIST_DONE | INTR_HIST_RESET_SEQ_DONE);
+ MDP_OUTP(base + 0x0010, 1);
+ MDP_OUTP(base + 0x001C, INTR_HIST_DONE | INTR_HIST_RESET_SEQ_DONE);
+
+ MDP_OUTP(base + 0x0004, mgmt->frame_cnt);
+ if (mgmt->block != MDP_BLOCK_VG_1 && mgmt->block != MDP_BLOCK_VG_2)
+ MDP_OUTP(base + 0x0008, mgmt->bit_mask);
+ mgmt->mdp_is_hist_data = TRUE;
+ mgmt->mdp_is_hist_valid = TRUE;
+ mgmt->mdp_is_hist_init = FALSE;
+ __mdp_histogram_reset(mgmt);
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ return 0;
+}
+
+static int mdp_histogram_disable(struct mdp_hist_mgmt *mgmt)
+{
+ uint32_t base, status;
+ if (mgmt->mdp_is_hist_data == FALSE) {
+ pr_err("%s histogram already stopped\n", __func__);
+ return -EINVAL;
}
- __mdp_histogram_kickoff();
+ mgmt->mdp_is_hist_data = FALSE;
+ mgmt->mdp_is_hist_valid = FALSE;
+ mgmt->mdp_is_hist_init = FALSE;
+ base = (uint32_t) (MDP_BASE + mgmt->base);
+
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ if (mdp_rev >= MDP_REV_42)
+ MDP_OUTP(base + 0x0020, 1);
+ status = inpdw(base + 0x001C);
+ status &= ~(INTR_HIST_DONE | INTR_HIST_RESET_SEQ_DONE);
+ MDP_OUTP(base + 0x001C, status);
+
+ MDP_OUTP(base + 0x0018, INTR_HIST_DONE | INTR_HIST_RESET_SEQ_DONE);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
- /* if read was triggered by an underrun, don't wake up readers*/
- if (mdp_is_hist_valid && mdp_is_hist_init) {
- complete(&mdp_hist_comp);
- } else {
- if (mdp_is_hist_valid == FALSE)
- mdp_is_hist_valid = TRUE;
-
- if (mdp_is_hist_init == FALSE)
- mdp_is_hist_init = TRUE;
- }
-error:
- mutex_unlock(&mdp_hist_mutex);
-}
-
-/*should hold mdp_hist_mutex before calling this function*/
-int _mdp_histogram_ctrl(boolean en)
-{
- unsigned long hist_base;
- uint32_t status;
-
- if (mdp_rev >= MDP_REV_40)
- hist_base = 0x95000;
- else
- hist_base = 0x94000;
-
- if (en == TRUE) {
- if (mdp_is_hist_data)
- return -EINVAL;
-
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- mdp_hist_frame_cnt = 1;
- mdp_enable_irq(MDP_HISTOGRAM_TERM);
- INIT_COMPLETION(mdp_hist_comp);
-
- /*Clear the interrupts before enabling them*/
- MDP_OUTP(MDP_BASE + hist_base + 0x18, INTR_HIST_DONE |
- INTR_HIST_RESET_SEQ_DONE);
- MDP_OUTP(MDP_BASE + hist_base + 0x10, 1);
- MDP_OUTP(MDP_BASE + hist_base + 0x1c, INTR_HIST_DONE |
- INTR_HIST_RESET_SEQ_DONE);
-
- mdp_is_hist_data = TRUE;
- mdp_is_hist_valid = TRUE;
- mdp_is_hist_init = FALSE;
-
- __mdp_histogram_reset();
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-
- } else {
- if (!mdp_is_hist_data)
- return -EINVAL;
-
- mdp_is_hist_data = FALSE;
- mdp_is_hist_valid = FALSE;
- mdp_is_hist_init = FALSE;
-
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- status = inpdw(MDP_BASE + hist_base + 0x1C);
- status &= ~(INTR_HIST_DONE | INTR_HIST_RESET_SEQ_DONE);
- MDP_OUTP(MDP_BASE + hist_base + 0x1C, status);
- MDP_OUTP(MDP_BASE + hist_base + 0x18, INTR_HIST_DONE |
- INTR_HIST_RESET_SEQ_DONE);
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-
- complete(&mdp_hist_comp);
-
- mdp_disable_irq(MDP_HISTOGRAM_TERM);
- }
-
+ complete(&mgmt->mdp_hist_comp);
+ mdp_disable_irq(mgmt->irq_term);
return 0;
}
-int mdp_histogram_ctrl(boolean en)
+/*call when spanning mgmt_array only*/
+int _mdp_histogram_ctrl(boolean en, struct mdp_hist_mgmt *mgmt)
{
int ret = 0;
- mutex_lock(&mdp_hist_mutex);
- if (mdp_is_hist_start)
- ret = _mdp_histogram_ctrl(en);
- mutex_unlock(&mdp_hist_mutex);
+
+ mutex_lock(&mgmt->mdp_hist_mutex);
+ if (mgmt->mdp_is_hist_start == TRUE) {
+ if (en)
+ ret = mdp_histogram_enable(mgmt);
+ else
+ ret = mdp_histogram_disable(mgmt);
+ }
+ mutex_unlock(&mgmt->mdp_hist_mutex);
if (en == false)
- flush_workqueue(mdp_hist_wq);
+ cancel_work_sync(&mgmt->mdp_histogram_worker);
return ret;
}
-int mdp_start_histogram(struct fb_info *info)
+int mdp_histogram_ctrl(boolean en, uint32_t block)
{
- unsigned long flag;
-
+ struct mdp_hist_mgmt *mgmt = NULL;
int ret = 0;
- mutex_lock(&mdp_hist_mutex);
- if (mdp_is_hist_start == TRUE) {
- printk(KERN_ERR "%s histogram already started\n", __func__);
- ret = -EPERM;
- goto mdp_hist_start_err;
- }
- ret = _mdp_histogram_ctrl(TRUE);
+ ret = mdp_histogram_block2mgmt(block, &mgmt);
+ if (ret)
+ goto error;
- spin_lock_irqsave(&mdp_spin_lock, flag);
- mdp_is_hist_start = TRUE;
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
-
-mdp_hist_start_err:
- mutex_unlock(&mdp_hist_mutex);
+ ret = _mdp_histogram_ctrl(en, mgmt);
+error:
return ret;
-
}
-int mdp_stop_histogram(struct fb_info *info)
+int mdp_histogram_ctrl_all(boolean en)
{
- unsigned long flag;
- int ret = 0;
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ struct mdp_hist_mgmt *temp;
+ int i, ret = 0, ret_temp = 0;
- mutex_lock(&mdp_hist_mutex);
- if (!mdp_is_hist_start) {
- printk(KERN_ERR "%s histogram already stopped\n", __func__);
- ret = -EPERM;
- goto mdp_hist_stop_err;
+ for (i = 0; i < MDP_HIST_MGMT_MAX; i++) {
+ temp = mdp_hist_mgmt_array[i];
+ if (!temp)
+ continue;
+
+ ret_temp = _mdp_histogram_ctrl(en, temp);
+ if (ret_temp)
+ ret = ret_temp;
+ }
+ return ret;
+}
+
+int mdp_histogram_start(struct mdp_histogram_start_req *req)
+{
+ struct mdp_hist_mgmt *mgmt = NULL;
+ int ret;
+
+ ret = mdp_histogram_block2mgmt(req->block, &mgmt);
+ if (ret) {
+ ret = -ENOTTY;
+ goto error;
}
- spin_lock_irqsave(&mdp_spin_lock, flag);
- mdp_is_hist_start = FALSE;
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
+ mutex_lock(&mgmt->mdp_hist_mutex);
+ if (mgmt->mdp_is_hist_start == TRUE) {
+ pr_err("%s histogram already started\n", __func__);
+ ret = -EPERM;
+ goto error_lock;
+ }
+
+ mgmt->block = req->block;
+ mgmt->frame_cnt = req->frame_cnt;
+ mgmt->bit_mask = req->bit_mask;
+ mgmt->num_bins = req->num_bins;
+
+ ret = mdp_histogram_enable(mgmt);
+
+ mgmt->mdp_is_hist_start = TRUE;
+
+error_lock:
+ mutex_unlock(&mgmt->mdp_hist_mutex);
+error:
+ return ret;
+}
+
+int mdp_histogram_stop(struct fb_info *info, uint32_t block)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *) info->par;
+ struct mdp_hist_mgmt *mgmt = NULL;
+ int ret;
+
+ ret = mdp_histogram_block2mgmt(block, &mgmt);
+ if (ret) {
+ ret = -ENOTTY;
+ goto error;
+ }
+
+ mutex_lock(&mgmt->mdp_hist_mutex);
+ if (mgmt->mdp_is_hist_start == FALSE) {
+ pr_err("%s histogram already stopped\n", __func__);
+ ret = -EPERM;
+ goto error_lock;
+ }
+
+ mgmt->mdp_is_hist_start = FALSE;
if (!mfd->panel_power_on) {
-
- mdp_is_hist_data = FALSE;
- complete(&mdp_hist_comp);
+ mgmt->mdp_is_hist_data = FALSE;
+ complete(&mgmt->mdp_hist_comp);
ret = -EINVAL;
- goto mdp_hist_stop_err;
+ goto error_lock;
}
- ret = _mdp_histogram_ctrl(FALSE);
+ ret = mdp_histogram_disable(mgmt);
- mutex_unlock(&mdp_hist_mutex);
- flush_workqueue(mdp_hist_wq);
+ mutex_unlock(&mgmt->mdp_hist_mutex);
+ cancel_work_sync(&mgmt->mdp_histogram_worker);
return ret;
-mdp_hist_stop_err:
- mutex_unlock(&mdp_hist_mutex);
+error_lock:
+ mutex_unlock(&mgmt->mdp_hist_mutex);
+error:
return ret;
}
-/*call from within mdp_hist_mutex*/
-static int _mdp_copy_hist_data(struct mdp_histogram *hist)
+/*call from within mdp_hist_mutex context*/
+static int _mdp_histogram_read_dma_data(struct mdp_hist_mgmt *mgmt)
{
- int ret = 0;
+ char *mdp_hist_base;
+ uint32_t r_data_offset, g_data_offset, b_data_offset;
+ int i, ret = 0;
- if (hist->r) {
- ret = copy_to_user(hist->r, mdp_hist_r, hist->bin_cnt * 4);
- if (ret)
- goto hist_err;
+ mdp_hist_base = MDP_BASE + mgmt->base;
+
+ r_data_offset = (32 == mgmt->num_bins) ? MDP_HIST_DATA32_R_OFF :
+ MDP_HIST_DATA128_R_OFF;
+ g_data_offset = (32 == mgmt->num_bins) ? MDP_HIST_DATA32_G_OFF :
+ MDP_HIST_DATA128_G_OFF;
+ b_data_offset = (32 == mgmt->num_bins) ? MDP_HIST_DATA32_B_OFF :
+ MDP_HIST_DATA128_B_OFF;
+
+ if (mgmt->c0 == NULL || mgmt->c1 == NULL || mgmt->c2 == NULL) {
+ ret = -ENOMEM;
+ goto hist_err;
}
- if (hist->g) {
- ret = copy_to_user(hist->g, mdp_hist_g, hist->bin_cnt * 4);
- if (ret)
- goto hist_err;
+
+ if (!mgmt->hist) {
+ pr_err("%s: mgmt->hist not set, mgmt->hist = 0x%08x",
+ __func__, (uint32_t) mgmt->hist);
+ return -EINVAL;
}
- if (hist->b) {
- ret = copy_to_user(hist->b, mdp_hist_b, hist->bin_cnt * 4);
- if (ret)
- goto hist_err;
+
+ if (mgmt->hist->bin_cnt != mgmt->num_bins) {
+ pr_err("%s, bins config = %d, bin requested = %d", __func__,
+ mgmt->num_bins, mgmt->hist->bin_cnt);
+ return -EINVAL;
}
- return 0;
+
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ for (i = 0; i < mgmt->num_bins; i++) {
+ mgmt->c0[i] = inpdw(mdp_hist_base + r_data_offset + (4*i));
+ mgmt->c1[i] = inpdw(mdp_hist_base + g_data_offset + (4*i));
+ mgmt->c2[i] = inpdw(mdp_hist_base + b_data_offset + (4*i));
+ }
+
+ if (mdp_rev >= MDP_REV_42) {
+ if (mgmt->extra_info) {
+ mgmt->extra_info[0] = inpdw(mdp_hist_base +
+ MDP_HIST_EXTRA_DATA0_OFF);
+ mgmt->extra_info[1] = inpdw(mdp_hist_base +
+ MDP_HIST_EXTRA_DATA0_OFF + 4);
+ } else
+ ret = -ENOMEM;
+ }
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+ if (!ret)
+ return ret;
+
hist_err:
pr_err("%s: invalid hist buffer\n", __func__);
return ret;
}
-static int mdp_do_histogram(struct fb_info *info, struct mdp_histogram *hist)
+/*call from within mdp_hist_mutex context*/
+static int _mdp_histogram_read_vg_data(struct mdp_hist_mgmt *mgmt)
{
+ char *mdp_hist_base;
+ int i, ret = 0;
+
+ mdp_hist_base = MDP_BASE + mgmt->base;
+
+ if (mgmt->c0 == NULL) {
+ ret = -ENOMEM;
+ goto hist_err;
+ }
+
+ if (!mgmt->hist) {
+ pr_err("%s: mgmt->hist not set", __func__);
+ return -EINVAL;
+ }
+
+ if (mgmt->hist->bin_cnt != mgmt->num_bins) {
+ pr_err("%s, bins config = %d, bin requested = %d", __func__,
+ mgmt->num_bins, mgmt->hist->bin_cnt);
+ return -EINVAL;
+ }
+
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ for (i = 0; i < mgmt->num_bins; i++)
+ mgmt->c0[i] = inpdw(mdp_hist_base + MDP_HIST_DATA_LUMA_OFF +
+ (4*i));
+
+ if (mdp_rev >= MDP_REV_42) {
+ if (mgmt->extra_info) {
+ mgmt->extra_info[0] = inpdw(mdp_hist_base +
+ MDP_HIST_EXTRA_DATA0_OFF);
+ } else
+ ret = -ENOMEM;
+ }
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+ if (!ret)
+ return ret;
+
+hist_err:
+ pr_err("%s: invalid hist buffer\n", __func__);
+ return ret;
+}
+
+static void mdp_hist_read_work(struct work_struct *data)
+{
+ struct mdp_hist_mgmt *mgmt = container_of(data, struct mdp_hist_mgmt,
+ mdp_histogram_worker);
int ret = 0;
-
- if (!hist->frame_cnt || (hist->bin_cnt == 0))
- return -EINVAL;
-
- if ((mdp_rev <= MDP_REV_41 && hist->bin_cnt > MDP_REV41_HIST_MAX_BIN)
- || (mdp_rev == MDP_REV_42 &&
- hist->bin_cnt > MDP_REV42_HIST_MAX_BIN))
- return -EINVAL;
-
- mutex_lock(&mdp_hist_mutex);
- if (!mdp_is_hist_data) {
- pr_err("%s - histogram not ready\n", __func__);
- ret = -EPERM;
+ mutex_lock(&mgmt->mdp_hist_mutex);
+ if (mgmt->mdp_is_hist_data == FALSE) {
+ pr_debug("%s, Histogram disabled before read.\n", __func__);
+ ret = -EINVAL;
goto error;
}
- if (!mdp_is_hist_start) {
- pr_err("%s histogram not started\n", __func__);
- ret = -EPERM;
+ switch (mgmt->block) {
+ case MDP_BLOCK_DMA_P:
+ case MDP_BLOCK_DMA_S:
+ ret = _mdp_histogram_read_dma_data(mgmt);
+ break;
+ case MDP_BLOCK_VG_1:
+ case MDP_BLOCK_VG_2:
+ ret = _mdp_histogram_read_vg_data(mgmt);
+ break;
+ default:
+ pr_err("%s, invalid MDP block = %d\n", __func__, mgmt->block);
+ ret = -EINVAL;
goto error;
}
- mdp_hist_frame_cnt = hist->frame_cnt;
- mutex_unlock(&mdp_hist_mutex);
-
- if (wait_for_completion_killable(&mdp_hist_comp)) {
- pr_err("%s(): histogram bin collection killed", __func__);
- return -EINVAL;
+ /* if read was triggered by an underrun, don't wake up readers*/
+ if (mgmt->mdp_is_hist_valid && mgmt->mdp_is_hist_init) {
+ mgmt->hist = NULL;
+ complete(&mgmt->mdp_hist_comp);
}
- mutex_lock(&mdp_hist_mutex);
- if (mdp_is_hist_data && mdp_is_hist_init)
- ret = _mdp_copy_hist_data(hist);
+ if (mgmt->mdp_is_hist_valid == FALSE)
+ mgmt->mdp_is_hist_valid = TRUE;
+ if (mgmt->mdp_is_hist_init == FALSE)
+ mgmt->mdp_is_hist_init = TRUE;
+
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ if (!ret)
+ __mdp_histogram_kickoff(mgmt);
+ else
+ __mdp_histogram_reset(mgmt);
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
error:
- mutex_unlock(&mdp_hist_mutex);
+ mutex_unlock(&mgmt->mdp_hist_mutex);
+}
+
+/*call from within mdp_hist_mutex*/
+static int _mdp_copy_hist_data(struct mdp_histogram_data *hist,
+ struct mdp_hist_mgmt *mgmt)
+{
+ int ret;
+
+ if (hist->c0) {
+ ret = copy_to_user(hist->c0, mgmt->c0,
+ sizeof(uint32_t) * (hist->bin_cnt));
+ if (ret)
+ goto err;
+ }
+ if (hist->c1) {
+ ret = copy_to_user(hist->c1, mgmt->c1,
+ sizeof(uint32_t) * (hist->bin_cnt));
+ if (ret)
+ goto err;
+ }
+ if (hist->c2) {
+ ret = copy_to_user(hist->c2, mgmt->c2,
+ sizeof(uint32_t) * (hist->bin_cnt));
+ if (ret)
+ goto err;
+ }
+ if (hist->extra_info) {
+ ret = copy_to_user(hist->extra_info, mgmt->extra_info,
+ sizeof(uint32_t) * ((hist->block > MDP_BLOCK_VG_2) ? 2 : 1));
+ if (ret)
+ goto err;
+ }
+err:
+ return ret;
+}
+
+static int mdp_do_histogram(struct fb_info *info,
+ struct mdp_histogram_data *hist)
+{
+ struct mdp_hist_mgmt *mgmt = NULL;
+ int ret = 0;
+
+ ret = mdp_histogram_block2mgmt(hist->block, &mgmt);
+ if (ret) {
+ pr_info("%s - %d", __func__, __LINE__);
+ ret = -EINVAL;
+ return ret;
+ }
+
+ mutex_lock(&mgmt->mdp_do_hist_mutex);
+ if (!mgmt->frame_cnt || (mgmt->num_bins == 0)) {
+ pr_info("%s - frame_cnt = %d, num_bins = %d", __func__,
+ mgmt->frame_cnt, mgmt->num_bins);
+ ret = -EINVAL;
+ goto error;
+}
+ if ((mdp_rev <= MDP_REV_41 && hist->bin_cnt > MDP_REV41_HIST_MAX_BIN)
+ || (mdp_rev == MDP_REV_42 &&
+ hist->bin_cnt > MDP_REV42_HIST_MAX_BIN)) {
+ pr_info("%s - mdp_rev = %d, num_bins = %d", __func__, mdp_rev,
+ hist->bin_cnt);
+ ret = -EINVAL;
+ goto error;
+}
+ mutex_lock(&mgmt->mdp_hist_mutex);
+ if (!mgmt->mdp_is_hist_data) {
+ pr_info("%s - hist_data = false!", __func__);
+ ret = -EINVAL;
+ goto error_lock;
+ }
+
+ if (!mgmt->mdp_is_hist_start) {
+ pr_err("%s histogram not started\n", __func__);
+ ret = -EPERM;
+ goto error_lock;
+ }
+
+ mgmt->hist = hist;
+ mutex_unlock(&mgmt->mdp_hist_mutex);
+
+ if (wait_for_completion_killable(&mgmt->mdp_hist_comp)) {
+ pr_err("%s(): histogram bin collection killed", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ mutex_lock(&mgmt->mdp_hist_mutex);
+ if (mgmt->mdp_is_hist_data && mgmt->mdp_is_hist_init)
+ ret = _mdp_copy_hist_data(hist, mgmt);
+ else
+ ret = -ENODATA;
+error_lock:
+ mutex_unlock(&mgmt->mdp_hist_mutex);
+error:
+ mutex_unlock(&mgmt->mdp_do_hist_mutex);
return ret;
}
#endif
@@ -1210,15 +1546,43 @@
}
}
+void mdp_histogram_handle_isr(struct mdp_hist_mgmt *mgmt)
+{
+ uint32 isr, mask;
+ char *base_addr = MDP_BASE + mgmt->base;
+ isr = inpdw(base_addr + MDP_HIST_INTR_STATUS_OFF);
+ mask = inpdw(base_addr + MDP_HIST_INTR_ENABLE_OFF);
+ outpdw(base_addr + MDP_HIST_INTR_CLEAR_OFF, isr);
+ mb();
+ isr &= mask;
+ if (isr & INTR_HIST_RESET_SEQ_DONE)
+ __mdp_histogram_kickoff(mgmt);
+
+ if (isr & INTR_HIST_DONE) {
+ if (waitqueue_active(&mgmt->mdp_hist_comp.wait)) {
+ if (!queue_work(mdp_hist_wq,
+ &mgmt->mdp_histogram_worker)) {
+ pr_err("%s %d- can't queue hist_read\n",
+ __func__, mgmt->block);
+ }
+ } else {
+ __mdp_histogram_reset(mgmt);
+ }
+ }
+}
+
#ifndef CONFIG_FB_MSM_MDP40
irqreturn_t mdp_isr(int irq, void *ptr)
{
- uint32 hist_interrupt, mdp_interrupt = 0;
+ uint32 mdp_interrupt = 0;
struct mdp_dma_data *dma;
unsigned long flag;
-
+ struct mdp_hist_mgmt *mgmt = NULL;
+ char *base_addr;
+ int i, ret;
/* Ensure all the register write are complete */
mb();
+
mdp_is_in_isr = TRUE;
mdp_interrupt = inp32(MDP_INTR_STATUS);
@@ -1246,25 +1610,14 @@
complete(&dma->comp);
}
}
- if (mdp_rev >= MDP_REV_30) {
- if (mdp_interrupt & MDP_HIST_DONE) {
- hist_interrupt = inp32(MDP_DMA_P_HIST_INTR_STATUS);
- outp32(MDP_BASE + 0x94018, 0x3);
- outp32(MDP_INTR_CLEAR, MDP_HIST_DONE);
- if (hist_interrupt & INTR_HIST_RESET_SEQ_DONE)
- __mdp_histogram_kickoff();
- if (hist_interrupt & INTR_HIST_DONE) {
- if (waitqueue_active(&mdp_hist_comp.wait)) {
- if (!queue_work(mdp_hist_wq,
- &mdp_histogram_worker)) {
- pr_err("%s: can't queue hist_read\n",
- __func__);
- }
- } else {
- __mdp_histogram_reset();
- }
- }
+ if (mdp_rev >= MDP_REV_30) {
+ /* Only DMA_P histogram exists for this MDP rev*/
+ if (mdp_interrupt & MDP_HIST_DONE) {
+ ret = mdp_histogram_block2mgmt(MDP_BLOCK_DMA_P, &mgmt);
+ if (!ret)
+ mdp_histogram_handle_isr(mgmt);
+ outp32(MDP_INTR_CLEAR, MDP_HIST_DONE);
}
/* LCDC UnderFlow */
@@ -1273,10 +1626,18 @@
/*when underflow happens HW resets all the histogram
registers that were set before so restore them back
to normal.*/
- MDP_OUTP(MDP_BASE + 0x94010, 1);
- MDP_OUTP(MDP_BASE + 0x9401c, INTR_HIST_DONE);
- mdp_is_hist_valid = FALSE;
- __mdp_histogram_reset();
+ for (i = 0; i < MDP_HIST_MGMT_MAX; i++) {
+ mgmt = mdp_hist_mgmt_array[i];
+ if (!mgmt)
+ continue;
+
+ base_addr = MDP_BASE + mgmt->base;
+ outpdw(base_addr + 0x010, 1);
+ outpdw(base_addr + 0x01C, INTR_HIST_DONE |
+ INTR_HIST_RESET_SEQ_DONE);
+ mgmt->mdp_is_hist_valid = FALSE;
+ __mdp_histogram_reset(mgmt);
+ }
}
/* LCDC Frame Start */
@@ -1377,7 +1738,6 @@
mdp_dma_wq = create_singlethread_workqueue("mdp_dma_wq");
mdp_vsync_wq = create_singlethread_workqueue("mdp_vsync_wq");
mdp_hist_wq = create_singlethread_workqueue("mdp_hist_wq");
- INIT_WORK(&mdp_histogram_worker, mdp_hist_read_work);
mdp_pipe_ctrl_wq = create_singlethread_workqueue("mdp_pipe_ctrl_wq");
INIT_DELAYED_WORK(&mdp_pipe_ctrl_worker,
mdp_pipe_ctrl_workqueue_handler);
@@ -1418,10 +1778,6 @@
mutex_init(&dma_wb_data.ov_mutex);
#endif
-#ifndef CONFIG_FB_MSM_MDP22
- init_completion(&mdp_hist_comp);
-#endif
-
/* initializing mdp power block counter to 0 */
for (i = 0; i < MDP_MAX_BLOCK; i++) {
atomic_set(&mdp_block_power_cnt[i], 0);
@@ -1510,7 +1866,7 @@
int ret = 0;
struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
- mdp_histogram_ctrl(FALSE);
+ mdp_histogram_ctrl_all(FALSE);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
ret = panel_next_off(pdev);
@@ -1551,7 +1907,8 @@
mdp4_mddi_overlay_restore();
#endif
- mdp_histogram_ctrl(TRUE);
+ mdp_histogram_ctrl_all(TRUE);
+
return ret;
}
@@ -1882,8 +2239,9 @@
mfd->ov0_blt_state = 0;
mfd->use_ov0_blt = 0 ;
- /* initialize Post Processing data*/
+ /* initialize Post Processing data*/
mdp_hist_lut_init();
+ mdp_histogram_init();
/* add panel data */
if (platform_device_add_data
@@ -1932,6 +2290,8 @@
mfd->dma = &dma2_data;
mfd->lut_update = mdp_lut_update_nonlcdc;
mfd->do_histogram = mdp_do_histogram;
+ mfd->start_histogram = mdp_histogram_start;
+ mfd->stop_histogram = mdp_histogram_stop;
} else {
mfd->dma_fnc = mdp_dma_s_update;
mfd->dma = &dma_s_data;
@@ -1978,6 +2338,8 @@
mfd->dma_fnc = mdp4_dsi_video_overlay;
mfd->lut_update = mdp_lut_update_lcdc;
mfd->do_histogram = mdp_do_histogram;
+ mfd->start_histogram = mdp_histogram_start;
+ mfd->stop_histogram = mdp_histogram_stop;
if (mfd->panel_info.pdest == DISPLAY_1) {
if_no = PRIMARY_INTF_SEL;
mfd->dma = &dma2_data;
@@ -1992,6 +2354,8 @@
mfd->hw_refresh = TRUE;
mfd->dma_fnc = mdp_dsi_video_update;
mfd->do_histogram = mdp_do_histogram;
+ mfd->start_histogram = mdp_histogram_start;
+ mfd->stop_histogram = mdp_histogram_stop;
if (mfd->panel_info.pdest == DISPLAY_1)
mfd->dma = &dma2_data;
else {
@@ -2021,6 +2385,8 @@
}
mfd->lut_update = mdp_lut_update_nonlcdc;
mfd->do_histogram = mdp_do_histogram;
+ mfd->start_histogram = mdp_histogram_start;
+ mfd->stop_histogram = mdp_histogram_stop;
mdp4_display_intf_sel(if_no, DSI_CMD_INTF);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
@@ -2032,6 +2398,8 @@
#else
mfd->dma_fnc = mdp_dma2_update;
mfd->do_histogram = mdp_do_histogram;
+ mfd->start_histogram = mdp_histogram_start;
+ mfd->stop_histogram = mdp_histogram_stop;
if (mfd->panel_info.pdest == DISPLAY_1)
mfd->dma = &dma2_data;
else {
@@ -2071,6 +2439,8 @@
#ifndef CONFIG_FB_MSM_MDP22
mfd->lut_update = mdp_lut_update_lcdc;
mfd->do_histogram = mdp_do_histogram;
+ mfd->start_histogram = mdp_histogram_start;
+ mfd->stop_histogram = mdp_histogram_stop;
#endif
#ifdef CONFIG_FB_MSM_OVERLAY
mfd->dma_fnc = mdp4_lcdc_overlay;
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index cf3a26a..6224dba 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -45,8 +45,6 @@
extern struct mdp_csc_cfg mdp_csc_convert[4];
extern struct workqueue_struct *mdp_hist_wq;
-extern struct work_struct mdp_histogram_worker;
-extern boolean mdp_is_hist_valid;
#define MDP4_REVISION_V1 0
#define MDP4_REVISION_V2 1
@@ -240,6 +238,32 @@
int bank_sel;
};
+struct mdp_hist_mgmt {
+ uint32_t block;
+ uint32_t irq_term;
+ uint32_t base;
+ struct completion mdp_hist_comp;
+ struct mutex mdp_hist_mutex;
+ struct mutex mdp_do_hist_mutex;
+ boolean mdp_is_hist_start, mdp_is_hist_data;
+ boolean mdp_is_hist_valid, mdp_is_hist_init;
+ uint8_t frame_cnt, bit_mask, num_bins;
+ struct work_struct mdp_histogram_worker;
+ struct mdp_histogram_data *hist;
+ uint32_t *c0, *c1, *c2;
+ uint32_t *extra_info;
+};
+
+enum {
+ MDP_HIST_MGMT_DMA_P = 0,
+ MDP_HIST_MGMT_DMA_S,
+ MDP_HIST_MGMT_VG_1,
+ MDP_HIST_MGMT_VG_2,
+ MDP_HIST_MGMT_MAX,
+};
+
+extern struct mdp_hist_mgmt *mdp_hist_mgmt_array[];
+
#define MDP_CMD_DEBUG_ACCESS_BASE (MDP_BASE+0x10000)
#define MDP_DMA2_TERM 0x1
@@ -251,8 +275,11 @@
#define MDP_OVERLAY0_TERM 0x20
#define MDP_OVERLAY1_TERM 0x40
#endif
-#define MDP_HISTOGRAM_TERM 0x80
-#define MDP_OVERLAY2_TERM 0x100
+#define MDP_OVERLAY2_TERM 0x80
+#define MDP_HISTOGRAM_TERM_DMA_P 0x100
+#define MDP_HISTOGRAM_TERM_DMA_S 0x200
+#define MDP_HISTOGRAM_TERM_VG_1 0x400
+#define MDP_HISTOGRAM_TERM_VG_2 0x800
#define ACTIVE_START_X_EN BIT(31)
#define ACTIVE_START_Y_EN BIT(31)
@@ -607,6 +634,10 @@
#define MDDI_VDO_PACKET_DESC 0x5666 /* 18 bits */
#define MDDI_VDO_PACKET_DESC_24 0x5888
+#define MDP_HIST_INTR_STATUS_OFF (0x0014)
+#define MDP_HIST_INTR_CLEAR_OFF (0x0018)
+#define MDP_HIST_INTR_ENABLE_OFF (0x001C)
+
#ifdef CONFIG_FB_MSM_MDP40
#define MDP_INTR_ENABLE (msm_mdp_base + 0x0050)
#define MDP_INTR_STATUS (msm_mdp_base + 0x0054)
@@ -618,6 +649,7 @@
#define MDP_DMA_P_HIST_INTR_STATUS (msm_mdp_base + 0x95014)
#define MDP_DMA_P_HIST_INTR_CLEAR (msm_mdp_base + 0x95018)
#define MDP_DMA_P_HIST_INTR_ENABLE (msm_mdp_base + 0x9501C)
+
#else
#define MDP_INTR_ENABLE (msm_mdp_base + 0x0020)
#define MDP_INTR_STATUS (msm_mdp_base + 0x0024)
@@ -761,11 +793,14 @@
#endif
void mdp_dma_s_update(struct msm_fb_data_type *mfd);
-int mdp_start_histogram(struct fb_info *info);
-int mdp_stop_histogram(struct fb_info *info);
-int mdp_histogram_ctrl(boolean en);
-void __mdp_histogram_kickoff(void);
-void __mdp_histogram_reset(void);
+int mdp_histogram_start(struct mdp_histogram_start_req *req);
+int mdp_histogram_stop(struct fb_info *info, uint32_t block);
+int mdp_histogram_ctrl(boolean en, uint32_t block);
+int mdp_histogram_ctrl_all(boolean en);
+int mdp_histogram_block2mgmt(uint32_t block, struct mdp_hist_mgmt **mgmt);
+void mdp_histogram_handle_isr(struct mdp_hist_mgmt *mgmt);
+void __mdp_histogram_kickoff(struct mdp_hist_mgmt *mgmt);
+void __mdp_histogram_reset(struct mdp_hist_mgmt *mgmt);
void mdp_footswitch_ctrl(boolean on);
#ifdef CONFIG_FB_MSM_MDP303
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 9c047e5..562c0c8 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -127,13 +127,20 @@
#define INTR_EXTERNAL_INTF_UDERRUN BIT(10)
#define INTR_PRIMARY_READ_PTR BIT(11)
#define INTR_DMA_P_HISTOGRAM BIT(17)
+#define INTR_DMA_S_HISTOGRAM BIT(26)
#define INTR_OVERLAY2_DONE BIT(30)
#ifdef CONFIG_FB_MSM_OVERLAY
-#define MDP4_ANY_INTR_MASK (INTR_DMA_P_HISTOGRAM)
+#define MDP4_ANY_INTR_MASK (INTR_DMA_P_HISTOGRAM | \
+ INTR_DMA_S_HISTOGRAM | \
+ INTR_VG1_HISTOGRAM | \
+ INTR_VG2_HISTOGRAM)
#else
#define MDP4_ANY_INTR_MASK (INTR_DMA_P_DONE| \
- INTR_DMA_P_HISTOGRAM)
+ INTR_DMA_P_HISTOGRAM | \
+ INTR_DMA_S_HISTOGRAM | \
+ INTR_VG1_HISTOGRAM | \
+ INTR_VG2_HISTOGRAM)
#endif
enum {
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index f06f380..d120071 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -274,7 +274,8 @@
MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x30, dsi_hsync_skew);
MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x38, ctrl_polarity);
mdp4_overlay_reg_flush(pipe, 1);
- mdp_histogram_ctrl(TRUE);
+
+ mdp_histogram_ctrl_all(TRUE);
ret = panel_next_on(pdev);
if (ret == 0) {
@@ -300,7 +301,7 @@
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
- mdp_histogram_ctrl(FALSE);
+ mdp_histogram_ctrl_all(FALSE);
ret = panel_next_off(pdev);
/* dis-engage rgb0 from mixer0 */
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index ed4553d..3f90380 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -247,7 +247,7 @@
#ifdef CONFIG_MSM_BUS_SCALING
mdp_bus_scale_update_request(2);
#endif
- mdp_histogram_ctrl(TRUE);
+ mdp_histogram_ctrl_all(TRUE);
ret = panel_next_on(pdev);
/* MDP cmd block disable */
@@ -273,7 +273,7 @@
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
- mdp_histogram_ctrl(FALSE);
+ mdp_histogram_ctrl_all(FALSE);
ret = panel_next_off(pdev);
mutex_unlock(&mfd->dma->ov_mutex);
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index a197c90..3aa848c 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -358,6 +358,9 @@
{
uint32 isr, mask, panel;
struct mdp_dma_data *dma;
+ struct mdp_hist_mgmt *mgmt = NULL;
+ char *base_addr;
+ int i, ret;
mdp_is_in_isr = TRUE;
@@ -379,10 +382,17 @@
/* When underun occurs mdp clear the histogram registers
that are set before in hw_init so restore them back so
that histogram works.*/
- MDP_OUTP(MDP_BASE + 0x95010, 1);
- outpdw(MDP_BASE + 0x9501c, INTR_HIST_DONE);
- mdp_is_hist_valid = FALSE;
- __mdp_histogram_reset();
+ for (i = 0; i < MDP_HIST_MGMT_MAX; i++) {
+ mgmt = mdp_hist_mgmt_array[i];
+ if (!mgmt)
+ continue;
+ base_addr = MDP_BASE + mgmt->base;
+ MDP_OUTP(base_addr + 0x010, 1);
+ outpdw(base_addr + 0x01c, INTR_HIST_DONE |
+ INTR_HIST_RESET_SEQ_DONE);
+ mgmt->mdp_is_hist_valid = FALSE;
+ __mdp_histogram_reset(mgmt);
+ }
}
if (isr & INTR_EXTERNAL_INTF_UDERRUN)
@@ -556,24 +566,27 @@
}
if (isr & INTR_DMA_P_HISTOGRAM) {
mdp4_stat.intr_histogram++;
- isr = inpdw(MDP_DMA_P_HIST_INTR_STATUS);
- mask = inpdw(MDP_DMA_P_HIST_INTR_ENABLE);
- outpdw(MDP_DMA_P_HIST_INTR_CLEAR, isr);
- mb();
- isr &= mask;
- if (isr & INTR_HIST_RESET_SEQ_DONE)
- __mdp_histogram_kickoff();
-
- if (isr & INTR_HIST_DONE) {
- if (waitqueue_active(&mdp_hist_comp.wait)) {
- if (!queue_work(mdp_hist_wq,
- &mdp_histogram_worker)) {
- pr_err("%s - can't queue hist_read\n",
- __func__);
- }
- } else
- __mdp_histogram_reset();
- }
+ ret = mdp_histogram_block2mgmt(MDP_BLOCK_DMA_P, &mgmt);
+ if (!ret)
+ mdp_histogram_handle_isr(mgmt);
+ }
+ if (isr & INTR_DMA_S_HISTOGRAM) {
+ mdp4_stat.intr_histogram++;
+ ret = mdp_histogram_block2mgmt(MDP_BLOCK_DMA_S, &mgmt);
+ if (!ret)
+ mdp_histogram_handle_isr(mgmt);
+ }
+ if (isr & INTR_VG1_HISTOGRAM) {
+ mdp4_stat.intr_histogram++;
+ ret = mdp_histogram_block2mgmt(MDP_BLOCK_VG_1, &mgmt);
+ if (!ret)
+ mdp_histogram_handle_isr(mgmt);
+ }
+ if (isr & INTR_VG2_HISTOGRAM) {
+ mdp4_stat.intr_histogram++;
+ ret = mdp_histogram_block2mgmt(MDP_BLOCK_VG_2, &mgmt);
+ if (!ret)
+ mdp_histogram_handle_isr(mgmt);
}
out:
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 74f7ead..76653ec 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -2962,7 +2962,6 @@
DEFINE_SEMAPHORE(msm_fb_ioctl_ppp_sem);
DEFINE_MUTEX(msm_fb_ioctl_lut_sem);
-DEFINE_MUTEX(msm_fb_ioctl_hist_sem);
/* Set color conversion matrix from user space */
@@ -3088,7 +3087,9 @@
void __user *argp = (void __user *)arg;
struct fb_cursor cursor;
struct fb_cmap cmap;
- struct mdp_histogram hist;
+ struct mdp_histogram_data hist;
+ struct mdp_histogram_start_req hist_req;
+ uint32_t block;
#ifndef CONFIG_FB_MSM_MDP40
struct mdp_ccs ccs_matrix;
#else
@@ -3309,24 +3310,32 @@
if (ret)
return ret;
- mutex_lock(&msm_fb_ioctl_hist_sem);
ret = mfd->do_histogram(info, &hist);
- mutex_unlock(&msm_fb_ioctl_hist_sem);
break;
case MSMFB_HISTOGRAM_START:
if (!mfd->panel_power_on)
return -EPERM;
- if (!mfd->do_histogram)
+ if (!mfd->start_histogram)
return -ENODEV;
- ret = mdp_start_histogram(info);
+
+ ret = copy_from_user(&hist_req, argp, sizeof(hist_req));
+ if (ret)
+ return ret;
+
+ ret = mfd->start_histogram(&hist_req);
break;
case MSMFB_HISTOGRAM_STOP:
- if (!mfd->do_histogram)
+ if (!mfd->stop_histogram)
return -ENODEV;
- ret = mdp_stop_histogram(info);
+
+ ret = copy_from_user(&block, argp, sizeof(int));
+ if (ret)
+ return ret;
+
+ ret = mfd->stop_histogram(info, block);
break;
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index 44d5018..3becc46 100644
--- a/drivers/video/msm/msm_fb.h
+++ b/drivers/video/msm/msm_fb.h
@@ -131,7 +131,9 @@
int (*lut_update) (struct fb_info *info,
struct fb_cmap *cmap);
int (*do_histogram) (struct fb_info *info,
- struct mdp_histogram *hist);
+ struct mdp_histogram_data *hist);
+ int (*start_histogram) (struct mdp_histogram_start_req *req);
+ int (*stop_histogram) (struct fb_info *info, uint32_t block);
void *cursor_buf;
void *cursor_buf_phys;
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index aa54b71..e57df1a 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -352,7 +352,7 @@
uint32_t *c0;
uint32_t *c1;
uint32_t *c2;
- uint32_t extra_info[2];
+ uint32_t *extra_info;
};
struct mdp_pcc_coeff {