blob: 6e793d9bdc96e92056e3aafc242da3d6d21255b8 [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"
Ping Li898b1bf2017-02-09 18:03:28 -080020#include "dsi_display.h"
Dhaval Patel7cdd6662017-03-08 13:10:37 -080021
22#define BL_NODE_NAME_SIZE 32
Clarence Ipdd8021c2016-07-20 16:39:47 -040023
Lloyd Atkinsonb6191972016-08-10 18:31:46 -040024static const struct drm_prop_enum_list e_topology_name[] = {
25 {SDE_RM_TOPOLOGY_UNKNOWN, "sde_unknown"},
26 {SDE_RM_TOPOLOGY_SINGLEPIPE, "sde_singlepipe"},
27 {SDE_RM_TOPOLOGY_DUALPIPE, "sde_dualpipe"},
28 {SDE_RM_TOPOLOGY_PPSPLIT, "sde_ppsplit"},
29 {SDE_RM_TOPOLOGY_DUALPIPEMERGE, "sde_dualpipemerge"}
30};
31static const struct drm_prop_enum_list e_topology_control[] = {
32 {SDE_RM_TOPCTL_RESERVE_LOCK, "reserve_lock"},
33 {SDE_RM_TOPCTL_RESERVE_CLEAR, "reserve_clear"},
34 {SDE_RM_TOPCTL_DSPP, "dspp"},
35 {SDE_RM_TOPCTL_FORCE_TILING, "force_tiling"},
36 {SDE_RM_TOPCTL_PPSPLIT, "ppsplit"}
37};
38
Dhaval Patel7cdd6662017-03-08 13:10:37 -080039static int sde_backlight_device_update_status(struct backlight_device *bd)
40{
41 int brightness;
42 struct dsi_display *display;
43 struct sde_connector *c_conn;
44 int bl_lvl;
45
46 brightness = bd->props.brightness;
47
48 if ((bd->props.power != FB_BLANK_UNBLANK) ||
49 (bd->props.state & BL_CORE_FBBLANK) ||
50 (bd->props.state & BL_CORE_SUSPENDED))
51 brightness = 0;
52
53 c_conn = bl_get_data(bd);
54 display = (struct dsi_display *) c_conn->display;
55 if (brightness > display->panel->bl_config.bl_max_level)
56 brightness = display->panel->bl_config.bl_max_level;
57
58 /* map UI brightness into driver backlight level with rounding */
59 bl_lvl = mult_frac(brightness, display->panel->bl_config.bl_max_level,
60 display->panel->bl_config.brightness_max_level);
61
62 if (!bl_lvl && brightness)
63 bl_lvl = 1;
64
65 if (c_conn->ops.set_backlight)
66 c_conn->ops.set_backlight(c_conn->display, bl_lvl);
67
68 return 0;
69}
70
71static int sde_backlight_device_get_brightness(struct backlight_device *bd)
72{
73 return 0;
74}
75
76static const struct backlight_ops sde_backlight_device_ops = {
77 .update_status = sde_backlight_device_update_status,
78 .get_brightness = sde_backlight_device_get_brightness,
79};
80
81static int sde_backlight_setup(struct sde_connector *c_conn)
82{
83 struct backlight_device *bl_device;
84 struct backlight_properties props;
85 struct dsi_display *display;
86 struct dsi_backlight_config *bl_config;
87 static int display_count;
88 char bl_node_name[BL_NODE_NAME_SIZE];
89
90 if (!c_conn) {
91 SDE_ERROR("invalid param\n");
92 return -EINVAL;
93 } else if (c_conn->connector_type != DRM_MODE_CONNECTOR_DSI) {
94 return 0;
95 }
96
97 memset(&props, 0, sizeof(props));
98 props.type = BACKLIGHT_RAW;
99 props.power = FB_BLANK_UNBLANK;
100
101 display = (struct dsi_display *) c_conn->display;
102 bl_config = &display->panel->bl_config;
103 props.max_brightness = bl_config->brightness_max_level;
104 props.brightness = bl_config->brightness_max_level;
105 snprintf(bl_node_name, BL_NODE_NAME_SIZE, "panel%u-backlight",
106 display_count);
107 bl_device = backlight_device_register(bl_node_name, c_conn->base.kdev,
108 c_conn, &sde_backlight_device_ops, &props);
109 if (IS_ERR_OR_NULL(bl_device)) {
110 SDE_ERROR("Failed to register backlight: %ld\n",
111 PTR_ERR(bl_device));
112 return -ENODEV;
113 }
114 display_count++;
115
116 return 0;
117}
118
Clarence Ipa18d4832017-03-13 12:35:44 -0700119int sde_connector_trigger_event(void *drm_connector,
120 uint32_t event_idx, uint32_t instance_idx,
121 uint32_t data0, uint32_t data1,
122 uint32_t data2, uint32_t data3)
123{
124 struct sde_connector *c_conn;
125 unsigned long irq_flags;
126 void (*cb_func)(uint32_t event_idx,
127 uint32_t instance_idx, void *usr,
128 uint32_t data0, uint32_t data1,
129 uint32_t data2, uint32_t data3);
130 void *usr;
131 int rc = 0;
132
133 /*
134 * This function may potentially be called from an ISR context, so
135 * avoid excessive logging/etc.
136 */
137 if (!drm_connector)
138 return -EINVAL;
139 else if (event_idx >= SDE_CONN_EVENT_COUNT)
140 return -EINVAL;
141 c_conn = to_sde_connector(drm_connector);
142
143 spin_lock_irqsave(&c_conn->event_lock, irq_flags);
144 cb_func = c_conn->event_table[event_idx].cb_func;
145 usr = c_conn->event_table[event_idx].usr;
146 spin_unlock_irqrestore(&c_conn->event_lock, irq_flags);
147
148 if (cb_func)
149 cb_func(event_idx, instance_idx, usr,
150 data0, data1, data2, data3);
151 else
152 rc = -EAGAIN;
153
154 return rc;
155}
156
157int sde_connector_register_event(struct drm_connector *connector,
158 uint32_t event_idx,
159 void (*cb_func)(uint32_t event_idx,
160 uint32_t instance_idx, void *usr,
161 uint32_t data0, uint32_t data1,
162 uint32_t data2, uint32_t data3),
163 void *usr)
164{
165 struct sde_connector *c_conn;
166 unsigned long irq_flags;
167
168 if (!connector) {
169 SDE_ERROR("invalid connector\n");
170 return -EINVAL;
171 } else if (event_idx >= SDE_CONN_EVENT_COUNT) {
172 SDE_ERROR("conn%d, invalid event %d\n",
173 connector->base.id, event_idx);
174 return -EINVAL;
175 }
176 c_conn = to_sde_connector(connector);
177
178 spin_lock_irqsave(&c_conn->event_lock, irq_flags);
179 c_conn->event_table[event_idx].cb_func = cb_func;
180 c_conn->event_table[event_idx].usr = usr;
181 spin_unlock_irqrestore(&c_conn->event_lock, irq_flags);
182
183 /* optionally notify display of event registration */
184 if (c_conn->ops.enable_event && c_conn->display)
185 c_conn->ops.enable_event(connector, event_idx,
186 cb_func != NULL, c_conn->display);
187 return 0;
188}
189
190void sde_connector_unregister_event(struct drm_connector *connector,
191 uint32_t event_idx)
192{
193 (void)sde_connector_register_event(connector, event_idx, 0, 0);
194}
195
Clarence Ipcb3afd42016-07-15 16:25:34 -0400196int sde_connector_get_info(struct drm_connector *connector,
197 struct msm_display_info *info)
198{
199 struct sde_connector *c_conn;
200
201 if (!connector || !info) {
202 SDE_ERROR("invalid argument(s), conn %pK, info %pK\n",
203 connector, info);
204 return -EINVAL;
205 }
206
207 c_conn = to_sde_connector(connector);
208
209 if (!c_conn->display || !c_conn->ops.get_info) {
210 SDE_ERROR("display info not supported for %pK\n",
211 c_conn->display);
212 return -EINVAL;
213 }
214
215 return c_conn->ops.get_info(info, c_conn->display);
216}
217
Lloyd Atkinson05d75512017-01-17 14:45:51 -0500218int sde_connector_pre_kickoff(struct drm_connector *connector)
219{
220 struct sde_connector *c_conn;
221 struct sde_connector_state *c_state;
222 struct msm_display_kickoff_params params;
223 int rc;
224
225 if (!connector) {
226 SDE_ERROR("invalid argument\n");
227 return -EINVAL;
228 }
229
230 c_conn = to_sde_connector(connector);
231 c_state = to_sde_connector_state(connector->state);
232
233 if (!c_conn->display) {
234 SDE_ERROR("invalid argument\n");
235 return -EINVAL;
236 }
237
238 if (!c_conn->ops.pre_kickoff)
239 return 0;
240
241 params.rois = &c_state->rois;
242
243 SDE_EVT32_VERBOSE(connector->base.id);
244
245 rc = c_conn->ops.pre_kickoff(connector, c_conn->display, &params);
246
247 return rc;
248}
249
Clarence Ipdd8021c2016-07-20 16:39:47 -0400250static void sde_connector_destroy(struct drm_connector *connector)
251{
252 struct sde_connector *c_conn;
253
254 if (!connector) {
255 SDE_ERROR("invalid connector\n");
256 return;
257 }
258
259 c_conn = to_sde_connector(connector);
260
Dhaval Patel4e574842016-08-23 15:11:37 -0700261 if (c_conn->blob_caps)
262 drm_property_unreference_blob(c_conn->blob_caps);
Ping Li898b1bf2017-02-09 18:03:28 -0800263 if (c_conn->blob_hdr)
264 drm_property_unreference_blob(c_conn->blob_hdr);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400265 msm_property_destroy(&c_conn->property_info);
266
267 drm_connector_unregister(connector);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400268 sde_fence_deinit(&c_conn->retire_fence);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400269 drm_connector_cleanup(connector);
270 kfree(c_conn);
271}
272
273/**
274 * _sde_connector_destroy_fb - clean up connector state's out_fb buffer
275 * @c_conn: Pointer to sde connector structure
276 * @c_state: Pointer to sde connector state structure
277 */
278static void _sde_connector_destroy_fb(struct sde_connector *c_conn,
279 struct sde_connector_state *c_state)
280{
281 if (!c_state || !c_state->out_fb) {
282 SDE_ERROR("invalid state %pK\n", c_state);
283 return;
284 }
285
286 msm_framebuffer_cleanup(c_state->out_fb,
287 c_state->mmu_id);
288 drm_framebuffer_unreference(c_state->out_fb);
289 c_state->out_fb = NULL;
290
291 if (c_conn) {
292 c_state->property_values[CONNECTOR_PROP_OUT_FB] =
293 msm_property_get_default(&c_conn->property_info,
294 CONNECTOR_PROP_OUT_FB);
295 } else {
296 c_state->property_values[CONNECTOR_PROP_OUT_FB] = ~0;
297 }
298}
299
300static void sde_connector_atomic_destroy_state(struct drm_connector *connector,
301 struct drm_connector_state *state)
302{
303 struct sde_connector *c_conn = NULL;
304 struct sde_connector_state *c_state = NULL;
305
306 if (!state) {
307 SDE_ERROR("invalid state\n");
308 return;
309 }
310
311 /*
312 * The base DRM framework currently always passes in a NULL
313 * connector pointer. This is not correct, but attempt to
314 * handle that case as much as possible.
315 */
316 if (connector)
317 c_conn = to_sde_connector(connector);
318 c_state = to_sde_connector_state(state);
319
320 if (c_state->out_fb)
321 _sde_connector_destroy_fb(c_conn, c_state);
322
323 if (!c_conn) {
324 kfree(c_state);
325 } else {
326 /* destroy value helper */
327 msm_property_destroy_state(&c_conn->property_info, c_state,
328 c_state->property_values, 0);
329 }
330}
331
332static void sde_connector_atomic_reset(struct drm_connector *connector)
333{
334 struct sde_connector *c_conn;
335 struct sde_connector_state *c_state;
336
337 if (!connector) {
338 SDE_ERROR("invalid connector\n");
339 return;
340 }
341
342 c_conn = to_sde_connector(connector);
343
344 if (connector->state) {
345 sde_connector_atomic_destroy_state(connector, connector->state);
346 connector->state = 0;
347 }
348
349 c_state = msm_property_alloc_state(&c_conn->property_info);
350 if (!c_state) {
351 SDE_ERROR("state alloc failed\n");
352 return;
353 }
354
355 /* reset value helper, zero out state structure and reset properties */
356 msm_property_reset_state(&c_conn->property_info, c_state,
357 c_state->property_values, 0);
358
359 c_state->base.connector = connector;
360 connector->state = &c_state->base;
361}
362
363static struct drm_connector_state *
364sde_connector_atomic_duplicate_state(struct drm_connector *connector)
365{
366 struct sde_connector *c_conn;
367 struct sde_connector_state *c_state, *c_oldstate;
368 int rc;
369
370 if (!connector || !connector->state) {
371 SDE_ERROR("invalid connector %pK\n", connector);
372 return NULL;
373 }
374
375 c_conn = to_sde_connector(connector);
376 c_oldstate = to_sde_connector_state(connector->state);
377 c_state = msm_property_alloc_state(&c_conn->property_info);
378 if (!c_state) {
379 SDE_ERROR("state alloc failed\n");
380 return NULL;
381 }
382
383 /* duplicate value helper */
384 msm_property_duplicate_state(&c_conn->property_info,
385 c_oldstate, c_state, c_state->property_values, 0);
386
387 /* additional handling for drm framebuffer objects */
388 if (c_state->out_fb) {
389 drm_framebuffer_reference(c_state->out_fb);
390 rc = msm_framebuffer_prepare(c_state->out_fb,
391 c_state->mmu_id);
392 if (rc)
393 SDE_ERROR("failed to prepare fb, %d\n", rc);
394 }
395
396 return &c_state->base;
397}
398
399static int sde_connector_atomic_set_property(struct drm_connector *connector,
400 struct drm_connector_state *state,
401 struct drm_property *property,
402 uint64_t val)
403{
404 struct sde_connector *c_conn;
405 struct sde_connector_state *c_state;
406 int idx, rc;
407
408 if (!connector || !state || !property) {
409 SDE_ERROR("invalid argument(s), conn %pK, state %pK, prp %pK\n",
410 connector, state, property);
411 return -EINVAL;
412 }
413
414 c_conn = to_sde_connector(connector);
415 c_state = to_sde_connector_state(state);
416
417 /* generic property handling */
418 rc = msm_property_atomic_set(&c_conn->property_info,
419 c_state->property_values, 0, property, val);
420 if (rc)
421 goto end;
422
423 /* connector-specific property handling */
424 idx = msm_property_index(&c_conn->property_info, property);
425
426 if (idx == CONNECTOR_PROP_OUT_FB) {
427 /* clear old fb, if present */
428 if (c_state->out_fb)
429 _sde_connector_destroy_fb(c_conn, c_state);
430
431 /* convert fb val to drm framebuffer and prepare it */
432 c_state->out_fb =
433 drm_framebuffer_lookup(connector->dev, val);
Alan Kwongae1b1142017-03-05 16:07:10 -0800434 if (!c_state->out_fb && val) {
Clarence Ipdd8021c2016-07-20 16:39:47 -0400435 SDE_ERROR("failed to look up fb %lld\n", val);
436 rc = -EFAULT;
Alan Kwongae1b1142017-03-05 16:07:10 -0800437 } else if (!c_state->out_fb && !val) {
438 SDE_DEBUG("cleared fb_id\n");
439 rc = 0;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400440 } else {
Alan Kwong578cdaf2017-01-28 17:25:43 -0800441 msm_framebuffer_set_kmap(c_state->out_fb,
442 c_conn->fb_kmap);
443
Alan Kwongdfa8c082016-07-29 04:10:00 -0400444 if (c_state->out_fb->flags & DRM_MODE_FB_SECURE)
445 c_state->mmu_id =
446 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE];
447 else
448 c_state->mmu_id =
449 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE];
Clarence Ipdd8021c2016-07-20 16:39:47 -0400450
451 rc = msm_framebuffer_prepare(c_state->out_fb,
452 c_state->mmu_id);
453 if (rc)
454 SDE_ERROR("prep fb failed, %d\n", rc);
455 }
456 }
457
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400458 if (idx == CONNECTOR_PROP_TOPOLOGY_CONTROL) {
459 rc = sde_rm_check_property_topctl(val);
460 if (rc)
461 SDE_ERROR("invalid topology_control: 0x%llX\n", val);
462 }
463
Clarence Ipdd8021c2016-07-20 16:39:47 -0400464 /* check for custom property handling */
465 if (!rc && c_conn->ops.set_property) {
466 rc = c_conn->ops.set_property(connector,
467 state,
468 idx,
469 val,
470 c_conn->display);
471
472 /* potentially clean up out_fb if rc != 0 */
473 if ((idx == CONNECTOR_PROP_OUT_FB) && rc)
474 _sde_connector_destroy_fb(c_conn, c_state);
475 }
476end:
477 return rc;
478}
479
480static int sde_connector_set_property(struct drm_connector *connector,
481 struct drm_property *property,
482 uint64_t val)
483{
484 if (!connector) {
485 SDE_ERROR("invalid connector\n");
486 return -EINVAL;
487 }
488
489 return sde_connector_atomic_set_property(connector,
490 connector->state, property, val);
491}
492
493static int sde_connector_atomic_get_property(struct drm_connector *connector,
494 const struct drm_connector_state *state,
495 struct drm_property *property,
496 uint64_t *val)
497{
498 struct sde_connector *c_conn;
499 struct sde_connector_state *c_state;
500 int idx, rc = -EINVAL;
501
502 if (!connector || !state) {
503 SDE_ERROR("invalid argument(s), conn %pK, state %pK\n",
504 connector, state);
505 return -EINVAL;
506 }
507
508 c_conn = to_sde_connector(connector);
509 c_state = to_sde_connector_state(state);
510
511 idx = msm_property_index(&c_conn->property_info, property);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400512 if (idx == CONNECTOR_PROP_RETIRE_FENCE)
Clarence Ip9a74a442016-08-25 18:29:03 -0400513 /*
514 * Set a fence offset if not a virtual connector, so that the
515 * fence signals after one additional commit rather than at the
516 * end of the current one.
517 */
518 rc = sde_fence_create(&c_conn->retire_fence, val,
519 c_conn->connector_type != DRM_MODE_CONNECTOR_VIRTUAL);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400520 else
521 /* get cached property value */
522 rc = msm_property_atomic_get(&c_conn->property_info,
523 c_state->property_values, 0, property, val);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400524
525 /* allow for custom override */
526 if (c_conn->ops.get_property)
527 rc = c_conn->ops.get_property(connector,
528 (struct drm_connector_state *)state,
529 idx,
530 val,
531 c_conn->display);
532 return rc;
533}
534
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400535void sde_connector_prepare_fence(struct drm_connector *connector)
536{
537 if (!connector) {
538 SDE_ERROR("invalid connector\n");
539 return;
540 }
541
542 sde_fence_prepare(&to_sde_connector(connector)->retire_fence);
543}
544
545void sde_connector_complete_commit(struct drm_connector *connector)
546{
547 if (!connector) {
548 SDE_ERROR("invalid connector\n");
549 return;
550 }
551
552 /* signal connector's retire fence */
553 sde_fence_signal(&to_sde_connector(connector)->retire_fence, 0);
554}
555
Clarence Ipdd8021c2016-07-20 16:39:47 -0400556static enum drm_connector_status
557sde_connector_detect(struct drm_connector *connector, bool force)
558{
559 enum drm_connector_status status = connector_status_unknown;
560 struct sde_connector *c_conn;
561
562 if (!connector) {
563 SDE_ERROR("invalid connector\n");
564 return status;
565 }
566
567 c_conn = to_sde_connector(connector);
568
569 if (c_conn->ops.detect)
570 status = c_conn->ops.detect(connector,
571 force,
572 c_conn->display);
573
574 return status;
575}
576
Alan Kwong578cdaf2017-01-28 17:25:43 -0800577#ifdef CONFIG_DEBUG_FS
578/**
579 * sde_connector_init_debugfs - initialize connector debugfs
580 * @connector: Pointer to drm connector
581 */
582static int sde_connector_init_debugfs(struct drm_connector *connector)
583{
584 struct sde_connector *sde_connector;
585
586 if (!connector || !connector->debugfs_entry) {
587 SDE_ERROR("invalid connector\n");
588 return -EINVAL;
589 }
590
591 sde_connector = to_sde_connector(connector);
592
593 if (!debugfs_create_bool("fb_kmap", 0644, connector->debugfs_entry,
594 &sde_connector->fb_kmap)) {
595 SDE_ERROR("failed to create connector fb_kmap\n");
596 return -ENOMEM;
597 }
598
599 return 0;
600}
601#else
602static int sde_connector_init_debugfs(struct drm_connector *connector)
603{
604 return 0;
605}
606#endif
607
608static int sde_connector_late_register(struct drm_connector *connector)
609{
610 return sde_connector_init_debugfs(connector);
611}
612
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -0700613static void sde_connector_early_unregister(struct drm_connector *connector)
614{
615 /* debugfs under connector->debugfs are deleted by drm_debugfs */
616}
617
Clarence Ipdd8021c2016-07-20 16:39:47 -0400618static const struct drm_connector_funcs sde_connector_ops = {
619 .dpms = drm_atomic_helper_connector_dpms,
620 .reset = sde_connector_atomic_reset,
621 .detect = sde_connector_detect,
622 .destroy = sde_connector_destroy,
623 .fill_modes = drm_helper_probe_single_connector_modes,
624 .atomic_duplicate_state = sde_connector_atomic_duplicate_state,
625 .atomic_destroy_state = sde_connector_atomic_destroy_state,
626 .atomic_set_property = sde_connector_atomic_set_property,
627 .atomic_get_property = sde_connector_atomic_get_property,
628 .set_property = sde_connector_set_property,
Alan Kwong578cdaf2017-01-28 17:25:43 -0800629 .late_register = sde_connector_late_register,
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -0700630 .early_unregister = sde_connector_early_unregister,
Clarence Ipdd8021c2016-07-20 16:39:47 -0400631};
632
633static int sde_connector_get_modes(struct drm_connector *connector)
634{
635 struct sde_connector *c_conn;
636
637 if (!connector) {
638 SDE_ERROR("invalid connector\n");
639 return 0;
640 }
641
642 c_conn = to_sde_connector(connector);
643 if (!c_conn->ops.get_modes) {
644 SDE_DEBUG("missing get_modes callback\n");
645 return 0;
646 }
647
648 return c_conn->ops.get_modes(connector, c_conn->display);
649}
650
651static enum drm_mode_status
652sde_connector_mode_valid(struct drm_connector *connector,
653 struct drm_display_mode *mode)
654{
655 struct sde_connector *c_conn;
656
657 if (!connector || !mode) {
658 SDE_ERROR("invalid argument(s), conn %pK, mode %pK\n",
659 connector, mode);
660 return MODE_ERROR;
661 }
662
663 c_conn = to_sde_connector(connector);
664
665 if (c_conn->ops.mode_valid)
666 return c_conn->ops.mode_valid(connector, mode, c_conn->display);
667
668 /* assume all modes okay by default */
669 return MODE_OK;
670}
671
672static struct drm_encoder *
673sde_connector_best_encoder(struct drm_connector *connector)
674{
675 struct sde_connector *c_conn = to_sde_connector(connector);
676
677 if (!connector) {
678 SDE_ERROR("invalid connector\n");
679 return NULL;
680 }
681
682 /*
683 * This is true for now, revisit this code when multiple encoders are
684 * supported.
685 */
686 return c_conn->encoder;
687}
688
689static const struct drm_connector_helper_funcs sde_connector_helper_ops = {
690 .get_modes = sde_connector_get_modes,
691 .mode_valid = sde_connector_mode_valid,
692 .best_encoder = sde_connector_best_encoder,
693};
694
695struct drm_connector *sde_connector_init(struct drm_device *dev,
696 struct drm_encoder *encoder,
697 struct drm_panel *panel,
698 void *display,
699 const struct sde_connector_ops *ops,
700 int connector_poll,
701 int connector_type)
702{
703 struct msm_drm_private *priv;
704 struct sde_kms *sde_kms;
705 struct sde_kms_info *info;
706 struct sde_connector *c_conn = NULL;
Ping Li898b1bf2017-02-09 18:03:28 -0800707 struct dsi_display *dsi_display;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400708 int rc;
709
710 if (!dev || !dev->dev_private || !encoder) {
711 SDE_ERROR("invalid argument(s), dev %pK, enc %pK\n",
712 dev, encoder);
713 return ERR_PTR(-EINVAL);
714 }
715
716 priv = dev->dev_private;
717 if (!priv->kms) {
718 SDE_ERROR("invalid kms reference\n");
719 return ERR_PTR(-EINVAL);
720 }
721
722 c_conn = kzalloc(sizeof(*c_conn), GFP_KERNEL);
723 if (!c_conn) {
724 SDE_ERROR("failed to alloc sde connector\n");
725 return ERR_PTR(-ENOMEM);
726 }
727
728 rc = drm_connector_init(dev,
729 &c_conn->base,
730 &sde_connector_ops,
731 connector_type);
732 if (rc)
733 goto error_free_conn;
734
Clarence Ipa18d4832017-03-13 12:35:44 -0700735 spin_lock_init(&c_conn->event_lock);
736
Clarence Ipdd8021c2016-07-20 16:39:47 -0400737 c_conn->connector_type = connector_type;
738 c_conn->encoder = encoder;
739 c_conn->panel = panel;
740 c_conn->display = display;
741
Alan Kwongdfa8c082016-07-29 04:10:00 -0400742 /* cache mmu_id's for later */
Clarence Ipdd8021c2016-07-20 16:39:47 -0400743 sde_kms = to_sde_kms(priv->kms);
Alan Kwongdfa8c082016-07-29 04:10:00 -0400744 if (sde_kms->vbif[VBIF_NRT]) {
745 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] =
746 sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_UNSECURE];
747 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE] =
748 sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_SECURE];
749 } else {
750 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] =
751 sde_kms->mmu_id[MSM_SMMU_DOMAIN_UNSECURE];
752 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE] =
753 sde_kms->mmu_id[MSM_SMMU_DOMAIN_SECURE];
754 }
Clarence Ipdd8021c2016-07-20 16:39:47 -0400755
756 if (ops)
757 c_conn->ops = *ops;
758
759 c_conn->base.helper_private = &sde_connector_helper_ops;
760 c_conn->base.polled = connector_poll;
761 c_conn->base.interlace_allowed = 0;
762 c_conn->base.doublescan_allowed = 0;
763
764 snprintf(c_conn->name,
765 SDE_CONNECTOR_NAME_SIZE,
766 "conn%u",
767 c_conn->base.base.id);
768
Lloyd Atkinson5d40d312016-09-06 08:34:13 -0400769 rc = sde_fence_init(&c_conn->retire_fence, c_conn->name,
770 c_conn->base.base.id);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400771 if (rc) {
772 SDE_ERROR("failed to init fence, %d\n", rc);
773 goto error_cleanup_conn;
774 }
775
Clarence Ipdd8021c2016-07-20 16:39:47 -0400776 rc = drm_mode_connector_attach_encoder(&c_conn->base, encoder);
777 if (rc) {
778 SDE_ERROR("failed to attach encoder to connector, %d\n", rc);
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -0800779 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400780 }
781
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800782 rc = sde_backlight_setup(c_conn);
783 if (rc) {
784 SDE_ERROR("failed to setup backlight, rc=%d\n", rc);
785 goto error_cleanup_fence;
Vishnuvardhan Prodduturi75b96802016-10-17 18:45:55 +0530786 }
787
Clarence Ipdd8021c2016-07-20 16:39:47 -0400788 /* create properties */
789 msm_property_init(&c_conn->property_info, &c_conn->base.base, dev,
790 priv->conn_property, c_conn->property_data,
791 CONNECTOR_PROP_COUNT, CONNECTOR_PROP_BLOBCOUNT,
792 sizeof(struct sde_connector_state));
793
794 if (c_conn->ops.post_init) {
795 info = kmalloc(sizeof(*info), GFP_KERNEL);
796 if (!info) {
797 SDE_ERROR("failed to allocate info buffer\n");
798 rc = -ENOMEM;
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -0800799 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400800 }
801
802 sde_kms_info_reset(info);
803 rc = c_conn->ops.post_init(&c_conn->base, info, display);
804 if (rc) {
805 SDE_ERROR("post-init failed, %d\n", rc);
806 kfree(info);
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -0800807 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400808 }
809
810 msm_property_install_blob(&c_conn->property_info,
Dhaval Patel4e574842016-08-23 15:11:37 -0700811 "capabilities",
Clarence Ipdd8021c2016-07-20 16:39:47 -0400812 DRM_MODE_PROP_IMMUTABLE,
813 CONNECTOR_PROP_SDE_INFO);
814
815 msm_property_set_blob(&c_conn->property_info,
Dhaval Patel4e574842016-08-23 15:11:37 -0700816 &c_conn->blob_caps,
Clarence Ipdd8021c2016-07-20 16:39:47 -0400817 SDE_KMS_INFO_DATA(info),
818 SDE_KMS_INFO_DATALEN(info),
819 CONNECTOR_PROP_SDE_INFO);
820 kfree(info);
821 }
822
Ping Li898b1bf2017-02-09 18:03:28 -0800823 if (connector_type == DRM_MODE_CONNECTOR_DSI) {
824 dsi_display = (struct dsi_display *)(display);
825 if (dsi_display && dsi_display->panel &&
826 dsi_display->panel->hdr_props.hdr_enabled == true) {
827 msm_property_install_blob(&c_conn->property_info,
828 "hdr_properties",
829 DRM_MODE_PROP_IMMUTABLE,
830 CONNECTOR_PROP_HDR_INFO);
831
832 msm_property_set_blob(&c_conn->property_info,
833 &c_conn->blob_hdr,
834 &dsi_display->panel->hdr_props,
835 sizeof(dsi_display->panel->hdr_props),
836 CONNECTOR_PROP_HDR_INFO);
837 }
838 }
839
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400840 msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE",
Dhaval Patel4e574842016-08-23 15:11:37 -0700841 0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400842
Lloyd Atkinsonb6191972016-08-10 18:31:46 -0400843 /* enum/bitmask properties */
844 msm_property_install_enum(&c_conn->property_info, "topology_name",
845 DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name,
846 ARRAY_SIZE(e_topology_name),
847 CONNECTOR_PROP_TOPOLOGY_NAME);
848 msm_property_install_enum(&c_conn->property_info, "topology_control",
849 0, 1, e_topology_control,
850 ARRAY_SIZE(e_topology_control),
851 CONNECTOR_PROP_TOPOLOGY_CONTROL);
852
Clarence Ipdd8021c2016-07-20 16:39:47 -0400853 rc = msm_property_install_get_status(&c_conn->property_info);
854 if (rc) {
855 SDE_ERROR("failed to create one or more properties\n");
856 goto error_destroy_property;
857 }
858
Lloyd Atkinsonb6191972016-08-10 18:31:46 -0400859 SDE_DEBUG("connector %d attach encoder %d\n",
860 c_conn->base.base.id, encoder->base.id);
861
Clarence Ipdd8021c2016-07-20 16:39:47 -0400862 priv->connectors[priv->num_connectors++] = &c_conn->base;
863
864 return &c_conn->base;
865
866error_destroy_property:
Dhaval Patel4e574842016-08-23 15:11:37 -0700867 if (c_conn->blob_caps)
868 drm_property_unreference_blob(c_conn->blob_caps);
Ping Li898b1bf2017-02-09 18:03:28 -0800869 if (c_conn->blob_hdr)
870 drm_property_unreference_blob(c_conn->blob_hdr);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400871 msm_property_destroy(&c_conn->property_info);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400872error_cleanup_fence:
873 sde_fence_deinit(&c_conn->retire_fence);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400874error_cleanup_conn:
875 drm_connector_cleanup(&c_conn->base);
876error_free_conn:
877 kfree(c_conn);
878
879 return ERR_PTR(rc);
880}
Gopikrishnaiah Anandande2c81b2017-03-15 12:41:29 -0700881
882int sde_connector_register_custom_event(struct sde_kms *kms,
883 struct drm_connector *conn_drm, u32 event, bool val)
884{
885 return -EINVAL;
886}