void mdp4_dtv_set_black_screen(void) { char *rgb_base; /*Black color*/ uint32 color = 0x00000000; uint32 temp_src_format; int cndx = 0; struct vsycn_ctrl *vctrl; vctrl = &vsync_ctrl_db[cndx]; if (vctrl->base_pipe == NULL || !hdmi_prim_display) { pr_err("dtv_pipe is not configured yet\n"); return; } rgb_base = MDP_BASE + MDP4_RGB_BASE; rgb_base += (MDP4_RGB_OFF * vctrl->base_pipe->pipe_num); /* * RGB Constant Color */ MDP_OUTP(rgb_base + 0x1008, color); /* * MDP_RGB_SRC_FORMAT */ temp_src_format = inpdw(rgb_base + 0x0050); MDP_OUTP(rgb_base + 0x0050, temp_src_format | BIT(22)); mdp4_overlay_reg_flush(vctrl->base_pipe, 1); mdp4_mixer_stage_up(vctrl->base_pipe, 0); mdp4_mixer_stage_commit(vctrl->base_pipe->mixer_num); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); }
int mdp4_overlay_writeback_update(struct msm_fb_data_type *mfd) { struct fb_info *fbi; uint8 *buf; unsigned int buf_offset; struct mdp4_overlay_pipe *pipe; int bpp; if (mfd->key != MFD_KEY) return -ENODEV; if (!writeback_pipe) return -EINVAL; fbi = mfd->fbi; pipe = writeback_pipe; bpp = fbi->var.bits_per_pixel / 8; buf = (uint8 *) fbi->fix.smem_start; buf_offset = fbi->var.xoffset * bpp + fbi->var.yoffset * fbi->fix.line_length; /* MDP cmd block enable */ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); pipe->src_height = fbi->var.yres; pipe->src_width = fbi->var.xres; pipe->src_h = fbi->var.yres; pipe->src_w = fbi->var.xres; pipe->dst_h = fbi->var.yres; pipe->dst_w = fbi->var.xres; pipe->srcp0_ystride = fbi->fix.line_length; pipe->src_y = 0; pipe->src_x = 0; pipe->dst_y = 0; pipe->dst_x = 0; mdp4_overlay_mdp_pipe_req(pipe, mfd); if (mfd->map_buffer) { pipe->srcp0_addr = (unsigned int)mfd->map_buffer->iova[0] + \ buf_offset; pr_debug("start 0x%lx srcp0_addr 0x%x\n", mfd-> map_buffer->iova[0], pipe->srcp0_addr); } else { pipe->srcp0_addr = (uint32)(buf + buf_offset); } mdp4_mixer_stage_up(pipe, 0); mdp4_overlayproc_cfg(pipe); mdp4_mixer_stage_commit(pipe->mixer_num); /* MDP cmd block disable */ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); wmb(); return 0; }
void mdp4_atv_overlay(struct msm_fb_data_type *mfd) { struct fb_info *fbi = mfd->fbi; uint8 *buf; unsigned int buf_offset; int bpp; unsigned long flag; struct mdp4_overlay_pipe *pipe; if (!mfd->panel_power_on) return; /* */ bpp = fbi->var.bits_per_pixel / 8; buf = (uint8 *) fbi->fix.smem_start; buf_offset = calc_fb_offset(mfd, fbi, bpp); mutex_lock(&mfd->dma->ov_mutex); pipe = atv_pipe; if (mfd->map_buffer) { pipe->srcp0_addr = (unsigned int)mfd->map_buffer->iova[0] + \ buf_offset; pr_debug("start 0x%lx srcp0_addr 0x%x\n", mfd-> map_buffer->iova[0], pipe->srcp0_addr); } else { pipe->srcp0_addr = (uint32)(buf + buf_offset); } mdp_update_pm(mfd, vsync_ctrl_db[0].vsync_time); mdp4_overlay_mdp_perf_req(pipe, mfd); mdp4_overlay_mdp_perf_upd(mfd, 1); mdp4_overlay_rgb_setup(pipe); mdp4_overlay_reg_flush(pipe, 0); mdp4_mixer_stage_up(pipe, 0); mdp4_mixer_stage_commit(pipe->mixer_num); printk(KERN_INFO "mdp4_atv_overlay: pipe=%x ndx=%d\n", (int)pipe, pipe->pipe_ndx); /* */ spin_lock_irqsave(&mdp_spin_lock, flag); mdp_enable_irq(MDP_OVERLAY1_TERM); INIT_COMPLETION(atv_pipe->comp); mfd->dma->waiting = TRUE; outp32(MDP_INTR_CLEAR, INTR_OVERLAY1_DONE); mdp_intr_mask |= INTR_OVERLAY1_DONE; outp32(MDP_INTR_ENABLE, mdp_intr_mask); spin_unlock_irqrestore(&mdp_spin_lock, flag); wait_for_completion_killable(&atv_pipe->comp); mdp_disable_irq(MDP_OVERLAY1_TERM); mdp4_overlay_mdp_perf_upd(mfd, 0); mdp4_stat.kickoff_atv++; mutex_unlock(&mfd->dma->ov_mutex); }
void mdp4_dtv_set_black_screen() { char *rgb_base; /*Black color*/ uint32 color = 0x00000000; uint32 temp_src_format; int commit = 1, cndx = 0; int pipe_num = OVERLAY_PIPE_RGB1; struct vsycn_ctrl *vctrl; vctrl = &vsync_ctrl_db[cndx]; if (!hdmi_prim_display) return; if (vctrl->base_pipe == NULL) commit = 0; else pipe_num = vctrl->base_pipe->pipe_num; rgb_base = MDP_BASE; rgb_base += (MDP4_RGB_OFF * (pipe_num + 2)); /* * RGB Constant Color */ MDP_OUTP(rgb_base + 0x1008, color); /* * MDP_RGB_SRC_FORMAT */ temp_src_format = inpdw(rgb_base + 0x0050); MDP_OUTP(rgb_base + 0x0050, temp_src_format | BIT(22)); mdp4_overlay_reg_flush(vctrl->base_pipe, 1); if (commit) { mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); mdp4_overlay_reg_flush(vctrl->base_pipe, 1); mdp4_mixer_stage_up(vctrl->base_pipe, 0); mdp4_mixer_stage_commit(vctrl->base_pipe->mixer_num); } else { /* MDP_OVERLAY_REG_FLUSH for pipe*/ MDP_OUTP(MDP_BASE + 0x18000, BIT(pipe_num + 2) | BIT(MDP4_MIXER1)); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); } }
void mdp4_overlay_update_lcd(struct msm_fb_data_type *mfd) { MDPIBUF *iBuf = &mfd->ibuf; uint8 *src; int ptype; uint32 mddi_ld_param; uint16 mddi_vdo_packet_reg; struct mdp4_overlay_pipe *pipe; int ret; if (mfd->key != MFD_KEY) return; mddi_mfd = mfd; /* keep it */ /* MDP cmd block enable */ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); if (mddi_pipe == NULL) { ptype = mdp4_overlay_format2type(mfd->fb_imgType); if (ptype < 0) printk(KERN_INFO "%s: format2type failed\n", __func__); pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0); if (pipe == NULL) printk(KERN_INFO "%s: pipe_alloc failed\n", __func__); pipe->pipe_used++; pipe->mixer_num = MDP4_MIXER0; pipe->src_format = mfd->fb_imgType; mdp4_overlay_panel_mode(pipe->mixer_num, MDP4_PANEL_MDDI); ret = mdp4_overlay_format2pipe(pipe); if (ret < 0) printk(KERN_INFO "%s: format2type failed\n", __func__); mddi_pipe = pipe; /* keep it */ mddi_ld_param = 0; mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt; if (mdp_hw_revision == MDP4_REVISION_V2_1) { uint32 data; data = inpdw(MDP_BASE + 0x0028); data &= ~0x0300; /* bit 8, 9, MASTER4 */ if (mfd->fbi->var.xres == 540) /* qHD, 540x960 */ data |= 0x0200; else data |= 0x0100; MDP_OUTP(MDP_BASE + 0x00028, data); } if (mfd->panel_info.type == MDDI_PANEL) { if (mfd->panel_info.pdest == DISPLAY_1) mddi_ld_param = 0; else mddi_ld_param = 1; } else { mddi_ld_param = 2; } MDP_OUTP(MDP_BASE + 0x00090, mddi_ld_param); if (mfd->panel_info.bpp == 24) MDP_OUTP(MDP_BASE + 0x00094, (MDDI_VDO_PACKET_DESC_24 << 16) | mddi_vdo_packet_reg); else if (mfd->panel_info.bpp == 16) MDP_OUTP(MDP_BASE + 0x00094, (MDDI_VDO_PACKET_DESC_16 << 16) | mddi_vdo_packet_reg); else MDP_OUTP(MDP_BASE + 0x00094, (MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg); MDP_OUTP(MDP_BASE + 0x00098, 0x01); mdp4_init_writeback_buf(mfd, MDP4_MIXER0); pipe->ov_blt_addr = 0; pipe->dma_blt_addr = 0; } else { pipe = mddi_pipe; } /* 0 for dma_p, client_id = 0 */ MDP_OUTP(MDP_BASE + 0x00090, 0); src = (uint8 *) iBuf->buf; #ifdef WHOLESCREEN { struct fb_info *fbi; fbi = mfd->fbi; pipe->src_height = fbi->var.yres; pipe->src_width = fbi->var.xres; pipe->src_h = fbi->var.yres; pipe->src_w = fbi->var.xres; pipe->src_y = 0; pipe->src_x = 0; pipe->dst_h = fbi->var.yres; pipe->dst_w = fbi->var.xres; pipe->dst_y = 0; pipe->dst_x = 0; pipe->srcp0_addr = (uint32)src; pipe->srcp0_ystride = fbi->fix.line_length; } #else if (mdp4_overlay_active(MDP4_MIXER0)) { struct fb_info *fbi; fbi = mfd->fbi; pipe->src_height = fbi->var.yres; pipe->src_width = fbi->var.xres; pipe->src_h = fbi->var.yres; pipe->src_w = fbi->var.xres; pipe->src_y = 0; pipe->src_x = 0; pipe->dst_h = fbi->var.yres; pipe->dst_w = fbi->var.xres; pipe->dst_y = 0; pipe->dst_x = 0; pipe->srcp0_addr = (uint32) src; pipe->srcp0_ystride = fbi->fix.line_length; } else { /* starting input address */ src += (iBuf->dma_x + iBuf->dma_y * iBuf->ibuf_width) * iBuf->bpp; pipe->src_height = iBuf->dma_h; pipe->src_width = iBuf->dma_w; pipe->src_h = iBuf->dma_h; pipe->src_w = iBuf->dma_w; pipe->src_y = 0; pipe->src_x = 0; pipe->dst_h = iBuf->dma_h; pipe->dst_w = iBuf->dma_w; pipe->dst_y = iBuf->dma_y; pipe->dst_x = iBuf->dma_x; pipe->srcp0_addr = (uint32) src; pipe->srcp0_ystride = iBuf->ibuf_width * iBuf->bpp; } #endif pipe->mixer_stage = MDP4_MIXER_STAGE_BASE; mdp4_overlay_rgb_setup(pipe); mdp4_mixer_stage_up(pipe); mdp4_overlayproc_cfg(pipe); mdp4_overlay_dmap_xy(pipe); mdp4_overlay_dmap_cfg(mfd, 0); mdp4_mixer_stage_commit(pipe->mixer_num); mdp4_mddi_vsync_enable(mfd, pipe, 0); /* MDP cmd block disable */ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); }
/* 3D side by side */ void mdp4_dsi_cmd_3d_sbys(struct msm_fb_data_type *mfd, struct msmfb_overlay_3d *r3d) { struct fb_info *fbi; int bpp; uint8 *src = NULL; int cndx = 0; struct vsycn_ctrl *vctrl; struct mdp4_overlay_pipe *pipe; vctrl = &vsync_ctrl_db[cndx]; pipe = vctrl->base_pipe; if (pipe == NULL) return; if (pipe->pipe_used == 0 || pipe->mixer_stage != MDP4_MIXER_STAGE_BASE) { pr_err("%s: NOT baselayer\n", __func__); return; } pipe->is_3d = r3d->is_3d; pipe->src_height_3d = r3d->height; pipe->src_width_3d = r3d->width; if (pipe->is_3d) mdp4_overlay_panel_3d(pipe->mixer_num, MDP4_3D_SIDE_BY_SIDE); else mdp4_overlay_panel_3d(pipe->mixer_num, MDP4_3D_NONE); fbi = mfd->fbi; if (pipe->is_3d) { bpp = fbi->var.bits_per_pixel / 8; pipe->src_height = pipe->src_height_3d; pipe->src_width = pipe->src_width_3d; pipe->src_h = pipe->src_height_3d; pipe->src_w = pipe->src_width_3d; pipe->dst_h = pipe->src_height_3d; pipe->dst_w = pipe->src_width_3d; pipe->srcp0_ystride = msm_fb_line_length(0, pipe->src_width, bpp); } else { /* 2D */ pipe->src_height = fbi->var.yres; pipe->src_width = fbi->var.xres; pipe->src_h = fbi->var.yres; pipe->src_w = fbi->var.xres; pipe->dst_h = fbi->var.yres; pipe->dst_w = fbi->var.xres; pipe->srcp0_ystride = fbi->fix.line_length; } pipe->src_y = 0; pipe->src_x = 0; pipe->dst_y = 0; pipe->dst_x = 0; pipe->srcp0_addr = (uint32)src; mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); mdp_clk_ctrl(1); mdp4_overlay_rgb_setup(pipe); mdp4_overlay_reg_flush(pipe, 1); mdp4_mixer_stage_up(pipe, 0); mdp4_overlayproc_cfg(pipe); mdp4_overlay_dmap_xy(pipe); mdp4_overlay_dmap_cfg(mfd, 0); mdp4_mixer_stage_commit(pipe->mixer_num); /* MDP cmd block disable */ mdp_clk_ctrl(0); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); }
int mdp4_dsi_video_on(struct platform_device *pdev) { int dsi_width; int dsi_height; int dsi_bpp; int dsi_border_clr; int dsi_underflow_clr; int dsi_hsync_skew; int hsync_period; int hsync_ctrl; int vsync_period; int display_hctl; int display_v_start; int display_v_end; int active_hctl; int active_h_start; int active_h_end; int active_v_start; int active_v_end; int ctrl_polarity; int h_back_porch; int h_front_porch; int v_back_porch; int v_front_porch; int hsync_pulse_width; int vsync_pulse_width; int hsync_polarity; int vsync_polarity; int data_en_polarity; int hsync_start_x; int hsync_end_x; uint8 *buf; unsigned int buf_offset; int bpp, ptype; struct fb_info *fbi; struct fb_var_screeninfo *var; struct msm_fb_data_type *mfd; struct mdp4_overlay_pipe *pipe; int ret = 0; int cndx = 0; struct vsycn_ctrl *vctrl; struct msm_panel_info *pinfo; vctrl = &vsync_ctrl_db[cndx]; mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); pinfo = &mfd->panel_info; if (!mfd) return -ENODEV; if (mfd->key != MFD_KEY) return -EINVAL; #if defined (CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_VIDEO_QHD_PT) if (get_lcd_attached() == 0) return -ENODEV; #endif mutex_lock(&mfd->dma->ov_mutex); vctrl->mfd = mfd; vctrl->dev = mfd->fbi->dev; vctrl->blt_ctrl = pinfo->lcd.blt_ctrl; vctrl->vsync_irq_enabled = 0; vsync_irq_cnt = 0; /* mdp clock on */ mdp_clk_ctrl(1); fbi = mfd->fbi; var = &fbi->var; bpp = fbi->var.bits_per_pixel / 8; buf = (uint8 *) fbi->fix.smem_start; buf_offset = calc_fb_offset(mfd, fbi, bpp); if (vctrl->base_pipe == NULL) { ptype = mdp4_overlay_format2type(mfd->fb_imgType); if (ptype < 0) printk(KERN_INFO "%s: format2type failed\n", __func__); pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0); if (pipe == NULL) { printk(KERN_INFO "%s: pipe_alloc failed\n", __func__); mutex_unlock(&mfd->dma->ov_mutex); return -EBUSY; } pipe->pipe_used++; pipe->mixer_stage = MDP4_MIXER_STAGE_BASE; pipe->mixer_num = MDP4_MIXER0; pipe->src_format = mfd->fb_imgType; mdp4_overlay_panel_mode(pipe->mixer_num, MDP4_PANEL_DSI_VIDEO); ret = mdp4_overlay_format2pipe(pipe); if (ret < 0) printk(KERN_INFO "%s: format2type failed\n", __func__); pipe->ov_blt_addr = 0; pipe->dma_blt_addr = 0; vctrl->base_pipe = pipe; /* keep it */ mdp4_init_writeback_buf(mfd, MDP4_MIXER0); } else { pipe = vctrl->base_pipe; } atomic_set(&vctrl->suspend, 0); #if defined(CONFIG_FEATURE_FLIPLR) pipe->mfd = mfd; #endif /* QC Patch for LCD black out Issue */ if (!(mfd->cont_splash_done)) { mfd->cont_splash_done = 1; mdp4_dsi_video_wait4vsync(0); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0); mipi_dsi_controller_cfg(0); /* Clks are enabled in probe. Disabling clocks now */ mdp_clk_ctrl(0); } pipe->src_height = fbi->var.yres; pipe->src_width = fbi->var.xres; pipe->src_h = fbi->var.yres; pipe->src_w = fbi->var.xres; pipe->src_y = 0; pipe->src_x = 0; pipe->dst_h = fbi->var.yres; pipe->dst_w = fbi->var.xres; pipe->srcp0_ystride = fbi->fix.line_length; pipe->bpp = bpp; /* there is no FB, so we need to set it until we get data from surfaceFlinger */ if (!use_frame_buffer) pipe->solid_fill = 1; if (mfd->display_iova) pipe->srcp0_addr = mfd->display_iova + buf_offset; else pipe->srcp0_addr = (uint32)(buf + buf_offset); pipe->dst_h = fbi->var.yres; pipe->dst_w = fbi->var.xres; mdp4_overlay_solidfill_init(pipe); mdp4_overlay_mdp_pipe_req(pipe, mfd); mdp4_calc_blt_mdp_bw(mfd, pipe); mdp4_overlay_dmap_xy(pipe); /* dma_p */ mdp4_overlay_dmap_cfg(mfd, 1); mdp4_overlay_rgb_setup(pipe); /* Solid_fill clear after booting */ if (!use_frame_buffer) pipe->solid_fill = 0; mdp4_overlayproc_cfg(pipe); mdp4_overlay_reg_flush(pipe, 1); mdp4_mixer_stage_up(pipe, 0); mdp4_mixer_stage_commit(pipe->mixer_num); /* * DSI timing setting */ h_back_porch = var->left_margin; h_front_porch = var->right_margin; v_back_porch = var->upper_margin; v_front_porch = var->lower_margin; hsync_pulse_width = var->hsync_len; vsync_pulse_width = var->vsync_len; dsi_border_clr = mfd->panel_info.lcdc.border_clr; dsi_underflow_clr = mfd->panel_info.lcdc.underflow_clr; dsi_hsync_skew = mfd->panel_info.lcdc.hsync_skew; dsi_width = mfd->panel_info.xres + mfd->panel_info.lcdc.xres_pad; dsi_height = mfd->panel_info.yres + mfd->panel_info.lcdc.yres_pad; dsi_bpp = mfd->panel_info.bpp; hsync_period = hsync_pulse_width + h_back_porch + dsi_width + h_front_porch; hsync_ctrl = (hsync_period << 16) | hsync_pulse_width; hsync_start_x = h_back_porch + hsync_pulse_width; hsync_end_x = hsync_period - h_front_porch - 1; display_hctl = (hsync_end_x << 16) | hsync_start_x; vsync_period = (vsync_pulse_width + v_back_porch + dsi_height + v_front_porch); display_v_start = ((vsync_pulse_width + v_back_porch) * hsync_period) + dsi_hsync_skew; display_v_end = ((vsync_period - v_front_porch) * hsync_period) + dsi_hsync_skew - 1; if (dsi_width != var->xres) { active_h_start = hsync_start_x + first_pixel_start_x; active_h_end = active_h_start + var->xres - 1; active_hctl = ACTIVE_START_X_EN | (active_h_end << 16) | active_h_start; } else { active_hctl = 0; } if (dsi_height != var->yres) { active_v_start = display_v_start + first_pixel_start_y * hsync_period; active_v_end = active_v_start + (var->yres) * hsync_period - 1; active_v_start |= ACTIVE_START_Y_EN; } else { active_v_start = 0; active_v_end = 0; } dsi_underflow_clr |= 0x80000000; /* enable recovery */ hsync_polarity = 0; vsync_polarity = 0; data_en_polarity = 0; ctrl_polarity = (data_en_polarity << 2) | (vsync_polarity << 1) | (hsync_polarity); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x4, hsync_ctrl); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x8, vsync_period * hsync_period); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0xc, vsync_pulse_width * hsync_period); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x10, display_hctl); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x14, display_v_start); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x18, display_v_end); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x1c, active_hctl); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x20, active_v_start); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x24, active_v_end); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x28, dsi_border_clr); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x2c, dsi_underflow_clr); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x30, dsi_hsync_skew); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x38, ctrl_polarity); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); mdp_histogram_ctrl_all(TRUE); mutex_unlock(&mfd->dma->ov_mutex); // mdp4_overlay_dsi_video_start(); return ret; }
int mdp4_lcdc_pipe_commit(void) { 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 cnt = 0; 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; if (vp->update_cnt == 0) { mutex_unlock(&vctrl->update_lock); return 0; } 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 (vctrl->ov_koff != vctrl->ov_done) { spin_unlock_irqrestore(&vctrl->spin_lock, flags); pr_err("%s: Error, frame dropped %d %d\n", __func__, vctrl->ov_koff, vctrl->ov_done); return 0; } spin_unlock_irqrestore(&vctrl->spin_lock, flags); mdp4_overlay_mdp_perf_upd(vctrl->mfd, 1); if (vctrl->blt_change) { pipe = vctrl->base_pipe; spin_lock_irqsave(&vctrl->spin_lock, flags); INIT_COMPLETION(vctrl->dmap_comp); INIT_COMPLETION(vctrl->ov_comp); vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM); spin_unlock_irqrestore(&vctrl->spin_lock, flags); mdp4_lcdc_wait4dmap(0); if (pipe->ov_blt_addr) mdp4_lcdc_wait4ov(0); } pipe = vp->plist; for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { if (pipe->pipe_used) { 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 */ } } mdp4_mixer_stage_commit(mixer); /* start timing generator & mmu if they are not started yet */ mdp4_overlay_lcdc_start(); pipe = vctrl->base_pipe; spin_lock_irqsave(&vctrl->spin_lock, flags); if (pipe->ov_blt_addr) { mdp4_lcdc_blt_ov_update(pipe); pipe->ov_cnt++; INIT_COMPLETION(vctrl->ov_comp); vsync_irq_enable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM); mb(); vctrl->ov_koff++; /* kickoff overlay engine */ mdp4_stat.kickoff_ov0++; outpdw(MDP_BASE + 0x0004, 0); } else { /* schedule second phase update at dmap */ INIT_COMPLETION(vctrl->dmap_comp); vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM); } spin_unlock_irqrestore(&vctrl->spin_lock, flags); mdp4_stat.overlay_commit[pipe->mixer_num]++; return cnt; }
static void mdp4_overlay_dtv_alloc_pipe(struct msm_fb_data_type *mfd, int32 ptype, struct vsycn_ctrl *vctrl) { int ret = 0; struct fb_info *fbi = mfd->fbi; struct mdp4_overlay_pipe *pipe; if (vctrl->base_pipe != NULL) return; pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER1); if (pipe == NULL) { pr_err("%s: pipe_alloc failed\n", __func__); return; } pipe->pipe_used++; pipe->mixer_stage = MDP4_MIXER_STAGE_BASE; pipe->mixer_num = MDP4_MIXER1; if (ptype == OVERLAY_TYPE_BF) { /* LSP_BORDER_COLOR */ MDP_OUTP(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x5004, ((0x0 & 0xFFF) << 16) | /* 12-bit B */ (0x0 & 0xFFF)); /* 12-bit G */ /* MSP_BORDER_COLOR */ MDP_OUTP(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x5008, (0x0 & 0xFFF)); /* 12-bit R */ pipe->src_format = MDP_ARGB_8888; } else { switch (mfd->ibuf.bpp) { case 2: pipe->src_format = MDP_RGB_565; break; case 3: pipe->src_format = MDP_RGB_888; break; case 4: default: if (hdmi_prim_display) pipe->src_format = MSMFB_DEFAULT_TYPE; else pipe->src_format = MDP_ARGB_8888; break; } } pipe->src_height = fbi->var.yres; pipe->src_width = fbi->var.xres; pipe->src_h = fbi->var.yres; pipe->src_w = fbi->var.xres; pipe->dst_h = fbi->var.yres; pipe->dst_w = fbi->var.xres; pipe->src_y = 0; pipe->src_x = 0; pipe->dst_h = fbi->var.yres; pipe->dst_w = fbi->var.xres; pipe->srcp0_ystride = fbi->fix.line_length; mdp4_overlay_mdp_pipe_req(pipe, mfd); ret = mdp4_overlay_format2pipe(pipe); if (ret < 0) pr_warn("%s: format2type failed\n", __func__); mdp4_overlay_dmae_xy(pipe); /* dma_e */ mdp4_overlayproc_cfg(pipe); if (pipe->pipe_type == OVERLAY_TYPE_RGB) { pipe->srcp0_addr = (uint32) mfd->ibuf.buf; mdp4_overlay_rgb_setup(pipe); } mdp4_overlay_reg_flush(pipe, 1); mdp4_mixer_stage_up(pipe, 0); mdp4_mixer_stage_commit(pipe->mixer_num); vctrl->base_pipe = pipe; /* keep it */ }
/* 3D side by side */ void mdp4_dsi_video_3d_sbys(struct msm_fb_data_type *mfd, struct msmfb_overlay_3d *r3d) { struct fb_info *fbi; unsigned int buf_offset; int bpp; uint8 *buf = NULL; int cndx = 0; struct vsycn_ctrl *vctrl; struct mdp4_overlay_pipe *pipe; vctrl = &vsync_ctrl_db[cndx]; pipe = vctrl->base_pipe; if (vctrl->base_pipe == NULL) return; pipe = vctrl->base_pipe; pipe->is_3d = r3d->is_3d; pipe->src_height_3d = r3d->height; pipe->src_width_3d = r3d->width; if (pipe->is_3d) mdp4_overlay_panel_3d(pipe->mixer_num, MDP4_3D_SIDE_BY_SIDE); else mdp4_overlay_panel_3d(pipe->mixer_num, MDP4_3D_NONE); fbi = mfd->fbi; bpp = fbi->var.bits_per_pixel / 8; buf = (uint8 *) fbi->fix.smem_start; buf_offset = calc_fb_offset(mfd, fbi, bpp); if (pipe->is_3d) { pipe->src_height = pipe->src_height_3d; pipe->src_width = pipe->src_width_3d; pipe->src_h = pipe->src_height_3d; pipe->src_w = pipe->src_width_3d; pipe->dst_h = pipe->src_height_3d; pipe->dst_w = pipe->src_width_3d; pipe->srcp0_ystride = msm_fb_line_length(0, pipe->src_width, bpp); } else { /* 2D */ pipe->src_height = fbi->var.yres; pipe->src_width = fbi->var.xres; pipe->src_h = fbi->var.yres; pipe->src_w = fbi->var.xres; pipe->dst_h = fbi->var.yres; pipe->dst_w = fbi->var.xres; pipe->srcp0_ystride = fbi->fix.line_length; } pipe->src_y = 0; pipe->src_x = 0; pipe->dst_y = 0; pipe->dst_x = 0; if (mfd->map_buffer) { pipe->srcp0_addr = (unsigned int)mfd->map_buffer->iova[0] + \ buf_offset; pr_debug("start 0x%lx srcp0_addr 0x%x\n", mfd-> map_buffer->iova[0], pipe->srcp0_addr); } else { pipe->srcp0_addr = (uint32)(buf + buf_offset); } mdp4_overlay_rgb_setup(pipe); mdp4_overlayproc_cfg(pipe); mdp4_overlay_dmap_xy(pipe); mdp4_overlay_dmap_cfg(mfd, 1); mdp4_overlay_reg_flush(pipe, 1); mdp4_mixer_stage_up(pipe, 0); mdp4_mixer_stage_commit(pipe->mixer_num); mb(); }
int mdp4_dsi_video_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 cnt = 0; #ifdef MDP_ODD_RESOLUTION_CTRL int current_pipe_ndx = 0; #endif vctrl = &vsync_ctrl_db[cndx]; mutex_lock(&vctrl->update_lock); undx = vctrl->update_ndx; vp = &vctrl->vlist[undx]; pipe = vctrl->base_pipe; if (pipe == NULL) { pr_err("%s: NO base pipe\n", __func__); mutex_unlock(&vctrl->update_lock); return 0; } mixer = pipe->mixer_num; mdp_update_pm(vctrl->mfd, vctrl->vsync_time); /* * allow stage_commit without pipes queued * (vp->update_cnt == 0) to unstage pipes after * overlay_unset */ 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); spin_lock_irqsave(&vctrl->spin_lock, flags); if (vctrl->ov_koff != vctrl->ov_done) { spin_unlock_irqrestore(&vctrl->spin_lock, flags); pr_err("%s: Error, frame dropped %d %d\n", __func__, vctrl->ov_koff, vctrl->ov_done); return 0; } spin_unlock_irqrestore(&vctrl->spin_lock, flags); pipe = vp->plist; for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { if (pipe->pipe_used) { cnt++; real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx); if (real_pipe && real_pipe->pipe_used) { /* * commit pipes which are in pending queue * and not be unset yet */ mdp4_overlay_vsync_commit(pipe); if (pipe->frame_format != MDP4_FRAME_FORMAT_LINEAR) { spin_lock_irqsave(&vctrl->spin_lock, flags); INIT_COMPLETION(vctrl->dmap_comp); vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM); spin_unlock_irqrestore(&vctrl->spin_lock, flags); } } } } mdp4_mixer_stage_commit(mixer); /* start timing generator & mmu if they are not started yet */ mdp4_overlay_dsi_video_start(); /* * there has possibility that pipe commit come very close to next vsync * this may cause two consecutive pie_commits happen within same vsync * period which casue iommu page fault when previous iommu buffer * freed. Set ION_IOMMU_UNMAP_DELAYED flag at ion_map_iommu() to * add delay unmap iommu buffer to fix this problem. * Also ion_unmap_iommu() may take as long as 9 ms to free an ion buffer. * therefore mdp4_overlay_iommu_unmap_freelist(mixer) should be called * ater stage_commit() to ensure pipe_commit (up to stage_commit) * is completed within vsync period. */ /* free previous committed iommu back to pool */ mdp4_overlay_iommu_unmap_freelist(mixer); pipe = vp->plist; for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { if (pipe->pipe_used) { /* 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 */ } } pipe = vctrl->base_pipe; spin_lock_irqsave(&vctrl->spin_lock, flags); if (pipe->ov_blt_addr) { mdp4_dsi_video_blt_ov_update(pipe); pipe->ov_cnt++; INIT_COMPLETION(vctrl->ov_comp); vsync_irq_enable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM); mb(); vctrl->ov_koff++; /* kickoff overlay engine */ mdp4_stat.kickoff_ov0++; outpdw(MDP_BASE + 0x0004, 0); } else { /* schedule second phase update at dmap */ INIT_COMPLETION(vctrl->dmap_comp); vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM); } spin_unlock_irqrestore(&vctrl->spin_lock, flags); mdp4_stat.overlay_commit[pipe->mixer_num]++; if (wait) { if (pipe->ov_blt_addr) mdp4_dsi_video_wait4ov(0); else mdp4_dsi_video_wait4dmap(0); } #ifdef MDP_ODD_RESOLUTION_CTRL current_pipe_ndx = pipe->pipe_ndx; for (i = current_pipe_ndx ; i >= 0; i--, pipe--) { pipe->check_odd_res = 0; } #endif return cnt; }
void mdp4_overlay_update_mddi(struct msm_fb_data_type *mfd) { int ptype; uint32 mddi_ld_param; uint16 mddi_vdo_packet_reg; struct mdp4_overlay_pipe *pipe; uint32 data; int ret; int cndx = 0; struct vsycn_ctrl *vctrl; if (mfd->key != MFD_KEY) return; vctrl = &vsync_ctrl_db[cndx]; if (vctrl->base_pipe == NULL) { ptype = mdp4_overlay_format2type(mfd->fb_imgType); if (ptype < 0) pr_info("%s: format2type failed\n", __func__); pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0); if (pipe == NULL) { pr_info("%s: pipe_alloc failed\n", __func__); return; } pipe->pipe_used++; pipe->mixer_stage = MDP4_MIXER_STAGE_BASE; pipe->mixer_num = MDP4_MIXER0; pipe->src_format = mfd->fb_imgType; mdp4_overlay_panel_mode(pipe->mixer_num, MDP4_PANEL_MDDI); ret = mdp4_overlay_format2pipe(pipe); if (ret < 0) pr_info("%s: format2type failed\n", __func__); vctrl->base_pipe = pipe; /* keep it */ mdp4_init_writeback_buf(mfd, MDP4_MIXER0); pipe->ov_blt_addr = 0; pipe->dma_blt_addr = 0; } else { pipe = vctrl->base_pipe; } MDP_OUTP(MDP_BASE + 0x021c, 10); /* read pointer */ mddi_ld_param = 0; mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt; if (mdp_hw_revision == MDP4_REVISION_V2_1) { data = inpdw(MDP_BASE + 0x0028); data &= ~0x0300; /* bit 8, 9, MASTER4 */ if (mfd->fbi->var.xres == 540) /* qHD, 540x960 */ data |= 0x0200; else data |= 0x0100; MDP_OUTP(MDP_BASE + 0x00028, data); } if (mfd->panel_info.type == MDDI_PANEL) { if (mfd->panel_info.pdest == DISPLAY_1) mddi_ld_param = 0; else mddi_ld_param = 1; } else { mddi_ld_param = 2; } MDP_OUTP(MDP_BASE + 0x00090, mddi_ld_param); if (mfd->panel_info.bpp == 24) MDP_OUTP(MDP_BASE + 0x00094, (MDDI_VDO_PACKET_DESC_24 << 16) | mddi_vdo_packet_reg); else if (mfd->panel_info.bpp == 16) MDP_OUTP(MDP_BASE + 0x00094, (MDDI_VDO_PACKET_DESC_16 << 16) | mddi_vdo_packet_reg); else MDP_OUTP(MDP_BASE + 0x00094, (MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg); MDP_OUTP(MDP_BASE + 0x00098, 0x01); mdp4_overlay_setup_pipe_addr(mfd, pipe); mdp4_overlay_rgb_setup(pipe); mdp4_overlay_reg_flush(pipe, 1); mdp4_mixer_stage_up(pipe, 0); mdp4_overlayproc_cfg(pipe); mdp4_overlay_dmap_xy(pipe); mdp4_overlay_dmap_cfg(mfd, 0); mdp4_mixer_stage_commit(pipe->mixer_num); wmb(); }
int mdp4_atv_on(struct platform_device *pdev) { uint8 *buf; unsigned int buf_offset; int bpp, ptype; struct fb_info *fbi; struct fb_var_screeninfo *var; struct msm_fb_data_type *mfd; struct mdp4_overlay_pipe *pipe; int ret; mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); if (!mfd) return -ENODEV; if (mfd->key != MFD_KEY) return -EINVAL; fbi = mfd->fbi; var = &fbi->var; bpp = fbi->var.bits_per_pixel / 8; buf = (uint8 *) fbi->fix.smem_start; buf_offset = calc_fb_offset(mfd, fbi, bpp); if (atv_pipe == NULL) { ptype = mdp4_overlay_format2type(mfd->fb_imgType); pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER1); if (pipe == NULL) return -EBUSY; pipe->pipe_used++; pipe->mixer_stage = MDP4_MIXER_STAGE_BASE; pipe->mixer_num = MDP4_MIXER1; pipe->src_format = mfd->fb_imgType; mdp4_overlay_panel_mode(pipe->mixer_num, MDP4_PANEL_ATV); mdp4_overlay_format2pipe(pipe); atv_pipe = pipe; /* */ } else { pipe = atv_pipe; } printk(KERN_INFO "mdp4_atv_overlay: pipe=%x ndx=%d\n", (int)pipe, pipe->pipe_ndx); /* */ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); /* */ ret = panel_next_on(pdev); pr_info("%s: fbi->var.yres: %d | fbi->var.xres: %d", __func__, fbi->var.yres, fbi->var.xres); /* */ pipe->src_height = fbi->var.yres; pipe->src_width = fbi->var.xres; pipe->src_h = fbi->var.yres; pipe->src_w = fbi->var.xres; pipe->src_y = 0; pipe->src_x = 0; if (mfd->map_buffer) { pipe->srcp0_addr = (unsigned int)mfd->map_buffer->iova[0] + \ buf_offset; pr_debug("start 0x%lx srcp0_addr 0x%x\n", mfd-> map_buffer->iova[0], pipe->srcp0_addr); } else { pipe->srcp0_addr = (uint32)(buf + buf_offset); } pipe->srcp0_ystride = fbi->fix.line_length; mdp4_overlay_dmae_xy(pipe); /* */ mdp4_overlay_dmae_cfg(mfd, 1); mdp4_overlay_rgb_setup(pipe); mdp4_overlayproc_cfg(pipe); mdp4_overlay_reg_flush(pipe, 1); mdp4_mixer_stage_up(pipe, 0); mdp4_mixer_stage_commit(pipe->mixer_num); if (ret == 0) mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_ON, FALSE); /* */ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); return ret; }
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; vctrl = &vsync_ctrl_db[0]; mutex_lock(&vctrl->update_lock); undx = vctrl->update_ndx; vp = &vctrl->vlist[undx]; pipe = vctrl->base_pipe; if (pipe == NULL) { pr_err("%s: NO base pipe\n", __func__); mutex_unlock(&vctrl->update_lock); return 0; } mixer = pipe->mixer_num; mdp_update_pm(vctrl->mfd, vctrl->vsync_time); /* * allow stage_commit without pipes queued * (vp->update_cnt == 0) to unstage pipes after * overlay_unset */ 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); } if (mdp4_dsi_cmd_clk_check(vctrl) < 0) { mdp4_dsi_cmd_pipe_clean(vp); mutex_unlock(&vctrl->update_lock); return 0; } 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) { INIT_COMPLETION(vctrl->dmap_comp); 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); 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; } } if (vctrl->blt_change) { mdp4_overlayproc_cfg(pipe); mdp4_overlay_dmap_xy(pipe); vctrl->blt_change = 0; } pipe = vp->plist; for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { if (pipe->pipe_used) { 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); 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++; mdp_pipe_kickoff_simplified(MDP_OVERLAY0_TERM); mb(); /* make sure kickoff ececuted */ spin_unlock_irqrestore(&vctrl->spin_lock, flags); mdp4_stat.overlay_commit[pipe->mixer_num]++; if (wait) { if (pipe->ov_blt_addr) mdp4_dsi_cmd_wait4ov(0); else mdp4_dsi_cmd_wait4dmap(0); } return cnt; }
int mdp4_dsi_cmd_pipe_commit(void) { int i, undx, cnt; int mixer = 0; struct vsycn_ctrl *vctrl; struct vsync_update *vp; struct mdp4_overlay_pipe *pipe; unsigned long flags; int diff; 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; pr_debug("%s: vndx=%d cnt=%d expire=%x pid=%d\n", __func__, undx, vp->update_cnt, vctrl->expire_tick, current->pid); cnt = 0; if (vp->update_cnt == 0) { mutex_unlock(&vctrl->update_lock); return cnt; } vctrl->update_ndx++; vctrl->update_ndx &= 0x01; vctrl->commit_cnt++; vp->update_cnt = 0; /* reset */ mutex_unlock(&vctrl->update_lock); mdp4_backlight_commit_level(vctrl); /* free previous committed iommu back to pool */ mdp4_overlay_iommu_unmap_freelist(mixer); pipe = vp->plist; for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { if (pipe->pipe_used) { cnt++; 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 */ } } mdp4_mixer_stage_commit(mixer); pr_debug("%s: intr=%d expire=%d cpu=%d\n", __func__, vctrl->rdptr_intr_tot, vctrl->expire_tick, smp_processor_id()); spin_lock_irqsave(&vctrl->spin_lock, flags); pipe = vctrl->base_pipe; if (pipe->blt_changed) { /* blt configurtion changed */ pipe->blt_changed = 0; mdp4_overlayproc_cfg(pipe); mdp4_overlay_dmap_xy(pipe); } if (pipe->ov_blt_addr) { diff = pipe->blt_ov_koff - pipe->blt_ov_done; if (diff < 1) { mdp4_blt_overlay0_cfg(pipe); vsync_commit_kickoff_ov0(pipe, 1); } } else { vsync_commit_kickoff_ov0(pipe, 0); } spin_unlock_irqrestore(&vctrl->spin_lock, flags); return cnt; }
int mdp4_dsi_video_on(struct platform_device *pdev) { int dsi_width; int dsi_height; int dsi_bpp; int dsi_border_clr; int dsi_underflow_clr; int dsi_hsync_skew; int hsync_period; int hsync_ctrl; int vsync_period; int display_hctl; int display_v_start; int display_v_end; int active_hctl; int active_h_start; int active_h_end; int active_v_start; int active_v_end; int ctrl_polarity; int h_back_porch; int h_front_porch; int v_back_porch; int v_front_porch; int hsync_pulse_width; int vsync_pulse_width; int hsync_polarity; int vsync_polarity; int data_en_polarity; int hsync_start_x; int hsync_end_x; uint8 *buf; unsigned int buf_offset; int bpp, ptype; static bool first_video_on = true; struct fb_info *fbi; struct fb_var_screeninfo *var; struct msm_fb_data_type *mfd; struct mdp4_overlay_pipe *pipe; int ret = 0; int cndx = 0; struct vsycn_ctrl *vctrl; vctrl = &vsync_ctrl_db[cndx]; mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); if (!mfd) return -ENODEV; if (mfd->key != MFD_KEY) return -EINVAL; vctrl->mfd = mfd; vctrl->dev = mfd->fbi->dev; mdp_clk_ctrl(1); fbi = mfd->fbi; var = &fbi->var; bpp = fbi->var.bits_per_pixel / 8; buf = (uint8 *) fbi->fix.smem_start; buf_offset = calc_fb_offset(mfd, fbi, bpp); if (first_video_on) first_video_on = false; else { if (mfd->ref_cnt == 0) { int ndx; for (ndx=1; ndx<4; ndx++) { pipe = mdp4_overlay_ndx2pipe(ndx); if (pipe && pipe->pipe_used) mdp4_overlay_unset(mfd->fbi, ndx); } } } if (vctrl->base_pipe == NULL) { ptype = mdp4_overlay_format2type(mfd->fb_imgType); if (ptype < 0) printk(KERN_INFO "%s: format2type failed\n", __func__); pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0); if (pipe == NULL) { printk(KERN_INFO "%s: pipe_alloc failed\n", __func__); return -EBUSY; } pipe->pipe_used++; pipe->mixer_stage = MDP4_MIXER_STAGE_BASE; pipe->mixer_num = MDP4_MIXER0; pipe->src_format = mfd->fb_imgType; mdp4_overlay_panel_mode(pipe->mixer_num, MDP4_PANEL_DSI_VIDEO); ret = mdp4_overlay_format2pipe(pipe); if (ret < 0) printk(KERN_INFO "%s: format2type failed\n", __func__); pipe->ov_blt_addr = 0; pipe->dma_blt_addr = 0; vctrl->base_pipe = pipe; mdp4_init_writeback_buf(mfd, MDP4_MIXER0); } else { pipe = vctrl->base_pipe; } #ifdef CONTINUOUS_SPLASH mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); if (!(mfd->cont_splash_done)) { mfd->cont_splash_done = 1; mdp4_dsi_video_wait4dmap_done(0); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0); mdelay(20); mipi_dsi_controller_cfg(0); } #endif pipe->src_height = fbi->var.yres; pipe->src_width = fbi->var.xres; pipe->src_h = fbi->var.yres; pipe->src_w = fbi->var.xres; pipe->src_y = 0; pipe->src_x = 0; pipe->dst_h = fbi->var.yres; pipe->dst_w = fbi->var.xres; pipe->srcp0_ystride = fbi->fix.line_length; pipe->bpp = bpp; if (mfd->display_iova) pipe->srcp0_addr = mfd->display_iova + buf_offset; else pipe->srcp0_addr = (uint32)(buf + buf_offset); pipe->dst_h = fbi->var.yres; pipe->dst_w = fbi->var.xres; mdp4_overlay_mdp_pipe_req(pipe, mfd); atomic_set(&vctrl->suspend, 0); mdp4_overlay_dmap_xy(pipe); mdp4_overlay_dmap_cfg(mfd, 1); mdp4_overlay_rgb_setup(pipe); mdp4_overlayproc_cfg(pipe); mdp4_overlay_reg_flush(pipe, 1); mdp4_mixer_stage_up(pipe); mdp4_mixer_stage_commit(pipe->mixer_num); h_back_porch = var->left_margin; h_front_porch = var->right_margin; v_back_porch = var->upper_margin; v_front_porch = var->lower_margin; hsync_pulse_width = var->hsync_len; vsync_pulse_width = var->vsync_len; dsi_border_clr = mfd->panel_info.lcdc.border_clr; dsi_underflow_clr = mfd->panel_info.lcdc.underflow_clr; dsi_hsync_skew = mfd->panel_info.lcdc.hsync_skew; dsi_width = mfd->panel_info.xres + mfd->panel_info.lcdc.xres_pad; dsi_height = mfd->panel_info.yres + mfd->panel_info.lcdc.yres_pad; dsi_bpp = mfd->panel_info.bpp; hsync_period = hsync_pulse_width + h_back_porch + dsi_width + h_front_porch; hsync_ctrl = (hsync_period << 16) | hsync_pulse_width; hsync_start_x = h_back_porch + hsync_pulse_width; hsync_end_x = hsync_period - h_front_porch - 1; display_hctl = (hsync_end_x << 16) | hsync_start_x; vsync_period = (vsync_pulse_width + v_back_porch + dsi_height + v_front_porch); display_v_start = ((vsync_pulse_width + v_back_porch) * hsync_period) + dsi_hsync_skew; display_v_end = ((vsync_period - v_front_porch) * hsync_period) + dsi_hsync_skew - 1; if (dsi_width != var->xres) { active_h_start = hsync_start_x + first_pixel_start_x; active_h_end = active_h_start + var->xres - 1; active_hctl = ACTIVE_START_X_EN | (active_h_end << 16) | active_h_start; } else { active_hctl = 0; } if (dsi_height != var->yres) { active_v_start = display_v_start + first_pixel_start_y * hsync_period; active_v_end = active_v_start + (var->yres) * hsync_period - 1; active_v_start |= ACTIVE_START_Y_EN; } else { active_v_start = 0; active_v_end = 0; } dsi_underflow_clr |= 0x80000000; hsync_polarity = 0; vsync_polarity = 0; data_en_polarity = 0; ctrl_polarity = (data_en_polarity << 2) | (vsync_polarity << 1) | (hsync_polarity); if ((mfd->cont_splash_done)) { mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x4, hsync_ctrl); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x8, vsync_period * hsync_period); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0xc, vsync_pulse_width * hsync_period); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x10, display_hctl); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x14, display_v_start); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x18, display_v_end); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x1c, active_hctl); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x20, active_v_start); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x24, active_v_end); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x28, dsi_border_clr); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x2c, dsi_underflow_clr); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x30, dsi_hsync_skew); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x38, ctrl_polarity); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); } else { mfd->cont_splash_done = 1; mdp_clk_ctrl(0); } mdp_histogram_ctrl_all(TRUE); if (!vctrl->sysfs_created) { ret = sysfs_create_group(&vctrl->dev->kobj, &vsync_fs_attr_group); if (ret) { pr_err("%s: sysfs group creation failed, ret=%d\n", __func__, ret); return ret; } kobject_uevent(&vctrl->dev->kobj, KOBJ_ADD); pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__); vctrl->sysfs_created = 1; } return ret; }
int mdp4_dsi_video_pipe_commit(void) { 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 cnt = 0; 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; if (vp->update_cnt == 0) { mutex_unlock(&vctrl->update_lock); return cnt; } vctrl->update_ndx++; vctrl->update_ndx &= 0x01; vp->update_cnt = 0; if (vctrl->blt_free) { vctrl->blt_free--; if (vctrl->blt_free == 0) mdp4_free_writeback_buf(vctrl->mfd, mixer); } mutex_unlock(&vctrl->update_lock); mdp4_overlay_iommu_unmap_freelist(mixer); spin_lock_irqsave(&vctrl->spin_lock, flags); if (vctrl->ov_koff != vctrl->ov_done) { spin_unlock_irqrestore(&vctrl->spin_lock, flags); pr_err("%s: Error, frame dropped %d %d\n", __func__, vctrl->ov_koff, vctrl->ov_done); return 0; } spin_unlock_irqrestore(&vctrl->spin_lock, flags); if (vctrl->blt_change) { pipe = vctrl->base_pipe; spin_lock_irqsave(&vctrl->spin_lock, flags); INIT_COMPLETION(vctrl->dmap_comp); INIT_COMPLETION(vctrl->ov_comp); vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM); spin_unlock_irqrestore(&vctrl->spin_lock, flags); mdp4_dsi_video_wait4dmap(0); if (pipe->ov_blt_addr) mdp4_dsi_video_wait4ov(0); } pipe = vp->plist; for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { if (pipe->pipe_used) { cnt++; real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx); if (real_pipe && real_pipe->pipe_used) { mdp4_overlay_vsync_commit(pipe); } mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0); pipe->pipe_used = 0; } } mdp4_mixer_stage_commit(mixer); pipe = vctrl->base_pipe; spin_lock_irqsave(&vctrl->spin_lock, flags); if (pipe->ov_blt_addr) { mdp4_dsi_video_blt_ov_update(pipe); pipe->ov_cnt++; INIT_COMPLETION(vctrl->ov_comp); vsync_irq_enable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM); mb(); vctrl->ov_koff++; mdp4_stat.kickoff_ov0++; outpdw(MDP_BASE + 0x0004, 0); } else { INIT_COMPLETION(vctrl->dmap_comp); vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM); } spin_unlock_irqrestore(&vctrl->spin_lock, flags); mdp4_stat.overlay_commit[pipe->mixer_num]++; return cnt; }
int mdp4_dsi_video_on(struct platform_device *pdev) { int dsi_width; int dsi_height; int dsi_bpp; int dsi_border_clr; int dsi_underflow_clr; int dsi_hsync_skew; int hsync_period; int hsync_ctrl; int vsync_period; int display_hctl; int display_v_start; int display_v_end; int active_hctl; int active_h_start; int active_h_end; int active_v_start; int active_v_end; int ctrl_polarity; int h_back_porch; int h_front_porch; int v_back_porch; int v_front_porch; int hsync_pulse_width; int vsync_pulse_width; int hsync_polarity; int vsync_polarity; int data_en_polarity; int hsync_start_x; int hsync_end_x; uint8 *buf; unsigned int buf_offset; int bpp; struct fb_info *fbi; struct fb_var_screeninfo *var; struct msm_fb_data_type *mfd; struct mdp4_overlay_pipe *pipe; int ret = 0; int cndx = 0; struct vsycn_ctrl *vctrl; struct msm_panel_info *pinfo; vctrl = &vsync_ctrl_db[cndx]; mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); pinfo = &mfd->panel_info; if (!mfd) return -ENODEV; if (mfd->key != MFD_KEY) return -EINVAL; mutex_lock(&mfd->dma->ov_mutex); vctrl->mfd = mfd; vctrl->dev = mfd->fbi->dev; vctrl->blt_ctrl = pinfo->lcd.blt_ctrl; vctrl->vsync_irq_enabled = 0; vsync_irq_cnt = 0; /* mdp clock on */ mdp_clk_ctrl(1); fbi = mfd->fbi; var = &fbi->var; pipe = mdp4_dsi_video_alloc_base_pipe(); if (IS_ERR_OR_NULL(pipe)) { mutex_unlock(&mfd->dma->ov_mutex); return -EPERM; } if (mfd->panel_info.pdest == DISPLAY_4) mdp4_overlay_panel_mode(MDP4_PANEL_DSI_VIDEO_DMA_S, pipe->mixer_num); else mdp4_overlay_panel_mode(MDP4_PANEL_DSI_VIDEO, pipe->mixer_num); bpp = fbi->var.bits_per_pixel / 8; buf = (uint8 *) fbi->fix.smem_start; buf_offset = calc_fb_offset(mfd, fbi, bpp); atomic_set(&vctrl->suspend, 0); pipe->src_height = fbi->var.yres; pipe->src_width = fbi->var.xres; pipe->src_h = fbi->var.yres; pipe->src_w = fbi->var.xres; pipe->src_y = 0; pipe->src_x = 0; pipe->dst_h = fbi->var.yres; pipe->dst_w = fbi->var.xres; pipe->srcp0_ystride = fbi->fix.line_length; pipe->bpp = bpp; if (mfd->display_iova) pipe->srcp0_addr = mfd->display_iova + buf_offset; else pipe->srcp0_addr = (uint32)(buf + buf_offset); pipe->dst_h = fbi->var.yres; pipe->dst_w = fbi->var.xres; mdp4_overlay_solidfill_init(pipe); mdp4_overlay_mdp_pipe_req(pipe, mfd); mdp4_calc_blt_mdp_bw(mfd, pipe); mdp4_overlay_dmap_xy(pipe); /* dma_p */ mdp4_overlay_dmap_cfg(mfd, 1); if (pipe->pipe_type == OVERLAY_TYPE_VIDEO) mdp4_overlay_vg_setup(pipe); /* video/graphic pipe */ else mdp4_overlay_rgb_setup(pipe); /* rgb pipe */ mdp4_overlayproc_cfg(pipe); mdp4_overlay_reg_flush(pipe, 1); mdp4_mixer_stage_up(pipe, 0); mdp4_mixer_stage_commit(pipe->mixer_num); /* * DSI timing setting */ h_back_porch = var->left_margin; h_front_porch = var->right_margin; v_back_porch = var->upper_margin; v_front_porch = var->lower_margin; hsync_pulse_width = var->hsync_len; vsync_pulse_width = var->vsync_len; dsi_border_clr = mfd->panel_info.lcdc.border_clr; dsi_underflow_clr = mfd->panel_info.lcdc.underflow_clr; dsi_hsync_skew = mfd->panel_info.lcdc.hsync_skew; dsi_width = mfd->panel_info.xres + mfd->panel_info.lcdc.xres_pad; dsi_height = mfd->panel_info.yres + mfd->panel_info.lcdc.yres_pad; dsi_bpp = mfd->panel_info.bpp; hsync_period = hsync_pulse_width + h_back_porch + dsi_width + h_front_porch; hsync_ctrl = (hsync_period << 16) | hsync_pulse_width; hsync_start_x = h_back_porch + hsync_pulse_width; hsync_end_x = hsync_period - h_front_porch - 1; display_hctl = (hsync_end_x << 16) | hsync_start_x; vsync_period = (vsync_pulse_width + v_back_porch + dsi_height + v_front_porch); display_v_start = ((vsync_pulse_width + v_back_porch) * hsync_period) + dsi_hsync_skew; display_v_end = ((vsync_period - v_front_porch) * hsync_period) + dsi_hsync_skew - 1; if (dsi_width != var->xres) { active_h_start = hsync_start_x + first_pixel_start_x; active_h_end = active_h_start + var->xres - 1; active_hctl = ACTIVE_START_X_EN | (active_h_end << 16) | active_h_start; } else { active_hctl = 0; } if (dsi_height != var->yres) { active_v_start = display_v_start + first_pixel_start_y * hsync_period; active_v_end = active_v_start + (var->yres) * hsync_period - 1; active_v_start |= ACTIVE_START_Y_EN; } else { active_v_start = 0; active_v_end = 0; } dsi_underflow_clr |= 0x80000000; /* enable recovery */ hsync_polarity = 0; vsync_polarity = 0; data_en_polarity = 0; ctrl_polarity = (data_en_polarity << 2) | (vsync_polarity << 1) | (hsync_polarity); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x4, hsync_ctrl); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x8, vsync_period * hsync_period); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0xc, vsync_pulse_width * hsync_period); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x10, display_hctl); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x14, display_v_start); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x18, display_v_end); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x1c, active_hctl); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x20, active_v_start); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x24, active_v_end); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x28, dsi_border_clr); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x2c, dsi_underflow_clr); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x30, dsi_hsync_skew); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x38, ctrl_polarity); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); mdp_histogram_ctrl_all(TRUE); mdp4_overlay_dsi_video_start(); mutex_unlock(&mfd->dma->ov_mutex); return ret; }
int mdp4_mddi_pipe_commit(void) { 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; 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; 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); if (need_dmap_wait) { pr_debug("%s: wait4dmap\n", __func__); mdp4_mddi_wait4dmap(0); } if (need_ov_wait) { pr_debug("%s: wait4ov\n", __func__); mdp4_mddi_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; } } if (vctrl->blt_change) { mdp4_overlayproc_cfg(pipe); mdp4_overlay_dmap_xy(pipe); vctrl->blt_change = 0; } pipe = vp->plist; for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { if (pipe->pipe_used) { 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 */ } } mdp4_mixer_stage_commit(mixer); pipe = vctrl->base_pipe; spin_lock_irqsave(&vctrl->spin_lock, flags); if (pipe->ov_blt_addr) { mdp4_mddi_blt_ov_update(pipe); pipe->ov_cnt++; vctrl->ov_koff++; vsync_irq_enable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM); } else { vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM); vctrl->dmap_koff++; } pr_debug("%s: kickoff\n", __func__); /* kickoff overlay engine */ mdp4_stat.kickoff_ov0++; outpdw(MDP_BASE + 0x0004, 0); mb(); /* make sure kickoff ececuted */ spin_unlock_irqrestore(&vctrl->spin_lock, flags); mdp4_stat.overlay_commit[pipe->mixer_num]++; return cnt; }
int mdp4_lcdc_on(struct platform_device *pdev) { int lcdc_width; int lcdc_height; int lcdc_bpp; int lcdc_border_clr; int lcdc_underflow_clr; int lcdc_hsync_skew; int hsync_period; int hsync_ctrl; int vsync_period; int display_hctl; int display_v_start; int display_v_end; int active_hctl; int active_h_start; int active_h_end; int active_v_start; int active_v_end; int ctrl_polarity; int h_back_porch; int h_front_porch; int v_back_porch; int v_front_porch; int hsync_pulse_width; int vsync_pulse_width; int hsync_polarity; int vsync_polarity; int data_en_polarity; int hsync_start_x; int hsync_end_x; uint8 *buf; unsigned int buf_offset; int bpp, ptype; struct fb_info *fbi; struct fb_var_screeninfo *var; struct msm_fb_data_type *mfd; struct mdp4_overlay_pipe *pipe; int ret = 0; int cndx = 0; struct vsycn_ctrl *vctrl; vctrl = &vsync_ctrl_db[cndx]; mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); if (!mfd) return -ENODEV; if (mfd->key != MFD_KEY) return -EINVAL; mutex_lock(&mfd->dma->ov_mutex); vctrl->mfd = mfd; vctrl->dev = mfd->fbi->dev; vctrl->vsync_irq_enabled = 0; /* mdp clock on */ mdp_clk_ctrl(1); fbi = mfd->fbi; var = &fbi->var; bpp = fbi->var.bits_per_pixel / 8; buf = (uint8 *) fbi->fix.smem_start; buf_offset = calc_fb_offset(mfd, fbi, bpp); if (vctrl->base_pipe == NULL) { ptype = mdp4_overlay_format2type(mfd->fb_imgType); if (ptype < 0) printk(KERN_INFO "%s: format2type failed\n", __func__); pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0); if (pipe == NULL) printk(KERN_INFO "%s: pipe_alloc failed\n", __func__); pipe->pipe_used++; pipe->mixer_stage = MDP4_MIXER_STAGE_BASE; pipe->mixer_num = MDP4_MIXER0; pipe->src_format = mfd->fb_imgType; mdp4_overlay_panel_mode(pipe->mixer_num, MDP4_PANEL_LCDC); ret = mdp4_overlay_format2pipe(pipe); if (ret < 0) printk(KERN_INFO "%s: format2pipe failed\n", __func__); mdp4_init_writeback_buf(mfd, MDP4_MIXER0); pipe->ov_blt_addr = 0; pipe->dma_blt_addr = 0; vctrl->base_pipe = pipe; /* keep it */ } else { pipe = vctrl->base_pipe; } pipe->src_height = fbi->var.yres; pipe->src_width = fbi->var.xres; pipe->src_h = fbi->var.yres; pipe->src_w = fbi->var.xres; pipe->src_y = 0; pipe->src_x = 0; pipe->dst_h = fbi->var.yres; pipe->dst_w = fbi->var.xres; if (mfd->display_iova) pipe->srcp0_addr = mfd->display_iova + buf_offset; else pipe->srcp0_addr = (uint32)(buf + buf_offset); pipe->srcp0_ystride = fbi->fix.line_length; pipe->bpp = bpp; mdp4_overlay_solidfill_init(pipe); mdp4_overlay_mdp_pipe_req(pipe, mfd); mdp4_calc_blt_mdp_bw(mfd, pipe); atomic_set(&vctrl->suspend, 0); mdp4_overlay_dmap_xy(pipe); mdp4_overlay_dmap_cfg(mfd, 1); mdp4_overlay_rgb_setup(pipe); mdp4_overlayproc_cfg(pipe); mdp4_overlay_reg_flush(pipe, 1); mdp4_mixer_stage_up(pipe, 0); mdp4_mixer_stage_commit(pipe->mixer_num); /* * LCDC timing setting */ h_back_porch = var->left_margin; h_front_porch = var->right_margin; v_back_porch = var->upper_margin; v_front_porch = var->lower_margin; hsync_pulse_width = var->hsync_len; vsync_pulse_width = var->vsync_len; lcdc_border_clr = mfd->panel_info.lcdc.border_clr; lcdc_underflow_clr = mfd->panel_info.lcdc.underflow_clr; lcdc_hsync_skew = mfd->panel_info.lcdc.hsync_skew; lcdc_width = var->xres + mfd->panel_info.lcdc.xres_pad; lcdc_height = var->yres + mfd->panel_info.lcdc.yres_pad; lcdc_bpp = mfd->panel_info.bpp; hsync_period = hsync_pulse_width + h_back_porch + lcdc_width + h_front_porch; hsync_ctrl = (hsync_period << 16) | hsync_pulse_width; hsync_start_x = hsync_pulse_width + h_back_porch; hsync_end_x = hsync_period - h_front_porch - 1; display_hctl = (hsync_end_x << 16) | hsync_start_x; vsync_period = (vsync_pulse_width + v_back_porch + lcdc_height + v_front_porch) * hsync_period; display_v_start = (vsync_pulse_width + v_back_porch) * hsync_period + lcdc_hsync_skew; display_v_end = vsync_period - (v_front_porch * hsync_period) + lcdc_hsync_skew - 1; if (lcdc_width != var->xres) { active_h_start = hsync_start_x + first_pixel_start_x; active_h_end = active_h_start + var->xres - 1; active_hctl = ACTIVE_START_X_EN | (active_h_end << 16) | active_h_start; } else { active_hctl = 0; } if (lcdc_height != var->yres) { active_v_start = display_v_start + first_pixel_start_y * hsync_period; active_v_end = active_v_start + (var->yres) * hsync_period - 1; active_v_start |= ACTIVE_START_Y_EN; } else { active_v_start = 0; active_v_end = 0; } #ifdef CONFIG_FB_MSM_MDP40 hsync_polarity = 1; vsync_polarity = 1; lcdc_underflow_clr |= 0x80000000; /* enable recovery */ #else hsync_polarity = 0; vsync_polarity = 0; #endif #ifdef CONFIG_SAMSUNG_8X60_TABLET data_en_polarity = 0; #else data_en_polarity = 1; #endif ctrl_polarity = (data_en_polarity << 2) | (vsync_polarity << 1) | (hsync_polarity); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); MDP_OUTP(MDP_BASE + LCDC_BASE + 0x4, hsync_ctrl); MDP_OUTP(MDP_BASE + LCDC_BASE + 0x8, vsync_period); MDP_OUTP(MDP_BASE + LCDC_BASE + 0xc, vsync_pulse_width * hsync_period); MDP_OUTP(MDP_BASE + LCDC_BASE + 0x10, display_hctl); MDP_OUTP(MDP_BASE + LCDC_BASE + 0x14, display_v_start); MDP_OUTP(MDP_BASE + LCDC_BASE + 0x18, display_v_end); MDP_OUTP(MDP_BASE + LCDC_BASE + 0x28, lcdc_border_clr); MDP_OUTP(MDP_BASE + LCDC_BASE + 0x2c, lcdc_underflow_clr); MDP_OUTP(MDP_BASE + LCDC_BASE + 0x30, lcdc_hsync_skew); MDP_OUTP(MDP_BASE + LCDC_BASE + 0x38, ctrl_polarity); MDP_OUTP(MDP_BASE + LCDC_BASE + 0x1c, active_hctl); MDP_OUTP(MDP_BASE + LCDC_BASE + 0x20, active_v_start); MDP_OUTP(MDP_BASE + LCDC_BASE + 0x24, active_v_end); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); mdp_histogram_ctrl_all(TRUE); mdp4_overlay_lcdc_start(); mutex_unlock(&mfd->dma->ov_mutex); return ret; }
int mdp4_dtv_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 cnt = 0; vctrl = &vsync_ctrl_db[cndx]; mutex_lock(&vctrl->update_lock); undx = vctrl->update_ndx; vp = &vctrl->vlist[undx]; pipe = vctrl->base_pipe; mixer = pipe->mixer_num; mdp4_overlay_iommu_unmap_freelist(mixer); if (vp->update_cnt == 0) { mutex_unlock(&vctrl->update_lock); return 0; } vctrl->update_ndx++; vctrl->update_ndx &= 0x01; vp->update_cnt = 0; /* reset */ mutex_unlock(&vctrl->update_lock); pipe = vp->plist; for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { if (pipe->pipe_used) { 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 */ } } mdp4_mixer_stage_commit(mixer); /* start timing generator & mmu if they are not started yet */ mdp4_overlay_dtv_start(); pipe = vctrl->base_pipe; spin_lock_irqsave(&vctrl->spin_lock, flags); if (pipe->ov_blt_addr) { mdp4_dtv_blt_ov_update(pipe); pipe->blt_ov_done++; vsync_irq_enable(INTR_OVERLAY1_DONE, MDP_OVERLAY1_TERM); mb(); pipe->blt_ov_koff++; /* kickoff overlay1 engine */ mdp4_stat.kickoff_ov1++; outpdw(MDP_BASE + 0x0008, 0); } else { /* schedule second phase update at dmap */ INIT_COMPLETION(vctrl->dmae_comp); vsync_irq_enable(INTR_DMA_E_DONE, MDP_DMA_E_TERM); } spin_unlock_irqrestore(&vctrl->spin_lock, flags); mdp4_stat.overlay_commit[pipe->mixer_num]++; if (wait) mdp4_dtv_wait4dmae(cndx); return cnt; }
int mdp4_dtv_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 cnt = 0; vctrl = &vsync_ctrl_db[cndx]; mutex_lock(&vctrl->update_lock); undx = vctrl->update_ndx; vp = &vctrl->vlist[undx]; pipe = vctrl->base_pipe; mixer = pipe->mixer_num; mdp4_overlay_iommu_unmap_freelist(mixer); if (vp->update_cnt == 0) { mutex_unlock(&vctrl->update_lock); return 0; } if(!dtv_pipe_ready) { for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { real_pipe = mdp4_overlay_ndx2pipe(i); if (real_pipe && real_pipe->pipe_used != 0 && real_pipe->pipe_type != OVERLAY_TYPE_BF && real_pipe->mixer_num == MDP4_MIXER1) { dtv_pipe_ready = true; break; } } if(!dtv_pipe_ready && dtv_enabled) { PR_DISP_INFO("Dtv real pipe is not ready, skip this time\n"); mutex_unlock(&vctrl->update_lock); return 0; } } vctrl->update_ndx++; vctrl->update_ndx &= 0x01; vp->update_cnt = 0; mutex_unlock(&vctrl->update_lock); pipe = vp->plist; for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { if (pipe->pipe_used) { cnt++; real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx); if (real_pipe && real_pipe->pipe_used) { mdp4_overlay_vsync_commit(pipe); } mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0); pipe->pipe_used = 0; } } mdp4_mixer_stage_commit(mixer); mdp4_overlay_dtv_start(); pipe = vctrl->base_pipe; spin_lock_irqsave(&vctrl->spin_lock, flags); if (pipe->ov_blt_addr) { mdp4_dtv_blt_ov_update(pipe); pipe->blt_ov_done++; vsync_irq_enable(INTR_OVERLAY1_DONE, MDP_OVERLAY1_TERM); mb(); pipe->blt_ov_koff++; mdp4_stat.kickoff_ov1++; outpdw(MDP_BASE + 0x0008, 0); } else { INIT_COMPLETION(vctrl->dmae_comp); vsync_irq_enable(INTR_DMA_E_DONE, MDP_DMA_E_TERM); } spin_unlock_irqrestore(&vctrl->spin_lock, flags); mdp4_stat.overlay_commit[pipe->mixer_num]++; if (wait) mdp4_dtv_wait4dmae(cndx); return cnt; }
int mdp4_dsi_video_on(struct platform_device *pdev) { int dsi_width; int dsi_height; int dsi_bpp; int dsi_border_clr; int dsi_underflow_clr; int dsi_hsync_skew; int hsync_period; int hsync_ctrl; int vsync_period; int display_hctl; int display_v_start; int display_v_end; int active_hctl; int active_h_start; int active_h_end; int active_v_start; int active_v_end; int ctrl_polarity; int h_back_porch; int h_front_porch; int v_back_porch; int v_front_porch; int hsync_pulse_width; int vsync_pulse_width; int hsync_polarity; int vsync_polarity; int data_en_polarity; int hsync_start_x; int hsync_end_x; uint8 *buf; unsigned int buf_offset; int bpp, ptype; struct fb_info *fbi; struct fb_var_screeninfo *var; struct msm_fb_data_type *mfd; struct mdp4_overlay_pipe *pipe; int ret = 0; int cndx = 0; struct vsycn_ctrl *vctrl; struct msm_panel_info *pinfo; vctrl = &vsync_ctrl_db[cndx]; mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); pinfo = &mfd->panel_info; if (!mfd) return -ENODEV; if (mfd->key != MFD_KEY) return -EINVAL; vctrl->mfd = mfd; vctrl->dev = mfd->fbi->dev; vctrl->blt_ctrl = pinfo->lcd.blt_ctrl; /* mdp clock on */ mdp_clk_ctrl(1); fbi = mfd->fbi; var = &fbi->var; bpp = fbi->var.bits_per_pixel / 8; buf = (uint8 *) fbi->fix.smem_start; buf_offset = calc_fb_offset(mfd, fbi, bpp); if (vctrl->base_pipe == NULL) { ptype = mdp4_overlay_format2type(mfd->fb_imgType); if (ptype < 0) printk(KERN_INFO "%s: format2type failed\n", __func__); pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0); if (pipe == NULL) { printk(KERN_INFO "%s: pipe_alloc failed\n", __func__); return -EBUSY; } pipe->pipe_used++; pipe->mixer_stage = MDP4_MIXER_STAGE_BASE; pipe->mixer_num = MDP4_MIXER0; pipe->src_format = mfd->fb_imgType; mdp4_overlay_panel_mode(pipe->mixer_num, MDP4_PANEL_DSI_VIDEO); ret = mdp4_overlay_format2pipe(pipe); if (ret < 0) printk(KERN_INFO "%s: format2type failed\n", __func__); pipe->ov_blt_addr = 0; pipe->dma_blt_addr = 0; vctrl->base_pipe = pipe; /* keep it */ mdp4_init_writeback_buf(mfd, MDP4_MIXER0); } else { pipe = vctrl->base_pipe; } if (!(mfd->cont_splash_done)) { mfd->cont_splash_done = 1; mdp4_dsi_video_wait4dmap_done(0); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0); mipi_dsi_controller_cfg(0); } pipe->src_height = fbi->var.yres; pipe->src_width = fbi->var.xres; pipe->src_h = fbi->var.yres; pipe->src_w = fbi->var.xres; pipe->src_y = 0; pipe->src_x = 0; pipe->dst_h = fbi->var.yres; pipe->dst_w = fbi->var.xres; pipe->srcp0_ystride = fbi->fix.line_length; pipe->bpp = bpp; if (mfd->map_buffer) { pipe->srcp0_addr = (unsigned int)mfd->map_buffer->iova[0] + \ buf_offset; pr_debug("start 0x%lx srcp0_addr 0x%x\n", mfd-> map_buffer->iova[0], pipe->srcp0_addr); } else { pipe->srcp0_addr = (uint32)(buf + buf_offset); } pipe->dst_h = fbi->var.yres; pipe->dst_w = fbi->var.xres; mdp4_overlay_mdp_pipe_req(pipe, mfd); atomic_set(&vctrl->suspend, 0); mdp4_overlay_dmap_xy(pipe); /* dma_p */ mdp4_overlay_dmap_cfg(mfd, 1); mdp4_overlay_rgb_setup(pipe); mdp4_overlayproc_cfg(pipe); mdp4_overlay_reg_flush(pipe, 1); mdp4_mixer_stage_up(pipe, 0); mdp4_mixer_stage_commit(pipe->mixer_num); /* * DSI timing setting */ h_back_porch = var->left_margin; h_front_porch = var->right_margin; v_back_porch = var->upper_margin; v_front_porch = var->lower_margin; hsync_pulse_width = var->hsync_len; vsync_pulse_width = var->vsync_len; dsi_border_clr = mfd->panel_info.lcdc.border_clr; dsi_underflow_clr = mfd->panel_info.lcdc.underflow_clr; dsi_hsync_skew = mfd->panel_info.lcdc.hsync_skew; dsi_width = mfd->panel_info.xres + mfd->panel_info.lcdc.xres_pad; dsi_height = mfd->panel_info.yres + mfd->panel_info.lcdc.yres_pad; dsi_bpp = mfd->panel_info.bpp; hsync_period = hsync_pulse_width + h_back_porch + dsi_width + h_front_porch; hsync_ctrl = (hsync_period << 16) | hsync_pulse_width; hsync_start_x = h_back_porch + hsync_pulse_width; hsync_end_x = hsync_period - h_front_porch - 1; display_hctl = (hsync_end_x << 16) | hsync_start_x; vsync_period = (vsync_pulse_width + v_back_porch + dsi_height + v_front_porch); display_v_start = ((vsync_pulse_width + v_back_porch) * hsync_period) + dsi_hsync_skew; display_v_end = ((vsync_period - v_front_porch) * hsync_period) + dsi_hsync_skew - 1; if (dsi_width != var->xres) { active_h_start = hsync_start_x + first_pixel_start_x; active_h_end = active_h_start + var->xres - 1; active_hctl = ACTIVE_START_X_EN | (active_h_end << 16) | active_h_start; } else { active_hctl = 0; } if (dsi_height != var->yres) { active_v_start = display_v_start + first_pixel_start_y * hsync_period; active_v_end = active_v_start + (var->yres) * hsync_period - 1; active_v_start |= ACTIVE_START_Y_EN; } else { active_v_start = 0; active_v_end = 0; } dsi_underflow_clr |= 0x80000000; /* enable recovery */ hsync_polarity = 0; vsync_polarity = 0; data_en_polarity = 0; ctrl_polarity = (data_en_polarity << 2) | (vsync_polarity << 1) | (hsync_polarity); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x4, hsync_ctrl); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x8, vsync_period * hsync_period); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0xc, vsync_pulse_width * hsync_period); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x10, display_hctl); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x14, display_v_start); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x18, display_v_end); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x1c, active_hctl); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x20, active_v_start); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x24, active_v_end); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x28, dsi_border_clr); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x2c, dsi_underflow_clr); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x30, dsi_hsync_skew); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x38, ctrl_polarity); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); mdp_histogram_ctrl_all(TRUE); return ret; }
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; int clk_set_on = 0; vctrl = &vsync_ctrl_db[0]; #ifdef FACTORY_TEST if (!is_lcd_connected) return 0; #endif mutex_lock(&vctrl->update_lock); undx = vctrl->update_ndx; vp = &vctrl->vlist[undx]; pipe = vctrl->base_pipe; if (pipe == NULL) { pr_err("%s: NO base pipe\n", __func__); mutex_unlock(&vctrl->update_lock); return 0; } mixer = pipe->mixer_num; /* * allow stage_commit without pipes queued * (vp->update_cnt == 0) to unstage pipes after * overlay_unset */ 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); if(wait == 1) { spin_lock_irqsave(&vctrl->spin_lock, flags); vctrl->clk_control = 0; vctrl->pan_display++; if (!vctrl->clk_enabled) { clk_set_on = 1; vctrl->clk_enabled = 1; } vctrl->expire_tick = VSYNC_EXPIRE_TICK; spin_unlock_irqrestore(&vctrl->spin_lock, flags); if (clk_set_on) { pr_err("%s: warning, clock off while pan display\n", __func__); pr_debug("%s: SET_CLK_ON\n", __func__); mipi_dsi_clk_cfg(1); mdp_clk_ctrl(1); vsync_irq_enable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM); } } if (mdp4_dsi_cmd_clk_check(vctrl) < 0) return 0; /* 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; else 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); if (need_dmap_wait) { pr_debug("%s: wait4dmap\n", __func__); mdp4_dsi_cmd_wait4dmap(0); } #if defined(CONFIG_FB_MSM_MIPI_NOVATEK_CMD_WVGA_PT) \ || defined(CONFIG_FB_MSM_MIPI_NOVATEK_BOE_CMD_WVGA_PT) \ || defined(CONFIG_FB_MSM_MIPI_SAMSUNG_OLED_CMD_QHD_PT) if(mdp_lut_push) { mipi_dsi_mdp_busy_wait(); mdp_lut_enable(); } #endif if (need_ov_wait) { pr_debug("#### %s: wait4ov\n", __func__); vsync_irq_enable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM); outpdw(MDP_BASE + 0x0004, 0); mb(); 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; } } if (vctrl->blt_change) { mdp4_overlayproc_cfg(pipe); mdp4_overlay_dmap_xy(pipe); vctrl->blt_change = 0; } pipe = vp->plist; for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { if (pipe->pipe_used) { 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); 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]++; if (wait) mdp4_dsi_cmd_wait4vsync(0); return cnt; }
int mdp4_dtv_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 cnt = 0; vctrl = &vsync_ctrl_db[cndx]; mutex_lock(&vctrl->update_lock); undx = vctrl->update_ndx; vp = &vctrl->vlist[undx]; pipe = vctrl->base_pipe; mixer = pipe->mixer_num; mdp4_overlay_iommu_unmap_freelist(mixer); if (vp->update_cnt == 0) { mutex_unlock(&vctrl->update_lock); return 0; } /* HTC FIXME: Sometime the mdp hang happened if mdp only create HDMI base pipe and do mdp4_dtv_pipe_commit. So checking all mdp pipe to prevent fail condition happened. */ if(!dtv_pipe_ready) { for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { real_pipe = mdp4_overlay_ndx2pipe(i); if (real_pipe && real_pipe->pipe_used != 0 && real_pipe->pipe_type != OVERLAY_TYPE_BF && real_pipe->mixer_num == MDP4_MIXER1) { dtv_pipe_ready = true; break; } } if(!dtv_pipe_ready && dtv_enabled) { PR_DISP_INFO("Dtv real pipe is not ready, skip this time\n"); mutex_unlock(&vctrl->update_lock); return 0; } } vctrl->update_ndx++; vctrl->update_ndx &= 0x01; vp->update_cnt = 0; /* reset */ mutex_unlock(&vctrl->update_lock); pipe = vp->plist; for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { if (pipe->pipe_used) { 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 */ } } mdp4_mixer_stage_commit(mixer); /* start timing generator & mmu if they are not started yet */ mdp4_overlay_dtv_start(); pipe = vctrl->base_pipe; spin_lock_irqsave(&vctrl->spin_lock, flags); if (pipe->ov_blt_addr) { mdp4_dtv_blt_ov_update(pipe); pipe->blt_ov_done++; vsync_irq_enable(INTR_OVERLAY1_DONE, MDP_OVERLAY1_TERM); mb(); pipe->blt_ov_koff++; /* kickoff overlay1 engine */ mdp4_stat.kickoff_ov1++; outpdw(MDP_BASE + 0x0008, 0); } else { /* schedule second phase update at dmap */ INIT_COMPLETION(vctrl->dmae_comp); vsync_irq_enable(INTR_DMA_E_DONE, MDP_DMA_E_TERM); } spin_unlock_irqrestore(&vctrl->spin_lock, flags); mdp4_stat.overlay_commit[pipe->mixer_num]++; if (wait) mdp4_dtv_wait4dmae(cndx); return cnt; }
int mdp4_dsi_video_pipe_commit(int cndx, int wait, u32 *release_busy) { 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 cnt = 0; vctrl = &vsync_ctrl_db[cndx]; mutex_lock(&vctrl->update_lock); undx = vctrl->update_ndx; vp = &vctrl->vlist[undx]; pipe = vctrl->base_pipe; if (pipe == NULL) { pr_err("%s: NO base pipe\n", __func__); mutex_unlock(&vctrl->update_lock); return 0; } mixer = pipe->mixer_num; mdp_update_pm(vctrl->mfd, vctrl->vsync_time); /* * allow stage_commit without pipes queued * (vp->update_cnt == 0) to unstage pipes after * overlay_unset */ 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 (vctrl->ov_koff != vctrl->ov_done) { spin_unlock_irqrestore(&vctrl->spin_lock, flags); pr_err("%s: Error, frame dropped %d %d\n", __func__, vctrl->ov_koff, vctrl->ov_done); return 0; } spin_unlock_irqrestore(&vctrl->spin_lock, flags); pipe = vp->plist; for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { if (pipe->pipe_used) { 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 */ } } mdp4_mixer_stage_commit(mixer); /* start timing generator & mmu if they are not started yet */ mdp4_overlay_dsi_video_start(); pipe = vctrl->base_pipe; spin_lock_irqsave(&vctrl->spin_lock, flags); if (pipe->ov_blt_addr) { mdp4_dsi_video_blt_ov_update(pipe); pipe->ov_cnt++; INIT_COMPLETION(vctrl->ov_comp); vsync_irq_enable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM); mb(); vctrl->ov_koff++; /* kickoff overlay engine */ mdp4_stat.kickoff_ov0++; outpdw(MDP_BASE + 0x0004, 0); } spin_unlock_irqrestore(&vctrl->spin_lock, flags); mdp4_stat.overlay_commit[pipe->mixer_num]++; if (wait) { if (release_busy) { msm_fb_release_busy(vctrl->mfd); *release_busy = false; mutex_unlock(&vctrl->mfd->dma->ov_mutex); } if (pipe->ov_blt_addr) mdp4_dsi_video_wait4ov(0); else mdp4_dsi_video_wait4vsync(0); } return cnt; }
int mdp4_dtv_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 cnt = 0; vctrl = &vsync_ctrl_db[cndx]; mutex_lock(&vctrl->update_lock); undx = vctrl->update_ndx; vp = &vctrl->vlist[undx]; pipe = vctrl->base_pipe; if (pipe == NULL) { pr_err("%s: NO base pipe\n", __func__); mutex_unlock(&vctrl->update_lock); return 0; } mixer = pipe->mixer_num; mdp_update_pm(vctrl->mfd, vctrl->vsync_time); /* * allow stage_commit without pipes queued * (vp->update_cnt == 0) to unstage pipes after * overlay_unset */ vctrl->update_ndx++; vctrl->update_ndx &= 0x01; vp->update_cnt = 0; /* reset */ mutex_unlock(&vctrl->update_lock); pipe = vp->plist; for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { if (pipe->pipe_used) { cnt++; real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx); if (real_pipe && real_pipe->pipe_used) { /* pipe not unset */ mdp4_overlay_vsync_commit(pipe); } } } mdp4_mixer_stage_commit(mixer); /* start timing generator & mmu if they are not started yet */ mdp4_overlay_dtv_start(); /* * there has possibility that pipe commit come very close to next vsync * this may cause two consecutive pie_commits happen within same vsync * period which casue iommu page fault when previous iommu buffer * freed. Set ION_IOMMU_UNMAP_DELAYED flag at ion_map_iommu() to * add delay unmap iommu buffer to fix this problem. * Also ion_unmap_iommu() may take as long as 9 ms to free an ion buffer. * therefore mdp4_overlay_iommu_unmap_freelist(mixer) should be called * ater stage_commit() to ensure pipe_commit (up to stage_commit) * is completed within vsync period. */ /* free previous committed iommu back to pool */ mdp4_overlay_iommu_unmap_freelist(mixer); pipe = vp->plist; for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { if (pipe->pipe_used) { /* 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 */ } } pipe = vctrl->base_pipe; spin_lock_irqsave(&vctrl->spin_lock, flags); if (pipe->ov_blt_addr) { mdp4_dtv_blt_ov_update(pipe); pipe->blt_ov_done++; vsync_irq_enable(INTR_OVERLAY1_DONE, MDP_OVERLAY1_TERM); mb(); pipe->blt_ov_koff++; /* kickoff overlay1 engine */ mdp4_stat.kickoff_ov1++; outpdw(MDP_BASE + 0x0008, 0); } else { /* schedule second phase update at dmap */ INIT_COMPLETION(vctrl->dmae_comp); vsync_irq_enable(INTR_DMA_E_DONE, MDP_DMA_E_TERM); } spin_unlock_irqrestore(&vctrl->spin_lock, flags); mdp4_stat.overlay_commit[pipe->mixer_num]++; if (wait) mdp4_dtv_wait4dmae(0); return cnt; }
int mdp4_dtv_pipe_commit(void) { 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 cnt = 0; 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; mdp4_overlay_iommu_unmap_freelist(mixer); if (vp->update_cnt == 0) { mutex_unlock(&vctrl->update_lock); return 0; } vctrl->update_ndx++; vctrl->update_ndx &= 0x01; vp->update_cnt = 0; mutex_unlock(&vctrl->update_lock); pipe = vp->plist; for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { if (pipe->pipe_used) { cnt++; real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx); if (real_pipe && real_pipe->pipe_used) { mdp4_overlay_vsync_commit(pipe); } mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0); pipe->pipe_used = 0; } } mdp4_mixer_stage_commit(mixer); mdp4_overlay_dtv_start(); pipe = vctrl->base_pipe; spin_lock_irqsave(&vctrl->spin_lock, flags); if (pipe->ov_blt_addr) { mdp4_dtv_blt_ov_update(pipe); pipe->blt_ov_done++; vsync_irq_enable(INTR_OVERLAY1_DONE, MDP_OVERLAY1_TERM); mb(); pipe->blt_ov_koff++; mdp4_stat.kickoff_ov1++; outpdw(MDP_BASE + 0x0008, 0); } else { INIT_COMPLETION(vctrl->dmae_comp); vsync_irq_enable(INTR_DMA_E_DONE, MDP_DMA_E_TERM); } spin_unlock_irqrestore(&vctrl->spin_lock, flags); mdp4_stat.overlay_commit[pipe->mixer_num]++; return cnt; }
int mdp4_lcdc_on(struct platform_device *pdev) { int lcdc_width; int lcdc_height; int lcdc_bpp; int lcdc_border_clr; int lcdc_underflow_clr; int lcdc_hsync_skew; int hsync_period; int hsync_ctrl; int vsync_period; int display_hctl; int display_v_start; int display_v_end; int active_hctl; int active_h_start; int active_h_end; int active_v_start; int active_v_end; int ctrl_polarity; int h_back_porch; int h_front_porch; int v_back_porch; int v_front_porch; int hsync_pulse_width; int vsync_pulse_width; int hsync_polarity; int vsync_polarity; int data_en_polarity; int hsync_start_x; int hsync_end_x; uint8 *buf; unsigned int buf_offset; int bpp, ptype; struct fb_info *fbi; struct fb_var_screeninfo *var; struct msm_fb_data_type *mfd; struct mdp4_overlay_pipe *pipe; int ret = 0; int cndx = 0; struct vsycn_ctrl *vctrl; vctrl = &vsync_ctrl_db[cndx]; mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); if (!mfd) return -ENODEV; if (mfd->key != MFD_KEY) return -EINVAL; vctrl->mfd = mfd; vctrl->dev = mfd->fbi->dev; /* mdp clock on */ mdp_clk_ctrl(1); fbi = mfd->fbi; var = &fbi->var; bpp = fbi->var.bits_per_pixel / 8; buf = (uint8 *) fbi->fix.smem_start; buf_offset = calc_fb_offset(mfd, fbi, bpp); if (vctrl->base_pipe == NULL) { ptype = mdp4_overlay_format2type(mfd->fb_imgType); if (ptype < 0) printk(KERN_INFO "%s: format2type failed\n", __func__); pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0); if (pipe == NULL) printk(KERN_INFO "%s: pipe_alloc failed\n", __func__); pipe->pipe_used++; pipe->mixer_stage = MDP4_MIXER_STAGE_BASE; pipe->mixer_num = MDP4_MIXER0; pipe->src_format = mfd->fb_imgType; mdp4_overlay_panel_mode(pipe->mixer_num, MDP4_PANEL_LCDC); ret = mdp4_overlay_format2pipe(pipe); if (ret < 0) printk(KERN_INFO "%s: format2pipe failed\n", __func__); mdp4_init_writeback_buf(mfd, MDP4_MIXER0); pipe->ov_blt_addr = 0; pipe->dma_blt_addr = 0; vctrl->base_pipe = pipe; /* keep it */ } else { pipe = vctrl->base_pipe; } pipe->src_height = fbi->var.yres; pipe->src_width = fbi->var.xres; pipe->src_h = fbi->var.yres; pipe->src_w = fbi->var.xres; pipe->src_y = 0; pipe->src_x = 0; pipe->dst_h = fbi->var.yres; pipe->dst_w = fbi->var.xres; if (mfd->map_buffer) { pipe->srcp0_addr = (unsigned int)mfd->map_buffer->iova[0] + \ buf_offset; pr_debug("start 0x%lx srcp0_addr 0x%x\n", mfd-> map_buffer->iova[0], pipe->srcp0_addr); } else { pipe->srcp0_addr = (uint32)(buf + buf_offset); } pipe->srcp0_ystride = fbi->fix.line_length; pipe->bpp = bpp; mdp4_overlay_mdp_pipe_req(pipe, mfd); atomic_set(&vctrl->suspend, 0); mdp4_overlay_dmap_xy(pipe); mdp4_overlay_dmap_cfg(mfd, 1); mdp4_overlay_rgb_setup(pipe); mdp4_overlayproc_cfg(pipe); mdp4_overlay_reg_flush(pipe, 1); mdp4_mixer_stage_up(pipe, 0); mdp4_mixer_stage_commit(pipe->mixer_num); /* * LCDC timing setting */ h_back_porch = var->left_margin; h_front_porch = var->right_margin; v_back_porch = var->upper_margin; v_front_porch = var->lower_margin; hsync_pulse_width = var->hsync_len; vsync_pulse_width = var->vsync_len; lcdc_border_clr = mfd->panel_info.lcdc.border_clr; lcdc_underflow_clr = mfd->panel_info.lcdc.underflow_clr; lcdc_hsync_skew = mfd->panel_info.lcdc.hsync_skew; lcdc_width = var->xres + mfd->panel_info.lcdc.xres_pad; lcdc_height = var->yres + mfd->panel_info.lcdc.yres_pad; lcdc_bpp = mfd->panel_info.bpp; hsync_period = hsync_pulse_width + h_back_porch + lcdc_width + h_front_porch; hsync_ctrl = (hsync_period << 16) | hsync_pulse_width; hsync_start_x = hsync_pulse_width + h_back_porch; hsync_end_x = hsync_period - h_front_porch - 1; display_hctl = (hsync_end_x << 16) | hsync_start_x; vsync_period = (vsync_pulse_width + v_back_porch + lcdc_height + v_front_porch) * hsync_period; display_v_start = (vsync_pulse_width + v_back_porch) * hsync_period + lcdc_hsync_skew; display_v_end = vsync_period - (v_front_porch * hsync_period) + lcdc_hsync_skew - 1; if (lcdc_width != var->xres) { active_h_start = hsync_start_x + first_pixel_start_x; active_h_end = active_h_start + var->xres - 1; active_hctl = ACTIVE_START_X_EN | (active_h_end << 16) | active_h_start; } else { active_hctl = 0; } if (lcdc_height != var->yres) { active_v_start = display_v_start + first_pixel_start_y * hsync_period; active_v_end = active_v_start + (var->yres) * hsync_period - 1; active_v_start |= ACTIVE_START_Y_EN; } else { active_v_start = 0; active_v_end = 0; } #ifdef CONFIG_FB_MSM_MDP40 hsync_polarity = 1; vsync_polarity = 1; lcdc_underflow_clr |= 0x80000000; /* enable recovery */ #else hsync_polarity = 0; vsync_polarity = 0; #endif #if defined(CONFIG_MACH_ARIESVE) || defined(CONFIG_MACH_APACHE) data_en_polarity = 1; #else data_en_polarity = 0; #endif ctrl_polarity = (data_en_polarity << 2) | (vsync_polarity << 1) | (hsync_polarity); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); MDP_OUTP(MDP_BASE + LCDC_BASE + 0x4, hsync_ctrl); MDP_OUTP(MDP_BASE + LCDC_BASE + 0x8, vsync_period); MDP_OUTP(MDP_BASE + LCDC_BASE + 0xc, vsync_pulse_width * hsync_period); MDP_OUTP(MDP_BASE + LCDC_BASE + 0x10, display_hctl); MDP_OUTP(MDP_BASE + LCDC_BASE + 0x14, display_v_start); MDP_OUTP(MDP_BASE + LCDC_BASE + 0x18, display_v_end); MDP_OUTP(MDP_BASE + LCDC_BASE + 0x28, lcdc_border_clr); MDP_OUTP(MDP_BASE + LCDC_BASE + 0x2c, lcdc_underflow_clr); MDP_OUTP(MDP_BASE + LCDC_BASE + 0x30, lcdc_hsync_skew); MDP_OUTP(MDP_BASE + LCDC_BASE + 0x38, ctrl_polarity); MDP_OUTP(MDP_BASE + LCDC_BASE + 0x1c, active_hctl); MDP_OUTP(MDP_BASE + LCDC_BASE + 0x20, active_v_start); MDP_OUTP(MDP_BASE + LCDC_BASE + 0x24, active_v_end); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); mdp_histogram_ctrl_all(TRUE); #if defined(CONFIG_MACH_ANCORA) || defined(CONFIG_MACH_ANCORA_TMO) if (board_lcd_hw_revision == 3) { ret = panel_next_on(pdev); if (ret == 0) { /* enable LCDC block */ MDP_OUTP(MDP_BASE + LCDC_BASE, 1); mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_ON, FALSE); } /* MDP cmd block disable */ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); } else { /* * LCDC Block must be enabled before the time of turn on lcd * because of the signal timing. */ mdp4_overlay_lcdc_start(); } #else /* * LCDC Block must be enabled before the time of turn on lcd * because of the signal timing. */ mdp4_overlay_lcdc_start(); #endif if (!vctrl->sysfs_created) { ret = sysfs_create_group(&vctrl->dev->kobj, &vsync_fs_attr_group); if (ret) { pr_err("%s: sysfs group creation failed, ret=%d\n", __func__, ret); return ret; } kobject_uevent(&vctrl->dev->kobj, KOBJ_ADD); pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__); vctrl->sysfs_created = 1; } return ret; }
int mdp4_overlay_writeback_update(struct msm_fb_data_type *mfd, struct mdp4_overlay_pipe *ov_pipe) { struct fb_info *fbi; uint8 *buf; unsigned int buf_offset; struct mdp4_overlay_pipe *pipe; int bpp; if (mfd->key != MFD_KEY) return -ENODEV; if (!writeback_pipe) return -EINVAL; fbi = mfd->fbi; pipe = writeback_pipe; bpp = fbi->var.bits_per_pixel / 8; buf = (uint8 *) fbi->fix.smem_start; buf_offset = fbi->var.xoffset * bpp + fbi->var.yoffset * fbi->fix.line_length; mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); if (ov_pipe && (ov_pipe->flags & MDP_BLIT_NON_CACHED)) { pipe->src_width = ov_pipe->dst_w; pipe->src_height = ov_pipe->dst_h; pipe->src_w = ov_pipe->dst_w; pipe->src_h = ov_pipe->dst_h; if(ov_pipe->src_format == MDP_Y_CBCR_H2V2 || ov_pipe->src_format == MDP_Y_CRCB_H2V2) { pipe->src_width = ov_pipe->dst_w; pipe->src_height = ov_pipe->dst_h; pipe->src_w = ov_pipe->dst_w; pipe->src_h = ov_pipe->dst_h; } pipe->dst_w = ov_pipe->dst_w; pipe->dst_h = ov_pipe->dst_h; pipe->srcp0_ystride = ov_pipe->dst_w * 2; pipe->src_x = ov_pipe->src_x; pipe->src_y = ov_pipe->src_y; pipe->dst_x = ov_pipe->dst_x; pipe->dst_y = ov_pipe->dst_y; } else { pipe->src_height = fbi->var.yres; pipe->src_width = fbi->var.xres; pipe->src_h = fbi->var.yres; pipe->src_w = fbi->var.xres; pipe->dst_h = fbi->var.yres; pipe->dst_w = fbi->var.xres; pipe->srcp0_ystride = fbi->fix.line_length; pipe->src_y = 0; pipe->src_x = 0; pipe->dst_y = 0; pipe->dst_x = 0; } mdp4_overlay_mdp_pipe_req(pipe, mfd); if (mfd->display_iova) pipe->srcp0_addr = mfd->display_iova + buf_offset; else pipe->srcp0_addr = (uint32)(buf + buf_offset); mdp4_mixer_stage_up(pipe, 0); mdp4_overlayproc_cfg(pipe); mdp4_mixer_stage_commit(pipe->mixer_num); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); wmb(); return 0; }