Commit | Line | Data |
---|---|---|
c943b494 CU |
1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* | |
3 | * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. | |
4 | */ | |
5 | ||
6 | #include <linux/module.h> | |
7 | #include <linux/slab.h> | |
8 | #include <linux/uaccess.h> | |
9 | #include <linux/debugfs.h> | |
10 | #include <linux/component.h> | |
11 | #include <linux/of_irq.h> | |
8ede2ecc | 12 | #include <linux/delay.h> |
c943b494 CU |
13 | |
14 | #include "msm_drv.h" | |
15 | #include "msm_kms.h" | |
16 | #include "dp_hpd.h" | |
17 | #include "dp_parser.h" | |
18 | #include "dp_power.h" | |
19 | #include "dp_catalog.h" | |
20 | #include "dp_aux.h" | |
220b856a | 21 | #include "dp_reg.h" |
c943b494 CU |
22 | #include "dp_link.h" |
23 | #include "dp_panel.h" | |
24 | #include "dp_ctrl.h" | |
25 | #include "dp_display.h" | |
26 | #include "dp_drm.h" | |
14975cff | 27 | #include "dp_pll.h" |
c943b494 CU |
28 | |
29 | static struct msm_dp *g_dp_display; | |
30 | #define HPD_STRING_SIZE 30 | |
31 | ||
8ede2ecc KH |
32 | enum { |
33 | ISR_DISCONNECTED, | |
34 | ISR_CONNECT_PENDING, | |
35 | ISR_CONNECTED, | |
36 | ISR_HPD_REPLUG_COUNT, | |
37 | ISR_IRQ_HPD_PULSE_COUNT, | |
38 | ISR_HPD_LO_GLITH_COUNT, | |
39 | }; | |
40 | ||
41 | /* event thread connection state */ | |
42 | enum { | |
43 | ST_DISCONNECTED, | |
44 | ST_CONNECT_PENDING, | |
45 | ST_CONNECTED, | |
46 | ST_DISCONNECT_PENDING, | |
47 | ST_SUSPEND_PENDING, | |
48 | ST_SUSPENDED, | |
49 | }; | |
50 | ||
51 | enum { | |
52 | EV_NO_EVENT, | |
53 | /* hpd events */ | |
54 | EV_HPD_INIT_SETUP, | |
55 | EV_HPD_PLUG_INT, | |
56 | EV_IRQ_HPD_INT, | |
57 | EV_HPD_REPLUG_INT, | |
58 | EV_HPD_UNPLUG_INT, | |
59 | EV_USER_NOTIFICATION, | |
60 | EV_CONNECT_PENDING_TIMEOUT, | |
61 | EV_DISCONNECT_PENDING_TIMEOUT, | |
62 | }; | |
63 | ||
64 | #define EVENT_TIMEOUT (HZ/10) /* 100ms */ | |
65 | #define DP_EVENT_Q_MAX 8 | |
66 | ||
67 | #define DP_TIMEOUT_5_SECOND (5000/EVENT_TIMEOUT) | |
68 | #define DP_TIMEOUT_NONE 0 | |
69 | ||
70 | #define WAIT_FOR_RESUME_TIMEOUT_JIFFIES (HZ / 2) | |
71 | ||
72 | struct dp_event { | |
73 | u32 event_id; | |
74 | u32 data; | |
75 | u32 delay; | |
76 | }; | |
77 | ||
c943b494 CU |
78 | struct dp_display_private { |
79 | char *name; | |
80 | int irq; | |
81 | ||
82 | /* state variables */ | |
83 | bool core_initialized; | |
84 | bool power_on; | |
85 | bool hpd_irq_on; | |
86 | bool audio_supported; | |
87 | ||
88 | struct platform_device *pdev; | |
89 | struct dentry *root; | |
c943b494 CU |
90 | |
91 | struct dp_usbpd *usbpd; | |
92 | struct dp_parser *parser; | |
14975cff | 93 | struct msm_dp_pll *pll; |
c943b494 CU |
94 | struct dp_power *power; |
95 | struct dp_catalog *catalog; | |
96 | struct drm_dp_aux *aux; | |
97 | struct dp_link *link; | |
98 | struct dp_panel *panel; | |
99 | struct dp_ctrl *ctrl; | |
8ede2ecc | 100 | struct dp_debug *debug; |
c943b494 CU |
101 | |
102 | struct dp_usbpd_cb usbpd_cb; | |
103 | struct dp_display_mode dp_mode; | |
104 | struct msm_dp dp_display; | |
220b856a | 105 | |
8ede2ecc KH |
106 | /* event related only access by event thread */ |
107 | struct mutex event_mutex; | |
108 | wait_queue_head_t event_q; | |
109 | atomic_t hpd_state; | |
110 | u32 event_pndx; | |
111 | u32 event_gndx; | |
112 | struct dp_event event_list[DP_EVENT_Q_MAX]; | |
113 | spinlock_t event_lock; | |
114 | ||
115 | struct completion resume_comp; | |
c943b494 CU |
116 | }; |
117 | ||
118 | static const struct of_device_id dp_dt_match[] = { | |
119 | {.compatible = "qcom,sc7180-dp"}, | |
120 | {} | |
121 | }; | |
122 | ||
8ede2ecc KH |
123 | static int dp_add_event(struct dp_display_private *dp_priv, u32 event, |
124 | u32 data, u32 delay) | |
c943b494 | 125 | { |
8ede2ecc KH |
126 | unsigned long flag; |
127 | struct dp_event *todo; | |
128 | int pndx; | |
129 | ||
130 | spin_lock_irqsave(&dp_priv->event_lock, flag); | |
131 | pndx = dp_priv->event_pndx + 1; | |
132 | pndx %= DP_EVENT_Q_MAX; | |
133 | if (pndx == dp_priv->event_gndx) { | |
134 | pr_err("event_q is full: pndx=%d gndx=%d\n", | |
135 | dp_priv->event_pndx, dp_priv->event_gndx); | |
136 | spin_unlock_irqrestore(&dp_priv->event_lock, flag); | |
137 | return -EPERM; | |
220b856a | 138 | } |
8ede2ecc KH |
139 | todo = &dp_priv->event_list[dp_priv->event_pndx++]; |
140 | dp_priv->event_pndx %= DP_EVENT_Q_MAX; | |
141 | todo->event_id = event; | |
142 | todo->data = data; | |
143 | todo->delay = delay; | |
144 | wake_up(&dp_priv->event_q); | |
145 | spin_unlock_irqrestore(&dp_priv->event_lock, flag); | |
c943b494 | 146 | |
8ede2ecc | 147 | return 0; |
220b856a TS |
148 | } |
149 | ||
8ede2ecc | 150 | static int dp_del_event(struct dp_display_private *dp_priv, u32 event) |
220b856a | 151 | { |
8ede2ecc KH |
152 | unsigned long flag; |
153 | struct dp_event *todo; | |
154 | u32 gndx; | |
155 | ||
156 | spin_lock_irqsave(&dp_priv->event_lock, flag); | |
157 | if (dp_priv->event_pndx == dp_priv->event_gndx) { | |
158 | spin_unlock_irqrestore(&dp_priv->event_lock, flag); | |
159 | return -ENOENT; | |
160 | } | |
220b856a | 161 | |
8ede2ecc KH |
162 | gndx = dp_priv->event_gndx; |
163 | while (dp_priv->event_pndx != gndx) { | |
164 | todo = &dp_priv->event_list[gndx]; | |
165 | if (todo->event_id == event) { | |
166 | todo->event_id = EV_NO_EVENT; /* deleted */ | |
167 | todo->delay = 0; | |
168 | } | |
169 | gndx++; | |
170 | gndx %= DP_EVENT_Q_MAX; | |
220b856a | 171 | } |
8ede2ecc | 172 | spin_unlock_irqrestore(&dp_priv->event_lock, flag); |
220b856a | 173 | |
8ede2ecc | 174 | return 0; |
c943b494 CU |
175 | } |
176 | ||
177 | static int dp_display_bind(struct device *dev, struct device *master, | |
178 | void *data) | |
179 | { | |
180 | int rc = 0; | |
181 | struct dp_display_private *dp; | |
182 | struct drm_device *drm; | |
183 | struct msm_drm_private *priv; | |
c943b494 CU |
184 | |
185 | drm = dev_get_drvdata(master); | |
186 | ||
061eb621 AK |
187 | dp = container_of(g_dp_display, |
188 | struct dp_display_private, dp_display); | |
c943b494 CU |
189 | if (!dp) { |
190 | DRM_ERROR("DP driver bind failed. Invalid driver data\n"); | |
191 | return -EINVAL; | |
192 | } | |
193 | ||
194 | dp->dp_display.drm_dev = drm; | |
195 | priv = drm->dev_private; | |
196 | priv->dp = &(dp->dp_display); | |
197 | ||
198 | rc = dp->parser->parse(dp->parser); | |
199 | if (rc) { | |
200 | DRM_ERROR("device tree parsing failed\n"); | |
201 | goto end; | |
202 | } | |
203 | ||
204 | rc = dp_aux_register(dp->aux); | |
205 | if (rc) { | |
206 | DRM_ERROR("DRM DP AUX register failed\n"); | |
207 | goto end; | |
208 | } | |
209 | ||
210 | rc = dp_power_client_init(dp->power); | |
211 | if (rc) { | |
212 | DRM_ERROR("Power client create failed\n"); | |
213 | goto end; | |
214 | } | |
c943b494 CU |
215 | end: |
216 | return rc; | |
217 | } | |
218 | ||
219 | static void dp_display_unbind(struct device *dev, struct device *master, | |
220 | void *data) | |
221 | { | |
222 | struct dp_display_private *dp; | |
c943b494 CU |
223 | struct drm_device *drm = dev_get_drvdata(master); |
224 | struct msm_drm_private *priv = drm->dev_private; | |
225 | ||
061eb621 AK |
226 | dp = container_of(g_dp_display, |
227 | struct dp_display_private, dp_display); | |
c943b494 CU |
228 | if (!dp) { |
229 | DRM_ERROR("Invalid DP driver data\n"); | |
230 | return; | |
231 | } | |
232 | ||
233 | dp_power_client_deinit(dp->power); | |
234 | dp_aux_unregister(dp->aux); | |
235 | priv->dp = NULL; | |
236 | } | |
237 | ||
238 | static const struct component_ops dp_display_comp_ops = { | |
239 | .bind = dp_display_bind, | |
240 | .unbind = dp_display_unbind, | |
241 | }; | |
242 | ||
243 | static bool dp_display_is_ds_bridge(struct dp_panel *panel) | |
244 | { | |
245 | return (panel->dpcd[DP_DOWNSTREAMPORT_PRESENT] & | |
246 | DP_DWN_STRM_PORT_PRESENT); | |
247 | } | |
248 | ||
249 | static bool dp_display_is_sink_count_zero(struct dp_display_private *dp) | |
250 | { | |
251 | return dp_display_is_ds_bridge(dp->panel) && | |
252 | (dp->link->sink_count == 0); | |
253 | } | |
254 | ||
255 | static void dp_display_send_hpd_event(struct msm_dp *dp_display) | |
256 | { | |
257 | struct dp_display_private *dp; | |
258 | struct drm_connector *connector; | |
259 | ||
260 | dp = container_of(dp_display, struct dp_display_private, dp_display); | |
261 | ||
262 | connector = dp->dp_display.connector; | |
263 | drm_helper_hpd_irq_event(connector->dev); | |
264 | } | |
265 | ||
266 | static int dp_display_send_hpd_notification(struct dp_display_private *dp, | |
267 | bool hpd) | |
268 | { | |
269 | static bool encoder_mode_set; | |
270 | struct msm_drm_private *priv = dp->dp_display.drm_dev->dev_private; | |
271 | struct msm_kms *kms = priv->kms; | |
272 | ||
c943b494 CU |
273 | if ((hpd && dp->dp_display.is_connected) || |
274 | (!hpd && !dp->dp_display.is_connected)) { | |
275 | DRM_DEBUG_DP("HPD already %s\n", (hpd ? "on" : "off")); | |
c943b494 CU |
276 | return 0; |
277 | } | |
278 | ||
279 | /* reset video pattern flag on disconnect */ | |
280 | if (!hpd) | |
281 | dp->panel->video_test = false; | |
282 | ||
283 | dp->dp_display.is_connected = hpd; | |
c943b494 CU |
284 | |
285 | if (dp->dp_display.is_connected && dp->dp_display.encoder | |
286 | && !encoder_mode_set | |
287 | && kms->funcs->set_encoder_mode) { | |
288 | kms->funcs->set_encoder_mode(kms, | |
289 | dp->dp_display.encoder, false); | |
290 | DRM_DEBUG_DP("set_encoder_mode() Completed\n"); | |
291 | encoder_mode_set = true; | |
292 | } | |
293 | ||
294 | dp_display_send_hpd_event(&dp->dp_display); | |
295 | ||
c943b494 CU |
296 | return 0; |
297 | } | |
298 | ||
299 | static int dp_display_process_hpd_high(struct dp_display_private *dp) | |
300 | { | |
301 | int rc = 0; | |
302 | struct edid *edid; | |
303 | ||
c943b494 CU |
304 | dp->panel->max_dp_lanes = dp->parser->max_dp_lanes; |
305 | ||
306 | rc = dp_panel_read_sink_caps(dp->panel, dp->dp_display.connector); | |
307 | if (rc) | |
8ede2ecc | 308 | goto end; |
c943b494 CU |
309 | |
310 | dp_link_process_request(dp->link); | |
311 | ||
c943b494 CU |
312 | edid = dp->panel->edid; |
313 | ||
314 | dp->audio_supported = drm_detect_monitor_audio(edid); | |
c943b494 CU |
315 | dp_panel_handle_sink_request(dp->panel); |
316 | ||
317 | dp->dp_display.max_pclk_khz = DP_MAX_PIXEL_CLK_KHZ; | |
318 | dp->dp_display.max_dp_lanes = dp->parser->max_dp_lanes; | |
8ede2ecc KH |
319 | |
320 | rc = dp_ctrl_on_link(dp->ctrl); | |
321 | if (rc) { | |
322 | DRM_ERROR("failed to complete DP link training\n"); | |
323 | goto end; | |
324 | } | |
325 | ||
326 | dp_add_event(dp, EV_USER_NOTIFICATION, true, 0); | |
327 | ||
c943b494 CU |
328 | |
329 | end: | |
330 | return rc; | |
331 | } | |
332 | ||
333 | static void dp_display_host_init(struct dp_display_private *dp) | |
334 | { | |
335 | bool flip = false; | |
336 | ||
337 | if (dp->core_initialized) { | |
338 | DRM_DEBUG_DP("DP core already initialized\n"); | |
339 | return; | |
340 | } | |
341 | ||
342 | if (dp->usbpd->orientation == ORIENTATION_CC2) | |
343 | flip = true; | |
344 | ||
345 | dp_power_init(dp->power, flip); | |
346 | dp_ctrl_host_init(dp->ctrl, flip); | |
347 | dp_aux_init(dp->aux); | |
348 | dp->core_initialized = true; | |
349 | } | |
350 | ||
c943b494 CU |
351 | static int dp_display_usbpd_configure_cb(struct device *dev) |
352 | { | |
353 | int rc = 0; | |
354 | struct dp_display_private *dp; | |
355 | ||
356 | if (!dev) { | |
357 | DRM_ERROR("invalid dev\n"); | |
358 | rc = -EINVAL; | |
359 | goto end; | |
360 | } | |
361 | ||
061eb621 AK |
362 | dp = container_of(g_dp_display, |
363 | struct dp_display_private, dp_display); | |
c943b494 CU |
364 | if (!dp) { |
365 | DRM_ERROR("no driver data found\n"); | |
366 | rc = -ENODEV; | |
367 | goto end; | |
368 | } | |
369 | ||
370 | dp_display_host_init(dp); | |
371 | ||
8ede2ecc KH |
372 | /* |
373 | * set sink to normal operation mode -- D0 | |
374 | * before dpcd read | |
375 | */ | |
376 | dp_link_psm_config(dp->link, &dp->panel->link_info, false); | |
377 | rc = dp_display_process_hpd_high(dp); | |
c943b494 CU |
378 | end: |
379 | return rc; | |
380 | } | |
381 | ||
c943b494 CU |
382 | static int dp_display_usbpd_disconnect_cb(struct device *dev) |
383 | { | |
384 | int rc = 0; | |
385 | struct dp_display_private *dp; | |
386 | ||
061eb621 AK |
387 | dp = container_of(g_dp_display, |
388 | struct dp_display_private, dp_display); | |
c943b494 | 389 | |
8ede2ecc | 390 | dp_add_event(dp, EV_USER_NOTIFICATION, false, 0); |
c943b494 | 391 | |
c943b494 CU |
392 | return rc; |
393 | } | |
394 | ||
395 | static void dp_display_handle_video_request(struct dp_display_private *dp) | |
396 | { | |
397 | if (dp->link->sink_request & DP_TEST_LINK_VIDEO_PATTERN) { | |
398 | /* force disconnect followed by connect */ | |
399 | dp->usbpd->connect(dp->usbpd, false); | |
400 | dp->panel->video_test = true; | |
401 | dp->usbpd->connect(dp->usbpd, true); | |
402 | dp_link_send_test_response(dp->link); | |
403 | } | |
404 | } | |
405 | ||
8ede2ecc | 406 | static int dp_display_handle_irq_hpd(struct dp_display_private *dp) |
c943b494 | 407 | { |
8ede2ecc KH |
408 | u32 sink_request; |
409 | ||
410 | sink_request = dp->link->sink_request; | |
c943b494 | 411 | |
8ede2ecc KH |
412 | if (sink_request & DS_PORT_STATUS_CHANGED) { |
413 | dp_add_event(dp, EV_USER_NOTIFICATION, false, 0); | |
c943b494 CU |
414 | if (dp_display_is_sink_count_zero(dp)) { |
415 | DRM_DEBUG_DP("sink count is zero, nothing to do\n"); | |
416 | return 0; | |
417 | } | |
418 | ||
419 | return dp_display_process_hpd_high(dp); | |
420 | } | |
421 | ||
422 | dp_ctrl_handle_sink_request(dp->ctrl); | |
423 | ||
8ede2ecc KH |
424 | if (dp->link->sink_request & DP_TEST_LINK_VIDEO_PATTERN) |
425 | dp_display_handle_video_request(dp); | |
c943b494 CU |
426 | |
427 | return 0; | |
428 | } | |
429 | ||
430 | static int dp_display_usbpd_attention_cb(struct device *dev) | |
431 | { | |
432 | int rc = 0; | |
433 | struct dp_display_private *dp; | |
434 | ||
435 | if (!dev) { | |
436 | DRM_ERROR("invalid dev\n"); | |
437 | return -EINVAL; | |
438 | } | |
439 | ||
061eb621 AK |
440 | dp = container_of(g_dp_display, |
441 | struct dp_display_private, dp_display); | |
c943b494 CU |
442 | if (!dp) { |
443 | DRM_ERROR("no driver data found\n"); | |
444 | return -ENODEV; | |
445 | } | |
446 | ||
8ede2ecc KH |
447 | /* check for any test request issued by sink */ |
448 | rc = dp_link_process_request(dp->link); | |
449 | if (!rc) | |
450 | dp_display_handle_irq_hpd(dp); | |
c943b494 | 451 | |
8ede2ecc KH |
452 | return rc; |
453 | } | |
c943b494 | 454 | |
8ede2ecc KH |
455 | static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) |
456 | { | |
457 | struct dp_usbpd *hpd = dp->usbpd; | |
458 | u32 state; | |
459 | u32 tout = DP_TIMEOUT_5_SECOND; | |
460 | int ret; | |
461 | ||
462 | if (!hpd) | |
463 | return 0; | |
464 | ||
465 | mutex_lock(&dp->event_mutex); | |
466 | ||
467 | state = atomic_read(&dp->hpd_state); | |
468 | if (state == ST_SUSPEND_PENDING) { | |
469 | mutex_unlock(&dp->event_mutex); | |
470 | return 0; | |
c943b494 CU |
471 | } |
472 | ||
8ede2ecc KH |
473 | if (state == ST_CONNECT_PENDING || state == ST_CONNECTED) { |
474 | mutex_unlock(&dp->event_mutex); | |
475 | return 0; | |
c943b494 CU |
476 | } |
477 | ||
8ede2ecc KH |
478 | if (state == ST_DISCONNECT_PENDING) { |
479 | /* wait until ST_DISCONNECTED */ | |
480 | dp_add_event(dp, EV_HPD_PLUG_INT, 0, 1); /* delay = 1 */ | |
481 | mutex_unlock(&dp->event_mutex); | |
482 | return 0; | |
483 | } | |
484 | ||
485 | if (state == ST_SUSPENDED) | |
486 | tout = DP_TIMEOUT_NONE; | |
487 | ||
488 | atomic_set(&dp->hpd_state, ST_CONNECT_PENDING); | |
489 | ||
490 | hpd->hpd_high = 1; | |
491 | ||
492 | ret = dp_display_usbpd_configure_cb(&dp->pdev->dev); | |
493 | if (ret) { /* failed */ | |
494 | hpd->hpd_high = 0; | |
495 | atomic_set(&dp->hpd_state, ST_DISCONNECTED); | |
496 | } | |
497 | ||
498 | /* start sanity checking */ | |
499 | dp_add_event(dp, EV_CONNECT_PENDING_TIMEOUT, 0, tout); | |
500 | ||
501 | mutex_unlock(&dp->event_mutex); | |
502 | ||
503 | /* uevent will complete connection part */ | |
504 | return 0; | |
505 | }; | |
506 | ||
507 | static int dp_display_enable(struct dp_display_private *dp, u32 data); | |
508 | static int dp_display_disable(struct dp_display_private *dp, u32 data); | |
509 | ||
510 | static int dp_connect_pending_timeout(struct dp_display_private *dp, u32 data) | |
511 | { | |
512 | u32 state; | |
513 | ||
514 | mutex_lock(&dp->event_mutex); | |
515 | ||
516 | state = atomic_read(&dp->hpd_state); | |
517 | if (state == ST_CONNECT_PENDING) { | |
518 | dp_display_enable(dp, 0); | |
519 | atomic_set(&dp->hpd_state, ST_CONNECTED); | |
520 | } | |
521 | ||
522 | mutex_unlock(&dp->event_mutex); | |
523 | ||
524 | return 0; | |
525 | } | |
526 | ||
527 | static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) | |
528 | { | |
529 | struct dp_usbpd *hpd = dp->usbpd; | |
530 | u32 state; | |
531 | ||
532 | if (!hpd) | |
533 | return 0; | |
534 | ||
535 | mutex_lock(&dp->event_mutex); | |
536 | ||
537 | state = atomic_read(&dp->hpd_state); | |
538 | if (state == ST_SUSPEND_PENDING) { | |
539 | mutex_unlock(&dp->event_mutex); | |
540 | return 0; | |
541 | } | |
542 | ||
543 | if (state == ST_DISCONNECT_PENDING || state == ST_DISCONNECTED) { | |
544 | mutex_unlock(&dp->event_mutex); | |
545 | return 0; | |
546 | } | |
547 | ||
548 | if (state == ST_CONNECT_PENDING) { | |
549 | /* wait until CONNECTED */ | |
550 | dp_add_event(dp, EV_HPD_UNPLUG_INT, 0, 1); /* delay = 1 */ | |
551 | mutex_unlock(&dp->event_mutex); | |
552 | return 0; | |
553 | } | |
554 | ||
555 | atomic_set(&dp->hpd_state, ST_DISCONNECT_PENDING); | |
556 | ||
557 | /* disable HPD plug interrupt until disconnect is done */ | |
558 | dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK | |
559 | | DP_DP_IRQ_HPD_INT_MASK, false); | |
560 | ||
561 | hpd->hpd_high = 0; | |
562 | ||
563 | /* | |
564 | * We don't need separate work for disconnect as | |
565 | * connect/attention interrupts are disabled | |
566 | */ | |
567 | dp_display_usbpd_disconnect_cb(&dp->pdev->dev); | |
568 | ||
569 | /* start sanity checking */ | |
570 | dp_add_event(dp, EV_DISCONNECT_PENDING_TIMEOUT, 0, DP_TIMEOUT_5_SECOND); | |
571 | ||
572 | dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK | | |
573 | DP_DP_IRQ_HPD_INT_MASK, true); | |
574 | ||
575 | /* uevent will complete disconnection part */ | |
576 | mutex_unlock(&dp->event_mutex); | |
577 | return 0; | |
578 | } | |
579 | ||
580 | static int dp_disconnect_pending_timeout(struct dp_display_private *dp, u32 data) | |
581 | { | |
582 | u32 state; | |
583 | ||
584 | mutex_lock(&dp->event_mutex); | |
585 | ||
586 | state = atomic_read(&dp->hpd_state); | |
587 | if (state == ST_DISCONNECT_PENDING) { | |
588 | dp_display_disable(dp, 0); | |
589 | atomic_set(&dp->hpd_state, ST_DISCONNECTED); | |
590 | } | |
591 | ||
592 | mutex_unlock(&dp->event_mutex); | |
593 | ||
594 | return 0; | |
595 | } | |
596 | ||
597 | static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data) | |
598 | { | |
599 | u32 state; | |
600 | ||
601 | mutex_lock(&dp->event_mutex); | |
602 | ||
603 | /* irq_hpd can happen at either connected or disconnected state */ | |
604 | state = atomic_read(&dp->hpd_state); | |
605 | if (state == ST_SUSPEND_PENDING) { | |
606 | mutex_unlock(&dp->event_mutex); | |
607 | return 0; | |
608 | } | |
609 | ||
610 | dp_display_usbpd_attention_cb(&dp->pdev->dev); | |
611 | ||
612 | mutex_unlock(&dp->event_mutex); | |
613 | ||
614 | return 0; | |
c943b494 CU |
615 | } |
616 | ||
617 | static void dp_display_deinit_sub_modules(struct dp_display_private *dp) | |
618 | { | |
619 | dp_ctrl_put(dp->ctrl); | |
620 | dp_panel_put(dp->panel); | |
621 | dp_aux_put(dp->aux); | |
14975cff | 622 | dp_pll_put(dp->pll); |
c943b494 CU |
623 | } |
624 | ||
625 | static int dp_init_sub_modules(struct dp_display_private *dp) | |
626 | { | |
627 | int rc = 0; | |
628 | struct device *dev = &dp->pdev->dev; | |
629 | struct dp_usbpd_cb *cb = &dp->usbpd_cb; | |
630 | struct dp_panel_in panel_in = { | |
631 | .dev = dev, | |
632 | }; | |
14975cff CU |
633 | struct dp_pll_in pll_in = { |
634 | .pdev = dp->pdev, | |
635 | }; | |
c943b494 CU |
636 | |
637 | /* Callback APIs used for cable status change event */ | |
638 | cb->configure = dp_display_usbpd_configure_cb; | |
639 | cb->disconnect = dp_display_usbpd_disconnect_cb; | |
640 | cb->attention = dp_display_usbpd_attention_cb; | |
641 | ||
642 | dp->usbpd = dp_hpd_get(dev, cb); | |
643 | if (IS_ERR(dp->usbpd)) { | |
644 | rc = PTR_ERR(dp->usbpd); | |
645 | DRM_ERROR("failed to initialize hpd, rc = %d\n", rc); | |
646 | dp->usbpd = NULL; | |
647 | goto error; | |
648 | } | |
649 | ||
650 | dp->parser = dp_parser_get(dp->pdev); | |
651 | if (IS_ERR(dp->parser)) { | |
652 | rc = PTR_ERR(dp->parser); | |
653 | DRM_ERROR("failed to initialize parser, rc = %d\n", rc); | |
654 | dp->parser = NULL; | |
655 | goto error; | |
656 | } | |
657 | ||
658 | dp->catalog = dp_catalog_get(dev, &dp->parser->io); | |
659 | if (IS_ERR(dp->catalog)) { | |
660 | rc = PTR_ERR(dp->catalog); | |
661 | DRM_ERROR("failed to initialize catalog, rc = %d\n", rc); | |
662 | dp->catalog = NULL; | |
663 | goto error; | |
664 | } | |
665 | ||
14975cff CU |
666 | pll_in.parser = dp->parser; |
667 | dp->pll = dp_pll_get(&pll_in); | |
668 | if (IS_ERR_OR_NULL(dp->pll)) { | |
669 | rc = -EINVAL; | |
670 | DRM_ERROR("failed to initialize pll, rc = %d\n", rc); | |
671 | dp->pll = NULL; | |
672 | goto error; | |
673 | } | |
674 | ||
675 | dp->parser->pll = dp->pll; | |
676 | ||
c943b494 CU |
677 | dp->power = dp_power_get(dp->parser); |
678 | if (IS_ERR(dp->power)) { | |
679 | rc = PTR_ERR(dp->power); | |
680 | DRM_ERROR("failed to initialize power, rc = %d\n", rc); | |
681 | dp->power = NULL; | |
682 | goto error; | |
683 | } | |
684 | ||
685 | dp->aux = dp_aux_get(dev, dp->catalog); | |
686 | if (IS_ERR(dp->aux)) { | |
687 | rc = PTR_ERR(dp->aux); | |
688 | DRM_ERROR("failed to initialize aux, rc = %d\n", rc); | |
689 | dp->aux = NULL; | |
690 | goto error; | |
691 | } | |
692 | ||
693 | dp->link = dp_link_get(dev, dp->aux); | |
694 | if (IS_ERR(dp->link)) { | |
695 | rc = PTR_ERR(dp->link); | |
696 | DRM_ERROR("failed to initialize link, rc = %d\n", rc); | |
697 | dp->link = NULL; | |
698 | goto error_link; | |
699 | } | |
700 | ||
701 | panel_in.aux = dp->aux; | |
702 | panel_in.catalog = dp->catalog; | |
703 | panel_in.link = dp->link; | |
704 | ||
705 | dp->panel = dp_panel_get(&panel_in); | |
706 | if (IS_ERR(dp->panel)) { | |
707 | rc = PTR_ERR(dp->panel); | |
708 | DRM_ERROR("failed to initialize panel, rc = %d\n", rc); | |
709 | dp->panel = NULL; | |
710 | goto error_link; | |
711 | } | |
712 | ||
713 | dp->ctrl = dp_ctrl_get(dev, dp->link, dp->panel, dp->aux, | |
714 | dp->power, dp->catalog, dp->parser); | |
715 | if (IS_ERR(dp->ctrl)) { | |
716 | rc = PTR_ERR(dp->ctrl); | |
717 | DRM_ERROR("failed to initialize ctrl, rc = %d\n", rc); | |
718 | dp->ctrl = NULL; | |
719 | goto error_ctrl; | |
720 | } | |
721 | ||
722 | return rc; | |
723 | error_ctrl: | |
724 | dp_panel_put(dp->panel); | |
725 | error_link: | |
726 | dp_aux_put(dp->aux); | |
727 | error: | |
728 | return rc; | |
729 | } | |
730 | ||
731 | static int dp_display_set_mode(struct msm_dp *dp_display, | |
732 | struct dp_display_mode *mode) | |
733 | { | |
734 | struct dp_display_private *dp; | |
735 | ||
736 | dp = container_of(dp_display, struct dp_display_private, dp_display); | |
737 | ||
738 | dp->panel->dp_mode.drm_mode = mode->drm_mode; | |
739 | dp->panel->dp_mode.bpp = mode->bpp; | |
740 | dp->panel->dp_mode.capabilities = mode->capabilities; | |
741 | dp_panel_init_panel_info(dp->panel); | |
742 | return 0; | |
743 | } | |
744 | ||
745 | static int dp_display_prepare(struct msm_dp *dp) | |
746 | { | |
747 | return 0; | |
748 | } | |
749 | ||
8ede2ecc | 750 | static int dp_display_enable(struct dp_display_private *dp, u32 data) |
c943b494 CU |
751 | { |
752 | int rc = 0; | |
c943b494 CU |
753 | |
754 | if (dp->power_on) { | |
755 | DRM_DEBUG_DP("Link already setup, return\n"); | |
756 | return 0; | |
757 | } | |
758 | ||
8ede2ecc | 759 | rc = dp_ctrl_on_stream(dp->ctrl); |
c943b494 CU |
760 | if (!rc) |
761 | dp->power_on = true; | |
762 | ||
8ede2ecc KH |
763 | /* complete resume_comp regardless it is armed or not */ |
764 | complete(&dp->resume_comp); | |
c943b494 CU |
765 | return rc; |
766 | } | |
767 | ||
768 | static int dp_display_post_enable(struct msm_dp *dp_display) | |
769 | { | |
c943b494 CU |
770 | return 0; |
771 | } | |
772 | ||
8ede2ecc | 773 | static int dp_display_disable(struct dp_display_private *dp, u32 data) |
c943b494 | 774 | { |
8ede2ecc | 775 | if (!dp->power_on) |
c943b494 CU |
776 | return -EINVAL; |
777 | ||
778 | dp_ctrl_off(dp->ctrl); | |
779 | ||
8ede2ecc | 780 | dp->core_initialized = false; |
c943b494 | 781 | |
8ede2ecc | 782 | dp->power_on = false; |
c943b494 CU |
783 | |
784 | return 0; | |
785 | } | |
786 | ||
787 | static int dp_display_unprepare(struct msm_dp *dp) | |
788 | { | |
789 | return 0; | |
790 | } | |
791 | ||
792 | int dp_display_validate_mode(struct msm_dp *dp, u32 mode_pclk_khz) | |
793 | { | |
794 | const u32 num_components = 3, default_bpp = 24; | |
795 | struct dp_display_private *dp_display; | |
796 | struct dp_link_info *link_info; | |
797 | u32 mode_rate_khz = 0, supported_rate_khz = 0, mode_bpp = 0; | |
798 | ||
799 | if (!dp || !mode_pclk_khz || !dp->connector) { | |
800 | DRM_ERROR("invalid params\n"); | |
801 | return -EINVAL; | |
802 | } | |
803 | ||
804 | dp_display = container_of(dp, struct dp_display_private, dp_display); | |
805 | link_info = &dp_display->panel->link_info; | |
806 | ||
807 | mode_bpp = dp->connector->display_info.bpc * num_components; | |
808 | if (!mode_bpp) | |
809 | mode_bpp = default_bpp; | |
810 | ||
811 | mode_bpp = dp_panel_get_mode_bpp(dp_display->panel, | |
812 | mode_bpp, mode_pclk_khz); | |
813 | ||
814 | mode_rate_khz = mode_pclk_khz * mode_bpp; | |
815 | supported_rate_khz = link_info->num_lanes * link_info->rate * 8; | |
816 | ||
817 | if (mode_rate_khz > supported_rate_khz) | |
818 | return MODE_BAD; | |
819 | ||
820 | return MODE_OK; | |
821 | } | |
822 | ||
823 | int dp_display_get_modes(struct msm_dp *dp, | |
824 | struct dp_display_mode *dp_mode) | |
825 | { | |
826 | struct dp_display_private *dp_display; | |
827 | int ret = 0; | |
828 | ||
829 | if (!dp) { | |
830 | DRM_ERROR("invalid params\n"); | |
831 | return 0; | |
832 | } | |
833 | ||
834 | dp_display = container_of(dp, struct dp_display_private, dp_display); | |
835 | ||
836 | ret = dp_panel_get_modes(dp_display->panel, | |
837 | dp->connector, dp_mode); | |
838 | if (dp_mode->drm_mode.clock) | |
839 | dp->max_pclk_khz = dp_mode->drm_mode.clock; | |
840 | return ret; | |
841 | } | |
842 | ||
843 | bool dp_display_check_video_test(struct msm_dp *dp) | |
844 | { | |
845 | struct dp_display_private *dp_display; | |
846 | ||
847 | dp_display = container_of(dp, struct dp_display_private, dp_display); | |
848 | ||
849 | return dp_display->panel->video_test; | |
850 | } | |
851 | ||
852 | int dp_display_get_test_bpp(struct msm_dp *dp) | |
853 | { | |
854 | struct dp_display_private *dp_display; | |
855 | ||
856 | if (!dp) { | |
857 | DRM_ERROR("invalid params\n"); | |
858 | return 0; | |
859 | } | |
860 | ||
861 | dp_display = container_of(dp, struct dp_display_private, dp_display); | |
862 | ||
863 | return dp_link_bit_depth_to_bpp( | |
864 | dp_display->link->test_video.test_bit_depth); | |
865 | } | |
866 | ||
8ede2ecc KH |
867 | static void dp_display_config_hpd(struct dp_display_private *dp) |
868 | { | |
869 | ||
870 | dp_display_host_init(dp); | |
871 | dp_catalog_ctrl_hpd_config(dp->catalog); | |
872 | ||
873 | /* Enable interrupt first time | |
874 | * we are leaving dp clocks on during disconnect | |
875 | * and never disable interrupt | |
876 | */ | |
877 | enable_irq(dp->irq); | |
878 | } | |
879 | ||
880 | static int hpd_event_thread(void *data) | |
881 | { | |
882 | struct dp_display_private *dp_priv; | |
883 | unsigned long flag; | |
884 | struct dp_event *todo; | |
885 | int timeout_mode = 0; | |
886 | ||
887 | dp_priv = (struct dp_display_private *)data; | |
888 | ||
889 | while (1) { | |
890 | if (timeout_mode) { | |
891 | wait_event_timeout(dp_priv->event_q, | |
892 | (dp_priv->event_pndx == dp_priv->event_gndx), | |
893 | EVENT_TIMEOUT); | |
894 | } else { | |
895 | wait_event_timeout(dp_priv->event_q, | |
896 | (dp_priv->event_pndx != dp_priv->event_gndx), | |
897 | EVENT_TIMEOUT); | |
898 | } | |
899 | spin_lock_irqsave(&dp_priv->event_lock, flag); | |
900 | todo = &dp_priv->event_list[dp_priv->event_gndx]; | |
901 | if (todo->delay) { | |
902 | struct dp_event *todo_next; | |
903 | ||
904 | dp_priv->event_gndx++; | |
905 | dp_priv->event_gndx %= DP_EVENT_Q_MAX; | |
906 | ||
907 | /* re enter delay event into q */ | |
908 | todo_next = &dp_priv->event_list[dp_priv->event_pndx++]; | |
909 | dp_priv->event_pndx %= DP_EVENT_Q_MAX; | |
910 | todo_next->event_id = todo->event_id; | |
911 | todo_next->data = todo->data; | |
912 | todo_next->delay = todo->delay - 1; | |
913 | ||
914 | /* clean up older event */ | |
915 | todo->event_id = EV_NO_EVENT; | |
916 | todo->delay = 0; | |
917 | ||
918 | /* switch to timeout mode */ | |
919 | timeout_mode = 1; | |
920 | spin_unlock_irqrestore(&dp_priv->event_lock, flag); | |
921 | continue; | |
922 | } | |
923 | ||
924 | /* timeout with no events in q */ | |
925 | if (dp_priv->event_pndx == dp_priv->event_gndx) { | |
926 | spin_unlock_irqrestore(&dp_priv->event_lock, flag); | |
927 | continue; | |
928 | } | |
929 | ||
930 | dp_priv->event_gndx++; | |
931 | dp_priv->event_gndx %= DP_EVENT_Q_MAX; | |
932 | timeout_mode = 0; | |
933 | spin_unlock_irqrestore(&dp_priv->event_lock, flag); | |
934 | ||
935 | switch (todo->event_id) { | |
936 | case EV_HPD_INIT_SETUP: | |
937 | dp_display_config_hpd(dp_priv); | |
938 | break; | |
939 | case EV_HPD_PLUG_INT: | |
940 | dp_hpd_plug_handle(dp_priv, todo->data); | |
941 | break; | |
942 | case EV_HPD_UNPLUG_INT: | |
943 | dp_hpd_unplug_handle(dp_priv, todo->data); | |
944 | break; | |
945 | case EV_IRQ_HPD_INT: | |
946 | dp_irq_hpd_handle(dp_priv, todo->data); | |
947 | break; | |
948 | case EV_HPD_REPLUG_INT: | |
949 | /* do nothing */ | |
950 | break; | |
951 | case EV_USER_NOTIFICATION: | |
952 | dp_display_send_hpd_notification(dp_priv, | |
953 | todo->data); | |
954 | break; | |
955 | case EV_CONNECT_PENDING_TIMEOUT: | |
956 | dp_connect_pending_timeout(dp_priv, | |
957 | todo->data); | |
958 | break; | |
959 | case EV_DISCONNECT_PENDING_TIMEOUT: | |
960 | dp_disconnect_pending_timeout(dp_priv, | |
961 | todo->data); | |
962 | break; | |
963 | default: | |
964 | break; | |
965 | } | |
966 | } | |
967 | ||
968 | return 0; | |
969 | } | |
970 | ||
971 | static void dp_hpd_event_setup(struct dp_display_private *dp_priv) | |
972 | { | |
973 | init_waitqueue_head(&dp_priv->event_q); | |
974 | spin_lock_init(&dp_priv->event_lock); | |
975 | ||
976 | kthread_run(hpd_event_thread, dp_priv, "dp_hpd_handler"); | |
977 | } | |
978 | ||
979 | static irqreturn_t dp_display_irq_handler(int irq, void *dev_id) | |
980 | { | |
981 | struct dp_display_private *dp = dev_id; | |
982 | irqreturn_t ret = IRQ_HANDLED; | |
983 | u32 hpd_isr_status; | |
984 | ||
985 | if (!dp) { | |
986 | DRM_ERROR("invalid data\n"); | |
987 | return IRQ_NONE; | |
988 | } | |
989 | ||
990 | hpd_isr_status = dp_catalog_hpd_get_intr_status(dp->catalog); | |
991 | ||
992 | if (hpd_isr_status & 0x0F) { | |
993 | /* hpd related interrupts */ | |
994 | if (hpd_isr_status & DP_DP_HPD_PLUG_INT_MASK || | |
995 | hpd_isr_status & DP_DP_HPD_REPLUG_INT_MASK) { | |
996 | dp_add_event(dp, EV_HPD_PLUG_INT, 0, 0); | |
997 | } | |
998 | ||
999 | if (hpd_isr_status & DP_DP_IRQ_HPD_INT_MASK) { | |
1000 | /* delete connect pending event first */ | |
1001 | dp_del_event(dp, EV_CONNECT_PENDING_TIMEOUT); | |
1002 | dp_add_event(dp, EV_IRQ_HPD_INT, 0, 0); | |
1003 | } | |
1004 | ||
1005 | if (hpd_isr_status & DP_DP_HPD_REPLUG_INT_MASK) | |
1006 | dp_add_event(dp, EV_HPD_REPLUG_INT, 0, 0); | |
1007 | ||
1008 | if (hpd_isr_status & DP_DP_HPD_UNPLUG_INT_MASK) | |
1009 | dp_add_event(dp, EV_HPD_UNPLUG_INT, 0, 0); | |
1010 | } | |
1011 | ||
1012 | /* DP controller isr */ | |
1013 | dp_ctrl_isr(dp->ctrl); | |
1014 | ||
1015 | /* DP aux isr */ | |
1016 | dp_aux_isr(dp->aux); | |
1017 | ||
1018 | return ret; | |
1019 | } | |
1020 | ||
1021 | int dp_display_request_irq(struct msm_dp *dp_display) | |
1022 | { | |
1023 | int rc = 0; | |
1024 | struct dp_display_private *dp; | |
1025 | ||
1026 | if (!dp_display) { | |
1027 | DRM_ERROR("invalid input\n"); | |
1028 | return -EINVAL; | |
1029 | } | |
1030 | ||
1031 | dp = container_of(dp_display, struct dp_display_private, dp_display); | |
1032 | ||
1033 | dp->irq = irq_of_parse_and_map(dp->pdev->dev.of_node, 0); | |
1034 | if (dp->irq < 0) { | |
1035 | rc = dp->irq; | |
1036 | DRM_ERROR("failed to get irq: %d\n", rc); | |
1037 | return rc; | |
1038 | } | |
1039 | ||
1040 | rc = devm_request_irq(&dp->pdev->dev, dp->irq, | |
1041 | dp_display_irq_handler, | |
1042 | IRQF_TRIGGER_HIGH, "dp_display_isr", dp); | |
1043 | if (rc < 0) { | |
1044 | DRM_ERROR("failed to request IRQ%u: %d\n", | |
1045 | dp->irq, rc); | |
1046 | return rc; | |
1047 | } | |
1048 | disable_irq(dp->irq); | |
1049 | ||
1050 | return 0; | |
1051 | } | |
1052 | ||
c943b494 CU |
1053 | static int dp_display_probe(struct platform_device *pdev) |
1054 | { | |
1055 | int rc = 0; | |
1056 | struct dp_display_private *dp; | |
1057 | ||
1058 | if (!pdev || !pdev->dev.of_node) { | |
1059 | DRM_ERROR("pdev not found\n"); | |
1060 | return -ENODEV; | |
1061 | } | |
1062 | ||
1063 | dp = devm_kzalloc(&pdev->dev, sizeof(*dp), GFP_KERNEL); | |
1064 | if (!dp) | |
1065 | return -ENOMEM; | |
1066 | ||
c943b494 CU |
1067 | dp->pdev = pdev; |
1068 | dp->name = "drm_dp"; | |
1069 | ||
1070 | rc = dp_init_sub_modules(dp); | |
1071 | if (rc) { | |
1072 | DRM_ERROR("init sub module failed\n"); | |
1073 | return -EPROBE_DEFER; | |
1074 | } | |
1075 | ||
8ede2ecc | 1076 | mutex_init(&dp->event_mutex); |
061eb621 | 1077 | |
8ede2ecc | 1078 | init_completion(&dp->resume_comp); |
061eb621 | 1079 | |
c943b494 CU |
1080 | g_dp_display = &dp->dp_display; |
1081 | ||
061eb621 AK |
1082 | platform_set_drvdata(pdev, g_dp_display); |
1083 | ||
c943b494 CU |
1084 | rc = component_add(&pdev->dev, &dp_display_comp_ops); |
1085 | if (rc) { | |
1086 | DRM_ERROR("component add failed, rc=%d\n", rc); | |
1087 | dp_display_deinit_sub_modules(dp); | |
1088 | } | |
1089 | ||
1090 | return rc; | |
1091 | } | |
1092 | ||
1093 | static int dp_display_remove(struct platform_device *pdev) | |
1094 | { | |
1095 | struct dp_display_private *dp; | |
1096 | ||
061eb621 AK |
1097 | dp = container_of(g_dp_display, |
1098 | struct dp_display_private, dp_display); | |
c943b494 CU |
1099 | |
1100 | dp_display_deinit_sub_modules(dp); | |
1101 | ||
1102 | component_del(&pdev->dev, &dp_display_comp_ops); | |
1103 | platform_set_drvdata(pdev, NULL); | |
1104 | ||
1105 | return 0; | |
1106 | } | |
1107 | ||
1108 | static int dp_pm_resume(struct device *dev) | |
1109 | { | |
1110 | return 0; | |
1111 | } | |
1112 | ||
1113 | static int dp_pm_suspend(struct device *dev) | |
1114 | { | |
8ede2ecc KH |
1115 | struct platform_device *pdev = to_platform_device(dev); |
1116 | struct dp_display_private *dp = platform_get_drvdata(pdev); | |
1117 | ||
1118 | if (!dp) { | |
1119 | DRM_ERROR("DP driver bind failed. Invalid driver data\n"); | |
1120 | return -EINVAL; | |
1121 | } | |
1122 | ||
1123 | atomic_set(&dp->hpd_state, ST_SUSPENDED); | |
1124 | ||
c943b494 CU |
1125 | return 0; |
1126 | } | |
1127 | ||
1128 | static int dp_pm_prepare(struct device *dev) | |
1129 | { | |
1130 | return 0; | |
1131 | } | |
1132 | ||
1133 | static void dp_pm_complete(struct device *dev) | |
1134 | { | |
1135 | ||
1136 | } | |
1137 | ||
1138 | static const struct dev_pm_ops dp_pm_ops = { | |
1139 | .suspend = dp_pm_suspend, | |
1140 | .resume = dp_pm_resume, | |
1141 | .prepare = dp_pm_prepare, | |
1142 | .complete = dp_pm_complete, | |
1143 | }; | |
1144 | ||
1145 | static struct platform_driver dp_display_driver = { | |
1146 | .probe = dp_display_probe, | |
1147 | .remove = dp_display_remove, | |
1148 | .driver = { | |
1149 | .name = "msm-dp-display", | |
1150 | .of_match_table = dp_dt_match, | |
1151 | .suppress_bind_attrs = true, | |
1152 | .pm = &dp_pm_ops, | |
1153 | }, | |
1154 | }; | |
1155 | ||
1156 | int __init msm_dp_register(void) | |
1157 | { | |
1158 | int ret; | |
1159 | ||
1160 | ret = platform_driver_register(&dp_display_driver); | |
1161 | if (ret) | |
1162 | DRM_ERROR("Dp display driver register failed"); | |
1163 | ||
1164 | return ret; | |
1165 | } | |
1166 | ||
1167 | void __exit msm_dp_unregister(void) | |
1168 | { | |
1169 | platform_driver_unregister(&dp_display_driver); | |
1170 | } | |
1171 | ||
220b856a TS |
1172 | void msm_dp_irq_postinstall(struct msm_dp *dp_display) |
1173 | { | |
1174 | struct dp_display_private *dp; | |
1175 | ||
1176 | if (!dp_display) | |
1177 | return; | |
1178 | ||
1179 | dp = container_of(dp_display, struct dp_display_private, dp_display); | |
1180 | ||
8ede2ecc KH |
1181 | dp_hpd_event_setup(dp); |
1182 | ||
1183 | dp_add_event(dp, EV_HPD_INIT_SETUP, 0, 100); | |
220b856a TS |
1184 | } |
1185 | ||
c943b494 CU |
1186 | int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev, |
1187 | struct drm_encoder *encoder) | |
1188 | { | |
1189 | struct msm_drm_private *priv; | |
1190 | int ret; | |
1191 | ||
1192 | if (WARN_ON(!encoder) || WARN_ON(!dp_display) || WARN_ON(!dev)) | |
1193 | return -EINVAL; | |
1194 | ||
1195 | priv = dev->dev_private; | |
1196 | dp_display->drm_dev = dev; | |
1197 | ||
1198 | ret = dp_display_request_irq(dp_display); | |
1199 | if (ret) { | |
1200 | DRM_ERROR("request_irq failed, ret=%d\n", ret); | |
1201 | return ret; | |
1202 | } | |
1203 | ||
1204 | dp_display->encoder = encoder; | |
1205 | ||
1206 | dp_display->connector = dp_drm_connector_init(dp_display); | |
1207 | if (IS_ERR(dp_display->connector)) { | |
1208 | ret = PTR_ERR(dp_display->connector); | |
1209 | DRM_DEV_ERROR(dev->dev, | |
1210 | "failed to create dp connector: %d\n", ret); | |
1211 | dp_display->connector = NULL; | |
1212 | return ret; | |
1213 | } | |
1214 | ||
1215 | priv->connectors[priv->num_connectors++] = dp_display->connector; | |
1216 | return 0; | |
1217 | } | |
1218 | ||
8ede2ecc KH |
1219 | static int dp_display_wait4resume_done(struct dp_display_private *dp) |
1220 | { | |
1221 | int ret = 0; | |
1222 | ||
1223 | reinit_completion(&dp->resume_comp); | |
1224 | if (!wait_for_completion_timeout(&dp->resume_comp, | |
1225 | WAIT_FOR_RESUME_TIMEOUT_JIFFIES)) { | |
1226 | DRM_ERROR("wait4resume_done timedout\n"); | |
1227 | ret = -ETIMEDOUT; | |
1228 | } | |
1229 | return ret; | |
1230 | } | |
1231 | ||
c943b494 CU |
1232 | int msm_dp_display_enable(struct msm_dp *dp, struct drm_encoder *encoder) |
1233 | { | |
1234 | int rc = 0; | |
1235 | struct dp_display_private *dp_display; | |
8ede2ecc | 1236 | u32 state; |
c943b494 CU |
1237 | |
1238 | dp_display = container_of(dp, struct dp_display_private, dp_display); | |
1239 | if (!dp_display->dp_mode.drm_mode.clock) { | |
1240 | DRM_ERROR("invalid params\n"); | |
1241 | return -EINVAL; | |
1242 | } | |
1243 | ||
8ede2ecc KH |
1244 | mutex_lock(&dp_display->event_mutex); |
1245 | ||
c943b494 CU |
1246 | rc = dp_display_set_mode(dp, &dp_display->dp_mode); |
1247 | if (rc) { | |
1248 | DRM_ERROR("Failed to perform a mode set, rc=%d\n", rc); | |
8ede2ecc | 1249 | mutex_unlock(&dp_display->event_mutex); |
c943b494 CU |
1250 | return rc; |
1251 | } | |
1252 | ||
1253 | rc = dp_display_prepare(dp); | |
1254 | if (rc) { | |
1255 | DRM_ERROR("DP display prepare failed, rc=%d\n", rc); | |
8ede2ecc | 1256 | mutex_unlock(&dp_display->event_mutex); |
c943b494 CU |
1257 | return rc; |
1258 | } | |
1259 | ||
8ede2ecc KH |
1260 | state = atomic_read(&dp_display->hpd_state); |
1261 | if (state == ST_SUSPENDED) { | |
1262 | /* start link training */ | |
1263 | dp_add_event(dp_display, EV_HPD_PLUG_INT, 0, 0); | |
1264 | mutex_unlock(&dp_display->event_mutex); | |
1265 | ||
1266 | /* wait until dp interface is up */ | |
1267 | goto resume_done; | |
c943b494 CU |
1268 | } |
1269 | ||
8ede2ecc KH |
1270 | dp_display_enable(dp_display, 0); |
1271 | ||
c943b494 CU |
1272 | rc = dp_display_post_enable(dp); |
1273 | if (rc) { | |
1274 | DRM_ERROR("DP display post enable failed, rc=%d\n", rc); | |
8ede2ecc | 1275 | dp_display_disable(dp_display, 0); |
c943b494 CU |
1276 | dp_display_unprepare(dp); |
1277 | } | |
8ede2ecc KH |
1278 | |
1279 | dp_del_event(dp_display, EV_CONNECT_PENDING_TIMEOUT); | |
1280 | ||
1281 | if (state == ST_SUSPEND_PENDING) | |
1282 | dp_add_event(dp_display, EV_IRQ_HPD_INT, 0, 0); | |
1283 | ||
1284 | /* completed connection */ | |
1285 | atomic_set(&dp_display->hpd_state, ST_CONNECTED); | |
1286 | ||
1287 | mutex_unlock(&dp_display->event_mutex); | |
1288 | ||
c943b494 | 1289 | return rc; |
8ede2ecc KH |
1290 | |
1291 | resume_done: | |
1292 | dp_display_wait4resume_done(dp_display); | |
1293 | return rc; | |
1294 | } | |
1295 | ||
1296 | int msm_dp_display_pre_disable(struct msm_dp *dp, struct drm_encoder *encoder) | |
1297 | { | |
1298 | struct dp_display_private *dp_display; | |
1299 | ||
1300 | dp_display = container_of(dp, struct dp_display_private, dp_display); | |
1301 | ||
1302 | dp_ctrl_push_idle(dp_display->ctrl); | |
1303 | ||
1304 | return 0; | |
c943b494 CU |
1305 | } |
1306 | ||
1307 | int msm_dp_display_disable(struct msm_dp *dp, struct drm_encoder *encoder) | |
1308 | { | |
1309 | int rc = 0; | |
8ede2ecc KH |
1310 | u32 state; |
1311 | struct dp_display_private *dp_display; | |
c943b494 | 1312 | |
8ede2ecc | 1313 | dp_display = container_of(dp, struct dp_display_private, dp_display); |
c943b494 | 1314 | |
8ede2ecc KH |
1315 | mutex_lock(&dp_display->event_mutex); |
1316 | ||
1317 | dp_display_disable(dp_display, 0); | |
c943b494 CU |
1318 | |
1319 | rc = dp_display_unprepare(dp); | |
1320 | if (rc) | |
1321 | DRM_ERROR("DP display unprepare failed, rc=%d\n", rc); | |
1322 | ||
8ede2ecc KH |
1323 | dp_del_event(dp_display, EV_DISCONNECT_PENDING_TIMEOUT); |
1324 | ||
1325 | state = atomic_read(&dp_display->hpd_state); | |
1326 | if (state == ST_DISCONNECT_PENDING) { | |
1327 | /* completed disconnection */ | |
1328 | atomic_set(&dp_display->hpd_state, ST_DISCONNECTED); | |
1329 | } else { | |
1330 | atomic_set(&dp_display->hpd_state, ST_SUSPEND_PENDING); | |
1331 | } | |
1332 | ||
1333 | mutex_unlock(&dp_display->event_mutex); | |
c943b494 CU |
1334 | return rc; |
1335 | } | |
1336 | ||
1337 | void msm_dp_display_mode_set(struct msm_dp *dp, struct drm_encoder *encoder, | |
1338 | struct drm_display_mode *mode, | |
1339 | struct drm_display_mode *adjusted_mode) | |
1340 | { | |
1341 | struct dp_display_private *dp_display; | |
1342 | ||
1343 | dp_display = container_of(dp, struct dp_display_private, dp_display); | |
1344 | ||
1345 | memset(&dp_display->dp_mode, 0x0, sizeof(struct dp_display_mode)); | |
1346 | ||
1347 | if (dp_display_check_video_test(dp)) | |
1348 | dp_display->dp_mode.bpp = dp_display_get_test_bpp(dp); | |
1349 | else /* Default num_components per pixel = 3 */ | |
1350 | dp_display->dp_mode.bpp = dp->connector->display_info.bpc * 3; | |
1351 | ||
1352 | if (!dp_display->dp_mode.bpp) | |
1353 | dp_display->dp_mode.bpp = 24; /* Default bpp */ | |
1354 | ||
1355 | drm_mode_copy(&dp_display->dp_mode.drm_mode, adjusted_mode); | |
1356 | ||
1357 | dp_display->dp_mode.v_active_low = | |
1358 | !!(dp_display->dp_mode.drm_mode.flags & DRM_MODE_FLAG_NVSYNC); | |
1359 | ||
1360 | dp_display->dp_mode.h_active_low = | |
1361 | !!(dp_display->dp_mode.drm_mode.flags & DRM_MODE_FLAG_NHSYNC); | |
1362 | } |