blob: 87720cf87d995b3b74e86857543596545367350a [file] [log] [blame]
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301/* Copyright (c) 2013-2015, 2017-2018, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12#include <linux/workqueue.h>
13#include <linux/delay.h>
14#include <linux/kobject.h>
15#include <linux/string.h>
16#include <linux/sysfs.h>
17#include <linux/interrupt.h>
18
19#include "mdss_dsi.h"
20#include "mdp3_ctrl.h"
Arun kumardb962812018-05-30 16:31:52 +053021#include "mdss_spi_panel.h"
Sachin Bhayareeeb88892018-01-02 16:36:01 +053022
23/*
24 * mdp3_check_te_status() - Check the status of panel for TE based ESD.
25 * @ctrl_pdata : dsi controller data
26 * @pstatus_data : dsi status data
27 * @interval : duration in milliseconds for panel TE wait
28 *
29 * This function waits for TE signal from the panel for a maximum
30 * duration of 3 vsyncs. If timeout occurs, report the panel to be
31 * dead due to ESD attack.
32 * NOTE: The TE IRQ handling is linked to the ESD thread scheduling,
33 * i.e. rate of TE IRQs firing is bound by the ESD interval.
34 */
35static int mdp3_check_te_status(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
36 struct dsi_status_data *pstatus_data, uint32_t interval)
37{
38 int ret;
39
40 pr_debug("%s: Checking panel TE status\n", __func__);
41
42 atomic_set(&ctrl_pdata->te_irq_ready, 0);
43 reinit_completion(&ctrl_pdata->te_irq_comp);
44 enable_irq(gpio_to_irq(ctrl_pdata->disp_te_gpio));
45
46 ret = wait_for_completion_timeout(&ctrl_pdata->te_irq_comp,
47 msecs_to_jiffies(interval));
48
49 disable_irq(gpio_to_irq(ctrl_pdata->disp_te_gpio));
50 pr_debug("%s: Panel TE check done with ret = %d\n", __func__, ret);
51
52 return ret;
53}
54
55/*
56 * mdp3_check_dsi_ctrl_status() - Check MDP3 DSI controller status periodically.
57 * @work : dsi controller status data
58 * @interval : duration in milliseconds to schedule work queue
59 *
60 * This function calls check_status API on DSI controller to send the BTA
61 * command. If DSI controller fails to acknowledge the BTA command, it sends
62 * the PANEL_ALIVE=0 status to HAL layer.
63 */
64void mdp3_check_dsi_ctrl_status(struct work_struct *work,
65 uint32_t interval)
66{
67 struct dsi_status_data *pdsi_status = NULL;
68 struct mdss_panel_data *pdata = NULL;
69 struct mipi_panel_info *mipi = NULL;
70 struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
71 struct mdp3_session_data *mdp3_session = NULL;
72 int ret = 0;
73
74 pdsi_status = container_of(to_delayed_work(work),
75 struct dsi_status_data, check_status);
76
77 if (!pdsi_status || !(pdsi_status->mfd)) {
78 pr_err("%s: mfd not available\n", __func__);
79 return;
80 }
81
82 pdata = dev_get_platdata(&pdsi_status->mfd->pdev->dev);
83 if (!pdata) {
84 pr_err("%s: Panel data not available\n", __func__);
85 return;
86 }
87
88 mipi = &pdata->panel_info.mipi;
89 ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
90 panel_data);
91
92 if (!ctrl_pdata || (!ctrl_pdata->check_status &&
93 (ctrl_pdata->status_mode != ESD_TE))) {
94 pr_err("%s: DSI ctrl or status_check callback not available\n",
95 __func__);
96 return;
97 }
98
99 if (!pdata->panel_info.esd_rdy) {
100 pr_err("%s: unblank not complete, reschedule check status\n",
101 __func__);
102 schedule_delayed_work(&pdsi_status->check_status,
103 msecs_to_jiffies(interval));
104 return;
105 }
106
107 mdp3_session = pdsi_status->mfd->mdp.private1;
108 if (!mdp3_session) {
109 pr_err("%s: Display is off\n", __func__);
110 return;
111 }
112
113 if (mdp3_session->in_splash_screen) {
114 schedule_delayed_work(&pdsi_status->check_status,
115 msecs_to_jiffies(interval));
116 pr_debug("%s: cont splash is on\n", __func__);
117 return;
118 }
119
120 if (mipi->mode == DSI_CMD_MODE &&
121 mipi->hw_vsync_mode &&
122 mdss_dsi_is_te_based_esd(ctrl_pdata)) {
123 uint32_t fps = mdss_panel_get_framerate(&pdata->panel_info,
124 FPS_RESOLUTION_HZ);
125 uint32_t timeout = ((1000 / fps) + 1) *
126 MDSS_STATUS_TE_WAIT_MAX;
127
128 if (mdp3_check_te_status(ctrl_pdata, pdsi_status, timeout) > 0)
129 goto sim;
130 goto status_dead;
131 }
132
133 mutex_lock(&mdp3_session->lock);
134 if (!mdp3_session->status) {
135 pr_debug("%s: display off already\n", __func__);
136 mutex_unlock(&mdp3_session->lock);
137 return;
138 }
139
140 if (mdp3_session->wait_for_dma_done)
141 ret = mdp3_session->wait_for_dma_done(mdp3_session);
142 mutex_unlock(&mdp3_session->lock);
143
144 if (!ret)
145 ret = ctrl_pdata->check_status(ctrl_pdata);
146 else
147 pr_err("%s: wait_for_dma_done error\n", __func__);
148
149 if (mdss_fb_is_power_on_interactive(pdsi_status->mfd)) {
150 if (ret > 0)
151 schedule_delayed_work(&pdsi_status->check_status,
152 msecs_to_jiffies(interval));
153 else
154 goto status_dead;
155 }
156sim:
157 if (pdata->panel_info.panel_force_dead) {
158 pr_debug("force_dead=%d\n", pdata->panel_info.panel_force_dead);
159 pdata->panel_info.panel_force_dead--;
160 if (!pdata->panel_info.panel_force_dead)
161 goto status_dead;
162 }
163 return;
164
165status_dead:
166 mdss_fb_report_panel_dead(pdsi_status->mfd);
167}
168
Arun kumardb962812018-05-30 16:31:52 +0530169#if defined(CONFIG_FB_MSM_MDSS_SPI_PANEL)
170void mdp3_check_spi_panel_status(struct work_struct *work, uint32_t interval)
171{
172 struct dsi_status_data *pdsi_status = NULL;
173 struct mdss_panel_data *pdata = NULL;
174 struct spi_panel_data *ctrl_pdata = NULL;
175 struct mdp3_session_data *mdp3_session = NULL;
176 int ret = 0;
177
178 pdsi_status = container_of(to_delayed_work(work),
179 struct dsi_status_data, check_status);
180
181 if (!pdsi_status || !(pdsi_status->mfd)) {
182 pr_err("%s: mfd not available\n", __func__);
183 return;
184 }
185
186 pdata = dev_get_platdata(&pdsi_status->mfd->pdev->dev);
187 if (!pdata) {
188 pr_err("%s: panel data not available\n", __func__);
189 return;
190 }
191
192 ctrl_pdata = container_of(pdata, struct spi_panel_data, panel_data);
193 if (!ctrl_pdata || !ctrl_pdata->check_status) {
194 pr_err("%s: Dsi ctrl or status_check callback not available\n",
195 __func__);
196 return;
197 }
198
199 mdp3_session = pdsi_status->mfd->mdp.private1;
200 if (!mdp3_session) {
201 pr_err("%s: Display is off\n", __func__);
202 return;
203 }
204
205 if (mdp3_session->in_splash_screen) {
206 schedule_delayed_work(&pdsi_status->check_status,
207 msecs_to_jiffies(interval));
208 pr_debug("%s: cont splash is on\n", __func__);
209 return;
210 }
211
212 mutex_lock(&mdp3_session->lock);
213 if (!mdp3_session->status) {
214 pr_debug("%s: display off already\n", __func__);
215 mutex_unlock(&mdp3_session->lock);
216 return;
217 }
218
219 if (!ret)
220 ret = ctrl_pdata->check_status(ctrl_pdata);
221 else
222 pr_err("%s:wait_for_dma_done error\n", __func__);
223 mutex_unlock(&mdp3_session->lock);
224
225 if (mdss_fb_is_power_on_interactive(pdsi_status->mfd)) {
226 if (ret > 0) {
227 schedule_delayed_work(&pdsi_status->check_status,
228 msecs_to_jiffies(interval));
229 } else {
230 char *envp[2] = {"PANEL_ALIVE=0", NULL};
231
232 pdata->panel_info.panel_dead = true;
233 ret = kobject_uevent_env(
234 &pdsi_status->mfd->fbi->dev->kobj, KOBJ_CHANGE, envp);
235 pr_err("%s:panel has gone bad, sending uevent - %s\n",
236 __func__, envp[0]);
237 }
238 }
239}
240#else
241void mdp3_check_spi_panel_status(struct work_struct *work, uint32_t interval)
242{
243}
244#endif