blob: 053ee20e2f4d0d3d250166d5e2ceff75ad8ae77b [file] [log] [blame]
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001/*
Ajay Singh Parmar87af50b2017-12-22 22:22:55 -08002 * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
Ajay Singh Parmar77668872017-03-28 21:36:15 -07003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 */
14
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -070015#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
Ajay Singh Parmar77668872017-03-28 21:36:15 -070016
17#include <linux/module.h>
18#include <linux/slab.h>
19#include <linux/uaccess.h>
20#include <linux/debugfs.h>
21#include <linux/component.h>
22#include <linux/of_irq.h>
Tatenda Chipeperekwab8cbd132017-07-07 17:43:29 -070023#include <linux/hdcp_qseecom.h>
Ajay Singh Parmar77668872017-03-28 21:36:15 -070024
Ajay Singh Parmar87af50b2017-12-22 22:22:55 -080025#include "sde_connector.h"
26
Padmanabhan Komanduru4152f392017-05-11 17:53:55 -070027#include "msm_drv.h"
Ajay Singh Parmar77668872017-03-28 21:36:15 -070028#include "dp_usbpd.h"
29#include "dp_parser.h"
30#include "dp_power.h"
31#include "dp_catalog.h"
32#include "dp_aux.h"
33#include "dp_link.h"
34#include "dp_panel.h"
35#include "dp_ctrl.h"
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -070036#include "dp_audio.h"
Ajay Singh Parmar77668872017-03-28 21:36:15 -070037#include "dp_display.h"
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -070038#include "sde_hdcp.h"
Samantha Tran2d1ed732017-07-31 17:30:14 -070039#include "dp_debug.h"
Ajay Singh Parmar77668872017-03-28 21:36:15 -070040
41static struct dp_display *g_dp_display;
Padmanabhan Komanduru71aec2d2017-08-30 20:07:59 +053042#define HPD_STRING_SIZE 30
Ajay Singh Parmar77668872017-03-28 21:36:15 -070043
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -070044struct dp_hdcp {
45 void *data;
46 struct sde_hdcp_ops *ops;
47
48 void *hdcp1;
49 void *hdcp2;
50
51 int enc_lvl;
52
53 bool auth_state;
54 bool hdcp1_present;
55 bool hdcp2_present;
56 bool feature_enabled;
57};
58
Ajay Singh Parmar77668872017-03-28 21:36:15 -070059struct dp_display_private {
60 char *name;
61 int irq;
62
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -070063 /* state variables */
64 bool core_initialized;
65 bool power_on;
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -070066 bool audio_supported;
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -070067
Ajay Singh Parmar77668872017-03-28 21:36:15 -070068 struct platform_device *pdev;
69 struct dentry *root;
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -070070 struct completion notification_comp;
Ajay Singh Parmar77668872017-03-28 21:36:15 -070071
72 struct dp_usbpd *usbpd;
73 struct dp_parser *parser;
74 struct dp_power *power;
75 struct dp_catalog *catalog;
76 struct dp_aux *aux;
77 struct dp_link *link;
78 struct dp_panel *panel;
79 struct dp_ctrl *ctrl;
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -070080 struct dp_audio *audio;
Samantha Tran2d1ed732017-07-31 17:30:14 -070081 struct dp_debug *debug;
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -070082
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -070083 struct dp_hdcp hdcp;
Ajay Singh Parmar77668872017-03-28 21:36:15 -070084
85 struct dp_usbpd_cb usbpd_cb;
86 struct dp_display_mode mode;
87 struct dp_display dp_display;
Ajay Singh Parmar315e5852017-11-23 21:47:32 -080088 struct msm_drm_private *priv;
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -070089
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -070090 struct workqueue_struct *wq;
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -070091 struct delayed_work hdcp_cb_work;
Ajay Singh Parmar84337302017-12-12 14:26:41 -080092 struct delayed_work connect_work;
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -070093 struct work_struct attention_work;
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -070094 struct mutex hdcp_mutex;
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -070095 struct mutex session_lock;
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -070096 int hdcp_status;
Ajay Singh Parmar84337302017-12-12 14:26:41 -080097 unsigned long audio_status;
Ajay Singh Parmar77668872017-03-28 21:36:15 -070098};
99
100static const struct of_device_id dp_dt_match[] = {
101 {.compatible = "qcom,dp-display"},
102 {}
103};
104
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800105static bool dp_display_framework_ready(struct dp_display_private *dp)
106{
107 return dp->dp_display.post_open ? false : true;
108}
109
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700110static inline bool dp_display_is_hdcp_enabled(struct dp_display_private *dp)
111{
112 return dp->hdcp.feature_enabled &&
113 (dp->hdcp.hdcp1_present || dp->hdcp.hdcp2_present) &&
114 dp->hdcp.ops;
115}
116
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -0700117static irqreturn_t dp_display_irq(int irq, void *dev_id)
118{
119 struct dp_display_private *dp = dev_id;
120
121 if (!dp) {
122 pr_err("invalid data\n");
123 return IRQ_NONE;
124 }
125
126 /* DP controller isr */
127 dp->ctrl->isr(dp->ctrl);
128
129 /* DP aux isr */
130 dp->aux->isr(dp->aux);
131
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700132 /* HDCP isr */
133 if (dp_display_is_hdcp_enabled(dp) && dp->hdcp.ops->isr) {
134 if (dp->hdcp.ops->isr(dp->hdcp.data))
135 pr_err("dp_hdcp_isr failed\n");
136 }
137
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -0700138 return IRQ_HANDLED;
139}
140
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700141static void dp_display_hdcp_cb_work(struct work_struct *work)
142{
143 struct dp_display_private *dp;
144 struct delayed_work *dw = to_delayed_work(work);
145 struct sde_hdcp_ops *ops;
146 int rc = 0;
147 u32 hdcp_auth_state;
148
149 dp = container_of(dw, struct dp_display_private, hdcp_cb_work);
150
151 rc = dp->catalog->ctrl.read_hdcp_status(&dp->catalog->ctrl);
152 if (rc >= 0) {
153 hdcp_auth_state = (rc >> 20) & 0x3;
154 pr_debug("hdcp auth state %d\n", hdcp_auth_state);
155 }
156
157 ops = dp->hdcp.ops;
158
159 switch (dp->hdcp_status) {
160 case HDCP_STATE_AUTHENTICATING:
161 pr_debug("start authenticaton\n");
162
163 if (dp->hdcp.ops && dp->hdcp.ops->authenticate)
164 rc = dp->hdcp.ops->authenticate(dp->hdcp.data);
165
166 break;
167 case HDCP_STATE_AUTHENTICATED:
168 pr_debug("hdcp authenticated\n");
169 dp->hdcp.auth_state = true;
170 break;
171 case HDCP_STATE_AUTH_FAIL:
172 dp->hdcp.auth_state = false;
173
174 if (dp->power_on) {
175 pr_debug("Reauthenticating\n");
176 if (ops && ops->reauthenticate) {
177 rc = ops->reauthenticate(dp->hdcp.data);
178 if (rc)
179 pr_err("reauth failed rc=%d\n", rc);
180 }
181 } else {
182 pr_debug("not reauthenticating, cable disconnected\n");
183 }
184
185 break;
186 default:
187 break;
188 }
189}
190
191static void dp_display_notify_hdcp_status_cb(void *ptr,
192 enum sde_hdcp_states status)
193{
194 struct dp_display_private *dp = ptr;
195
196 if (!dp) {
197 pr_err("invalid input\n");
198 return;
199 }
200
201 dp->hdcp_status = status;
202
203 if (dp->dp_display.is_connected)
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700204 queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ/4);
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700205}
206
207static void dp_display_destroy_hdcp_workqueue(struct dp_display_private *dp)
208{
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700209 if (dp->wq)
210 destroy_workqueue(dp->wq);
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700211}
212
213static void dp_display_update_hdcp_info(struct dp_display_private *dp)
214{
215 void *fd = NULL;
216 struct sde_hdcp_ops *ops = NULL;
217
218 if (!dp) {
219 pr_err("invalid input\n");
220 return;
221 }
222
223 if (!dp->hdcp.feature_enabled) {
224 pr_debug("feature not enabled\n");
225 return;
226 }
227
228 fd = dp->hdcp.hdcp2;
229 if (fd)
230 ops = sde_dp_hdcp2p2_start(fd);
231
232 if (ops && ops->feature_supported)
233 dp->hdcp.hdcp2_present = ops->feature_supported(fd);
234 else
235 dp->hdcp.hdcp2_present = false;
236
Tatenda Chipeperekwab8cbd132017-07-07 17:43:29 -0700237 pr_debug("hdcp2p2: %s\n",
238 dp->hdcp.hdcp2_present ? "supported" : "not supported");
239
240 if (!dp->hdcp.hdcp2_present) {
241 dp->hdcp.hdcp1_present = hdcp1_check_if_supported_load_app();
242
243 if (dp->hdcp.hdcp1_present) {
244 fd = dp->hdcp.hdcp1;
245 ops = sde_hdcp_1x_start(fd);
246 }
247 }
248
249 pr_debug("hdcp1x: %s\n",
250 dp->hdcp.hdcp1_present ? "supported" : "not supported");
251
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700252 if (dp->hdcp.hdcp2_present || dp->hdcp.hdcp1_present) {
253 dp->hdcp.data = fd;
254 dp->hdcp.ops = ops;
255 } else {
256 dp->hdcp.data = NULL;
257 dp->hdcp.ops = NULL;
258 }
259}
260
261static void dp_display_deinitialize_hdcp(struct dp_display_private *dp)
262{
263 if (!dp) {
264 pr_err("invalid input\n");
265 return;
266 }
267
268 sde_dp_hdcp2p2_deinit(dp->hdcp.data);
269 dp_display_destroy_hdcp_workqueue(dp);
270 if (&dp->hdcp_mutex)
271 mutex_destroy(&dp->hdcp_mutex);
272}
273
274static int dp_display_initialize_hdcp(struct dp_display_private *dp)
275{
276 struct sde_hdcp_init_data hdcp_init_data;
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700277 int rc = 0;
278
279 if (!dp) {
280 pr_err("invalid input\n");
281 return -EINVAL;
282 }
283
284 mutex_init(&dp->hdcp_mutex);
285
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700286 hdcp_init_data.client_id = HDCP_CLIENT_DP;
287 hdcp_init_data.drm_aux = dp->aux->drm_aux;
288 hdcp_init_data.cb_data = (void *)dp;
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700289 hdcp_init_data.workq = dp->wq;
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700290 hdcp_init_data.mutex = &dp->hdcp_mutex;
291 hdcp_init_data.sec_access = true;
292 hdcp_init_data.notify_status = dp_display_notify_hdcp_status_cb;
293 hdcp_init_data.core_io = &dp->parser->io.ctrl_io;
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700294 hdcp_init_data.dp_ahb = &dp->parser->io.dp_ahb;
295 hdcp_init_data.dp_aux = &dp->parser->io.dp_aux;
296 hdcp_init_data.dp_link = &dp->parser->io.dp_link;
297 hdcp_init_data.dp_p0 = &dp->parser->io.dp_p0;
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700298 hdcp_init_data.qfprom_io = &dp->parser->io.qfprom_io;
299 hdcp_init_data.hdcp_io = &dp->parser->io.hdcp_io;
300 hdcp_init_data.revision = &dp->panel->link_info.revision;
301
Tatenda Chipeperekwab8cbd132017-07-07 17:43:29 -0700302 dp->hdcp.hdcp1 = sde_hdcp_1x_init(&hdcp_init_data);
303 if (IS_ERR_OR_NULL(dp->hdcp.hdcp1)) {
304 pr_err("Error initializing HDCP 1.x\n");
305 rc = -EINVAL;
306 goto error;
307 }
308
309 pr_debug("HDCP 1.3 initialized\n");
310
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700311 dp->hdcp.hdcp2 = sde_dp_hdcp2p2_init(&hdcp_init_data);
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800312 if (IS_ERR_OR_NULL(dp->hdcp.hdcp2)) {
313 pr_err("Error initializing HDCP 2.x\n");
314 rc = -EINVAL;
315 goto error;
316 }
317
318 pr_debug("HDCP 2.2 initialized\n");
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700319
320 dp->hdcp.feature_enabled = true;
321
322 return 0;
323error:
324 dp_display_deinitialize_hdcp(dp);
325 return rc;
326}
327
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700328static int dp_display_bind(struct device *dev, struct device *master,
329 void *data)
330{
331 int rc = 0;
332 struct dp_display_private *dp;
333 struct drm_device *drm;
334 struct platform_device *pdev = to_platform_device(dev);
335
336 if (!dev || !pdev || !master) {
337 pr_err("invalid param(s), dev %pK, pdev %pK, master %pK\n",
338 dev, pdev, master);
339 rc = -EINVAL;
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700340 goto end;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700341 }
342
343 drm = dev_get_drvdata(master);
344 dp = platform_get_drvdata(pdev);
345 if (!drm || !dp) {
346 pr_err("invalid param(s), drm %pK, dp %pK\n",
347 drm, dp);
348 rc = -EINVAL;
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700349 goto end;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700350 }
351
352 dp->dp_display.drm_dev = drm;
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800353 dp->priv = drm->dev_private;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700354end:
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700355 return rc;
356}
357
358static void dp_display_unbind(struct device *dev, struct device *master,
359 void *data)
360{
361 struct dp_display_private *dp;
362 struct platform_device *pdev = to_platform_device(dev);
363
364 if (!dev || !pdev) {
365 pr_err("invalid param(s)\n");
366 return;
367 }
368
369 dp = platform_get_drvdata(pdev);
370 if (!dp) {
371 pr_err("Invalid params\n");
372 return;
373 }
374
Padmanabhan Komanduru4152f392017-05-11 17:53:55 -0700375 (void)dp->power->power_client_deinit(dp->power);
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700376 (void)dp->aux->drm_aux_deregister(dp->aux);
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700377 dp_display_deinitialize_hdcp(dp);
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700378}
379
380static const struct component_ops dp_display_comp_ops = {
381 .bind = dp_display_bind,
382 .unbind = dp_display_unbind,
383};
384
Padmanabhan Komanduru58717282017-08-28 17:01:49 +0530385static bool dp_display_is_ds_bridge(struct dp_panel *panel)
386{
387 return (panel->dpcd[DP_DOWNSTREAMPORT_PRESENT] &
388 DP_DWN_STRM_PORT_PRESENT);
389}
390
391static bool dp_display_is_sink_count_zero(struct dp_display_private *dp)
392{
393 return dp_display_is_ds_bridge(dp->panel) &&
394 (dp->link->sink_count.count == 0);
395}
396
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800397static void dp_display_send_hpd_event(struct dp_display_private *dp)
Padmanabhan Komanduru71aec2d2017-08-30 20:07:59 +0530398{
399 struct drm_device *dev = NULL;
Padmanabhan Komanduru71aec2d2017-08-30 20:07:59 +0530400 struct drm_connector *connector;
401 char name[HPD_STRING_SIZE], status[HPD_STRING_SIZE],
402 bpp[HPD_STRING_SIZE], pattern[HPD_STRING_SIZE];
403 char *envp[5];
404
Padmanabhan Komanduru71aec2d2017-08-30 20:07:59 +0530405 connector = dp->dp_display.connector;
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800406
407 if (!connector) {
408 pr_err("connector not set\n");
409 return;
410 }
Padmanabhan Komanduru71aec2d2017-08-30 20:07:59 +0530411
412 connector->status = connector->funcs->detect(connector, false);
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800413
414 dev = dp->dp_display.connector->dev;
415
Padmanabhan Komanduru71aec2d2017-08-30 20:07:59 +0530416 snprintf(name, HPD_STRING_SIZE, "name=%s", connector->name);
417 snprintf(status, HPD_STRING_SIZE, "status=%s",
418 drm_get_connector_status_name(connector->status));
419 snprintf(bpp, HPD_STRING_SIZE, "bpp=%d",
420 dp_link_bit_depth_to_bpp(
421 dp->link->test_video.test_bit_depth));
422 snprintf(pattern, HPD_STRING_SIZE, "pattern=%d",
423 dp->link->test_video.test_video_pattern);
424
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800425 pr_debug("[%s]:[%s] [%s] [%s]\n", name, status, bpp, pattern);
Padmanabhan Komanduru71aec2d2017-08-30 20:07:59 +0530426 envp[0] = name;
427 envp[1] = status;
428 envp[2] = bpp;
429 envp[3] = pattern;
430 envp[4] = NULL;
431 kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE,
432 envp);
433}
434
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800435static void dp_display_post_open(struct dp_display *dp_display)
436{
437 struct drm_connector *connector;
438 struct dp_display_private *dp;
439
440 if (!dp_display) {
441 pr_err("invalid input\n");
442 return;
443 }
444
445 dp = container_of(dp_display, struct dp_display_private, dp_display);
446 if (IS_ERR_OR_NULL(dp)) {
447 pr_err("invalid params\n");
448 return;
449 }
450
451 connector = dp->dp_display.connector;
452
453 if (!connector) {
454 pr_err("connector not set\n");
455 return;
456 }
457
458 /* if cable is already connected, send notification */
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800459 if (dp->usbpd->hpd_high)
460 queue_delayed_work(dp->wq, &dp->connect_work, HZ * 10);
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800461 else
462 dp_display->post_open = NULL;
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800463}
464
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530465static int dp_display_send_hpd_notification(struct dp_display_private *dp,
466 bool hpd)
467{
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800468 u32 timeout_sec;
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800469 int ret = 0;
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800470
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530471 dp->dp_display.is_connected = hpd;
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800472
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800473 if (dp_display_framework_ready(dp))
474 timeout_sec = 5;
475 else
476 timeout_sec = 10;
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800477
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800478 dp->aux->state |= DP_STATE_NOTIFICATION_SENT;
479
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530480 reinit_completion(&dp->notification_comp);
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800481 dp_display_send_hpd_event(dp);
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530482
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800483 if (!wait_for_completion_timeout(&dp->notification_comp,
484 HZ * timeout_sec)) {
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -0700485 pr_warn("%s timeout\n", hpd ? "connect" : "disconnect");
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800486 ret = -EINVAL;
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530487 }
488
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800489 dp->aux->state &= ~DP_STATE_NOTIFICATION_SENT;
490
491 return ret;
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530492}
493
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700494static int dp_display_process_hpd_high(struct dp_display_private *dp)
495{
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700496 int rc = 0;
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -0700497 struct edid *edid;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700498
Tatenda Chipeperekwa344498e2017-09-06 12:34:36 -0700499 dp->aux->init(dp->aux, dp->parser->aux_cfg);
500
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700501 if (dp->debug->psm_enabled) {
502 dp->link->psm_config(dp->link, &dp->panel->link_info, false);
503 dp->debug->psm_enabled = false;
504 }
Padmanabhan Komandurub6f7c6f2017-09-05 18:50:30 +0530505
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800506 if (!dp->dp_display.connector)
507 return 0;
508
Padmanabhan Komanduruda8b3d02017-12-22 15:45:12 +0530509 rc = dp->panel->read_sink_caps(dp->panel,
510 dp->dp_display.connector, dp->usbpd->multi_func);
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530511 if (rc) {
Ajay Singh Parmar6da24b02017-12-08 14:30:36 -0800512 /*
513 * ETIMEDOUT --> cable may have been removed
514 * ENOTCONN --> no downstream device connected
515 */
516 if (rc == -ETIMEDOUT || rc == -ENOTCONN)
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530517 goto end;
Ajay Singh Parmar6da24b02017-12-08 14:30:36 -0800518 else
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530519 goto notify;
Padmanabhan Komanduru58717282017-08-28 17:01:49 +0530520 }
521
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -0700522 edid = dp->panel->edid_ctrl->edid;
523
524 dp->audio_supported = drm_detect_monitor_audio(edid);
525
Ajay Singh Parmar6da24b02017-12-08 14:30:36 -0800526 dp->link->process_request(dp->link);
Padmanabhan Komanduru504e2892017-09-19 20:38:31 +0530527 dp->panel->handle_sink_request(dp->panel);
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530528
Tatenda Chipeperekwa8a44bd92017-10-05 16:32:06 -0700529 dp->dp_display.max_pclk_khz = dp->parser->max_pclk_khz;
Padmanabhan Komandurub6f7c6f2017-09-05 18:50:30 +0530530notify:
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530531 dp_display_send_hpd_notification(dp, true);
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700532
Padmanabhan Komanduru58717282017-08-28 17:01:49 +0530533end:
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700534 return rc;
535}
536
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700537static void dp_display_host_init(struct dp_display_private *dp)
538{
539 bool flip = false;
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800540 bool reset;
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700541
542 if (dp->core_initialized) {
543 pr_debug("DP core already initialized\n");
544 return;
545 }
546
547 if (dp->usbpd->orientation == ORIENTATION_CC2)
548 flip = true;
549
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800550 reset = dp->debug->sim_mode ? false : !dp->usbpd->multi_func;
551
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700552 dp->power->init(dp->power, flip);
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800553 dp->ctrl->init(dp->ctrl, flip, reset);
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700554 enable_irq(dp->irq);
555 dp->core_initialized = true;
556}
557
558static void dp_display_host_deinit(struct dp_display_private *dp)
559{
560 if (!dp->core_initialized) {
561 pr_debug("DP core already off\n");
562 return;
563 }
564
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700565 dp->ctrl->deinit(dp->ctrl);
566 dp->power->deinit(dp->power);
567 disable_irq(dp->irq);
568 dp->core_initialized = false;
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800569 dp->aux->state = 0;
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700570}
571
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700572static int dp_display_process_hpd_low(struct dp_display_private *dp)
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700573{
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700574 int rc = 0;
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700575
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700576 if (!dp->dp_display.is_connected) {
577 pr_debug("HPD already off\n");
578 return 0;
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700579 }
580
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700581 if (dp_display_is_hdcp_enabled(dp) && dp->hdcp.ops->off)
582 dp->hdcp.ops->off(dp->hdcp.data);
583
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -0700584 if (dp->audio_supported)
585 dp->audio->off(dp->audio);
586
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800587 dp->audio_status = -ENODEV;
588
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700589 rc = dp_display_send_hpd_notification(dp, false);
Tatenda Chipeperekwa344498e2017-09-06 12:34:36 -0700590
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700591 dp->panel->video_test = false;
592
593 return rc;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700594}
595
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700596static int dp_display_usbpd_configure_cb(struct device *dev)
597{
598 int rc = 0;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700599 struct dp_display_private *dp;
600
601 if (!dev) {
602 pr_err("invalid dev\n");
603 rc = -EINVAL;
604 goto end;
605 }
606
607 dp = dev_get_drvdata(dev);
608 if (!dp) {
609 pr_err("no driver data found\n");
610 rc = -ENODEV;
611 goto end;
612 }
613
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700614 dp_display_host_init(dp);
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700615
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800616 /* check for hpd high and framework ready */
617 if (dp->usbpd->hpd_high && dp_display_framework_ready(dp))
618 queue_delayed_work(dp->wq, &dp->connect_work, 0);
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700619end:
620 return rc;
621}
622
Ajay Singh Parmarbf9531c2017-08-11 19:02:02 -0700623static void dp_display_clean(struct dp_display_private *dp)
624{
625 if (dp_display_is_hdcp_enabled(dp)) {
626 dp->hdcp_status = HDCP_STATE_INACTIVE;
627
628 cancel_delayed_work_sync(&dp->hdcp_cb_work);
629 if (dp->hdcp.ops->off)
630 dp->hdcp.ops->off(dp->hdcp.data);
631 }
632
633 dp->ctrl->push_idle(dp->ctrl);
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530634 dp->ctrl->off(dp->ctrl);
Ajay Singh Parmar420e7e12018-01-11 21:27:16 -0800635 dp->panel->deinit(dp->panel);
636 dp->aux->deinit(dp->aux);
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -0700637 dp->power_on = false;
Ajay Singh Parmarbf9531c2017-08-11 19:02:02 -0700638}
639
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700640static int dp_display_handle_disconnect(struct dp_display_private *dp)
641{
642 int rc;
643
644 rc = dp_display_process_hpd_low(dp);
645
646 mutex_lock(&dp->session_lock);
647 if (rc && dp->power_on)
648 dp_display_clean(dp);
649
650 if (!dp->usbpd->alt_mode_cfg_done)
651 dp_display_host_deinit(dp);
652
653 mutex_unlock(&dp->session_lock);
654
655 return rc;
656}
657
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700658static int dp_display_usbpd_disconnect_cb(struct device *dev)
659{
660 int rc = 0;
661 struct dp_display_private *dp;
662
663 if (!dev) {
664 pr_err("invalid dev\n");
665 rc = -EINVAL;
666 goto end;
667 }
668
669 dp = dev_get_drvdata(dev);
670 if (!dp) {
671 pr_err("no driver data found\n");
672 rc = -ENODEV;
673 goto end;
674 }
675
Padmanabhan Komanduruac827ee2018-01-18 18:51:25 +0530676 /*
677 * In case cable/dongle is disconnected during adb shell stop,
678 * reset psm_enabled flag to false since it is no more needed
679 */
680 if (dp->dp_display.post_open)
681 dp->debug->psm_enabled = false;
682
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700683 if (dp->debug->psm_enabled)
684 dp->link->psm_config(dp->link, &dp->panel->link_info, true);
685
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700686 /* cancel any pending request */
687 dp->ctrl->abort(dp->ctrl);
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530688 dp->aux->abort(dp->aux);
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700689
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700690 /* wait for idle state */
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800691 cancel_delayed_work(&dp->connect_work);
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700692 flush_workqueue(dp->wq);
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -0700693
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700694 dp_display_handle_disconnect(dp);
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700695end:
696 return rc;
697}
698
Ajay Singh Parmar8a1bcde2017-11-20 12:37:39 -0800699static void dp_display_handle_maintenance_req(struct dp_display_private *dp)
700{
701 mutex_lock(&dp->audio->ops_lock);
702
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800703 if (dp->audio_supported && !IS_ERR_VALUE(dp->audio_status))
Ajay Singh Parmar8a1bcde2017-11-20 12:37:39 -0800704 dp->audio->off(dp->audio);
705
706 dp->ctrl->link_maintenance(dp->ctrl);
707
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800708 if (dp->audio_supported && !IS_ERR_VALUE(dp->audio_status))
709 dp->audio_status = dp->audio->on(dp->audio);
Ajay Singh Parmar8a1bcde2017-11-20 12:37:39 -0800710
711 mutex_unlock(&dp->audio->ops_lock);
712}
713
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700714static void dp_display_attention_work(struct work_struct *work)
Padmanabhan Komanduru58717282017-08-28 17:01:49 +0530715{
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700716 struct dp_display_private *dp = container_of(work,
717 struct dp_display_private, attention_work);
718
719 if (dp_display_is_hdcp_enabled(dp) && dp->hdcp.ops->cp_irq) {
720 if (!dp->hdcp.ops->cp_irq(dp->hdcp.data))
721 return;
722 }
Ajay Singh Parmardb147892017-10-18 15:42:41 -0700723
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530724 if (dp->link->sink_request & DS_PORT_STATUS_CHANGED) {
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700725 dp_display_handle_disconnect(dp);
Padmanabhan Komanduru58717282017-08-28 17:01:49 +0530726
727 if (dp_display_is_sink_count_zero(dp)) {
728 pr_debug("sink count is zero, nothing to do\n");
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700729 return;
Padmanabhan Komanduru58717282017-08-28 17:01:49 +0530730 }
731
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800732 queue_delayed_work(dp->wq, &dp->connect_work, 0);
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700733 return;
734 }
735
736 if (dp->link->sink_request & DP_TEST_LINK_VIDEO_PATTERN) {
737 dp_display_handle_disconnect(dp);
738
739 dp->panel->video_test = true;
740 dp_display_send_hpd_notification(dp, true);
741 dp->link->send_test_response(dp->link);
742
743 return;
Padmanabhan Komanduru58717282017-08-28 17:01:49 +0530744 }
745
Ajay Singh Parmar8a1bcde2017-11-20 12:37:39 -0800746 if (dp->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
747 dp->ctrl->process_phy_test_request(dp->ctrl);
748 return;
749 }
Ajay Singh Parmardb147892017-10-18 15:42:41 -0700750
Ajay Singh Parmar8a1bcde2017-11-20 12:37:39 -0800751 if (dp->link->sink_request & DP_LINK_STATUS_UPDATED) {
752 dp_display_handle_maintenance_req(dp);
753 return;
754 }
755
756 if (dp->link->sink_request & DP_TEST_LINK_TRAINING) {
757 dp->link->send_test_response(dp->link);
758 dp_display_handle_maintenance_req(dp);
759 return;
Ajay Singh Parmardb147892017-10-18 15:42:41 -0700760 }
Padmanabhan Komanduru58717282017-08-28 17:01:49 +0530761}
762
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700763static int dp_display_usbpd_attention_cb(struct device *dev)
764{
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700765 struct dp_display_private *dp;
766
767 if (!dev) {
768 pr_err("invalid dev\n");
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700769 return -EINVAL;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700770 }
771
772 dp = dev_get_drvdata(dev);
773 if (!dp) {
774 pr_err("no driver data found\n");
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700775 return -ENODEV;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700776 }
777
Ajay Singh Parmar420e7e12018-01-11 21:27:16 -0800778 if (dp->usbpd->hpd_irq && dp->usbpd->hpd_high &&
779 dp->power_on) {
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700780 dp->link->process_request(dp->link);
781 queue_work(dp->wq, &dp->attention_work);
782 } else if (dp->usbpd->hpd_high) {
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800783 queue_delayed_work(dp->wq, &dp->connect_work, 0);
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700784 } else {
785 /* cancel any pending request */
786 dp->ctrl->abort(dp->ctrl);
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530787 dp->aux->abort(dp->aux);
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700788
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700789 /* wait for idle state */
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800790 cancel_delayed_work(&dp->connect_work);
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700791 flush_workqueue(dp->wq);
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700792
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700793 dp_display_handle_disconnect(dp);
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700794 }
795
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700796 return 0;
797}
798
799static void dp_display_connect_work(struct work_struct *work)
800{
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800801 struct delayed_work *dw = to_delayed_work(work);
802 struct dp_display_private *dp = container_of(dw,
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700803 struct dp_display_private, connect_work);
804
805 if (dp->dp_display.is_connected) {
806 pr_debug("HPD already on\n");
807 return;
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700808 }
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700809
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700810 dp_display_process_hpd_high(dp);
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700811}
812
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700813static void dp_display_deinit_sub_modules(struct dp_display_private *dp)
814{
815 dp_audio_put(dp->audio);
816 dp_ctrl_put(dp->ctrl);
817 dp_link_put(dp->link);
818 dp_panel_put(dp->panel);
819 dp_aux_put(dp->aux);
820 dp_power_put(dp->power);
821 dp_catalog_put(dp->catalog);
822 dp_parser_put(dp->parser);
823 dp_usbpd_put(dp->usbpd);
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -0700824 mutex_destroy(&dp->session_lock);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700825 dp_debug_put(dp->debug);
826}
827
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700828static int dp_init_sub_modules(struct dp_display_private *dp)
829{
830 int rc = 0;
831 struct device *dev = &dp->pdev->dev;
832 struct dp_usbpd_cb *cb = &dp->usbpd_cb;
833 struct dp_ctrl_in ctrl_in = {
834 .dev = dev,
835 };
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +0530836 struct dp_panel_in panel_in = {
837 .dev = dev,
838 };
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700839
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -0700840 mutex_init(&dp->session_lock);
841
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700842 dp->parser = dp_parser_get(dp->pdev);
843 if (IS_ERR(dp->parser)) {
844 rc = PTR_ERR(dp->parser);
845 pr_err("failed to initialize parser, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700846 dp->parser = NULL;
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800847 goto error;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700848 }
849
Ajay Singh Parmard948c052017-10-27 20:58:58 -0700850 rc = dp->parser->parse(dp->parser);
851 if (rc) {
852 pr_err("device tree parsing failed\n");
853 goto error_catalog;
854 }
855
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700856 dp->catalog = dp_catalog_get(dev, &dp->parser->io);
857 if (IS_ERR(dp->catalog)) {
858 rc = PTR_ERR(dp->catalog);
859 pr_err("failed to initialize catalog, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700860 dp->catalog = NULL;
861 goto error_catalog;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700862 }
863
864 dp->power = dp_power_get(dp->parser);
865 if (IS_ERR(dp->power)) {
866 rc = PTR_ERR(dp->power);
867 pr_err("failed to initialize power, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700868 dp->power = NULL;
869 goto error_power;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700870 }
871
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800872 rc = dp->power->power_client_init(dp->power, &dp->priv->phandle);
873 if (rc) {
874 pr_err("Power client create failed\n");
875 goto error_aux;
876 }
877
Padmanabhan Komanduru2e9914b2017-08-04 20:51:31 +0530878 dp->aux = dp_aux_get(dev, &dp->catalog->aux, dp->parser->aux_cfg);
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700879 if (IS_ERR(dp->aux)) {
880 rc = PTR_ERR(dp->aux);
881 pr_err("failed to initialize aux, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700882 dp->aux = NULL;
883 goto error_aux;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700884 }
885
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800886 rc = dp->aux->drm_aux_register(dp->aux);
887 if (rc) {
888 pr_err("DRM DP AUX register failed\n");
889 goto error_link;
890 }
891
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700892 dp->link = dp_link_get(dev, dp->aux);
893 if (IS_ERR(dp->link)) {
894 rc = PTR_ERR(dp->link);
895 pr_err("failed to initialize link, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700896 dp->link = NULL;
897 goto error_link;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700898 }
899
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +0530900 panel_in.aux = dp->aux;
901 panel_in.catalog = &dp->catalog->panel;
902 panel_in.link = dp->link;
903
904 dp->panel = dp_panel_get(&panel_in);
905 if (IS_ERR(dp->panel)) {
906 rc = PTR_ERR(dp->panel);
907 pr_err("failed to initialize panel, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700908 dp->panel = NULL;
909 goto error_panel;
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +0530910 }
911
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700912 ctrl_in.link = dp->link;
913 ctrl_in.panel = dp->panel;
914 ctrl_in.aux = dp->aux;
915 ctrl_in.power = dp->power;
916 ctrl_in.catalog = &dp->catalog->ctrl;
917 ctrl_in.parser = dp->parser;
918
919 dp->ctrl = dp_ctrl_get(&ctrl_in);
920 if (IS_ERR(dp->ctrl)) {
921 rc = PTR_ERR(dp->ctrl);
922 pr_err("failed to initialize ctrl, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700923 dp->ctrl = NULL;
924 goto error_ctrl;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700925 }
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -0700926
927 dp->audio = dp_audio_get(dp->pdev, dp->panel, &dp->catalog->audio);
928 if (IS_ERR(dp->audio)) {
929 rc = PTR_ERR(dp->audio);
930 pr_err("failed to initialize audio, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700931 dp->audio = NULL;
932 goto error_audio;
Samantha Tran2d1ed732017-07-31 17:30:14 -0700933 }
934
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800935 cb->configure = dp_display_usbpd_configure_cb;
936 cb->disconnect = dp_display_usbpd_disconnect_cb;
937 cb->attention = dp_display_usbpd_attention_cb;
938
939 dp->usbpd = dp_usbpd_get(dev, cb);
940 if (IS_ERR(dp->usbpd)) {
941 rc = PTR_ERR(dp->usbpd);
942 pr_err("failed to initialize usbpd, rc = %d\n", rc);
943 dp->usbpd = NULL;
944 goto error_usbpd;
945 }
946
Samantha Tran2d1ed732017-07-31 17:30:14 -0700947 dp->debug = dp_debug_get(dev, dp->panel, dp->usbpd,
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800948 dp->link, dp->aux, &dp->dp_display.connector);
Samantha Tran2d1ed732017-07-31 17:30:14 -0700949 if (IS_ERR(dp->debug)) {
950 rc = PTR_ERR(dp->debug);
951 pr_err("failed to initialize debug, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700952 dp->debug = NULL;
953 goto error_debug;
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -0700954 }
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700955
956 return rc;
957error_debug:
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800958 dp_usbpd_put(dp->usbpd);
959error_usbpd:
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700960 dp_audio_put(dp->audio);
961error_audio:
962 dp_ctrl_put(dp->ctrl);
963error_ctrl:
964 dp_panel_put(dp->panel);
965error_panel:
966 dp_link_put(dp->link);
967error_link:
968 dp_aux_put(dp->aux);
969error_aux:
970 dp_power_put(dp->power);
971error_power:
972 dp_catalog_put(dp->catalog);
973error_catalog:
974 dp_parser_put(dp->parser);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700975error:
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800976 mutex_destroy(&dp->session_lock);
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700977 return rc;
978}
979
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800980static void dp_display_post_init(struct dp_display *dp_display)
981{
982 int rc = 0;
983 struct dp_display_private *dp;
984
985 if (!dp_display) {
986 pr_err("invalid input\n");
987 rc = -EINVAL;
988 goto end;
989 }
990
991 dp = container_of(dp_display, struct dp_display_private, dp_display);
992 if (IS_ERR_OR_NULL(dp)) {
993 pr_err("invalid params\n");
994 rc = -EINVAL;
995 goto end;
996 }
997
998 rc = dp_init_sub_modules(dp);
999 if (rc)
1000 goto end;
1001
1002 dp_display_initialize_hdcp(dp);
1003
1004 dp_display->post_init = NULL;
1005end:
1006 pr_debug("%s\n", rc ? "failed" : "success");
1007}
1008
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001009static int dp_display_set_mode(struct dp_display *dp_display,
1010 struct dp_display_mode *mode)
1011{
Tatenda Chipeperekwa8a44bd92017-10-05 16:32:06 -07001012 const u32 num_components = 3, default_bpp = 24;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001013 struct dp_display_private *dp;
1014
1015 if (!dp_display) {
1016 pr_err("invalid input\n");
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001017 return -EINVAL;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001018 }
1019 dp = container_of(dp_display, struct dp_display_private, dp_display);
1020
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001021 mutex_lock(&dp->session_lock);
Tatenda Chipeperekwa8a44bd92017-10-05 16:32:06 -07001022 mode->timing.bpp =
1023 dp_display->connector->display_info.bpc * num_components;
1024 if (!mode->timing.bpp)
1025 mode->timing.bpp = default_bpp;
1026
1027 mode->timing.bpp = dp->panel->get_mode_bpp(dp->panel,
1028 mode->timing.bpp, mode->timing.pixel_clk_khz);
1029
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001030 dp->panel->pinfo = mode->timing;
Ajay Singh Parmarfae11672017-09-01 19:49:30 -07001031 dp->panel->init(dp->panel);
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001032 mutex_unlock(&dp->session_lock);
1033
1034 return 0;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001035}
1036
1037static int dp_display_prepare(struct dp_display *dp)
1038{
1039 return 0;
1040}
1041
1042static int dp_display_enable(struct dp_display *dp_display)
1043{
1044 int rc = 0;
1045 struct dp_display_private *dp;
1046
1047 if (!dp_display) {
1048 pr_err("invalid input\n");
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001049 return -EINVAL;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001050 }
1051
1052 dp = container_of(dp_display, struct dp_display_private, dp_display);
1053
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001054 mutex_lock(&dp->session_lock);
1055
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301056 if (dp->power_on) {
1057 pr_debug("Link already setup, return\n");
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001058 goto end;
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301059 }
1060
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +05301061 dp->aux->init(dp->aux, dp->parser->aux_cfg);
1062
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301063 rc = dp->ctrl->on(dp->ctrl);
Padmanabhan Komanduru04aa2a72017-11-06 17:59:24 +05301064
1065 if (dp->debug->tpg_state)
1066 dp->panel->tpg_config(dp->panel, true);
1067
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -07001068 if (!rc)
1069 dp->power_on = true;
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001070end:
1071 mutex_unlock(&dp->session_lock);
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001072 return rc;
1073}
1074
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -07001075static int dp_display_post_enable(struct dp_display *dp_display)
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001076{
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -07001077 struct dp_display_private *dp;
1078
1079 if (!dp_display) {
1080 pr_err("invalid input\n");
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001081 return -EINVAL;
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -07001082 }
1083
1084 dp = container_of(dp_display, struct dp_display_private, dp_display);
1085
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001086 mutex_lock(&dp->session_lock);
1087
1088 if (!dp->power_on) {
1089 pr_debug("Link not setup, return\n");
1090 goto end;
1091 }
1092
Padmanabhan Komanduru62a01d02017-11-03 19:44:13 +05301093 dp->panel->spd_config(dp->panel);
1094
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -07001095 if (dp->audio_supported) {
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +05301096 dp->audio->bw_code = dp->link->link_params.bw_code;
1097 dp->audio->lane_count = dp->link->link_params.lane_count;
Ajay Singh Parmar84337302017-12-12 14:26:41 -08001098 dp->audio_status = dp->audio->on(dp->audio);
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -07001099 }
1100
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -07001101 dp_display_update_hdcp_info(dp);
1102
1103 if (dp_display_is_hdcp_enabled(dp)) {
1104 cancel_delayed_work_sync(&dp->hdcp_cb_work);
1105
1106 dp->hdcp_status = HDCP_STATE_AUTHENTICATING;
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -07001107 queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ / 2);
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -07001108 }
Ajay Singh Parmar87af50b2017-12-22 22:22:55 -08001109
1110 dp->panel->setup_hdr(dp->panel, NULL);
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -07001111end:
Ajay Singh Parmar2307c202017-11-12 20:14:30 -08001112 /* clear framework event notifier */
Ajay Singh Parmar315e5852017-11-23 21:47:32 -08001113 dp_display->post_open = NULL;
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -08001114 dp->aux->state |= DP_STATE_CTRL_POWERED_ON;
Ajay Singh Parmar2307c202017-11-12 20:14:30 -08001115
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +05301116 complete_all(&dp->notification_comp);
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001117 mutex_unlock(&dp->session_lock);
1118 return 0;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001119}
1120
1121static int dp_display_pre_disable(struct dp_display *dp_display)
1122{
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001123 struct dp_display_private *dp;
1124
1125 if (!dp_display) {
1126 pr_err("invalid input\n");
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001127 return -EINVAL;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001128 }
1129
1130 dp = container_of(dp_display, struct dp_display_private, dp_display);
1131
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001132 mutex_lock(&dp->session_lock);
1133
1134 if (!dp->power_on) {
1135 pr_debug("Link already powered off, return\n");
1136 goto end;
1137 }
1138
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -07001139 if (dp_display_is_hdcp_enabled(dp)) {
1140 dp->hdcp_status = HDCP_STATE_INACTIVE;
1141
1142 cancel_delayed_work_sync(&dp->hdcp_cb_work);
1143 if (dp->hdcp.ops->off)
1144 dp->hdcp.ops->off(dp->hdcp.data);
1145 }
1146
Padmanabhan Komanduruac827ee2018-01-18 18:51:25 +05301147 if (dp->usbpd->hpd_high && dp->usbpd->alt_mode_cfg_done) {
1148 if (dp->audio_supported)
1149 dp->audio->off(dp->audio);
1150
1151 dp->link->psm_config(dp->link, &dp->panel->link_info, true);
1152 dp->debug->psm_enabled = true;
1153 }
1154
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -07001155 dp->ctrl->push_idle(dp->ctrl);
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001156end:
1157 mutex_unlock(&dp->session_lock);
1158 return 0;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001159}
1160
1161static int dp_display_disable(struct dp_display *dp_display)
1162{
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001163 struct dp_display_private *dp;
Ajay Singh Parmar87af50b2017-12-22 22:22:55 -08001164 struct drm_connector *connector;
1165 struct sde_connector_state *c_state;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001166
1167 if (!dp_display) {
1168 pr_err("invalid input\n");
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001169 return -EINVAL;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001170 }
1171
1172 dp = container_of(dp_display, struct dp_display_private, dp_display);
Ajay Singh Parmar87af50b2017-12-22 22:22:55 -08001173 connector = dp->dp_display.connector;
1174 c_state = to_sde_connector_state(connector->state);
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001175
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001176 mutex_lock(&dp->session_lock);
1177
1178 if (!dp->power_on || !dp->core_initialized) {
1179 pr_debug("Link already powered off, return\n");
1180 goto end;
1181 }
Ajay Singh Parmarbf9531c2017-08-11 19:02:02 -07001182
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301183 dp->ctrl->off(dp->ctrl);
Ajay Singh Parmarfae11672017-09-01 19:49:30 -07001184 dp->panel->deinit(dp->panel);
Ajay Singh Parmar420e7e12018-01-11 21:27:16 -08001185 dp->aux->deinit(dp->aux);
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -07001186
Ajay Singh Parmar87af50b2017-12-22 22:22:55 -08001187 connector->hdr_eotf = 0;
1188 connector->hdr_metadata_type_one = 0;
1189 connector->hdr_max_luminance = 0;
1190 connector->hdr_avg_luminance = 0;
1191 connector->hdr_min_luminance = 0;
1192
1193 memset(&c_state->hdr_meta, 0, sizeof(c_state->hdr_meta));
1194
Padmanabhan Komanduruac827ee2018-01-18 18:51:25 +05301195 /*
1196 * In case of framework reboot, the DP off sequence is executed without
1197 * any notification from driver. Initialize post_open callback to notify
1198 * DP connection once framework restarts.
1199 */
1200 if (dp->usbpd->hpd_high && dp->usbpd->alt_mode_cfg_done) {
1201 dp_display->post_open = dp_display_post_open;
1202 dp->dp_display.is_connected = false;
1203 }
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -07001204 dp->power_on = false;
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -08001205 dp->aux->state = DP_STATE_CTRL_POWERED_OFF;
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001206end:
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -07001207 complete_all(&dp->notification_comp);
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001208 mutex_unlock(&dp->session_lock);
1209 return 0;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001210}
1211
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -07001212static int dp_request_irq(struct dp_display *dp_display)
1213{
1214 int rc = 0;
1215 struct dp_display_private *dp;
1216
1217 if (!dp_display) {
1218 pr_err("invalid input\n");
1219 return -EINVAL;
1220 }
1221
1222 dp = container_of(dp_display, struct dp_display_private, dp_display);
1223
1224 dp->irq = irq_of_parse_and_map(dp->pdev->dev.of_node, 0);
1225 if (dp->irq < 0) {
1226 rc = dp->irq;
1227 pr_err("failed to get irq: %d\n", rc);
1228 return rc;
1229 }
1230
1231 rc = devm_request_irq(&dp->pdev->dev, dp->irq, dp_display_irq,
1232 IRQF_TRIGGER_HIGH, "dp_display_isr", dp);
1233 if (rc < 0) {
1234 pr_err("failed to request IRQ%u: %d\n",
1235 dp->irq, rc);
1236 return rc;
1237 }
1238 disable_irq(dp->irq);
1239
1240 return 0;
1241}
1242
Samantha Tran2d1ed732017-07-31 17:30:14 -07001243static struct dp_debug *dp_get_debug(struct dp_display *dp_display)
1244{
1245 struct dp_display_private *dp;
1246
1247 if (!dp_display) {
1248 pr_err("invalid input\n");
1249 return ERR_PTR(-EINVAL);
1250 }
1251
1252 dp = container_of(dp_display, struct dp_display_private, dp_display);
1253
1254 return dp->debug;
1255}
1256
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001257static int dp_display_unprepare(struct dp_display *dp)
1258{
1259 return 0;
1260}
1261
Tatenda Chipeperekwa8a44bd92017-10-05 16:32:06 -07001262static int dp_display_validate_mode(struct dp_display *dp, u32 mode_pclk_khz)
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001263{
Tatenda Chipeperekwa8a44bd92017-10-05 16:32:06 -07001264 const u32 num_components = 3, default_bpp = 24;
1265 struct dp_display_private *dp_display;
1266 struct drm_dp_link *link_info;
1267 u32 mode_rate_khz = 0, supported_rate_khz = 0, mode_bpp = 0;
1268
Ajay Singh Parmar315e5852017-11-23 21:47:32 -08001269 if (!dp || !mode_pclk_khz || !dp->connector) {
Tatenda Chipeperekwa8a44bd92017-10-05 16:32:06 -07001270 pr_err("invalid params\n");
1271 return -EINVAL;
1272 }
1273
1274 dp_display = container_of(dp, struct dp_display_private, dp_display);
1275 link_info = &dp_display->panel->link_info;
1276
1277 mode_bpp = dp->connector->display_info.bpc * num_components;
1278 if (!mode_bpp)
1279 mode_bpp = default_bpp;
1280
1281 mode_bpp = dp_display->panel->get_mode_bpp(dp_display->panel,
1282 mode_bpp, mode_pclk_khz);
1283
1284 mode_rate_khz = mode_pclk_khz * mode_bpp;
1285 supported_rate_khz = link_info->num_lanes * link_info->rate * 8;
1286
1287 if (mode_rate_khz > supported_rate_khz)
1288 return MODE_BAD;
1289
1290 return MODE_OK;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001291}
1292
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +05301293static int dp_display_get_modes(struct dp_display *dp,
1294 struct dp_display_mode *dp_mode)
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001295{
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -07001296 struct dp_display_private *dp_display;
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +05301297 int ret = 0;
1298
Ajay Singh Parmar315e5852017-11-23 21:47:32 -08001299 if (!dp || !dp->connector) {
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +05301300 pr_err("invalid params\n");
1301 return 0;
1302 }
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001303
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -07001304 dp_display = container_of(dp, struct dp_display_private, dp_display);
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001305
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +05301306 ret = dp_display->panel->get_modes(dp_display->panel,
1307 dp->connector, dp_mode);
1308 if (dp_mode->timing.pixel_clk_khz)
1309 dp->max_pclk_khz = dp_mode->timing.pixel_clk_khz;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -07001310 return ret;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001311}
1312
Ajay Singh Parmar87af50b2017-12-22 22:22:55 -08001313static int dp_display_config_hdr(struct dp_display *dp_display,
Ajay Singh Parmar9c842d42017-09-21 13:02:05 -07001314 struct drm_msm_ext_hdr_metadata *hdr)
1315{
Ajay Singh Parmar973cab12017-11-15 15:33:33 -08001316 int rc = 0;
Ajay Singh Parmar9c842d42017-09-21 13:02:05 -07001317 struct dp_display_private *dp;
1318
1319 if (!dp_display) {
1320 pr_err("invalid input\n");
1321 return -EINVAL;
1322 }
1323
1324 dp = container_of(dp_display, struct dp_display_private, dp_display);
1325
Ajay Singh Parmar87af50b2017-12-22 22:22:55 -08001326 rc = dp->panel->setup_hdr(dp->panel, hdr);
Ajay Singh Parmar973cab12017-11-15 15:33:33 -08001327
1328 return rc;
Ajay Singh Parmar9c842d42017-09-21 13:02:05 -07001329}
1330
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -07001331static int dp_display_create_workqueue(struct dp_display_private *dp)
1332{
1333 dp->wq = create_singlethread_workqueue("drm_dp");
1334 if (IS_ERR_OR_NULL(dp->wq)) {
1335 pr_err("Error creating wq\n");
1336 return -EPERM;
1337 }
1338
1339 INIT_DELAYED_WORK(&dp->hdcp_cb_work, dp_display_hdcp_cb_work);
Ajay Singh Parmar84337302017-12-12 14:26:41 -08001340 INIT_DELAYED_WORK(&dp->connect_work, dp_display_connect_work);
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -07001341 INIT_WORK(&dp->attention_work, dp_display_attention_work);
1342
1343 return 0;
1344}
1345
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001346static int dp_display_probe(struct platform_device *pdev)
1347{
1348 int rc = 0;
1349 struct dp_display_private *dp;
1350
1351 if (!pdev || !pdev->dev.of_node) {
1352 pr_err("pdev not found\n");
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -07001353 rc = -ENODEV;
1354 goto bail;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001355 }
1356
1357 dp = devm_kzalloc(&pdev->dev, sizeof(*dp), GFP_KERNEL);
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -07001358 if (!dp) {
1359 rc = -ENOMEM;
1360 goto bail;
1361 }
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001362
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -07001363 init_completion(&dp->notification_comp);
1364
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001365 dp->pdev = pdev;
1366 dp->name = "drm_dp";
Ajay Singh Parmar84337302017-12-12 14:26:41 -08001367 dp->audio_status = -ENODEV;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001368
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -07001369 rc = dp_display_create_workqueue(dp);
1370 if (rc) {
1371 pr_err("Failed to create workqueue\n");
Ajay Singh Parmar315e5852017-11-23 21:47:32 -08001372 goto error;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001373 }
1374
1375 platform_set_drvdata(pdev, dp);
1376
1377 g_dp_display = &dp->dp_display;
1378
1379 g_dp_display->enable = dp_display_enable;
1380 g_dp_display->post_enable = dp_display_post_enable;
1381 g_dp_display->pre_disable = dp_display_pre_disable;
1382 g_dp_display->disable = dp_display_disable;
1383 g_dp_display->set_mode = dp_display_set_mode;
1384 g_dp_display->validate_mode = dp_display_validate_mode;
1385 g_dp_display->get_modes = dp_display_get_modes;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001386 g_dp_display->prepare = dp_display_prepare;
1387 g_dp_display->unprepare = dp_display_unprepare;
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -07001388 g_dp_display->request_irq = dp_request_irq;
Samantha Tran2d1ed732017-07-31 17:30:14 -07001389 g_dp_display->get_debug = dp_get_debug;
Ajay Singh Parmar315e5852017-11-23 21:47:32 -08001390 g_dp_display->post_open = dp_display_post_open;
1391 g_dp_display->post_init = dp_display_post_init;
Ajay Singh Parmar87af50b2017-12-22 22:22:55 -08001392 g_dp_display->config_hdr = dp_display_config_hdr;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001393
1394 rc = component_add(&pdev->dev, &dp_display_comp_ops);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -07001395 if (rc) {
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001396 pr_err("component add failed, rc=%d\n", rc);
Ajay Singh Parmar315e5852017-11-23 21:47:32 -08001397 goto error;
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -07001398 }
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001399
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -07001400 return 0;
Ajay Singh Parmar315e5852017-11-23 21:47:32 -08001401error:
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -07001402 devm_kfree(&pdev->dev, dp);
1403bail:
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001404 return rc;
1405}
1406
Padmanabhan Komanduru63758612017-05-23 01:47:18 -07001407int dp_display_get_displays(void **displays, int count)
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001408{
Padmanabhan Komanduru63758612017-05-23 01:47:18 -07001409 if (!displays) {
1410 pr_err("invalid data\n");
1411 return -EINVAL;
1412 }
1413
1414 if (count != 1) {
1415 pr_err("invalid number of displays\n");
1416 return -EINVAL;
1417 }
1418
1419 displays[0] = g_dp_display;
1420 return count;
1421}
1422
1423int dp_display_get_num_of_displays(void)
1424{
1425 return 1;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001426}
1427
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001428static int dp_display_remove(struct platform_device *pdev)
1429{
1430 struct dp_display_private *dp;
1431
1432 if (!pdev)
1433 return -EINVAL;
1434
1435 dp = platform_get_drvdata(pdev);
1436
1437 dp_display_deinit_sub_modules(dp);
1438
1439 platform_set_drvdata(pdev, NULL);
1440 devm_kfree(&pdev->dev, dp);
1441
1442 return 0;
1443}
1444
1445static struct platform_driver dp_display_driver = {
1446 .probe = dp_display_probe,
1447 .remove = dp_display_remove,
1448 .driver = {
1449 .name = "msm-dp-display",
1450 .of_match_table = dp_dt_match,
1451 },
1452};
1453
1454static int __init dp_display_init(void)
1455{
1456 int ret;
1457
1458 ret = platform_driver_register(&dp_display_driver);
1459 if (ret) {
1460 pr_err("driver register failed");
1461 return ret;
1462 }
1463
1464 return ret;
1465}
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -07001466late_initcall(dp_display_init);
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001467
1468static void __exit dp_display_cleanup(void)
1469{
1470 platform_driver_unregister(&dp_display_driver);
1471}
1472module_exit(dp_display_cleanup);
1473