Loading Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt +1 −0 Original line number Diff line number Diff line Loading @@ -344,6 +344,7 @@ Optional properties: - qcom,mdss-dsi-panel-status-check-mode:Specifies the panel status check method for ESD recovery. "bta_check" = Uses BTA to check the panel status "reg_read" = Reads panel status register to check the panel status "te_signal_check" = Uses TE signal behaviour to check the panel status - qcom,mdss-dsi-panel-status-value: Specifies the value of the panel status register when the panel is in good state. - qcom,dynamic-mode-switch-enabled: Boolean used to mention whether panel supports Loading drivers/video/msm/mdss/dsi_status_6g.c +69 −12 Original line number Diff line number Diff line Loading @@ -18,6 +18,64 @@ #include "mdss_dsi.h" #include "mdss_mdp.h" /* * mdss_report_panel_dead() - Sends the PANEL_ALIVE=0 status to HAL layer. * @pstatus_data : dsi status data * * This function is called if the panel fails to respond as expected to * the register read/BTA or if the TE signal is not coming as expected * from the panel. The function sends the PANEL_ALIVE=0 status to HAL * layer. */ static void mdss_report_panel_dead(struct dsi_status_data *pstatus_data) { char *envp[2] = {"PANEL_ALIVE=0", NULL}; struct mdss_panel_data *pdata = dev_get_platdata(&pstatus_data->mfd->pdev->dev); if (!pdata) { pr_err("%s: Panel data not available\n", __func__); return; } pdata->panel_info.panel_dead = true; 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]); return; } /* * mdss_check_te_status() - Check the status of panel for TE based ESD. * @ctrl_pdata : dsi controller data * @pstatus_data : dsi status data * @interval : duration in milliseconds to schedule work queue * * This function is called when the TE signal from the panel doesn't arrive * after 'interval' milliseconds. If the TE IRQ is not ready, the workqueue * gets re-scheduled. Otherwise, report the panel to be dead due to ESD attack. */ static void mdss_check_te_status(struct mdss_dsi_ctrl_pdata *ctrl_pdata, struct dsi_status_data *pstatus_data, uint32_t interval) { /* * During resume, the panel status will be ON but due to race condition * between ESD thread and display UNBLANK (or rather can be put as * asynchronuous nature between these two threads), the ESD thread might * reach this point before the TE IRQ line is enabled or before the * first TE interrupt arrives after the TE IRQ line is enabled. For such * cases, re-schedule the ESD thread. */ if (!atomic_read(&ctrl_pdata->te_irq_ready)) { schedule_delayed_work(&pstatus_data->check_status, msecs_to_jiffies(interval)); pr_debug("%s: TE IRQ line not enabled yet\n", __func__); return; } mdss_report_panel_dead(pstatus_data); } /* * mdss_check_dsi_ctrl_status() - Check MDP5 DSI controller status periodically. * @work : dsi controller status data Loading Loading @@ -53,7 +111,8 @@ void mdss_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval) ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); if (!ctrl_pdata || !ctrl_pdata->check_status) { 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; Loading @@ -70,7 +129,12 @@ void mdss_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval) if (ctl->power_state == MDSS_PANEL_POWER_OFF) { schedule_delayed_work(&pstatus_data->check_status, msecs_to_jiffies(interval)); pr_err("%s: ctl not powered on\n", __func__); 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; } Loading Loading @@ -119,17 +183,10 @@ void mdss_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval) mutex_unlock(&ctrl_pdata->mutex); if ((pstatus_data->mfd->panel_power_state == MDSS_PANEL_POWER_ON)) { if (ret > 0) { 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]); } else mdss_report_panel_dead(pstatus_data); } } drivers/video/msm/mdss/mdss_dsi.c +30 −2 Original line number Diff line number Diff line Loading @@ -706,8 +706,11 @@ static int mdss_dsi_unblank(struct mdss_panel_data *pdata) } if ((pdata->panel_info.type == MIPI_CMD_PANEL) && mipi->vsync_enable && mipi->hw_vsync_mode) mipi->vsync_enable && mipi->hw_vsync_mode) { mdss_dsi_set_tear_on(ctrl_pdata); if (mdss_dsi_is_te_based_esd(ctrl_pdata)) enable_irq(gpio_to_irq(ctrl_pdata->disp_te_gpio)); } error: mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0); Loading Loading @@ -763,8 +766,14 @@ static int mdss_dsi_blank(struct mdss_panel_data *pdata, int power_state) } if ((pdata->panel_info.type == MIPI_CMD_PANEL) && mipi->vsync_enable && mipi->hw_vsync_mode) mipi->vsync_enable && mipi->hw_vsync_mode) { if (mdss_dsi_is_te_based_esd(ctrl_pdata)) { disable_irq(gpio_to_irq( ctrl_pdata->disp_te_gpio)); atomic_dec(&ctrl_pdata->te_irq_ready); } mdss_dsi_set_tear_off(ctrl_pdata); } if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) { if (!pdata->panel_info.dynamic_switch_pending) { Loading Loading @@ -1407,6 +1416,7 @@ static int mdss_dsi_ctrl_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ctrl_pdata); } ctrl_pdata->mdss_util = util; atomic_set(&ctrl_pdata->te_irq_ready, 0); ctrl_name = of_get_property(pdev->dev.of_node, "label", NULL); if (!ctrl_name) Loading Loading @@ -1490,6 +1500,17 @@ static int mdss_dsi_ctrl_probe(struct platform_device *pdev) goto error_pan_node; } if (mdss_dsi_is_te_based_esd(ctrl_pdata)) { rc = devm_request_irq(&pdev->dev, gpio_to_irq(ctrl_pdata->disp_te_gpio), hw_vsync_handler, IRQF_TRIGGER_FALLING, "VSYNC_GPIO", ctrl_pdata); if (rc) { pr_err("TE request_irq failed.\n"); goto error_pan_node; } disable_irq(gpio_to_irq(ctrl_pdata->disp_te_gpio)); } pr_debug("%s: Dsi Ctrl->%d initialized\n", __func__, index); return 0; Loading Loading @@ -1752,6 +1773,13 @@ int dsi_panel_device_register(struct device_node *pan_node, __func__, __LINE__); } ctrl_pdata->disp_te_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node, "qcom,platform-te-gpio", 0); if (!gpio_is_valid(ctrl_pdata->disp_te_gpio)) pr_err("%s:%d, TE gpio not specified\n", __func__, __LINE__); ctrl_pdata->bklt_en_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node, "qcom,platform-bklight-en-gpio", 0); if (!gpio_is_valid(ctrl_pdata->bklt_en_gpio)) Loading drivers/video/msm/mdss/mdss_dsi.h +12 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include <linux/mdss_io_util.h> #include <linux/irqreturn.h> #include <linux/pinctrl/consumer.h> #include <linux/gpio.h> #include "mdss_panel.h" #include "mdss_dsi_cmd.h" Loading Loading @@ -96,6 +97,7 @@ enum dsi_panel_status_mode { ESD_BTA, ESD_REG, ESD_REG_NT35596, ESD_TE, ESD_MAX, }; Loading Loading @@ -315,6 +317,7 @@ struct mdss_dsi_ctrl_pdata { u8 ctrl_state; int panel_mode; int irq_cnt; int disp_te_gpio; int rst_gpio; int disp_en_gpio; int bklt_en_gpio; Loading @@ -329,6 +332,7 @@ struct mdss_dsi_ctrl_pdata { int pwm_enabled; bool panel_bias_vreg; bool dsi_irq_line; atomic_t te_irq_ready; bool cmd_sync_wait_broadcast; bool cmd_sync_wait_trigger; Loading Loading @@ -420,6 +424,7 @@ void mdss_dsi_controller_cfg(int enable, void mdss_dsi_sw_reset(struct mdss_dsi_ctrl_pdata *ctrl_pdata, bool restore); irqreturn_t mdss_dsi_isr(int irq, void *ptr); irqreturn_t hw_vsync_handler(int irq, void *data); void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata); void mdss_dsi_set_tx_power_mode(int mode, struct mdss_panel_data *pdata); Loading Loading @@ -539,6 +544,13 @@ static inline bool mdss_dsi_is_ctrl_clk_slave(struct mdss_dsi_ctrl_pdata *ctrl) (ctrl->ndx == DSI_CTRL_CLK_SLAVE); } static inline bool mdss_dsi_is_te_based_esd(struct mdss_dsi_ctrl_pdata *ctrl) { return (ctrl->status_mode == ESD_TE) && gpio_is_valid(ctrl->disp_te_gpio) && mdss_dsi_is_left_ctrl(ctrl); } static inline struct mdss_dsi_ctrl_pdata *mdss_dsi_get_ctrl_clk_master(void) { return ctrl_list[DSI_CTRL_CLK_MASTER]; Loading drivers/video/msm/mdss/mdss_dsi_panel.c +5 −0 Original line number Diff line number Diff line Loading @@ -1595,6 +1595,11 @@ static int mdss_panel_parse_dt(struct device_node *np, ctrl_pdata->status_cmds_rlen = 8; ctrl_pdata->check_read_status = mdss_dsi_nt35596_read_status; } else if (!strcmp(data, "te_signal_check")) { if (pinfo->mipi.mode == DSI_CMD_MODE) ctrl_pdata->status_mode = ESD_TE; else pr_err("TE-ESD not valid for video mode\n"); } } Loading Loading
Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt +1 −0 Original line number Diff line number Diff line Loading @@ -344,6 +344,7 @@ Optional properties: - qcom,mdss-dsi-panel-status-check-mode:Specifies the panel status check method for ESD recovery. "bta_check" = Uses BTA to check the panel status "reg_read" = Reads panel status register to check the panel status "te_signal_check" = Uses TE signal behaviour to check the panel status - qcom,mdss-dsi-panel-status-value: Specifies the value of the panel status register when the panel is in good state. - qcom,dynamic-mode-switch-enabled: Boolean used to mention whether panel supports Loading
drivers/video/msm/mdss/dsi_status_6g.c +69 −12 Original line number Diff line number Diff line Loading @@ -18,6 +18,64 @@ #include "mdss_dsi.h" #include "mdss_mdp.h" /* * mdss_report_panel_dead() - Sends the PANEL_ALIVE=0 status to HAL layer. * @pstatus_data : dsi status data * * This function is called if the panel fails to respond as expected to * the register read/BTA or if the TE signal is not coming as expected * from the panel. The function sends the PANEL_ALIVE=0 status to HAL * layer. */ static void mdss_report_panel_dead(struct dsi_status_data *pstatus_data) { char *envp[2] = {"PANEL_ALIVE=0", NULL}; struct mdss_panel_data *pdata = dev_get_platdata(&pstatus_data->mfd->pdev->dev); if (!pdata) { pr_err("%s: Panel data not available\n", __func__); return; } pdata->panel_info.panel_dead = true; 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]); return; } /* * mdss_check_te_status() - Check the status of panel for TE based ESD. * @ctrl_pdata : dsi controller data * @pstatus_data : dsi status data * @interval : duration in milliseconds to schedule work queue * * This function is called when the TE signal from the panel doesn't arrive * after 'interval' milliseconds. If the TE IRQ is not ready, the workqueue * gets re-scheduled. Otherwise, report the panel to be dead due to ESD attack. */ static void mdss_check_te_status(struct mdss_dsi_ctrl_pdata *ctrl_pdata, struct dsi_status_data *pstatus_data, uint32_t interval) { /* * During resume, the panel status will be ON but due to race condition * between ESD thread and display UNBLANK (or rather can be put as * asynchronuous nature between these two threads), the ESD thread might * reach this point before the TE IRQ line is enabled or before the * first TE interrupt arrives after the TE IRQ line is enabled. For such * cases, re-schedule the ESD thread. */ if (!atomic_read(&ctrl_pdata->te_irq_ready)) { schedule_delayed_work(&pstatus_data->check_status, msecs_to_jiffies(interval)); pr_debug("%s: TE IRQ line not enabled yet\n", __func__); return; } mdss_report_panel_dead(pstatus_data); } /* * mdss_check_dsi_ctrl_status() - Check MDP5 DSI controller status periodically. * @work : dsi controller status data Loading Loading @@ -53,7 +111,8 @@ void mdss_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval) ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); if (!ctrl_pdata || !ctrl_pdata->check_status) { 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; Loading @@ -70,7 +129,12 @@ void mdss_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval) if (ctl->power_state == MDSS_PANEL_POWER_OFF) { schedule_delayed_work(&pstatus_data->check_status, msecs_to_jiffies(interval)); pr_err("%s: ctl not powered on\n", __func__); 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; } Loading Loading @@ -119,17 +183,10 @@ void mdss_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval) mutex_unlock(&ctrl_pdata->mutex); if ((pstatus_data->mfd->panel_power_state == MDSS_PANEL_POWER_ON)) { if (ret > 0) { 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]); } else mdss_report_panel_dead(pstatus_data); } }
drivers/video/msm/mdss/mdss_dsi.c +30 −2 Original line number Diff line number Diff line Loading @@ -706,8 +706,11 @@ static int mdss_dsi_unblank(struct mdss_panel_data *pdata) } if ((pdata->panel_info.type == MIPI_CMD_PANEL) && mipi->vsync_enable && mipi->hw_vsync_mode) mipi->vsync_enable && mipi->hw_vsync_mode) { mdss_dsi_set_tear_on(ctrl_pdata); if (mdss_dsi_is_te_based_esd(ctrl_pdata)) enable_irq(gpio_to_irq(ctrl_pdata->disp_te_gpio)); } error: mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0); Loading Loading @@ -763,8 +766,14 @@ static int mdss_dsi_blank(struct mdss_panel_data *pdata, int power_state) } if ((pdata->panel_info.type == MIPI_CMD_PANEL) && mipi->vsync_enable && mipi->hw_vsync_mode) mipi->vsync_enable && mipi->hw_vsync_mode) { if (mdss_dsi_is_te_based_esd(ctrl_pdata)) { disable_irq(gpio_to_irq( ctrl_pdata->disp_te_gpio)); atomic_dec(&ctrl_pdata->te_irq_ready); } mdss_dsi_set_tear_off(ctrl_pdata); } if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) { if (!pdata->panel_info.dynamic_switch_pending) { Loading Loading @@ -1407,6 +1416,7 @@ static int mdss_dsi_ctrl_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ctrl_pdata); } ctrl_pdata->mdss_util = util; atomic_set(&ctrl_pdata->te_irq_ready, 0); ctrl_name = of_get_property(pdev->dev.of_node, "label", NULL); if (!ctrl_name) Loading Loading @@ -1490,6 +1500,17 @@ static int mdss_dsi_ctrl_probe(struct platform_device *pdev) goto error_pan_node; } if (mdss_dsi_is_te_based_esd(ctrl_pdata)) { rc = devm_request_irq(&pdev->dev, gpio_to_irq(ctrl_pdata->disp_te_gpio), hw_vsync_handler, IRQF_TRIGGER_FALLING, "VSYNC_GPIO", ctrl_pdata); if (rc) { pr_err("TE request_irq failed.\n"); goto error_pan_node; } disable_irq(gpio_to_irq(ctrl_pdata->disp_te_gpio)); } pr_debug("%s: Dsi Ctrl->%d initialized\n", __func__, index); return 0; Loading Loading @@ -1752,6 +1773,13 @@ int dsi_panel_device_register(struct device_node *pan_node, __func__, __LINE__); } ctrl_pdata->disp_te_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node, "qcom,platform-te-gpio", 0); if (!gpio_is_valid(ctrl_pdata->disp_te_gpio)) pr_err("%s:%d, TE gpio not specified\n", __func__, __LINE__); ctrl_pdata->bklt_en_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node, "qcom,platform-bklight-en-gpio", 0); if (!gpio_is_valid(ctrl_pdata->bklt_en_gpio)) Loading
drivers/video/msm/mdss/mdss_dsi.h +12 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include <linux/mdss_io_util.h> #include <linux/irqreturn.h> #include <linux/pinctrl/consumer.h> #include <linux/gpio.h> #include "mdss_panel.h" #include "mdss_dsi_cmd.h" Loading Loading @@ -96,6 +97,7 @@ enum dsi_panel_status_mode { ESD_BTA, ESD_REG, ESD_REG_NT35596, ESD_TE, ESD_MAX, }; Loading Loading @@ -315,6 +317,7 @@ struct mdss_dsi_ctrl_pdata { u8 ctrl_state; int panel_mode; int irq_cnt; int disp_te_gpio; int rst_gpio; int disp_en_gpio; int bklt_en_gpio; Loading @@ -329,6 +332,7 @@ struct mdss_dsi_ctrl_pdata { int pwm_enabled; bool panel_bias_vreg; bool dsi_irq_line; atomic_t te_irq_ready; bool cmd_sync_wait_broadcast; bool cmd_sync_wait_trigger; Loading Loading @@ -420,6 +424,7 @@ void mdss_dsi_controller_cfg(int enable, void mdss_dsi_sw_reset(struct mdss_dsi_ctrl_pdata *ctrl_pdata, bool restore); irqreturn_t mdss_dsi_isr(int irq, void *ptr); irqreturn_t hw_vsync_handler(int irq, void *data); void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata); void mdss_dsi_set_tx_power_mode(int mode, struct mdss_panel_data *pdata); Loading Loading @@ -539,6 +544,13 @@ static inline bool mdss_dsi_is_ctrl_clk_slave(struct mdss_dsi_ctrl_pdata *ctrl) (ctrl->ndx == DSI_CTRL_CLK_SLAVE); } static inline bool mdss_dsi_is_te_based_esd(struct mdss_dsi_ctrl_pdata *ctrl) { return (ctrl->status_mode == ESD_TE) && gpio_is_valid(ctrl->disp_te_gpio) && mdss_dsi_is_left_ctrl(ctrl); } static inline struct mdss_dsi_ctrl_pdata *mdss_dsi_get_ctrl_clk_master(void) { return ctrl_list[DSI_CTRL_CLK_MASTER]; Loading
drivers/video/msm/mdss/mdss_dsi_panel.c +5 −0 Original line number Diff line number Diff line Loading @@ -1595,6 +1595,11 @@ static int mdss_panel_parse_dt(struct device_node *np, ctrl_pdata->status_cmds_rlen = 8; ctrl_pdata->check_read_status = mdss_dsi_nt35596_read_status; } else if (!strcmp(data, "te_signal_check")) { if (pinfo->mipi.mode == DSI_CMD_MODE) ctrl_pdata->status_mode = ESD_TE; else pr_err("TE-ESD not valid for video mode\n"); } } Loading