QCom MSM MDP4驱动显示过程

来源:互联网 发布:linux 文件后面带星号 编辑:程序博客网 时间:2024/04/30 06:05

记录了Qualcomm MSM8xxx MDP4上Overlay和Framebuffer显示过程,仅涉及驱动中部分,应用层参考Overlay HAL。

Overlay设置和提交过程

msmfb_overlay_set(struct fb_info *info, void __user *p)

è mdp4_overlay_set(struct fb_info *info, struct mdp_overlay *req)

申请pipe,并设置pipeclockbandwidth

int msmfb_overlay_play(struct fb_info *info, unsigned long *argp)

è int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req)

计算pipe输入缓冲地址、参数配置等;将request暂存,如对DSI CMD屏,是使用void mdp4_dsi_cmd_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe),而DSI VIDEO屏是使用void mdp4_dsi_video_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe)

base_pipe设置和提交,Layer Mix DMA

当送FBIOPUT_VSCREENINFOFBIOPAN_DISPLAY命令给FB设备时,最终会调用msm_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)

msm_fb_pan_display

è mdp_set_dma_pan_info(info, dirtyPtr, (var->activate == FB_ACTIVATE_VBL));   //设置DMA区域

è mdp_dma_pan_update(info);       //启动DMA,包括Layer Mixer合成和DMA输出

void mdp_dma_pan_update(struct fb_info *info)

è mfd->dma_fnc(mfd);

MIPI DSI CMD屏,该DMA函数是mdp4_dsi_cmd_overlay

