Loading drivers/video/msm/mdss/mdss_mdp.h +11 −3 Original line number Diff line number Diff line Loading @@ -335,6 +335,7 @@ struct mdss_mdp_pipe { atomic_t ref_cnt; u32 play_cnt; int pid; bool is_handed_off; u32 flags; u32 bwc_mode; Loading Loading @@ -404,6 +405,7 @@ struct mdss_overlay_private { int free_list_size; int ad_state; bool handoff; u32 splash_mem_addr; u32 splash_mem_size; u32 sd_enabled; Loading Loading @@ -482,9 +484,11 @@ int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd, struct mdss_mdp_ctl *mdss_mdp_ctl_init(struct mdss_panel_data *pdata, struct msm_fb_data_type *mfd); int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl); int mdss_mdp_cmd_reconfigure_splash_done(struct mdss_mdp_ctl *ctl); int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl); int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl, bool handoff); int mdss_mdp_cmd_reconfigure_splash_done(struct mdss_mdp_ctl *ctl, bool handoff); int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl, bool handoff); int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl); int mdss_mdp_ctl_split_display_setup(struct mdss_mdp_ctl *ctl, struct mdss_panel_data *pdata); Loading @@ -502,6 +506,8 @@ void mdss_mdp_ctl_notifier_unregister(struct mdss_mdp_ctl *ctl, int mdss_mdp_scan_pipes(void); int mdss_mdp_mixer_handoff(struct mdss_mdp_ctl *ctl, u32 num, struct mdss_mdp_pipe *pipe); struct mdss_mdp_mixer *mdss_mdp_wb_mixer_alloc(int rotator); int mdss_mdp_wb_mixer_destroy(struct mdss_mdp_mixer *mixer); struct mdss_mdp_mixer *mdss_mdp_mixer_get(struct mdss_mdp_ctl *ctl, int mux); Loading Loading @@ -556,6 +562,8 @@ int mdss_mdp_ad_addr_setup(struct mdss_data_type *mdata, u32 *ad_off); int mdss_mdp_calib_mode(struct msm_fb_data_type *mfd, struct mdss_calib_cfg *cfg); int mdss_mdp_pipe_handoff(struct mdss_mdp_pipe *pipe); int mdss_mdp_smp_handoff(struct mdss_data_type *mdata); struct mdss_mdp_pipe *mdss_mdp_pipe_alloc(struct mdss_mdp_mixer *mixer, u32 type); struct mdss_mdp_pipe *mdss_mdp_pipe_get(struct mdss_data_type *mdata, u32 ndx); Loading drivers/video/msm/mdss/mdss_mdp_ctl.c +72 −6 Original line number Diff line number Diff line Loading @@ -623,14 +623,14 @@ int mdss_mdp_wb_mixer_destroy(struct mdss_mdp_mixer *mixer) return 0; } int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl) int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl, bool handoff) { switch (ctl->panel_data->panel_info.type) { case MIPI_VIDEO_PANEL: case EDP_PANEL: return mdss_mdp_video_reconfigure_splash_done(ctl); return mdss_mdp_video_reconfigure_splash_done(ctl, handoff); case MIPI_CMD_PANEL: return mdss_mdp_cmd_reconfigure_splash_done(ctl); return mdss_mdp_cmd_reconfigure_splash_done(ctl, handoff); default: return 0; } Loading Loading @@ -1097,9 +1097,12 @@ static int mdss_mdp_ctl_start_sub(struct mdss_mdp_ctl *ctl) pr_debug("ctl_num=%d\n", ctl->num); nmixers = MDSS_MDP_INTF_MAX_LAYERMIXER + MDSS_MDP_WB_MAX_LAYERMIXER; if (!ctl->panel_data->panel_info.cont_splash_enabled) { nmixers = MDSS_MDP_INTF_MAX_LAYERMIXER + MDSS_MDP_WB_MAX_LAYERMIXER; for (i = 0; i < nmixers; i++) mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_LAYER(i), 0); } mixer = ctl->mixer_left; mdss_mdp_pp_resume(ctl, mixer->num); Loading Loading @@ -2011,3 +2014,66 @@ static inline int __mdss_mdp_ctl_get_mixer_off(struct mdss_mdp_mixer *mixer) MDSS_MDP_INTF_LAYERMIXER3); } } static int __mdss_mdp_mixer_handoff_helper(struct mdss_mdp_mixer *mixer, struct mdss_mdp_pipe *pipe) { int rc = 0; if (!mixer) { rc = -EINVAL; goto error; } if (mixer->stage_pipe[MDSS_MDP_STAGE_UNUSED] != NULL) { pr_err("More than one pipe staged on mixer num %d\n", mixer->num); rc = -EINVAL; goto error; } pr_debug("Staging pipe num %d on mixer num %d\n", pipe->num, mixer->num); mixer->stage_pipe[MDSS_MDP_STAGE_UNUSED] = pipe; pipe->mixer = mixer; pipe->mixer_stage = MDSS_MDP_STAGE_UNUSED; error: return rc; } /** * mdss_mdp_mixer_handoff() - Stages a given pipe on the appropriate mixer * @ctl: pointer to the control structure associated with the overlay device. * @num: the mixer number on which the pipe needs to be staged. * @pipe: pointer to the pipe to be staged. * * Function stages a given pipe on either the left mixer or the right mixer * for the control structre based on the mixer number. If the input mixer * number does not match either of the mixers then an error is returned. * This function is called during overlay handoff when certain pipes are * already staged by the bootloader. */ int mdss_mdp_mixer_handoff(struct mdss_mdp_ctl *ctl, u32 num, struct mdss_mdp_pipe *pipe) { int rc = 0; struct mdss_mdp_mixer *mx_left = ctl->mixer_left; struct mdss_mdp_mixer *mx_right = ctl->mixer_right; /* * For performance calculations, stage the handed off pipe * as MDSS_MDP_STAGE_UNUSED */ if (mx_left && (mx_left->num == num)) { rc = __mdss_mdp_mixer_handoff_helper(mx_left, pipe); } else if (mx_right && (mx_right->num == num)) { rc = __mdss_mdp_mixer_handoff_helper(mx_right, pipe); } else { pr_err("pipe num %d staged on unallocated mixer num %d\n", pipe->num, num); rc = -EINVAL; } return rc; } drivers/video/msm/mdss/mdss_mdp_intf_cmd.c +1 −1 Original line number Diff line number Diff line Loading @@ -394,7 +394,7 @@ static int mdss_mdp_cmd_remove_vsync_handler(struct mdss_mdp_ctl *ctl, return 0; } int mdss_mdp_cmd_reconfigure_splash_done(struct mdss_mdp_ctl *ctl) int mdss_mdp_cmd_reconfigure_splash_done(struct mdss_mdp_ctl *ctl, bool handoff) { struct mdss_panel_data *pdata; int ret = 0; Loading drivers/video/msm/mdss/mdss_mdp_intf_video.c +33 −27 Original line number Diff line number Diff line Loading @@ -587,7 +587,8 @@ static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg) return 0; } int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl) int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl, bool handoff) { struct mdss_panel_data *pdata; int i, ret = 0, off; Loading @@ -602,20 +603,23 @@ int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl) pdata->panel_info.cont_splash_enabled = 0; if (!handoff) { ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_BEGIN, NULL); if (ret) { pr_err("%s: Failed to handle 'CONT_SPLASH_BEGIN' event\n", __func__); pr_err("%s: Failed to handle 'CONT_SPLASH_BEGIN' event\n" , __func__); return ret; } /* clear up mixer0 and mixer1 */ flush = 0; for (i = 0; i < 2; i++) { data = mdss_mdp_ctl_read(ctl, MDSS_MDP_REG_CTL_LAYER(i)); data = mdss_mdp_ctl_read(ctl, MDSS_MDP_REG_CTL_LAYER(i)); if (data) { mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_LAYER(i), mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_LAYER(i), MDSS_MDP_LM_BORDER_COLOR); flush |= (0x40 << i); } Loading @@ -632,13 +636,15 @@ int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl) /* wait for 1 VSYNC for the pipe to be unstaged */ msleep(20); ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_FINISH, NULL); } /* Give back the reserved memory to the system */ memblock_free(mdp5_data->splash_mem_addr, mdp5_data->splash_mem_size); free_bootmem_late(mdp5_data->splash_mem_addr, mdp5_data->splash_mem_size); ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_FINISH, NULL); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); return ret; } Loading drivers/video/msm/mdss/mdss_mdp_overlay.c +272 −37 Original line number Diff line number Diff line Loading @@ -810,12 +810,60 @@ static void mdss_mdp_overlay_cleanup(struct msm_fb_data_type *mfd) mdss_mdp_pipe_destroy(pipe); } static void __mdss_mdp_handoff_cleanup_pipes(struct msm_fb_data_type *mfd, u32 type) { u32 i, npipes; struct mdss_mdp_pipe *pipes; struct mdss_mdp_pipe *pipe; struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); struct mdss_data_type *mdata = mfd_to_mdata(mfd); switch (type) { case MDSS_MDP_PIPE_TYPE_VIG: pipes = mdata->vig_pipes; npipes = mdata->nvig_pipes; break; case MDSS_MDP_PIPE_TYPE_RGB: pipes = mdata->rgb_pipes; npipes = mdata->nrgb_pipes; break; case MDSS_MDP_PIPE_TYPE_DMA: pipes = mdata->dma_pipes; npipes = mdata->ndma_pipes; break; default: return; } for (i = 0; i < npipes; i++) { pipe = &pipes[i]; if (pipe->is_handed_off) { pr_debug("Unmapping handed off pipe %d\n", pipe->num); list_add(&pipe->cleanup_list, &mdp5_data->pipes_cleanup); mdss_mdp_mixer_pipe_unstage(pipe); pipe->is_handed_off = false; } } } /** * mdss_mdp_overlay_start() - Programs the MDP control data path to hardware * @mfd: Msm frame buffer structure associated with fb device. * * Program the MDP hardware with the control settings for the framebuffer * device. In addition to this, this function also handles the transition * from the the splash screen to the android boot animation when the * continuous splash screen feature is enabled. */ static int mdss_mdp_overlay_start(struct msm_fb_data_type *mfd) { int rc; struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); struct mdss_mdp_ctl *ctl = mdp5_data->ctl; if (mdp5_data->ctl->power_on) { if (ctl->power_on) { if (!mdp5_data->mdata->batfet) mdss_mdp_batfet_ctrl(mdp5_data->mdata, true); return 0; Loading @@ -829,27 +877,77 @@ static int mdss_mdp_overlay_start(struct msm_fb_data_type *mfd) return rc; } if (mfd->panel_info->cont_splash_enabled) { mdss_mdp_ctl_splash_finish(mdp5_data->ctl); mdss_mdp_footswitch_ctrl_splash(0); } /* * We need to do hw init before any hw programming. * Also, hw init involves programming the VBIF registers which * should be done only after attaching IOMMU which in turn would call * in to TZ to restore security configs on the VBIF registers. * This is not needed when continuous splash screen is enabled since * we would have called in to TZ to restore security configs from LK. */ if (!is_mdss_iommu_attached()) { if (!mfd->panel_info->cont_splash_enabled) mdss_iommu_attach(mdss_res); mdss_hw_init(mdss_res); } rc = mdss_mdp_ctl_start(mdp5_data->ctl); rc = mdss_mdp_ctl_start(ctl); if (rc == 0) { atomic_inc(&ov_active_panels); mdss_mdp_ctl_notifier_register(mdp5_data->ctl, &mfd->mdp_sync_pt_data.notifier); } else { pr_err("overlay start failed.\n"); mdss_mdp_ctl_destroy(mdp5_data->ctl); mdp5_data->ctl = NULL; pr_err("mdp ctl start failed.\n"); goto error; } if (mfd->panel_info->cont_splash_enabled) { if (mdp5_data->handoff) { /* * Set up border-fill on the handed off pipes. * This is needed to ensure that there are no memory * accesses prior to attaching iommu during continuous * splash screen case. However, for command mode * displays, this is not necessary since the panels can * refresh from their internal memory if no data is sent * out on the dsi lanes. */ if (ctl && ctl->is_video_mode) { rc = mdss_mdp_display_commit(ctl, NULL); if (!IS_ERR_VALUE(rc)) { mdss_mdp_display_wait4comp(ctl); } else { /* * Since border-fill setup failed, we * need to ensure that we turn off the * MDP timing generator before attaching * iommu */ pr_err("failed to set BF at handoff\n"); mdp5_data->handoff = false; rc = 0; } } /* Add all the handed off pipes to the cleanup list */ __mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_RGB); __mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_VIG); __mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_DMA); } mdss_mdp_ctl_splash_finish(ctl, mdp5_data->handoff); mdss_mdp_footswitch_ctrl_splash(0); if (!is_mdss_iommu_attached()) mdss_iommu_attach(mdss_res); } error: if (rc) { mdss_mdp_ctl_destroy(ctl); mdp5_data->ctl = NULL; pm_runtime_put(&mfd->pdev->dev); } Loading Loading @@ -2288,35 +2386,39 @@ static int mdss_mdp_overlay_ioctl_handler(struct msm_fb_data_type *mfd, return ret; } static int mdss_mdp_overlay_on(struct msm_fb_data_type *mfd) /** * __mdss_mdp_overlay_ctl_init - Helper function to intialize control structure * @mfd: msm frame buffer data structure associated with the fb device. * * Helper function that allocates and initializes the mdp control structure * for a frame buffer device. Whenver applicable, this function will also setup * the control for the split display path as well. * * Return: pointer to the newly allocated control structure. */ static struct mdss_mdp_ctl *__mdss_mdp_overlay_ctl_init( struct msm_fb_data_type *mfd) { int rc; struct mdss_overlay_private *mdp5_data; if (!mfd) return -ENODEV; if (mfd->key != MFD_KEY) return -EINVAL; mdp5_data = mfd_to_mdp5_data(mfd); if (!mdp5_data) return -EINVAL; if (!mdp5_data->ctl) { int rc = 0; struct mdss_mdp_ctl *ctl; struct mdss_panel_data *pdata; if (!mfd) return ERR_PTR(-EINVAL); pdata = dev_get_platdata(&mfd->pdev->dev); if (!pdata) { pr_err("no panel connected for fb%d\n", mfd->index); return -ENODEV; rc = -ENODEV; goto error; } ctl = mdss_mdp_ctl_init(pdata, mfd); if (IS_ERR_OR_NULL(ctl)) { pr_err("Unable to initialize ctl for fb%d\n", mfd->index); return PTR_ERR(ctl); rc = PTR_ERR(ctl); goto error; } ctl->vsync_handler.vsync_handler = mdss_mdp_overlay_handle_vsync; Loading @@ -2327,9 +2429,37 @@ static int mdss_mdp_overlay_on(struct msm_fb_data_type *mfd) rc = mdss_mdp_ctl_split_display_setup(ctl, pdata->next); if (rc) { mdss_mdp_ctl_destroy(ctl); return rc; goto error; } } error: if (rc) return ERR_PTR(rc); else return ctl; } static int mdss_mdp_overlay_on(struct msm_fb_data_type *mfd) { int rc; struct mdss_overlay_private *mdp5_data; struct mdss_mdp_ctl *ctl = NULL; if (!mfd) return -ENODEV; if (mfd->key != MFD_KEY) return -EINVAL; mdp5_data = mfd_to_mdp5_data(mfd); if (!mdp5_data) return -EINVAL; if (!mdp5_data->ctl) { ctl = __mdss_mdp_overlay_ctl_init(mfd); if (IS_ERR_OR_NULL(ctl)) return PTR_ERR(ctl); mdp5_data->ctl = ctl; } Loading Loading @@ -2430,6 +2560,96 @@ int mdss_panel_register_done(struct mdss_panel_data *pdata) return 0; } /** * mdss_mdp_overlay_handoff() - Read MDP registers to handoff an active ctl path * @mfd: Msm frame buffer structure associated with the fb device. * * This function populates the MDP software structures with the current state of * the MDP hardware to handoff any active control path for the framebuffer * device. This is needed to identify any ctl, mixers and pipes being set up by * the bootloader to display the splash screen when the continuous splash screen * feature is enabled in kernel. */ static int mdss_mdp_overlay_handoff(struct msm_fb_data_type *mfd) { int rc = 0; struct mdss_data_type *mdata = mfd_to_mdata(mfd); struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); int i, j; u32 reg; struct mdss_mdp_pipe *pipe = NULL; struct mdss_mdp_ctl *ctl = NULL; if (!mdp5_data->ctl) { ctl = __mdss_mdp_overlay_ctl_init(mfd); if (IS_ERR_OR_NULL(ctl)) { rc = PTR_ERR(ctl); goto error; } mdp5_data->ctl = ctl; } rc = mdss_mdp_ctl_setup(ctl); if (rc) goto error; ctl->clk_rate = mdss_mdp_get_clk_rate(MDSS_CLK_MDP_SRC); pr_debug("Set the ctl clock rate to %d Hz\n", ctl->clk_rate); for (i = 0; i < mdata->nmixers_intf; i++) { reg = mdss_mdp_ctl_read(ctl, MDSS_MDP_REG_CTL_LAYER(i)); pr_debug("for lm%d reg = 0x%09x\n", i, reg); for (j = MDSS_MDP_SSPP_VIG0; j < MDSS_MDP_MAX_SSPP; j++) { u32 cfg = j * 3; if ((j == MDSS_MDP_SSPP_VIG3) || (j == MDSS_MDP_SSPP_RGB3)) { /* Add 2 to account for Cursor & Border bits */ cfg += 2; } if (reg & (0x7 << cfg)) { pr_debug("Pipe %d staged\n", j); pipe = mdss_mdp_pipe_search(mdata, BIT(j)); if (!pipe) { pr_warn("Invalid pipe %d staged\n", j); continue; } rc = mdss_mdp_pipe_handoff(pipe); if (rc) { pr_err("Failed to handoff pipe num %d\n" , pipe->num); goto error; } rc = mdss_mdp_mixer_handoff(ctl, i, pipe); if (rc) { pr_err("failed to handoff mixer num %d\n" , i); goto error; } } } } rc = mdss_mdp_smp_handoff(mdata); if (rc) pr_err("Failed to handoff smps\n"); mdp5_data->handoff = true; error: if (rc && ctl) { __mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_RGB); __mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_VIG); __mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_DMA); mdss_mdp_ctl_destroy(ctl); mdp5_data->ctl = NULL; mdp5_data->handoff = false; } return rc; } int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd) { struct device *dev = mfd->fbi->dev; Loading Loading @@ -2513,6 +2733,21 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd) if (!mdp5_data->cpu_pm_hdl) pr_warn("%s: unable to add event timer\n", __func__); if (mfd->panel_info->cont_splash_enabled) { rc = mdss_mdp_overlay_handoff(mfd); if (rc) { /* * Even though handoff failed, it is not fatal. * MDP can continue, just that we would have a longer * delay in transitioning from splash screen to boot * animation */ pr_warn("Overlay handoff failed for fb%d. rc=%d\n", mfd->index, rc); rc = 0; } } return rc; init_fail: kfree(mdp5_data); Loading Loading
drivers/video/msm/mdss/mdss_mdp.h +11 −3 Original line number Diff line number Diff line Loading @@ -335,6 +335,7 @@ struct mdss_mdp_pipe { atomic_t ref_cnt; u32 play_cnt; int pid; bool is_handed_off; u32 flags; u32 bwc_mode; Loading Loading @@ -404,6 +405,7 @@ struct mdss_overlay_private { int free_list_size; int ad_state; bool handoff; u32 splash_mem_addr; u32 splash_mem_size; u32 sd_enabled; Loading Loading @@ -482,9 +484,11 @@ int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd, struct mdss_mdp_ctl *mdss_mdp_ctl_init(struct mdss_panel_data *pdata, struct msm_fb_data_type *mfd); int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl); int mdss_mdp_cmd_reconfigure_splash_done(struct mdss_mdp_ctl *ctl); int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl); int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl, bool handoff); int mdss_mdp_cmd_reconfigure_splash_done(struct mdss_mdp_ctl *ctl, bool handoff); int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl, bool handoff); int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl); int mdss_mdp_ctl_split_display_setup(struct mdss_mdp_ctl *ctl, struct mdss_panel_data *pdata); Loading @@ -502,6 +506,8 @@ void mdss_mdp_ctl_notifier_unregister(struct mdss_mdp_ctl *ctl, int mdss_mdp_scan_pipes(void); int mdss_mdp_mixer_handoff(struct mdss_mdp_ctl *ctl, u32 num, struct mdss_mdp_pipe *pipe); struct mdss_mdp_mixer *mdss_mdp_wb_mixer_alloc(int rotator); int mdss_mdp_wb_mixer_destroy(struct mdss_mdp_mixer *mixer); struct mdss_mdp_mixer *mdss_mdp_mixer_get(struct mdss_mdp_ctl *ctl, int mux); Loading Loading @@ -556,6 +562,8 @@ int mdss_mdp_ad_addr_setup(struct mdss_data_type *mdata, u32 *ad_off); int mdss_mdp_calib_mode(struct msm_fb_data_type *mfd, struct mdss_calib_cfg *cfg); int mdss_mdp_pipe_handoff(struct mdss_mdp_pipe *pipe); int mdss_mdp_smp_handoff(struct mdss_data_type *mdata); struct mdss_mdp_pipe *mdss_mdp_pipe_alloc(struct mdss_mdp_mixer *mixer, u32 type); struct mdss_mdp_pipe *mdss_mdp_pipe_get(struct mdss_data_type *mdata, u32 ndx); Loading
drivers/video/msm/mdss/mdss_mdp_ctl.c +72 −6 Original line number Diff line number Diff line Loading @@ -623,14 +623,14 @@ int mdss_mdp_wb_mixer_destroy(struct mdss_mdp_mixer *mixer) return 0; } int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl) int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl, bool handoff) { switch (ctl->panel_data->panel_info.type) { case MIPI_VIDEO_PANEL: case EDP_PANEL: return mdss_mdp_video_reconfigure_splash_done(ctl); return mdss_mdp_video_reconfigure_splash_done(ctl, handoff); case MIPI_CMD_PANEL: return mdss_mdp_cmd_reconfigure_splash_done(ctl); return mdss_mdp_cmd_reconfigure_splash_done(ctl, handoff); default: return 0; } Loading Loading @@ -1097,9 +1097,12 @@ static int mdss_mdp_ctl_start_sub(struct mdss_mdp_ctl *ctl) pr_debug("ctl_num=%d\n", ctl->num); nmixers = MDSS_MDP_INTF_MAX_LAYERMIXER + MDSS_MDP_WB_MAX_LAYERMIXER; if (!ctl->panel_data->panel_info.cont_splash_enabled) { nmixers = MDSS_MDP_INTF_MAX_LAYERMIXER + MDSS_MDP_WB_MAX_LAYERMIXER; for (i = 0; i < nmixers; i++) mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_LAYER(i), 0); } mixer = ctl->mixer_left; mdss_mdp_pp_resume(ctl, mixer->num); Loading Loading @@ -2011,3 +2014,66 @@ static inline int __mdss_mdp_ctl_get_mixer_off(struct mdss_mdp_mixer *mixer) MDSS_MDP_INTF_LAYERMIXER3); } } static int __mdss_mdp_mixer_handoff_helper(struct mdss_mdp_mixer *mixer, struct mdss_mdp_pipe *pipe) { int rc = 0; if (!mixer) { rc = -EINVAL; goto error; } if (mixer->stage_pipe[MDSS_MDP_STAGE_UNUSED] != NULL) { pr_err("More than one pipe staged on mixer num %d\n", mixer->num); rc = -EINVAL; goto error; } pr_debug("Staging pipe num %d on mixer num %d\n", pipe->num, mixer->num); mixer->stage_pipe[MDSS_MDP_STAGE_UNUSED] = pipe; pipe->mixer = mixer; pipe->mixer_stage = MDSS_MDP_STAGE_UNUSED; error: return rc; } /** * mdss_mdp_mixer_handoff() - Stages a given pipe on the appropriate mixer * @ctl: pointer to the control structure associated with the overlay device. * @num: the mixer number on which the pipe needs to be staged. * @pipe: pointer to the pipe to be staged. * * Function stages a given pipe on either the left mixer or the right mixer * for the control structre based on the mixer number. If the input mixer * number does not match either of the mixers then an error is returned. * This function is called during overlay handoff when certain pipes are * already staged by the bootloader. */ int mdss_mdp_mixer_handoff(struct mdss_mdp_ctl *ctl, u32 num, struct mdss_mdp_pipe *pipe) { int rc = 0; struct mdss_mdp_mixer *mx_left = ctl->mixer_left; struct mdss_mdp_mixer *mx_right = ctl->mixer_right; /* * For performance calculations, stage the handed off pipe * as MDSS_MDP_STAGE_UNUSED */ if (mx_left && (mx_left->num == num)) { rc = __mdss_mdp_mixer_handoff_helper(mx_left, pipe); } else if (mx_right && (mx_right->num == num)) { rc = __mdss_mdp_mixer_handoff_helper(mx_right, pipe); } else { pr_err("pipe num %d staged on unallocated mixer num %d\n", pipe->num, num); rc = -EINVAL; } return rc; }
drivers/video/msm/mdss/mdss_mdp_intf_cmd.c +1 −1 Original line number Diff line number Diff line Loading @@ -394,7 +394,7 @@ static int mdss_mdp_cmd_remove_vsync_handler(struct mdss_mdp_ctl *ctl, return 0; } int mdss_mdp_cmd_reconfigure_splash_done(struct mdss_mdp_ctl *ctl) int mdss_mdp_cmd_reconfigure_splash_done(struct mdss_mdp_ctl *ctl, bool handoff) { struct mdss_panel_data *pdata; int ret = 0; Loading
drivers/video/msm/mdss/mdss_mdp_intf_video.c +33 −27 Original line number Diff line number Diff line Loading @@ -587,7 +587,8 @@ static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg) return 0; } int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl) int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl, bool handoff) { struct mdss_panel_data *pdata; int i, ret = 0, off; Loading @@ -602,20 +603,23 @@ int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl) pdata->panel_info.cont_splash_enabled = 0; if (!handoff) { ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_BEGIN, NULL); if (ret) { pr_err("%s: Failed to handle 'CONT_SPLASH_BEGIN' event\n", __func__); pr_err("%s: Failed to handle 'CONT_SPLASH_BEGIN' event\n" , __func__); return ret; } /* clear up mixer0 and mixer1 */ flush = 0; for (i = 0; i < 2; i++) { data = mdss_mdp_ctl_read(ctl, MDSS_MDP_REG_CTL_LAYER(i)); data = mdss_mdp_ctl_read(ctl, MDSS_MDP_REG_CTL_LAYER(i)); if (data) { mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_LAYER(i), mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_LAYER(i), MDSS_MDP_LM_BORDER_COLOR); flush |= (0x40 << i); } Loading @@ -632,13 +636,15 @@ int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl) /* wait for 1 VSYNC for the pipe to be unstaged */ msleep(20); ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_FINISH, NULL); } /* Give back the reserved memory to the system */ memblock_free(mdp5_data->splash_mem_addr, mdp5_data->splash_mem_size); free_bootmem_late(mdp5_data->splash_mem_addr, mdp5_data->splash_mem_size); ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_FINISH, NULL); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); return ret; } Loading
drivers/video/msm/mdss/mdss_mdp_overlay.c +272 −37 Original line number Diff line number Diff line Loading @@ -810,12 +810,60 @@ static void mdss_mdp_overlay_cleanup(struct msm_fb_data_type *mfd) mdss_mdp_pipe_destroy(pipe); } static void __mdss_mdp_handoff_cleanup_pipes(struct msm_fb_data_type *mfd, u32 type) { u32 i, npipes; struct mdss_mdp_pipe *pipes; struct mdss_mdp_pipe *pipe; struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); struct mdss_data_type *mdata = mfd_to_mdata(mfd); switch (type) { case MDSS_MDP_PIPE_TYPE_VIG: pipes = mdata->vig_pipes; npipes = mdata->nvig_pipes; break; case MDSS_MDP_PIPE_TYPE_RGB: pipes = mdata->rgb_pipes; npipes = mdata->nrgb_pipes; break; case MDSS_MDP_PIPE_TYPE_DMA: pipes = mdata->dma_pipes; npipes = mdata->ndma_pipes; break; default: return; } for (i = 0; i < npipes; i++) { pipe = &pipes[i]; if (pipe->is_handed_off) { pr_debug("Unmapping handed off pipe %d\n", pipe->num); list_add(&pipe->cleanup_list, &mdp5_data->pipes_cleanup); mdss_mdp_mixer_pipe_unstage(pipe); pipe->is_handed_off = false; } } } /** * mdss_mdp_overlay_start() - Programs the MDP control data path to hardware * @mfd: Msm frame buffer structure associated with fb device. * * Program the MDP hardware with the control settings for the framebuffer * device. In addition to this, this function also handles the transition * from the the splash screen to the android boot animation when the * continuous splash screen feature is enabled. */ static int mdss_mdp_overlay_start(struct msm_fb_data_type *mfd) { int rc; struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); struct mdss_mdp_ctl *ctl = mdp5_data->ctl; if (mdp5_data->ctl->power_on) { if (ctl->power_on) { if (!mdp5_data->mdata->batfet) mdss_mdp_batfet_ctrl(mdp5_data->mdata, true); return 0; Loading @@ -829,27 +877,77 @@ static int mdss_mdp_overlay_start(struct msm_fb_data_type *mfd) return rc; } if (mfd->panel_info->cont_splash_enabled) { mdss_mdp_ctl_splash_finish(mdp5_data->ctl); mdss_mdp_footswitch_ctrl_splash(0); } /* * We need to do hw init before any hw programming. * Also, hw init involves programming the VBIF registers which * should be done only after attaching IOMMU which in turn would call * in to TZ to restore security configs on the VBIF registers. * This is not needed when continuous splash screen is enabled since * we would have called in to TZ to restore security configs from LK. */ if (!is_mdss_iommu_attached()) { if (!mfd->panel_info->cont_splash_enabled) mdss_iommu_attach(mdss_res); mdss_hw_init(mdss_res); } rc = mdss_mdp_ctl_start(mdp5_data->ctl); rc = mdss_mdp_ctl_start(ctl); if (rc == 0) { atomic_inc(&ov_active_panels); mdss_mdp_ctl_notifier_register(mdp5_data->ctl, &mfd->mdp_sync_pt_data.notifier); } else { pr_err("overlay start failed.\n"); mdss_mdp_ctl_destroy(mdp5_data->ctl); mdp5_data->ctl = NULL; pr_err("mdp ctl start failed.\n"); goto error; } if (mfd->panel_info->cont_splash_enabled) { if (mdp5_data->handoff) { /* * Set up border-fill on the handed off pipes. * This is needed to ensure that there are no memory * accesses prior to attaching iommu during continuous * splash screen case. However, for command mode * displays, this is not necessary since the panels can * refresh from their internal memory if no data is sent * out on the dsi lanes. */ if (ctl && ctl->is_video_mode) { rc = mdss_mdp_display_commit(ctl, NULL); if (!IS_ERR_VALUE(rc)) { mdss_mdp_display_wait4comp(ctl); } else { /* * Since border-fill setup failed, we * need to ensure that we turn off the * MDP timing generator before attaching * iommu */ pr_err("failed to set BF at handoff\n"); mdp5_data->handoff = false; rc = 0; } } /* Add all the handed off pipes to the cleanup list */ __mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_RGB); __mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_VIG); __mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_DMA); } mdss_mdp_ctl_splash_finish(ctl, mdp5_data->handoff); mdss_mdp_footswitch_ctrl_splash(0); if (!is_mdss_iommu_attached()) mdss_iommu_attach(mdss_res); } error: if (rc) { mdss_mdp_ctl_destroy(ctl); mdp5_data->ctl = NULL; pm_runtime_put(&mfd->pdev->dev); } Loading Loading @@ -2288,35 +2386,39 @@ static int mdss_mdp_overlay_ioctl_handler(struct msm_fb_data_type *mfd, return ret; } static int mdss_mdp_overlay_on(struct msm_fb_data_type *mfd) /** * __mdss_mdp_overlay_ctl_init - Helper function to intialize control structure * @mfd: msm frame buffer data structure associated with the fb device. * * Helper function that allocates and initializes the mdp control structure * for a frame buffer device. Whenver applicable, this function will also setup * the control for the split display path as well. * * Return: pointer to the newly allocated control structure. */ static struct mdss_mdp_ctl *__mdss_mdp_overlay_ctl_init( struct msm_fb_data_type *mfd) { int rc; struct mdss_overlay_private *mdp5_data; if (!mfd) return -ENODEV; if (mfd->key != MFD_KEY) return -EINVAL; mdp5_data = mfd_to_mdp5_data(mfd); if (!mdp5_data) return -EINVAL; if (!mdp5_data->ctl) { int rc = 0; struct mdss_mdp_ctl *ctl; struct mdss_panel_data *pdata; if (!mfd) return ERR_PTR(-EINVAL); pdata = dev_get_platdata(&mfd->pdev->dev); if (!pdata) { pr_err("no panel connected for fb%d\n", mfd->index); return -ENODEV; rc = -ENODEV; goto error; } ctl = mdss_mdp_ctl_init(pdata, mfd); if (IS_ERR_OR_NULL(ctl)) { pr_err("Unable to initialize ctl for fb%d\n", mfd->index); return PTR_ERR(ctl); rc = PTR_ERR(ctl); goto error; } ctl->vsync_handler.vsync_handler = mdss_mdp_overlay_handle_vsync; Loading @@ -2327,9 +2429,37 @@ static int mdss_mdp_overlay_on(struct msm_fb_data_type *mfd) rc = mdss_mdp_ctl_split_display_setup(ctl, pdata->next); if (rc) { mdss_mdp_ctl_destroy(ctl); return rc; goto error; } } error: if (rc) return ERR_PTR(rc); else return ctl; } static int mdss_mdp_overlay_on(struct msm_fb_data_type *mfd) { int rc; struct mdss_overlay_private *mdp5_data; struct mdss_mdp_ctl *ctl = NULL; if (!mfd) return -ENODEV; if (mfd->key != MFD_KEY) return -EINVAL; mdp5_data = mfd_to_mdp5_data(mfd); if (!mdp5_data) return -EINVAL; if (!mdp5_data->ctl) { ctl = __mdss_mdp_overlay_ctl_init(mfd); if (IS_ERR_OR_NULL(ctl)) return PTR_ERR(ctl); mdp5_data->ctl = ctl; } Loading Loading @@ -2430,6 +2560,96 @@ int mdss_panel_register_done(struct mdss_panel_data *pdata) return 0; } /** * mdss_mdp_overlay_handoff() - Read MDP registers to handoff an active ctl path * @mfd: Msm frame buffer structure associated with the fb device. * * This function populates the MDP software structures with the current state of * the MDP hardware to handoff any active control path for the framebuffer * device. This is needed to identify any ctl, mixers and pipes being set up by * the bootloader to display the splash screen when the continuous splash screen * feature is enabled in kernel. */ static int mdss_mdp_overlay_handoff(struct msm_fb_data_type *mfd) { int rc = 0; struct mdss_data_type *mdata = mfd_to_mdata(mfd); struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); int i, j; u32 reg; struct mdss_mdp_pipe *pipe = NULL; struct mdss_mdp_ctl *ctl = NULL; if (!mdp5_data->ctl) { ctl = __mdss_mdp_overlay_ctl_init(mfd); if (IS_ERR_OR_NULL(ctl)) { rc = PTR_ERR(ctl); goto error; } mdp5_data->ctl = ctl; } rc = mdss_mdp_ctl_setup(ctl); if (rc) goto error; ctl->clk_rate = mdss_mdp_get_clk_rate(MDSS_CLK_MDP_SRC); pr_debug("Set the ctl clock rate to %d Hz\n", ctl->clk_rate); for (i = 0; i < mdata->nmixers_intf; i++) { reg = mdss_mdp_ctl_read(ctl, MDSS_MDP_REG_CTL_LAYER(i)); pr_debug("for lm%d reg = 0x%09x\n", i, reg); for (j = MDSS_MDP_SSPP_VIG0; j < MDSS_MDP_MAX_SSPP; j++) { u32 cfg = j * 3; if ((j == MDSS_MDP_SSPP_VIG3) || (j == MDSS_MDP_SSPP_RGB3)) { /* Add 2 to account for Cursor & Border bits */ cfg += 2; } if (reg & (0x7 << cfg)) { pr_debug("Pipe %d staged\n", j); pipe = mdss_mdp_pipe_search(mdata, BIT(j)); if (!pipe) { pr_warn("Invalid pipe %d staged\n", j); continue; } rc = mdss_mdp_pipe_handoff(pipe); if (rc) { pr_err("Failed to handoff pipe num %d\n" , pipe->num); goto error; } rc = mdss_mdp_mixer_handoff(ctl, i, pipe); if (rc) { pr_err("failed to handoff mixer num %d\n" , i); goto error; } } } } rc = mdss_mdp_smp_handoff(mdata); if (rc) pr_err("Failed to handoff smps\n"); mdp5_data->handoff = true; error: if (rc && ctl) { __mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_RGB); __mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_VIG); __mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_DMA); mdss_mdp_ctl_destroy(ctl); mdp5_data->ctl = NULL; mdp5_data->handoff = false; } return rc; } int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd) { struct device *dev = mfd->fbi->dev; Loading Loading @@ -2513,6 +2733,21 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd) if (!mdp5_data->cpu_pm_hdl) pr_warn("%s: unable to add event timer\n", __func__); if (mfd->panel_info->cont_splash_enabled) { rc = mdss_mdp_overlay_handoff(mfd); if (rc) { /* * Even though handoff failed, it is not fatal. * MDP can continue, just that we would have a longer * delay in transitioning from splash screen to boot * animation */ pr_warn("Overlay handoff failed for fb%d. rc=%d\n", mfd->index, rc); rc = 0; } } return rc; init_fail: kfree(mdp5_data); Loading