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