blob: b1d03d620ae64bde32e59f88535a155a07e0c877 [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;
Samantha Tranb6a5cd82018-02-01 14:47:16 -0800277 struct dp_parser *parser;
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700278 int rc = 0;
279
280 if (!dp) {
281 pr_err("invalid input\n");
282 return -EINVAL;
283 }
284
Samantha Tranb6a5cd82018-02-01 14:47:16 -0800285 parser = dp->parser;
286
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700287 mutex_init(&dp->hdcp_mutex);
288
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700289 hdcp_init_data.client_id = HDCP_CLIENT_DP;
290 hdcp_init_data.drm_aux = dp->aux->drm_aux;
291 hdcp_init_data.cb_data = (void *)dp;
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700292 hdcp_init_data.workq = dp->wq;
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700293 hdcp_init_data.mutex = &dp->hdcp_mutex;
294 hdcp_init_data.sec_access = true;
295 hdcp_init_data.notify_status = dp_display_notify_hdcp_status_cb;
Samantha Tranb6a5cd82018-02-01 14:47:16 -0800296 hdcp_init_data.dp_ahb = &parser->get_io(parser, "dp_ahb")->io;
297 hdcp_init_data.dp_aux = &parser->get_io(parser, "dp_aux")->io;
298 hdcp_init_data.dp_link = &parser->get_io(parser, "dp_link")->io;
299 hdcp_init_data.dp_p0 = &parser->get_io(parser, "dp_p0")->io;
300 hdcp_init_data.qfprom_io = &parser->get_io(parser,
301 "qfprom_physical")->io;
302 hdcp_init_data.hdcp_io = &parser->get_io(parser,
303 "hdcp_physical")->io;
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700304 hdcp_init_data.revision = &dp->panel->link_info.revision;
305
Tatenda Chipeperekwab8cbd132017-07-07 17:43:29 -0700306 dp->hdcp.hdcp1 = sde_hdcp_1x_init(&hdcp_init_data);
307 if (IS_ERR_OR_NULL(dp->hdcp.hdcp1)) {
308 pr_err("Error initializing HDCP 1.x\n");
309 rc = -EINVAL;
310 goto error;
311 }
312
313 pr_debug("HDCP 1.3 initialized\n");
314
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700315 dp->hdcp.hdcp2 = sde_dp_hdcp2p2_init(&hdcp_init_data);
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800316 if (IS_ERR_OR_NULL(dp->hdcp.hdcp2)) {
317 pr_err("Error initializing HDCP 2.x\n");
318 rc = -EINVAL;
319 goto error;
320 }
321
322 pr_debug("HDCP 2.2 initialized\n");
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700323
324 dp->hdcp.feature_enabled = true;
325
326 return 0;
327error:
328 dp_display_deinitialize_hdcp(dp);
329 return rc;
330}
331
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700332static int dp_display_bind(struct device *dev, struct device *master,
333 void *data)
334{
335 int rc = 0;
336 struct dp_display_private *dp;
337 struct drm_device *drm;
338 struct platform_device *pdev = to_platform_device(dev);
339
340 if (!dev || !pdev || !master) {
341 pr_err("invalid param(s), dev %pK, pdev %pK, master %pK\n",
342 dev, pdev, master);
343 rc = -EINVAL;
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700344 goto end;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700345 }
346
347 drm = dev_get_drvdata(master);
348 dp = platform_get_drvdata(pdev);
349 if (!drm || !dp) {
350 pr_err("invalid param(s), drm %pK, dp %pK\n",
351 drm, dp);
352 rc = -EINVAL;
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700353 goto end;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700354 }
355
356 dp->dp_display.drm_dev = drm;
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800357 dp->priv = drm->dev_private;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700358end:
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700359 return rc;
360}
361
362static void dp_display_unbind(struct device *dev, struct device *master,
363 void *data)
364{
365 struct dp_display_private *dp;
366 struct platform_device *pdev = to_platform_device(dev);
367
368 if (!dev || !pdev) {
369 pr_err("invalid param(s)\n");
370 return;
371 }
372
373 dp = platform_get_drvdata(pdev);
374 if (!dp) {
375 pr_err("Invalid params\n");
376 return;
377 }
378
Padmanabhan Komanduru4152f392017-05-11 17:53:55 -0700379 (void)dp->power->power_client_deinit(dp->power);
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700380 (void)dp->aux->drm_aux_deregister(dp->aux);
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700381 dp_display_deinitialize_hdcp(dp);
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700382}
383
384static const struct component_ops dp_display_comp_ops = {
385 .bind = dp_display_bind,
386 .unbind = dp_display_unbind,
387};
388
Padmanabhan Komanduru58717282017-08-28 17:01:49 +0530389static bool dp_display_is_ds_bridge(struct dp_panel *panel)
390{
391 return (panel->dpcd[DP_DOWNSTREAMPORT_PRESENT] &
392 DP_DWN_STRM_PORT_PRESENT);
393}
394
395static bool dp_display_is_sink_count_zero(struct dp_display_private *dp)
396{
397 return dp_display_is_ds_bridge(dp->panel) &&
398 (dp->link->sink_count.count == 0);
399}
400
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800401static void dp_display_send_hpd_event(struct dp_display_private *dp)
Padmanabhan Komanduru71aec2d2017-08-30 20:07:59 +0530402{
403 struct drm_device *dev = NULL;
Padmanabhan Komanduru71aec2d2017-08-30 20:07:59 +0530404 struct drm_connector *connector;
405 char name[HPD_STRING_SIZE], status[HPD_STRING_SIZE],
406 bpp[HPD_STRING_SIZE], pattern[HPD_STRING_SIZE];
407 char *envp[5];
408
Padmanabhan Komanduru71aec2d2017-08-30 20:07:59 +0530409 connector = dp->dp_display.connector;
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800410
411 if (!connector) {
412 pr_err("connector not set\n");
413 return;
414 }
Padmanabhan Komanduru71aec2d2017-08-30 20:07:59 +0530415
416 connector->status = connector->funcs->detect(connector, false);
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800417
418 dev = dp->dp_display.connector->dev;
419
Padmanabhan Komanduru71aec2d2017-08-30 20:07:59 +0530420 snprintf(name, HPD_STRING_SIZE, "name=%s", connector->name);
421 snprintf(status, HPD_STRING_SIZE, "status=%s",
422 drm_get_connector_status_name(connector->status));
423 snprintf(bpp, HPD_STRING_SIZE, "bpp=%d",
424 dp_link_bit_depth_to_bpp(
425 dp->link->test_video.test_bit_depth));
426 snprintf(pattern, HPD_STRING_SIZE, "pattern=%d",
427 dp->link->test_video.test_video_pattern);
428
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800429 pr_debug("[%s]:[%s] [%s] [%s]\n", name, status, bpp, pattern);
Padmanabhan Komanduru71aec2d2017-08-30 20:07:59 +0530430 envp[0] = name;
431 envp[1] = status;
432 envp[2] = bpp;
433 envp[3] = pattern;
434 envp[4] = NULL;
435 kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE,
436 envp);
437}
438
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800439static void dp_display_post_open(struct dp_display *dp_display)
440{
441 struct drm_connector *connector;
442 struct dp_display_private *dp;
443
444 if (!dp_display) {
445 pr_err("invalid input\n");
446 return;
447 }
448
449 dp = container_of(dp_display, struct dp_display_private, dp_display);
450 if (IS_ERR_OR_NULL(dp)) {
451 pr_err("invalid params\n");
452 return;
453 }
454
455 connector = dp->dp_display.connector;
456
457 if (!connector) {
458 pr_err("connector not set\n");
459 return;
460 }
461
462 /* if cable is already connected, send notification */
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800463 if (dp->usbpd->hpd_high)
464 queue_delayed_work(dp->wq, &dp->connect_work, HZ * 10);
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800465 else
466 dp_display->post_open = NULL;
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800467}
468
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530469static int dp_display_send_hpd_notification(struct dp_display_private *dp,
470 bool hpd)
471{
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800472 u32 timeout_sec;
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800473 int ret = 0;
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800474
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530475 dp->dp_display.is_connected = hpd;
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800476
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800477 if (dp_display_framework_ready(dp))
478 timeout_sec = 5;
479 else
480 timeout_sec = 10;
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800481
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800482 dp->aux->state |= DP_STATE_NOTIFICATION_SENT;
483
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530484 reinit_completion(&dp->notification_comp);
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800485 dp_display_send_hpd_event(dp);
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530486
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800487 if (!wait_for_completion_timeout(&dp->notification_comp,
488 HZ * timeout_sec)) {
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -0700489 pr_warn("%s timeout\n", hpd ? "connect" : "disconnect");
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800490 ret = -EINVAL;
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530491 }
492
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800493 dp->aux->state &= ~DP_STATE_NOTIFICATION_SENT;
494
495 return ret;
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530496}
497
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700498static int dp_display_process_hpd_high(struct dp_display_private *dp)
499{
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700500 int rc = 0;
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -0700501 struct edid *edid;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700502
Tatenda Chipeperekwa344498e2017-09-06 12:34:36 -0700503 dp->aux->init(dp->aux, dp->parser->aux_cfg);
504
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700505 if (dp->debug->psm_enabled) {
506 dp->link->psm_config(dp->link, &dp->panel->link_info, false);
507 dp->debug->psm_enabled = false;
508 }
Padmanabhan Komandurub6f7c6f2017-09-05 18:50:30 +0530509
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800510 if (!dp->dp_display.connector)
511 return 0;
512
Padmanabhan Komanduruda8b3d02017-12-22 15:45:12 +0530513 rc = dp->panel->read_sink_caps(dp->panel,
514 dp->dp_display.connector, dp->usbpd->multi_func);
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530515 if (rc) {
Ajay Singh Parmar6da24b02017-12-08 14:30:36 -0800516 /*
517 * ETIMEDOUT --> cable may have been removed
518 * ENOTCONN --> no downstream device connected
519 */
520 if (rc == -ETIMEDOUT || rc == -ENOTCONN)
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530521 goto end;
Ajay Singh Parmar6da24b02017-12-08 14:30:36 -0800522 else
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530523 goto notify;
Padmanabhan Komanduru58717282017-08-28 17:01:49 +0530524 }
525
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -0700526 edid = dp->panel->edid_ctrl->edid;
527
528 dp->audio_supported = drm_detect_monitor_audio(edid);
529
Ajay Singh Parmar6da24b02017-12-08 14:30:36 -0800530 dp->link->process_request(dp->link);
Padmanabhan Komanduru504e2892017-09-19 20:38:31 +0530531 dp->panel->handle_sink_request(dp->panel);
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530532
Tatenda Chipeperekwa8a44bd92017-10-05 16:32:06 -0700533 dp->dp_display.max_pclk_khz = dp->parser->max_pclk_khz;
Padmanabhan Komandurub6f7c6f2017-09-05 18:50:30 +0530534notify:
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530535 dp_display_send_hpd_notification(dp, true);
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700536
Padmanabhan Komanduru58717282017-08-28 17:01:49 +0530537end:
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700538 return rc;
539}
540
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700541static void dp_display_host_init(struct dp_display_private *dp)
542{
543 bool flip = false;
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800544 bool reset;
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700545
546 if (dp->core_initialized) {
547 pr_debug("DP core already initialized\n");
548 return;
549 }
550
551 if (dp->usbpd->orientation == ORIENTATION_CC2)
552 flip = true;
553
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800554 reset = dp->debug->sim_mode ? false : !dp->usbpd->multi_func;
555
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700556 dp->power->init(dp->power, flip);
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800557 dp->ctrl->init(dp->ctrl, flip, reset);
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700558 enable_irq(dp->irq);
559 dp->core_initialized = true;
560}
561
562static void dp_display_host_deinit(struct dp_display_private *dp)
563{
564 if (!dp->core_initialized) {
565 pr_debug("DP core already off\n");
566 return;
567 }
568
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700569 dp->ctrl->deinit(dp->ctrl);
570 dp->power->deinit(dp->power);
571 disable_irq(dp->irq);
572 dp->core_initialized = false;
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800573 dp->aux->state = 0;
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700574}
575
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700576static int dp_display_process_hpd_low(struct dp_display_private *dp)
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700577{
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700578 int rc = 0;
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700579
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700580 if (!dp->dp_display.is_connected) {
581 pr_debug("HPD already off\n");
582 return 0;
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700583 }
584
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700585 if (dp_display_is_hdcp_enabled(dp) && dp->hdcp.ops->off)
586 dp->hdcp.ops->off(dp->hdcp.data);
587
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -0700588 if (dp->audio_supported)
589 dp->audio->off(dp->audio);
590
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800591 dp->audio_status = -ENODEV;
592
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700593 rc = dp_display_send_hpd_notification(dp, false);
Tatenda Chipeperekwa344498e2017-09-06 12:34:36 -0700594
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700595 dp->panel->video_test = false;
596
597 return rc;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700598}
599
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700600static int dp_display_usbpd_configure_cb(struct device *dev)
601{
602 int rc = 0;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700603 struct dp_display_private *dp;
604
605 if (!dev) {
606 pr_err("invalid dev\n");
607 rc = -EINVAL;
608 goto end;
609 }
610
611 dp = dev_get_drvdata(dev);
612 if (!dp) {
613 pr_err("no driver data found\n");
614 rc = -ENODEV;
615 goto end;
616 }
617
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700618 dp_display_host_init(dp);
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700619
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800620 /* check for hpd high and framework ready */
621 if (dp->usbpd->hpd_high && dp_display_framework_ready(dp))
622 queue_delayed_work(dp->wq, &dp->connect_work, 0);
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700623end:
624 return rc;
625}
626
Ajay Singh Parmarbf9531c2017-08-11 19:02:02 -0700627static void dp_display_clean(struct dp_display_private *dp)
628{
629 if (dp_display_is_hdcp_enabled(dp)) {
630 dp->hdcp_status = HDCP_STATE_INACTIVE;
631
632 cancel_delayed_work_sync(&dp->hdcp_cb_work);
633 if (dp->hdcp.ops->off)
634 dp->hdcp.ops->off(dp->hdcp.data);
635 }
636
637 dp->ctrl->push_idle(dp->ctrl);
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530638 dp->ctrl->off(dp->ctrl);
Ajay Singh Parmar420e7e12018-01-11 21:27:16 -0800639 dp->panel->deinit(dp->panel);
640 dp->aux->deinit(dp->aux);
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -0700641 dp->power_on = false;
Ajay Singh Parmarbf9531c2017-08-11 19:02:02 -0700642}
643
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700644static int dp_display_handle_disconnect(struct dp_display_private *dp)
645{
646 int rc;
647
648 rc = dp_display_process_hpd_low(dp);
649
650 mutex_lock(&dp->session_lock);
651 if (rc && dp->power_on)
652 dp_display_clean(dp);
653
654 if (!dp->usbpd->alt_mode_cfg_done)
655 dp_display_host_deinit(dp);
656
657 mutex_unlock(&dp->session_lock);
658
659 return rc;
660}
661
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700662static int dp_display_usbpd_disconnect_cb(struct device *dev)
663{
664 int rc = 0;
665 struct dp_display_private *dp;
666
667 if (!dev) {
668 pr_err("invalid dev\n");
669 rc = -EINVAL;
670 goto end;
671 }
672
673 dp = dev_get_drvdata(dev);
674 if (!dp) {
675 pr_err("no driver data found\n");
676 rc = -ENODEV;
677 goto end;
678 }
679
Padmanabhan Komanduruac827ee2018-01-18 18:51:25 +0530680 /*
681 * In case cable/dongle is disconnected during adb shell stop,
682 * reset psm_enabled flag to false since it is no more needed
683 */
684 if (dp->dp_display.post_open)
685 dp->debug->psm_enabled = false;
686
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700687 if (dp->debug->psm_enabled)
688 dp->link->psm_config(dp->link, &dp->panel->link_info, true);
689
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700690 /* cancel any pending request */
691 dp->ctrl->abort(dp->ctrl);
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530692 dp->aux->abort(dp->aux);
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700693
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700694 /* wait for idle state */
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800695 cancel_delayed_work(&dp->connect_work);
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700696 flush_workqueue(dp->wq);
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -0700697
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700698 dp_display_handle_disconnect(dp);
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700699end:
700 return rc;
701}
702
Ajay Singh Parmar8a1bcde2017-11-20 12:37:39 -0800703static void dp_display_handle_maintenance_req(struct dp_display_private *dp)
704{
705 mutex_lock(&dp->audio->ops_lock);
706
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800707 if (dp->audio_supported && !IS_ERR_VALUE(dp->audio_status))
Ajay Singh Parmar8a1bcde2017-11-20 12:37:39 -0800708 dp->audio->off(dp->audio);
709
710 dp->ctrl->link_maintenance(dp->ctrl);
711
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800712 if (dp->audio_supported && !IS_ERR_VALUE(dp->audio_status))
713 dp->audio_status = dp->audio->on(dp->audio);
Ajay Singh Parmar8a1bcde2017-11-20 12:37:39 -0800714
715 mutex_unlock(&dp->audio->ops_lock);
716}
717
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700718static void dp_display_attention_work(struct work_struct *work)
Padmanabhan Komanduru58717282017-08-28 17:01:49 +0530719{
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700720 struct dp_display_private *dp = container_of(work,
721 struct dp_display_private, attention_work);
722
723 if (dp_display_is_hdcp_enabled(dp) && dp->hdcp.ops->cp_irq) {
724 if (!dp->hdcp.ops->cp_irq(dp->hdcp.data))
725 return;
726 }
Ajay Singh Parmardb147892017-10-18 15:42:41 -0700727
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530728 if (dp->link->sink_request & DS_PORT_STATUS_CHANGED) {
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700729 dp_display_handle_disconnect(dp);
Padmanabhan Komanduru58717282017-08-28 17:01:49 +0530730
731 if (dp_display_is_sink_count_zero(dp)) {
732 pr_debug("sink count is zero, nothing to do\n");
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700733 return;
Padmanabhan Komanduru58717282017-08-28 17:01:49 +0530734 }
735
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800736 queue_delayed_work(dp->wq, &dp->connect_work, 0);
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700737 return;
738 }
739
740 if (dp->link->sink_request & DP_TEST_LINK_VIDEO_PATTERN) {
741 dp_display_handle_disconnect(dp);
742
743 dp->panel->video_test = true;
744 dp_display_send_hpd_notification(dp, true);
745 dp->link->send_test_response(dp->link);
746
747 return;
Padmanabhan Komanduru58717282017-08-28 17:01:49 +0530748 }
749
Ajay Singh Parmar8a1bcde2017-11-20 12:37:39 -0800750 if (dp->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
751 dp->ctrl->process_phy_test_request(dp->ctrl);
752 return;
753 }
Ajay Singh Parmardb147892017-10-18 15:42:41 -0700754
Ajay Singh Parmar8a1bcde2017-11-20 12:37:39 -0800755 if (dp->link->sink_request & DP_LINK_STATUS_UPDATED) {
756 dp_display_handle_maintenance_req(dp);
757 return;
758 }
759
760 if (dp->link->sink_request & DP_TEST_LINK_TRAINING) {
761 dp->link->send_test_response(dp->link);
762 dp_display_handle_maintenance_req(dp);
763 return;
Ajay Singh Parmardb147892017-10-18 15:42:41 -0700764 }
Padmanabhan Komanduru58717282017-08-28 17:01:49 +0530765}
766
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700767static int dp_display_usbpd_attention_cb(struct device *dev)
768{
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700769 struct dp_display_private *dp;
770
771 if (!dev) {
772 pr_err("invalid dev\n");
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700773 return -EINVAL;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700774 }
775
776 dp = dev_get_drvdata(dev);
777 if (!dp) {
778 pr_err("no driver data found\n");
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700779 return -ENODEV;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700780 }
781
Ajay Singh Parmar420e7e12018-01-11 21:27:16 -0800782 if (dp->usbpd->hpd_irq && dp->usbpd->hpd_high &&
783 dp->power_on) {
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700784 dp->link->process_request(dp->link);
785 queue_work(dp->wq, &dp->attention_work);
786 } else if (dp->usbpd->hpd_high) {
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800787 queue_delayed_work(dp->wq, &dp->connect_work, 0);
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700788 } else {
789 /* cancel any pending request */
790 dp->ctrl->abort(dp->ctrl);
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530791 dp->aux->abort(dp->aux);
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700792
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700793 /* wait for idle state */
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800794 cancel_delayed_work(&dp->connect_work);
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700795 flush_workqueue(dp->wq);
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700796
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700797 dp_display_handle_disconnect(dp);
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700798 }
799
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700800 return 0;
801}
802
803static void dp_display_connect_work(struct work_struct *work)
804{
Ajay Singh Parmar84337302017-12-12 14:26:41 -0800805 struct delayed_work *dw = to_delayed_work(work);
806 struct dp_display_private *dp = container_of(dw,
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700807 struct dp_display_private, connect_work);
808
809 if (dp->dp_display.is_connected) {
810 pr_debug("HPD already on\n");
811 return;
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700812 }
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700813
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -0700814 dp_display_process_hpd_high(dp);
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700815}
816
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700817static void dp_display_deinit_sub_modules(struct dp_display_private *dp)
818{
819 dp_audio_put(dp->audio);
820 dp_ctrl_put(dp->ctrl);
821 dp_link_put(dp->link);
822 dp_panel_put(dp->panel);
823 dp_aux_put(dp->aux);
824 dp_power_put(dp->power);
825 dp_catalog_put(dp->catalog);
826 dp_parser_put(dp->parser);
827 dp_usbpd_put(dp->usbpd);
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -0700828 mutex_destroy(&dp->session_lock);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700829 dp_debug_put(dp->debug);
830}
831
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700832static int dp_init_sub_modules(struct dp_display_private *dp)
833{
834 int rc = 0;
835 struct device *dev = &dp->pdev->dev;
836 struct dp_usbpd_cb *cb = &dp->usbpd_cb;
837 struct dp_ctrl_in ctrl_in = {
838 .dev = dev,
839 };
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +0530840 struct dp_panel_in panel_in = {
841 .dev = dev,
842 };
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700843
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -0700844 mutex_init(&dp->session_lock);
845
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700846 dp->parser = dp_parser_get(dp->pdev);
847 if (IS_ERR(dp->parser)) {
848 rc = PTR_ERR(dp->parser);
849 pr_err("failed to initialize parser, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700850 dp->parser = NULL;
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800851 goto error;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700852 }
853
Ajay Singh Parmard948c052017-10-27 20:58:58 -0700854 rc = dp->parser->parse(dp->parser);
855 if (rc) {
856 pr_err("device tree parsing failed\n");
857 goto error_catalog;
858 }
859
Samantha Tranb6a5cd82018-02-01 14:47:16 -0800860 dp->catalog = dp_catalog_get(dev, dp->parser);
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700861 if (IS_ERR(dp->catalog)) {
862 rc = PTR_ERR(dp->catalog);
863 pr_err("failed to initialize catalog, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700864 dp->catalog = NULL;
865 goto error_catalog;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700866 }
867
868 dp->power = dp_power_get(dp->parser);
869 if (IS_ERR(dp->power)) {
870 rc = PTR_ERR(dp->power);
871 pr_err("failed to initialize power, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700872 dp->power = NULL;
873 goto error_power;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700874 }
875
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800876 rc = dp->power->power_client_init(dp->power, &dp->priv->phandle);
877 if (rc) {
878 pr_err("Power client create failed\n");
879 goto error_aux;
880 }
881
Padmanabhan Komanduru2e9914b2017-08-04 20:51:31 +0530882 dp->aux = dp_aux_get(dev, &dp->catalog->aux, dp->parser->aux_cfg);
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700883 if (IS_ERR(dp->aux)) {
884 rc = PTR_ERR(dp->aux);
885 pr_err("failed to initialize aux, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700886 dp->aux = NULL;
887 goto error_aux;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700888 }
889
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800890 rc = dp->aux->drm_aux_register(dp->aux);
891 if (rc) {
892 pr_err("DRM DP AUX register failed\n");
893 goto error_link;
894 }
895
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700896 dp->link = dp_link_get(dev, dp->aux);
897 if (IS_ERR(dp->link)) {
898 rc = PTR_ERR(dp->link);
899 pr_err("failed to initialize link, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700900 dp->link = NULL;
901 goto error_link;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700902 }
903
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +0530904 panel_in.aux = dp->aux;
905 panel_in.catalog = &dp->catalog->panel;
906 panel_in.link = dp->link;
907
908 dp->panel = dp_panel_get(&panel_in);
909 if (IS_ERR(dp->panel)) {
910 rc = PTR_ERR(dp->panel);
911 pr_err("failed to initialize panel, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700912 dp->panel = NULL;
913 goto error_panel;
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +0530914 }
915
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700916 ctrl_in.link = dp->link;
917 ctrl_in.panel = dp->panel;
918 ctrl_in.aux = dp->aux;
919 ctrl_in.power = dp->power;
920 ctrl_in.catalog = &dp->catalog->ctrl;
921 ctrl_in.parser = dp->parser;
922
923 dp->ctrl = dp_ctrl_get(&ctrl_in);
924 if (IS_ERR(dp->ctrl)) {
925 rc = PTR_ERR(dp->ctrl);
926 pr_err("failed to initialize ctrl, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700927 dp->ctrl = NULL;
928 goto error_ctrl;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700929 }
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -0700930
931 dp->audio = dp_audio_get(dp->pdev, dp->panel, &dp->catalog->audio);
932 if (IS_ERR(dp->audio)) {
933 rc = PTR_ERR(dp->audio);
934 pr_err("failed to initialize audio, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700935 dp->audio = NULL;
936 goto error_audio;
Samantha Tran2d1ed732017-07-31 17:30:14 -0700937 }
938
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800939 cb->configure = dp_display_usbpd_configure_cb;
940 cb->disconnect = dp_display_usbpd_disconnect_cb;
941 cb->attention = dp_display_usbpd_attention_cb;
942
943 dp->usbpd = dp_usbpd_get(dev, cb);
944 if (IS_ERR(dp->usbpd)) {
945 rc = PTR_ERR(dp->usbpd);
946 pr_err("failed to initialize usbpd, rc = %d\n", rc);
947 dp->usbpd = NULL;
948 goto error_usbpd;
949 }
950
Samantha Tran2d1ed732017-07-31 17:30:14 -0700951 dp->debug = dp_debug_get(dev, dp->panel, dp->usbpd,
Samantha Tranb6a5cd82018-02-01 14:47:16 -0800952 dp->link, dp->aux, &dp->dp_display.connector,
953 dp->catalog);
Samantha Tran2d1ed732017-07-31 17:30:14 -0700954 if (IS_ERR(dp->debug)) {
955 rc = PTR_ERR(dp->debug);
956 pr_err("failed to initialize debug, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700957 dp->debug = NULL;
958 goto error_debug;
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -0700959 }
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700960
961 return rc;
962error_debug:
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800963 dp_usbpd_put(dp->usbpd);
964error_usbpd:
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700965 dp_audio_put(dp->audio);
966error_audio:
967 dp_ctrl_put(dp->ctrl);
968error_ctrl:
969 dp_panel_put(dp->panel);
970error_panel:
971 dp_link_put(dp->link);
972error_link:
973 dp_aux_put(dp->aux);
974error_aux:
975 dp_power_put(dp->power);
976error_power:
977 dp_catalog_put(dp->catalog);
978error_catalog:
979 dp_parser_put(dp->parser);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700980error:
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800981 mutex_destroy(&dp->session_lock);
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700982 return rc;
983}
984
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800985static void dp_display_post_init(struct dp_display *dp_display)
986{
987 int rc = 0;
988 struct dp_display_private *dp;
989
990 if (!dp_display) {
991 pr_err("invalid input\n");
992 rc = -EINVAL;
993 goto end;
994 }
995
996 dp = container_of(dp_display, struct dp_display_private, dp_display);
997 if (IS_ERR_OR_NULL(dp)) {
998 pr_err("invalid params\n");
999 rc = -EINVAL;
1000 goto end;
1001 }
1002
1003 rc = dp_init_sub_modules(dp);
1004 if (rc)
1005 goto end;
1006
1007 dp_display_initialize_hdcp(dp);
1008
1009 dp_display->post_init = NULL;
1010end:
1011 pr_debug("%s\n", rc ? "failed" : "success");
1012}
1013
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001014static int dp_display_set_mode(struct dp_display *dp_display,
1015 struct dp_display_mode *mode)
1016{
Tatenda Chipeperekwa8a44bd92017-10-05 16:32:06 -07001017 const u32 num_components = 3, default_bpp = 24;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001018 struct dp_display_private *dp;
1019
1020 if (!dp_display) {
1021 pr_err("invalid input\n");
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001022 return -EINVAL;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001023 }
1024 dp = container_of(dp_display, struct dp_display_private, dp_display);
1025
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001026 mutex_lock(&dp->session_lock);
Tatenda Chipeperekwa8a44bd92017-10-05 16:32:06 -07001027 mode->timing.bpp =
1028 dp_display->connector->display_info.bpc * num_components;
1029 if (!mode->timing.bpp)
1030 mode->timing.bpp = default_bpp;
1031
1032 mode->timing.bpp = dp->panel->get_mode_bpp(dp->panel,
1033 mode->timing.bpp, mode->timing.pixel_clk_khz);
1034
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001035 dp->panel->pinfo = mode->timing;
Ajay Singh Parmarfae11672017-09-01 19:49:30 -07001036 dp->panel->init(dp->panel);
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001037 mutex_unlock(&dp->session_lock);
1038
1039 return 0;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001040}
1041
1042static int dp_display_prepare(struct dp_display *dp)
1043{
1044 return 0;
1045}
1046
1047static int dp_display_enable(struct dp_display *dp_display)
1048{
1049 int rc = 0;
1050 struct dp_display_private *dp;
1051
1052 if (!dp_display) {
1053 pr_err("invalid input\n");
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001054 return -EINVAL;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001055 }
1056
1057 dp = container_of(dp_display, struct dp_display_private, dp_display);
1058
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001059 mutex_lock(&dp->session_lock);
1060
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301061 if (dp->power_on) {
1062 pr_debug("Link already setup, return\n");
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001063 goto end;
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301064 }
1065
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +05301066 dp->aux->init(dp->aux, dp->parser->aux_cfg);
1067
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301068 rc = dp->ctrl->on(dp->ctrl);
Padmanabhan Komanduru04aa2a72017-11-06 17:59:24 +05301069
1070 if (dp->debug->tpg_state)
1071 dp->panel->tpg_config(dp->panel, true);
1072
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -07001073 if (!rc)
1074 dp->power_on = true;
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001075end:
1076 mutex_unlock(&dp->session_lock);
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001077 return rc;
1078}
1079
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -07001080static int dp_display_post_enable(struct dp_display *dp_display)
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001081{
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -07001082 struct dp_display_private *dp;
1083
1084 if (!dp_display) {
1085 pr_err("invalid input\n");
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001086 return -EINVAL;
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -07001087 }
1088
1089 dp = container_of(dp_display, struct dp_display_private, dp_display);
1090
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001091 mutex_lock(&dp->session_lock);
1092
1093 if (!dp->power_on) {
1094 pr_debug("Link not setup, return\n");
1095 goto end;
1096 }
1097
Padmanabhan Komanduru62a01d02017-11-03 19:44:13 +05301098 dp->panel->spd_config(dp->panel);
1099
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -07001100 if (dp->audio_supported) {
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +05301101 dp->audio->bw_code = dp->link->link_params.bw_code;
1102 dp->audio->lane_count = dp->link->link_params.lane_count;
Ajay Singh Parmar84337302017-12-12 14:26:41 -08001103 dp->audio_status = dp->audio->on(dp->audio);
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -07001104 }
1105
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -07001106 dp_display_update_hdcp_info(dp);
1107
1108 if (dp_display_is_hdcp_enabled(dp)) {
1109 cancel_delayed_work_sync(&dp->hdcp_cb_work);
1110
1111 dp->hdcp_status = HDCP_STATE_AUTHENTICATING;
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -07001112 queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ / 2);
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -07001113 }
Ajay Singh Parmar87af50b2017-12-22 22:22:55 -08001114
1115 dp->panel->setup_hdr(dp->panel, NULL);
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -07001116end:
Ajay Singh Parmar2307c202017-11-12 20:14:30 -08001117 /* clear framework event notifier */
Ajay Singh Parmar315e5852017-11-23 21:47:32 -08001118 dp_display->post_open = NULL;
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -08001119 dp->aux->state |= DP_STATE_CTRL_POWERED_ON;
Ajay Singh Parmar2307c202017-11-12 20:14:30 -08001120
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +05301121 complete_all(&dp->notification_comp);
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001122 mutex_unlock(&dp->session_lock);
1123 return 0;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001124}
1125
1126static int dp_display_pre_disable(struct dp_display *dp_display)
1127{
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001128 struct dp_display_private *dp;
1129
1130 if (!dp_display) {
1131 pr_err("invalid input\n");
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001132 return -EINVAL;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001133 }
1134
1135 dp = container_of(dp_display, struct dp_display_private, dp_display);
1136
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001137 mutex_lock(&dp->session_lock);
1138
1139 if (!dp->power_on) {
1140 pr_debug("Link already powered off, return\n");
1141 goto end;
1142 }
1143
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -07001144 if (dp_display_is_hdcp_enabled(dp)) {
1145 dp->hdcp_status = HDCP_STATE_INACTIVE;
1146
1147 cancel_delayed_work_sync(&dp->hdcp_cb_work);
1148 if (dp->hdcp.ops->off)
1149 dp->hdcp.ops->off(dp->hdcp.data);
1150 }
1151
Padmanabhan Komanduruac827ee2018-01-18 18:51:25 +05301152 if (dp->usbpd->hpd_high && dp->usbpd->alt_mode_cfg_done) {
1153 if (dp->audio_supported)
1154 dp->audio->off(dp->audio);
1155
1156 dp->link->psm_config(dp->link, &dp->panel->link_info, true);
1157 dp->debug->psm_enabled = true;
1158 }
1159
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -07001160 dp->ctrl->push_idle(dp->ctrl);
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001161end:
1162 mutex_unlock(&dp->session_lock);
1163 return 0;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001164}
1165
1166static int dp_display_disable(struct dp_display *dp_display)
1167{
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001168 struct dp_display_private *dp;
Ajay Singh Parmar87af50b2017-12-22 22:22:55 -08001169 struct drm_connector *connector;
1170 struct sde_connector_state *c_state;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001171
1172 if (!dp_display) {
1173 pr_err("invalid input\n");
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001174 return -EINVAL;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001175 }
1176
1177 dp = container_of(dp_display, struct dp_display_private, dp_display);
Ajay Singh Parmar87af50b2017-12-22 22:22:55 -08001178 connector = dp->dp_display.connector;
1179 c_state = to_sde_connector_state(connector->state);
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001180
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001181 mutex_lock(&dp->session_lock);
1182
1183 if (!dp->power_on || !dp->core_initialized) {
1184 pr_debug("Link already powered off, return\n");
1185 goto end;
1186 }
Ajay Singh Parmarbf9531c2017-08-11 19:02:02 -07001187
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301188 dp->ctrl->off(dp->ctrl);
Ajay Singh Parmarfae11672017-09-01 19:49:30 -07001189 dp->panel->deinit(dp->panel);
Ajay Singh Parmar420e7e12018-01-11 21:27:16 -08001190 dp->aux->deinit(dp->aux);
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -07001191
Ajay Singh Parmar87af50b2017-12-22 22:22:55 -08001192 connector->hdr_eotf = 0;
1193 connector->hdr_metadata_type_one = 0;
1194 connector->hdr_max_luminance = 0;
1195 connector->hdr_avg_luminance = 0;
1196 connector->hdr_min_luminance = 0;
1197
1198 memset(&c_state->hdr_meta, 0, sizeof(c_state->hdr_meta));
1199
Padmanabhan Komanduruac827ee2018-01-18 18:51:25 +05301200 /*
1201 * In case of framework reboot, the DP off sequence is executed without
1202 * any notification from driver. Initialize post_open callback to notify
1203 * DP connection once framework restarts.
1204 */
1205 if (dp->usbpd->hpd_high && dp->usbpd->alt_mode_cfg_done) {
1206 dp_display->post_open = dp_display_post_open;
1207 dp->dp_display.is_connected = false;
1208 }
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -07001209 dp->power_on = false;
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -08001210 dp->aux->state = DP_STATE_CTRL_POWERED_OFF;
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001211end:
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -07001212 complete_all(&dp->notification_comp);
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001213 mutex_unlock(&dp->session_lock);
1214 return 0;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001215}
1216
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -07001217static int dp_request_irq(struct dp_display *dp_display)
1218{
1219 int rc = 0;
1220 struct dp_display_private *dp;
1221
1222 if (!dp_display) {
1223 pr_err("invalid input\n");
1224 return -EINVAL;
1225 }
1226
1227 dp = container_of(dp_display, struct dp_display_private, dp_display);
1228
1229 dp->irq = irq_of_parse_and_map(dp->pdev->dev.of_node, 0);
1230 if (dp->irq < 0) {
1231 rc = dp->irq;
1232 pr_err("failed to get irq: %d\n", rc);
1233 return rc;
1234 }
1235
1236 rc = devm_request_irq(&dp->pdev->dev, dp->irq, dp_display_irq,
1237 IRQF_TRIGGER_HIGH, "dp_display_isr", dp);
1238 if (rc < 0) {
1239 pr_err("failed to request IRQ%u: %d\n",
1240 dp->irq, rc);
1241 return rc;
1242 }
1243 disable_irq(dp->irq);
1244
1245 return 0;
1246}
1247
Samantha Tran2d1ed732017-07-31 17:30:14 -07001248static struct dp_debug *dp_get_debug(struct dp_display *dp_display)
1249{
1250 struct dp_display_private *dp;
1251
1252 if (!dp_display) {
1253 pr_err("invalid input\n");
1254 return ERR_PTR(-EINVAL);
1255 }
1256
1257 dp = container_of(dp_display, struct dp_display_private, dp_display);
1258
1259 return dp->debug;
1260}
1261
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001262static int dp_display_unprepare(struct dp_display *dp)
1263{
1264 return 0;
1265}
1266
Tatenda Chipeperekwa8a44bd92017-10-05 16:32:06 -07001267static int dp_display_validate_mode(struct dp_display *dp, u32 mode_pclk_khz)
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001268{
Tatenda Chipeperekwa8a44bd92017-10-05 16:32:06 -07001269 const u32 num_components = 3, default_bpp = 24;
1270 struct dp_display_private *dp_display;
1271 struct drm_dp_link *link_info;
1272 u32 mode_rate_khz = 0, supported_rate_khz = 0, mode_bpp = 0;
1273
Ajay Singh Parmar315e5852017-11-23 21:47:32 -08001274 if (!dp || !mode_pclk_khz || !dp->connector) {
Tatenda Chipeperekwa8a44bd92017-10-05 16:32:06 -07001275 pr_err("invalid params\n");
1276 return -EINVAL;
1277 }
1278
1279 dp_display = container_of(dp, struct dp_display_private, dp_display);
1280 link_info = &dp_display->panel->link_info;
1281
1282 mode_bpp = dp->connector->display_info.bpc * num_components;
1283 if (!mode_bpp)
1284 mode_bpp = default_bpp;
1285
1286 mode_bpp = dp_display->panel->get_mode_bpp(dp_display->panel,
1287 mode_bpp, mode_pclk_khz);
1288
1289 mode_rate_khz = mode_pclk_khz * mode_bpp;
1290 supported_rate_khz = link_info->num_lanes * link_info->rate * 8;
1291
1292 if (mode_rate_khz > supported_rate_khz)
1293 return MODE_BAD;
1294
1295 return MODE_OK;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001296}
1297
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +05301298static int dp_display_get_modes(struct dp_display *dp,
1299 struct dp_display_mode *dp_mode)
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001300{
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -07001301 struct dp_display_private *dp_display;
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +05301302 int ret = 0;
1303
Ajay Singh Parmar315e5852017-11-23 21:47:32 -08001304 if (!dp || !dp->connector) {
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +05301305 pr_err("invalid params\n");
1306 return 0;
1307 }
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001308
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -07001309 dp_display = container_of(dp, struct dp_display_private, dp_display);
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001310
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +05301311 ret = dp_display->panel->get_modes(dp_display->panel,
1312 dp->connector, dp_mode);
1313 if (dp_mode->timing.pixel_clk_khz)
1314 dp->max_pclk_khz = dp_mode->timing.pixel_clk_khz;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -07001315 return ret;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001316}
1317
Ajay Singh Parmar87af50b2017-12-22 22:22:55 -08001318static int dp_display_config_hdr(struct dp_display *dp_display,
Ajay Singh Parmar9c842d42017-09-21 13:02:05 -07001319 struct drm_msm_ext_hdr_metadata *hdr)
1320{
Ajay Singh Parmar973cab12017-11-15 15:33:33 -08001321 int rc = 0;
Ajay Singh Parmar9c842d42017-09-21 13:02:05 -07001322 struct dp_display_private *dp;
1323
1324 if (!dp_display) {
1325 pr_err("invalid input\n");
1326 return -EINVAL;
1327 }
1328
1329 dp = container_of(dp_display, struct dp_display_private, dp_display);
1330
Ajay Singh Parmar87af50b2017-12-22 22:22:55 -08001331 rc = dp->panel->setup_hdr(dp->panel, hdr);
Ajay Singh Parmar973cab12017-11-15 15:33:33 -08001332
1333 return rc;
Ajay Singh Parmar9c842d42017-09-21 13:02:05 -07001334}
1335
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -07001336static int dp_display_create_workqueue(struct dp_display_private *dp)
1337{
1338 dp->wq = create_singlethread_workqueue("drm_dp");
1339 if (IS_ERR_OR_NULL(dp->wq)) {
1340 pr_err("Error creating wq\n");
1341 return -EPERM;
1342 }
1343
1344 INIT_DELAYED_WORK(&dp->hdcp_cb_work, dp_display_hdcp_cb_work);
Ajay Singh Parmar84337302017-12-12 14:26:41 -08001345 INIT_DELAYED_WORK(&dp->connect_work, dp_display_connect_work);
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -07001346 INIT_WORK(&dp->attention_work, dp_display_attention_work);
1347
1348 return 0;
1349}
1350
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001351static int dp_display_probe(struct platform_device *pdev)
1352{
1353 int rc = 0;
1354 struct dp_display_private *dp;
1355
1356 if (!pdev || !pdev->dev.of_node) {
1357 pr_err("pdev not found\n");
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -07001358 rc = -ENODEV;
1359 goto bail;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001360 }
1361
1362 dp = devm_kzalloc(&pdev->dev, sizeof(*dp), GFP_KERNEL);
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -07001363 if (!dp) {
1364 rc = -ENOMEM;
1365 goto bail;
1366 }
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001367
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -07001368 init_completion(&dp->notification_comp);
1369
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001370 dp->pdev = pdev;
1371 dp->name = "drm_dp";
Ajay Singh Parmar84337302017-12-12 14:26:41 -08001372 dp->audio_status = -ENODEV;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001373
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -07001374 rc = dp_display_create_workqueue(dp);
1375 if (rc) {
1376 pr_err("Failed to create workqueue\n");
Ajay Singh Parmar315e5852017-11-23 21:47:32 -08001377 goto error;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001378 }
1379
1380 platform_set_drvdata(pdev, dp);
1381
1382 g_dp_display = &dp->dp_display;
1383
1384 g_dp_display->enable = dp_display_enable;
1385 g_dp_display->post_enable = dp_display_post_enable;
1386 g_dp_display->pre_disable = dp_display_pre_disable;
1387 g_dp_display->disable = dp_display_disable;
1388 g_dp_display->set_mode = dp_display_set_mode;
1389 g_dp_display->validate_mode = dp_display_validate_mode;
1390 g_dp_display->get_modes = dp_display_get_modes;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001391 g_dp_display->prepare = dp_display_prepare;
1392 g_dp_display->unprepare = dp_display_unprepare;
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -07001393 g_dp_display->request_irq = dp_request_irq;
Samantha Tran2d1ed732017-07-31 17:30:14 -07001394 g_dp_display->get_debug = dp_get_debug;
Ajay Singh Parmar315e5852017-11-23 21:47:32 -08001395 g_dp_display->post_open = dp_display_post_open;
1396 g_dp_display->post_init = dp_display_post_init;
Ajay Singh Parmar87af50b2017-12-22 22:22:55 -08001397 g_dp_display->config_hdr = dp_display_config_hdr;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001398
1399 rc = component_add(&pdev->dev, &dp_display_comp_ops);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -07001400 if (rc) {
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001401 pr_err("component add failed, rc=%d\n", rc);
Ajay Singh Parmar315e5852017-11-23 21:47:32 -08001402 goto error;
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -07001403 }
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001404
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -07001405 return 0;
Ajay Singh Parmar315e5852017-11-23 21:47:32 -08001406error:
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -07001407 devm_kfree(&pdev->dev, dp);
1408bail:
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001409 return rc;
1410}
1411
Padmanabhan Komanduru63758612017-05-23 01:47:18 -07001412int dp_display_get_displays(void **displays, int count)
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001413{
Padmanabhan Komanduru63758612017-05-23 01:47:18 -07001414 if (!displays) {
1415 pr_err("invalid data\n");
1416 return -EINVAL;
1417 }
1418
1419 if (count != 1) {
1420 pr_err("invalid number of displays\n");
1421 return -EINVAL;
1422 }
1423
1424 displays[0] = g_dp_display;
1425 return count;
1426}
1427
1428int dp_display_get_num_of_displays(void)
1429{
1430 return 1;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001431}
1432
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001433static int dp_display_remove(struct platform_device *pdev)
1434{
1435 struct dp_display_private *dp;
1436
1437 if (!pdev)
1438 return -EINVAL;
1439
1440 dp = platform_get_drvdata(pdev);
1441
1442 dp_display_deinit_sub_modules(dp);
1443
1444 platform_set_drvdata(pdev, NULL);
1445 devm_kfree(&pdev->dev, dp);
1446
1447 return 0;
1448}
1449
1450static struct platform_driver dp_display_driver = {
1451 .probe = dp_display_probe,
1452 .remove = dp_display_remove,
1453 .driver = {
1454 .name = "msm-dp-display",
1455 .of_match_table = dp_dt_match,
1456 },
1457};
1458
1459static int __init dp_display_init(void)
1460{
1461 int ret;
1462
1463 ret = platform_driver_register(&dp_display_driver);
1464 if (ret) {
1465 pr_err("driver register failed");
1466 return ret;
1467 }
1468
1469 return ret;
1470}
Ajay Singh Parmar25e2ee52017-10-20 23:50:53 -07001471late_initcall(dp_display_init);
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001472
1473static void __exit dp_display_cleanup(void)
1474{
1475 platform_driver_unregister(&dp_display_driver);
1476}
1477module_exit(dp_display_cleanup);
1478