34. lcm ESD

本文介绍了MTK平台LCM静电防护(ESD)的客制化方法,包括通过读取寄存器和外部TE方式实现ESD检查。详细分析了代码流程,涉及LCM驱动的`lcm_get_params`函数,以及`primary_display_esd_check_worker_kthread`线程的工作原理,解释了如何进行ESD检查、恢复和重试机制。
摘要由CSDN通过智能技术生成
MTK 平台LCM ESD客制化及代码分析和案例
参考文档:
[FAQ14251]如何配置LCM ESD Check——读寄存器方式
https://onlinesso.mediatek.com/FAQ/SW/FAQ14251
[FAQ14273]MT6735/MT6753/MT6580 ESD问题攻略——外部TE方式
https://onlinesso.mediatek.com/FAQ/SW/FAQ14273
[FAQ14880]LCM ESD Check 问题处理流程
https://onlinesso.mediatek.com/FAQ/SW/FAQ14880
[FAQ13728]MT6735通过读寄存器方式做ESD,客制化需求----多个返回值
https://onlinesso.mediatek.com/FAQ/SW/FAQ13728

一.LCM ESD客制化方法
alps/kernel-3.18/drivers/misc/mediatek/lcm/xxx/xxx.c
alps/vendor/mediatek/proprietary/bootable/bootloader/lk/dev/lcm/xxx/xxx.c
static void lcm_get_params(LCM_PARAMS *params)
{
……
		/* Esd Check方法1 : Read from lcm */
		params->dsi.esd_check_enable = 1; 
		params->dsi.customization_esd_check_enable = 1; 
		params->dsi.lcm_esd_check_table[0].cmd = 0x0A; //具体是哪个寄存器由FAE告知
		params->dsi.lcm_esd_check_table[0].count = 1; 
		params->dsi.lcm_esd_check_table[0].para_list[0] = 0x1C; //读取寄存器的正确值也由FAE告知,寄存器的值要配置正确,否则会不断地esd recovery
		
/* Esd Check方法2 : EXT TE */
		//params->dsi.esd_check_enable = 1; 
		//params->dsi.customization_esd_check_enable = 0; 
}

二.MT6580 LCM ESD check流程分析
alps/kernel-3.18/drivers/misc/mediatek/video/mt6580/videox/primary_display.c

int primary_display_init(char *lcm_name, unsigned int lcm_fps)
{
......
		primary_display_esd_check_task =
		    kthread_create(primary_display_esd_check_worker_kthread,
				   NULL, "display_esd_check");
......
//这里根据LCM中配置的params->dsi.esd_check_enable是否等于1来判断是否开启primary_display_esd_check_worker_kthread线程
		if (_need_do_esd_check())
			wake_up_process(primary_display_esd_check_task);
......
}

unsigned int _need_do_esd_check(void)
{
	int ret = 0;
#ifdef CONFIG_OF
	if ((pgc->plcm->params->dsi.esd_check_enable == 1)
	    && (islcmconnected == 1))
		ret = 1;
#else
	if (pgc->plcm->params->dsi.esd_check_enable == 1)
		ret = 1;
#endif
	return ret;
}

static int primary_display_esd_check_worker_kthread(void *data)
{
......
//定义esd recovery重试的次数
int esd_try_cnt = 5;
......
//这里每2秒扫描一次
		msleep(2000);	/* esd check and pull clock lane every 2s */
......
//执行esd check判断是否要进行esd recovery,关于primary_display_esd_check函数的分析在下面会讲到
		ret = primary_display_esd_check();
		if (ret == 1) {
			pr_debug("[ESD]esd check fail, will do esd recovery\n");
			i = esd_try_cnt;
			while (i--) {
				DISPCHECK("[ESD]esd recovery try:%d\n", i);
				//执行恢复动作,重新初始化显示屏参数,关于primary_display_esd_recovery函数的分析在下面有讲到
				primary_display_esd_recovery();
				//执行完恢复动作后,再次进行esd check,如果检测到的lcm寄存器的值正常,则不会再进行recovery的动作;否则会连续进行recovery和esd check,若在规定的5次内recovery均不成功,就会执行primary_display_esd_check_enable(0)关闭primary_display_esd_check_worker_kthread线程。
				ret = primary_display_esd_check();
				if (ret == 0) {
					pr_debug
					    ("[ESD]esd recovery success\n");
					break;
				}
				pr_debug("[ESD]after esd recovery, esd check still fail\n");
				if (i == 0) {
					DISPERR(
					"[ESD]after esd recovery %d times, esd check still fail, disable esd check\n",
					     esd_try_cnt);
					primary_display_esd_check_enable(0);
				}
			}
		}
......
}

