int ext_disp_trigger(int blocking, void *callback, unsigned int userdata)
{
	int ret = 0;
	EXT_DISP_FUNC();
	
	if((is_hdmi_active() == false)|| pgc->state == EXTD_DEINIT || pgc->state == EXTD_SUSPEND || pgc->need_trigger_overlay < 1)
	{
		EXT_DISP_LOG("trigger ext display is already sleeped\n");
		MMProfileLogEx(ddp_mmp_get_events()->Extd_ErrorInfo, MMProfileFlagPulse, Trigger, 0);
		return -1;
	}
	
	_ext_disp_path_lock();

	if(_should_trigger_interface())
	{	
		_trigger_display_interface(blocking, callback, userdata);
	}
	else
	{
		_trigger_overlay_engine();
	}

	pgc->state = EXTD_RESUME;
	_ext_disp_path_unlock();
	EXT_DISP_LOG("ext_disp_trigger done \n");

	return ret;
}
int ext_disp_deinit(char *lcm_name)
{
	EXT_DISP_FUNC();    
        
	_ext_disp_path_lock();

	if(pgc->state == EXTD_DEINIT)
	{
		goto deinit_exit;
	}
        
	dpmgr_path_deinit(pgc->dpmgr_handle, CMDQ_DISABLE);
	dpmgr_destroy_path(pgc->dpmgr_handle, NULL);

	cmdqRecDestroy(pgc->cmdq_handle_config);
	cmdqRecDestroy(pgc->cmdq_handle_trigger);    

	pgc->state = EXTD_DEINIT;

deinit_exit:    
	_ext_disp_path_unlock();
	is_context_inited = 0;
	EXT_DISP_LOG("ext_disp_deinit done \n" );
	return 0;
}
int ext_disp_deinit(char *lcm_name)
{
    DISPFUNC();    
        
    _ext_disp_path_lock();

    if(pgc->state == EXTD_DEINIT)
        goto deinit_exit;
        
    dpmgr_path_deinit(pgc->dpmgr_handle, CMDQ_DISABLE);
    dpmgr_destroy_path(pgc->dpmgr_handle,NULL);

    cmdqRecDestroy(pgc->cmdq_handle_config);
    cmdqRecDestroy(pgc->cmdq_handle_trigger);    

    pgc->state = EXTD_DEINIT;


deinit_exit:    
    _ext_disp_path_unlock();
    is_context_inited = 0;
    
    hdmi_smb_kpd_disable();
    
    DISPMSG("ext_disp_deinit done \n" );
    
}
int ext_disp_suspend(void)
{
	EXT_DISP_STATUS ret = EXT_DISP_STATUS_OK;

	DISPFUNC();
	    
	_ext_disp_path_lock();
	
	if(pgc->state == EXTD_DEINIT || pgc->state == EXTD_SUSPEND)
	{
		DISPERR("EXTD_DEINIT or EXTD_SUSPEND\n");
		goto done;
	}

    pgc->need_trigger_overlay = 0;
    
	if(dpmgr_path_is_busy(pgc->dpmgr_handle))
	{
	    dpmgr_wait_event_timeout(pgc->dpmgr_handle, DISP_PATH_EVENT_FRAME_DONE, HZ/30);
	}
	    
    if(ext_disp_use_cmdq == CMDQ_ENABLE)
        _cmdq_stop_trigger_loop();

    dpmgr_path_stop(pgc->dpmgr_handle, CMDQ_DISABLE);
//ALPS01857347+
    dpmgr_path_power_off(pgc->dpmgr_handle, CMDQ_DISABLE);
//-
    if(dpmgr_path_is_busy(pgc->dpmgr_handle))
    {
        dpmgr_wait_event_timeout(pgc->dpmgr_handle, DISP_PATH_EVENT_FRAME_DONE, HZ/30);

    }

    ///if(dpmgr_path_is_busy(pgc->dpmgr_handle))
    dpmgr_path_reset(pgc->dpmgr_handle, CMDQ_DISABLE);

    #if 0///(dpmgr_path_is_busy2(pgc->dpmgr_handle))
	{		   
        dpmgr_path_reset(pgc->dpmgr_handle, CMDQ_DISABLE);
        dpmgr_check_status(pgc->dpmgr_handle);	    
    }
    #endif
    
	extd_drv_suspend(pgc->plcm);
	///dpmgr_path_power_off(pgc->dpmgr_handle, CMDQ_DISABLE);

	pgc->state = EXTD_SUSPEND;
	
	
done:
	_ext_disp_path_unlock();
	
	DISPMSG("ext_disp_suspend done \n");
	return ret;
}
// register rdma done event
int ext_disp_wait_for_idle(void)
{	
	EXT_DISP_STATUS ret = EXT_DISP_STATUS_OK;

	EXT_DISP_FUNC();
	_ext_disp_path_lock();
	
	_ext_disp_path_unlock();
	return ret;
}
int ext_disp_switch_cmdq_cpu(CMDQ_SWITCH use_cmdq)
{
	_ext_disp_path_lock();

	ext_disp_use_cmdq = use_cmdq;
	EXT_DISP_LOG("display driver use %s to config register now\n", (use_cmdq==CMDQ_ENABLE)?"CMDQ":"CPU");

	_ext_disp_path_unlock();
	return ext_disp_use_cmdq;
}
int ext_disp_is_sleepd(void)
{
	unsigned int temp = 0;
	//EXT_DISP_FUNC();
	_ext_disp_path_lock();
	temp = !pgc->state;
	_ext_disp_path_unlock();
	
	return temp;
}
int ext_disp_is_alive(void)
{
	unsigned int temp = 0;
	EXT_DISP_FUNC();
	_ext_disp_path_lock();
	temp = pgc->state;
	_ext_disp_path_unlock();
	
	return temp;
}
int ext_disp_suspend(void)
{
	EXT_DISP_STATUS ret = EXT_DISP_STATUS_OK;

	EXT_DISP_FUNC();
	    
	_ext_disp_path_lock();
	
	if(pgc->state == EXTD_DEINIT || pgc->state == EXTD_SUSPEND)
	{
		EXT_DISP_ERR("status is not EXTD_RESUME\n");
		goto done;
	}

	pgc->need_trigger_overlay = 0;
    
	if(dpmgr_path_is_busy(pgc->dpmgr_handle))
	{
		dpmgr_wait_event_timeout(pgc->dpmgr_handle, DISP_PATH_EVENT_FRAME_DONE, HZ/30);
	}
	    
	if(ext_disp_use_cmdq == CMDQ_ENABLE)
	{
		_cmdq_stop_trigger_loop();
	}

	dpmgr_path_stop(pgc->dpmgr_handle, CMDQ_DISABLE);
	dpmgr_path_power_off(pgc->dpmgr_handle, CMDQ_DISABLE);
	if(dpmgr_path_is_busy(pgc->dpmgr_handle))
	{
		dpmgr_wait_event_timeout(pgc->dpmgr_handle, DISP_PATH_EVENT_FRAME_DONE, HZ/30);
	}

	dpmgr_path_reset(pgc->dpmgr_handle, CMDQ_DISABLE);
	extd_drv_suspend(pgc->plcm);

	pgc->state = EXTD_SUSPEND;
	
done:
	_ext_disp_path_unlock();
	
	EXT_DISP_LOG("ext_disp_suspend done \n");
	return ret;
}
int ext_disp_resume(void)
{
	EXT_DISP_STATUS ret = EXT_DISP_STATUS_OK;

	EXT_DISP_FUNC();

	_ext_disp_path_lock();
	
	if(pgc->state != EXTD_SUSPEND)
	{
		EXT_DISP_ERR("EXTD_DEINIT/EXTD_INIT/EXTD_RESUME \n");
		goto done;
	}

	if(_should_reset_cmdq_config_handle())
	{
		_cmdq_reset_config_handle();
	}
	
	dpmgr_path_power_on(pgc->dpmgr_handle, CMDQ_DISABLE);

	extd_drv_resume(pgc->plcm);

	if(ext_disp_use_cmdq == CMDQ_ENABLE)
	{
		_cmdq_start_trigger_loop();
	}

	if(dpmgr_path_is_busy(pgc->dpmgr_handle))
	{
		EXT_DISP_LOG("stop display path failed, still busy\n");
		ret = -1;
		goto done;
	}

	pgc->state = EXTD_RESUME;
	
done:
	_ext_disp_path_unlock();
	EXT_DISP_LOG("ext_disp_resume done \n");
	return ret;
}
int ext_disp_resume(void)
{
	EXT_DISP_STATUS ret = EXT_DISP_STATUS_OK;
        
	_ext_disp_path_lock();
	
	if(pgc->state < EXTD_INIT)
	{
		DISPERR("EXTD_DEINIT \n");
		goto done;
	}
	
	dpmgr_path_power_on(pgc->dpmgr_handle, CMDQ_DISABLE);

	extd_drv_resume(pgc->plcm);

	///dpmgr_path_start(pgc->dpmgr_handle, CMDQ_DISABLE);

     if(ext_disp_use_cmdq == CMDQ_ENABLE)
    	_cmdq_start_trigger_loop();


	if(dpmgr_path_is_busy(pgc->dpmgr_handle))
	{
		DISPCHECK("stop display path failed, still busy\n");
		ret = -1;
		goto done;
	}

	pgc->state = EXTD_RESUME;
	
done:
	_ext_disp_path_unlock();
	DISPMSG("ext_disp_resume done \n");
	return ret;
}
int ext_disp_init(char *lcm_name, unsigned int session)
{
	EXT_DISP_FUNC();
	EXT_DISP_STATUS ret = EXT_DISP_STATUS_OK;
	//DISP_MODULE_ENUM dst_module = 0;
	
	LCM_PARAMS *lcm_param = NULL;
	//LCM_INTERFACE_ID lcm_id = LCM_INTERFACE_NOTDEFINED;

	dpmgr_init();

	extd_mutex_init(&(pgc->lock));
	_ext_disp_path_lock();

	pgc->plcm = extd_drv_probe( lcm_name, LCM_INTERFACE_NOTDEFINED);
	if(pgc->plcm == NULL)
	{
		EXT_DISP_LOG("disp_lcm_probe returns null\n");
		ret = EXT_DISP_STATUS_ERROR;
		//goto done;  //Donglei
	}

	lcm_param = extd_drv_get_params(pgc->plcm);
	if(lcm_param == NULL)
	{
		EXT_DISP_ERR("get lcm params FAILED\n");
		ret = EXT_DISP_STATUS_ERROR;
		goto done;
	}

#if 0
	ret = cmdqCoreRegisterCB(CMDQ_GROUP_DISP, cmdqDdpClockOn, cmdqDdpDumpInfo, cmdqDdpResetEng, cmdqDdpClockOff);
	if(ret)
	{
		EXT_DISP_ERR("cmdqCoreRegisterCB failed, ret=%d \n", ret);
		ret = EXT_DISP_STATUS_ERROR;
		goto done;
	}					 
#endif	
	ret = cmdqRecCreate(CMDQ_SCENARIO_MHL_DISP, &(pgc->cmdq_handle_config));
	if(ret)
	{
		EXT_DISP_LOG("cmdqRecCreate FAIL, ret=%d \n", ret);
		ret = EXT_DISP_STATUS_ERROR;
		goto done;
	}
	else
	{
		EXT_DISP_LOG("cmdqRecCreate SUCCESS, g_cmdq_handle=%p \n", pgc->cmdq_handle_config);
	}

	if(ext_disp_mode == EXTD_DIRECT_LINK_MODE)
	{
		_build_path_direct_link();
//		EXT_DISP_LOG("ext_disp display is DIRECT LINK MODE\n");
	}
	else if(ext_disp_mode == EXTD_DECOUPLE_MODE)
	{
		_build_path_decouple();
//		EXT_DISP_LOG("ext_disp display is DECOUPLE MODE\n");
	}
	else if(ext_disp_mode == EXTD_SINGLE_LAYER_MODE)
	{
		_build_path_single_layer();
//		EXT_DISP_LOG("ext_disp display is SINGLE LAYER MODE\n");
	}
	else if(ext_disp_mode == EXTD_RDMA_DPI_MODE)
	{
		_build_path_rdma_dpi();
//		EXT_DISP_LOG("ext_disp display is RDMA to dpi MODE\n");
	}
	else
	{
		EXT_DISP_LOG("ext_disp display mode is WRONG\n");
	}

	if(ext_disp_use_cmdq == CMDQ_ENABLE)
	{
		_cmdq_build_trigger_loop();
		EXT_DISP_LOG("ext_disp display BUILD cmdq trigger loop finished\n");
    	
		_cmdq_start_trigger_loop();
	}

	pgc->session = session;
	
	EXT_DISP_LOG("ext_disp display START cmdq trigger loop finished\n");
	
	dpmgr_path_set_video_mode(pgc->dpmgr_handle, ext_disp_is_video_mode());

	dpmgr_path_init(pgc->dpmgr_handle, CMDQ_DISABLE);
    
	disp_ddp_path_config *data_config = (disp_ddp_path_config *)vmalloc(sizeof(disp_ddp_path_config));	
	if(data_config)
	{
		memset((void*)data_config, 0, sizeof(disp_ddp_path_config));
		memcpy(&(data_config->dispif_config), &(extd_dpi_params.dispif_config), sizeof(LCM_PARAMS));

		data_config->dst_w = lcm_param->width;
		data_config->dst_h = lcm_param->height;
		data_config->dst_dirty = 1;
        init_roi = 0;	
		ret = dpmgr_path_config(pgc->dpmgr_handle, data_config, CMDQ_DISABLE);
	}
	else
	{
		EXT_DISP_LOG("allocate buffer failed!!!\n");
	}
	
	if(!extd_drv_is_inited(pgc->plcm))
	{
		ret = extd_drv_init(pgc->plcm);
	}

	// this will be set to always enable cmdq later 
	if(ext_disp_is_video_mode())
	{
			dpmgr_map_event_to_irq(pgc->dpmgr_handle, DISP_PATH_EVENT_IF_VSYNC, DDP_IRQ_RDMA1_DONE);

	}
	
	if(ext_disp_use_cmdq == CMDQ_ENABLE)
	{
		_cmdq_reset_config_handle();
		//_cmdq_insert_wait_frame_done_token(); //Fixed me: why insert EOF event before the first frame start
	}

	dpmgr_path_power_on(pgc->dpmgr_handle, CMDQ_DISABLE);
	
	pgc->state = EXTD_INIT;

done:

	_ext_disp_path_unlock();
    dpmgr_path_stop(pgc->dpmgr_handle, CMDQ_DISABLE);
            
	EXT_DISP_LOG("ext_disp_init done \n");
	return ret;
}
int ext_disp_config_input_multiple(ext_disp_input_config* input, int idx)
{
	int ret = 0;
	int i=0;
	int layer =0;
	///EXT_DISP_FUNC();
	
	disp_ddp_path_config *data_config;	

	if((is_hdmi_active() == false) || (pgc->state != EXTD_INIT && pgc->state != EXTD_RESUME) )
	{
		EXT_DISP_LOG("[Donglei]config ext disp is already sleeped, hdmi_active:%d, state:%d\n", is_hdmi_active(), pgc->state);	
		MMProfileLogEx(ddp_mmp_get_events()->Extd_ErrorInfo, MMProfileFlagPulse, Config, idx );
		return -2;
	}

    _ext_disp_path_lock();

	// all dirty should be cleared in dpmgr_path_get_last_config()
	data_config = dpmgr_path_get_last_config(pgc->dpmgr_handle);
    
	// hope we can use only 1 input struct for input config, just set layer number
	if(_should_config_ovl_input())
	{
		for(i = 0;i<HW_OVERLAY_COUNT;i++)
		{	
			if(input[i].dirty)
			{	
				ret = _convert_disp_input_to_ovl(&(data_config->ovl_config[input[i].layer]), &input[i]);
				dprec_mmp_dump_ovl_layer(&(data_config->ovl_config[input[i].layer]), input[i].layer, 2);
			}

			if (init_roi == 1)
			{
				LCM_PARAMS *lcm_param = extd_drv_get_params(pgc->plcm);
				memcpy(&(data_config->dispif_config), &(extd_dpi_params.dispif_config), sizeof(LCM_PARAMS));
				
				if(lcm_param != NULL)
				{
					EXT_DISP_LOG("set dest w:%d, h:%d\n", lcm_param->width, lcm_param->height);
					data_config->dst_w = lcm_param->width;
					data_config->dst_h = lcm_param->height;
				}
				
				data_config->dst_dirty = 1;
				data_config->rdma_config.address = 0;
			}
			data_config->ovl_dirty = 1;	
		}
	}
	else
	{
		OVL_CONFIG_STRUCT  ovl_config;
		_convert_disp_input_to_ovl(&ovl_config, input);
		dprec_mmp_dump_ovl_layer(&ovl_config, input->layer, 2);

		ret = _convert_disp_input_to_rdma(&(data_config->rdma_config), input);
		if (data_config->rdma_config.address)
		{
			data_config->rdma_dirty = 1;
		}
	}

	if(_should_wait_path_idle())
	{
		dpmgr_wait_event_timeout(pgc->dpmgr_handle, DISP_PATH_EVENT_FRAME_DONE, HZ/2);
	}

	memcpy(&(data_config->dispif_config), &(extd_dpi_params.dispif_config), sizeof(LCM_PARAMS));
	ret = dpmgr_path_config(pgc->dpmgr_handle, data_config, ext_disp_cmdq_enabled()? pgc->cmdq_handle_config : NULL);

	// this is used for decouple mode, to indicate whether we need to trigger ovl
	pgc->need_trigger_overlay = 1;
	init_roi = 0;

	_ext_disp_path_unlock();
	if (data_config->ovl_dirty)
	{
		EXT_DISP_LOG("config_input_multiple idx:%d -w:%d, h:%d, pitch:%d\n", idx ,data_config->ovl_config[0].src_w, data_config->ovl_config[0].src_h, data_config->ovl_config[0].src_pitch);	
	}else{
		EXT_DISP_LOG("config_input_multiple idx:%d -w:%d, h:%d, pitch:%d, mva:%p\n", idx ,data_config->rdma_config.width, data_config->rdma_config.height, data_config->rdma_config.pitch, data_config->rdma_config.address);
	}
		
	return ret;
}
int ext_disp_config_input(ext_disp_input_config* input)
{
	int ret = 0;
	int i=0;
	int layer =0;
	///EXT_DISP_FUNC();
	
	disp_ddp_path_config *data_config;	
	
	if((is_hdmi_active() == false)|| ext_disp_is_sleepd())
	{
		EXT_DISP_LOG("ext disp is already sleeped\n");		
		return 0;
	}

	_ext_disp_path_lock();
	data_config = dpmgr_path_get_last_config(pgc->dpmgr_handle);
	
	if(input->layer_en)
	{
		if(input->vaddr)
		{
			///_debug_pattern(0x00000000, input->vaddr, input->dst_w, input->dst_h, input->src_pitch, 0x00000000, input->layer, input->buff_idx);
		}	
		else
		{
			///_debug_pattern(input->addr,0x00000000,  input->dst_w, input->dst_h, input->src_pitch, 0x00000000, input->layer, input->buff_idx);
		}
	}

#ifdef EXTD_DBG_USE_INNER_BUF
    if(input->fmt == eYUY2)    
    {
        ///input->layer_en = 1;
        ///memset(input, 0, sizeof(ext_disp_input_config));
        input->layer_en = 1;
        input->addr = hdmi_mva_r ;
        input->vaddr = hdmi_va ;
        input->fmt = eRGB888;   ///eRGBA8888  eYUY2
        input->src_w = 1280;
        input->src_h = 720;
        input->src_x = 0;
        input->src_y = 0;
        input->src_pitch = 1280*3;        
        input->dst_w = 1280;
        input->dst_h = 720;
        input->dst_x = 0;
        input->dst_y = 0;
        input->aen = 0;
        input->alpha = 0xff;
    }
#endif


	// hope we can use only 1 input struct for input config, just set layer number
	if(_should_config_ovl_input())
	{
		ret = _convert_disp_input_to_ovl(&(data_config->ovl_config[input->layer]), input);
		data_config->ovl_dirty = 1;
	}
	else
	{
		ret = _convert_disp_input_to_rdma(&(data_config->rdma_config), input);
		data_config->rdma_dirty= 1;
	}

	///EXT_DISP_ERR("ext_disp_config_input cmdq %d wi %d ovl %d vm %d\n", ext_disp_cmdq_enabled(), _should_wait_path_idle(), _should_config_ovl_input(), ext_disp_is_video_mode());
	if(_should_wait_path_idle())
	{
		dpmgr_wait_event_timeout(pgc->dpmgr_handle, DISP_PATH_EVENT_FRAME_DONE, HZ/2);
	}

	memcpy(&(data_config->dispif_config), &(extd_dpi_params.dispif_config), sizeof(LCM_PARAMS));
	ret = dpmgr_path_config(pgc->dpmgr_handle, data_config, ext_disp_cmdq_enabled()? pgc->cmdq_handle_config : NULL);

	// this is used for decouple mode, to indicate whether we need to trigger ovl
	pgc->need_trigger_overlay = 1;
    ///EXT_DISP_LOG("ext_disp_config_input done \n");

	_ext_disp_path_unlock();
	
	return ret;
}
int ext_disp_config_input_multiple(ext_disp_input_config* input, int idx)
{
	int ret = 0;
	int i=0;
	int layer =0;
	///DISPFUNC();
	
	disp_ddp_path_config *data_config;	

	if((is_hdmi_active() == false) || (pgc->state != EXTD_RESUME) )
	{
		DISPMSG("config ext disp is already sleeped\n");	
		MMProfileLogEx(ddp_mmp_get_events()->Extd_ErrorInfo, MMProfileFlagPulse, Config, idx );
		return 0;
	}

    _ext_disp_path_lock();

	// all dirty should be cleared in dpmgr_path_get_last_config()
	data_config = dpmgr_path_get_last_config(pgc->dpmgr_handle);
	data_config->dst_dirty = 0;
	data_config->ovl_dirty = 0;
	data_config->rdma_dirty = 0;
	data_config->wdma_dirty = 0;

    
	// hope we can use only 1 input struct for input config, just set layer number
	if(_should_config_ovl_input())
	{
		for(i = 0;i<HW_OVERLAY_COUNT;i++)
		{	///dprec_logger_start(DPREC_LOGGER_PRIMARY_CONFIG, input->layer|(input->layer_en<<16), input->addr);


			if(input[i].dirty)
			{
				dprec_mmp_dump_ovl_layer(&(data_config->ovl_config[input[i].layer]), input[i].layer, 2);
				ret = _convert_disp_input_to_ovl(&(data_config->ovl_config[input[i].layer]), &input[i]);
			}
/*
			else
			{
                data_config->ovl_config[input[i].layer].layer_en = input[i].layer_en;
                data_config->ovl_config[input[i].layer].layer = input[i].layer;
			}
*/
			data_config->ovl_dirty = 1;	

			
			///dprec_logger_done(DPREC_LOGGER_PRIMARY_CONFIG, input->src_x, input->src_y);

		}
	}
	else
	{
		ret = _convert_disp_input_to_rdma(&(data_config->rdma_config), input);
		data_config->rdma_dirty= 1;
	}

	if(_should_wait_path_idle())
	{
		dpmgr_wait_event_timeout(pgc->dpmgr_handle, DISP_PATH_EVENT_FRAME_DONE, HZ/2);
	}

	memcpy(&(data_config->dispif_config), &(extd_dpi_params.dispif_config), sizeof(LCM_PARAMS));
	ret = dpmgr_path_config(pgc->dpmgr_handle, data_config, ext_disp_cmdq_enabled()? pgc->cmdq_handle_config : NULL);

	// this is used for decouple mode, to indicate whether we need to trigger ovl
	pgc->need_trigger_overlay = 1;

	_ext_disp_path_unlock();
	DISPMSG("config_input_multiple idx %x -w %d, h %d\n", idx ,data_config->ovl_config[0].src_w, data_config->ovl_config[0].src_h);	
	return ret;
}