static int mdp3_ctrl_dma_init(struct msm_fb_data_type *mfd, struct mdp3_dma *dma) { int rc; struct mdss_panel_info *panel_info = mfd->panel_info; struct fb_info *fbi = mfd->fbi; struct fb_fix_screeninfo *fix; struct fb_var_screeninfo *var; struct mdp3_dma_output_config outputConfig; struct mdp3_dma_source sourceConfig; int frame_rate = mfd->panel_info->mipi.frame_rate; int vbp, vfp, vspw; int vtotal, vporch; struct mdp3_notification dma_done_callback; struct mdp3_tear_check te; vbp = panel_info->lcdc.v_back_porch; vfp = panel_info->lcdc.v_front_porch; vspw = panel_info->lcdc.v_pulse_width; vporch = vbp + vfp + vspw; vtotal = vporch + panel_info->yres; fix = &fbi->fix; var = &fbi->var; sourceConfig.format = mdp3_ctrl_get_source_format(mfd->fb_imgType); sourceConfig.width = panel_info->xres; sourceConfig.height = panel_info->yres; sourceConfig.x = 0; sourceConfig.y = 0; sourceConfig.stride = fix->line_length; sourceConfig.buf = (void *)mfd->iova; sourceConfig.vporch = vporch; sourceConfig.vsync_count = MDP_VSYNC_CLK_RATE / (frame_rate * vtotal); outputConfig.dither_en = 0; outputConfig.out_sel = mdp3_ctrl_get_intf_type(mfd); outputConfig.bit_mask_polarity = 0; outputConfig.color_components_flip = 0; outputConfig.pack_pattern = mdp3_ctrl_get_pack_pattern(mfd->fb_imgType); outputConfig.pack_align = MDP3_DMA_OUTPUT_PACK_ALIGN_LSB; outputConfig.color_comp_out_bits = (MDP3_DMA_OUTPUT_COMP_BITS_8 << 4) | (MDP3_DMA_OUTPUT_COMP_BITS_8 << 2)| MDP3_DMA_OUTPUT_COMP_BITS_8; te.frame_rate = panel_info->mipi.frame_rate; te.hw_vsync_mode = panel_info->mipi.hw_vsync_mode; te.tear_check_en = panel_info->te.tear_check_en; te.sync_cfg_height = panel_info->te.sync_cfg_height; te.vsync_init_val = panel_info->te.vsync_init_val; te.sync_threshold_start = panel_info->te.sync_threshold_start; te.sync_threshold_continue = panel_info->te.sync_threshold_continue; te.start_pos = panel_info->te.start_pos; te.rd_ptr_irq = panel_info->te.rd_ptr_irq; te.refx100 = panel_info->te.refx100; if (dma->dma_config) rc = dma->dma_config(dma, &sourceConfig, &outputConfig); else rc = -EINVAL; if (outputConfig.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) { if (dma->dma_sync_config) rc = dma->dma_sync_config(dma, &sourceConfig, &te); else rc = -EINVAL; dma_done_callback.handler = dma_done_notify_handler; dma_done_callback.arg = mfd->mdp.private1; dma->dma_done_notifier(dma, &dma_done_callback); } return rc; }
int mdp3_ctrl_init(struct msm_fb_data_type *mfd) { struct device *dev = mfd->fbi->dev; struct msm_mdp_interface *mdp3_interface = &mfd->mdp; struct mdp3_session_data *mdp3_session = NULL; u32 intf_type = MDP3_DMA_OUTPUT_SEL_DSI_VIDEO; int rc; int splash_mismatch = 0; pr_debug("mdp3_ctrl_init\n"); rc = mdp3_parse_dt_splash(mfd); if (rc) splash_mismatch = 1; mdp3_interface->on_fnc = mdp3_ctrl_on; mdp3_interface->off_fnc = mdp3_ctrl_off; mdp3_interface->do_histogram = NULL; mdp3_interface->cursor_update = NULL; mdp3_interface->dma_fnc = mdp3_ctrl_pan_display; mdp3_interface->ioctl_handler = mdp3_ctrl_ioctl_handler; mdp3_interface->kickoff_fnc = mdp3_ctrl_display_commit_kickoff; mdp3_interface->lut_update = mdp3_ctrl_lut_update; mdp3_session = kmalloc(sizeof(struct mdp3_session_data), GFP_KERNEL); if (!mdp3_session) { pr_err("fail to allocate mdp3 private data structure"); return -ENOMEM; } memset(mdp3_session, 0, sizeof(struct mdp3_session_data)); mutex_init(&mdp3_session->lock); INIT_WORK(&mdp3_session->clk_off_work, mdp3_dispatch_clk_off); INIT_WORK(&mdp3_session->dma_done_work, mdp3_dispatch_dma_done); atomic_set(&mdp3_session->vsync_countdown, 0); mutex_init(&mdp3_session->histo_lock); mdp3_session->dma = mdp3_get_dma_pipe(MDP3_DMA_CAP_ALL); if (!mdp3_session->dma) { rc = -ENODEV; goto init_done; } rc = mdp3_dma_init(mdp3_session->dma); if (rc) { pr_err("fail to init dma\n"); goto init_done; } intf_type = mdp3_ctrl_get_intf_type(mfd); mdp3_session->intf = mdp3_get_display_intf(intf_type); if (!mdp3_session->intf) { rc = -ENODEV; goto init_done; } rc = mdp3_intf_init(mdp3_session->intf); if (rc) { pr_err("fail to init interface\n"); goto init_done; } mdp3_session->dma->output_config.out_sel = intf_type; mdp3_session->mfd = mfd; mdp3_session->panel = dev_get_platdata(&mfd->pdev->dev); mdp3_session->status = mdp3_session->intf->active; mdp3_session->overlay.id = MSMFB_NEW_REQUEST; mdp3_bufq_init(&mdp3_session->bufq_in); mdp3_bufq_init(&mdp3_session->bufq_out); mdp3_session->histo_status = 0; mdp3_session->lut_sel = 0; BLOCKING_INIT_NOTIFIER_HEAD(&mdp3_session->notifier_head); init_timer(&mdp3_session->vsync_timer); mdp3_session->vsync_timer.function = mdp3_vsync_timer_func; mdp3_session->vsync_timer.data = (u32)mdp3_session; mdp3_session->vsync_period = 1000 / mfd->panel_info->mipi.frame_rate; mfd->mdp.private1 = mdp3_session; init_completion(&mdp3_session->dma_completion); if (intf_type != MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) mdp3_session->wait_for_dma_done = mdp3_wait_for_dma_done; rc = sysfs_create_group(&dev->kobj, &vsync_fs_attr_group); if (rc) { pr_err("vsync sysfs group creation failed, ret=%d\n", rc); goto init_done; } mdp3_session->vsync_event_sd = sysfs_get_dirent(dev->kobj.sd, NULL, "vsync_event"); if (!mdp3_session->vsync_event_sd) { pr_err("vsync_event sysfs lookup failed\n"); rc = -ENODEV; goto init_done; } rc = mdp3_create_sysfs_link(dev); if (rc) pr_warn("problem creating link to mdp sysfs\n"); kobject_uevent(&dev->kobj, KOBJ_ADD); pr_debug("vsync kobject_uevent(KOBJ_ADD)\n"); if (mdp3_get_cont_spash_en()) { mdp3_session->clk_on = 1; mdp3_session->in_splash_screen = 1; mdp3_ctrl_notifier_register(mdp3_session, &mdp3_session->mfd->mdp_sync_pt_data.notifier); } if (splash_mismatch) { pr_err("splash memory mismatch, stop splash\n"); mdp3_ctrl_off(mfd); } mdp3_session->vsync_before_commit = true; init_done: if (IS_ERR_VALUE(rc)) kfree(mdp3_session); return rc; }
void mdp3_ctrl_reset_countdown(struct mdp3_session_data *session, struct msm_fb_data_type *mfd) { if (mdp3_ctrl_get_intf_type(mfd) == MDP3_DMA_OUTPUT_SEL_DSI_CMD) atomic_set(&session->vsync_countdown, VSYNC_EXPIRE_TICK); }
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; int rc; 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 (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 *)(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_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; } 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 *)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_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) { 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)) panel->set_backlight(panel, panel->panel_info.bl_max); mutex_unlock(&mdp3_session->lock); mdss_fb_update_notify_update(mfd); return 0; }
int mdp3_ctrl_init(struct msm_fb_data_type *mfd) { struct device *dev = mfd->fbi->dev; struct msm_mdp_interface *mdp3_interface = &mfd->mdp; struct mdp3_session_data *mdp3_session = NULL; u32 intf_type = MDP3_DMA_OUTPUT_SEL_DSI_VIDEO; int rc; pr_debug("mdp3_ctrl_init\n"); mdp3_interface->on_fnc = mdp3_ctrl_on; mdp3_interface->off_fnc = mdp3_ctrl_off; mdp3_interface->do_histogram = NULL; mdp3_interface->cursor_update = NULL; mdp3_interface->dma_fnc = mdp3_ctrl_pan_display; mdp3_interface->ioctl_handler = mdp3_ctrl_ioctl_handler; mdp3_interface->kickoff_fnc = mdp3_ctrl_display_commit_kickoff; mdp3_interface->lut_update = mdp3_ctrl_lut_update; mdp3_session = kmalloc(sizeof(struct mdp3_session_data), GFP_KERNEL); if (!mdp3_session) { pr_err("fail to allocate mdp3 private data structure"); return -ENOMEM; } memset(mdp3_session, 0, sizeof(struct mdp3_session_data)); mutex_init(&mdp3_session->lock); mutex_init(&mdp3_session->histo_lock); mdp3_session->dma = mdp3_get_dma_pipe(MDP3_DMA_CAP_ALL); if (!mdp3_session->dma) { rc = -ENODEV; goto init_done; } intf_type = mdp3_ctrl_get_intf_type(mfd); mdp3_session->intf = mdp3_get_display_intf(intf_type); if (!mdp3_session->intf) { rc = -ENODEV; goto init_done; } mdp3_session->mfd = mfd; mdp3_session->panel = dev_get_platdata(&mfd->pdev->dev); mdp3_session->status = 0; mdp3_session->overlay.id = MSMFB_NEW_REQUEST; mdp3_bufq_init(&mdp3_session->bufq_in); mdp3_bufq_init(&mdp3_session->bufq_out); mdp3_session->histo_status = 0; mdp3_session->lut_sel = 0; init_timer(&mdp3_session->vsync_timer); mdp3_session->vsync_timer.function = mdp3_vsync_timer_func; mdp3_session->vsync_timer.data = (u32)mdp3_session; mdp3_session->vsync_period = 1000 / mfd->panel_info->mipi.frame_rate; mfd->mdp.private1 = mdp3_session; rc = sysfs_create_group(&dev->kobj, &vsync_fs_attr_group); if (rc) { pr_err("vsync sysfs group creation failed, ret=%d\n", rc); goto init_done; } mdp3_session->vsync_event_sd = sysfs_get_dirent(dev->kobj.sd, NULL, "vsync_event"); if (!mdp3_session->vsync_event_sd) { pr_err("vsync_event sysfs lookup failed\n"); rc = -ENODEV; goto init_done; } kobject_uevent(&dev->kobj, KOBJ_ADD); pr_debug("vsync kobject_uevent(KOBJ_ADD)\n"); init_done: if (IS_ERR_VALUE(rc)) kfree(mdp3_session); return rc; }