static u32 mdss_mdp_res_init(struct platform_device *pdev) { u32 rc; rc = mdss_mdp_irq_clk_setup(pdev); if (rc) return rc; mdss_res->clk_ctrl_wq = create_singlethread_workqueue("mdp_clk_wq"); INIT_DELAYED_WORK(&mdss_res->clk_ctrl_worker, mdss_mdp_clk_ctrl_workqueue_handler); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); mdss_res->rev = MDSS_MDP_REG_READ(MDSS_REG_HW_VERSION); mdss_res->mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); mdss_res->smp_mb_cnt = MDSS_MDP_SMP_MMB_BLOCKS; mdss_res->smp_mb_size = MDSS_MDP_SMP_MMB_SIZE; mdss_res->pipe_type_map = mdss_mdp_pipe_type_map; mdss_res->mixer_type_map = mdss_mdp_mixer_type_map; pr_info("mdss_revision=%x\n", mdss_res->rev); pr_info("mdp_hw_revision=%x\n", mdss_res->mdp_rev); mdss_res->res_init = true; mdss_res->timeout = HZ/20; mdss_res->clk_ena = false; mdss_res->irq_mask = MDSS_MDP_DEFAULT_INTR_MASK; mdss_res->suspend = false; mdss_res->prim_ptype = NO_PANEL; mdss_res->irq_ena = false; return 0; }
int mdss_dsi_panel_ief_on(void) { struct mdss_dsi_ctrl_pdata *ctrl = NULL; if (pdata_base == NULL || mfd_base == NULL) { pr_err("%s: Invalid input data\n", __func__); return -EINVAL; } if (mfd_base->panel_power_on == 0) { pr_err("%s: Panel is off\n", __func__); return -EPERM; } ctrl = container_of(pdata_base, struct mdss_dsi_ctrl_pdata, panel_data); if(lge_ief_on_cmds.cmd_cnt){ pr_info("sending IEF_ON code\n"); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); mdss_dsi_panel_cmds_send(ctrl, &lge_ief_on_cmds); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); } return 0; }
static u32 mdss_mdp_res_init(struct mdss_data_type *mdata) { u32 rc = 0; rc = mdss_mdp_irq_clk_setup(mdata); if (rc) return rc; mdata->clk_ctrl_wq = create_singlethread_workqueue("mdp_clk_wq"); INIT_DELAYED_WORK(&mdata->clk_ctrl_worker, mdss_mdp_clk_ctrl_workqueue_handler); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); mdata->rev = MDSS_MDP_REG_READ(MDSS_REG_HW_VERSION); mdata->mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); mdata->smp_mb_cnt = MDSS_MDP_SMP_MMB_BLOCKS; mdata->smp_mb_size = MDSS_MDP_SMP_MMB_SIZE; mdata->pipe_type_map = mdss_mdp_pipe_type_map; mdata->mixer_type_map = mdss_mdp_mixer_type_map; pr_info("mdss_revision=%x\n", mdata->rev); pr_info("mdp_hw_revision=%x\n", mdata->mdp_rev); mdata->res_init = true; mdata->timeout = HZ/20; mdata->clk_ena = false; mdata->irq_mask = MDSS_MDP_DEFAULT_INTR_MASK; mdata->suspend = false; mdata->prim_ptype = NO_PANEL; mdata->irq_ena = false; mdata->iclient = msm_ion_client_create(-1, mdata->pdev->name); if (IS_ERR_OR_NULL(mdata->iclient)) { pr_err("msm_ion_client_create() return error (%p)\n", mdata->iclient); mdata->iclient = NULL; } rc = mdss_iommu_init(); if (!IS_ERR_VALUE(rc)) mdss_iommu_attach(); rc = mdss_hw_init(mdata); return rc; }
static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg) { struct mdss_mdp_video_ctx *ctx; u32 intr_type = MDSS_MDP_IRQ_INTF_VSYNC; pr_debug("kickoff ctl=%d\n", ctl->num); ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data; if (!ctx) { pr_err("invalid ctx\n"); return -ENODEV; } mdss_mdp_set_intr_callback(intr_type, ctl->intf_num, mdss_mdp_video_vsync_intr_done, ctx); mdss_mdp_irq_enable(intr_type, ctl->intf_num); if (!ctx->timegen_en) { int off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num); pr_debug("enabling timing gen for intf=%d\n", ctl->intf_num); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 1); ctx->timegen_en = true; wmb(); } wait_for_completion_interruptible(&ctx->vsync_comp); mdss_mdp_irq_disable(intr_type, ctl->intf_num); return 0; }
int mdss_edp_off(struct mdss_panel_data *pdata) { struct mdss_edp_drv_pdata *edp_drv = NULL; int ret = 0; edp_drv = container_of(pdata, struct mdss_edp_drv_pdata, panel_data); if (!edp_drv) { pr_err("%s: Invalid input data\n", __func__); return -EINVAL; } pr_debug("%s:+\n", __func__); mdss_edp_irq_disable(edp_drv); gpio_set_value(edp_drv->gpio_panel_en, 0); if (edp_drv->bl_pwm != NULL) pwm_disable(edp_drv->bl_pwm); mdss_edp_enable(edp_drv->base, 0); mdss_edp_unconfig_clk(edp_drv->base, edp_drv->mmss_cc_base); mdss_edp_enable_mainlink(edp_drv->base, 0); mdss_edp_lane_power_ctrl(edp_drv->base, edp_drv->dpcd.max_lane_count, 0); mdss_edp_clk_disable(edp_drv); mdss_edp_phy_powerup(edp_drv->base, 0); mdss_edp_unprepare_clocks(edp_drv); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); mdss_edp_aux_ctrl(edp_drv->base, 0); pr_debug("%s:-\n", __func__); return ret; }
static int prepare_for_reg_access(struct msm_fb_data_type *mfd) { struct mdss_panel_data *pdata; int ret = 0; struct mdss_mdp_ctl *ctl; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; ctl = mfd_to_ctl(mfd); if (!ctl) return -ENODEV; pdata = dev_get_platdata(&mfd->pdev->dev); if (!pdata) { pr_err("%s: no panel connected\n", __func__); return -ENODEV; } ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); mdss_dsi_cmd_mdp_busy(ctrl_pdata); mdss_bus_bandwidth_ctrl(1); mdss_dsi_clk_ctrl(ctrl_pdata, 1); mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata); return ret; }
static inline u32 mdss_mdp_cmd_line_count(struct mdss_mdp_ctl *ctl) { struct mdss_mdp_mixer *mixer; u32 cnt = 0xffff; /* init it to an invalid value */ u32 init; u32 height; mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT); if (!mixer) { mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_RIGHT); if (!mixer) { mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); goto exit; } } init = mdss_mdp_pingpong_read (mixer, MDSS_MDP_REG_PP_VSYNC_INIT_VAL) & 0xffff; height = mdss_mdp_pingpong_read (mixer, MDSS_MDP_REG_PP_SYNC_CONFIG_HEIGHT) & 0xffff; if (height < init) { mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); goto exit; } cnt = mdss_mdp_pingpong_read (mixer, MDSS_MDP_REG_PP_INT_COUNT_VAL) & 0xffff; if (cnt < init) /* wrap around happened at height */ cnt += (height - init); else cnt -= init; mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); pr_debug("cnt=%d init=%d height=%d\n", cnt, init, height); exit: return cnt; }
int mdss_hw_init(struct mdss_data_type *mdata) { int i, j; char *offset; struct mdss_mdp_pipe *vig; mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); mdata->mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION); pr_info_once("MDP Rev=%x\n", mdata->mdp_rev); if (mdata->hw_settings) { struct mdss_hw_settings *hws = mdata->hw_settings; while (hws->reg) { writel_relaxed(hws->val, hws->reg); hws++; } } for (i = 0; i < mdata->nmixers_intf; i++) { offset = mdata->mixer_intf[i].dspp_base + MDSS_MDP_REG_DSPP_HIST_LUT_BASE; for (j = 0; j < ENHIST_LUT_ENTRIES; j++) writel_relaxed(j, offset); /* swap */ writel_relaxed(1, offset + 4); } vig = mdata->vig_pipes; for (i = 0; i < mdata->nvig_pipes; i++) { offset = vig[i].base + MDSS_MDP_REG_VIG_HIST_LUT_BASE; for (j = 0; j < ENHIST_LUT_ENTRIES; j++) writel_relaxed(j, offset); /* swap */ writel_relaxed(1, offset + 16); } mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); pr_debug("MDP hw init done\n"); return 0; }
int mdss_edp_on(struct mdss_panel_data *pdata) { struct mdss_edp_drv_pdata *edp_drv = NULL; int ret = 0; if (!pdata) { pr_err("%s: Invalid input data\n", __func__); return -EINVAL; } edp_drv = container_of(pdata, struct mdss_edp_drv_pdata, panel_data); pr_debug("%s:+\n", __func__); if (edp_drv->train_start == 0) edp_drv->train_start++; mdss_edp_phy_pll_reset(edp_drv->base); mdss_edp_aux_reset(edp_drv->base); mdss_edp_mainlink_reset(edp_drv->base); ret = mdss_edp_prepare_clocks(edp_drv); if (ret) return ret; mdss_edp_phy_powerup(edp_drv->base, 1); mdss_edp_pll_configure(edp_drv->base, edp_drv->edid.timing[0].pclk); mdss_edp_phy_pll_ready(edp_drv->base); ret = mdss_edp_clk_enable(edp_drv); if (ret) { mdss_edp_unprepare_clocks(edp_drv); return ret; } mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); mdss_edp_aux_ctrl(edp_drv->base, 1); mdss_edp_lane_power_ctrl(edp_drv->base, edp_drv->dpcd.max_lane_count, 1); mdss_edp_enable_mainlink(edp_drv->base, 1); mdss_edp_config_clk(edp_drv->base, edp_drv->mmss_cc_base); mdss_edp_clock_synchrous(edp_drv->base, 1); mdss_edp_phy_vm_pe_init(edp_drv->base); mdss_edp_config_sync(edp_drv->base); mdss_edp_config_sw_div(edp_drv->base); mdss_edp_config_static_mdiv(edp_drv->base); gpio_set_value(edp_drv->gpio_panel_en, 1); mdss_edp_irq_enable(edp_drv); pr_debug("%s:-\n", __func__); return 0; }
static int mdss_hw_init(struct mdss_data_type *mdata) { char *base = mdata->vbif_base; mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); /* Setup VBIF QoS settings*/ MDSS_MDP_REG_WRITE(0x2E0, 0x000000AA); MDSS_MDP_REG_WRITE(0x2E4, 0x00000055); writel_relaxed(0x00000001, base + 0x004); writel_relaxed(0x00000707, base + 0x0D8); writel_relaxed(0x00000030, base + 0x0F0); writel_relaxed(0x00000001, base + 0x124); writel_relaxed(0x00000FFF, base + 0x178); writel_relaxed(0x0FFF0FFF, base + 0x17C); writel_relaxed(0x22222222, base + 0x160); writel_relaxed(0x00002222, base + 0x164); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); pr_debug("MDP hw init done\n"); return 0; }
static void mdss_mdp_pipe_nrt_vbif_setup(struct mdss_data_type *mdata, struct mdss_mdp_pipe *pipe) { uint32_t nrt_vbif_client_sel; if (pipe->type != MDSS_MDP_PIPE_TYPE_DMA) return; mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); nrt_vbif_client_sel = readl_relaxed(mdata->mdp_base + MMSS_MDP_RT_NRT_VBIF_CLIENT_SEL); if (mdss_mdp_is_nrt_vbif_client(mdata, pipe)) nrt_vbif_client_sel |= BIT(pipe->num - MDSS_MDP_SSPP_DMA0); else nrt_vbif_client_sel &= ~BIT(pipe->num - MDSS_MDP_SSPP_DMA0); writel_relaxed(nrt_vbif_client_sel, mdata->mdp_base + MMSS_MDP_RT_NRT_VBIF_CLIENT_SEL); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); return; }
static void mdss_mdp_suspend_sub(void) { cancel_delayed_work(&mdss_res->clk_ctrl_worker); flush_workqueue(mdss_res->clk_ctrl_wq); mdss_mdp_clk_ctrl(MDP_BLOCK_MASTER_OFF, false); mutex_lock(&mdp_suspend_mutex); mdss_res->suspend = true; mutex_unlock(&mdp_suspend_mutex); }
int mdss_dsi_panel_img_tune_apply(unsigned int screen_mode) { struct mdss_dsi_ctrl_pdata *ctrl = NULL; if (pdata_base == NULL) { pr_err("%s: Invalid input data.\n", __func__); return -EINVAL; } ctrl = container_of(pdata_base, struct mdss_dsi_ctrl_pdata, panel_data); if (pdata_base->panel_info.panel_power_on == 0) { pr_err("%s: panel off state. This screen mode will not be applied.\n", __func__); return -EINVAL; } /* if (ctrl->ctrl_state != (CTRL_STATE_PANEL_INIT | CTRL_STATE_MDP_ACTIVE)) { pr_err("%s: panel is not 'on' state(cur=%d). The screen mode will be applied next time.\n", __func__, ctrl->ctrl_state); return -EINVAL; } */ if ((screen_mode < 0) || (screen_mode > IMG_TUNE_COUNT)) { pr_err("%s: invalid input data(%d). Retry(0-5).\n", __func__, screen_mode); return -EINVAL; } if (screen_mode == IMG_TUNE_COUNT) { pr_info("%s: send the screen mode on(%d) from kernel.\n", __func__, img_tune_mode); } else { img_tune_mode = screen_mode; pr_info("%s: send the screen mode on(%d) from user.\n", __func__, img_tune_mode); } if(img_tune_cmds_set->img_tune_cmds[img_tune_mode].cmd_cnt) { mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); // 0 : CM0 / 1 : CM0 + PLC 60% / 2 : CM1 / 3 : CM1 + PLC 60% / 4 : CM2 / 5 : CM2 + PLC 60% mdss_dsi_panel_cmds_send(ctrl, &img_tune_cmds_set->img_tune_cmds[img_tune_mode]); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); } return 0; }
int mdss_mdp_pipe_panic_signal_ctrl(struct mdss_mdp_pipe *pipe, bool enable) { uint32_t panic_robust_ctrl; struct mdss_data_type *mdata = mdss_mdp_get_mdata(); if (!mdata->has_panic_ctrl) goto end; mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); panic_robust_ctrl = readl_relaxed(mdata->mdp_base + MMSS_MDP_PANIC_ROBUST_CTRL); if (enable) panic_robust_ctrl |= BIT(pipe->panic_ctrl_ndx); else panic_robust_ctrl &= ~BIT(pipe->panic_ctrl_ndx); writel_relaxed(panic_robust_ctrl, mdata->mdp_base + MMSS_MDP_PANIC_ROBUST_CTRL); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); end: return 0; }
/** * @mdss_mdp_cdm_setup - Sets up the CDM block based on the usecase. The CDM * block should be initialized before calling this * function. * @cdm: Pointer to the CDM structure. * @data: Pointer to the structure containing configuration * data. */ int mdss_mdp_cdm_setup(struct mdss_mdp_cdm *cdm, struct mdp_cdm_cfg *data) { int rc = 0; if (!cdm || !data) { pr_err("%s: invalid arguments\n", __func__); return -EINVAL; } mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); mutex_lock(&cdm->lock); /* Setup CSC block */ rc = mdss_mdp_cdm_csc_setup(cdm, data); if (rc) { pr_err("%s: csc configuration failure\n", __func__); goto fail; } /* Setup chroma down sampler */ rc = mdss_mdp_cdm_cdwn_setup(cdm, data); if (rc) { pr_err("%s: cdwn configuration failure\n", __func__); goto fail; } /* Setup HDMI packer */ rc = mdss_mdp_cdm_out_packer_setup(cdm, data); if (rc) { pr_err("%s: out packer configuration failure\n", __func__); goto fail; } memcpy(&cdm->setup, data, sizeof(struct mdp_cdm_cfg)); fail: mutex_unlock(&cdm->lock); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); return rc; }
int mdss_mdp_pipe_panic_signal_ctrl(struct mdss_mdp_pipe *pipe, bool enable) { uint32_t panic_robust_ctrl; struct mdss_data_type *mdata = mdss_mdp_get_mdata(); if (!mdata->has_panic_ctrl) goto end; switch (mdss_mdp_panic_signal_support_mode(mdata, pipe)) { case MDSS_MDP_PANIC_COMMON_REG_CFG: mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); panic_robust_ctrl = readl_relaxed(mdata->mdp_base + MMSS_MDP_PANIC_ROBUST_CTRL); if (enable) panic_robust_ctrl |= BIT(pipe->panic_ctrl_ndx); else panic_robust_ctrl &= ~BIT(pipe->panic_ctrl_ndx); writel_relaxed(panic_robust_ctrl, mdata->mdp_base + MMSS_MDP_PANIC_ROBUST_CTRL); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); break; case MDSS_MDP_PANIC_PER_PIPE_CFG: mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); panic_robust_ctrl = mdss_mdp_pipe_read(pipe, MDSS_MDP_REG_SSPP_QOS_CTRL); if (enable) panic_robust_ctrl |= BIT(0); else panic_robust_ctrl &= ~BIT(0); mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_QOS_CTRL, panic_robust_ctrl); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); break; } end: return 0; }
void htc_set_pp_pa(struct mdss_mdp_ctl *ctl) { struct mdss_data_type *mdata; struct mdss_mdp_mixer *mixer; u32 base = 0, opmode; char __iomem *basel; if (htc_mdss_pp_pa[HUE_INDEX].req_value == htc_mdss_pp_pa[HUE_INDEX].cur_value) return; if (htc_mdss_pp_pa[HUE_INDEX].req_value >= HUE_MAX) return; mdata = mdss_mdp_get_mdata(); mixer = mdata->mixer_intf; base = MDSS_MDP_REG_DSPP_OFFSET(0); basel = mixer->dspp_base; mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); MDSS_MDP_REG_WRITE(base + MDSS_MDP_REG_DSPP_PA_BASE, htc_mdss_pp_pa[HUE_INDEX].req_value); opmode = MDSS_MDP_REG_READ(base); opmode |= (1 << 20); writel_relaxed(opmode, basel + MDSS_MDP_REG_DSPP_OP_MODE); ctl->flush_bits |= BIT(13); wmb(); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); htc_mdss_pp_pa[HUE_INDEX].cur_value = htc_mdss_pp_pa[HUE_INDEX].req_value; PR_DISP_INFO("%s pp_hue = 0x%x\n", __func__, htc_mdss_pp_pa[HUE_INDEX].req_value); }
/** * @mdss_mdp_cdm_destroy - Destroys the CDM configuration and return it to * default state. * @cdm: Pointer to the CDM structure */ int mdss_mdp_cdm_destroy(struct mdss_mdp_cdm *cdm) { int rc = 0; if (!cdm) { pr_err("%s: invalid parameters\n", __func__); return -EINVAL; } mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); mutex_lock(&cdm->lock); /* Disable HDMI packer */ writel_relaxed(0x0, cdm->base + MDSS_MDP_REG_CDM_HDMI_PACK_OP_MODE); /* Put CDM in bypass */ writel_relaxed(0x0, cdm->mdata->mdp_base + MDSS_MDP_MDP_OUT_CTL_0); mutex_unlock(&cdm->lock); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); kref_put(&cdm->kref, mdss_mdp_cdm_free); return rc; }
int mdss_mdp_cmd_reconfigure_splash_done(struct mdss_mdp_ctl *ctl) { struct mdss_panel_data *pdata; int ret = 0; pdata = ctl->panel_data; pdata->panel_info.cont_splash_enabled = 0; ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_FINISH, NULL); mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)0); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); return ret; }
static inline void mdss_mdp_cmd_clk_on(struct mdss_mdp_cmd_ctx *ctx) { unsigned long flags; mutex_lock(&ctx->clk_mtx); if (!ctx->clk_enabled) { ctx->clk_enabled = 1; mdss_mdp_ctl_intf_event (ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)1); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); } spin_lock_irqsave(&ctx->clk_lock, flags); if (!ctx->rdptr_enabled) mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num); ctx->rdptr_enabled = VSYNC_EXPIRE_TICK; spin_unlock_irqrestore(&ctx->clk_lock, flags); mutex_unlock(&ctx->clk_mtx); }
static inline void mdss_mdp_cmd_clk_off(struct mdss_mdp_cmd_ctx *ctx) { unsigned long flags; int set_clk_off = 0; mutex_lock(&ctx->clk_mtx); spin_lock_irqsave(&ctx->clk_lock, flags); if (!ctx->rdptr_enabled) set_clk_off = 1; spin_unlock_irqrestore(&ctx->clk_lock, flags); if (ctx->clk_enabled && set_clk_off) { ctx->clk_enabled = 0; mdss_mdp_ctl_intf_event (ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)0); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); } mutex_unlock(&ctx->clk_mtx); }
static int post_reg_access(struct msm_fb_data_type *mfd) { struct mdss_panel_data *pdata; int ret = 0; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; pdata = dev_get_platdata(&mfd->pdev->dev); if (!pdata) { pr_err("%s: no panel connected\n", __func__); return -ENODEV; } ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); mdss_dsi_clk_ctrl(ctrl_pdata, 0); mdss_bus_bandwidth_ctrl(0); mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode, pdata); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); return ret; }
static int mdss_mdp_video_stop(struct mdss_mdp_ctl *ctl) { struct mdss_mdp_video_ctx *ctx; int off; pr_debug("stop ctl=%d\n", ctl->num); ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data; if (!ctx) { pr_err("invalid ctx for ctl=%d\n", ctl->num); return -ENODEV; } if (ctx->timegen_en) { off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num); MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 0); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); ctx->timegen_en = false; } memset(ctx, 0, sizeof(*ctx)); return 0; }
/* * mdss_check_dsi_ctrl_status() - Check MDP5 DSI controller status periodically. * @work : dsi controller status data * @interval : duration in milliseconds to schedule work queue * * This function calls check_status API on DSI controller to send the BTA * command. If DSI controller fails to acknowledge the BTA command, it sends * the PANEL_ALIVE=0 status to HAL layer. */ void mdss_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval) { struct dsi_status_data *pstatus_data = NULL; struct mdss_panel_data *pdata = NULL; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; struct mdss_overlay_private *mdp5_data = NULL; struct mdss_mdp_ctl *ctl = NULL; int ret = 0; pstatus_data = container_of(to_delayed_work(work), struct dsi_status_data, check_status); if (!pstatus_data || !(pstatus_data->mfd)) { pr_err("%s: mfd not available\n", __func__); return; } pdata = dev_get_platdata(&pstatus_data->mfd->pdev->dev); if (!pdata) { pr_err("%s: Panel data not available\n", __func__); return; } ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); if (!ctrl_pdata || (!ctrl_pdata->check_status && (ctrl_pdata->status_mode != ESD_TE))) { pr_err("%s: DSI ctrl or status_check callback not available\n", __func__); return; } mdp5_data = mfd_to_mdp5_data(pstatus_data->mfd); ctl = mfd_to_ctl(pstatus_data->mfd); if (!ctl) { pr_err("%s: Display is off\n", __func__); return; } if (ctl->power_state == MDSS_PANEL_POWER_OFF) { schedule_delayed_work(&pstatus_data->check_status, msecs_to_jiffies(interval)); pr_debug("%s: ctl not powered on\n", __func__); return; } if (ctrl_pdata->status_mode == ESD_TE) { mdss_check_te_status(ctrl_pdata, pstatus_data, interval); return; } mutex_lock(&ctrl_pdata->mutex); if (ctl->shared_lock) mutex_lock(ctl->shared_lock); mutex_lock(&mdp5_data->ov_lock); if (pstatus_data->mfd->shutdown_pending) { mutex_unlock(&mdp5_data->ov_lock); if (ctl->shared_lock) mutex_unlock(ctl->shared_lock); mutex_unlock(&ctrl_pdata->mutex); pr_err("%s: DSI turning off, avoiding panel status check\n", __func__); return; } /* * For the command mode panels, we return pan display * IOCTL on vsync interrupt. So, after vsync interrupt comes * and when DMA_P is in progress, if the panel stops responding * and if we trigger BTA before DMA_P finishes, then the DSI * FIFO will not be cleared since the DSI data bus control * doesn't come back to the host after BTA. This may cause the * display reset not to be proper. Hence, wait for DMA_P done * for command mode panels before triggering BTA. */ if (ctl->wait_pingpong) ctl->wait_pingpong(ctl, NULL); pr_debug("%s: DSI ctrl wait for ping pong done\n", __func__); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); ret = ctrl_pdata->check_status(ctrl_pdata); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); mutex_unlock(&mdp5_data->ov_lock); if (ctl->shared_lock) mutex_unlock(ctl->shared_lock); mutex_unlock(&ctrl_pdata->mutex); if ((pstatus_data->mfd->panel_power_state == MDSS_PANEL_POWER_ON)) { if (ret > 0) schedule_delayed_work(&pstatus_data->check_status, msecs_to_jiffies(interval)); else mdss_report_panel_dead(pstatus_data); } }
/* * mdss_check_dsi_ctrl_status() - Check MDP5 DSI controller status periodically. * @work : dsi controller status data * @interval : duration in milliseconds to schedule work queue * * This function calls check_status API on DSI controller to send the BTA * command. If DSI controller fails to acknowledge the BTA command, it sends * the PANEL_ALIVE=0 status to HAL layer. */ void mdss_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval) { struct dsi_status_data *pstatus_data = NULL; struct mdss_panel_data *pdata = NULL; struct mipi_panel_info *mipi = NULL; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; struct mdss_overlay_private *mdp5_data = NULL; struct mdss_mdp_ctl *ctl = NULL; int ret = 0; #ifdef VENDOR_EDIT /* Xiaori.Yuan@Mobile Phone Software Dept.Driver, 2015/01/09 Add for 14045 TP and LCD ESD */ int tp_ret=-1; #endif /*VENDOR_EDIT*/ pstatus_data = container_of(to_delayed_work(work), struct dsi_status_data, check_status); if (!pstatus_data || !(pstatus_data->mfd)) { pr_err("%s: mfd not available\n", __func__); return; } pdata = dev_get_platdata(&pstatus_data->mfd->pdev->dev); if (!pdata) { pr_err("%s: Panel data not available\n", __func__); return; } mipi = &pdata->panel_info.mipi; ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); if (!ctrl_pdata || !ctrl_pdata->check_status) { pr_err("%s: DSI ctrl or status_check callback not available\n", __func__); return; } mdp5_data = mfd_to_mdp5_data(pstatus_data->mfd); ctl = mfd_to_ctl(pstatus_data->mfd); if (!ctl) { pr_err("%s: Display is off\n", __func__); return; } if (!ctl->power_on) { schedule_delayed_work(&pstatus_data->check_status, msecs_to_jiffies(interval)); pr_err("%s: ctl not powered on\n", __func__); return; } /* * TODO: Because mdss_dsi_cmd_mdp_busy has made sure DMA to * be idle in mdss_dsi_cmdlist_commit, it is not necessary * to acquire ov_lock in case of video mode. Removing this * lock to fix issues so that ESD thread could block other * overlay operations. Need refine this lock for command mode */ if (mipi->mode == DSI_CMD_MODE) mutex_lock(&mdp5_data->ov_lock); if (pstatus_data->mfd->shutdown_pending || !pstatus_data->mfd->panel_power_on) { if (mipi->mode == DSI_CMD_MODE) mutex_unlock(&mdp5_data->ov_lock); pr_err("%s: DSI turning off, avoiding panel status check\n", __func__); return; } /* * For the command mode panels, we return pan display * IOCTL on vsync interrupt. So, after vsync interrupt comes * and when DMA_P is in progress, if the panel stops responding * and if we trigger BTA before DMA_P finishes, then the DSI * FIFO will not be cleared since the DSI data bus control * doesn't come back to the host after BTA. This may cause the * display reset not to be proper. Hence, wait for DMA_P done * for command mode panels before triggering BTA. */ if (ctl->wait_pingpong) ctl->wait_pingpong(ctl, NULL); pr_debug("%s: DSI ctrl wait for ping pong done\n", __func__); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); ret = ctrl_pdata->check_status(ctrl_pdata); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); if (mipi->mode == DSI_CMD_MODE) mutex_unlock(&mdp5_data->ov_lock); #ifdef VENDOR_EDIT /* Xiaori.Yuan@Mobile Phone Software Dept.Driver, 2015/01/09 Add for 14045 TP and LCD ESD */ if(is_project(OPPO_14045) && tp_esd_check_fn!=NULL) { tp_ret = tp_esd_check_fn(); }else{ tp_ret = 1; } #endif /*VENDOR_EDIT*/ if ((pstatus_data->mfd->panel_power_on)) { /* VENDOR_EDIT Xiaori.Yuan@Mobile Phone Software Dept.Driver, 2015/01/09 Modified for 14045 TP and LCD ESD */ //if (ret > 0) { if ((ret > 0) && (tp_ret >= 0)) { /*VENDOR_EDIT Modified end*/ schedule_delayed_work(&pstatus_data->check_status, msecs_to_jiffies(interval)); } else { char *envp[2] = {"PANEL_ALIVE=0", NULL}; pdata->panel_info.panel_dead = true; ret = kobject_uevent_env( &pstatus_data->mfd->fbi->dev->kobj, KOBJ_CHANGE, envp); pr_err("%s: Panel has gone bad, sending uevent - %s\n", __func__, envp[0]); } } }
void klog(void) { int i; static u32 *buff = NULL; int mdp_reg_count = 0; struct mdss_panel_data *pdata = NULL; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; struct mdss_data_type *mdata = mdss_mdp_get_mdata(); int mdp_reg_dump_en; unsigned long flags; /* NULL Checks */ if(mdata == NULL) return; if(mdata->ctl_off == NULL) return; pdata = (mdata->ctl_off+0)->panel_data; if(pdata ==NULL) return; ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); mdp_reg_dump_en = (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT); if(debug_mdp->reg_log.last*4 >= debug_mdp->reg_log.len ) return; if(debug_mdp->reg_log.len == 0) return; pr_debug("KK: -----------> Inside %s",__func__); #ifdef __KERNEL__ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); spin_lock_irqsave(&xlock, flags); #else if((readl_relaxed(HWIO_MMSS_MDSS_AHB_CBCR_ADDR) & 0x80000000) != 0x0) { pr_info("AHB Clock not ON, Cannot Read MDP Regs\n"); } //Switch on clcok #endif if(debug_mdp && buff == NULL){ buff = (u32 *)((char *)debug_mdp + (sizeof(struct debug_mdp) + debug_mdp->reg_log.offset)); } else if(!debug_mdp){ pr_info("Debug module not Initialized\n"); return ; } pr_debug("KK:------------------->(%s)::>> first: %x \t last: %x buff:%p-%p\n", __func__, debug_mdp->reg_log.first, debug_mdp->reg_log.last,buff,buff+debug_mdp->reg_log.len); if(!mdp_reg_dump_en) i = sizeof(mdss_reg_desc)/sizeof(struct reg_desc) -1; else i = 1; for(; i < sizeof(mdss_reg_desc)/sizeof(struct reg_desc) ; i++){ buff[debug_mdp->reg_log.last++] = START_MAGIC; buff[debug_mdp->reg_log.last++] = mdss_reg_desc[i].base; #if defined(__KERNEL__) if(fill_reg_log(buff, mdss_reg_desc[i].vaddr, mdss_reg_desc[i].len)) pr_info("failed to dump lcd regs at %x ----------> KK\n",mdss_reg_desc[i].base); #else if(fill_reg_log(buff, base, len*4)) pr_info("failed to dump lcd regs at %x ----------> KK\n",base); #endif } #if defined(CONFIG_ARCH_MSM8974) || defined(CONFIG_ARCH_MSM8226) if(mdp_reg_dump_en){ buff[debug_mdp->reg_log.last++] = START_MAGIC; buff[debug_mdp->reg_log.last++] = mdss_reg_desc[0].base; for(i = 0; i < sizeof(mdp_reg_info)/sizeof(u32); i++){ int len; u32 base; len = mdp_reg_info[i] & 0xfff00000; len = len >> 20; len += 1; mdp_reg_count += len; base = mdp_reg_info[i] & 0x000fffff; base = base | mdss_reg_desc[0].base; #if defined(__KERNEL__) if(fill_reg_log(buff, mdp_reg_vaddr[i], len*4)) pr_info("failed to dump lcd regs at %x ----------> KK\n",base); #else if(fill_reg_log(buff, base, len*4)) pr_info("failed to dump lcd regs at %x ----------> KK\n",base); #endif } } #endif #ifdef __KERNEL__ spin_unlock_irqrestore(&xlock, flags); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); #else //Switch off clock #endif pr_debug("total mdp regs: %d\n",mdp_reg_count); }
static void check_dsi_ctrl_status(struct work_struct *work) { struct dsi_status_data *pdsi_status = NULL; struct mdss_panel_data *pdata = NULL; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; struct mdss_overlay_private *mdp5_data = NULL; struct mdss_mdp_ctl *ctl = NULL; int ret = 0; pdsi_status = container_of(to_delayed_work(work), struct dsi_status_data, check_status); if (!pdsi_status) { pr_err("%s: DSI status data not available\n", __func__); return; } //patch + case1481899 mayu 3.27 if(!pdsi_status->mfd){ pr_err("%s:mfd is NULL \n",__func__); return; } //patch - case1481899 mayu 3.27 pdata = dev_get_platdata(&pdsi_status->mfd->pdev->dev); if (!pdata) { pr_err("%s: Panel data not available\n", __func__); return; } ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); if (!ctrl_pdata || !ctrl_pdata->check_status) { pr_err("%s: DSI ctrl or status_check callback not available\n", __func__); return; } //+++duguowei,crash if no lcd if(!ctrl_pdata->panel_name) return; //---duguowei,crash if no lcd mdp5_data = mfd_to_mdp5_data(pdsi_status->mfd); ctl = mfd_to_ctl(pdsi_status->mfd); if (ctl->shared_lock) mutex_lock(ctl->shared_lock); mutex_lock(&mdp5_data->ov_lock); /* * For the command mode panels, we return pan display * IOCTL on vsync interrupt. So, after vsync interrupt comes * and when DMA_P is in progress, if the panel stops responding * and if we trigger BTA before DMA_P finishes, then the DSI * FIFO will not be cleared since the DSI data bus control * doesn't come back to the host after BTA. This may cause the * display reset not to be proper. Hence, wait for DMA_P done * for command mode panels before triggering BTA. */ if (pdsi_status->mfd->shutdown_pending) { mutex_unlock(&mdp5_data->ov_lock); if (ctl->shared_lock) mutex_unlock(ctl->shared_lock); return; } if (ctl->wait_pingpong) ctl->wait_pingpong(ctl, NULL); pr_debug("%s: DSI ctrl wait for ping pong done\n", __func__); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); ret = ctrl_pdata->check_status(ctrl_pdata); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); mutex_unlock(&mdp5_data->ov_lock); if (ctl->shared_lock) mutex_unlock(ctl->shared_lock); if ((pdsi_status->mfd->panel_power_on)) { if (ret > 0) { schedule_delayed_work(&pdsi_status->check_status, msecs_to_jiffies(pdsi_status->check_interval)); } else { #ifdef CONFIG_ZTEMT_NE501_LCD if (mipi_lcd_esd_command(ctrl_pdata)) { char *envp[2] = {"PANEL_ALIVE=0", NULL}; pdata->panel_info.panel_dead = true; ret = kobject_uevent_env( &pdsi_status->mfd->fbi->dev->kobj, KOBJ_CHANGE, envp); pr_err("%s: Panel has gone bad, sending uevent - %s\n", __func__, envp[0]); printk("default reset panel\n"); } #else char *envp[2] = {"PANEL_ALIVE=0", NULL}; pdata->panel_info.panel_dead = true; ret = kobject_uevent_env( &pdsi_status->mfd->fbi->dev->kobj, KOBJ_CHANGE, envp); pr_err("%s: Panel has gone bad, sending uevent - %s\n", __func__, envp[0]); #endif } } }
/* * mdss_check_dsi_ctrl_status() - Check MDP5 DSI controller status periodically. * @work : dsi controller status data * @interval : duration in milliseconds to schedule work queue * * This function calls check_status API on DSI controller to send the BTA * command. If DSI controller fails to acknowledge the BTA command, it sends * the PANEL_ALIVE=0 status to HAL layer. */ void mdss_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval) { struct dsi_status_data *pstatus_data = NULL; struct mdss_panel_data *pdata = NULL; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; struct mdss_overlay_private *mdp5_data = NULL; struct mdss_mdp_ctl *ctl = NULL; int ret = 0; pstatus_data = container_of(to_delayed_work(work), struct dsi_status_data, check_status); if (!pstatus_data || !(pstatus_data->mfd)) { pr_err("%s: mfd not available\n", __func__); return; } pdata = dev_get_platdata(&pstatus_data->mfd->pdev->dev); if (!pdata) { pr_err("%s: Panel data not available\n", __func__); return; } ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); if (!ctrl_pdata || !ctrl_pdata->check_status) { pr_err("%s: DSI ctrl or status_check callback not available\n", __func__); return; } mdp5_data = mfd_to_mdp5_data(pstatus_data->mfd); ctl = mfd_to_ctl(pstatus_data->mfd); if (!ctl) { pr_err("%s: Display is off\n", __func__); return; } if (!ctl->power_on) { schedule_delayed_work(&pstatus_data->check_status, msecs_to_jiffies(interval)); pr_err("%s: ctl not powered on\n", __func__); return; } if (ctl->shared_lock) mutex_lock(ctl->shared_lock); mutex_lock(&mdp5_data->ov_lock); if (pstatus_data->mfd->shutdown_pending || !pstatus_data->mfd->panel_power_on) { mutex_unlock(&mdp5_data->ov_lock); if (ctl->shared_lock) mutex_unlock(ctl->shared_lock); pr_err("%s: DSI turning off, avoiding panel status check\n", __func__); return; } /* * For the command mode panels, we return pan display * IOCTL on vsync interrupt. So, after vsync interrupt comes * and when DMA_P is in progress, if the panel stops responding * and if we trigger BTA before DMA_P finishes, then the DSI * FIFO will not be cleared since the DSI data bus control * doesn't come back to the host after BTA. This may cause the * display reset not to be proper. Hence, wait for DMA_P done * for command mode panels before triggering BTA. */ if (ctl->wait_pingpong) ctl->wait_pingpong(ctl, NULL); pr_debug("%s: DSI ctrl wait for ping pong done\n", __func__); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); ret = ctrl_pdata->check_status(ctrl_pdata); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); mutex_unlock(&mdp5_data->ov_lock); if (ctl->shared_lock) mutex_unlock(ctl->shared_lock); if ((pstatus_data->mfd->panel_power_on)) { if (ret > 0) { schedule_delayed_work(&pstatus_data->check_status, msecs_to_jiffies(interval)); } else { char *envp[2] = {"PANEL_ALIVE=0", NULL}; pdata->panel_info.panel_dead = true; ret = kobject_uevent_env( &pstatus_data->mfd->fbi->dev->kobj, KOBJ_CHANGE, envp); pr_err("%s: Panel has gone bad, sending uevent - %s\n", __func__, envp[0]); } } }
void mdss_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval) { struct dsi_status_data *pstatus_data = NULL; struct mdss_panel_data *pdata = NULL; struct mipi_panel_info *mipi = NULL; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; struct mdss_overlay_private *mdp5_data = NULL; struct mdss_mdp_ctl *ctl = NULL; int ret = 0; pstatus_data = container_of(to_delayed_work(work), struct dsi_status_data, check_status); if (!pstatus_data || !(pstatus_data->mfd)) { pr_err("%s: mfd not available\n", __func__); return; } pdata = dev_get_platdata(&pstatus_data->mfd->pdev->dev); if (!pdata) { pr_err("%s: Panel data not available\n", __func__); return; } mipi = &pdata->panel_info.mipi; ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); if (!ctrl_pdata || (!ctrl_pdata->check_status && (ctrl_pdata->status_mode != ESD_TE))) { pr_err("%s: DSI ctrl or status_check callback not available\n", __func__); return; } mdp5_data = mfd_to_mdp5_data(pstatus_data->mfd); ctl = mfd_to_ctl(pstatus_data->mfd); if (!ctl) { pr_err("%s: Display is off\n", __func__); return; } if (ctl->power_state == MDSS_PANEL_POWER_OFF) { schedule_delayed_work(&pstatus_data->check_status, msecs_to_jiffies(interval)); pr_debug("%s: ctl not powered on\n", __func__); return; } if (ctrl_pdata->status_mode == ESD_TE) { mdss_check_te_status(ctrl_pdata, pstatus_data, interval); return; } mutex_lock(&ctl->offlock); if (mipi->mode == DSI_CMD_MODE) mutex_lock(&mdp5_data->ov_lock); if (mdss_panel_is_power_off(pstatus_data->mfd->panel_power_state) || pstatus_data->mfd->shutdown_pending) { if (mipi->mode == DSI_CMD_MODE) mutex_unlock(&mdp5_data->ov_lock); mutex_unlock(&ctl->offlock); pr_err("%s: DSI turning off, avoiding panel status check\n", __func__); return; } if (ctl->wait_pingpong) ctl->wait_pingpong(ctl, NULL); pr_debug("%s: DSI ctrl wait for ping pong done\n", __func__); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); ret = ctrl_pdata->check_status(ctrl_pdata); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); if (mipi->mode == DSI_CMD_MODE) mutex_unlock(&mdp5_data->ov_lock); mutex_unlock(&ctl->offlock); if ((pstatus_data->mfd->panel_power_state == MDSS_PANEL_POWER_ON)) { if (ret > 0) schedule_delayed_work(&pstatus_data->check_status, msecs_to_jiffies(interval)); else mdss_report_panel_dead(pstatus_data); } }
int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg) { int mixer1_changed, mixer2_changed; int ret = 0; int perf_update = MDSS_MDP_PERF_UPDATE_SKIP; u32 update_flags = 0; if (!ctl) { pr_err("display function not set\n"); return -ENODEV; } pr_debug("commit ctl=%d play_cnt=%d\n", ctl->num, ctl->play_cnt); ret = mutex_lock_interruptible(&ctl->lock); if (ret) return ret; if (!ctl->power_on) { mutex_unlock(&ctl->lock); return 0; } mixer1_changed = (ctl->mixer_left && ctl->mixer_left->params_changed); mixer2_changed = (ctl->mixer_right && ctl->mixer_right->params_changed); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); if (mixer1_changed || mixer2_changed) { perf_update = mdss_mdp_ctl_perf_update(ctl, &update_flags); if (ctl->prepare_fnc) ret = ctl->prepare_fnc(ctl, arg); if (ret) { pr_err("error preparing display\n"); goto done; } if (perf_update == MDSS_MDP_PERF_UPDATE_EARLY) mdss_mdp_ctl_perf_commit(update_flags); if (mixer1_changed) mdss_mdp_mixer_update(ctl->mixer_left); if (mixer2_changed) mdss_mdp_mixer_update(ctl->mixer_right); mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_TOP, ctl->opmode); ctl->flush_bits |= BIT(17); /* CTL */ } /* postprocessing setup, including dspp */ mdss_mdp_pp_setup(ctl); mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl->flush_bits); wmb(); ctl->flush_bits = 0; if (ctl->display_fnc) ret = ctl->display_fnc(ctl, arg); /* kickoff */ if (ret) pr_warn("error displaying frame\n"); ctl->play_cnt++; if (perf_update == MDSS_MDP_PERF_UPDATE_LATE) mdss_mdp_ctl_perf_commit(update_flags); done: mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); mutex_unlock(&ctl->lock); return ret; }