static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable) { struct mdp3_session_data *mdp3_session; struct mdp3_notification vsync_client; struct mdp3_notification *arg = NULL; pr_debug("mdp3_ctrl_vsync_enable =%d\n", enable); mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma || !mdp3_session->intf) return -ENODEV; if (!mdp3_session->status) { pr_debug("fb%d is not on yet", mfd->index); return -EINVAL; } if (enable) { vsync_client.handler = vsync_notify_handler; vsync_client.arg = mdp3_session; arg = &vsync_client; } else if (atomic_read(&mdp3_session->vsync_countdown)) { /* * Now that vsync is no longer needed we will * shutdown dsi clocks as soon as cnt down == 0 * for cmd mode panels */ vsync_client.handler = vsync_count_down; vsync_client.arg = mdp3_session; arg = &vsync_client; enable = 1; } mdp3_clk_enable(1, 0); mdp3_session->dma->vsync_enable(mdp3_session->dma, arg); mdp3_clk_enable(0, 0); /* * Need to fake vsync whenever dsi interface is not * active or when dsi clocks are currently off */ if (enable && mdp3_session->status == 1 && (mdp3_session->vsync_before_commit || !mdp3_session->intf->active)) { mod_timer(&mdp3_session->vsync_timer, jiffies + msecs_to_jiffies(mdp3_session->vsync_period)); } else if (enable && !mdp3_session->clk_on) { mdp3_ctrl_reset_countdown(mdp3_session, mfd); mdp3_ctrl_clk_enable(mfd, 1); } else if (!enable) { del_timer(&mdp3_session->vsync_timer); } return 0; }
static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable) { struct mdp3_session_data *mdp3_session; struct mdp3_notification vsync_client; struct mdp3_notification *arg = NULL; pr_debug("mdp3_ctrl_vsync_enable =%d\n", enable); mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma || !mdp3_session->intf) return -ENODEV; if (!mdp3_session->status) { pr_debug("fb%d is not on yet", mfd->index); return -EINVAL; } if (enable) { vsync_client.handler = vsync_notify_handler; vsync_client.arg = mdp3_session; arg = &vsync_client; } else if (atomic_read(&mdp3_session->vsync_countdown)) { vsync_client.handler = vsync_count_down; vsync_client.arg = mdp3_session; arg = &vsync_client; enable = 1; } mdp3_clk_enable(1, 0); mdp3_session->dma->vsync_enable(mdp3_session->dma, arg); mdp3_clk_enable(0, 0); if (enable && mdp3_session->status == 1 && (mdp3_session->vsync_before_commit || !mdp3_session->intf->active)) { mod_timer(&mdp3_session->vsync_timer, jiffies + msecs_to_jiffies(mdp3_session->vsync_period)); } else if (enable && !mdp3_session->clk_on) { mdp3_ctrl_reset_countdown(mdp3_session, mfd); mdp3_ctrl_clk_enable(mfd, 1); } else if (!enable) { del_timer(&mdp3_session->vsync_timer); } return 0; }
static void mdp3_dispatch_clk_off(struct work_struct *work) { struct mdp3_session_data *session; pr_debug("%s\n", __func__); session = container_of(work, struct mdp3_session_data, clk_off_work); if (!session) return; mutex_lock(&session->lock); if (session->vsync_enabled || atomic_read(&session->vsync_countdown) != 0) { mutex_unlock(&session->lock); pr_debug("Ignoring clk shut down\n"); return; } mdp3_ctrl_vsync_enable(session->mfd, 0); mdp3_ctrl_clk_enable(session->mfd, 0); mutex_unlock(&session->lock); }
static int mdp3_ctrl_display_commit_kickoff(struct msm_fb_data_type *mfd, struct mdp_display_commit *cmt_data) { struct mdp3_session_data *mdp3_session; struct mdp3_img_data *data; struct mdss_panel_info *panel_info; int rc = 0; bool reset_done = false; struct mdss_panel_data *panel; if (!mfd || !mfd->mdp.private1) return -EINVAL; panel_info = mfd->panel_info; mdp3_session = mfd->mdp.private1; if (!mdp3_session || !mdp3_session->dma) return -EINVAL; if (mdp3_bufq_count(&mdp3_session->bufq_in) == 0) { pr_debug("no buffer in queue yet\n"); return -EPERM; } panel = mdp3_session->panel; if (mdp3_session->in_splash_screen) { pr_debug("continuous splash screen, IOMMU not attached\n"); rc = mdp3_ctrl_reset(mfd); if (rc) { pr_err("fail to reset display\n"); return -EINVAL; } reset_done = true; } mutex_lock(&mdp3_session->lock); if (!mdp3_session->status) { pr_err("%s, display off!\n", __func__); mutex_unlock(&mdp3_session->lock); return -EPERM; } mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_BEGIN); data = mdp3_bufq_pop(&mdp3_session->bufq_in); if (data) { mdp3_ctrl_reset_countdown(mdp3_session, mfd); mdp3_ctrl_clk_enable(mfd, 1); rc = mdp3_session->dma->update(mdp3_session->dma, (void *)(int)data->addr, mdp3_session->intf); /* This is for the previous frame */ if (rc < 0) { mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_TIMEOUT); } else { if (mdp3_ctrl_get_intf_type(mfd) == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) { mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_DONE); } } mdp3_session->dma_active = 1; init_completion(&mdp3_session->dma_completion); mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_FLUSHED); mdp3_bufq_push(&mdp3_session->bufq_out, data); } if (mdp3_bufq_count(&mdp3_session->bufq_out) > 1) { mdp3_release_splash_memory(mfd); data = mdp3_bufq_pop(&mdp3_session->bufq_out); if (data) mdp3_put_img(data, MDP3_CLIENT_DMA_P); } if (mdp3_session->first_commit) { /*wait for one frame time to ensure frame is sent to panel*/ msleep(1000 / panel_info->mipi.frame_rate); mdp3_session->first_commit = false; } mdp3_session->vsync_before_commit = 0; if (reset_done && (panel && panel->set_backlight)) panel->set_backlight(panel, panel->panel_info.bl_max); mutex_unlock(&mdp3_session->lock); mdss_fb_update_notify_update(mfd); return 0; }
static int mdp3_ctrl_off(struct msm_fb_data_type *mfd) { int rc = 0; struct mdp3_session_data *mdp3_session; struct mdss_panel_data *panel; pr_debug("mdp3_ctrl_off\n"); mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma || !mdp3_session->intf) { pr_err("mdp3_ctrl_on no device"); return -ENODEV; } panel = mdp3_session->panel; mutex_lock(&mdp3_session->lock); if (panel && panel->set_backlight) panel->set_backlight(panel, 0); if (!mdp3_session->status) { pr_debug("fb%d is off already", mfd->index); goto off_error; } mdp3_ctrl_clk_enable(mfd, 1); mdp3_histogram_stop(mdp3_session, MDP_BLOCK_DMA_P); if (panel->event_handler) rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF, NULL); if (rc) pr_err("fail to turn off the panel\n"); rc = mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf); if (rc) pr_debug("fail to stop the MDP3 dma\n"); /* Wait for TG to turn off */ msleep(20); mdp3_irq_deregister(); pr_debug("mdp3_ctrl_off stop clock\n"); if (mdp3_session->clk_on) { rc = mdp3_res_update(0, 1, MDP3_CLIENT_DMA_P); if (rc) pr_err("mdp clock resource release failed\n"); pr_debug("mdp3_ctrl_off stop dsi controller\n"); if (panel->event_handler) rc = panel->event_handler(panel, MDSS_EVENT_BLANK, NULL); if (rc) pr_err("fail to turn off the panel\n"); } mdp3_ctrl_notifier_unregister(mdp3_session, &mdp3_session->mfd->mdp_sync_pt_data.notifier); mdp3_enable_regulator(false); mdp3_session->vsync_enabled = 0; atomic_set(&mdp3_session->vsync_countdown, 0); atomic_set(&mdp3_session->dma_done_cnt, 0); mdp3_session->clk_on = 0; mdp3_session->in_splash_screen = 0; off_error: mdp3_session->status = 0; mdp3_bufq_deinit(&mdp3_session->bufq_out); if (mdp3_session->overlay.id != MSMFB_NEW_REQUEST) { mdp3_session->overlay.id = MSMFB_NEW_REQUEST; mdp3_bufq_deinit(&mdp3_session->bufq_in); } mutex_unlock(&mdp3_session->lock); return 0; }
static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd) { struct fb_info *fbi; struct mdp3_session_data *mdp3_session; u32 offset; int bpp; struct mdss_panel_info *panel_info; int rc; pr_debug("mdp3_ctrl_pan_display\n"); if (!mfd || !mfd->mdp.private1) return; panel_info = mfd->panel_info; mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; if (!mdp3_session || !mdp3_session->dma) return; if (mdp3_session->in_splash_screen) { pr_debug("continuous splash screen, IOMMU not attached\n"); rc = mdp3_ctrl_reset(mfd); if (rc) { pr_err("fail to reset display\n"); return; } } mutex_lock(&mdp3_session->lock); if (!mdp3_session->status) { pr_err("mdp3_ctrl_pan_display, display off!\n"); goto pan_error; } fbi = mfd->fbi; bpp = fbi->var.bits_per_pixel / 8; offset = fbi->var.xoffset * bpp + fbi->var.yoffset * fbi->fix.line_length; if (offset > fbi->fix.smem_len) { pr_err("invalid fb offset=%u total length=%u\n", offset, fbi->fix.smem_len); goto pan_error; } if (mfd->fbi->screen_base) { mdp3_ctrl_reset_countdown(mdp3_session, mfd); mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_BEGIN); mdp3_ctrl_clk_enable(mfd, 1); rc = mdp3_session->dma->update(mdp3_session->dma, (void *)(int)(mfd->iova + offset), mdp3_session->intf); /* This is for the previous frame */ if (rc < 0) { mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_TIMEOUT); } else { if (mdp3_ctrl_get_intf_type(mfd) == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) { mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_DONE); } } mdp3_session->dma_active = 1; init_completion(&mdp3_session->dma_completion); mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_FLUSHED); } else { pr_debug("mdp3_ctrl_pan_display no memory, stop interface"); mdp3_clk_enable(1, 0); mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf); mdp3_clk_enable(0, 0); } if (mdp3_session->first_commit) { /*wait for one frame time to ensure frame is sent to panel*/ msleep(1000 / panel_info->mipi.frame_rate); mdp3_session->first_commit = false; } mdp3_session->vsync_before_commit = 0; pan_error: mutex_unlock(&mdp3_session->lock); }
static int mdp3_ctrl_off(struct msm_fb_data_type *mfd) { int rc = 0; struct mdp3_session_data *mdp3_session; struct mdss_panel_data *panel; pr_debug("mdp3_ctrl_off\n"); mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma || !mdp3_session->intf) { pr_err("mdp3_ctrl_on no device"); return -ENODEV; } panel = mdp3_session->panel; mutex_lock(&mdp3_session->lock); if (!mdp3_session->status) { pr_debug("fb%d is off already", mfd->index); goto off_error; } mdp3_ctrl_clk_enable(mfd, 1); mdp3_histogram_stop(mdp3_session, MDP_BLOCK_DMA_P); rc = mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf); if (rc) pr_debug("fail to stop the MDP3 dma\n"); if (panel->event_handler) rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF, NULL); if (rc) pr_err("fail to turn off the panel\n"); mdp3_irq_deregister(); pr_debug("mdp3_ctrl_off stop clock\n"); if (mdp3_session->clk_on) { rc = mdp3_clk_enable(0, 1); if (rc) pr_err("mdp clock resource release failed\n"); pr_debug("mdp3_ctrl_off stop dsi controller\n"); if (panel->event_handler) rc = panel->event_handler(panel, MDSS_EVENT_BLANK, NULL); if (rc) pr_err("fail to turn off the panel\n"); } mdp3_clk_unprepare(); pr_debug("mdp3_ctrl_off release bus\n"); rc = mdp3_ctrl_res_req_bus(mfd, 0); if (rc) pr_err("mdp bus resource release failed\n"); rc = mdp3_iommu_disable(MDP3_CLIENT_DMA_P); if (rc) pr_err("fail to dettach MDP DMA SMMU\n"); mdp3_ctrl_notifier_unregister(mdp3_session, &mdp3_session->mfd->mdp_sync_pt_data.notifier); mdp3_batfet_ctrl(false); mdp3_session->vsync_enabled = 0; atomic_set(&mdp3_session->vsync_countdown, 0); mdp3_session->clk_on = 0; off_error: mdp3_session->status = 0; mdp3_bufq_deinit(&mdp3_session->bufq_out); mutex_unlock(&mdp3_session->lock); if (mdp3_session->overlay.id != MSMFB_NEW_REQUEST) mdp3_overlay_unset(mfd, mdp3_session->overlay.id); return 0; }
static int mdp3_ctrl_display_commit_kickoff(struct msm_fb_data_type *mfd, struct mdp_display_commit *cmt_data) { struct mdp3_session_data *mdp3_session; struct mdp3_img_data *data; struct mdss_panel_info *panel_info = mfd->panel_info; int rc = 0; bool reset_done = false; struct mdss_panel_data *panel; if (!mfd || !mfd->mdp.private1) return -EINVAL; mdp3_session = mfd->mdp.private1; if (!mdp3_session || !mdp3_session->dma) return -EINVAL; if (mdp3_bufq_count(&mdp3_session->bufq_in) == 0) { pr_debug("no buffer in queue yet\n"); return -EPERM; } panel = mdp3_session->panel; if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) { pr_debug("continuous splash screen, IOMMU not attached\n"); mdp3_ctrl_reset(mfd); reset_done = true; } mdp3_release_splash_memory(); mutex_lock(&mdp3_session->lock); if (!mdp3_session->status) { pr_err("%s, display off!\n", __func__); mutex_unlock(&mdp3_session->lock); return -EPERM; } data = mdp3_bufq_pop(&mdp3_session->bufq_in); if (data) { mdp3_ctrl_reset_countdown(mdp3_session, mfd); mdp3_ctrl_clk_enable(mfd, 1); mdp3_session->dma->update(mdp3_session->dma, (void *)data->addr, mdp3_session->intf); mdp3_bufq_push(&mdp3_session->bufq_out, data); } if (mdp3_bufq_count(&mdp3_session->bufq_out) > 2) { data = mdp3_bufq_pop(&mdp3_session->bufq_out); mdp3_put_img(data, MDP3_CLIENT_DMA_P); } if (mdp3_session->first_commit) { /*wait for one frame time to ensure frame is sent to panel*/ msleep(1000 / panel_info->mipi.frame_rate); mdp3_session->first_commit = false; } mdp3_session->vsync_before_commit = 0; if (reset_done && (panel && panel->set_backlight)){ #if defined(CONFIG_FB_MSM_MIPI_TIANMA_CMD_HVGA_PT) msleep(1); #endif panel->set_backlight(panel, panel->panel_info.bl_max); } mutex_unlock(&mdp3_session->lock); mdss_fb_update_notify_update(mfd); return rc; }
static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd) { struct fb_info *fbi; struct mdp3_session_data *mdp3_session; u32 offset; int bpp; struct mdss_panel_info *panel_info = mfd->panel_info; #if defined(CONFIG_FB_MSM_MIPI_TIANMA_CMD_HVGA_PT) || defined(CONFIG_MACH_MSM8X10_W5) || defined(CONFIG_MACH_MSM8X10_W6) bool reset_done = false; struct mdss_panel_data *panel; #endif pr_debug("mdp3_ctrl_pan_display\n"); if (!mfd || !mfd->mdp.private1) return; mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; if (!mdp3_session || !mdp3_session->dma) return; #if defined(CONFIG_FB_MSM_MIPI_TIANMA_CMD_HVGA_PT) || defined(CONFIG_MACH_MSM8X10_W5) || defined(CONFIG_MACH_MSM8X10_W6) panel = mdp3_session->panel; #endif if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) { pr_debug("continuous splash screen, IOMMU not attached\n"); mdp3_ctrl_reset(mfd); #if defined(CONFIG_FB_MSM_MIPI_TIANMA_CMD_HVGA_PT) || defined(CONFIG_MACH_MSM8X10_W5) || defined(CONFIG_MACH_MSM8X10_W6) reset_done = true; #endif } mdp3_release_splash_memory(); mutex_lock(&mdp3_session->lock); if (!mdp3_session->status) { pr_err("mdp3_ctrl_pan_display, display off!\n"); goto pan_error; } fbi = mfd->fbi; bpp = fbi->var.bits_per_pixel / 8; offset = fbi->var.xoffset * bpp + fbi->var.yoffset * fbi->fix.line_length; if (offset > fbi->fix.smem_len) { pr_err("invalid fb offset=%u total length=%u\n", offset, fbi->fix.smem_len); goto pan_error; } if (mfd->fbi->screen_base) { mdp3_ctrl_reset_countdown(mdp3_session, mfd); mdp3_ctrl_clk_enable(mfd, 1); mdp3_session->dma->update(mdp3_session->dma, (void *)mfd->iova + offset, mdp3_session->intf); } else { pr_debug("mdp3_ctrl_pan_display no memory, stop interface"); mdp3_clk_enable(1, 0); mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf); mdp3_clk_enable(0, 0); } if (mdp3_session->first_commit) { /*wait for one frame time to ensure frame is sent to panel*/ msleep(1000 / panel_info->mipi.frame_rate); mdp3_session->first_commit = false; } #if defined(CONFIG_FB_MSM_MIPI_TIANMA_CMD_HVGA_PT) || defined(CONFIG_MACH_MSM8X10_W5) || defined(CONFIG_MACH_MSM8X10_W6) if (reset_done && (panel && panel->set_backlight)){ panel->set_backlight(panel, panel->panel_info.bl_max); } #endif mdp3_session->vsync_before_commit = 0; pan_error: mutex_unlock(&mdp3_session->lock); }