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