void mdss_dsi_cmd_mdp_busy(struct mdss_dsi_ctrl_pdata *ctrl) { unsigned long flags; int need_wait = 0; pr_debug("%s: start pid=%d\n", __func__, current->pid); MDSS_XLOG(ctrl->ndx, ctrl->mdp_busy, current->pid, XLOG_FUNC_ENTRY); spin_lock_irqsave(&ctrl->mdp_lock, flags); if (ctrl->mdp_busy == true) need_wait++; spin_unlock_irqrestore(&ctrl->mdp_lock, flags); if (need_wait) { /* wait until DMA finishes the current job */ pr_debug("%s: pending pid=%d\n", __func__, current->pid); if (!wait_for_completion_timeout(&ctrl->mdp_comp, msecs_to_jiffies(DMA_TX_TIMEOUT))) { pr_err("%s: timeout error\n", __func__); MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0", "dsi1", "edp", "hdmi", "panic"); } } pr_debug("%s: done pid=%d\n", __func__, current->pid); MDSS_XLOG(ctrl->ndx, ctrl->mdp_busy, current->pid, XLOG_FUNC_EXIT); }
int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp) { struct dcs_cmd_req *req; int ret = -EINVAL; int rc = 0; mutex_lock(&ctrl->cmd_mutex); req = mdss_dsi_cmdlist_get(ctrl); MDSS_XLOG(ctrl->ndx, from_mdp, ctrl->mdp_busy, current->pid, XLOG_FUNC_ENTRY); /* make sure dsi_cmd_mdp is idle */ mdss_dsi_cmd_mdp_busy(ctrl); pr_debug("%s: from_mdp=%d pid=%d\n", __func__, from_mdp, current->pid); if (req == NULL) goto need_lock; MDSS_XLOG(ctrl->ndx, req->flags, req->cmds_cnt, from_mdp, current->pid); /* * mdss interrupt is generated in mdp core clock domain * mdp clock need to be enabled to receive dsi interrupt * also, axi bus bandwidth need since dsi controller will * fetch dcs commands from axi bus */ mdss_bus_bandwidth_ctrl(1); pr_debug("%s: from_mdp=%d pid=%d\n", __func__, from_mdp, current->pid); mdss_dsi_clk_ctrl(ctrl, 1); rc = mdss_iommu_ctrl(1); if (IS_ERR_VALUE(rc)) { pr_err("IOMMU attach failed\n"); mutex_unlock(&ctrl->cmd_mutex); return rc; } if (req->flags & CMD_REQ_RX) ret = mdss_dsi_cmdlist_rx(ctrl, req); else ret = mdss_dsi_cmdlist_tx(ctrl, req); mdss_iommu_ctrl(0); mdss_dsi_clk_ctrl(ctrl, 0); mdss_bus_bandwidth_ctrl(0); need_lock: if (from_mdp) /* from pipe_commit */ mdss_dsi_cmd_mdp_start(ctrl); MDSS_XLOG(ctrl->ndx, from_mdp, ctrl->mdp_busy, current->pid, XLOG_FUNC_EXIT); mutex_unlock(&ctrl->cmd_mutex); return ret; }
irqreturn_t mdss_dsi_isr(int irq, void *ptr) { u32 isr; struct mdss_dsi_ctrl_pdata *ctrl = (struct mdss_dsi_ctrl_pdata *)ptr; if (!ctrl->ctrl_base) pr_err("%s:%d DSI base adr no Initialized", __func__, __LINE__); isr = MIPI_INP(ctrl->ctrl_base + 0x0110);/* DSI_INTR_CTRL */ MIPI_OUTP(ctrl->ctrl_base + 0x0110, isr); pr_debug("%s: ndx=%d isr=%x\n", __func__, ctrl->ndx, isr); if (isr & DSI_INTR_ERROR) { MDSS_XLOG(ctrl->ndx, ctrl->mdp_busy, isr, 0x97); pr_err("%s: ndx=%d isr=%x\n", __func__, ctrl->ndx, isr); mdss_dsi_error(ctrl); } if (isr & DSI_INTR_VIDEO_DONE) { spin_lock(&ctrl->mdp_lock); mdss_dsi_disable_irq_nosync(ctrl, DSI_VIDEO_TERM); complete(&ctrl->video_comp); spin_unlock(&ctrl->mdp_lock); } if (isr & DSI_INTR_CMD_DMA_DONE) { MDSS_XLOG(ctrl->ndx, ctrl->mdp_busy, isr, 0x98); spin_lock(&ctrl->mdp_lock); mdss_dsi_disable_irq_nosync(ctrl, DSI_CMD_TERM); complete(&ctrl->dma_comp); spin_unlock(&ctrl->mdp_lock); } if (isr & DSI_INTR_CMD_MDP_DONE) { MDSS_XLOG(ctrl->ndx, ctrl->mdp_busy, isr, 0x99); spin_lock(&ctrl->mdp_lock); ctrl->mdp_busy = false; mdss_dsi_disable_irq_nosync(ctrl, DSI_MDP_TERM); complete(&ctrl->mdp_comp); spin_unlock(&ctrl->mdp_lock); } if (isr & DSI_INTR_BTA_DONE) { spin_lock(&ctrl->mdp_lock); mdss_dsi_disable_irq_nosync(ctrl, DSI_BTA_TERM); complete(&ctrl->bta_comp); spin_unlock(&ctrl->mdp_lock); } return IRQ_HANDLED; }
void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl, int enable) { MDSS_XLOG(ctrl->ndx, enable, ctrl->mdp_busy, current->pid); if (enable == 0) { /* need wait before disable */ mutex_lock(&ctrl->cmd_mutex); mdss_dsi_cmd_mdp_busy(ctrl); mutex_unlock(&ctrl->cmd_mutex); } MDSS_XLOG(ctrl->ndx, enable, ctrl->mdp_busy, current->pid); mdss_dsi_clk_ctrl(ctrl, enable); }
void mdss_dsi_cmd_mdp_start(struct mdss_dsi_ctrl_pdata *ctrl) { unsigned long flag; spin_lock_irqsave(&ctrl->mdp_lock, flag); mdss_dsi_enable_irq(ctrl, DSI_MDP_TERM); ctrl->mdp_busy = true; INIT_COMPLETION(ctrl->mdp_comp); MDSS_XLOG(ctrl->ndx, ctrl->mdp_busy, current->pid); spin_unlock_irqrestore(&ctrl->mdp_lock, flag); }
/* * mdss_dsi_disale_irq_nosync() should be called * from interrupt context */ void mdss_dsi_disable_irq_nosync(struct mdss_dsi_ctrl_pdata *ctrl, u32 term) { spin_lock(&ctrl->irq_lock); if (!(ctrl->dsi_irq_mask & term)) { spin_unlock(&ctrl->irq_lock); return; } ctrl->dsi_irq_mask &= ~term; if (ctrl->dsi_irq_mask == 0) { MDSS_XLOG(ctrl->ndx, term); mdss_disable_irq_nosync(ctrl->dsi_hw); pr_debug("%s: IRQ Disable, ndx=%d mask=%x term=%x\n", __func__, ctrl->ndx, (int)ctrl->dsi_irq_mask, (int)term); } spin_unlock(&ctrl->irq_lock); }
void mdss_dsi_disable_irq(struct mdss_dsi_ctrl_pdata *ctrl, u32 term) { unsigned long flags; spin_lock_irqsave(&ctrl->irq_lock, flags); if (!(ctrl->dsi_irq_mask & term)) { spin_unlock_irqrestore(&ctrl->irq_lock, flags); return; } ctrl->dsi_irq_mask &= ~term; if (ctrl->dsi_irq_mask == 0) { MDSS_XLOG(ctrl->ndx, term); mdss_disable_irq(ctrl->dsi_hw); pr_debug("%s: IRQ Disable, ndx=%d mask=%x term=%x\n", __func__, ctrl->ndx, (int)ctrl->dsi_irq_mask, (int)term); } spin_unlock_irqrestore(&ctrl->irq_lock, flags); }
static int mdss_mdp_rotator_busy_wait(struct mdss_mdp_rotator_session *rot) { mutex_lock(&rot->lock); if (!rot->pipe || !rot->pipe->mixer_left || !rot->pipe->mixer_left->ctl) { mutex_unlock(&rot->lock); return -ENODEV; } if (rot->busy) { struct mdss_mdp_ctl *ctl = rot->pipe->mixer_left->ctl; mdss_mdp_display_wait4comp(ctl); rot->busy = false; MDSS_XLOG(rot->session_id, 0x222); if (ctl->shared_lock) mutex_unlock(ctl->shared_lock); } mutex_unlock(&rot->lock); return 0; }
static struct mdss_mdp_pipe *mdss_mdp_rotator_pipe_alloc(void) { struct mdss_mdp_mixer *mixer; struct mdss_mdp_pipe *pipe = NULL; mixer = mdss_mdp_wb_mixer_alloc(1); if (!mixer) { pr_debug("wb mixer alloc failed\n"); return NULL; } pipe = mdss_mdp_pipe_alloc_dma(mixer); if (!pipe) { mdss_mdp_wb_mixer_destroy(mixer); pr_debug("dma pipe allocation failed\n"); return NULL; } MDSS_XLOG(pipe->num, mixer->num); pipe->mixer_stage = MDSS_MDP_STAGE_UNUSED; return pipe; }
static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, int event, void *arg) { int rc = 0; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; if (pdata == NULL) { pr_err("%s: Invalid input data\n", __func__); return -EINVAL; } ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); pr_debug("%s+:event=%d\n", __func__, event); MDSS_XLOG(event, arg, ctrl_pdata->ndx, 0x3333); switch (event) { case MDSS_EVENT_UNBLANK: rc = mdss_dsi_on(pdata); mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode, pdata); if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE) rc = mdss_dsi_unblank(pdata); break; case MDSS_EVENT_PANEL_ON: ctrl_pdata->ctrl_state |= CTRL_STATE_MDP_ACTIVE; if (ctrl_pdata->on_cmds.link_state == DSI_HS_MODE) rc = mdss_dsi_unblank(pdata); break; case MDSS_EVENT_BLANK: if (ctrl_pdata->off_cmds.link_state == DSI_HS_MODE) rc = mdss_dsi_blank(pdata); break; case MDSS_EVENT_PANEL_OFF: ctrl_pdata->ctrl_state &= ~CTRL_STATE_MDP_ACTIVE; if (ctrl_pdata->off_cmds.link_state == DSI_LP_MODE) rc = mdss_dsi_blank(pdata); rc = mdss_dsi_off(pdata); break; case MDSS_EVENT_CONT_SPLASH_FINISH: if (ctrl_pdata->off_cmds.link_state == DSI_LP_MODE) rc = mdss_dsi_blank(pdata); ctrl_pdata->ctrl_state &= ~CTRL_STATE_MDP_ACTIVE; rc = mdss_dsi_cont_splash_on(pdata); break; case MDSS_EVENT_PANEL_CLK_CTRL: mdss_dsi_clk_req(ctrl_pdata, (int) (unsigned long) arg); break; case MDSS_EVENT_DSI_CMDLIST_KOFF: ctrl_pdata->recovery = (struct mdss_panel_recovery *)arg; mdss_dsi_cmdlist_commit(ctrl_pdata, 1); break; case MDSS_EVENT_PANEL_UPDATE_FPS: if (arg != NULL) { rc = mdss_dsi_dfps_config(pdata, (int) (unsigned long) arg); pr_debug("%s:update fps to = %d\n", __func__, (int) (unsigned long) arg); } break; case MDSS_EVENT_CONT_SPLASH_BEGIN: if (ctrl_pdata->off_cmds.link_state == DSI_HS_MODE) { /* Panel is Enabled in Bootloader */ rc = mdss_dsi_blank(pdata); } break; case MDSS_EVENT_ENABLE_PARTIAL_UPDATE: rc = mdss_dsi_ctl_partial_update(pdata); break; case MDSS_EVENT_DSI_DYNAMIC_SWITCH: rc = mdss_dsi_update_panel_config(ctrl_pdata, (int)(unsigned long) arg); break; default: pr_debug("%s: unhandled event=%d\n", __func__, event); break; } pr_debug("%s-:event=%d, rc=%d\n", __func__, event, rc); return rc; }
static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, int event, void *arg) { int rc = 0; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; int power_state; if (pdata == NULL) { pr_err("%s: Invalid input data\n", __func__); return -EINVAL; } ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); pr_debug("%s+: ctrl=%d event=%d\n", __func__, ctrl_pdata->ndx, event); MDSS_XLOG(event, arg, ctrl_pdata->ndx, 0x3333); switch (event) { case MDSS_EVENT_UNBLANK: // pr_info("%s : MDSS_EVENT_UNBLANK \n", __func__); pr_info("%s :(%d) MDSS_EVENT_UNBLANK (%s)\n", __func__, ctrl_pdata->ndx, ctrl_pdata->on_cmds.link_state? "HS" : "LP"); rc = mdss_dsi_on(pdata); mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode, pdata); if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE) rc = mdss_dsi_unblank(pdata); break; case MDSS_EVENT_PANEL_ON: //pr_info("%s : MDSS_EVENT_PANEL_ON \n", __func__); pr_info("%s :(%d) MDSS_EVENT_PANEL_ON (%s)\n", __func__, ctrl_pdata->ndx, ctrl_pdata->on_cmds.link_state? "HS" : "LP"); ctrl_pdata->ctrl_state |= CTRL_STATE_MDP_ACTIVE; if (ctrl_pdata->on_cmds.link_state == DSI_HS_MODE) rc = mdss_dsi_unblank(pdata); break; case MDSS_EVENT_BLANK: pr_info("%s :(%d) MDSS_EVENT_BLANK (%s)\n", __func__, ctrl_pdata->ndx, ctrl_pdata->off_cmds.link_state? "HS" : "LP"); power_state = (int) (unsigned long) arg; if (ctrl_pdata->off_cmds.link_state == DSI_HS_MODE) rc = mdss_dsi_blank(pdata, power_state); break; case MDSS_EVENT_PANEL_OFF: pr_info("%s :(%d) MDSS_EVENT_PANEL_OFF (%s) \n", __func__, ctrl_pdata->ndx, ctrl_pdata->off_cmds.link_state? "HS" : "LP"); power_state = (int) (unsigned long) arg; ctrl_pdata->ctrl_state &= ~CTRL_STATE_MDP_ACTIVE; if (ctrl_pdata->off_cmds.link_state == DSI_LP_MODE) rc = mdss_dsi_blank(pdata, power_state); rc = mdss_dsi_off(pdata, power_state); break; case MDSS_EVENT_FB_REGISTERED: pr_info("%s : MDSS_EVENT_FB_REGISTERED \n", __func__); if (ctrl_pdata->registered) { pr_debug("%s:event=%d, calling panel registered callback \n", __func__, event); rc = ctrl_pdata->registered(pdata); } break; case MDSS_EVENT_CONT_SPLASH_FINISH: pr_info("%s : MDSS_EVENT_CONT_SPLASH_FINISH \n", __func__); if (ctrl_pdata->off_cmds.link_state == DSI_LP_MODE) rc = mdss_dsi_blank(pdata, MDSS_PANEL_POWER_OFF); ctrl_pdata->ctrl_state &= ~CTRL_STATE_MDP_ACTIVE; #if defined(CONFIG_FB_MSM_MDSS_SAMSUNG) ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_INIT; #endif rc = mdss_dsi_cont_splash_on(pdata); break; case MDSS_EVENT_PANEL_CLK_CTRL: mdss_dsi_clk_req(ctrl_pdata, (int) (unsigned long) arg); break; case MDSS_EVENT_DSI_CMDLIST_KOFF: ctrl_pdata->recovery = (struct mdss_panel_recovery *)arg; mdss_dsi_cmdlist_commit(ctrl_pdata, 1); break; case MDSS_EVENT_PANEL_UPDATE_FPS: if (arg != NULL) { rc = mdss_dsi_dfps_config(pdata, (int) (unsigned long) arg); pr_debug("%s:update fps to = %d\n", __func__, (int) (unsigned long) arg); } break; case MDSS_EVENT_CONT_SPLASH_BEGIN: pr_info("%s : MDSS_EVENT_CONT_SPLASH_BEGIN \n", __func__); if (ctrl_pdata->off_cmds.link_state == DSI_HS_MODE) { /* Panel is Enabled in Bootloader */ rc = mdss_dsi_blank(pdata, MDSS_PANEL_POWER_OFF); } break; case MDSS_EVENT_ENABLE_PARTIAL_ROI: rc = mdss_dsi_ctl_partial_roi(pdata); break; case MDSS_EVENT_DSI_STREAM_SIZE: rc = mdss_dsi_set_stream_size(pdata); break; default: #if defined(CONFIG_FB_MSM_MDSS_SAMSUNG) if(ctrl_pdata->event_handler) rc = ctrl_pdata->event_handler(pdata, event, arg); else #endif pr_debug("%s: unhandled event=%d\n", __func__, event); break; } pr_debug("%s-:event=%d, rc=%d\n", __func__, event, rc); return rc; }
int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp) { struct dcs_cmd_req *req; struct mdss_panel_info *pinfo; struct mdss_rect *roi = NULL; int ret = -EINVAL; int rc = 0; if (from_mdp) /* from mdp kickoff */ mutex_lock(&ctrl->cmd_mutex); req = mdss_dsi_cmdlist_get(ctrl); MDSS_XLOG(ctrl->ndx, from_mdp, ctrl->mdp_busy, current->pid, XLOG_FUNC_ENTRY); /* make sure dsi_cmd_mdp is idle */ mdss_dsi_cmd_mdp_busy(ctrl); pr_debug("%s: ctrl=%d from_mdp=%d pid=%d\n", __func__, ctrl->ndx, from_mdp, current->pid); if (req == NULL) goto need_lock; MDSS_XLOG(ctrl->ndx, req->flags, req->cmds_cnt, from_mdp, current->pid); /* * mdss interrupt is generated in mdp core clock domain * mdp clock need to be enabled to receive dsi interrupt * also, axi bus bandwidth need since dsi controller will * fetch dcs commands from axi bus */ mdss_bus_scale_set_quota(MDSS_HW_DSI0, SZ_1M, SZ_1M); pr_debug("%s: from_mdp=%d pid=%d\n", __func__, from_mdp, current->pid); mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, 1); rc = mdss_iommu_ctrl(1); if (IS_ERR_VALUE(rc)) { pr_err("IOMMU attach failed\n"); mutex_unlock(&ctrl->cmd_mutex); return rc; } if (req->flags & CMD_REQ_RX) ret = mdss_dsi_cmdlist_rx(ctrl, req); else ret = mdss_dsi_cmdlist_tx(ctrl, req); mdss_iommu_ctrl(0); mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, 0); mdss_bus_scale_set_quota(MDSS_HW_DSI0, 0, 0); need_lock: MDSS_XLOG(ctrl->ndx, from_mdp, ctrl->mdp_busy, current->pid, XLOG_FUNC_EXIT); if (from_mdp) { /* from mdp kickoff */ /* * when partial update enabled, the roi of pinfo * is updated before mdp kickoff. Either width or * height of roi is 0, then it is false kickoff so * no mdp_busy flag set needed. * when partial update disabled, mdp_busy flag * alway set. */ pinfo = &ctrl->panel_data.panel_info; if (pinfo->partial_update_enabled) roi = &pinfo->roi; if (!roi || (roi->w != 0 || roi->h != 0)) mdss_dsi_cmd_mdp_start(ctrl); mutex_unlock(&ctrl->cmd_mutex); } return ret; }