Qualcomm CABL(content adaptive backlight) driver

转载自http://blog.csdn.net/robinyeung/article/details/9189837

1. init  <--- mdp_probe  (mdp.c)
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;
when lcd on, first call mdp_on, then enable histogram at last
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;
}
when lcd off, first call mdp_off, then disable hisogram imediately
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;
}
mdp_do_histogram
#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);
}
mdp4_isr is the interrupt handler for mdp, including all kinds of status, such as histogram, vsync, overlay done, dma_p_done.
	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.

Qualcomm CABL(content adaptive backlight) driver_第1张图片

Refer to 80-NA308-1

你可能感兴趣的:(mdp4,CABL)