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