blob: e4ebece7f8a82327bd4f1c0462af96025010ac01 [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
Veera Sundaram Sankaranbb2bf9a2017-03-29 18:56:47 -0700250void sde_connector_clk_ctrl(struct drm_connector *connector, bool enable)
251{
252 struct sde_connector *c_conn;
253 struct dsi_display *display;
254 u32 state = enable ? DSI_CLK_ON : DSI_CLK_OFF;
255
256 if (!connector) {
257 SDE_ERROR("invalid connector\n");
258 return;
259 }
260
261 c_conn = to_sde_connector(connector);
262 display = (struct dsi_display *) c_conn->display;
263
264 if (display && c_conn->ops.clk_ctrl)
265 c_conn->ops.clk_ctrl(display->mdp_clk_handle,
266 DSI_ALL_CLKS, state);
267}
268
Clarence Ipdd8021c2016-07-20 16:39:47 -0400269static void sde_connector_destroy(struct drm_connector *connector)
270{
271 struct sde_connector *c_conn;
272
273 if (!connector) {
274 SDE_ERROR("invalid connector\n");
275 return;
276 }
277
278 c_conn = to_sde_connector(connector);
279
Dhaval Patel4e574842016-08-23 15:11:37 -0700280 if (c_conn->blob_caps)
281 drm_property_unreference_blob(c_conn->blob_caps);
Ping Li898b1bf2017-02-09 18:03:28 -0800282 if (c_conn->blob_hdr)
283 drm_property_unreference_blob(c_conn->blob_hdr);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400284 msm_property_destroy(&c_conn->property_info);
285
286 drm_connector_unregister(connector);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400287 sde_fence_deinit(&c_conn->retire_fence);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400288 drm_connector_cleanup(connector);
289 kfree(c_conn);
290}
291
292/**
293 * _sde_connector_destroy_fb - clean up connector state's out_fb buffer
294 * @c_conn: Pointer to sde connector structure
295 * @c_state: Pointer to sde connector state structure
296 */
297static void _sde_connector_destroy_fb(struct sde_connector *c_conn,
298 struct sde_connector_state *c_state)
299{
300 if (!c_state || !c_state->out_fb) {
301 SDE_ERROR("invalid state %pK\n", c_state);
302 return;
303 }
304
305 msm_framebuffer_cleanup(c_state->out_fb,
306 c_state->mmu_id);
307 drm_framebuffer_unreference(c_state->out_fb);
308 c_state->out_fb = NULL;
309
310 if (c_conn) {
311 c_state->property_values[CONNECTOR_PROP_OUT_FB] =
312 msm_property_get_default(&c_conn->property_info,
313 CONNECTOR_PROP_OUT_FB);
314 } else {
315 c_state->property_values[CONNECTOR_PROP_OUT_FB] = ~0;
316 }
317}
318
319static void sde_connector_atomic_destroy_state(struct drm_connector *connector,
320 struct drm_connector_state *state)
321{
322 struct sde_connector *c_conn = NULL;
323 struct sde_connector_state *c_state = NULL;
324
325 if (!state) {
326 SDE_ERROR("invalid state\n");
327 return;
328 }
329
330 /*
331 * The base DRM framework currently always passes in a NULL
332 * connector pointer. This is not correct, but attempt to
333 * handle that case as much as possible.
334 */
335 if (connector)
336 c_conn = to_sde_connector(connector);
337 c_state = to_sde_connector_state(state);
338
339 if (c_state->out_fb)
340 _sde_connector_destroy_fb(c_conn, c_state);
341
342 if (!c_conn) {
343 kfree(c_state);
344 } else {
345 /* destroy value helper */
346 msm_property_destroy_state(&c_conn->property_info, c_state,
347 c_state->property_values, 0);
348 }
349}
350
351static void sde_connector_atomic_reset(struct drm_connector *connector)
352{
353 struct sde_connector *c_conn;
354 struct sde_connector_state *c_state;
355
356 if (!connector) {
357 SDE_ERROR("invalid connector\n");
358 return;
359 }
360
361 c_conn = to_sde_connector(connector);
362
363 if (connector->state) {
364 sde_connector_atomic_destroy_state(connector, connector->state);
365 connector->state = 0;
366 }
367
368 c_state = msm_property_alloc_state(&c_conn->property_info);
369 if (!c_state) {
370 SDE_ERROR("state alloc failed\n");
371 return;
372 }
373
374 /* reset value helper, zero out state structure and reset properties */
375 msm_property_reset_state(&c_conn->property_info, c_state,
376 c_state->property_values, 0);
377
378 c_state->base.connector = connector;
379 connector->state = &c_state->base;
380}
381
382static struct drm_connector_state *
383sde_connector_atomic_duplicate_state(struct drm_connector *connector)
384{
385 struct sde_connector *c_conn;
386 struct sde_connector_state *c_state, *c_oldstate;
387 int rc;
388
389 if (!connector || !connector->state) {
390 SDE_ERROR("invalid connector %pK\n", connector);
391 return NULL;
392 }
393
394 c_conn = to_sde_connector(connector);
395 c_oldstate = to_sde_connector_state(connector->state);
396 c_state = msm_property_alloc_state(&c_conn->property_info);
397 if (!c_state) {
398 SDE_ERROR("state alloc failed\n");
399 return NULL;
400 }
401
402 /* duplicate value helper */
403 msm_property_duplicate_state(&c_conn->property_info,
404 c_oldstate, c_state, c_state->property_values, 0);
405
406 /* additional handling for drm framebuffer objects */
407 if (c_state->out_fb) {
408 drm_framebuffer_reference(c_state->out_fb);
409 rc = msm_framebuffer_prepare(c_state->out_fb,
410 c_state->mmu_id);
411 if (rc)
412 SDE_ERROR("failed to prepare fb, %d\n", rc);
413 }
414
415 return &c_state->base;
416}
417
418static int sde_connector_atomic_set_property(struct drm_connector *connector,
419 struct drm_connector_state *state,
420 struct drm_property *property,
421 uint64_t val)
422{
423 struct sde_connector *c_conn;
424 struct sde_connector_state *c_state;
425 int idx, rc;
426
427 if (!connector || !state || !property) {
428 SDE_ERROR("invalid argument(s), conn %pK, state %pK, prp %pK\n",
429 connector, state, property);
430 return -EINVAL;
431 }
432
433 c_conn = to_sde_connector(connector);
434 c_state = to_sde_connector_state(state);
435
436 /* generic property handling */
437 rc = msm_property_atomic_set(&c_conn->property_info,
438 c_state->property_values, 0, property, val);
439 if (rc)
440 goto end;
441
442 /* connector-specific property handling */
443 idx = msm_property_index(&c_conn->property_info, property);
444
445 if (idx == CONNECTOR_PROP_OUT_FB) {
446 /* clear old fb, if present */
447 if (c_state->out_fb)
448 _sde_connector_destroy_fb(c_conn, c_state);
449
450 /* convert fb val to drm framebuffer and prepare it */
451 c_state->out_fb =
452 drm_framebuffer_lookup(connector->dev, val);
Alan Kwongae1b1142017-03-05 16:07:10 -0800453 if (!c_state->out_fb && val) {
Clarence Ipdd8021c2016-07-20 16:39:47 -0400454 SDE_ERROR("failed to look up fb %lld\n", val);
455 rc = -EFAULT;
Alan Kwongae1b1142017-03-05 16:07:10 -0800456 } else if (!c_state->out_fb && !val) {
457 SDE_DEBUG("cleared fb_id\n");
458 rc = 0;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400459 } else {
Alan Kwong578cdaf2017-01-28 17:25:43 -0800460 msm_framebuffer_set_kmap(c_state->out_fb,
461 c_conn->fb_kmap);
462
Alan Kwongdfa8c082016-07-29 04:10:00 -0400463 if (c_state->out_fb->flags & DRM_MODE_FB_SECURE)
464 c_state->mmu_id =
465 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE];
466 else
467 c_state->mmu_id =
468 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE];
Clarence Ipdd8021c2016-07-20 16:39:47 -0400469
470 rc = msm_framebuffer_prepare(c_state->out_fb,
471 c_state->mmu_id);
472 if (rc)
473 SDE_ERROR("prep fb failed, %d\n", rc);
474 }
475 }
476
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400477 if (idx == CONNECTOR_PROP_TOPOLOGY_CONTROL) {
478 rc = sde_rm_check_property_topctl(val);
479 if (rc)
480 SDE_ERROR("invalid topology_control: 0x%llX\n", val);
481 }
482
Clarence Ipdd8021c2016-07-20 16:39:47 -0400483 /* check for custom property handling */
484 if (!rc && c_conn->ops.set_property) {
485 rc = c_conn->ops.set_property(connector,
486 state,
487 idx,
488 val,
489 c_conn->display);
490
491 /* potentially clean up out_fb if rc != 0 */
492 if ((idx == CONNECTOR_PROP_OUT_FB) && rc)
493 _sde_connector_destroy_fb(c_conn, c_state);
494 }
495end:
496 return rc;
497}
498
499static int sde_connector_set_property(struct drm_connector *connector,
500 struct drm_property *property,
501 uint64_t val)
502{
503 if (!connector) {
504 SDE_ERROR("invalid connector\n");
505 return -EINVAL;
506 }
507
508 return sde_connector_atomic_set_property(connector,
509 connector->state, property, val);
510}
511
512static int sde_connector_atomic_get_property(struct drm_connector *connector,
513 const struct drm_connector_state *state,
514 struct drm_property *property,
515 uint64_t *val)
516{
517 struct sde_connector *c_conn;
518 struct sde_connector_state *c_state;
519 int idx, rc = -EINVAL;
520
521 if (!connector || !state) {
522 SDE_ERROR("invalid argument(s), conn %pK, state %pK\n",
523 connector, state);
524 return -EINVAL;
525 }
526
527 c_conn = to_sde_connector(connector);
528 c_state = to_sde_connector_state(state);
529
530 idx = msm_property_index(&c_conn->property_info, property);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400531 if (idx == CONNECTOR_PROP_RETIRE_FENCE)
Clarence Ip9a74a442016-08-25 18:29:03 -0400532 /*
533 * Set a fence offset if not a virtual connector, so that the
534 * fence signals after one additional commit rather than at the
535 * end of the current one.
536 */
537 rc = sde_fence_create(&c_conn->retire_fence, val,
538 c_conn->connector_type != DRM_MODE_CONNECTOR_VIRTUAL);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400539 else
540 /* get cached property value */
541 rc = msm_property_atomic_get(&c_conn->property_info,
542 c_state->property_values, 0, property, val);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400543
544 /* allow for custom override */
545 if (c_conn->ops.get_property)
546 rc = c_conn->ops.get_property(connector,
547 (struct drm_connector_state *)state,
548 idx,
549 val,
550 c_conn->display);
551 return rc;
552}
553
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400554void sde_connector_prepare_fence(struct drm_connector *connector)
555{
556 if (!connector) {
557 SDE_ERROR("invalid connector\n");
558 return;
559 }
560
561 sde_fence_prepare(&to_sde_connector(connector)->retire_fence);
562}
563
564void sde_connector_complete_commit(struct drm_connector *connector)
565{
566 if (!connector) {
567 SDE_ERROR("invalid connector\n");
568 return;
569 }
570
571 /* signal connector's retire fence */
572 sde_fence_signal(&to_sde_connector(connector)->retire_fence, 0);
573}
574
Clarence Ipdd8021c2016-07-20 16:39:47 -0400575static enum drm_connector_status
576sde_connector_detect(struct drm_connector *connector, bool force)
577{
578 enum drm_connector_status status = connector_status_unknown;
579 struct sde_connector *c_conn;
580
581 if (!connector) {
582 SDE_ERROR("invalid connector\n");
583 return status;
584 }
585
586 c_conn = to_sde_connector(connector);
587
588 if (c_conn->ops.detect)
589 status = c_conn->ops.detect(connector,
590 force,
591 c_conn->display);
592
593 return status;
594}
595
Alan Kwong578cdaf2017-01-28 17:25:43 -0800596#ifdef CONFIG_DEBUG_FS
597/**
598 * sde_connector_init_debugfs - initialize connector debugfs
599 * @connector: Pointer to drm connector
600 */
601static int sde_connector_init_debugfs(struct drm_connector *connector)
602{
603 struct sde_connector *sde_connector;
604
605 if (!connector || !connector->debugfs_entry) {
606 SDE_ERROR("invalid connector\n");
607 return -EINVAL;
608 }
609
610 sde_connector = to_sde_connector(connector);
611
612 if (!debugfs_create_bool("fb_kmap", 0644, connector->debugfs_entry,
613 &sde_connector->fb_kmap)) {
614 SDE_ERROR("failed to create connector fb_kmap\n");
615 return -ENOMEM;
616 }
617
618 return 0;
619}
620#else
621static int sde_connector_init_debugfs(struct drm_connector *connector)
622{
623 return 0;
624}
625#endif
626
627static int sde_connector_late_register(struct drm_connector *connector)
628{
629 return sde_connector_init_debugfs(connector);
630}
631
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -0700632static void sde_connector_early_unregister(struct drm_connector *connector)
633{
634 /* debugfs under connector->debugfs are deleted by drm_debugfs */
635}
636
Clarence Ipdd8021c2016-07-20 16:39:47 -0400637static const struct drm_connector_funcs sde_connector_ops = {
638 .dpms = drm_atomic_helper_connector_dpms,
639 .reset = sde_connector_atomic_reset,
640 .detect = sde_connector_detect,
641 .destroy = sde_connector_destroy,
642 .fill_modes = drm_helper_probe_single_connector_modes,
643 .atomic_duplicate_state = sde_connector_atomic_duplicate_state,
644 .atomic_destroy_state = sde_connector_atomic_destroy_state,
645 .atomic_set_property = sde_connector_atomic_set_property,
646 .atomic_get_property = sde_connector_atomic_get_property,
647 .set_property = sde_connector_set_property,
Alan Kwong578cdaf2017-01-28 17:25:43 -0800648 .late_register = sde_connector_late_register,
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -0700649 .early_unregister = sde_connector_early_unregister,
Clarence Ipdd8021c2016-07-20 16:39:47 -0400650};
651
652static int sde_connector_get_modes(struct drm_connector *connector)
653{
654 struct sde_connector *c_conn;
655
656 if (!connector) {
657 SDE_ERROR("invalid connector\n");
658 return 0;
659 }
660
661 c_conn = to_sde_connector(connector);
662 if (!c_conn->ops.get_modes) {
663 SDE_DEBUG("missing get_modes callback\n");
664 return 0;
665 }
666
667 return c_conn->ops.get_modes(connector, c_conn->display);
668}
669
670static enum drm_mode_status
671sde_connector_mode_valid(struct drm_connector *connector,
672 struct drm_display_mode *mode)
673{
674 struct sde_connector *c_conn;
675
676 if (!connector || !mode) {
677 SDE_ERROR("invalid argument(s), conn %pK, mode %pK\n",
678 connector, mode);
679 return MODE_ERROR;
680 }
681
682 c_conn = to_sde_connector(connector);
683
684 if (c_conn->ops.mode_valid)
685 return c_conn->ops.mode_valid(connector, mode, c_conn->display);
686
687 /* assume all modes okay by default */
688 return MODE_OK;
689}
690
691static struct drm_encoder *
692sde_connector_best_encoder(struct drm_connector *connector)
693{
694 struct sde_connector *c_conn = to_sde_connector(connector);
695
696 if (!connector) {
697 SDE_ERROR("invalid connector\n");
698 return NULL;
699 }
700
701 /*
702 * This is true for now, revisit this code when multiple encoders are
703 * supported.
704 */
705 return c_conn->encoder;
706}
707
708static const struct drm_connector_helper_funcs sde_connector_helper_ops = {
709 .get_modes = sde_connector_get_modes,
710 .mode_valid = sde_connector_mode_valid,
711 .best_encoder = sde_connector_best_encoder,
712};
713
714struct drm_connector *sde_connector_init(struct drm_device *dev,
715 struct drm_encoder *encoder,
716 struct drm_panel *panel,
717 void *display,
718 const struct sde_connector_ops *ops,
719 int connector_poll,
720 int connector_type)
721{
722 struct msm_drm_private *priv;
723 struct sde_kms *sde_kms;
724 struct sde_kms_info *info;
725 struct sde_connector *c_conn = NULL;
Ping Li898b1bf2017-02-09 18:03:28 -0800726 struct dsi_display *dsi_display;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400727 int rc;
728
729 if (!dev || !dev->dev_private || !encoder) {
730 SDE_ERROR("invalid argument(s), dev %pK, enc %pK\n",
731 dev, encoder);
732 return ERR_PTR(-EINVAL);
733 }
734
735 priv = dev->dev_private;
736 if (!priv->kms) {
737 SDE_ERROR("invalid kms reference\n");
738 return ERR_PTR(-EINVAL);
739 }
740
741 c_conn = kzalloc(sizeof(*c_conn), GFP_KERNEL);
742 if (!c_conn) {
743 SDE_ERROR("failed to alloc sde connector\n");
744 return ERR_PTR(-ENOMEM);
745 }
746
747 rc = drm_connector_init(dev,
748 &c_conn->base,
749 &sde_connector_ops,
750 connector_type);
751 if (rc)
752 goto error_free_conn;
753
Clarence Ipa18d4832017-03-13 12:35:44 -0700754 spin_lock_init(&c_conn->event_lock);
755
Clarence Ipdd8021c2016-07-20 16:39:47 -0400756 c_conn->connector_type = connector_type;
757 c_conn->encoder = encoder;
758 c_conn->panel = panel;
759 c_conn->display = display;
760
Alan Kwongdfa8c082016-07-29 04:10:00 -0400761 /* cache mmu_id's for later */
Clarence Ipdd8021c2016-07-20 16:39:47 -0400762 sde_kms = to_sde_kms(priv->kms);
Alan Kwongdfa8c082016-07-29 04:10:00 -0400763 if (sde_kms->vbif[VBIF_NRT]) {
764 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] =
765 sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_UNSECURE];
766 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE] =
767 sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_SECURE];
768 } else {
769 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] =
770 sde_kms->mmu_id[MSM_SMMU_DOMAIN_UNSECURE];
771 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE] =
772 sde_kms->mmu_id[MSM_SMMU_DOMAIN_SECURE];
773 }
Clarence Ipdd8021c2016-07-20 16:39:47 -0400774
775 if (ops)
776 c_conn->ops = *ops;
777
778 c_conn->base.helper_private = &sde_connector_helper_ops;
779 c_conn->base.polled = connector_poll;
780 c_conn->base.interlace_allowed = 0;
781 c_conn->base.doublescan_allowed = 0;
782
783 snprintf(c_conn->name,
784 SDE_CONNECTOR_NAME_SIZE,
785 "conn%u",
786 c_conn->base.base.id);
787
Lloyd Atkinson5d40d312016-09-06 08:34:13 -0400788 rc = sde_fence_init(&c_conn->retire_fence, c_conn->name,
789 c_conn->base.base.id);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400790 if (rc) {
791 SDE_ERROR("failed to init fence, %d\n", rc);
792 goto error_cleanup_conn;
793 }
794
Clarence Ipdd8021c2016-07-20 16:39:47 -0400795 rc = drm_mode_connector_attach_encoder(&c_conn->base, encoder);
796 if (rc) {
797 SDE_ERROR("failed to attach encoder to connector, %d\n", rc);
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -0800798 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400799 }
800
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800801 rc = sde_backlight_setup(c_conn);
802 if (rc) {
803 SDE_ERROR("failed to setup backlight, rc=%d\n", rc);
804 goto error_cleanup_fence;
Vishnuvardhan Prodduturi75b96802016-10-17 18:45:55 +0530805 }
806
Clarence Ipdd8021c2016-07-20 16:39:47 -0400807 /* create properties */
808 msm_property_init(&c_conn->property_info, &c_conn->base.base, dev,
809 priv->conn_property, c_conn->property_data,
810 CONNECTOR_PROP_COUNT, CONNECTOR_PROP_BLOBCOUNT,
811 sizeof(struct sde_connector_state));
812
813 if (c_conn->ops.post_init) {
814 info = kmalloc(sizeof(*info), GFP_KERNEL);
815 if (!info) {
816 SDE_ERROR("failed to allocate info buffer\n");
817 rc = -ENOMEM;
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -0800818 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400819 }
820
821 sde_kms_info_reset(info);
822 rc = c_conn->ops.post_init(&c_conn->base, info, display);
823 if (rc) {
824 SDE_ERROR("post-init failed, %d\n", rc);
825 kfree(info);
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -0800826 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400827 }
828
829 msm_property_install_blob(&c_conn->property_info,
Dhaval Patel4e574842016-08-23 15:11:37 -0700830 "capabilities",
Clarence Ipdd8021c2016-07-20 16:39:47 -0400831 DRM_MODE_PROP_IMMUTABLE,
832 CONNECTOR_PROP_SDE_INFO);
833
834 msm_property_set_blob(&c_conn->property_info,
Dhaval Patel4e574842016-08-23 15:11:37 -0700835 &c_conn->blob_caps,
Clarence Ipdd8021c2016-07-20 16:39:47 -0400836 SDE_KMS_INFO_DATA(info),
837 SDE_KMS_INFO_DATALEN(info),
838 CONNECTOR_PROP_SDE_INFO);
839 kfree(info);
840 }
841
Ping Li898b1bf2017-02-09 18:03:28 -0800842 if (connector_type == DRM_MODE_CONNECTOR_DSI) {
843 dsi_display = (struct dsi_display *)(display);
844 if (dsi_display && dsi_display->panel &&
845 dsi_display->panel->hdr_props.hdr_enabled == true) {
846 msm_property_install_blob(&c_conn->property_info,
847 "hdr_properties",
848 DRM_MODE_PROP_IMMUTABLE,
849 CONNECTOR_PROP_HDR_INFO);
850
851 msm_property_set_blob(&c_conn->property_info,
852 &c_conn->blob_hdr,
853 &dsi_display->panel->hdr_props,
854 sizeof(dsi_display->panel->hdr_props),
855 CONNECTOR_PROP_HDR_INFO);
856 }
857 }
858
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400859 msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE",
Dhaval Patel4e574842016-08-23 15:11:37 -0700860 0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400861
Lloyd Atkinsonb6191972016-08-10 18:31:46 -0400862 /* enum/bitmask properties */
863 msm_property_install_enum(&c_conn->property_info, "topology_name",
864 DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name,
865 ARRAY_SIZE(e_topology_name),
866 CONNECTOR_PROP_TOPOLOGY_NAME);
867 msm_property_install_enum(&c_conn->property_info, "topology_control",
868 0, 1, e_topology_control,
869 ARRAY_SIZE(e_topology_control),
870 CONNECTOR_PROP_TOPOLOGY_CONTROL);
871
Clarence Ipdd8021c2016-07-20 16:39:47 -0400872 rc = msm_property_install_get_status(&c_conn->property_info);
873 if (rc) {
874 SDE_ERROR("failed to create one or more properties\n");
875 goto error_destroy_property;
876 }
877
Lloyd Atkinsonb6191972016-08-10 18:31:46 -0400878 SDE_DEBUG("connector %d attach encoder %d\n",
879 c_conn->base.base.id, encoder->base.id);
880
Clarence Ipdd8021c2016-07-20 16:39:47 -0400881 priv->connectors[priv->num_connectors++] = &c_conn->base;
882
883 return &c_conn->base;
884
885error_destroy_property:
Dhaval Patel4e574842016-08-23 15:11:37 -0700886 if (c_conn->blob_caps)
887 drm_property_unreference_blob(c_conn->blob_caps);
Ping Li898b1bf2017-02-09 18:03:28 -0800888 if (c_conn->blob_hdr)
889 drm_property_unreference_blob(c_conn->blob_hdr);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400890 msm_property_destroy(&c_conn->property_info);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400891error_cleanup_fence:
892 sde_fence_deinit(&c_conn->retire_fence);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400893error_cleanup_conn:
894 drm_connector_cleanup(&c_conn->base);
895error_free_conn:
896 kfree(c_conn);
897
898 return ERR_PTR(rc);
899}
Gopikrishnaiah Anandande2c81b2017-03-15 12:41:29 -0700900
901int sde_connector_register_custom_event(struct sde_kms *kms,
902 struct drm_connector *conn_drm, u32 event, bool val)
903{
904 return -EINVAL;
905}