blob: 442179f15409c3e78649756a158d48f72c0d133d [file] [log] [blame]
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -07001/*
Narender Ankam1afbd172020-03-16 17:27:44 +05302 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -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
15#define pr_fmt(fmt) "[drm-dp]: %s: " fmt, __func__
16
17#include <drm/drm_atomic_helper.h>
18#include <drm/drm_atomic.h>
19#include <drm/drm_crtc.h>
20
21#include "msm_drv.h"
22#include "msm_kms.h"
23#include "sde_connector.h"
24#include "dp_drm.h"
Samantha Tran2d1ed732017-07-31 17:30:14 -070025#include "dp_debug.h"
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -070026
27#define to_dp_bridge(x) container_of((x), struct dp_bridge, base)
28
Narender Ankam1afbd172020-03-16 17:27:44 +053029enum dp_connector_hdr_state {
30 HDR_DISABLE,
31 HDR_ENABLE
32};
33
Narender Ankamde426242019-12-23 20:54:31 +053034static int get_sink_dc_support(struct dp_display *dp,
35 struct drm_display_mode *mode)
36{
37 int dc_format = 0;
38 struct drm_connector *connector = dp->connector;
39
40 if ((mode->flags & DRM_MODE_FLAG_SUPPORTS_YUV420) &&
41 (connector->display_info.edid_hdmi_dc_modes
42 & DRM_EDID_YCBCR420_DC_30))
43 if (dp->get_dc_support(dp, mode->clock,
44 MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420, true))
45 dc_format |= MSM_MODE_FLAG_YUV420_DC_ENABLE;
46
47 if ((mode->flags & DRM_MODE_FLAG_SUPPORTS_RGB) &&
48 (connector->display_info.edid_hdmi_dc_modes
49 & DRM_EDID_HDMI_DC_30))
50 if (dp->get_dc_support(dp, mode->clock,
51 MSM_MODE_FLAG_COLOR_FORMAT_RGB444, true))
52 dc_format |= MSM_MODE_FLAG_RGB444_DC_ENABLE;
53
54 if ((mode->flags & DRM_MODE_FLAG_SUPPORTS_YUV422) &&
55 (connector->display_info.edid_hdmi_dc_modes
56 & DRM_EDID_HDMI_DC_30))
57 if (dp->get_dc_support(dp, mode->clock,
58 MSM_MODE_FLAG_COLOR_FORMAT_YCBCR422, false))
59 dc_format |= MSM_MODE_FLAG_YUV422_DC_ENABLE;
60
61 return dc_format;
62}
63
64static u32 choose_best_format(struct dp_display *dp,
65 struct drm_display_mode *mode)
66{
67 /*
68 * choose priority:
69 * 1. DC + RGB
70 * 2. DC + YUV422
71 * 3. DC + YUV420
72 * 4. RGB
73 * 5. YUV420
74 */
75 int dc_format;
76
77 dc_format = get_sink_dc_support(dp, mode);
78 if (dc_format & MSM_MODE_FLAG_RGB444_DC_ENABLE)
79 return (MSM_MODE_FLAG_COLOR_FORMAT_RGB444
80 | MSM_MODE_FLAG_RGB444_DC_ENABLE);
81 else if (dc_format & MSM_MODE_FLAG_YUV422_DC_ENABLE)
82 return (MSM_MODE_FLAG_COLOR_FORMAT_YCBCR422
83 | MSM_MODE_FLAG_YUV422_DC_ENABLE);
84 else if (dc_format & MSM_MODE_FLAG_YUV420_DC_ENABLE)
85 return (MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420
86 | MSM_MODE_FLAG_YUV420_DC_ENABLE);
87 else if (mode->flags & DRM_MODE_FLAG_SUPPORTS_RGB)
88 return MSM_MODE_FLAG_COLOR_FORMAT_RGB444;
89 else if (mode->flags & DRM_MODE_FLAG_SUPPORTS_YUV420)
90 return MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420;
91
92 pr_err("Can't get available best display format\n");
93
94 return MSM_MODE_FLAG_COLOR_FORMAT_RGB444;
95}
96
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -070097static void convert_to_dp_mode(const struct drm_display_mode *drm_mode,
Padmanabhan Komandurud0ed9c42017-05-23 02:56:08 -070098 struct dp_display_mode *dp_mode, struct dp_display *dp)
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -070099{
100 memset(dp_mode, 0, sizeof(*dp_mode));
101
Narender Ankamde426242019-12-23 20:54:31 +0530102 dp_mode->timing.out_format = MSM_MODE_FLAG_COLOR_FORMAT_RGB444;
103 if (drm_mode->private_flags & MSM_MODE_FLAG_COLOR_FORMAT_YCBCR422)
104 dp_mode->timing.out_format =
105 MSM_MODE_FLAG_COLOR_FORMAT_YCBCR422;
106 else if (drm_mode->private_flags & MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420)
107 dp_mode->timing.out_format =
108 MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420;
109
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -0700110 dp_mode->timing.h_active = drm_mode->hdisplay;
111 dp_mode->timing.h_back_porch = drm_mode->htotal - drm_mode->hsync_end;
112 dp_mode->timing.h_sync_width = drm_mode->htotal -
113 (drm_mode->hsync_start + dp_mode->timing.h_back_porch);
114 dp_mode->timing.h_front_porch = drm_mode->hsync_start -
115 drm_mode->hdisplay;
116 dp_mode->timing.h_skew = drm_mode->hskew;
117
118 dp_mode->timing.v_active = drm_mode->vdisplay;
119 dp_mode->timing.v_back_porch = drm_mode->vtotal - drm_mode->vsync_end;
120 dp_mode->timing.v_sync_width = drm_mode->vtotal -
121 (drm_mode->vsync_start + dp_mode->timing.v_back_porch);
122
123 dp_mode->timing.v_front_porch = drm_mode->vsync_start -
124 drm_mode->vdisplay;
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +0530125
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -0700126 dp_mode->timing.refresh_rate = drm_mode->vrefresh;
127
128 dp_mode->timing.pixel_clk_khz = drm_mode->clock;
129
130 dp_mode->timing.v_active_low =
131 !!(drm_mode->flags & DRM_MODE_FLAG_NVSYNC);
132
133 dp_mode->timing.h_active_low =
134 !!(drm_mode->flags & DRM_MODE_FLAG_NHSYNC);
Narender Ankamde426242019-12-23 20:54:31 +0530135
136 dp_mode->flags = drm_mode->flags;
Narender Ankam7f2aa152020-02-11 13:20:36 +0530137
138 dp_mode->timing.par = drm_mode->picture_aspect_ratio;
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -0700139}
140
141static void convert_to_drm_mode(const struct dp_display_mode *dp_mode,
142 struct drm_display_mode *drm_mode)
143{
144 u32 flags = 0;
145
146 memset(drm_mode, 0, sizeof(*drm_mode));
147
148 drm_mode->hdisplay = dp_mode->timing.h_active;
149 drm_mode->hsync_start = drm_mode->hdisplay +
150 dp_mode->timing.h_front_porch;
151 drm_mode->hsync_end = drm_mode->hsync_start +
152 dp_mode->timing.h_sync_width;
153 drm_mode->htotal = drm_mode->hsync_end + dp_mode->timing.h_back_porch;
154 drm_mode->hskew = dp_mode->timing.h_skew;
155
156 drm_mode->vdisplay = dp_mode->timing.v_active;
157 drm_mode->vsync_start = drm_mode->vdisplay +
158 dp_mode->timing.v_front_porch;
159 drm_mode->vsync_end = drm_mode->vsync_start +
160 dp_mode->timing.v_sync_width;
161 drm_mode->vtotal = drm_mode->vsync_end + dp_mode->timing.v_back_porch;
162
163 drm_mode->vrefresh = dp_mode->timing.refresh_rate;
164 drm_mode->clock = dp_mode->timing.pixel_clk_khz;
165
166 if (dp_mode->timing.h_active_low)
167 flags |= DRM_MODE_FLAG_NHSYNC;
168 else
169 flags |= DRM_MODE_FLAG_PHSYNC;
170
171 if (dp_mode->timing.v_active_low)
172 flags |= DRM_MODE_FLAG_NVSYNC;
173 else
174 flags |= DRM_MODE_FLAG_PVSYNC;
175
176 drm_mode->flags = flags;
Narender Ankamde426242019-12-23 20:54:31 +0530177 drm_mode->flags |= (dp_mode->flags & SDE_DRM_MODE_FLAG_FMT_MASK);
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -0700178
Narender Ankam7f2aa152020-02-11 13:20:36 +0530179 drm_mode->picture_aspect_ratio = dp_mode->timing.par;
180
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -0700181 drm_mode->type = 0x48;
182 drm_mode_set_name(drm_mode);
183}
184
185static int dp_bridge_attach(struct drm_bridge *dp_bridge)
186{
187 struct dp_bridge *bridge = to_dp_bridge(dp_bridge);
188
189 if (!dp_bridge) {
190 pr_err("Invalid params\n");
191 return -EINVAL;
192 }
193
194 pr_debug("[%d] attached\n", bridge->id);
195
196 return 0;
197}
198
199static void dp_bridge_pre_enable(struct drm_bridge *drm_bridge)
200{
201 int rc = 0;
202 struct dp_bridge *bridge;
203 struct dp_display *dp;
204
205 if (!drm_bridge) {
206 pr_err("Invalid params\n");
207 return;
208 }
209
210 bridge = to_dp_bridge(drm_bridge);
211 dp = bridge->display;
212
213 /* By this point mode should have been validated through mode_fixup */
214 rc = dp->set_mode(dp, &bridge->dp_mode);
215 if (rc) {
216 pr_err("[%d] failed to perform a mode set, rc=%d\n",
217 bridge->id, rc);
218 return;
219 }
220
221 rc = dp->prepare(dp);
222 if (rc) {
223 pr_err("[%d] DP display prepare failed, rc=%d\n",
224 bridge->id, rc);
225 return;
226 }
227
228 rc = dp->enable(dp);
229 if (rc) {
230 pr_err("[%d] DP display enable failed, rc=%d\n",
231 bridge->id, rc);
232 dp->unprepare(dp);
233 }
Narender Ankamde426242019-12-23 20:54:31 +0530234
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -0700235}
236
237static void dp_bridge_enable(struct drm_bridge *drm_bridge)
238{
239 int rc = 0;
240 struct dp_bridge *bridge;
241 struct dp_display *dp;
242
243 if (!drm_bridge) {
244 pr_err("Invalid params\n");
245 return;
246 }
247
248 bridge = to_dp_bridge(drm_bridge);
249 dp = bridge->display;
250
251 rc = dp->post_enable(dp);
252 if (rc)
253 pr_err("[%d] DP display post enable failed, rc=%d\n",
254 bridge->id, rc);
255}
256
257static void dp_bridge_disable(struct drm_bridge *drm_bridge)
258{
259 int rc = 0;
260 struct dp_bridge *bridge;
261 struct dp_display *dp;
262
263 if (!drm_bridge) {
264 pr_err("Invalid params\n");
265 return;
266 }
267
268 bridge = to_dp_bridge(drm_bridge);
269 dp = bridge->display;
270
Jayant Shekhar67ad2a92018-03-01 11:32:23 +0530271 if (!dp) {
272 pr_err("dp is null\n");
273 return;
274 }
275
276 if (dp->connector)
Clarence Ip458a5d02017-11-27 18:15:16 -0500277 sde_connector_helper_bridge_disable(dp->connector);
278
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -0700279 rc = dp->pre_disable(dp);
280 if (rc) {
281 pr_err("[%d] DP display pre disable failed, rc=%d\n",
282 bridge->id, rc);
283 }
284}
285
286static void dp_bridge_post_disable(struct drm_bridge *drm_bridge)
287{
288 int rc = 0;
289 struct dp_bridge *bridge;
290 struct dp_display *dp;
291
292 if (!drm_bridge) {
293 pr_err("Invalid params\n");
294 return;
295 }
296
297 bridge = to_dp_bridge(drm_bridge);
298 dp = bridge->display;
299
300 rc = dp->disable(dp);
301 if (rc) {
302 pr_err("[%d] DP display disable failed, rc=%d\n",
303 bridge->id, rc);
304 return;
305 }
306
307 rc = dp->unprepare(dp);
308 if (rc) {
309 pr_err("[%d] DP display unprepare failed, rc=%d\n",
310 bridge->id, rc);
311 return;
312 }
313}
314
315static void dp_bridge_mode_set(struct drm_bridge *drm_bridge,
316 struct drm_display_mode *mode,
317 struct drm_display_mode *adjusted_mode)
318{
319 struct dp_bridge *bridge;
320 struct dp_display *dp;
321
322 if (!drm_bridge || !mode || !adjusted_mode) {
323 pr_err("Invalid params\n");
324 return;
325 }
326
327 bridge = to_dp_bridge(drm_bridge);
328 dp = bridge->display;
329
330 memset(&bridge->dp_mode, 0x0, sizeof(struct dp_display_mode));
Padmanabhan Komandurud0ed9c42017-05-23 02:56:08 -0700331 convert_to_dp_mode(adjusted_mode, &bridge->dp_mode, dp);
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -0700332}
333
334static bool dp_bridge_mode_fixup(struct drm_bridge *drm_bridge,
335 const struct drm_display_mode *mode,
336 struct drm_display_mode *adjusted_mode)
337{
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -0700338 bool ret = true;
339 struct dp_display_mode dp_mode;
340 struct dp_bridge *bridge;
341 struct dp_display *dp;
342
343 if (!drm_bridge || !mode || !adjusted_mode) {
344 pr_err("Invalid params\n");
345 ret = false;
346 goto end;
347 }
348
349 bridge = to_dp_bridge(drm_bridge);
350 dp = bridge->display;
351
Padmanabhan Komandurud0ed9c42017-05-23 02:56:08 -0700352 convert_to_dp_mode(mode, &dp_mode, dp);
Tatenda Chipeperekwa8a44bd92017-10-05 16:32:06 -0700353 convert_to_drm_mode(&dp_mode, adjusted_mode);
Narender Ankamde426242019-12-23 20:54:31 +0530354
355 /* Clear the private flags before assigning new one */
356 adjusted_mode->private_flags = 0;
357
358 adjusted_mode->private_flags |=
359 choose_best_format(dp, adjusted_mode);
360 SDE_DEBUG("Adjusted mode private flags: 0x%x\n",
361 adjusted_mode->private_flags);
362
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -0700363end:
364 return ret;
365}
366
367static const struct drm_bridge_funcs dp_bridge_ops = {
368 .attach = dp_bridge_attach,
369 .mode_fixup = dp_bridge_mode_fixup,
370 .pre_enable = dp_bridge_pre_enable,
371 .enable = dp_bridge_enable,
372 .disable = dp_bridge_disable,
373 .post_disable = dp_bridge_post_disable,
374 .mode_set = dp_bridge_mode_set,
375};
376
Ajay Singh Parmar87af50b2017-12-22 22:22:55 -0800377int dp_connector_config_hdr(void *display,
378 struct sde_connector_state *c_state)
Ajay Singh Parmar9c842d42017-09-21 13:02:05 -0700379{
380 struct dp_display *dp = display;
381
Ajay Singh Parmar87af50b2017-12-22 22:22:55 -0800382 if (!display || !c_state) {
Ajay Singh Parmar9c842d42017-09-21 13:02:05 -0700383 pr_err("invalid params\n");
384 return -EINVAL;
385 }
386
Ajay Singh Parmar87af50b2017-12-22 22:22:55 -0800387 return dp->config_hdr(dp, &c_state->hdr_meta);
Ajay Singh Parmar9c842d42017-09-21 13:02:05 -0700388}
389
Alan Kwong769fba92017-11-13 16:50:36 -0500390int dp_connector_post_init(struct drm_connector *connector, void *display)
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -0700391{
392 struct dp_display *dp_display = display;
393
Alan Kwong769fba92017-11-13 16:50:36 -0500394 if (!dp_display)
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -0700395 return -EINVAL;
396
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700397 dp_display->connector = connector;
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800398
399 if (dp_display->post_init)
400 dp_display->post_init(dp_display);
401
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -0700402 return 0;
403}
404
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -0700405int dp_connector_get_mode_info(const struct drm_display_mode *drm_mode,
Alan Kwongb1bca602017-09-18 17:28:45 -0400406 struct msm_mode_info *mode_info, u32 max_mixer_width, void *display)
Tatenda Chipeperekwa9f2abe12017-05-25 12:06:22 -0700407{
408 const u32 dual_lm = 2;
409 const u32 single_lm = 1;
410 const u32 single_intf = 1;
411 const u32 no_enc = 0;
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -0700412 struct msm_display_topology *topology;
Tatenda Chipeperekwa9f2abe12017-05-25 12:06:22 -0700413
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -0700414 if (!drm_mode || !mode_info || !max_mixer_width) {
Tatenda Chipeperekwa9f2abe12017-05-25 12:06:22 -0700415 pr_err("invalid params\n");
416 return -EINVAL;
417 }
418
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -0700419 topology = &mode_info->topology;
Tatenda Chipeperekwa9f2abe12017-05-25 12:06:22 -0700420 topology->num_lm = (max_mixer_width <= drm_mode->hdisplay) ?
421 dual_lm : single_lm;
422 topology->num_enc = no_enc;
423 topology->num_intf = single_intf;
424
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -0700425 mode_info->frame_rate = drm_mode->vrefresh;
426 mode_info->vtotal = drm_mode->vtotal;
427 mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE;
428
Tatenda Chipeperekwa9f2abe12017-05-25 12:06:22 -0700429 return 0;
430}
431
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -0700432int dp_connector_get_info(struct msm_display_info *info, void *data)
433{
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700434 struct dp_display *display = data;
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -0700435
436 if (!info || !display) {
437 pr_err("invalid params\n");
438 return -EINVAL;
439 }
440
441 info->intf_type = DRM_MODE_CONNECTOR_DisplayPort;
442
443 info->num_of_h_tiles = 1;
444 info->h_tile_instance[0] = 0;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700445 info->is_connected = display->is_connected;
Narender Ankam96d70542019-12-12 14:42:59 +0530446 info->is_primary = display->is_primary;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700447 info->capabilities = MSM_DISPLAY_CAP_VID_MODE | MSM_DISPLAY_CAP_EDID |
448 MSM_DISPLAY_CAP_HOT_PLUG;
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -0700449
450 return 0;
451}
452
Chirag Khuranace2aa512019-11-20 18:27:03 +0530453bool dp_connector_mode_needs_full_range(void *data)
454{
455 struct dp_display *display = data;
456 struct dp_bridge *bridge;
457 struct dp_display_mode *mode;
458 struct dp_panel_info *timing;
459
460 if (!display) {
461 pr_err("invalid input\n");
462 return false;
463 }
464
465 bridge = display->bridge;
466 if (!bridge) {
467 pr_err("invalid bridge data\n");
468 return false;
469 }
470
471 mode = &bridge->dp_mode;
472 timing = &mode->timing;
473
474 if (timing->h_active == 640 &&
475 timing->v_active == 480)
476 return true;
477
478 return false;
479}
480
Narender Ankam7f2aa152020-02-11 13:20:36 +0530481bool dp_connector_mode_is_cea_mode(void *data)
482{
483 struct dp_display *display = data;
484 struct dp_bridge *bridge;
485 struct dp_display_mode *mode;
486 struct drm_display_mode drm_mode;
487 struct dp_panel_info *timing;
488 bool is_ce_mode = false;
489
490 if (!display) {
491 pr_err("invalid input\n");
492 return false;
493 }
494
495 bridge = display->bridge;
496 if (!bridge) {
497 pr_err("invalid bridge data\n");
498 return false;
499 }
500
501 mode = &bridge->dp_mode;
502 timing = &mode->timing;
503
504 if (timing->h_active == 640 &&
505 timing->v_active == 480)
506 is_ce_mode = false;
507
508 convert_to_drm_mode(mode, &drm_mode);
509 drm_mode.flags &= ~SDE_DRM_MODE_FLAG_FMT_MASK;
510
511 if (drm_match_cea_mode(&drm_mode) || drm_match_hdmi_mode(&drm_mode))
512 is_ce_mode = true;
513
514 pr_debug("%s: %s : %s video format\n", __func__,
515 drm_mode.name, is_ce_mode ? "CE" : "IT");
516
517 return is_ce_mode;
518}
519
Narender Ankam1afbd172020-03-16 17:27:44 +0530520enum sde_csc_type dp_connector_get_csc_type(struct drm_connector *conn,
521 void *data)
522{
523 struct dp_display *display = data;
524 struct sde_connector_state *c_state;
525 struct drm_msm_ext_hdr_metadata *hdr_meta;
526
527 if (!display || !conn) {
528 pr_err("invalid input\n");
529 goto error;
530 }
531
532 c_state = to_sde_connector_state(conn->state);
533
534 if (!c_state) {
535 pr_err("invalid input\n");
536 goto error;
537 }
538
539 hdr_meta = &c_state->hdr_meta;
540
541 if ((hdr_meta->hdr_state == HDR_ENABLE)
542 && (hdr_meta->eotf != 0))
543 return SDE_CSC_RGB2YUV_2020L;
544 else if (dp_connector_mode_needs_full_range(data)
545 || conn->yuv_qs)
Narender Ankam7f2aa152020-02-11 13:20:36 +0530546 return SDE_CSC_RGB2YUV_709FR;
Narender Ankam1afbd172020-03-16 17:27:44 +0530547
548error:
Narender Ankam7f2aa152020-02-11 13:20:36 +0530549 return SDE_CSC_RGB2YUV_709L;
Narender Ankam1afbd172020-03-16 17:27:44 +0530550}
551
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -0700552enum drm_connector_status dp_connector_detect(struct drm_connector *conn,
553 bool force,
554 void *display)
555{
556 enum drm_connector_status status = connector_status_unknown;
557 struct msm_display_info info;
558 int rc;
559
560 if (!conn || !display)
561 return status;
562
563 /* get display dp_info */
564 memset(&info, 0x0, sizeof(info));
565 rc = dp_connector_get_info(&info, display);
566 if (rc) {
567 pr_err("failed to get display info, rc=%d\n", rc);
568 return connector_status_disconnected;
569 }
570
571 if (info.capabilities & MSM_DISPLAY_CAP_HOT_PLUG)
572 status = (info.is_connected ? connector_status_connected :
573 connector_status_disconnected);
574 else
575 status = connector_status_connected;
576
577 conn->display_info.width_mm = info.width_mm;
578 conn->display_info.height_mm = info.height_mm;
579
580 return status;
581}
582
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800583void dp_connector_post_open(void *display)
Padmanabhan Komanduru71aec2d2017-08-30 20:07:59 +0530584{
585 struct dp_display *dp;
586
587 if (!display) {
588 pr_err("invalid input\n");
589 return;
590 }
591
592 dp = display;
593
Ajay Singh Parmar315e5852017-11-23 21:47:32 -0800594 if (dp->post_open)
595 dp->post_open(dp);
Padmanabhan Komanduru71aec2d2017-08-30 20:07:59 +0530596}
597
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -0700598int dp_connector_get_modes(struct drm_connector *connector,
599 void *display)
600{
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700601 int rc = 0;
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -0700602 struct dp_display *dp;
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +0530603 struct dp_display_mode *dp_mode = NULL;
604 struct drm_display_mode *m, drm_mode;
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -0700605
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700606 if (!connector || !display)
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +0530607 return 0;
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -0700608
609 dp = display;
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +0530610
611 dp_mode = kzalloc(sizeof(*dp_mode), GFP_KERNEL);
612 if (!dp_mode)
613 return 0;
614
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700615 /* pluggable case assumes EDID is read when HPD */
616 if (dp->is_connected) {
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +0530617 rc = dp->get_modes(dp, dp_mode);
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700618 if (!rc)
619 pr_err("failed to get DP sink modes, rc=%d\n", rc);
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +0530620
621 if (dp_mode->timing.pixel_clk_khz) { /* valid DP mode */
622 memset(&drm_mode, 0x0, sizeof(drm_mode));
623 convert_to_drm_mode(dp_mode, &drm_mode);
624 m = drm_mode_duplicate(connector->dev, &drm_mode);
625 if (!m) {
626 pr_err("failed to add mode %ux%u\n",
627 drm_mode.hdisplay,
628 drm_mode.vdisplay);
629 kfree(dp_mode);
630 return 0;
631 }
632 m->width_mm = connector->display_info.width_mm;
633 m->height_mm = connector->display_info.height_mm;
634 drm_mode_probed_add(connector, m);
635 }
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700636 } else {
637 pr_err("No sink connected\n");
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -0700638 }
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +0530639 kfree(dp_mode);
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -0700640
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +0530641 return rc;
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -0700642}
643
Narender Ankam96d70542019-12-12 14:42:59 +0530644int dp_connnector_set_info_blob(struct drm_connector *connector,
645 void *info, void *display, struct msm_mode_info *mode_info)
646{
647 struct dp_display *dp_display = display;
648 const char *display_type = NULL;
649
650 dp_display->get_display_type(dp_display, &display_type);
651 sde_kms_info_add_keystr(info,
652 "display type", display_type);
653
654 return 0;
655}
656
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -0700657int dp_drm_bridge_init(void *data, struct drm_encoder *encoder)
658{
659 int rc = 0;
660 struct dp_bridge *bridge;
661 struct drm_device *dev;
662 struct dp_display *display = data;
663 struct msm_drm_private *priv = NULL;
664
665 bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
666 if (!bridge) {
667 rc = -ENOMEM;
668 goto error;
669 }
670
671 dev = display->drm_dev;
672 bridge->display = display;
673 bridge->base.funcs = &dp_bridge_ops;
674 bridge->base.encoder = encoder;
675
676 priv = dev->dev_private;
677
678 rc = drm_bridge_attach(dev, &bridge->base);
679 if (rc) {
680 pr_err("failed to attach bridge, rc=%d\n", rc);
681 goto error_free_bridge;
682 }
683
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -0700684 rc = display->request_irq(display);
685 if (rc) {
686 pr_err("request_irq failed, rc=%d\n", rc);
687 goto error_free_bridge;
688 }
689
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -0700690 encoder->bridge = &bridge->base;
691 priv->bridges[priv->num_bridges++] = &bridge->base;
692 display->bridge = bridge;
693
694 return 0;
695error_free_bridge:
696 kfree(bridge);
697error:
698 return rc;
699}
700
701void dp_drm_bridge_deinit(void *data)
702{
703 struct dp_display *display = data;
704 struct dp_bridge *bridge = display->bridge;
705
706 if (bridge && bridge->base.encoder)
707 bridge->base.encoder->bridge = NULL;
708
709 kfree(bridge);
710}
711
712enum drm_mode_status dp_connector_mode_valid(struct drm_connector *connector,
713 struct drm_display_mode *mode,
714 void *display)
715{
Padmanabhan Komandurud5eae9d2017-06-22 19:23:36 +0530716 struct dp_display *dp_disp;
Samantha Tran2d1ed732017-07-31 17:30:14 -0700717 struct dp_debug *debug;
Narender Ankamde426242019-12-23 20:54:31 +0530718 u32 pclk = 0;
719 u32 rate_ratio = RGB_24BPP_TMDS_CHAR_RATE_RATIO;
Padmanabhan Komandurud5eae9d2017-06-22 19:23:36 +0530720
721 if (!mode || !display) {
722 pr_err("invalid params\n");
723 return MODE_ERROR;
724 }
725
726 dp_disp = display;
Samantha Tran2d1ed732017-07-31 17:30:14 -0700727 debug = dp_disp->get_debug(dp_disp);
Padmanabhan Komandurud5eae9d2017-06-22 19:23:36 +0530728
Tatenda Chipeperekwa59510402017-09-28 12:50:58 -0700729 mode->vrefresh = drm_mode_vrefresh(mode);
Padmanabhan Komandurufdafc412017-09-11 13:13:38 +0530730
Narender Ankamb6e39e52019-12-25 21:48:19 +0530731 if (!dp_disp->yuv_support) {
732 mode->flags &= ~DRM_MODE_FLAG_SUPPORTS_YUV420;
733 mode->flags &= ~DRM_MODE_FLAG_SUPPORTS_YUV422;
734 }
735
Narender Ankam71580a02019-12-27 14:43:29 +0530736 if (!dp_disp->vsc_sdp_supported(dp_disp))
737 mode->flags &= ~DRM_MODE_FLAG_SUPPORTS_YUV420;
738
739 if (!(mode->flags & SDE_DRM_MODE_FLAG_FMT_MASK))
740 return MODE_BAD;
741
Narender Ankamde426242019-12-23 20:54:31 +0530742 if ((mode->flags & SDE_DRM_MODE_FLAG_FMT_MASK) ==
743 DRM_MODE_FLAG_SUPPORTS_YUV420) {
744 rate_ratio = YUV420_24BPP_TMDS_CHAR_RATE_RATIO;
745 } else if ((mode->flags & DRM_MODE_FLAG_SUPPORTS_RGB) &&
746 (mode->flags & DRM_MODE_FLAG_SUPPORTS_YUV420)) {
747 if (mode->clock > dp_disp->max_pclk_khz) {
748 /* Clear RGB and YUV422 support flags */
749 mode->flags &= ~DRM_MODE_FLAG_SUPPORTS_RGB;
750 mode->flags &= ~DRM_MODE_FLAG_SUPPORTS_YUV422;
751 /* Only YUV420 format is now supported */
752 rate_ratio = YUV420_24BPP_TMDS_CHAR_RATE_RATIO;
753 }
754 }
755
756 pclk = mode->clock / rate_ratio;
757
758 if (pclk > dp_disp->max_pclk_khz)
Tatenda Chipeperekwa59510402017-09-28 12:50:58 -0700759 return MODE_BAD;
760
761 if (debug->debug_en && (mode->hdisplay != debug->hdisplay ||
762 mode->vdisplay != debug->vdisplay ||
763 mode->vrefresh != debug->vrefresh ||
764 mode->picture_aspect_ratio != debug->aspect_ratio))
765 return MODE_BAD;
766
Narender Ankamde426242019-12-23 20:54:31 +0530767 return dp_disp->validate_mode(dp_disp, pclk, mode->flags);
Ajay Singh Parmar0d6250b2017-04-02 14:08:51 -0700768}