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