转载自http://blog.csdn.net/robinyeung/article/details/9189837
INIT_WORK(&mgmt->mdp_histogram_worker, mdp_hist_read_work); // work queue
case MIPI_VIDEO_PANEL: // register callback function mipi = &mfd->panel_info.mipi; mfd->vsync_init = mdp4_dsi_vsync_init; mfd->vsync_show = mdp4_dsi_video_show_event; mfd->hw_refresh = TRUE; 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; } else { if_no = EXTERNAL_INTF_SEL; mfd->dma = &dma_e_data; } mdp4_display_intf_sel(if_no, DSI_VIDEO_INTF); if (mdp_rev >= MDP_REV_40) mfd->cursor_update = mdp_hw_cursor_sync_update; else mfd->cursor_update = mdp_hw_cursor_update; break;
static int mdp_on(struct platform_device *pdev) { int ret = 0; struct msm_fb_data_type *mfd; mfd = platform_get_drvdata(pdev); pr_debug("%s:+\n", __func__); if (!(mfd->cont_splash_done)) { if (mfd->panel.type == MIPI_VIDEO_PANEL) mdp4_dsi_video_splash_done(); /* Clks are enabled in probe. Disabling clocks now */ mdp_clk_ctrl(0); mfd->cont_splash_done = 1; } mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); ret = panel_next_on(pdev); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); if (mdp_rev >= MDP_REV_40) { mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); mdp_clk_ctrl(1); mdp_bus_scale_restore_request(); 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); } mdp_clk_ctrl(0); mdp4_overlay_reset(); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); } if (mdp_rev == MDP_REV_303 && mfd->panel.type == MIPI_CMD_PANEL) { vsync_cntrl.dev = mfd->fbi->dev; atomic_set(&vsync_cntrl.suspend, 1); } mdp_histogram_ctrl_all(TRUE); if (ret == 0) ret = panel_next_late_init(pdev); pr_debug("%s:-\n", __func__); return ret; }
static int mdp_off(struct platform_device *pdev) { int ret = 0; struct msm_fb_data_type *mfd = platform_get_drvdata(pdev); pr_debug("%s:+\n", __func__); mdp_histogram_ctrl_all(FALSE); atomic_set(&vsync_cntrl.suspend, 1); atomic_set(&vsync_cntrl.vsync_resume, 0); complete_all(&vsync_cntrl.vsync_wait); mdp_clk_ctrl(1); ret = panel_next_early_off(pdev); if (mfd->panel.type == MIPI_CMD_PANEL) mdp4_dsi_cmd_off(pdev); else if (mfd->panel.type == MIPI_VIDEO_PANEL) mdp4_dsi_video_off(pdev); else if (mfd->panel.type == HDMI_PANEL || mfd->panel.type == LCDC_PANEL || mfd->panel.type == LVDS_PANEL) mdp4_lcdc_off(pdev); else if (mfd->panel.type == WRITEBACK_PANEL) mdp4_overlay_writeback_off(pdev); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); ret = panel_next_off(pdev); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); mdp_clk_ctrl(0); #ifdef CONFIG_MSM_BUS_SCALING mdp_bus_scale_update_request(0, 0); #endif pr_debug("%s:-\n", __func__); return ret; }
#define MDP_HISTOGRAM_TIMEOUT_MS 84 /*5 Frames*/ static int mdp_do_histogram(struct fb_info *info, struct mdp_histogram_data *hist) { // ...... unsigned long timeout = (MDP_HISTOGRAM_TIMEOUT_MS * HZ) / 1000; ret = wait_for_completion_killable_timeout(&mgmt->mdp_hist_comp, timeout); // ...... }
2. ioctl interface (msm_fb.c): qualcomm setting call the interface to enable or disable CABL
case MSMFB_SET_LUT: ret = copy_from_user(&cmap, argp, sizeof(cmap)); if (ret) return ret; mutex_lock(&msm_fb_ioctl_lut_sem); ret = msm_fb_set_lut(&cmap, info); mutex_unlock(&msm_fb_ioctl_lut_sem); break; case MSMFB_HISTOGRAM: if (!mfd->panel_power_on) return -EPERM; if (!mfd->do_histogram) return -ENODEV; ret = copy_from_user(&hist, argp, sizeof(hist)); if (ret) return ret; ret = mfd->do_histogram(info, &hist); break; case MSMFB_HISTOGRAM_START: if (!mfd->panel_power_on) return -EPERM; if (!mfd->start_histogram) return -ENODEV; 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->stop_histogram) return -ENODEV; ret = copy_from_user(&block, argp, sizeof(int)); if (ret) return ret; ret = mfd->stop_histogram(info, block); break;
3. interrupt handler (call queue_work, then the function mdp_hist_read_work will work to read histogram)
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); else if (isr & INTR_HIST_DONE) queue_work(mdp_hist_wq, &mgmt->mdp_histogram_worker); }
if (isr & INTR_DMA_P_HISTOGRAM) { mdp4_stat.intr_histogram++; 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); }
After the histogram data is transferred to the CABL core block, the histogram data is analyzed and a new backlight level is generated that is lower than the original backlight level. To compensate(['kɒmpenseɪt] 补偿) for the lowered backlight level, the CABL core block generates a CABL LUT for tone reproduction which makes the image brighter than the original input image. The new backlight level is passed to the backlight controller, while the CABL LUT values are sent to the hardware registers. A new image is generated using the CABL LUT and is sent to the LCD panel. Concurrently, the backlight controller sets the display backlight to its new level. When the new image generated by the CABL LUT is displayed on the LCD panel, the new backlight level (which is darker than the original level) is applied so that the final output image appears normal.
Refer to 80-NA308-1