blob: 0e5342f270ce58b068da72f8c103178b46781680 [file] [log] [blame]
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -08001/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
Clarence Ipdd8021c2016-07-20 16:39:47 -04002 *
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"
Dhaval Patel7cdd6662017-03-08 13:10:37 -080018#include <linux/backlight.h>
19#include "dsi_drm.h"
20
21#define BL_NODE_NAME_SIZE 32
Clarence Ipdd8021c2016-07-20 16:39:47 -040022
Lloyd Atkinsonb6191972016-08-10 18:31:46 -040023static const struct drm_prop_enum_list e_topology_name[] = {
24 {SDE_RM_TOPOLOGY_UNKNOWN, "sde_unknown"},
25 {SDE_RM_TOPOLOGY_SINGLEPIPE, "sde_singlepipe"},
26 {SDE_RM_TOPOLOGY_DUALPIPE, "sde_dualpipe"},
27 {SDE_RM_TOPOLOGY_PPSPLIT, "sde_ppsplit"},
28 {SDE_RM_TOPOLOGY_DUALPIPEMERGE, "sde_dualpipemerge"}
29};
30static const struct drm_prop_enum_list e_topology_control[] = {
31 {SDE_RM_TOPCTL_RESERVE_LOCK, "reserve_lock"},
32 {SDE_RM_TOPCTL_RESERVE_CLEAR, "reserve_clear"},
33 {SDE_RM_TOPCTL_DSPP, "dspp"},
34 {SDE_RM_TOPCTL_FORCE_TILING, "force_tiling"},
35 {SDE_RM_TOPCTL_PPSPLIT, "ppsplit"}
36};
37
Dhaval Patel7cdd6662017-03-08 13:10:37 -080038static int sde_backlight_device_update_status(struct backlight_device *bd)
39{
40 int brightness;
41 struct dsi_display *display;
42 struct sde_connector *c_conn;
43 int bl_lvl;
44
45 brightness = bd->props.brightness;
46
47 if ((bd->props.power != FB_BLANK_UNBLANK) ||
48 (bd->props.state & BL_CORE_FBBLANK) ||
49 (bd->props.state & BL_CORE_SUSPENDED))
50 brightness = 0;
51
52 c_conn = bl_get_data(bd);
53 display = (struct dsi_display *) c_conn->display;
54 if (brightness > display->panel->bl_config.bl_max_level)
55 brightness = display->panel->bl_config.bl_max_level;
56
57 /* map UI brightness into driver backlight level with rounding */
58 bl_lvl = mult_frac(brightness, display->panel->bl_config.bl_max_level,
59 display->panel->bl_config.brightness_max_level);
60
61 if (!bl_lvl && brightness)
62 bl_lvl = 1;
63
64 if (c_conn->ops.set_backlight)
65 c_conn->ops.set_backlight(c_conn->display, bl_lvl);
66
67 return 0;
68}
69
70static int sde_backlight_device_get_brightness(struct backlight_device *bd)
71{
72 return 0;
73}
74
75static const struct backlight_ops sde_backlight_device_ops = {
76 .update_status = sde_backlight_device_update_status,
77 .get_brightness = sde_backlight_device_get_brightness,
78};
79
80static int sde_backlight_setup(struct sde_connector *c_conn)
81{
82 struct backlight_device *bl_device;
83 struct backlight_properties props;
84 struct dsi_display *display;
85 struct dsi_backlight_config *bl_config;
86 static int display_count;
87 char bl_node_name[BL_NODE_NAME_SIZE];
88
89 if (!c_conn) {
90 SDE_ERROR("invalid param\n");
91 return -EINVAL;
92 } else if (c_conn->connector_type != DRM_MODE_CONNECTOR_DSI) {
93 return 0;
94 }
95
96 memset(&props, 0, sizeof(props));
97 props.type = BACKLIGHT_RAW;
98 props.power = FB_BLANK_UNBLANK;
99
100 display = (struct dsi_display *) c_conn->display;
101 bl_config = &display->panel->bl_config;
102 props.max_brightness = bl_config->brightness_max_level;
103 props.brightness = bl_config->brightness_max_level;
104 snprintf(bl_node_name, BL_NODE_NAME_SIZE, "panel%u-backlight",
105 display_count);
106 bl_device = backlight_device_register(bl_node_name, c_conn->base.kdev,
107 c_conn, &sde_backlight_device_ops, &props);
108 if (IS_ERR_OR_NULL(bl_device)) {
109 SDE_ERROR("Failed to register backlight: %ld\n",
110 PTR_ERR(bl_device));
111 return -ENODEV;
112 }
113 display_count++;
114
115 return 0;
116}
117
Clarence Ipcb3afd42016-07-15 16:25:34 -0400118int sde_connector_get_info(struct drm_connector *connector,
119 struct msm_display_info *info)
120{
121 struct sde_connector *c_conn;
122
123 if (!connector || !info) {
124 SDE_ERROR("invalid argument(s), conn %pK, info %pK\n",
125 connector, info);
126 return -EINVAL;
127 }
128
129 c_conn = to_sde_connector(connector);
130
131 if (!c_conn->display || !c_conn->ops.get_info) {
132 SDE_ERROR("display info not supported for %pK\n",
133 c_conn->display);
134 return -EINVAL;
135 }
136
137 return c_conn->ops.get_info(info, c_conn->display);
138}
139
Clarence Ipdd8021c2016-07-20 16:39:47 -0400140static void sde_connector_destroy(struct drm_connector *connector)
141{
142 struct sde_connector *c_conn;
143
144 if (!connector) {
145 SDE_ERROR("invalid connector\n");
146 return;
147 }
148
149 c_conn = to_sde_connector(connector);
150
Dhaval Patel4e574842016-08-23 15:11:37 -0700151 if (c_conn->blob_caps)
152 drm_property_unreference_blob(c_conn->blob_caps);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400153 msm_property_destroy(&c_conn->property_info);
154
155 drm_connector_unregister(connector);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400156 sde_fence_deinit(&c_conn->retire_fence);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400157 drm_connector_cleanup(connector);
158 kfree(c_conn);
159}
160
161/**
162 * _sde_connector_destroy_fb - clean up connector state's out_fb buffer
163 * @c_conn: Pointer to sde connector structure
164 * @c_state: Pointer to sde connector state structure
165 */
166static void _sde_connector_destroy_fb(struct sde_connector *c_conn,
167 struct sde_connector_state *c_state)
168{
169 if (!c_state || !c_state->out_fb) {
170 SDE_ERROR("invalid state %pK\n", c_state);
171 return;
172 }
173
174 msm_framebuffer_cleanup(c_state->out_fb,
175 c_state->mmu_id);
176 drm_framebuffer_unreference(c_state->out_fb);
177 c_state->out_fb = NULL;
178
179 if (c_conn) {
180 c_state->property_values[CONNECTOR_PROP_OUT_FB] =
181 msm_property_get_default(&c_conn->property_info,
182 CONNECTOR_PROP_OUT_FB);
183 } else {
184 c_state->property_values[CONNECTOR_PROP_OUT_FB] = ~0;
185 }
186}
187
188static void sde_connector_atomic_destroy_state(struct drm_connector *connector,
189 struct drm_connector_state *state)
190{
191 struct sde_connector *c_conn = NULL;
192 struct sde_connector_state *c_state = NULL;
193
194 if (!state) {
195 SDE_ERROR("invalid state\n");
196 return;
197 }
198
199 /*
200 * The base DRM framework currently always passes in a NULL
201 * connector pointer. This is not correct, but attempt to
202 * handle that case as much as possible.
203 */
204 if (connector)
205 c_conn = to_sde_connector(connector);
206 c_state = to_sde_connector_state(state);
207
208 if (c_state->out_fb)
209 _sde_connector_destroy_fb(c_conn, c_state);
210
211 if (!c_conn) {
212 kfree(c_state);
213 } else {
214 /* destroy value helper */
215 msm_property_destroy_state(&c_conn->property_info, c_state,
216 c_state->property_values, 0);
217 }
218}
219
220static void sde_connector_atomic_reset(struct drm_connector *connector)
221{
222 struct sde_connector *c_conn;
223 struct sde_connector_state *c_state;
224
225 if (!connector) {
226 SDE_ERROR("invalid connector\n");
227 return;
228 }
229
230 c_conn = to_sde_connector(connector);
231
232 if (connector->state) {
233 sde_connector_atomic_destroy_state(connector, connector->state);
234 connector->state = 0;
235 }
236
237 c_state = msm_property_alloc_state(&c_conn->property_info);
238 if (!c_state) {
239 SDE_ERROR("state alloc failed\n");
240 return;
241 }
242
243 /* reset value helper, zero out state structure and reset properties */
244 msm_property_reset_state(&c_conn->property_info, c_state,
245 c_state->property_values, 0);
246
247 c_state->base.connector = connector;
248 connector->state = &c_state->base;
249}
250
251static struct drm_connector_state *
252sde_connector_atomic_duplicate_state(struct drm_connector *connector)
253{
254 struct sde_connector *c_conn;
255 struct sde_connector_state *c_state, *c_oldstate;
256 int rc;
257
258 if (!connector || !connector->state) {
259 SDE_ERROR("invalid connector %pK\n", connector);
260 return NULL;
261 }
262
263 c_conn = to_sde_connector(connector);
264 c_oldstate = to_sde_connector_state(connector->state);
265 c_state = msm_property_alloc_state(&c_conn->property_info);
266 if (!c_state) {
267 SDE_ERROR("state alloc failed\n");
268 return NULL;
269 }
270
271 /* duplicate value helper */
272 msm_property_duplicate_state(&c_conn->property_info,
273 c_oldstate, c_state, c_state->property_values, 0);
274
275 /* additional handling for drm framebuffer objects */
276 if (c_state->out_fb) {
277 drm_framebuffer_reference(c_state->out_fb);
278 rc = msm_framebuffer_prepare(c_state->out_fb,
279 c_state->mmu_id);
280 if (rc)
281 SDE_ERROR("failed to prepare fb, %d\n", rc);
282 }
283
284 return &c_state->base;
285}
286
287static int sde_connector_atomic_set_property(struct drm_connector *connector,
288 struct drm_connector_state *state,
289 struct drm_property *property,
290 uint64_t val)
291{
292 struct sde_connector *c_conn;
293 struct sde_connector_state *c_state;
294 int idx, rc;
295
296 if (!connector || !state || !property) {
297 SDE_ERROR("invalid argument(s), conn %pK, state %pK, prp %pK\n",
298 connector, state, property);
299 return -EINVAL;
300 }
301
302 c_conn = to_sde_connector(connector);
303 c_state = to_sde_connector_state(state);
304
305 /* generic property handling */
306 rc = msm_property_atomic_set(&c_conn->property_info,
307 c_state->property_values, 0, property, val);
308 if (rc)
309 goto end;
310
311 /* connector-specific property handling */
312 idx = msm_property_index(&c_conn->property_info, property);
313
314 if (idx == CONNECTOR_PROP_OUT_FB) {
315 /* clear old fb, if present */
316 if (c_state->out_fb)
317 _sde_connector_destroy_fb(c_conn, c_state);
318
319 /* convert fb val to drm framebuffer and prepare it */
320 c_state->out_fb =
321 drm_framebuffer_lookup(connector->dev, val);
322 if (!c_state->out_fb) {
323 SDE_ERROR("failed to look up fb %lld\n", val);
324 rc = -EFAULT;
325 } else {
Alan Kwong578cdaf2017-01-28 17:25:43 -0800326 msm_framebuffer_set_kmap(c_state->out_fb,
327 c_conn->fb_kmap);
328
Alan Kwongdfa8c082016-07-29 04:10:00 -0400329 if (c_state->out_fb->flags & DRM_MODE_FB_SECURE)
330 c_state->mmu_id =
331 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE];
332 else
333 c_state->mmu_id =
334 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE];
Clarence Ipdd8021c2016-07-20 16:39:47 -0400335
336 rc = msm_framebuffer_prepare(c_state->out_fb,
337 c_state->mmu_id);
338 if (rc)
339 SDE_ERROR("prep fb failed, %d\n", rc);
340 }
341 }
342
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400343 if (idx == CONNECTOR_PROP_TOPOLOGY_CONTROL) {
344 rc = sde_rm_check_property_topctl(val);
345 if (rc)
346 SDE_ERROR("invalid topology_control: 0x%llX\n", val);
347 }
348
Clarence Ipdd8021c2016-07-20 16:39:47 -0400349 /* check for custom property handling */
350 if (!rc && c_conn->ops.set_property) {
351 rc = c_conn->ops.set_property(connector,
352 state,
353 idx,
354 val,
355 c_conn->display);
356
357 /* potentially clean up out_fb if rc != 0 */
358 if ((idx == CONNECTOR_PROP_OUT_FB) && rc)
359 _sde_connector_destroy_fb(c_conn, c_state);
360 }
361end:
362 return rc;
363}
364
365static int sde_connector_set_property(struct drm_connector *connector,
366 struct drm_property *property,
367 uint64_t val)
368{
369 if (!connector) {
370 SDE_ERROR("invalid connector\n");
371 return -EINVAL;
372 }
373
374 return sde_connector_atomic_set_property(connector,
375 connector->state, property, val);
376}
377
378static int sde_connector_atomic_get_property(struct drm_connector *connector,
379 const struct drm_connector_state *state,
380 struct drm_property *property,
381 uint64_t *val)
382{
383 struct sde_connector *c_conn;
384 struct sde_connector_state *c_state;
385 int idx, rc = -EINVAL;
386
387 if (!connector || !state) {
388 SDE_ERROR("invalid argument(s), conn %pK, state %pK\n",
389 connector, state);
390 return -EINVAL;
391 }
392
393 c_conn = to_sde_connector(connector);
394 c_state = to_sde_connector_state(state);
395
396 idx = msm_property_index(&c_conn->property_info, property);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400397 if (idx == CONNECTOR_PROP_RETIRE_FENCE)
Clarence Ip9a74a442016-08-25 18:29:03 -0400398 /*
399 * Set a fence offset if not a virtual connector, so that the
400 * fence signals after one additional commit rather than at the
401 * end of the current one.
402 */
403 rc = sde_fence_create(&c_conn->retire_fence, val,
404 c_conn->connector_type != DRM_MODE_CONNECTOR_VIRTUAL);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400405 else
406 /* get cached property value */
407 rc = msm_property_atomic_get(&c_conn->property_info,
408 c_state->property_values, 0, property, val);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400409
410 /* allow for custom override */
411 if (c_conn->ops.get_property)
412 rc = c_conn->ops.get_property(connector,
413 (struct drm_connector_state *)state,
414 idx,
415 val,
416 c_conn->display);
417 return rc;
418}
419
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400420void sde_connector_prepare_fence(struct drm_connector *connector)
421{
422 if (!connector) {
423 SDE_ERROR("invalid connector\n");
424 return;
425 }
426
427 sde_fence_prepare(&to_sde_connector(connector)->retire_fence);
428}
429
430void sde_connector_complete_commit(struct drm_connector *connector)
431{
432 if (!connector) {
433 SDE_ERROR("invalid connector\n");
434 return;
435 }
436
437 /* signal connector's retire fence */
438 sde_fence_signal(&to_sde_connector(connector)->retire_fence, 0);
439}
440
Clarence Ipdd8021c2016-07-20 16:39:47 -0400441static enum drm_connector_status
442sde_connector_detect(struct drm_connector *connector, bool force)
443{
444 enum drm_connector_status status = connector_status_unknown;
445 struct sde_connector *c_conn;
446
447 if (!connector) {
448 SDE_ERROR("invalid connector\n");
449 return status;
450 }
451
452 c_conn = to_sde_connector(connector);
453
454 if (c_conn->ops.detect)
455 status = c_conn->ops.detect(connector,
456 force,
457 c_conn->display);
458
459 return status;
460}
461
Alan Kwong578cdaf2017-01-28 17:25:43 -0800462#ifdef CONFIG_DEBUG_FS
463/**
464 * sde_connector_init_debugfs - initialize connector debugfs
465 * @connector: Pointer to drm connector
466 */
467static int sde_connector_init_debugfs(struct drm_connector *connector)
468{
469 struct sde_connector *sde_connector;
470
471 if (!connector || !connector->debugfs_entry) {
472 SDE_ERROR("invalid connector\n");
473 return -EINVAL;
474 }
475
476 sde_connector = to_sde_connector(connector);
477
478 if (!debugfs_create_bool("fb_kmap", 0644, connector->debugfs_entry,
479 &sde_connector->fb_kmap)) {
480 SDE_ERROR("failed to create connector fb_kmap\n");
481 return -ENOMEM;
482 }
483
484 return 0;
485}
486#else
487static int sde_connector_init_debugfs(struct drm_connector *connector)
488{
489 return 0;
490}
491#endif
492
493static int sde_connector_late_register(struct drm_connector *connector)
494{
495 return sde_connector_init_debugfs(connector);
496}
497
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -0700498static void sde_connector_early_unregister(struct drm_connector *connector)
499{
500 /* debugfs under connector->debugfs are deleted by drm_debugfs */
501}
502
Clarence Ipdd8021c2016-07-20 16:39:47 -0400503static const struct drm_connector_funcs sde_connector_ops = {
504 .dpms = drm_atomic_helper_connector_dpms,
505 .reset = sde_connector_atomic_reset,
506 .detect = sde_connector_detect,
507 .destroy = sde_connector_destroy,
508 .fill_modes = drm_helper_probe_single_connector_modes,
509 .atomic_duplicate_state = sde_connector_atomic_duplicate_state,
510 .atomic_destroy_state = sde_connector_atomic_destroy_state,
511 .atomic_set_property = sde_connector_atomic_set_property,
512 .atomic_get_property = sde_connector_atomic_get_property,
513 .set_property = sde_connector_set_property,
Alan Kwong578cdaf2017-01-28 17:25:43 -0800514 .late_register = sde_connector_late_register,
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -0700515 .early_unregister = sde_connector_early_unregister,
Clarence Ipdd8021c2016-07-20 16:39:47 -0400516};
517
518static int sde_connector_get_modes(struct drm_connector *connector)
519{
520 struct sde_connector *c_conn;
521
522 if (!connector) {
523 SDE_ERROR("invalid connector\n");
524 return 0;
525 }
526
527 c_conn = to_sde_connector(connector);
528 if (!c_conn->ops.get_modes) {
529 SDE_DEBUG("missing get_modes callback\n");
530 return 0;
531 }
532
533 return c_conn->ops.get_modes(connector, c_conn->display);
534}
535
536static enum drm_mode_status
537sde_connector_mode_valid(struct drm_connector *connector,
538 struct drm_display_mode *mode)
539{
540 struct sde_connector *c_conn;
541
542 if (!connector || !mode) {
543 SDE_ERROR("invalid argument(s), conn %pK, mode %pK\n",
544 connector, mode);
545 return MODE_ERROR;
546 }
547
548 c_conn = to_sde_connector(connector);
549
550 if (c_conn->ops.mode_valid)
551 return c_conn->ops.mode_valid(connector, mode, c_conn->display);
552
553 /* assume all modes okay by default */
554 return MODE_OK;
555}
556
557static struct drm_encoder *
558sde_connector_best_encoder(struct drm_connector *connector)
559{
560 struct sde_connector *c_conn = to_sde_connector(connector);
561
562 if (!connector) {
563 SDE_ERROR("invalid connector\n");
564 return NULL;
565 }
566
567 /*
568 * This is true for now, revisit this code when multiple encoders are
569 * supported.
570 */
571 return c_conn->encoder;
572}
573
574static const struct drm_connector_helper_funcs sde_connector_helper_ops = {
575 .get_modes = sde_connector_get_modes,
576 .mode_valid = sde_connector_mode_valid,
577 .best_encoder = sde_connector_best_encoder,
578};
579
580struct drm_connector *sde_connector_init(struct drm_device *dev,
581 struct drm_encoder *encoder,
582 struct drm_panel *panel,
583 void *display,
584 const struct sde_connector_ops *ops,
585 int connector_poll,
586 int connector_type)
587{
588 struct msm_drm_private *priv;
589 struct sde_kms *sde_kms;
590 struct sde_kms_info *info;
591 struct sde_connector *c_conn = NULL;
592 int rc;
593
594 if (!dev || !dev->dev_private || !encoder) {
595 SDE_ERROR("invalid argument(s), dev %pK, enc %pK\n",
596 dev, encoder);
597 return ERR_PTR(-EINVAL);
598 }
599
600 priv = dev->dev_private;
601 if (!priv->kms) {
602 SDE_ERROR("invalid kms reference\n");
603 return ERR_PTR(-EINVAL);
604 }
605
606 c_conn = kzalloc(sizeof(*c_conn), GFP_KERNEL);
607 if (!c_conn) {
608 SDE_ERROR("failed to alloc sde connector\n");
609 return ERR_PTR(-ENOMEM);
610 }
611
612 rc = drm_connector_init(dev,
613 &c_conn->base,
614 &sde_connector_ops,
615 connector_type);
616 if (rc)
617 goto error_free_conn;
618
619 c_conn->connector_type = connector_type;
620 c_conn->encoder = encoder;
621 c_conn->panel = panel;
622 c_conn->display = display;
623
Alan Kwongdfa8c082016-07-29 04:10:00 -0400624 /* cache mmu_id's for later */
Clarence Ipdd8021c2016-07-20 16:39:47 -0400625 sde_kms = to_sde_kms(priv->kms);
Alan Kwongdfa8c082016-07-29 04:10:00 -0400626 if (sde_kms->vbif[VBIF_NRT]) {
627 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] =
628 sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_UNSECURE];
629 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE] =
630 sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_SECURE];
631 } else {
632 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] =
633 sde_kms->mmu_id[MSM_SMMU_DOMAIN_UNSECURE];
634 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE] =
635 sde_kms->mmu_id[MSM_SMMU_DOMAIN_SECURE];
636 }
Clarence Ipdd8021c2016-07-20 16:39:47 -0400637
638 if (ops)
639 c_conn->ops = *ops;
640
641 c_conn->base.helper_private = &sde_connector_helper_ops;
642 c_conn->base.polled = connector_poll;
643 c_conn->base.interlace_allowed = 0;
644 c_conn->base.doublescan_allowed = 0;
645
646 snprintf(c_conn->name,
647 SDE_CONNECTOR_NAME_SIZE,
648 "conn%u",
649 c_conn->base.base.id);
650
Lloyd Atkinson5d40d312016-09-06 08:34:13 -0400651 rc = sde_fence_init(&c_conn->retire_fence, c_conn->name,
652 c_conn->base.base.id);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400653 if (rc) {
654 SDE_ERROR("failed to init fence, %d\n", rc);
655 goto error_cleanup_conn;
656 }
657
Clarence Ipdd8021c2016-07-20 16:39:47 -0400658 rc = drm_mode_connector_attach_encoder(&c_conn->base, encoder);
659 if (rc) {
660 SDE_ERROR("failed to attach encoder to connector, %d\n", rc);
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -0800661 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400662 }
663
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800664 rc = sde_backlight_setup(c_conn);
665 if (rc) {
666 SDE_ERROR("failed to setup backlight, rc=%d\n", rc);
667 goto error_cleanup_fence;
Vishnuvardhan Prodduturi75b96802016-10-17 18:45:55 +0530668 }
669
Clarence Ipdd8021c2016-07-20 16:39:47 -0400670 /* create properties */
671 msm_property_init(&c_conn->property_info, &c_conn->base.base, dev,
672 priv->conn_property, c_conn->property_data,
673 CONNECTOR_PROP_COUNT, CONNECTOR_PROP_BLOBCOUNT,
674 sizeof(struct sde_connector_state));
675
676 if (c_conn->ops.post_init) {
677 info = kmalloc(sizeof(*info), GFP_KERNEL);
678 if (!info) {
679 SDE_ERROR("failed to allocate info buffer\n");
680 rc = -ENOMEM;
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -0800681 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400682 }
683
684 sde_kms_info_reset(info);
685 rc = c_conn->ops.post_init(&c_conn->base, info, display);
686 if (rc) {
687 SDE_ERROR("post-init failed, %d\n", rc);
688 kfree(info);
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -0800689 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400690 }
691
692 msm_property_install_blob(&c_conn->property_info,
Dhaval Patel4e574842016-08-23 15:11:37 -0700693 "capabilities",
Clarence Ipdd8021c2016-07-20 16:39:47 -0400694 DRM_MODE_PROP_IMMUTABLE,
695 CONNECTOR_PROP_SDE_INFO);
696
697 msm_property_set_blob(&c_conn->property_info,
Dhaval Patel4e574842016-08-23 15:11:37 -0700698 &c_conn->blob_caps,
Clarence Ipdd8021c2016-07-20 16:39:47 -0400699 SDE_KMS_INFO_DATA(info),
700 SDE_KMS_INFO_DATALEN(info),
701 CONNECTOR_PROP_SDE_INFO);
702 kfree(info);
703 }
704
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400705 msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE",
Dhaval Patel4e574842016-08-23 15:11:37 -0700706 0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400707
Lloyd Atkinsonb6191972016-08-10 18:31:46 -0400708 /* enum/bitmask properties */
709 msm_property_install_enum(&c_conn->property_info, "topology_name",
710 DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name,
711 ARRAY_SIZE(e_topology_name),
712 CONNECTOR_PROP_TOPOLOGY_NAME);
713 msm_property_install_enum(&c_conn->property_info, "topology_control",
714 0, 1, e_topology_control,
715 ARRAY_SIZE(e_topology_control),
716 CONNECTOR_PROP_TOPOLOGY_CONTROL);
717
Clarence Ipdd8021c2016-07-20 16:39:47 -0400718 rc = msm_property_install_get_status(&c_conn->property_info);
719 if (rc) {
720 SDE_ERROR("failed to create one or more properties\n");
721 goto error_destroy_property;
722 }
723
Lloyd Atkinsonb6191972016-08-10 18:31:46 -0400724 SDE_DEBUG("connector %d attach encoder %d\n",
725 c_conn->base.base.id, encoder->base.id);
726
Clarence Ipdd8021c2016-07-20 16:39:47 -0400727 priv->connectors[priv->num_connectors++] = &c_conn->base;
728
729 return &c_conn->base;
730
731error_destroy_property:
Dhaval Patel4e574842016-08-23 15:11:37 -0700732 if (c_conn->blob_caps)
733 drm_property_unreference_blob(c_conn->blob_caps);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400734 msm_property_destroy(&c_conn->property_info);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400735error_cleanup_fence:
736 sde_fence_deinit(&c_conn->retire_fence);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400737error_cleanup_conn:
738 drm_connector_cleanup(&c_conn->base);
739error_free_conn:
740 kfree(c_conn);
741
742 return ERR_PTR(rc);
743}