void mdp4_dsi_cmd_overlay(struct msm_fb_data_type *mfd){……pipe = vctrl->base_pipe;……if (pipe->mixer_stage == MDP4_MIXER_STAGE_BASE) {    // it is certain for base_pipe                                  // it is setup in mdp4_overlay_update_dsi_cmd when dsi cmd panel is on.mdp4_mipi_vsync_enable(mfd, pipe, 0);mdp4_overlay_setup_pipe_addr(mfd, pipe);mdp4_dsi_cmd_pipe_queue(0, pipe);                   // arm the base pipe with framebuffer}mdp4_overlay_mdp_perf_upd(mfd, 1);                            // level up the mdp performancemutex_lock(&mfd->dma->ov_mutex);mdp4_dsi_cmd_pipe_commit(cndx, 0);                            // fire the overlay layer mixer and dmamdp4_overlay_mdp_perf_upd(mfd, 0);mutex_unlock(&mfd->dma->ov_mutex);}

其余相关代码引用并注释如下:

int mdp4_dsi_cmd_pipe_commit(int cndx, int wait){int  i, undx;int mixer = 0;struct vsycn_ctrl *vctrl;struct vsync_update *vp;struct mdp4_overlay_pipe *pipe;struct mdp4_overlay_pipe *real_pipe;unsigned long flags;int need_dmap_wait = 0;int need_ov_wait = 0;int cnt = 0;               /**                    *static struct vsycn_ctrl { … } vsync_ctrl_db [MAX_CONTROLLER]                   * 在不同的显示器文件中有不同的定义,注意其是static的。                   * 不同显示应用时关联不同的LayerMixer,所以同一种应用中,                   * 使用具有同一mixer_num的pipe,mixer_num由应用分配的主pipe即该应用对应的                   * vsync_ctrl_db的base_pipe指定。所有pipe的LayerMixer0是驱动中固定指定的。                    */vctrl = &vsync_ctrl_db[0];mutex_lock(&vctrl->update_lock);undx =  vctrl->update_ndx;vp = &vctrl->vlist[undx];pipe = vctrl->base_pipe;mixer = pipe->mixer_num;              // the Layer mixer used, LayerMixer0 here.if (vp->update_cnt == 0) {mutex_unlock(&vctrl->update_lock);return cnt;}//vctrl->update_ndx++;//vctrl->update_ndx &= 0x01;vp->update_cnt = 0;     /* reset */if (vctrl->blt_free) {vctrl->blt_free--;if (vctrl->blt_free == 0)mdp4_free_writeback_buf(vctrl->mfd, mixer);}mutex_unlock(&vctrl->update_lock);/* free previous committed iommu back to pool */mdp4_overlay_iommu_unmap_freelist(mixer);spin_lock_irqsave(&vctrl->spin_lock, flags);if (pipe->ov_blt_addr) {/* Blt */if (vctrl->blt_wait)need_dmap_wait = 1;if (vctrl->ov_koff != vctrl->ov_done) {INIT_COMPLETION(vctrl->ov_comp);need_ov_wait = 1;}} else {/* direct out */if (vctrl->dmap_koff != vctrl->dmap_done) {INIT_COMPLETION(vctrl->dmap_comp);pr_debug("%s: wait, ok=%d od=%d dk=%d dd=%d cpu=%d\n", __func__, vctrl->ov_koff, vctrl->ov_done,vctrl->dmap_koff, vctrl->dmap_done, smp_processor_id());need_dmap_wait = 1;}}spin_unlock_irqrestore(&vctrl->spin_lock, flags);         /* setup completion for dmap wait in DIRECTOUT mode or overlay wait in BLT mode */if (need_dmap_wait) {pr_debug("%s: wait4dmap\n", __func__);mdp4_dsi_cmd_wait4dmap(0);}if (need_ov_wait) {pr_debug("%s: wait4ov\n", __func__);mdp4_dsi_cmd_wait4ov(0);}if (pipe->ov_blt_addr) {if (vctrl->blt_end) {vctrl->blt_end = 0;pipe->ov_blt_addr = 0;pipe->dma_blt_addr =  0;pr_info("%s: reset ov_blt_addr and dma_blt_addr\n", __func__);}}/* if blt has some change, reconfig overlay proccessor and dmap*/if (vctrl->blt_change) {mdp4_overlayproc_cfg(pipe);mdp4_overlay_dmap_xy(pipe);vctrl->blt_change = 0;}pipe = vp->plist;               /*                * All pipes used here is targeted to LayerMixer0.                * These pipes are allocated with MIXER0 indeed,                * and queued in vctrl->vlist[undx].plist[pipe->pipe_ndx - 1] again.               * Obvious with target to MIXER0.               */for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {if (pipe->pipe_used) {                           /* pipes in vp->plist maybe point to same physical pipe */cnt++;real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx);if (real_pipe && real_pipe->pipe_used) {/* pipe not unset */mdp4_overlay_vsync_commit(pipe); }/* free previous iommu to freelist* which will be freed at next* pipe_commit*/mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0);pipe->pipe_used = 0; /* clear */}}/* tx dcs command if had any */mipi_dsi_cmdlist_commit(1);         /* mixer here is MIXER0. Setup mixer’s each stage with pipe */mdp4_mixer_stage_commit(mixer);pipe = vctrl->base_pipe;spin_lock_irqsave(&vctrl->spin_lock, flags);if (pipe->ov_blt_addr) {mdp4_dsi_cmd_blt_ov_update(pipe);pipe->ov_cnt++;vctrl->ov_koff++;INIT_COMPLETION(vctrl->ov_comp);vsync_irq_enable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM);} else {INIT_COMPLETION(vctrl->dmap_comp);vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM);vctrl->dmap_koff++;}pr_debug("%s: kickoff, pid=%d\n", __func__, current->pid);/* kickoff overlay engine */mdp4_stat.kickoff_ov0++;outpdw(MDP_BASE + 0x0004, 0);mb();spin_unlock_irqrestore(&vctrl->spin_lock, flags);mdp4_stat.overlay_commit[pipe->mixer_num]++;         /* wait for vsync */if (wait) {long long tick;mdp4_dsi_cmd_wait4vsync(cndx, &tick);}return cnt;}void mdp4_overlay_vsync_commit(struct mdp4_overlay_pipe *pipe){if (pipe->pipe_type == OVERLAY_TYPE_VIDEO)mdp4_overlay_vg_setup(pipe);/* video/graphic pipe */elsemdp4_overlay_rgb_setup(pipe);/* rgb pipe */pr_debug("%s: pipe=%x ndx=%d num=%d used=%d\n", __func__,(int) pipe, pipe->pipe_ndx, pipe->pipe_num, pipe->pipe_used);/* figure out the flush value to fill register */         mdp4_overlay_reg_flush(pipe, 1);         /* stage setup but not commit */mdp4_mixer_stage_up(pipe, 0);}void mdp4_mixer_stage_commit(int mixer){struct mdp4_overlay_pipe *pipe;int i, num;u32 data, stage;int off;unsigned long flags;data = 0;for (i = MDP4_MIXER_STAGE_BASE; i < MDP4_MIXER_STAGE_MAX; i++) {pipe = ctrl->stage[mixer][i];if (pipe == NULL)continue;pr_debug("%s: mixer=%d ndx=%d stage=%d\n", __func__,mixer, pipe->pipe_ndx, i);stage = pipe->mixer_stage;if (mixer >= MDP4_MIXER1)stage += 8;stage <<= (4 * pipe->pipe_num);data |= stage;}/* * stage_commit may be called from overlay_unset * for command panel, mdp clocks may be off at this time. * so mdp clock enabled is necessary */mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);mdp_clk_ctrl(1);mdp4_mixer_blend_setup(mixer);off = 0;if (data != ctrl->mixer_cfg[mixer]) {ctrl->mixer_cfg[mixer] = data;if (mixer >= MDP4_MIXER2) {/* MDP_LAYERMIXER2_IN_CFG */off = 0x100f0;} else {/* mixer 0 or 1 */num = mixer + 1;num &= 0x01;data |= ctrl->mixer_cfg[num];off = 0x10100;}pr_debug("%s: mixer=%d data=%x flush=%x pid=%d\n", __func__,mixer, data, ctrl->flush[mixer], current->pid);}local_irq_save(flags);if (off)outpdw(MDP_BASE + off, data);if (ctrl->flush[mixer]) {outpdw(MDP_BASE + 0x18000, ctrl->flush[mixer]);ctrl->flush[mixer] = 0;}local_irq_restore(flags);mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);mdp_clk_ctrl(0);}

原创粉丝点击