/* ESD CHECK FUNCTION */
/* return 1: esd check fail */
/* return 0: esd check pass */
int primary_display_esd_check(void)
{
……
	/* Esd Check : EXT TE */
	//使用TE的方式进行esd check的时候,需要在lcm的驱动中定义esd_check_enable为1,customization_esd_check_enable为0,lcm的初始化参数也要匹配TE的,主控这边的TE GPIO口需要配置正确
	if (pgc->plcm->params->dsi.customization_esd_check_enable == 0) {
		MMProfileLogEx(ddp_mmp_get_events()->esd_extte,
			       MMProfileFlagStart, 0, 0);
		if (primary_display_is_video_mode()) {
			primary_display_switch_esd_mode(1);
			/* use cmdq to pull DSI clk lane*/
			if (primary_display_cmdq_enabled()) {
				_primary_path_lock(__func__);

				/* 0.create esd check cmdq */
				cmdqRecCreate(CMDQ_SCENARIO_DISP_ESD_CHECK, &(pgc->cmdq_handle_config_esd));
				_primary_path_unlock(__func__);

				/* 1.reset*/
				cmdqRecReset(pgc->cmdq_handle_config_esd);

				/* wait stream eof first */
				ret = cmdqRecWait(pgc->cmdq_handle_config_esd, CMDQ_EVENT_DISP_RDMA0_EOF);
				cmdqRecWait(pgc->cmdq_handle_config_esd, CMDQ_EVENT_MUTEX0_STREAM_EOF);

				_primary_path_lock(__func__);
				/* 2.stop dsi vdo mode */
				dpmgr_path_build_cmdq(pgc->dpmgr_handle,
							pgc->cmdq_handle_config_esd, CMDQ_STOP_VDO_MODE, 0);

				/* 3.pull DSI clock lane */
				DSI_sw_clk_trail_cmdq(0, pgc->cmdq_handle_config_esd);
				DSI_manual_enter_HS(pgc->cmdq_handle_config_esd);


				/* 4.start dsi vdo mode */
				dpmgr_path_build_cmdq(pgc->dpmgr_handle,
							pgc->cmdq_handle_config_esd, CMDQ_START_VDO_MODE, 0);

				/* 5. trigger path */
				cmdqRecClearEventToken(pgc->cmdq_handle_config_esd, CMDQ_EVENT_MUTEX0_STREAM_EOF);

				dpmgr_path_trigger(pgc->dpmgr_handle, pgc->cmdq_handle_config_esd, CMDQ_ENABLE);

				_primary_path_unlock(__func__);
				cmdqRecFlush(pgc->cmdq_handle_config_esd);

				cmdqRecDestroy(pgc->cmdq_handle_config_esd);
				pgc->cmdq_handle_config_esd = NULL;
			}
			if (_need_register_eint()) {
				MMProfileLogEx(ddp_mmp_get_events()->esd_extte,
					       MMProfileFlagPulse, 1, 1);

				if (wait_event_interruptible_timeout
				    (esd_ext_te_wq,
				     atomic_read(&esd_ext_te_event),
				     HZ / 2) > 0) {
					ret = 0;	/* esd check pass */
				} else {
					ret = 1;	/* esd check fail */
				}
				atomic_set(&esd_ext_te_event, 0);
			}
			primary_display_switch_esd_mode(0);
		} else {
			MMProfileLogEx(ddp_mmp_get_events()->esd_extte,
				       MMProfileFlagPulse, 0, 1);
			if (dpmgr_wait_event_timeout
			    (pgc->dpmgr_handle, DISP_PATH_EVENT_IF_VSYNC,
			     HZ / 2) > 0) {
				ret = 0;	/* esd check pass */
			} else {
				ret = 1;	/* esd check fail */
			}
		}
		MMProfileLogEx(ddp_mmp_get_events()->esd_extte,
			       MMProfileFlagEnd, 0, ret);
		/* _primary_path_unlock(__func__); */
		goto done;
	}
	/* / Esd Check : Read from lcm */
	//读LCM寄存器方式进行esd check和recovery
	MMProfileLogEx(ddp_mmp_get_events()->esd_rdlcm, MMProfileFlagStart, 0,
		       primary_display_cmdq_enabled());
	if (primary_display_cmdq_enabled()) {
		_primary_path_lock(__func__);
		MMProfileLogEx(ddp_mmp_get_events()->esd_rdlcm,
			       MMProfileFlagPulse, 0, 1);

		/* 0.create esd check cmdq */
		cmdqRecCreate(CMDQ_SCENARIO_DISP_ESD_CHECK,
			      &(pgc->cmdq_handle_config_esd));
		dpmgr_path_build_cmdq(pgc->dpmgr_handle,
				      pgc->cmdq_handle_config_esd,
				      CMDQ_ESD_ALLC_SLOT, 0);
		MMProfileLogEx(ddp_mmp_get_events()->esd_rdlcm,
			       MMProfileFlagPulse, 0, 2);
		DISPCHECK("[ESD]ESD config thread=%p\n", pgc->cmdq_handle_config_esd);
		_primary_path_unlock(__func__);

		/* 1.use cmdq to read from lcm */
		//发CMDQ_ESD_CHECK_READ的命令读取lcm的寄存器数据,_esd_check_config_handle_vdo函数在下面会讲到
		if (primary_display_is_video_mode())
			ret = _esd_check_config_handle_vdo();
		else
			ret = _esd_check_config_handle_cmd();

		MMProfileLogEx(ddp_mmp_get_events()->esd_rdlcm,
			       MMProfileFlagPulse,
			       primary_display_is_video_mode(), 3);
		if (ret == 1) {
			/* cmdq fail */
			if (_need_wait_esd_eof()) {
				/* Need set esd check eof synctoken to let trigger loop go. */
				cmdqCoreSetEvent(CMDQ_SYNC_TOKEN_ESD_EOF);
			}
			/* do dsi reset */
			dpmgr_path_build_cmdq(pgc->dpmgr_handle,
					      pgc->cmdq_handle_config_esd,
					      CMDQ_DSI_RESET, 0);
			goto destroy_cmdq;
		}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值