static int _should_insert_wait_frame_done_token(void) { /***trigger operation: VDO+CMDQ CMD+CMDQ VDO+CPU CMD+CPU *** 7.flush cmdq: Y Y N N */ if(ext_disp_cmdq_enabled()) { if(ext_disp_is_video_mode()) { return 1; } else { return 1; } } else { if(ext_disp_is_video_mode()) { return 0; } else { return 0; } } }
static int _should_flush_cmdq_config_handle(void) { /***trigger operation: VDO+CMDQ CMD+CMDQ VDO+CPU CMD+CPU *** 7.flush cmdq: Y Y N N ***/ if(ext_disp_cmdq_enabled()) { if(ext_disp_is_video_mode()) { return 1; } else { return 1; } } else { if(ext_disp_is_video_mode()) { return 0; } else { return 0; } } }
static int _should_reset_cmdq_config_handle(void) { if(ext_disp_cmdq_enabled()) { if(ext_disp_is_video_mode()) { return 1; } else { return 1; } } else { if(ext_disp_is_video_mode()) { return 0; } else { return 0; } } }
static int _should_set_cmdq_dirty(void) { /***trigger operation: VDO+CMDQ CMD+CMDQ VDO+CPU CMD+CPU *** 6.set cmdq dirty: N Y N N ***/ if(ext_disp_cmdq_enabled()) { if(ext_disp_is_video_mode()) { return 0; } else { return 1; } } else { if(ext_disp_is_video_mode()) { return 0; } else { return 0; } } }
static int _should_trigger_path(void) { /***trigger operation: VDO+CMDQ CMD+CMDQ VDO+CPU CMD+CPU *** 4.path trigger: idle->Y Y idle->Y Y *** 5.mutex enable: N N idle->Y Y ***/ // this is not a perfect design, we can't decide path trigger(ovl/rdma/dsi..) seperately with mutex enable // but it's lucky because path trigger and mutex enable is the same w/o cmdq, and it's correct w/ CMDQ(Y+N). if(ext_disp_cmdq_enabled()) { if(ext_disp_is_video_mode()) { return dpmgr_path_is_idle(pgc->dpmgr_handle); } else { return 0; } } else { if(ext_disp_is_video_mode()) { return dpmgr_path_is_idle(pgc->dpmgr_handle); } else { return 1; } } }
static int _should_start_path(void) { /***trigger operation: VDO+CMDQ CMD+CMDQ VDO+CPU CMD+CPU *** 3.path start: idle->Y Y idle->Y Y ***/ if(ext_disp_cmdq_enabled()) { if(ext_disp_is_video_mode()) { return dpmgr_path_is_idle(pgc->dpmgr_handle); } else { return 1; } } else { if(ext_disp_is_video_mode()) { return dpmgr_path_is_idle(pgc->dpmgr_handle); } else { return 1; } } }
static int _should_update_lcm(void) { /***trigger operation: VDO+CMDQ CMD+CMDQ VDO+CPU CMD+CPU *** 2.lcm update: N Y N Y **/ if(ext_disp_cmdq_enabled()) { if(ext_disp_is_video_mode()) { return 0; } else { // TODO: lcm_update can't use cmdq now return 0; } } else { if(ext_disp_is_video_mode()) { return 0; } else { return 1; } } }
static int _should_wait_path_idle(void) { /***trigger operation: VDO+CMDQ CMD+CMDQ VDO+CPU CMD+CPU *** 1.wait idle: N N Y Y */ if(ext_disp_cmdq_enabled()) { if(ext_disp_is_video_mode()) { return 0; } else { return 0; } } else { if(ext_disp_is_video_mode()) { return dpmgr_path_is_busy(pgc->dpmgr_handle); } else { return dpmgr_path_is_busy(pgc->dpmgr_handle); } } }
static void _cmdq_set_config_handle_dirty(void) { if(!ext_disp_is_video_mode()) { // only command mode need to set dirty cmdqRecSetEventToken(pgc->cmdq_handle_config, CMDQ_SYNC_TOKEN_CONFIG_DIRTY); ///dprec_event_op(DPREC_EVENT_CMDQ_SET_DIRTY); } }
/* trigger operation: VDO+CMDQ CMD+CMDQ VDO+CPU CMD+CPU * 6. set cmdq dirty: N Y N N */ static int _should_set_cmdq_dirty(void) { if(ext_disp_cmdq_enabled() && (ext_disp_is_video_mode() == 0)) { return 1; } else { return 0; } }
/* trigger operation: VDO+CMDQ CMD+CMDQ VDO+CPU CMD+CPU * 3.path start: idle->Y Y idle->Y Y */ static int _should_start_path(void) { if(ext_disp_is_video_mode()) { return dpmgr_path_is_idle(pgc->dpmgr_handle); } else { return 1; } }
/* trigger operation: VDO+CMDQ CMD+CMDQ VDO+CPU CMD+CPU * 2.lcm update: N Y N Y */ static int _should_update_lcm(void) { if(ext_disp_cmdq_enabled() || ext_disp_is_video_mode()) { return 0; } else { return 1; } }
static void _cmdq_insert_wait_frame_done_token(void) { if(ext_disp_is_video_mode()) { cmdqRecWaitNoClear(pgc->cmdq_handle_config, dpmgr_path_get_mutex(pgc->dpmgr_handle) + CMDQ_EVENT_MUTEX0_STREAM_EOF); ///CMDQ_EVENT_MUTEX1_STREAM_EOF dpmgr_path_get_mutex() } else { cmdqRecWaitNoClear(pgc->cmdq_handle_config, CMDQ_SYNC_TOKEN_STREAM_EOF); } ///dprec_event_op(DPREC_EVENT_CMDQ_WAIT_STREAM_EOF); }
static void _cmdq_start_trigger_loop(void) { int ret = 0; // this should be called only once because trigger loop will nevet stop ret = cmdqRecStartLoop(pgc->cmdq_handle_trigger); if(!ext_disp_is_video_mode()) { // need to set STREAM_EOF for the first time, otherwise we will stuck in dead loop cmdqCoreSetEvent(CMDQ_SYNC_TOKEN_STREAM_EOF); ///dprec_event_op(DPREC_EVENT_CMDQ_SET_EVENT_ALLOW); } EXT_DISP_LOG("START cmdq trigger loop finished\n"); }
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; }
static void _cmdq_build_trigger_loop(void) { int ret = 0; cmdqRecCreate(CMDQ_SCENARIO_TRIGGER_LOOP, &(pgc->cmdq_handle_trigger)); EXT_DISP_LOG("ext_disp path trigger thread cmd handle=%p\n", pgc->cmdq_handle_trigger); cmdqRecReset(pgc->cmdq_handle_trigger); if(ext_disp_is_video_mode()) { // wait and clear stream_done, HW will assert mutex enable automatically in frame done reset. // todo: should let dpmanager to decide wait which mutex's eof. ret = cmdqRecWait(pgc->cmdq_handle_trigger, dpmgr_path_get_mutex(pgc->dpmgr_handle) + CMDQ_EVENT_MUTEX0_STREAM_EOF); ///dpmgr_path_get_mutex(pgc->dpmgr_handle) // for some module(like COLOR) to read hw register to GPR after frame done dpmgr_path_build_cmdq(pgc->dpmgr_handle, pgc->cmdq_handle_trigger,CMDQ_AFTER_STREAM_EOF); } else { // DSI command mode doesn't have mutex_stream_eof, need use CMDQ token instead ret = cmdqRecWait(pgc->cmdq_handle_trigger, CMDQ_SYNC_TOKEN_CONFIG_DIRTY); //ret = cmdqRecWait(pgc->cmdq_handle_trigger, CMDQ_EVENT_MDP_DSI0_TE_SOF); // for operations before frame transfer, such as waiting for DSI TE dpmgr_path_build_cmdq(pgc->dpmgr_handle, pgc->cmdq_handle_trigger,CMDQ_BEFORE_STREAM_SOF); // cleat frame done token, now the config thread will not allowed to config registers. // remember that config thread's priority is higher than trigger thread, so all the config queued before will be applied then STREAM_EOF token be cleared // this is what CMDQ did as "Merge" ret = cmdqRecClearEventToken(pgc->cmdq_handle_trigger, CMDQ_SYNC_TOKEN_STREAM_EOF); // enable mutex, only cmd mode need this // this is what CMDQ did as "Trigger" dpmgr_path_trigger(pgc->dpmgr_handle, pgc->cmdq_handle_trigger, CMDQ_ENABLE); //ret = cmdqRecWrite(pgc->cmdq_handle_trigger, (unsigned int)(DISP_REG_CONFIG_MUTEX_EN(0))&0x1fffffff, 1, ~0); // waiting for frame done, because we can't use mutex stream eof here, so need to let dpmanager help to decide which event to wait // most time we wait rdmax frame done event. ret = cmdqRecWait(pgc->cmdq_handle_trigger, CMDQ_EVENT_DISP_RDMA1_EOF); dpmgr_path_build_cmdq(pgc->dpmgr_handle, pgc->cmdq_handle_trigger,CMDQ_WAIT_STREAM_EOF_EVENT); // dsi is not idle rightly after rdma frame done, so we need to polling about 1us for dsi returns to idle // do not polling dsi idle directly which will decrease CMDQ performance dpmgr_path_build_cmdq(pgc->dpmgr_handle, pgc->cmdq_handle_trigger,CMDQ_CHECK_IDLE_AFTER_STREAM_EOF); // for some module(like COLOR) to read hw register to GPR after frame done dpmgr_path_build_cmdq(pgc->dpmgr_handle, pgc->cmdq_handle_trigger,CMDQ_AFTER_STREAM_EOF); // polling DSI idle //ret = cmdqRecPoll(pgc->cmdq_handle_trigger, 0x1401b00c, 0, 0x80000000); // polling wdma frame done //ret = cmdqRecPoll(pgc->cmdq_handle_trigger, 0x140060A0, 1, 0x1); // now frame done, config thread is allowed to config register now ret = cmdqRecSetEventToken(pgc->cmdq_handle_trigger, CMDQ_SYNC_TOKEN_STREAM_EOF); // RUN forever!!!! BUG_ON(ret < 0); } // dump trigger loop instructions to check whether dpmgr_path_build_cmdq works correctly cmdqRecDumpCommand(pgc->cmdq_handle_trigger); EXT_DISP_LOG("ext display BUILD cmdq trigger loop finished\n"); return; }