blob: 6bc69cb1e5786c4f05974c5ff6b8f8e3ba99d0b6 [file] [log] [blame]
Clarence Ipdd8021c2016-07-20 16:39:47 -04001/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#define pr_fmt(fmt) "sde-drm:[%s] " fmt, __func__
14#include "msm_drv.h"
15
16#include "sde_kms.h"
17#include "sde_connector.h"
Vishnuvardhan Prodduturi75b96802016-10-17 18:45:55 +053018#include "sde_backlight.h"
Clarence Ipdd8021c2016-07-20 16:39:47 -040019
Lloyd Atkinsonb6191972016-08-10 18:31:46 -040020static const struct drm_prop_enum_list e_topology_name[] = {
21 {SDE_RM_TOPOLOGY_UNKNOWN, "sde_unknown"},
22 {SDE_RM_TOPOLOGY_SINGLEPIPE, "sde_singlepipe"},
23 {SDE_RM_TOPOLOGY_DUALPIPE, "sde_dualpipe"},
24 {SDE_RM_TOPOLOGY_PPSPLIT, "sde_ppsplit"},
25 {SDE_RM_TOPOLOGY_DUALPIPEMERGE, "sde_dualpipemerge"}
26};
27static const struct drm_prop_enum_list e_topology_control[] = {
28 {SDE_RM_TOPCTL_RESERVE_LOCK, "reserve_lock"},
29 {SDE_RM_TOPCTL_RESERVE_CLEAR, "reserve_clear"},
30 {SDE_RM_TOPCTL_DSPP, "dspp"},
31 {SDE_RM_TOPCTL_FORCE_TILING, "force_tiling"},
32 {SDE_RM_TOPCTL_PPSPLIT, "ppsplit"}
33};
34
Clarence Ipcb3afd42016-07-15 16:25:34 -040035int sde_connector_get_info(struct drm_connector *connector,
36 struct msm_display_info *info)
37{
38 struct sde_connector *c_conn;
39
40 if (!connector || !info) {
41 SDE_ERROR("invalid argument(s), conn %pK, info %pK\n",
42 connector, info);
43 return -EINVAL;
44 }
45
46 c_conn = to_sde_connector(connector);
47
48 if (!c_conn->display || !c_conn->ops.get_info) {
49 SDE_ERROR("display info not supported for %pK\n",
50 c_conn->display);
51 return -EINVAL;
52 }
53
54 return c_conn->ops.get_info(info, c_conn->display);
55}
56
Clarence Ipdd8021c2016-07-20 16:39:47 -040057static void sde_connector_destroy(struct drm_connector *connector)
58{
59 struct sde_connector *c_conn;
60
61 if (!connector) {
62 SDE_ERROR("invalid connector\n");
63 return;
64 }
65
66 c_conn = to_sde_connector(connector);
67
Dhaval Patel4e574842016-08-23 15:11:37 -070068 if (c_conn->blob_caps)
69 drm_property_unreference_blob(c_conn->blob_caps);
Clarence Ipdd8021c2016-07-20 16:39:47 -040070 msm_property_destroy(&c_conn->property_info);
71
72 drm_connector_unregister(connector);
Clarence Ipe59fb3f2016-07-26 13:39:59 -040073 sde_fence_deinit(&c_conn->retire_fence);
Clarence Ipdd8021c2016-07-20 16:39:47 -040074 drm_connector_cleanup(connector);
75 kfree(c_conn);
76}
77
78/**
79 * _sde_connector_destroy_fb - clean up connector state's out_fb buffer
80 * @c_conn: Pointer to sde connector structure
81 * @c_state: Pointer to sde connector state structure
82 */
83static void _sde_connector_destroy_fb(struct sde_connector *c_conn,
84 struct sde_connector_state *c_state)
85{
86 if (!c_state || !c_state->out_fb) {
87 SDE_ERROR("invalid state %pK\n", c_state);
88 return;
89 }
90
91 msm_framebuffer_cleanup(c_state->out_fb,
92 c_state->mmu_id);
93 drm_framebuffer_unreference(c_state->out_fb);
94 c_state->out_fb = NULL;
95
96 if (c_conn) {
97 c_state->property_values[CONNECTOR_PROP_OUT_FB] =
98 msm_property_get_default(&c_conn->property_info,
99 CONNECTOR_PROP_OUT_FB);
100 } else {
101 c_state->property_values[CONNECTOR_PROP_OUT_FB] = ~0;
102 }
103}
104
105static void sde_connector_atomic_destroy_state(struct drm_connector *connector,
106 struct drm_connector_state *state)
107{
108 struct sde_connector *c_conn = NULL;
109 struct sde_connector_state *c_state = NULL;
110
111 if (!state) {
112 SDE_ERROR("invalid state\n");
113 return;
114 }
115
116 /*
117 * The base DRM framework currently always passes in a NULL
118 * connector pointer. This is not correct, but attempt to
119 * handle that case as much as possible.
120 */
121 if (connector)
122 c_conn = to_sde_connector(connector);
123 c_state = to_sde_connector_state(state);
124
125 if (c_state->out_fb)
126 _sde_connector_destroy_fb(c_conn, c_state);
127
128 if (!c_conn) {
129 kfree(c_state);
130 } else {
131 /* destroy value helper */
132 msm_property_destroy_state(&c_conn->property_info, c_state,
133 c_state->property_values, 0);
134 }
135}
136
137static void sde_connector_atomic_reset(struct drm_connector *connector)
138{
139 struct sde_connector *c_conn;
140 struct sde_connector_state *c_state;
141
142 if (!connector) {
143 SDE_ERROR("invalid connector\n");
144 return;
145 }
146
147 c_conn = to_sde_connector(connector);
148
149 if (connector->state) {
150 sde_connector_atomic_destroy_state(connector, connector->state);
151 connector->state = 0;
152 }
153
154 c_state = msm_property_alloc_state(&c_conn->property_info);
155 if (!c_state) {
156 SDE_ERROR("state alloc failed\n");
157 return;
158 }
159
160 /* reset value helper, zero out state structure and reset properties */
161 msm_property_reset_state(&c_conn->property_info, c_state,
162 c_state->property_values, 0);
163
164 c_state->base.connector = connector;
165 connector->state = &c_state->base;
166}
167
168static struct drm_connector_state *
169sde_connector_atomic_duplicate_state(struct drm_connector *connector)
170{
171 struct sde_connector *c_conn;
172 struct sde_connector_state *c_state, *c_oldstate;
173 int rc;
174
175 if (!connector || !connector->state) {
176 SDE_ERROR("invalid connector %pK\n", connector);
177 return NULL;
178 }
179
180 c_conn = to_sde_connector(connector);
181 c_oldstate = to_sde_connector_state(connector->state);
182 c_state = msm_property_alloc_state(&c_conn->property_info);
183 if (!c_state) {
184 SDE_ERROR("state alloc failed\n");
185 return NULL;
186 }
187
188 /* duplicate value helper */
189 msm_property_duplicate_state(&c_conn->property_info,
190 c_oldstate, c_state, c_state->property_values, 0);
191
192 /* additional handling for drm framebuffer objects */
193 if (c_state->out_fb) {
194 drm_framebuffer_reference(c_state->out_fb);
195 rc = msm_framebuffer_prepare(c_state->out_fb,
196 c_state->mmu_id);
197 if (rc)
198 SDE_ERROR("failed to prepare fb, %d\n", rc);
199 }
200
201 return &c_state->base;
202}
203
204static int sde_connector_atomic_set_property(struct drm_connector *connector,
205 struct drm_connector_state *state,
206 struct drm_property *property,
207 uint64_t val)
208{
209 struct sde_connector *c_conn;
210 struct sde_connector_state *c_state;
211 int idx, rc;
212
213 if (!connector || !state || !property) {
214 SDE_ERROR("invalid argument(s), conn %pK, state %pK, prp %pK\n",
215 connector, state, property);
216 return -EINVAL;
217 }
218
219 c_conn = to_sde_connector(connector);
220 c_state = to_sde_connector_state(state);
221
222 /* generic property handling */
223 rc = msm_property_atomic_set(&c_conn->property_info,
224 c_state->property_values, 0, property, val);
225 if (rc)
226 goto end;
227
228 /* connector-specific property handling */
229 idx = msm_property_index(&c_conn->property_info, property);
230
231 if (idx == CONNECTOR_PROP_OUT_FB) {
232 /* clear old fb, if present */
233 if (c_state->out_fb)
234 _sde_connector_destroy_fb(c_conn, c_state);
235
236 /* convert fb val to drm framebuffer and prepare it */
237 c_state->out_fb =
238 drm_framebuffer_lookup(connector->dev, val);
239 if (!c_state->out_fb) {
240 SDE_ERROR("failed to look up fb %lld\n", val);
241 rc = -EFAULT;
242 } else {
Alan Kwongdfa8c082016-07-29 04:10:00 -0400243 if (c_state->out_fb->flags & DRM_MODE_FB_SECURE)
244 c_state->mmu_id =
245 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE];
246 else
247 c_state->mmu_id =
248 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE];
Clarence Ipdd8021c2016-07-20 16:39:47 -0400249
250 rc = msm_framebuffer_prepare(c_state->out_fb,
251 c_state->mmu_id);
252 if (rc)
253 SDE_ERROR("prep fb failed, %d\n", rc);
254 }
255 }
256
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400257 if (idx == CONNECTOR_PROP_TOPOLOGY_CONTROL) {
258 rc = sde_rm_check_property_topctl(val);
259 if (rc)
260 SDE_ERROR("invalid topology_control: 0x%llX\n", val);
261 }
262
Clarence Ipdd8021c2016-07-20 16:39:47 -0400263 /* check for custom property handling */
264 if (!rc && c_conn->ops.set_property) {
265 rc = c_conn->ops.set_property(connector,
266 state,
267 idx,
268 val,
269 c_conn->display);
270
271 /* potentially clean up out_fb if rc != 0 */
272 if ((idx == CONNECTOR_PROP_OUT_FB) && rc)
273 _sde_connector_destroy_fb(c_conn, c_state);
274 }
275end:
276 return rc;
277}
278
279static int sde_connector_set_property(struct drm_connector *connector,
280 struct drm_property *property,
281 uint64_t val)
282{
283 if (!connector) {
284 SDE_ERROR("invalid connector\n");
285 return -EINVAL;
286 }
287
288 return sde_connector_atomic_set_property(connector,
289 connector->state, property, val);
290}
291
292static int sde_connector_atomic_get_property(struct drm_connector *connector,
293 const struct drm_connector_state *state,
294 struct drm_property *property,
295 uint64_t *val)
296{
297 struct sde_connector *c_conn;
298 struct sde_connector_state *c_state;
299 int idx, rc = -EINVAL;
300
301 if (!connector || !state) {
302 SDE_ERROR("invalid argument(s), conn %pK, state %pK\n",
303 connector, state);
304 return -EINVAL;
305 }
306
307 c_conn = to_sde_connector(connector);
308 c_state = to_sde_connector_state(state);
309
310 idx = msm_property_index(&c_conn->property_info, property);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400311 if (idx == CONNECTOR_PROP_RETIRE_FENCE)
Clarence Ip9a74a442016-08-25 18:29:03 -0400312 /*
313 * Set a fence offset if not a virtual connector, so that the
314 * fence signals after one additional commit rather than at the
315 * end of the current one.
316 */
317 rc = sde_fence_create(&c_conn->retire_fence, val,
318 c_conn->connector_type != DRM_MODE_CONNECTOR_VIRTUAL);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400319 else
320 /* get cached property value */
321 rc = msm_property_atomic_get(&c_conn->property_info,
322 c_state->property_values, 0, property, val);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400323
324 /* allow for custom override */
325 if (c_conn->ops.get_property)
326 rc = c_conn->ops.get_property(connector,
327 (struct drm_connector_state *)state,
328 idx,
329 val,
330 c_conn->display);
331 return rc;
332}
333
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400334void sde_connector_prepare_fence(struct drm_connector *connector)
335{
336 if (!connector) {
337 SDE_ERROR("invalid connector\n");
338 return;
339 }
340
341 sde_fence_prepare(&to_sde_connector(connector)->retire_fence);
342}
343
344void sde_connector_complete_commit(struct drm_connector *connector)
345{
346 if (!connector) {
347 SDE_ERROR("invalid connector\n");
348 return;
349 }
350
351 /* signal connector's retire fence */
352 sde_fence_signal(&to_sde_connector(connector)->retire_fence, 0);
353}
354
Clarence Ipdd8021c2016-07-20 16:39:47 -0400355static enum drm_connector_status
356sde_connector_detect(struct drm_connector *connector, bool force)
357{
358 enum drm_connector_status status = connector_status_unknown;
359 struct sde_connector *c_conn;
360
361 if (!connector) {
362 SDE_ERROR("invalid connector\n");
363 return status;
364 }
365
366 c_conn = to_sde_connector(connector);
367
368 if (c_conn->ops.detect)
369 status = c_conn->ops.detect(connector,
370 force,
371 c_conn->display);
372
373 return status;
374}
375
376static const struct drm_connector_funcs sde_connector_ops = {
377 .dpms = drm_atomic_helper_connector_dpms,
378 .reset = sde_connector_atomic_reset,
379 .detect = sde_connector_detect,
380 .destroy = sde_connector_destroy,
381 .fill_modes = drm_helper_probe_single_connector_modes,
382 .atomic_duplicate_state = sde_connector_atomic_duplicate_state,
383 .atomic_destroy_state = sde_connector_atomic_destroy_state,
384 .atomic_set_property = sde_connector_atomic_set_property,
385 .atomic_get_property = sde_connector_atomic_get_property,
386 .set_property = sde_connector_set_property,
387};
388
389static int sde_connector_get_modes(struct drm_connector *connector)
390{
391 struct sde_connector *c_conn;
392
393 if (!connector) {
394 SDE_ERROR("invalid connector\n");
395 return 0;
396 }
397
398 c_conn = to_sde_connector(connector);
399 if (!c_conn->ops.get_modes) {
400 SDE_DEBUG("missing get_modes callback\n");
401 return 0;
402 }
403
404 return c_conn->ops.get_modes(connector, c_conn->display);
405}
406
407static enum drm_mode_status
408sde_connector_mode_valid(struct drm_connector *connector,
409 struct drm_display_mode *mode)
410{
411 struct sde_connector *c_conn;
412
413 if (!connector || !mode) {
414 SDE_ERROR("invalid argument(s), conn %pK, mode %pK\n",
415 connector, mode);
416 return MODE_ERROR;
417 }
418
419 c_conn = to_sde_connector(connector);
420
421 if (c_conn->ops.mode_valid)
422 return c_conn->ops.mode_valid(connector, mode, c_conn->display);
423
424 /* assume all modes okay by default */
425 return MODE_OK;
426}
427
428static struct drm_encoder *
429sde_connector_best_encoder(struct drm_connector *connector)
430{
431 struct sde_connector *c_conn = to_sde_connector(connector);
432
433 if (!connector) {
434 SDE_ERROR("invalid connector\n");
435 return NULL;
436 }
437
438 /*
439 * This is true for now, revisit this code when multiple encoders are
440 * supported.
441 */
442 return c_conn->encoder;
443}
444
445static const struct drm_connector_helper_funcs sde_connector_helper_ops = {
446 .get_modes = sde_connector_get_modes,
447 .mode_valid = sde_connector_mode_valid,
448 .best_encoder = sde_connector_best_encoder,
449};
450
451struct drm_connector *sde_connector_init(struct drm_device *dev,
452 struct drm_encoder *encoder,
453 struct drm_panel *panel,
454 void *display,
455 const struct sde_connector_ops *ops,
456 int connector_poll,
457 int connector_type)
458{
459 struct msm_drm_private *priv;
460 struct sde_kms *sde_kms;
461 struct sde_kms_info *info;
462 struct sde_connector *c_conn = NULL;
463 int rc;
464
465 if (!dev || !dev->dev_private || !encoder) {
466 SDE_ERROR("invalid argument(s), dev %pK, enc %pK\n",
467 dev, encoder);
468 return ERR_PTR(-EINVAL);
469 }
470
471 priv = dev->dev_private;
472 if (!priv->kms) {
473 SDE_ERROR("invalid kms reference\n");
474 return ERR_PTR(-EINVAL);
475 }
476
477 c_conn = kzalloc(sizeof(*c_conn), GFP_KERNEL);
478 if (!c_conn) {
479 SDE_ERROR("failed to alloc sde connector\n");
480 return ERR_PTR(-ENOMEM);
481 }
482
483 rc = drm_connector_init(dev,
484 &c_conn->base,
485 &sde_connector_ops,
486 connector_type);
487 if (rc)
488 goto error_free_conn;
489
490 c_conn->connector_type = connector_type;
491 c_conn->encoder = encoder;
492 c_conn->panel = panel;
493 c_conn->display = display;
494
Alan Kwongdfa8c082016-07-29 04:10:00 -0400495 /* cache mmu_id's for later */
Clarence Ipdd8021c2016-07-20 16:39:47 -0400496 sde_kms = to_sde_kms(priv->kms);
Alan Kwongdfa8c082016-07-29 04:10:00 -0400497 if (sde_kms->vbif[VBIF_NRT]) {
498 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] =
499 sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_UNSECURE];
500 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE] =
501 sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_SECURE];
502 } else {
503 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] =
504 sde_kms->mmu_id[MSM_SMMU_DOMAIN_UNSECURE];
505 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE] =
506 sde_kms->mmu_id[MSM_SMMU_DOMAIN_SECURE];
507 }
Clarence Ipdd8021c2016-07-20 16:39:47 -0400508
509 if (ops)
510 c_conn->ops = *ops;
511
512 c_conn->base.helper_private = &sde_connector_helper_ops;
513 c_conn->base.polled = connector_poll;
514 c_conn->base.interlace_allowed = 0;
515 c_conn->base.doublescan_allowed = 0;
516
517 snprintf(c_conn->name,
518 SDE_CONNECTOR_NAME_SIZE,
519 "conn%u",
520 c_conn->base.base.id);
521
Clarence Ip9a74a442016-08-25 18:29:03 -0400522 rc = sde_fence_init(dev, &c_conn->retire_fence, c_conn->name);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400523 if (rc) {
524 SDE_ERROR("failed to init fence, %d\n", rc);
525 goto error_cleanup_conn;
526 }
527
Clarence Ipdd8021c2016-07-20 16:39:47 -0400528 rc = drm_connector_register(&c_conn->base);
529 if (rc) {
530 SDE_ERROR("failed to register drm connector, %d\n", rc);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400531 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400532 }
533
534 rc = drm_mode_connector_attach_encoder(&c_conn->base, encoder);
535 if (rc) {
536 SDE_ERROR("failed to attach encoder to connector, %d\n", rc);
537 goto error_unregister_conn;
538 }
539
Vishnuvardhan Prodduturi75b96802016-10-17 18:45:55 +0530540 if (c_conn->ops.set_backlight) {
541 rc = sde_backlight_setup(&c_conn->base);
542 if (rc) {
543 pr_err("failed to setup backlight, rc=%d\n", rc);
544 goto error_unregister_conn;
545 }
546 }
547
Clarence Ipdd8021c2016-07-20 16:39:47 -0400548 /* create properties */
549 msm_property_init(&c_conn->property_info, &c_conn->base.base, dev,
550 priv->conn_property, c_conn->property_data,
551 CONNECTOR_PROP_COUNT, CONNECTOR_PROP_BLOBCOUNT,
552 sizeof(struct sde_connector_state));
553
554 if (c_conn->ops.post_init) {
555 info = kmalloc(sizeof(*info), GFP_KERNEL);
556 if (!info) {
557 SDE_ERROR("failed to allocate info buffer\n");
558 rc = -ENOMEM;
559 goto error_unregister_conn;
560 }
561
562 sde_kms_info_reset(info);
563 rc = c_conn->ops.post_init(&c_conn->base, info, display);
564 if (rc) {
565 SDE_ERROR("post-init failed, %d\n", rc);
566 kfree(info);
567 goto error_unregister_conn;
568 }
569
570 msm_property_install_blob(&c_conn->property_info,
Dhaval Patel4e574842016-08-23 15:11:37 -0700571 "capabilities",
Clarence Ipdd8021c2016-07-20 16:39:47 -0400572 DRM_MODE_PROP_IMMUTABLE,
573 CONNECTOR_PROP_SDE_INFO);
574
575 msm_property_set_blob(&c_conn->property_info,
Dhaval Patel4e574842016-08-23 15:11:37 -0700576 &c_conn->blob_caps,
Clarence Ipdd8021c2016-07-20 16:39:47 -0400577 SDE_KMS_INFO_DATA(info),
578 SDE_KMS_INFO_DATALEN(info),
579 CONNECTOR_PROP_SDE_INFO);
580 kfree(info);
581 }
582
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400583 msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE",
Dhaval Patel4e574842016-08-23 15:11:37 -0700584 0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400585
Lloyd Atkinsonb6191972016-08-10 18:31:46 -0400586 /* enum/bitmask properties */
587 msm_property_install_enum(&c_conn->property_info, "topology_name",
588 DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name,
589 ARRAY_SIZE(e_topology_name),
590 CONNECTOR_PROP_TOPOLOGY_NAME);
591 msm_property_install_enum(&c_conn->property_info, "topology_control",
592 0, 1, e_topology_control,
593 ARRAY_SIZE(e_topology_control),
594 CONNECTOR_PROP_TOPOLOGY_CONTROL);
595
Clarence Ipdd8021c2016-07-20 16:39:47 -0400596 rc = msm_property_install_get_status(&c_conn->property_info);
597 if (rc) {
598 SDE_ERROR("failed to create one or more properties\n");
599 goto error_destroy_property;
600 }
601
Lloyd Atkinsonb6191972016-08-10 18:31:46 -0400602 SDE_DEBUG("connector %d attach encoder %d\n",
603 c_conn->base.base.id, encoder->base.id);
604
Clarence Ipdd8021c2016-07-20 16:39:47 -0400605 priv->connectors[priv->num_connectors++] = &c_conn->base;
606
607 return &c_conn->base;
608
609error_destroy_property:
Dhaval Patel4e574842016-08-23 15:11:37 -0700610 if (c_conn->blob_caps)
611 drm_property_unreference_blob(c_conn->blob_caps);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400612 msm_property_destroy(&c_conn->property_info);
613error_unregister_conn:
614 drm_connector_unregister(&c_conn->base);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400615error_cleanup_fence:
616 sde_fence_deinit(&c_conn->retire_fence);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400617error_cleanup_conn:
618 drm_connector_cleanup(&c_conn->base);
619error_free_conn:
620 kfree(c_conn);
621
622 return ERR_PTR(rc);
623}