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; 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; } if (pdata->panel_info.type == MIPI_CMD_PANEL) { if (ctl->display_fnc) ret = ctl->display_fnc(ctl, NULL); if (ret) pr_warn("error displaying frame\n"); } mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata); 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; }
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); } }
/* * 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]); } } }
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]); } } }
static ssize_t reg_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { struct seq_file *s = file->private_data; struct msm_fb_data_type *mfd = s->private; struct mdss_panel_data *pdata; struct mdss_mdp_ctl *ctl; char *buf; const char *p; enum dbg_cmd_type cmd; u8 data[MAX_WRITE_DATA]; int i = 0; int j; int ret; struct dsi_cmd_desc dsi; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; if (!mfd->panel_power_on) { pr_err("%s: panel is NOT on\n", __func__); goto exit; } ctl = mfd_to_ctl(mfd); if (!ctl) goto exit; if (mutex_lock_interruptible(&ctl->lock)) goto exit; pdata = dev_get_platdata(&mfd->pdev->dev); if (!pdata) { pr_err("%s: no panel connected\n", __func__); goto exit; } ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); if (!ctrl_pdata) { pr_err("%s: Invalid input data\n", __func__); goto exit; } pr_err("%s\n", __func__); ret = setup_reg_access(&buf, ubuf, count); if (ret) goto exit; ret = get_cmd_type(buf, &cmd); if (ret) { update_res_buf("Write - unknown type\n"); goto fail_free_all; } p = buf; p = p+4; /* Get first param, Register */ if (sscanf(p, "%4hhx", &data[0]) != 1) { update_res_buf("Write - parameter error\n"); ret = -EINVAL; goto fail_free_all; } i++; while (isxdigit(*p) || (*p == 'x')) p++; ret = get_parameters(p, data, ARRAY_SIZE(data) - 1, &i); if (ret) goto fail_free_all; ret = prepare_for_reg_access(mfd); if (ret) goto fail_free_all; if (cmd == DCS) { if (i == 1) { /* 0 parameters */ dsi.dchdr.dtype = DTYPE_DCS_WRITE; } else if (i == 2) { /* 1 parameter */ dsi.dchdr.dtype = DTYPE_DCS_WRITE1; } else { /* Many parameters */ dsi.dchdr.dtype = DTYPE_DCS_LWRITE; } } else { if (i == 1) { /* 0 parameters */ dsi.dchdr.dtype = DTYPE_GEN_WRITE; } else if (i == 2) { /* 1 parameter */ dsi.dchdr.dtype = DTYPE_GEN_WRITE1; } else if (i == 3) { /* 2 parameters */ dsi.dchdr.dtype = DTYPE_GEN_WRITE2; } else { /* Many parameters */ dsi.dchdr.dtype = DTYPE_GEN_LWRITE; } } dsi.dchdr.last = 1; dsi.dchdr.vc = 0; dsi.dchdr.ack = 0; dsi.dchdr.wait = 0; dsi.dchdr.dlen = i; dsi.payload = data; pr_err("%s: last = %d, vc = %d, ack = %d, wait = %d, dlen = %d\n", __func__, dsi.dchdr.last, dsi.dchdr.vc, dsi.dchdr.ack, dsi.dchdr.wait, dsi.dchdr.dlen); for (j = 0; j < i; j++) pr_err("%s: payload[%d] = 0x%x\n", __func__, j, dsi.payload[j]); mdss_dsi_cmds_tx(ctrl_pdata, &dsi, 1); ret = post_reg_access(mfd); if (ret) goto fail_free_all; print_params(dsi.dchdr.dtype, data[0], i, dsi.payload); mutex_unlock(&ctl->lock); fail_free_all: kfree(buf); exit: return count; }
static ssize_t reg_read(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { struct seq_file *s = file->private_data; struct msm_fb_data_type *mfd = s->private; struct mdss_panel_data *pdata; struct mdss_mdp_ctl *ctl; u8 params[3]; /* No more than reg + two parameters is allowed */ char *buf; const char *p; int ret; int nbr_bytes_to_read; int i; int j; enum dbg_cmd_type cmd; struct dsi_cmd_desc dsi; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; if (!mfd->panel_power_on) { pr_err("%s: panel is NOT on\n", __func__); goto exit; } ctl = mfd_to_ctl(mfd); if (!ctl) goto exit; if (mutex_lock_interruptible(&ctl->lock)) goto exit; pdata = dev_get_platdata(&mfd->pdev->dev); if (!pdata) { pr_err("%s: no panel connected\n", __func__); goto exit; } ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); if (!ctrl_pdata) { pr_err("%s: Invalid input data\n", __func__); goto exit; } pr_err("%s\n", __func__); ret = setup_reg_access(&buf, ubuf, count); if (ret) goto exit; ret = get_cmd_type(buf, &cmd); if (ret) { update_res_buf("Read - unknown type\n"); goto fail_free_all; } p = buf; p = p+4; /* Get nbr_bytes_to_read */ if (sscanf(p, "%d", &nbr_bytes_to_read) != 1) { update_res_buf("Read - parameter error\n"); ret = -EINVAL; goto fail_free_all; } while (isxdigit(*p) || (*p == 'x')) p++; pr_err("%s: nbr_bytes_to_read = %d\n", __func__, nbr_bytes_to_read); i = 0; ret = get_parameters(p, params, ARRAY_SIZE(params), &i); if (ret) goto fail_free_all; ret = prepare_for_reg_access(mfd); if (ret) goto fail_free_all; if (cmd == DCS) { dsi.dchdr.dtype = DTYPE_DCS_READ; } else { if (i == 1) { /* 0 parameters */ dsi.dchdr.dtype = DTYPE_GEN_READ; } else if (i == 2) { /* 1 parameter */ dsi.dchdr.dtype = DTYPE_GEN_READ1; } else { /* 2 paramters */ dsi.dchdr.dtype = DTYPE_GEN_READ2; } } dsi.dchdr.last = 1; dsi.dchdr.vc = 0; dsi.dchdr.ack = 1; dsi.dchdr.wait = 5; dsi.dchdr.dlen = i; dsi.payload = params; pr_err("%s: dtype=%d, last=%d, vc=%d, ack=%d, wait=%d, dlen=%d\n", __func__, dsi.dchdr.dtype, dsi.dchdr.last, dsi.dchdr.vc, dsi.dchdr.ack, dsi.dchdr.wait, dsi.dchdr.dlen); for (j = 0; j < i; j++) pr_err("%s: payload[%d] = 0x%x\n", __func__, j, dsi.payload[j]); mdss_dsi_cmds_rx(ctrl_pdata, &dsi, nbr_bytes_to_read, 0); ret = post_reg_access(mfd); if (ret) goto fail_free_all; print_params(dsi.dchdr.dtype, params[0], ctrl_pdata->rx_buf.len, ctrl_pdata->rx_buf.data); mutex_unlock(&ctl->lock); fail_free_all: kfree(buf); exit: return count; }
/* * 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; 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(&ctrl_pdata->mutex); /* * 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 would not block other * overlay operations. Need refine this lock for command mode */ if (mipi->mode == DSI_CMD_MODE) mutex_lock(&mdp5_data->ov_lock); if (mdss_panel_is_power_off(pstatus_data->mfd->panel_power_state)) { if (mipi->mode == DSI_CMD_MODE) mutex_unlock(&mdp5_data->ov_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); if (mipi->mode == DSI_CMD_MODE) mutex_unlock(&mdp5_data->ov_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); } }