Samsung VZW MB1 update
/drivers/video/msm/mdp.c
blob:37ab015374dfb4c2f2c3c195359ec86dada8c00e -> blob:a1b608c72fd4eaad5be9e9b3f8d3b0cb5cbf036d
--- drivers/video/msm/mdp.c
+++ drivers/video/msm/mdp.c
@@ -94,6 +94,7 @@ struct workqueue_struct *mdp_dma_wq; /*m
struct workqueue_struct *mdp_vsync_wq; /*mdp vsync wq */
struct workqueue_struct *mdp_hist_wq; /*mdp histogram wq */
+bool mdp_pp_initialized = FALSE;
static struct workqueue_struct *mdp_pipe_ctrl_wq; /* mdp mdp pipe ctrl wq */
static struct delayed_work mdp_pipe_ctrl_worker;
@@ -225,10 +226,28 @@ static void mdp_hist_lut_init_mgmt(struc
mutex_unlock(&mdp_hist_lut_list_mutex);
}
-static int mdp_hist_lut_init(void)
+static int mdp_hist_lut_destroy(void)
{
struct mdp_hist_lut_mgmt *temp;
struct list_head *pos, *q;
+
+ mutex_lock(&mdp_hist_lut_list_mutex);
+ list_for_each_safe(pos, q, &mdp_hist_lut_list) {
+ temp = list_entry(pos, struct mdp_hist_lut_mgmt, list);
+ list_del(pos);
+ kfree(temp);
+ }
+ mutex_unlock(&mdp_hist_lut_list_mutex);
+ return 0;
+}
+
+static int mdp_hist_lut_init(void)
+{
+ struct mdp_hist_lut_mgmt *temp;
+
+ if (mdp_pp_initialized)
+ return -EEXIST;
+
INIT_LIST_HEAD(&mdp_hist_lut_list);
if (mdp_rev >= MDP_REV_30) {
@@ -259,13 +278,7 @@ static int mdp_hist_lut_init(void)
return 0;
exit_list:
- mutex_lock(&mdp_hist_lut_list_mutex);
- list_for_each_safe(pos, q, &mdp_hist_lut_list) {
- temp = list_entry(pos, struct mdp_hist_lut_mgmt, list);
- list_del(pos);
- kfree(temp);
- }
- mutex_unlock(&mdp_hist_lut_list_mutex);
+ mdp_hist_lut_destroy();
exit:
pr_err("Failed initializing histogram LUT memory\n");
return -ENOMEM;
@@ -666,6 +679,7 @@ static int mdp_hist_init_mgmt(struct mdp
goto error_extra;
INIT_WORK(&mgmt->mdp_histogram_worker, mdp_hist_read_work);
+ mgmt->hist = NULL;
mdp_hist_mgmt_array[index] = mgmt;
return 0;
@@ -688,11 +702,32 @@ static void mdp_hist_del_mgmt(struct mdp
kfree(mgmt->c0);
}
+static int mdp_histogram_destroy(void)
+{
+ struct mdp_hist_mgmt *temp;
+ int i;
+
+ 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;
+ }
+ return 0;
+}
+
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);
+
+ if (mdp_pp_initialized)
+ return -EEXIST;
+
+ mdp_hist_wq = alloc_workqueue("mdp_hist_wq",
+ WQ_NON_REENTRANT | WQ_UNBOUND, 0);
for (i = 0; i < MDP_HIST_MGMT_MAX; i++)
mdp_hist_mgmt_array[i] = NULL;
@@ -736,14 +771,7 @@ static int mdp_histogram_init(void)
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;
- }
+ mdp_histogram_destroy();
exit:
return -ENOMEM;
}
@@ -826,7 +854,11 @@ static int mdp_histogram_disable(struct
MDP_OUTP(base + 0x0018, INTR_HIST_DONE | INTR_HIST_RESET_SEQ_DONE);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
- complete(&mgmt->mdp_hist_comp);
+ if (mgmt->hist != NULL) {
+ mgmt->hist = NULL;
+ complete(&mgmt->mdp_hist_comp);
+ }
+
mdp_disable_irq(mgmt->irq_term);
return 0;
}
@@ -893,6 +925,7 @@ int mdp_histogram_start(struct mdp_histo
goto error;
}
+ mutex_lock(&mgmt->mdp_do_hist_mutex);
mutex_lock(&mgmt->mdp_hist_mutex);
if (mgmt->mdp_is_hist_start == TRUE) {
pr_err("%s histogram already started\n", __func__);
@@ -911,6 +944,7 @@ int mdp_histogram_start(struct mdp_histo
error_lock:
mutex_unlock(&mgmt->mdp_hist_mutex);
+ mutex_unlock(&mgmt->mdp_do_hist_mutex);
error:
return ret;
}
@@ -927,6 +961,7 @@ int mdp_histogram_stop(struct fb_info *i
goto error;
}
+ mutex_lock(&mgmt->mdp_do_hist_mutex);
mutex_lock(&mgmt->mdp_hist_mutex);
if (mgmt->mdp_is_hist_start == FALSE) {
pr_err("%s histogram already stopped\n", __func__);
@@ -938,7 +973,10 @@ int mdp_histogram_stop(struct fb_info *i
if (!mfd->panel_power_on) {
mgmt->mdp_is_hist_data = FALSE;
- complete(&mgmt->mdp_hist_comp);
+ if (mgmt->hist != NULL) {
+ mgmt->hist = NULL;
+ complete(&mgmt->mdp_hist_comp);
+ }
ret = -EINVAL;
goto error_lock;
}
@@ -947,10 +985,12 @@ int mdp_histogram_stop(struct fb_info *i
mutex_unlock(&mgmt->mdp_hist_mutex);
cancel_work_sync(&mgmt->mdp_histogram_worker);
+ mutex_unlock(&mgmt->mdp_do_hist_mutex);
return ret;
error_lock:
mutex_unlock(&mgmt->mdp_hist_mutex);
+ mutex_unlock(&mgmt->mdp_do_hist_mutex);
error:
return ret;
}
@@ -1072,25 +1112,39 @@ static void mdp_hist_read_work(struct wo
goto error;
}
- 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);
+ if (mgmt->hist == NULL) {
+ if ((mgmt->mdp_is_hist_init == TRUE) &&
+ ((!completion_done(&mgmt->mdp_hist_comp)) &&
+ waitqueue_active(&mgmt->mdp_hist_comp.wait)))
+ pr_err("mgmt->hist invalid NULL\n");
ret = -EINVAL;
- goto error;
}
- /* if read was triggered by an underrun, don't wake up readers*/
- if (mgmt->mdp_is_hist_valid && mgmt->mdp_is_hist_init) {
+ if (!ret) {
+ 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;
+ }
+ }
+ /*
+ * if read was triggered by an underrun or failed copying,
+ * don't wake up readers
+ */
+ if (!ret && mgmt->mdp_is_hist_valid && mgmt->mdp_is_hist_init) {
mgmt->hist = NULL;
- complete(&mgmt->mdp_hist_comp);
+ if (waitqueue_active(&mgmt->mdp_hist_comp.wait))
+ complete(&mgmt->mdp_hist_comp);
}
if (mgmt->mdp_is_hist_valid == FALSE)
@@ -1143,11 +1197,13 @@ err:
return ret;
}
+#define MDP_HISTOGRAM_TIMEOUT_MS 84 /*5 Frames*/
static int mdp_do_histogram(struct fb_info *info,
struct mdp_histogram_data *hist)
{
struct mdp_hist_mgmt *mgmt = NULL;
int ret = 0;
+ unsigned long timeout = (MDP_HISTOGRAM_TIMEOUT_MS * HZ) / 1000;
ret = mdp_histogram_block2mgmt(hist->block, &mgmt);
if (ret) {
@@ -1184,12 +1240,26 @@ static int mdp_do_histogram(struct fb_in
goto error_lock;
}
+ if (mgmt->hist != NULL) {
+ pr_err("%s; histogram attempted to be read twice\n", __func__);
+ ret = -EPERM;
+ goto error_lock;
+ }
+ INIT_COMPLETION(mgmt->mdp_hist_comp);
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;
+ ret = wait_for_completion_killable_timeout(&mgmt->mdp_hist_comp,
+ timeout);
+ if (ret <= 0) {
+ if (!ret) {
+ mgmt->hist = NULL;
+ ret = -ETIMEDOUT;
+ pr_debug("%s: bin collection timedout", __func__);
+ } else {
+ mgmt->hist = NULL;
+ pr_debug("%s: bin collection interrupted", __func__);
+ }
goto error;
}
@@ -1686,15 +1756,7 @@ void mdp_histogram_handle_isr(struct mdp
__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);
- }
+ queue_work(mdp_hist_wq, &mgmt->mdp_histogram_worker);
}
}
@@ -1868,7 +1930,6 @@ static void mdp_drv_init(void)
#endif
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");
mdp_pipe_ctrl_wq = create_singlethread_workqueue("mdp_pipe_ctrl_wq");
INIT_DELAYED_WORK(&mdp_pipe_ctrl_worker,
mdp_pipe_ctrl_workqueue_handler);
@@ -2008,6 +2069,8 @@ static int mdp_off(struct platform_devic
mfd->panel.type == LCDC_PANEL ||
mfd->panel.type == LVDS_PANEL)
mdp4_lcdc_off(pdev);
+ else if (mfd->panel.type == MDDI_PANEL)
+ mdp4_mddi_off(pdev);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
ret = panel_next_off(pdev);
@@ -2020,6 +2083,18 @@ static int mdp_off(struct platform_devic
return ret;
}
+#ifdef CONFIG_FB_MSM_MDP303
+unsigned is_mdp4_hw_reset(void)
+{
+ return 0;
+}
+void mdp4_hw_init(void)
+{
+ /* empty */
+}
+
+#endif
+
static int mdp_on(struct platform_device *pdev)
{
int ret = 0;
@@ -2028,24 +2103,29 @@ static int mdp_on(struct platform_device
pr_debug("%s:+\n", __func__);
-#ifdef CONFIG_FB_MSM_MDP40
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- mdp_clk_ctrl(1);
- mdp4_hw_init();
- outpdw(MDP_BASE + 0x0038, mdp4_display_intf);
- if (mfd->panel.type == MIPI_CMD_PANEL) {
- mdp_vsync_cfg_regs(mfd, FALSE);
- mdp4_dsi_cmd_on(pdev);
- } else if (mfd->panel.type == MIPI_VIDEO_PANEL)
- mdp4_dsi_video_on(pdev);
- else if (mfd->panel.type == HDMI_PANEL ||
- mfd->panel.type == LCDC_PANEL ||
- mfd->panel.type == LVDS_PANEL)
- mdp4_lcdc_on(pdev);
+ if (mdp_rev >= MDP_REV_40) {
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ mdp_clk_ctrl(1);
+ mdp4_hw_init();
+ outpdw(MDP_BASE + 0x0038, mdp4_display_intf);
+ if (mfd->panel.type == MIPI_CMD_PANEL) {
+ mdp_vsync_cfg_regs(mfd, FALSE);
+ mdp4_dsi_cmd_on(pdev);
+ } else if (mfd->panel.type == MIPI_VIDEO_PANEL) {
+ mdp4_dsi_video_on(pdev);
+ } else if (mfd->panel.type == HDMI_PANEL ||
+ mfd->panel.type == LCDC_PANEL ||
+ mfd->panel.type == LVDS_PANEL) {
+ mdp4_lcdc_on(pdev);
+ } else if (mfd->panel.type == MDDI_PANEL) {
+ mdp_vsync_cfg_regs(mfd, FALSE);
+ mdp4_mddi_on(pdev);
+ }
+
+ mdp_clk_ctrl(0);
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ }
- mdp_clk_ctrl(0);
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-#endif
if ((mdp_rev == MDP_REV_303) &&
(mfd->panel.type == MIPI_CMD_PANEL))
@@ -2353,6 +2433,7 @@ static int mdp_probe(struct platform_dev
/* initialize Post Processing data*/
mdp_hist_lut_init();
mdp_histogram_init();
+ mdp_pp_initialized = TRUE;
/* add panel data */
if (platform_device_add_data
@@ -2388,6 +2469,9 @@ static int mdp_probe(struct platform_dev
mdp_vsync_resync_workqueue_handler);
mfd->hw_refresh = FALSE;
+ if(mfd->panel.type == MDDI_PANEL)
+ mdp4_mddi_rdptr_init(0);
+
if (mfd->panel.type == EXT_MDDI_PANEL) {
/* 15 fps -> 66 msec */
mfd->refresh_timer_duration = (66 * HZ / 1000);
@@ -2476,6 +2560,7 @@ static int mdp_probe(struct platform_dev
else {
printk(KERN_ERR "Invalid Selection of destination panel\n");
rc = -ENODEV;
+ mdp_clk_ctrl(0);
goto mdp_probe_err;
}
@@ -2518,6 +2603,7 @@ static int mdp_probe(struct platform_dev
else {
printk(KERN_ERR "Invalid Selection of destination panel\n");
rc = -ENODEV;
+ mdp_clk_ctrl(0);
goto mdp_probe_err;
}
INIT_WORK(&mfd->dma_update_worker,
@@ -2610,6 +2696,7 @@ static int mdp_probe(struct platform_dev
pr_err("%s: writeback panel not supprted\n",
__func__);
platform_device_put(msm_fb_dev);
+ mdp_clk_ctrl(0);
return -ENODEV;
}
pdata->on = mdp4_overlay_writeback_on;
@@ -2777,6 +2864,12 @@ static int mdp_remove(struct platform_de
{
if (footswitch != NULL)
regulator_put(footswitch);
+
+ /*free post processing memory*/
+ mdp_histogram_destroy();
+ mdp_hist_lut_destroy();
+ mdp_pp_initialized = FALSE;
+
iounmap(msm_mdp_base);
pm_runtime_disable(&pdev->dev);
#ifdef CONFIG_MSM_BUS_SCALING