Qualcomm CABL(content adaptive backlight) driver

本文详细介绍了MIPIDSI面板初始化过程,包括工作队列注册、硬件配置、接口选择、时钟控制及历史记录功能的启用与禁用等关键步骤。同时,阐述了MIPIDSI面板在LCD打开与关闭时的操作流程,以及如何通过ioctl接口进行特定设置。文章还涉及中断处理机制和历史记录数据的读取与生成。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载自http://blog.youkuaiyun.com/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.


Refer to 80-NA308-1

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值