blob: 92b7e5d719e51a2305c96a0f7d615b3982d1ffed [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 Ipa18d4832017-03-13 12:35:44 -0700118int sde_connector_trigger_event(void *drm_connector,
119 uint32_t event_idx, uint32_t instance_idx,
120 uint32_t data0, uint32_t data1,
121 uint32_t data2, uint32_t data3)
122{
123 struct sde_connector *c_conn;
124 unsigned long irq_flags;
125 void (*cb_func)(uint32_t event_idx,
126 uint32_t instance_idx, void *usr,
127 uint32_t data0, uint32_t data1,
128 uint32_t data2, uint32_t data3);
129 void *usr;
130 int rc = 0;
131
132 /*
133 * This function may potentially be called from an ISR context, so
134 * avoid excessive logging/etc.
135 */
136 if (!drm_connector)
137 return -EINVAL;
138 else if (event_idx >= SDE_CONN_EVENT_COUNT)
139 return -EINVAL;
140 c_conn = to_sde_connector(drm_connector);
141
142 spin_lock_irqsave(&c_conn->event_lock, irq_flags);
143 cb_func = c_conn->event_table[event_idx].cb_func;
144 usr = c_conn->event_table[event_idx].usr;
145 spin_unlock_irqrestore(&c_conn->event_lock, irq_flags);
146
147 if (cb_func)
148 cb_func(event_idx, instance_idx, usr,
149 data0, data1, data2, data3);
150 else
151 rc = -EAGAIN;
152
153 return rc;
154}
155
156int sde_connector_register_event(struct drm_connector *connector,
157 uint32_t event_idx,
158 void (*cb_func)(uint32_t event_idx,
159 uint32_t instance_idx, void *usr,
160 uint32_t data0, uint32_t data1,
161 uint32_t data2, uint32_t data3),
162 void *usr)
163{
164 struct sde_connector *c_conn;
165 unsigned long irq_flags;
166
167 if (!connector) {
168 SDE_ERROR("invalid connector\n");
169 return -EINVAL;
170 } else if (event_idx >= SDE_CONN_EVENT_COUNT) {
171 SDE_ERROR("conn%d, invalid event %d\n",
172 connector->base.id, event_idx);
173 return -EINVAL;
174 }
175 c_conn = to_sde_connector(connector);
176
177 spin_lock_irqsave(&c_conn->event_lock, irq_flags);
178 c_conn->event_table[event_idx].cb_func = cb_func;
179 c_conn->event_table[event_idx].usr = usr;
180 spin_unlock_irqrestore(&c_conn->event_lock, irq_flags);
181
182 /* optionally notify display of event registration */
183 if (c_conn->ops.enable_event && c_conn->display)
184 c_conn->ops.enable_event(connector, event_idx,
185 cb_func != NULL, c_conn->display);
186 return 0;
187}
188
189void sde_connector_unregister_event(struct drm_connector *connector,
190 uint32_t event_idx)
191{
192 (void)sde_connector_register_event(connector, event_idx, 0, 0);
193}
194
Clarence Ipcb3afd42016-07-15 16:25:34 -0400195int sde_connector_get_info(struct drm_connector *connector,
196 struct msm_display_info *info)
197{
198 struct sde_connector *c_conn;
199
200 if (!connector || !info) {
201 SDE_ERROR("invalid argument(s), conn %pK, info %pK\n",
202 connector, info);
203 return -EINVAL;
204 }
205
206 c_conn = to_sde_connector(connector);
207
208 if (!c_conn->display || !c_conn->ops.get_info) {
209 SDE_ERROR("display info not supported for %pK\n",
210 c_conn->display);
211 return -EINVAL;
212 }
213
214 return c_conn->ops.get_info(info, c_conn->display);
215}
216
Clarence Ipdd8021c2016-07-20 16:39:47 -0400217static void sde_connector_destroy(struct drm_connector *connector)
218{
219 struct sde_connector *c_conn;
220
221 if (!connector) {
222 SDE_ERROR("invalid connector\n");
223 return;
224 }
225
226 c_conn = to_sde_connector(connector);
227
Dhaval Patel4e574842016-08-23 15:11:37 -0700228 if (c_conn->blob_caps)
229 drm_property_unreference_blob(c_conn->blob_caps);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400230 msm_property_destroy(&c_conn->property_info);
231
232 drm_connector_unregister(connector);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400233 sde_fence_deinit(&c_conn->retire_fence);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400234 drm_connector_cleanup(connector);
235 kfree(c_conn);
236}
237
238/**
239 * _sde_connector_destroy_fb - clean up connector state's out_fb buffer
240 * @c_conn: Pointer to sde connector structure
241 * @c_state: Pointer to sde connector state structure
242 */
243static void _sde_connector_destroy_fb(struct sde_connector *c_conn,
244 struct sde_connector_state *c_state)
245{
246 if (!c_state || !c_state->out_fb) {
247 SDE_ERROR("invalid state %pK\n", c_state);
248 return;
249 }
250
251 msm_framebuffer_cleanup(c_state->out_fb,
252 c_state->mmu_id);
253 drm_framebuffer_unreference(c_state->out_fb);
254 c_state->out_fb = NULL;
255
256 if (c_conn) {
257 c_state->property_values[CONNECTOR_PROP_OUT_FB] =
258 msm_property_get_default(&c_conn->property_info,
259 CONNECTOR_PROP_OUT_FB);
260 } else {
261 c_state->property_values[CONNECTOR_PROP_OUT_FB] = ~0;
262 }
263}
264
265static void sde_connector_atomic_destroy_state(struct drm_connector *connector,
266 struct drm_connector_state *state)
267{
268 struct sde_connector *c_conn = NULL;
269 struct sde_connector_state *c_state = NULL;
270
271 if (!state) {
272 SDE_ERROR("invalid state\n");
273 return;
274 }
275
276 /*
277 * The base DRM framework currently always passes in a NULL
278 * connector pointer. This is not correct, but attempt to
279 * handle that case as much as possible.
280 */
281 if (connector)
282 c_conn = to_sde_connector(connector);
283 c_state = to_sde_connector_state(state);
284
285 if (c_state->out_fb)
286 _sde_connector_destroy_fb(c_conn, c_state);
287
288 if (!c_conn) {
289 kfree(c_state);
290 } else {
291 /* destroy value helper */
292 msm_property_destroy_state(&c_conn->property_info, c_state,
293 c_state->property_values, 0);
294 }
295}
296
297static void sde_connector_atomic_reset(struct drm_connector *connector)
298{
299 struct sde_connector *c_conn;
300 struct sde_connector_state *c_state;
301
302 if (!connector) {
303 SDE_ERROR("invalid connector\n");
304 return;
305 }
306
307 c_conn = to_sde_connector(connector);
308
309 if (connector->state) {
310 sde_connector_atomic_destroy_state(connector, connector->state);
311 connector->state = 0;
312 }
313
314 c_state = msm_property_alloc_state(&c_conn->property_info);
315 if (!c_state) {
316 SDE_ERROR("state alloc failed\n");
317 return;
318 }
319
320 /* reset value helper, zero out state structure and reset properties */
321 msm_property_reset_state(&c_conn->property_info, c_state,
322 c_state->property_values, 0);
323
324 c_state->base.connector = connector;
325 connector->state = &c_state->base;
326}
327
328static struct drm_connector_state *
329sde_connector_atomic_duplicate_state(struct drm_connector *connector)
330{
331 struct sde_connector *c_conn;
332 struct sde_connector_state *c_state, *c_oldstate;
333 int rc;
334
335 if (!connector || !connector->state) {
336 SDE_ERROR("invalid connector %pK\n", connector);
337 return NULL;
338 }
339
340 c_conn = to_sde_connector(connector);
341 c_oldstate = to_sde_connector_state(connector->state);
342 c_state = msm_property_alloc_state(&c_conn->property_info);
343 if (!c_state) {
344 SDE_ERROR("state alloc failed\n");
345 return NULL;
346 }
347
348 /* duplicate value helper */
349 msm_property_duplicate_state(&c_conn->property_info,
350 c_oldstate, c_state, c_state->property_values, 0);
351
352 /* additional handling for drm framebuffer objects */
353 if (c_state->out_fb) {
354 drm_framebuffer_reference(c_state->out_fb);
355 rc = msm_framebuffer_prepare(c_state->out_fb,
356 c_state->mmu_id);
357 if (rc)
358 SDE_ERROR("failed to prepare fb, %d\n", rc);
359 }
360
361 return &c_state->base;
362}
363
364static int sde_connector_atomic_set_property(struct drm_connector *connector,
365 struct drm_connector_state *state,
366 struct drm_property *property,
367 uint64_t val)
368{
369 struct sde_connector *c_conn;
370 struct sde_connector_state *c_state;
371 int idx, rc;
372
373 if (!connector || !state || !property) {
374 SDE_ERROR("invalid argument(s), conn %pK, state %pK, prp %pK\n",
375 connector, state, property);
376 return -EINVAL;
377 }
378
379 c_conn = to_sde_connector(connector);
380 c_state = to_sde_connector_state(state);
381
382 /* generic property handling */
383 rc = msm_property_atomic_set(&c_conn->property_info,
384 c_state->property_values, 0, property, val);
385 if (rc)
386 goto end;
387
388 /* connector-specific property handling */
389 idx = msm_property_index(&c_conn->property_info, property);
390
391 if (idx == CONNECTOR_PROP_OUT_FB) {
392 /* clear old fb, if present */
393 if (c_state->out_fb)
394 _sde_connector_destroy_fb(c_conn, c_state);
395
396 /* convert fb val to drm framebuffer and prepare it */
397 c_state->out_fb =
398 drm_framebuffer_lookup(connector->dev, val);
399 if (!c_state->out_fb) {
400 SDE_ERROR("failed to look up fb %lld\n", val);
401 rc = -EFAULT;
402 } else {
Alan Kwong578cdaf2017-01-28 17:25:43 -0800403 msm_framebuffer_set_kmap(c_state->out_fb,
404 c_conn->fb_kmap);
405
Alan Kwongdfa8c082016-07-29 04:10:00 -0400406 if (c_state->out_fb->flags & DRM_MODE_FB_SECURE)
407 c_state->mmu_id =
408 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE];
409 else
410 c_state->mmu_id =
411 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE];
Clarence Ipdd8021c2016-07-20 16:39:47 -0400412
413 rc = msm_framebuffer_prepare(c_state->out_fb,
414 c_state->mmu_id);
415 if (rc)
416 SDE_ERROR("prep fb failed, %d\n", rc);
417 }
418 }
419
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400420 if (idx == CONNECTOR_PROP_TOPOLOGY_CONTROL) {
421 rc = sde_rm_check_property_topctl(val);
422 if (rc)
423 SDE_ERROR("invalid topology_control: 0x%llX\n", val);
424 }
425
Clarence Ipdd8021c2016-07-20 16:39:47 -0400426 /* check for custom property handling */
427 if (!rc && c_conn->ops.set_property) {
428 rc = c_conn->ops.set_property(connector,
429 state,
430 idx,
431 val,
432 c_conn->display);
433
434 /* potentially clean up out_fb if rc != 0 */
435 if ((idx == CONNECTOR_PROP_OUT_FB) && rc)
436 _sde_connector_destroy_fb(c_conn, c_state);
437 }
438end:
439 return rc;
440}
441
442static int sde_connector_set_property(struct drm_connector *connector,
443 struct drm_property *property,
444 uint64_t val)
445{
446 if (!connector) {
447 SDE_ERROR("invalid connector\n");
448 return -EINVAL;
449 }
450
451 return sde_connector_atomic_set_property(connector,
452 connector->state, property, val);
453}
454
455static int sde_connector_atomic_get_property(struct drm_connector *connector,
456 const struct drm_connector_state *state,
457 struct drm_property *property,
458 uint64_t *val)
459{
460 struct sde_connector *c_conn;
461 struct sde_connector_state *c_state;
462 int idx, rc = -EINVAL;
463
464 if (!connector || !state) {
465 SDE_ERROR("invalid argument(s), conn %pK, state %pK\n",
466 connector, state);
467 return -EINVAL;
468 }
469
470 c_conn = to_sde_connector(connector);
471 c_state = to_sde_connector_state(state);
472
473 idx = msm_property_index(&c_conn->property_info, property);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400474 if (idx == CONNECTOR_PROP_RETIRE_FENCE)
Clarence Ip9a74a442016-08-25 18:29:03 -0400475 /*
476 * Set a fence offset if not a virtual connector, so that the
477 * fence signals after one additional commit rather than at the
478 * end of the current one.
479 */
480 rc = sde_fence_create(&c_conn->retire_fence, val,
481 c_conn->connector_type != DRM_MODE_CONNECTOR_VIRTUAL);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400482 else
483 /* get cached property value */
484 rc = msm_property_atomic_get(&c_conn->property_info,
485 c_state->property_values, 0, property, val);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400486
487 /* allow for custom override */
488 if (c_conn->ops.get_property)
489 rc = c_conn->ops.get_property(connector,
490 (struct drm_connector_state *)state,
491 idx,
492 val,
493 c_conn->display);
494 return rc;
495}
496
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400497void sde_connector_prepare_fence(struct drm_connector *connector)
498{
499 if (!connector) {
500 SDE_ERROR("invalid connector\n");
501 return;
502 }
503
504 sde_fence_prepare(&to_sde_connector(connector)->retire_fence);
505}
506
507void sde_connector_complete_commit(struct drm_connector *connector)
508{
509 if (!connector) {
510 SDE_ERROR("invalid connector\n");
511 return;
512 }
513
514 /* signal connector's retire fence */
515 sde_fence_signal(&to_sde_connector(connector)->retire_fence, 0);
516}
517
Clarence Ipdd8021c2016-07-20 16:39:47 -0400518static enum drm_connector_status
519sde_connector_detect(struct drm_connector *connector, bool force)
520{
521 enum drm_connector_status status = connector_status_unknown;
522 struct sde_connector *c_conn;
523
524 if (!connector) {
525 SDE_ERROR("invalid connector\n");
526 return status;
527 }
528
529 c_conn = to_sde_connector(connector);
530
531 if (c_conn->ops.detect)
532 status = c_conn->ops.detect(connector,
533 force,
534 c_conn->display);
535
536 return status;
537}
538
Alan Kwong578cdaf2017-01-28 17:25:43 -0800539#ifdef CONFIG_DEBUG_FS
540/**
541 * sde_connector_init_debugfs - initialize connector debugfs
542 * @connector: Pointer to drm connector
543 */
544static int sde_connector_init_debugfs(struct drm_connector *connector)
545{
546 struct sde_connector *sde_connector;
547
548 if (!connector || !connector->debugfs_entry) {
549 SDE_ERROR("invalid connector\n");
550 return -EINVAL;
551 }
552
553 sde_connector = to_sde_connector(connector);
554
555 if (!debugfs_create_bool("fb_kmap", 0644, connector->debugfs_entry,
556 &sde_connector->fb_kmap)) {
557 SDE_ERROR("failed to create connector fb_kmap\n");
558 return -ENOMEM;
559 }
560
561 return 0;
562}
563#else
564static int sde_connector_init_debugfs(struct drm_connector *connector)
565{
566 return 0;
567}
568#endif
569
570static int sde_connector_late_register(struct drm_connector *connector)
571{
572 return sde_connector_init_debugfs(connector);
573}
574
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -0700575static void sde_connector_early_unregister(struct drm_connector *connector)
576{
577 /* debugfs under connector->debugfs are deleted by drm_debugfs */
578}
579
Clarence Ipdd8021c2016-07-20 16:39:47 -0400580static const struct drm_connector_funcs sde_connector_ops = {
581 .dpms = drm_atomic_helper_connector_dpms,
582 .reset = sde_connector_atomic_reset,
583 .detect = sde_connector_detect,
584 .destroy = sde_connector_destroy,
585 .fill_modes = drm_helper_probe_single_connector_modes,
586 .atomic_duplicate_state = sde_connector_atomic_duplicate_state,
587 .atomic_destroy_state = sde_connector_atomic_destroy_state,
588 .atomic_set_property = sde_connector_atomic_set_property,
589 .atomic_get_property = sde_connector_atomic_get_property,
590 .set_property = sde_connector_set_property,
Alan Kwong578cdaf2017-01-28 17:25:43 -0800591 .late_register = sde_connector_late_register,
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -0700592 .early_unregister = sde_connector_early_unregister,
Clarence Ipdd8021c2016-07-20 16:39:47 -0400593};
594
595static int sde_connector_get_modes(struct drm_connector *connector)
596{
597 struct sde_connector *c_conn;
598
599 if (!connector) {
600 SDE_ERROR("invalid connector\n");
601 return 0;
602 }
603
604 c_conn = to_sde_connector(connector);
605 if (!c_conn->ops.get_modes) {
606 SDE_DEBUG("missing get_modes callback\n");
607 return 0;
608 }
609
610 return c_conn->ops.get_modes(connector, c_conn->display);
611}
612
613static enum drm_mode_status
614sde_connector_mode_valid(struct drm_connector *connector,
615 struct drm_display_mode *mode)
616{
617 struct sde_connector *c_conn;
618
619 if (!connector || !mode) {
620 SDE_ERROR("invalid argument(s), conn %pK, mode %pK\n",
621 connector, mode);
622 return MODE_ERROR;
623 }
624
625 c_conn = to_sde_connector(connector);
626
627 if (c_conn->ops.mode_valid)
628 return c_conn->ops.mode_valid(connector, mode, c_conn->display);
629
630 /* assume all modes okay by default */
631 return MODE_OK;
632}
633
634static struct drm_encoder *
635sde_connector_best_encoder(struct drm_connector *connector)
636{
637 struct sde_connector *c_conn = to_sde_connector(connector);
638
639 if (!connector) {
640 SDE_ERROR("invalid connector\n");
641 return NULL;
642 }
643
644 /*
645 * This is true for now, revisit this code when multiple encoders are
646 * supported.
647 */
648 return c_conn->encoder;
649}
650
651static const struct drm_connector_helper_funcs sde_connector_helper_ops = {
652 .get_modes = sde_connector_get_modes,
653 .mode_valid = sde_connector_mode_valid,
654 .best_encoder = sde_connector_best_encoder,
655};
656
657struct drm_connector *sde_connector_init(struct drm_device *dev,
658 struct drm_encoder *encoder,
659 struct drm_panel *panel,
660 void *display,
661 const struct sde_connector_ops *ops,
662 int connector_poll,
663 int connector_type)
664{
665 struct msm_drm_private *priv;
666 struct sde_kms *sde_kms;
667 struct sde_kms_info *info;
668 struct sde_connector *c_conn = NULL;
669 int rc;
670
671 if (!dev || !dev->dev_private || !encoder) {
672 SDE_ERROR("invalid argument(s), dev %pK, enc %pK\n",
673 dev, encoder);
674 return ERR_PTR(-EINVAL);
675 }
676
677 priv = dev->dev_private;
678 if (!priv->kms) {
679 SDE_ERROR("invalid kms reference\n");
680 return ERR_PTR(-EINVAL);
681 }
682
683 c_conn = kzalloc(sizeof(*c_conn), GFP_KERNEL);
684 if (!c_conn) {
685 SDE_ERROR("failed to alloc sde connector\n");
686 return ERR_PTR(-ENOMEM);
687 }
688
689 rc = drm_connector_init(dev,
690 &c_conn->base,
691 &sde_connector_ops,
692 connector_type);
693 if (rc)
694 goto error_free_conn;
695
Clarence Ipa18d4832017-03-13 12:35:44 -0700696 spin_lock_init(&c_conn->event_lock);
697
Clarence Ipdd8021c2016-07-20 16:39:47 -0400698 c_conn->connector_type = connector_type;
699 c_conn->encoder = encoder;
700 c_conn->panel = panel;
701 c_conn->display = display;
702
Alan Kwongdfa8c082016-07-29 04:10:00 -0400703 /* cache mmu_id's for later */
Clarence Ipdd8021c2016-07-20 16:39:47 -0400704 sde_kms = to_sde_kms(priv->kms);
Alan Kwongdfa8c082016-07-29 04:10:00 -0400705 if (sde_kms->vbif[VBIF_NRT]) {
706 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] =
707 sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_UNSECURE];
708 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE] =
709 sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_SECURE];
710 } else {
711 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] =
712 sde_kms->mmu_id[MSM_SMMU_DOMAIN_UNSECURE];
713 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE] =
714 sde_kms->mmu_id[MSM_SMMU_DOMAIN_SECURE];
715 }
Clarence Ipdd8021c2016-07-20 16:39:47 -0400716
717 if (ops)
718 c_conn->ops = *ops;
719
720 c_conn->base.helper_private = &sde_connector_helper_ops;
721 c_conn->base.polled = connector_poll;
722 c_conn->base.interlace_allowed = 0;
723 c_conn->base.doublescan_allowed = 0;
724
725 snprintf(c_conn->name,
726 SDE_CONNECTOR_NAME_SIZE,
727 "conn%u",
728 c_conn->base.base.id);
729
Lloyd Atkinson5d40d312016-09-06 08:34:13 -0400730 rc = sde_fence_init(&c_conn->retire_fence, c_conn->name,
731 c_conn->base.base.id);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400732 if (rc) {
733 SDE_ERROR("failed to init fence, %d\n", rc);
734 goto error_cleanup_conn;
735 }
736
Clarence Ipdd8021c2016-07-20 16:39:47 -0400737 rc = drm_mode_connector_attach_encoder(&c_conn->base, encoder);
738 if (rc) {
739 SDE_ERROR("failed to attach encoder to connector, %d\n", rc);
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -0800740 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400741 }
742
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800743 rc = sde_backlight_setup(c_conn);
744 if (rc) {
745 SDE_ERROR("failed to setup backlight, rc=%d\n", rc);
746 goto error_cleanup_fence;
Vishnuvardhan Prodduturi75b96802016-10-17 18:45:55 +0530747 }
748
Clarence Ipdd8021c2016-07-20 16:39:47 -0400749 /* create properties */
750 msm_property_init(&c_conn->property_info, &c_conn->base.base, dev,
751 priv->conn_property, c_conn->property_data,
752 CONNECTOR_PROP_COUNT, CONNECTOR_PROP_BLOBCOUNT,
753 sizeof(struct sde_connector_state));
754
755 if (c_conn->ops.post_init) {
756 info = kmalloc(sizeof(*info), GFP_KERNEL);
757 if (!info) {
758 SDE_ERROR("failed to allocate info buffer\n");
759 rc = -ENOMEM;
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -0800760 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400761 }
762
763 sde_kms_info_reset(info);
764 rc = c_conn->ops.post_init(&c_conn->base, info, display);
765 if (rc) {
766 SDE_ERROR("post-init failed, %d\n", rc);
767 kfree(info);
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -0800768 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400769 }
770
771 msm_property_install_blob(&c_conn->property_info,
Dhaval Patel4e574842016-08-23 15:11:37 -0700772 "capabilities",
Clarence Ipdd8021c2016-07-20 16:39:47 -0400773 DRM_MODE_PROP_IMMUTABLE,
774 CONNECTOR_PROP_SDE_INFO);
775
776 msm_property_set_blob(&c_conn->property_info,
Dhaval Patel4e574842016-08-23 15:11:37 -0700777 &c_conn->blob_caps,
Clarence Ipdd8021c2016-07-20 16:39:47 -0400778 SDE_KMS_INFO_DATA(info),
779 SDE_KMS_INFO_DATALEN(info),
780 CONNECTOR_PROP_SDE_INFO);
781 kfree(info);
782 }
783
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400784 msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE",
Dhaval Patel4e574842016-08-23 15:11:37 -0700785 0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400786
Lloyd Atkinsonb6191972016-08-10 18:31:46 -0400787 /* enum/bitmask properties */
788 msm_property_install_enum(&c_conn->property_info, "topology_name",
789 DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name,
790 ARRAY_SIZE(e_topology_name),
791 CONNECTOR_PROP_TOPOLOGY_NAME);
792 msm_property_install_enum(&c_conn->property_info, "topology_control",
793 0, 1, e_topology_control,
794 ARRAY_SIZE(e_topology_control),
795 CONNECTOR_PROP_TOPOLOGY_CONTROL);
796
Clarence Ipdd8021c2016-07-20 16:39:47 -0400797 rc = msm_property_install_get_status(&c_conn->property_info);
798 if (rc) {
799 SDE_ERROR("failed to create one or more properties\n");
800 goto error_destroy_property;
801 }
802
Lloyd Atkinsonb6191972016-08-10 18:31:46 -0400803 SDE_DEBUG("connector %d attach encoder %d\n",
804 c_conn->base.base.id, encoder->base.id);
805
Clarence Ipdd8021c2016-07-20 16:39:47 -0400806 priv->connectors[priv->num_connectors++] = &c_conn->base;
807
808 return &c_conn->base;
809
810error_destroy_property:
Dhaval Patel4e574842016-08-23 15:11:37 -0700811 if (c_conn->blob_caps)
812 drm_property_unreference_blob(c_conn->blob_caps);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400813 msm_property_destroy(&c_conn->property_info);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400814error_cleanup_fence:
815 sde_fence_deinit(&c_conn->retire_fence);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400816error_cleanup_conn:
817 drm_connector_cleanup(&c_conn->base);
818error_free_conn:
819 kfree(c_conn);
820
821 return ERR_PTR(rc);
822}