blob: 7eb2306f502417ab34b04c36d21bc45d082178fa [file] [log] [blame]
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001/*
2 * Copyright (c) 2017, The Linux Foundation. All rights reserved.
3 *
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
Padmanabhan Komanduru4152f392017-05-11 17:53:55 -070025#include "msm_drv.h"
Ajay Singh Parmar77668872017-03-28 21:36:15 -070026#include "dp_usbpd.h"
27#include "dp_parser.h"
28#include "dp_power.h"
29#include "dp_catalog.h"
30#include "dp_aux.h"
31#include "dp_link.h"
32#include "dp_panel.h"
33#include "dp_ctrl.h"
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -070034#include "dp_audio.h"
Ajay Singh Parmar77668872017-03-28 21:36:15 -070035#include "dp_display.h"
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -070036#include "sde_hdcp.h"
Samantha Tran2d1ed732017-07-31 17:30:14 -070037#include "dp_debug.h"
Ajay Singh Parmar77668872017-03-28 21:36:15 -070038
39static struct dp_display *g_dp_display;
Padmanabhan Komanduru71aec2d2017-08-30 20:07:59 +053040#define HPD_STRING_SIZE 30
Ajay Singh Parmar77668872017-03-28 21:36:15 -070041
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -070042struct dp_hdcp {
43 void *data;
44 struct sde_hdcp_ops *ops;
45
46 void *hdcp1;
47 void *hdcp2;
48
49 int enc_lvl;
50
51 bool auth_state;
52 bool hdcp1_present;
53 bool hdcp2_present;
54 bool feature_enabled;
55};
56
Ajay Singh Parmar77668872017-03-28 21:36:15 -070057struct dp_display_private {
58 char *name;
59 int irq;
60
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -070061 /* state variables */
62 bool core_initialized;
63 bool power_on;
64 bool hpd_irq_on;
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -070065 bool audio_supported;
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -070066
Ajay Singh Parmar77668872017-03-28 21:36:15 -070067 struct platform_device *pdev;
68 struct dentry *root;
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -070069 struct completion notification_comp;
Ajay Singh Parmar77668872017-03-28 21:36:15 -070070
71 struct dp_usbpd *usbpd;
72 struct dp_parser *parser;
73 struct dp_power *power;
74 struct dp_catalog *catalog;
75 struct dp_aux *aux;
76 struct dp_link *link;
77 struct dp_panel *panel;
78 struct dp_ctrl *ctrl;
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -070079 struct dp_audio *audio;
Samantha Tran2d1ed732017-07-31 17:30:14 -070080 struct dp_debug *debug;
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -070081
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -070082 struct dp_hdcp hdcp;
Ajay Singh Parmar77668872017-03-28 21:36:15 -070083
84 struct dp_usbpd_cb usbpd_cb;
85 struct dp_display_mode mode;
86 struct dp_display dp_display;
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -070087
88 struct workqueue_struct *hdcp_workqueue;
89 struct delayed_work hdcp_cb_work;
90 struct mutex hdcp_mutex;
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -070091 struct mutex session_lock;
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -070092 int hdcp_status;
Ajay Singh Parmar77668872017-03-28 21:36:15 -070093};
94
95static const struct of_device_id dp_dt_match[] = {
96 {.compatible = "qcom,dp-display"},
97 {}
98};
99
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700100static inline bool dp_display_is_hdcp_enabled(struct dp_display_private *dp)
101{
102 return dp->hdcp.feature_enabled &&
103 (dp->hdcp.hdcp1_present || dp->hdcp.hdcp2_present) &&
104 dp->hdcp.ops;
105}
106
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -0700107static irqreturn_t dp_display_irq(int irq, void *dev_id)
108{
109 struct dp_display_private *dp = dev_id;
110
111 if (!dp) {
112 pr_err("invalid data\n");
113 return IRQ_NONE;
114 }
115
116 /* DP controller isr */
117 dp->ctrl->isr(dp->ctrl);
118
119 /* DP aux isr */
120 dp->aux->isr(dp->aux);
121
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700122 /* HDCP isr */
123 if (dp_display_is_hdcp_enabled(dp) && dp->hdcp.ops->isr) {
124 if (dp->hdcp.ops->isr(dp->hdcp.data))
125 pr_err("dp_hdcp_isr failed\n");
126 }
127
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -0700128 return IRQ_HANDLED;
129}
130
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700131static void dp_display_hdcp_cb_work(struct work_struct *work)
132{
133 struct dp_display_private *dp;
134 struct delayed_work *dw = to_delayed_work(work);
135 struct sde_hdcp_ops *ops;
136 int rc = 0;
137 u32 hdcp_auth_state;
138
139 dp = container_of(dw, struct dp_display_private, hdcp_cb_work);
140
141 rc = dp->catalog->ctrl.read_hdcp_status(&dp->catalog->ctrl);
142 if (rc >= 0) {
143 hdcp_auth_state = (rc >> 20) & 0x3;
144 pr_debug("hdcp auth state %d\n", hdcp_auth_state);
145 }
146
147 ops = dp->hdcp.ops;
148
149 switch (dp->hdcp_status) {
150 case HDCP_STATE_AUTHENTICATING:
151 pr_debug("start authenticaton\n");
152
153 if (dp->hdcp.ops && dp->hdcp.ops->authenticate)
154 rc = dp->hdcp.ops->authenticate(dp->hdcp.data);
155
156 break;
157 case HDCP_STATE_AUTHENTICATED:
158 pr_debug("hdcp authenticated\n");
159 dp->hdcp.auth_state = true;
160 break;
161 case HDCP_STATE_AUTH_FAIL:
162 dp->hdcp.auth_state = false;
163
164 if (dp->power_on) {
165 pr_debug("Reauthenticating\n");
166 if (ops && ops->reauthenticate) {
167 rc = ops->reauthenticate(dp->hdcp.data);
168 if (rc)
169 pr_err("reauth failed rc=%d\n", rc);
170 }
171 } else {
172 pr_debug("not reauthenticating, cable disconnected\n");
173 }
174
175 break;
176 default:
177 break;
178 }
179}
180
181static void dp_display_notify_hdcp_status_cb(void *ptr,
182 enum sde_hdcp_states status)
183{
184 struct dp_display_private *dp = ptr;
185
186 if (!dp) {
187 pr_err("invalid input\n");
188 return;
189 }
190
191 dp->hdcp_status = status;
192
193 if (dp->dp_display.is_connected)
194 queue_delayed_work(dp->hdcp_workqueue, &dp->hdcp_cb_work, HZ/4);
195}
196
197static int dp_display_create_hdcp_workqueue(struct dp_display_private *dp)
198{
199 dp->hdcp_workqueue = create_workqueue("sdm_dp_hdcp");
200 if (IS_ERR_OR_NULL(dp->hdcp_workqueue)) {
201 pr_err("Error creating hdcp_workqueue\n");
202 return -EPERM;
203 }
204
205 INIT_DELAYED_WORK(&dp->hdcp_cb_work, dp_display_hdcp_cb_work);
206
207 return 0;
208}
209
210static void dp_display_destroy_hdcp_workqueue(struct dp_display_private *dp)
211{
212 if (dp->hdcp_workqueue)
213 destroy_workqueue(dp->hdcp_workqueue);
214}
215
216static void dp_display_update_hdcp_info(struct dp_display_private *dp)
217{
218 void *fd = NULL;
219 struct sde_hdcp_ops *ops = NULL;
220
221 if (!dp) {
222 pr_err("invalid input\n");
223 return;
224 }
225
226 if (!dp->hdcp.feature_enabled) {
227 pr_debug("feature not enabled\n");
228 return;
229 }
230
231 fd = dp->hdcp.hdcp2;
232 if (fd)
233 ops = sde_dp_hdcp2p2_start(fd);
234
235 if (ops && ops->feature_supported)
236 dp->hdcp.hdcp2_present = ops->feature_supported(fd);
237 else
238 dp->hdcp.hdcp2_present = false;
239
Tatenda Chipeperekwab8cbd132017-07-07 17:43:29 -0700240 pr_debug("hdcp2p2: %s\n",
241 dp->hdcp.hdcp2_present ? "supported" : "not supported");
242
243 if (!dp->hdcp.hdcp2_present) {
244 dp->hdcp.hdcp1_present = hdcp1_check_if_supported_load_app();
245
246 if (dp->hdcp.hdcp1_present) {
247 fd = dp->hdcp.hdcp1;
248 ops = sde_hdcp_1x_start(fd);
249 }
250 }
251
252 pr_debug("hdcp1x: %s\n",
253 dp->hdcp.hdcp1_present ? "supported" : "not supported");
254
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700255 if (dp->hdcp.hdcp2_present || dp->hdcp.hdcp1_present) {
256 dp->hdcp.data = fd;
257 dp->hdcp.ops = ops;
258 } else {
259 dp->hdcp.data = NULL;
260 dp->hdcp.ops = NULL;
261 }
262}
263
264static void dp_display_deinitialize_hdcp(struct dp_display_private *dp)
265{
266 if (!dp) {
267 pr_err("invalid input\n");
268 return;
269 }
270
271 sde_dp_hdcp2p2_deinit(dp->hdcp.data);
272 dp_display_destroy_hdcp_workqueue(dp);
273 if (&dp->hdcp_mutex)
274 mutex_destroy(&dp->hdcp_mutex);
275}
276
277static int dp_display_initialize_hdcp(struct dp_display_private *dp)
278{
279 struct sde_hdcp_init_data hdcp_init_data;
280 struct resource *res;
281 int rc = 0;
282
283 if (!dp) {
284 pr_err("invalid input\n");
285 return -EINVAL;
286 }
287
288 mutex_init(&dp->hdcp_mutex);
289
290 rc = dp_display_create_hdcp_workqueue(dp);
291 if (rc) {
292 pr_err("Failed to create HDCP workqueue\n");
293 goto error;
294 }
295
296 res = platform_get_resource_byname(dp->pdev,
297 IORESOURCE_MEM, "dp_ctrl");
298 if (!res) {
299 pr_err("Error getting dp ctrl resource\n");
300 rc = -EINVAL;
301 goto error;
302 }
303
304 hdcp_init_data.phy_addr = res->start;
305 hdcp_init_data.client_id = HDCP_CLIENT_DP;
306 hdcp_init_data.drm_aux = dp->aux->drm_aux;
307 hdcp_init_data.cb_data = (void *)dp;
308 hdcp_init_data.workq = dp->hdcp_workqueue;
309 hdcp_init_data.mutex = &dp->hdcp_mutex;
310 hdcp_init_data.sec_access = true;
311 hdcp_init_data.notify_status = dp_display_notify_hdcp_status_cb;
312 hdcp_init_data.core_io = &dp->parser->io.ctrl_io;
313 hdcp_init_data.qfprom_io = &dp->parser->io.qfprom_io;
314 hdcp_init_data.hdcp_io = &dp->parser->io.hdcp_io;
315 hdcp_init_data.revision = &dp->panel->link_info.revision;
316
Tatenda Chipeperekwab8cbd132017-07-07 17:43:29 -0700317 dp->hdcp.hdcp1 = sde_hdcp_1x_init(&hdcp_init_data);
318 if (IS_ERR_OR_NULL(dp->hdcp.hdcp1)) {
319 pr_err("Error initializing HDCP 1.x\n");
320 rc = -EINVAL;
321 goto error;
322 }
323
324 pr_debug("HDCP 1.3 initialized\n");
325
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700326 dp->hdcp.hdcp2 = sde_dp_hdcp2p2_init(&hdcp_init_data);
327 if (!IS_ERR_OR_NULL(dp->hdcp.hdcp2))
Tatenda Chipeperekwab8cbd132017-07-07 17:43:29 -0700328 pr_debug("HDCP 2.2 initialized\n");
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700329
330 dp->hdcp.feature_enabled = true;
331
332 return 0;
333error:
334 dp_display_deinitialize_hdcp(dp);
335 return rc;
336}
337
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700338static int dp_display_bind(struct device *dev, struct device *master,
339 void *data)
340{
341 int rc = 0;
342 struct dp_display_private *dp;
343 struct drm_device *drm;
Padmanabhan Komanduru4152f392017-05-11 17:53:55 -0700344 struct msm_drm_private *priv;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700345 struct platform_device *pdev = to_platform_device(dev);
346
347 if (!dev || !pdev || !master) {
348 pr_err("invalid param(s), dev %pK, pdev %pK, master %pK\n",
349 dev, pdev, master);
350 rc = -EINVAL;
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700351 goto end;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700352 }
353
354 drm = dev_get_drvdata(master);
355 dp = platform_get_drvdata(pdev);
356 if (!drm || !dp) {
357 pr_err("invalid param(s), drm %pK, dp %pK\n",
358 drm, dp);
359 rc = -EINVAL;
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700360 goto end;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700361 }
362
363 dp->dp_display.drm_dev = drm;
Padmanabhan Komanduru4152f392017-05-11 17:53:55 -0700364 priv = drm->dev_private;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700365
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700366 rc = dp->parser->parse(dp->parser);
367 if (rc) {
368 pr_err("device tree parsing failed\n");
369 goto end;
370 }
Padmanabhan Komanduru4152f392017-05-11 17:53:55 -0700371
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700372 rc = dp->aux->drm_aux_register(dp->aux);
373 if (rc) {
374 pr_err("DRM DP AUX register failed\n");
375 goto end;
376 }
377
Padmanabhan Komanduru4152f392017-05-11 17:53:55 -0700378 rc = dp->power->power_client_init(dp->power, &priv->phandle);
379 if (rc) {
380 pr_err("Power client create failed\n");
381 goto end;
382 }
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700383
384 rc = dp_display_initialize_hdcp(dp);
385 if (rc) {
386 pr_err("HDCP initialization failed\n");
387 goto end;
388 }
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700389end:
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700390 return rc;
391}
392
393static void dp_display_unbind(struct device *dev, struct device *master,
394 void *data)
395{
396 struct dp_display_private *dp;
397 struct platform_device *pdev = to_platform_device(dev);
398
399 if (!dev || !pdev) {
400 pr_err("invalid param(s)\n");
401 return;
402 }
403
404 dp = platform_get_drvdata(pdev);
405 if (!dp) {
406 pr_err("Invalid params\n");
407 return;
408 }
409
Padmanabhan Komanduru4152f392017-05-11 17:53:55 -0700410 (void)dp->power->power_client_deinit(dp->power);
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700411 (void)dp->aux->drm_aux_deregister(dp->aux);
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700412 dp_display_deinitialize_hdcp(dp);
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700413}
414
415static const struct component_ops dp_display_comp_ops = {
416 .bind = dp_display_bind,
417 .unbind = dp_display_unbind,
418};
419
Padmanabhan Komanduru58717282017-08-28 17:01:49 +0530420static bool dp_display_is_ds_bridge(struct dp_panel *panel)
421{
422 return (panel->dpcd[DP_DOWNSTREAMPORT_PRESENT] &
423 DP_DWN_STRM_PORT_PRESENT);
424}
425
426static bool dp_display_is_sink_count_zero(struct dp_display_private *dp)
427{
428 return dp_display_is_ds_bridge(dp->panel) &&
429 (dp->link->sink_count.count == 0);
430}
431
Padmanabhan Komanduru71aec2d2017-08-30 20:07:59 +0530432static void dp_display_send_hpd_event(struct dp_display *dp_display)
433{
434 struct drm_device *dev = NULL;
435 struct dp_display_private *dp;
436 struct drm_connector *connector;
437 char name[HPD_STRING_SIZE], status[HPD_STRING_SIZE],
438 bpp[HPD_STRING_SIZE], pattern[HPD_STRING_SIZE];
439 char *envp[5];
440
441 if (!dp_display) {
442 pr_err("invalid input\n");
443 return;
444 }
445
446 dp = container_of(dp_display, struct dp_display_private, dp_display);
447 if (!dp) {
448 pr_err("invalid params\n");
449 return;
450 }
451 connector = dp->dp_display.connector;
452 dev = dp_display->connector->dev;
453
454 connector->status = connector->funcs->detect(connector, false);
455 pr_debug("[%s] status updated to %s\n",
456 connector->name,
457 drm_get_connector_status_name(connector->status));
458 snprintf(name, HPD_STRING_SIZE, "name=%s", connector->name);
459 snprintf(status, HPD_STRING_SIZE, "status=%s",
460 drm_get_connector_status_name(connector->status));
461 snprintf(bpp, HPD_STRING_SIZE, "bpp=%d",
462 dp_link_bit_depth_to_bpp(
463 dp->link->test_video.test_bit_depth));
464 snprintf(pattern, HPD_STRING_SIZE, "pattern=%d",
465 dp->link->test_video.test_video_pattern);
466
467 pr_debug("generating hotplug event [%s]:[%s] [%s] [%s]\n",
468 name, status, bpp, pattern);
469 envp[0] = name;
470 envp[1] = status;
471 envp[2] = bpp;
472 envp[3] = pattern;
473 envp[4] = NULL;
474 kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE,
475 envp);
476}
477
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530478static int dp_display_send_hpd_notification(struct dp_display_private *dp,
479 bool hpd)
480{
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530481 if ((hpd && dp->dp_display.is_connected) ||
482 (!hpd && !dp->dp_display.is_connected)) {
483 pr_info("HPD already %s\n", (hpd ? "on" : "off"));
484 return 0;
485 }
486
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +0530487 /* reset video pattern flag on disconnect */
488 if (!hpd)
489 dp->panel->video_test = false;
490
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530491 dp->dp_display.is_connected = hpd;
492 reinit_completion(&dp->notification_comp);
Padmanabhan Komanduru71aec2d2017-08-30 20:07:59 +0530493 dp_display_send_hpd_event(&dp->dp_display);
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530494
Tatenda Chipeperekwaa4172f92017-09-21 15:25:57 -0700495 if (!wait_for_completion_timeout(&dp->notification_comp, HZ * 5)) {
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -0700496 pr_warn("%s timeout\n", hpd ? "connect" : "disconnect");
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -0700497 /* cancel any pending request */
498 dp->ctrl->abort(dp->ctrl);
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530499 return -EINVAL;
500 }
501
502 return 0;
503}
504
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700505static int dp_display_process_hpd_high(struct dp_display_private *dp)
506{
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700507 int rc = 0;
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -0700508 struct edid *edid;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700509
Tatenda Chipeperekwa344498e2017-09-06 12:34:36 -0700510 dp->aux->init(dp->aux, dp->parser->aux_cfg);
511
Padmanabhan Komandurub6f7c6f2017-09-05 18:50:30 +0530512 if (dp->link->psm_enabled)
513 goto notify;
514
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530515 rc = dp->panel->read_sink_caps(dp->panel, dp->dp_display.connector);
Padmanabhan Komanduru58717282017-08-28 17:01:49 +0530516 if (rc)
Padmanabhan Komanduruef656fa2017-09-19 20:33:27 +0530517 goto notify;
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530518
519 dp->link->process_request(dp->link);
Padmanabhan Komanduru58717282017-08-28 17:01:49 +0530520
521 if (dp_display_is_sink_count_zero(dp)) {
522 pr_debug("no downstream devices connected\n");
523 rc = -EINVAL;
524 goto end;
525 }
526
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -0700527 edid = dp->panel->edid_ctrl->edid;
528
529 dp->audio_supported = drm_detect_monitor_audio(edid);
530
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;
544
545 if (dp->core_initialized) {
546 pr_debug("DP core already initialized\n");
547 return;
548 }
549
550 if (dp->usbpd->orientation == ORIENTATION_CC2)
551 flip = true;
552
553 dp->power->init(dp->power, flip);
554 dp->ctrl->init(dp->ctrl, flip);
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700555 enable_irq(dp->irq);
556 dp->core_initialized = true;
557}
558
559static void dp_display_host_deinit(struct dp_display_private *dp)
560{
561 if (!dp->core_initialized) {
562 pr_debug("DP core already off\n");
563 return;
564 }
565
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700566 dp->ctrl->deinit(dp->ctrl);
567 dp->power->deinit(dp->power);
568 disable_irq(dp->irq);
569 dp->core_initialized = false;
570}
571
572static void dp_display_process_hpd_low(struct dp_display_private *dp)
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700573{
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700574 /* cancel any pending request */
575 dp->ctrl->abort(dp->ctrl);
576
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700577 if (dp_display_is_hdcp_enabled(dp) && dp->hdcp.ops->off) {
578 cancel_delayed_work_sync(&dp->hdcp_cb_work);
579 dp->hdcp.ops->off(dp->hdcp.data);
580 }
581
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -0700582 if (dp->audio_supported)
583 dp->audio->off(dp->audio);
584
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530585 dp_display_send_hpd_notification(dp, false);
Tatenda Chipeperekwa344498e2017-09-06 12:34:36 -0700586
587 dp->aux->deinit(dp->aux);
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700588}
589
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700590static int dp_display_usbpd_configure_cb(struct device *dev)
591{
592 int rc = 0;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700593 struct dp_display_private *dp;
594
595 if (!dev) {
596 pr_err("invalid dev\n");
597 rc = -EINVAL;
598 goto end;
599 }
600
601 dp = dev_get_drvdata(dev);
602 if (!dp) {
603 pr_err("no driver data found\n");
604 rc = -ENODEV;
605 goto end;
606 }
607
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700608 dp_display_host_init(dp);
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700609
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700610 if (dp->usbpd->hpd_high)
611 dp_display_process_hpd_high(dp);
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700612end:
613 return rc;
614}
615
Ajay Singh Parmarbf9531c2017-08-11 19:02:02 -0700616static void dp_display_clean(struct dp_display_private *dp)
617{
618 if (dp_display_is_hdcp_enabled(dp)) {
619 dp->hdcp_status = HDCP_STATE_INACTIVE;
620
621 cancel_delayed_work_sync(&dp->hdcp_cb_work);
622 if (dp->hdcp.ops->off)
623 dp->hdcp.ops->off(dp->hdcp.data);
624 }
625
626 dp->ctrl->push_idle(dp->ctrl);
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530627 dp->ctrl->off(dp->ctrl);
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -0700628 dp->power_on = false;
Ajay Singh Parmarbf9531c2017-08-11 19:02:02 -0700629}
630
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700631static int dp_display_usbpd_disconnect_cb(struct device *dev)
632{
633 int rc = 0;
634 struct dp_display_private *dp;
635
636 if (!dev) {
637 pr_err("invalid dev\n");
638 rc = -EINVAL;
639 goto end;
640 }
641
642 dp = dev_get_drvdata(dev);
643 if (!dp) {
644 pr_err("no driver data found\n");
645 rc = -ENODEV;
646 goto end;
647 }
648
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700649 /* cancel any pending request */
650 dp->ctrl->abort(dp->ctrl);
651
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -0700652 if (dp->audio_supported)
653 dp->audio->off(dp->audio);
654
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530655 rc = dp_display_send_hpd_notification(dp, false);
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700656
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -0700657 mutex_lock(&dp->session_lock);
658
Padmanabhan Komandurub6f7c6f2017-09-05 18:50:30 +0530659 /* if cable is disconnected, reset psm_enabled flag */
660 if (!dp->usbpd->alt_mode_cfg_done)
661 dp->link->psm_enabled = false;
662
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530663 if ((rc < 0) && dp->power_on)
664 dp_display_clean(dp);
Ajay Singh Parmarbf9531c2017-08-11 19:02:02 -0700665
666 dp_display_host_deinit(dp);
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -0700667
668 mutex_unlock(&dp->session_lock);
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700669end:
670 return rc;
671}
672
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +0530673static void dp_display_handle_video_request(struct dp_display_private *dp)
674{
675 if (dp->link->sink_request & DP_TEST_LINK_VIDEO_PATTERN) {
676 /* force disconnect followed by connect */
677 dp->usbpd->connect(dp->usbpd, false);
678 dp->panel->video_test = true;
679 dp->usbpd->connect(dp->usbpd, true);
680 dp->link->send_test_response(dp->link);
681 }
682}
683
Padmanabhan Komanduru58717282017-08-28 17:01:49 +0530684static int dp_display_handle_hpd_irq(struct dp_display_private *dp)
685{
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530686 if (dp->link->sink_request & DS_PORT_STATUS_CHANGED) {
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530687 dp_display_send_hpd_notification(dp, false);
Padmanabhan Komanduru58717282017-08-28 17:01:49 +0530688
689 if (dp_display_is_sink_count_zero(dp)) {
690 pr_debug("sink count is zero, nothing to do\n");
691 return 0;
692 }
693
694 return dp_display_process_hpd_high(dp);
695 }
696
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -0700697 dp->ctrl->handle_sink_request(dp->ctrl);
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530698
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +0530699 dp_display_handle_video_request(dp);
700
Padmanabhan Komanduru58717282017-08-28 17:01:49 +0530701 return 0;
702}
703
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700704static int dp_display_usbpd_attention_cb(struct device *dev)
705{
706 int rc = 0;
707 struct dp_display_private *dp;
708
709 if (!dev) {
710 pr_err("invalid dev\n");
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700711 return -EINVAL;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700712 }
713
714 dp = dev_get_drvdata(dev);
715 if (!dp) {
716 pr_err("no driver data found\n");
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700717 return -ENODEV;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700718 }
719
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700720 if (dp->usbpd->hpd_irq) {
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700721 dp->hpd_irq_on = true;
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700722
723 if (dp_display_is_hdcp_enabled(dp) && dp->hdcp.ops->cp_irq) {
724 if (!dp->hdcp.ops->cp_irq(dp->hdcp.data))
725 goto end;
726 }
727
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700728 rc = dp->link->process_request(dp->link);
Padmanabhan Komanduru58717282017-08-28 17:01:49 +0530729 /* check for any test request issued by sink */
Tatenda Chipeperekwa9c4ed4a2017-08-22 18:43:15 -0700730 if (!rc)
Padmanabhan Komanduru58717282017-08-28 17:01:49 +0530731 dp_display_handle_hpd_irq(dp);
Tatenda Chipeperekwa9c4ed4a2017-08-22 18:43:15 -0700732
Padmanabhan Komanduru58717282017-08-28 17:01:49 +0530733 dp->hpd_irq_on = false;
Tatenda Chipeperekwa9c4ed4a2017-08-22 18:43:15 -0700734 goto end;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700735 }
736
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700737 if (!dp->usbpd->hpd_high) {
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700738 dp_display_process_hpd_low(dp);
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700739 goto end;
740 }
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700741
Ajay Singh Parmarbf9531c2017-08-11 19:02:02 -0700742 if (dp->usbpd->alt_mode_cfg_done)
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700743 dp_display_process_hpd_high(dp);
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700744end:
745 return rc;
746}
747
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700748static void dp_display_deinit_sub_modules(struct dp_display_private *dp)
749{
750 dp_audio_put(dp->audio);
751 dp_ctrl_put(dp->ctrl);
752 dp_link_put(dp->link);
753 dp_panel_put(dp->panel);
754 dp_aux_put(dp->aux);
755 dp_power_put(dp->power);
756 dp_catalog_put(dp->catalog);
757 dp_parser_put(dp->parser);
758 dp_usbpd_put(dp->usbpd);
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -0700759 mutex_destroy(&dp->session_lock);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700760 dp_debug_put(dp->debug);
761}
762
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700763static int dp_init_sub_modules(struct dp_display_private *dp)
764{
765 int rc = 0;
766 struct device *dev = &dp->pdev->dev;
767 struct dp_usbpd_cb *cb = &dp->usbpd_cb;
768 struct dp_ctrl_in ctrl_in = {
769 .dev = dev,
770 };
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +0530771 struct dp_panel_in panel_in = {
772 .dev = dev,
773 };
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700774
775 cb->configure = dp_display_usbpd_configure_cb;
776 cb->disconnect = dp_display_usbpd_disconnect_cb;
777 cb->attention = dp_display_usbpd_attention_cb;
778
779 dp->usbpd = dp_usbpd_get(dev, cb);
780 if (IS_ERR(dp->usbpd)) {
781 rc = PTR_ERR(dp->usbpd);
782 pr_err("failed to initialize usbpd, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700783 dp->usbpd = NULL;
784 goto error;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700785 }
786
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -0700787 mutex_init(&dp->session_lock);
788
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700789 dp->parser = dp_parser_get(dp->pdev);
790 if (IS_ERR(dp->parser)) {
791 rc = PTR_ERR(dp->parser);
792 pr_err("failed to initialize parser, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700793 dp->parser = NULL;
794 goto error_parser;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700795 }
796
797 dp->catalog = dp_catalog_get(dev, &dp->parser->io);
798 if (IS_ERR(dp->catalog)) {
799 rc = PTR_ERR(dp->catalog);
800 pr_err("failed to initialize catalog, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700801 dp->catalog = NULL;
802 goto error_catalog;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700803 }
804
805 dp->power = dp_power_get(dp->parser);
806 if (IS_ERR(dp->power)) {
807 rc = PTR_ERR(dp->power);
808 pr_err("failed to initialize power, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700809 dp->power = NULL;
810 goto error_power;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700811 }
812
Padmanabhan Komanduru2e9914b2017-08-04 20:51:31 +0530813 dp->aux = dp_aux_get(dev, &dp->catalog->aux, dp->parser->aux_cfg);
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700814 if (IS_ERR(dp->aux)) {
815 rc = PTR_ERR(dp->aux);
816 pr_err("failed to initialize aux, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700817 dp->aux = NULL;
818 goto error_aux;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700819 }
820
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700821 dp->link = dp_link_get(dev, dp->aux);
822 if (IS_ERR(dp->link)) {
823 rc = PTR_ERR(dp->link);
824 pr_err("failed to initialize link, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700825 dp->link = NULL;
826 goto error_link;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700827 }
828
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +0530829 panel_in.aux = dp->aux;
830 panel_in.catalog = &dp->catalog->panel;
831 panel_in.link = dp->link;
832
833 dp->panel = dp_panel_get(&panel_in);
834 if (IS_ERR(dp->panel)) {
835 rc = PTR_ERR(dp->panel);
836 pr_err("failed to initialize panel, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700837 dp->panel = NULL;
838 goto error_panel;
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +0530839 }
840
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700841 ctrl_in.link = dp->link;
842 ctrl_in.panel = dp->panel;
843 ctrl_in.aux = dp->aux;
844 ctrl_in.power = dp->power;
845 ctrl_in.catalog = &dp->catalog->ctrl;
846 ctrl_in.parser = dp->parser;
847
848 dp->ctrl = dp_ctrl_get(&ctrl_in);
849 if (IS_ERR(dp->ctrl)) {
850 rc = PTR_ERR(dp->ctrl);
851 pr_err("failed to initialize ctrl, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700852 dp->ctrl = NULL;
853 goto error_ctrl;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700854 }
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -0700855
856 dp->audio = dp_audio_get(dp->pdev, dp->panel, &dp->catalog->audio);
857 if (IS_ERR(dp->audio)) {
858 rc = PTR_ERR(dp->audio);
859 pr_err("failed to initialize audio, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700860 dp->audio = NULL;
861 goto error_audio;
Samantha Tran2d1ed732017-07-31 17:30:14 -0700862 }
863
864 dp->debug = dp_debug_get(dev, dp->panel, dp->usbpd,
865 dp->link, &dp->dp_display.connector);
866 if (IS_ERR(dp->debug)) {
867 rc = PTR_ERR(dp->debug);
868 pr_err("failed to initialize debug, rc = %d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700869 dp->debug = NULL;
870 goto error_debug;
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -0700871 }
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700872
873 return rc;
874error_debug:
875 dp_audio_put(dp->audio);
876error_audio:
877 dp_ctrl_put(dp->ctrl);
878error_ctrl:
879 dp_panel_put(dp->panel);
880error_panel:
881 dp_link_put(dp->link);
882error_link:
883 dp_aux_put(dp->aux);
884error_aux:
885 dp_power_put(dp->power);
886error_power:
887 dp_catalog_put(dp->catalog);
888error_catalog:
889 dp_parser_put(dp->parser);
890error_parser:
891 dp_usbpd_put(dp->usbpd);
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -0700892 mutex_destroy(&dp->session_lock);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700893error:
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700894 return rc;
895}
896
897static int dp_display_set_mode(struct dp_display *dp_display,
898 struct dp_display_mode *mode)
899{
Tatenda Chipeperekwa8a44bd92017-10-05 16:32:06 -0700900 const u32 num_components = 3, default_bpp = 24;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700901 struct dp_display_private *dp;
902
903 if (!dp_display) {
904 pr_err("invalid input\n");
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -0700905 return -EINVAL;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700906 }
907 dp = container_of(dp_display, struct dp_display_private, dp_display);
908
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -0700909 mutex_lock(&dp->session_lock);
Tatenda Chipeperekwa8a44bd92017-10-05 16:32:06 -0700910 mode->timing.bpp =
911 dp_display->connector->display_info.bpc * num_components;
912 if (!mode->timing.bpp)
913 mode->timing.bpp = default_bpp;
914
915 mode->timing.bpp = dp->panel->get_mode_bpp(dp->panel,
916 mode->timing.bpp, mode->timing.pixel_clk_khz);
917
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700918 dp->panel->pinfo = mode->timing;
Ajay Singh Parmarfae11672017-09-01 19:49:30 -0700919 dp->panel->init(dp->panel);
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -0700920 mutex_unlock(&dp->session_lock);
921
922 return 0;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700923}
924
925static int dp_display_prepare(struct dp_display *dp)
926{
927 return 0;
928}
929
930static int dp_display_enable(struct dp_display *dp_display)
931{
932 int rc = 0;
933 struct dp_display_private *dp;
934
935 if (!dp_display) {
936 pr_err("invalid input\n");
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -0700937 return -EINVAL;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700938 }
939
940 dp = container_of(dp_display, struct dp_display_private, dp_display);
941
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -0700942 mutex_lock(&dp->session_lock);
943
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530944 if (dp->power_on) {
945 pr_debug("Link already setup, return\n");
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -0700946 goto end;
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +0530947 }
948
949 rc = dp->ctrl->on(dp->ctrl);
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -0700950 if (!rc)
951 dp->power_on = true;
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -0700952end:
953 mutex_unlock(&dp->session_lock);
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700954 return rc;
955}
956
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700957static int dp_display_post_enable(struct dp_display *dp_display)
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700958{
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700959 struct dp_display_private *dp;
960
961 if (!dp_display) {
962 pr_err("invalid input\n");
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -0700963 return -EINVAL;
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700964 }
965
966 dp = container_of(dp_display, struct dp_display_private, dp_display);
967
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -0700968 mutex_lock(&dp->session_lock);
969
970 if (!dp->power_on) {
971 pr_debug("Link not setup, return\n");
972 goto end;
973 }
974
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -0700975 if (dp->audio_supported) {
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530976 dp->audio->bw_code = dp->link->link_params.bw_code;
977 dp->audio->lane_count = dp->link->link_params.lane_count;
Ajay Singh Parmar3dc92a22017-08-05 00:09:35 -0700978 dp->audio->on(dp->audio);
979 }
980
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700981 complete_all(&dp->notification_comp);
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700982
983 dp_display_update_hdcp_info(dp);
984
985 if (dp_display_is_hdcp_enabled(dp)) {
986 cancel_delayed_work_sync(&dp->hdcp_cb_work);
987
988 dp->hdcp_status = HDCP_STATE_AUTHENTICATING;
989 queue_delayed_work(dp->hdcp_workqueue,
990 &dp->hdcp_cb_work, HZ / 2);
991 }
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -0700992
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700993end:
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -0700994 mutex_unlock(&dp->session_lock);
995 return 0;
Ajay Singh Parmar77668872017-03-28 21:36:15 -0700996}
997
998static int dp_display_pre_disable(struct dp_display *dp_display)
999{
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001000 struct dp_display_private *dp;
1001
1002 if (!dp_display) {
1003 pr_err("invalid input\n");
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001004 return -EINVAL;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001005 }
1006
1007 dp = container_of(dp_display, struct dp_display_private, dp_display);
1008
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001009 mutex_lock(&dp->session_lock);
1010
1011 if (!dp->power_on) {
1012 pr_debug("Link already powered off, return\n");
1013 goto end;
1014 }
1015
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -07001016 if (dp_display_is_hdcp_enabled(dp)) {
1017 dp->hdcp_status = HDCP_STATE_INACTIVE;
1018
1019 cancel_delayed_work_sync(&dp->hdcp_cb_work);
1020 if (dp->hdcp.ops->off)
1021 dp->hdcp.ops->off(dp->hdcp.data);
1022 }
1023
Padmanabhan Komandurub6f7c6f2017-09-05 18:50:30 +05301024 if (dp->usbpd->alt_mode_cfg_done && (dp->usbpd->hpd_high ||
1025 dp->usbpd->forced_disconnect))
1026 dp->link->psm_config(dp->link, &dp->panel->link_info, true);
1027
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -07001028 dp->ctrl->push_idle(dp->ctrl);
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001029
1030end:
1031 mutex_unlock(&dp->session_lock);
1032 return 0;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001033}
1034
1035static int dp_display_disable(struct dp_display *dp_display)
1036{
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001037 struct dp_display_private *dp;
1038
1039 if (!dp_display) {
1040 pr_err("invalid input\n");
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001041 return -EINVAL;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001042 }
1043
1044 dp = container_of(dp_display, struct dp_display_private, dp_display);
1045
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001046 mutex_lock(&dp->session_lock);
1047
1048 if (!dp->power_on || !dp->core_initialized) {
1049 pr_debug("Link already powered off, return\n");
1050 goto end;
1051 }
Ajay Singh Parmarbf9531c2017-08-11 19:02:02 -07001052
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301053 dp->ctrl->off(dp->ctrl);
Ajay Singh Parmarfae11672017-09-01 19:49:30 -07001054 dp->panel->deinit(dp->panel);
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -07001055
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -07001056 dp->power_on = false;
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -07001057
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001058end:
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -07001059 complete_all(&dp->notification_comp);
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -07001060 mutex_unlock(&dp->session_lock);
1061 return 0;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001062}
1063
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -07001064static int dp_request_irq(struct dp_display *dp_display)
1065{
1066 int rc = 0;
1067 struct dp_display_private *dp;
1068
1069 if (!dp_display) {
1070 pr_err("invalid input\n");
1071 return -EINVAL;
1072 }
1073
1074 dp = container_of(dp_display, struct dp_display_private, dp_display);
1075
1076 dp->irq = irq_of_parse_and_map(dp->pdev->dev.of_node, 0);
1077 if (dp->irq < 0) {
1078 rc = dp->irq;
1079 pr_err("failed to get irq: %d\n", rc);
1080 return rc;
1081 }
1082
1083 rc = devm_request_irq(&dp->pdev->dev, dp->irq, dp_display_irq,
1084 IRQF_TRIGGER_HIGH, "dp_display_isr", dp);
1085 if (rc < 0) {
1086 pr_err("failed to request IRQ%u: %d\n",
1087 dp->irq, rc);
1088 return rc;
1089 }
1090 disable_irq(dp->irq);
1091
1092 return 0;
1093}
1094
Samantha Tran2d1ed732017-07-31 17:30:14 -07001095static struct dp_debug *dp_get_debug(struct dp_display *dp_display)
1096{
1097 struct dp_display_private *dp;
1098
1099 if (!dp_display) {
1100 pr_err("invalid input\n");
1101 return ERR_PTR(-EINVAL);
1102 }
1103
1104 dp = container_of(dp_display, struct dp_display_private, dp_display);
1105
1106 return dp->debug;
1107}
1108
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001109static int dp_display_unprepare(struct dp_display *dp)
1110{
1111 return 0;
1112}
1113
Tatenda Chipeperekwa8a44bd92017-10-05 16:32:06 -07001114static int dp_display_validate_mode(struct dp_display *dp, u32 mode_pclk_khz)
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001115{
Tatenda Chipeperekwa8a44bd92017-10-05 16:32:06 -07001116 const u32 num_components = 3, default_bpp = 24;
1117 struct dp_display_private *dp_display;
1118 struct drm_dp_link *link_info;
1119 u32 mode_rate_khz = 0, supported_rate_khz = 0, mode_bpp = 0;
1120
1121 if (!dp || !mode_pclk_khz) {
1122 pr_err("invalid params\n");
1123 return -EINVAL;
1124 }
1125
1126 dp_display = container_of(dp, struct dp_display_private, dp_display);
1127 link_info = &dp_display->panel->link_info;
1128
1129 mode_bpp = dp->connector->display_info.bpc * num_components;
1130 if (!mode_bpp)
1131 mode_bpp = default_bpp;
1132
1133 mode_bpp = dp_display->panel->get_mode_bpp(dp_display->panel,
1134 mode_bpp, mode_pclk_khz);
1135
1136 mode_rate_khz = mode_pclk_khz * mode_bpp;
1137 supported_rate_khz = link_info->num_lanes * link_info->rate * 8;
1138
1139 if (mode_rate_khz > supported_rate_khz)
1140 return MODE_BAD;
1141
1142 return MODE_OK;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001143}
1144
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +05301145static int dp_display_get_modes(struct dp_display *dp,
1146 struct dp_display_mode *dp_mode)
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001147{
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -07001148 struct dp_display_private *dp_display;
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +05301149 int ret = 0;
1150
1151 if (!dp) {
1152 pr_err("invalid params\n");
1153 return 0;
1154 }
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001155
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -07001156 dp_display = container_of(dp, struct dp_display_private, dp_display);
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001157
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +05301158 ret = dp_display->panel->get_modes(dp_display->panel,
1159 dp->connector, dp_mode);
1160 if (dp_mode->timing.pixel_clk_khz)
1161 dp->max_pclk_khz = dp_mode->timing.pixel_clk_khz;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -07001162 return ret;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001163}
1164
1165static int dp_display_probe(struct platform_device *pdev)
1166{
1167 int rc = 0;
1168 struct dp_display_private *dp;
1169
1170 if (!pdev || !pdev->dev.of_node) {
1171 pr_err("pdev not found\n");
1172 return -ENODEV;
1173 }
1174
1175 dp = devm_kzalloc(&pdev->dev, sizeof(*dp), GFP_KERNEL);
1176 if (!dp)
1177 return -ENOMEM;
1178
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -07001179 init_completion(&dp->notification_comp);
1180
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001181 dp->pdev = pdev;
1182 dp->name = "drm_dp";
1183
1184 rc = dp_init_sub_modules(dp);
1185 if (rc) {
1186 devm_kfree(&pdev->dev, dp);
1187 return -EPROBE_DEFER;
1188 }
1189
1190 platform_set_drvdata(pdev, dp);
1191
1192 g_dp_display = &dp->dp_display;
1193
1194 g_dp_display->enable = dp_display_enable;
1195 g_dp_display->post_enable = dp_display_post_enable;
1196 g_dp_display->pre_disable = dp_display_pre_disable;
1197 g_dp_display->disable = dp_display_disable;
1198 g_dp_display->set_mode = dp_display_set_mode;
1199 g_dp_display->validate_mode = dp_display_validate_mode;
1200 g_dp_display->get_modes = dp_display_get_modes;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001201 g_dp_display->prepare = dp_display_prepare;
1202 g_dp_display->unprepare = dp_display_unprepare;
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -07001203 g_dp_display->request_irq = dp_request_irq;
Samantha Tran2d1ed732017-07-31 17:30:14 -07001204 g_dp_display->get_debug = dp_get_debug;
Padmanabhan Komanduru71aec2d2017-08-30 20:07:59 +05301205 g_dp_display->send_hpd_event = dp_display_send_hpd_event;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001206
1207 rc = component_add(&pdev->dev, &dp_display_comp_ops);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -07001208 if (rc) {
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001209 pr_err("component add failed, rc=%d\n", rc);
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -07001210 dp_display_deinit_sub_modules(dp);
1211 devm_kfree(&pdev->dev, dp);
1212 }
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001213
1214 return rc;
1215}
1216
Padmanabhan Komanduru63758612017-05-23 01:47:18 -07001217int dp_display_get_displays(void **displays, int count)
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001218{
Padmanabhan Komanduru63758612017-05-23 01:47:18 -07001219 if (!displays) {
1220 pr_err("invalid data\n");
1221 return -EINVAL;
1222 }
1223
1224 if (count != 1) {
1225 pr_err("invalid number of displays\n");
1226 return -EINVAL;
1227 }
1228
1229 displays[0] = g_dp_display;
1230 return count;
1231}
1232
1233int dp_display_get_num_of_displays(void)
1234{
1235 return 1;
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001236}
1237
Ajay Singh Parmar77668872017-03-28 21:36:15 -07001238static int dp_display_remove(struct platform_device *pdev)
1239{
1240 struct dp_display_private *dp;
1241
1242 if (!pdev)
1243 return -EINVAL;
1244
1245 dp = platform_get_drvdata(pdev);
1246
1247 dp_display_deinit_sub_modules(dp);
1248
1249 platform_set_drvdata(pdev, NULL);
1250 devm_kfree(&pdev->dev, dp);
1251
1252 return 0;
1253}
1254
1255static struct platform_driver dp_display_driver = {
1256 .probe = dp_display_probe,
1257 .remove = dp_display_remove,
1258 .driver = {
1259 .name = "msm-dp-display",
1260 .of_match_table = dp_dt_match,
1261 },
1262};
1263
1264static int __init dp_display_init(void)
1265{
1266 int ret;
1267
1268 ret = platform_driver_register(&dp_display_driver);
1269 if (ret) {
1270 pr_err("driver register failed");
1271 return ret;
1272 }
1273
1274 return ret;
1275}
1276module_init(dp_display_init);
1277
1278static void __exit dp_display_cleanup(void)
1279{
1280 platform_driver_unregister(&dp_display_driver);
1281}
1282module_exit(dp_display_cleanup);
1283