blob: e66005f069803ee51017f6d91f0b40b443b067d4 [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
Shashank Babu Chinta Venkata06c428e2017-04-17 13:52:28 -070081static int sde_backlight_setup(struct sde_connector *c_conn,
82 struct drm_device *dev)
Dhaval Patel7cdd6662017-03-08 13:10:37 -080083{
84 struct backlight_device *bl_device;
85 struct backlight_properties props;
86 struct dsi_display *display;
87 struct dsi_backlight_config *bl_config;
88 static int display_count;
89 char bl_node_name[BL_NODE_NAME_SIZE];
90
Shashank Babu Chinta Venkata06c428e2017-04-17 13:52:28 -070091 if (!c_conn || !dev || !dev->dev) {
Dhaval Patel7cdd6662017-03-08 13:10:37 -080092 SDE_ERROR("invalid param\n");
93 return -EINVAL;
94 } else if (c_conn->connector_type != DRM_MODE_CONNECTOR_DSI) {
95 return 0;
96 }
97
98 memset(&props, 0, sizeof(props));
99 props.type = BACKLIGHT_RAW;
100 props.power = FB_BLANK_UNBLANK;
101
102 display = (struct dsi_display *) c_conn->display;
103 bl_config = &display->panel->bl_config;
104 props.max_brightness = bl_config->brightness_max_level;
105 props.brightness = bl_config->brightness_max_level;
106 snprintf(bl_node_name, BL_NODE_NAME_SIZE, "panel%u-backlight",
107 display_count);
Shashank Babu Chinta Venkata06c428e2017-04-17 13:52:28 -0700108 bl_device = backlight_device_register(bl_node_name, dev->dev,
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800109 c_conn, &sde_backlight_device_ops, &props);
110 if (IS_ERR_OR_NULL(bl_device)) {
111 SDE_ERROR("Failed to register backlight: %ld\n",
112 PTR_ERR(bl_device));
113 return -ENODEV;
114 }
115 display_count++;
116
117 return 0;
118}
119
Clarence Ipa18d4832017-03-13 12:35:44 -0700120int sde_connector_trigger_event(void *drm_connector,
121 uint32_t event_idx, uint32_t instance_idx,
122 uint32_t data0, uint32_t data1,
123 uint32_t data2, uint32_t data3)
124{
125 struct sde_connector *c_conn;
126 unsigned long irq_flags;
127 void (*cb_func)(uint32_t event_idx,
128 uint32_t instance_idx, void *usr,
129 uint32_t data0, uint32_t data1,
130 uint32_t data2, uint32_t data3);
131 void *usr;
132 int rc = 0;
133
134 /*
135 * This function may potentially be called from an ISR context, so
136 * avoid excessive logging/etc.
137 */
138 if (!drm_connector)
139 return -EINVAL;
140 else if (event_idx >= SDE_CONN_EVENT_COUNT)
141 return -EINVAL;
142 c_conn = to_sde_connector(drm_connector);
143
144 spin_lock_irqsave(&c_conn->event_lock, irq_flags);
145 cb_func = c_conn->event_table[event_idx].cb_func;
146 usr = c_conn->event_table[event_idx].usr;
147 spin_unlock_irqrestore(&c_conn->event_lock, irq_flags);
148
149 if (cb_func)
150 cb_func(event_idx, instance_idx, usr,
151 data0, data1, data2, data3);
152 else
153 rc = -EAGAIN;
154
155 return rc;
156}
157
158int sde_connector_register_event(struct drm_connector *connector,
159 uint32_t event_idx,
160 void (*cb_func)(uint32_t event_idx,
161 uint32_t instance_idx, void *usr,
162 uint32_t data0, uint32_t data1,
163 uint32_t data2, uint32_t data3),
164 void *usr)
165{
166 struct sde_connector *c_conn;
167 unsigned long irq_flags;
168
169 if (!connector) {
170 SDE_ERROR("invalid connector\n");
171 return -EINVAL;
172 } else if (event_idx >= SDE_CONN_EVENT_COUNT) {
173 SDE_ERROR("conn%d, invalid event %d\n",
174 connector->base.id, event_idx);
175 return -EINVAL;
176 }
177 c_conn = to_sde_connector(connector);
178
179 spin_lock_irqsave(&c_conn->event_lock, irq_flags);
180 c_conn->event_table[event_idx].cb_func = cb_func;
181 c_conn->event_table[event_idx].usr = usr;
182 spin_unlock_irqrestore(&c_conn->event_lock, irq_flags);
183
184 /* optionally notify display of event registration */
185 if (c_conn->ops.enable_event && c_conn->display)
186 c_conn->ops.enable_event(connector, event_idx,
187 cb_func != NULL, c_conn->display);
188 return 0;
189}
190
191void sde_connector_unregister_event(struct drm_connector *connector,
192 uint32_t event_idx)
193{
194 (void)sde_connector_register_event(connector, event_idx, 0, 0);
195}
196
Clarence Ipcb3afd42016-07-15 16:25:34 -0400197int sde_connector_get_info(struct drm_connector *connector,
198 struct msm_display_info *info)
199{
200 struct sde_connector *c_conn;
201
202 if (!connector || !info) {
203 SDE_ERROR("invalid argument(s), conn %pK, info %pK\n",
204 connector, info);
205 return -EINVAL;
206 }
207
208 c_conn = to_sde_connector(connector);
209
210 if (!c_conn->display || !c_conn->ops.get_info) {
211 SDE_ERROR("display info not supported for %pK\n",
212 c_conn->display);
213 return -EINVAL;
214 }
215
216 return c_conn->ops.get_info(info, c_conn->display);
217}
218
Lloyd Atkinson05d75512017-01-17 14:45:51 -0500219int sde_connector_pre_kickoff(struct drm_connector *connector)
220{
221 struct sde_connector *c_conn;
222 struct sde_connector_state *c_state;
223 struct msm_display_kickoff_params params;
224 int rc;
225
226 if (!connector) {
227 SDE_ERROR("invalid argument\n");
228 return -EINVAL;
229 }
230
231 c_conn = to_sde_connector(connector);
232 c_state = to_sde_connector_state(connector->state);
233
234 if (!c_conn->display) {
235 SDE_ERROR("invalid argument\n");
236 return -EINVAL;
237 }
238
239 if (!c_conn->ops.pre_kickoff)
240 return 0;
241
242 params.rois = &c_state->rois;
243
244 SDE_EVT32_VERBOSE(connector->base.id);
245
246 rc = c_conn->ops.pre_kickoff(connector, c_conn->display, &params);
247
248 return rc;
249}
250
Clarence Ipdd8021c2016-07-20 16:39:47 -0400251static void sde_connector_destroy(struct drm_connector *connector)
252{
253 struct sde_connector *c_conn;
254
255 if (!connector) {
256 SDE_ERROR("invalid connector\n");
257 return;
258 }
259
260 c_conn = to_sde_connector(connector);
261
Dhaval Patel4e574842016-08-23 15:11:37 -0700262 if (c_conn->blob_caps)
263 drm_property_unreference_blob(c_conn->blob_caps);
Ping Li898b1bf2017-02-09 18:03:28 -0800264 if (c_conn->blob_hdr)
265 drm_property_unreference_blob(c_conn->blob_hdr);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400266 msm_property_destroy(&c_conn->property_info);
267
268 drm_connector_unregister(connector);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400269 sde_fence_deinit(&c_conn->retire_fence);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400270 drm_connector_cleanup(connector);
271 kfree(c_conn);
272}
273
274/**
275 * _sde_connector_destroy_fb - clean up connector state's out_fb buffer
276 * @c_conn: Pointer to sde connector structure
277 * @c_state: Pointer to sde connector state structure
278 */
279static void _sde_connector_destroy_fb(struct sde_connector *c_conn,
280 struct sde_connector_state *c_state)
281{
282 if (!c_state || !c_state->out_fb) {
283 SDE_ERROR("invalid state %pK\n", c_state);
284 return;
285 }
286
287 msm_framebuffer_cleanup(c_state->out_fb,
288 c_state->mmu_id);
289 drm_framebuffer_unreference(c_state->out_fb);
290 c_state->out_fb = NULL;
291
292 if (c_conn) {
293 c_state->property_values[CONNECTOR_PROP_OUT_FB] =
294 msm_property_get_default(&c_conn->property_info,
295 CONNECTOR_PROP_OUT_FB);
296 } else {
297 c_state->property_values[CONNECTOR_PROP_OUT_FB] = ~0;
298 }
299}
300
301static void sde_connector_atomic_destroy_state(struct drm_connector *connector,
302 struct drm_connector_state *state)
303{
304 struct sde_connector *c_conn = NULL;
305 struct sde_connector_state *c_state = NULL;
306
307 if (!state) {
308 SDE_ERROR("invalid state\n");
309 return;
310 }
311
312 /*
313 * The base DRM framework currently always passes in a NULL
314 * connector pointer. This is not correct, but attempt to
315 * handle that case as much as possible.
316 */
317 if (connector)
318 c_conn = to_sde_connector(connector);
319 c_state = to_sde_connector_state(state);
320
321 if (c_state->out_fb)
322 _sde_connector_destroy_fb(c_conn, c_state);
323
324 if (!c_conn) {
325 kfree(c_state);
326 } else {
327 /* destroy value helper */
328 msm_property_destroy_state(&c_conn->property_info, c_state,
329 c_state->property_values, 0);
330 }
331}
332
333static void sde_connector_atomic_reset(struct drm_connector *connector)
334{
335 struct sde_connector *c_conn;
336 struct sde_connector_state *c_state;
337
338 if (!connector) {
339 SDE_ERROR("invalid connector\n");
340 return;
341 }
342
343 c_conn = to_sde_connector(connector);
344
345 if (connector->state) {
346 sde_connector_atomic_destroy_state(connector, connector->state);
347 connector->state = 0;
348 }
349
350 c_state = msm_property_alloc_state(&c_conn->property_info);
351 if (!c_state) {
352 SDE_ERROR("state alloc failed\n");
353 return;
354 }
355
356 /* reset value helper, zero out state structure and reset properties */
357 msm_property_reset_state(&c_conn->property_info, c_state,
358 c_state->property_values, 0);
359
360 c_state->base.connector = connector;
361 connector->state = &c_state->base;
362}
363
364static struct drm_connector_state *
365sde_connector_atomic_duplicate_state(struct drm_connector *connector)
366{
367 struct sde_connector *c_conn;
368 struct sde_connector_state *c_state, *c_oldstate;
369 int rc;
370
371 if (!connector || !connector->state) {
372 SDE_ERROR("invalid connector %pK\n", connector);
373 return NULL;
374 }
375
376 c_conn = to_sde_connector(connector);
377 c_oldstate = to_sde_connector_state(connector->state);
378 c_state = msm_property_alloc_state(&c_conn->property_info);
379 if (!c_state) {
380 SDE_ERROR("state alloc failed\n");
381 return NULL;
382 }
383
384 /* duplicate value helper */
385 msm_property_duplicate_state(&c_conn->property_info,
386 c_oldstate, c_state, c_state->property_values, 0);
387
388 /* additional handling for drm framebuffer objects */
389 if (c_state->out_fb) {
390 drm_framebuffer_reference(c_state->out_fb);
391 rc = msm_framebuffer_prepare(c_state->out_fb,
392 c_state->mmu_id);
393 if (rc)
394 SDE_ERROR("failed to prepare fb, %d\n", rc);
395 }
396
397 return &c_state->base;
398}
399
400static int sde_connector_atomic_set_property(struct drm_connector *connector,
401 struct drm_connector_state *state,
402 struct drm_property *property,
403 uint64_t val)
404{
405 struct sde_connector *c_conn;
406 struct sde_connector_state *c_state;
407 int idx, rc;
408
409 if (!connector || !state || !property) {
410 SDE_ERROR("invalid argument(s), conn %pK, state %pK, prp %pK\n",
411 connector, state, property);
412 return -EINVAL;
413 }
414
415 c_conn = to_sde_connector(connector);
416 c_state = to_sde_connector_state(state);
417
418 /* generic property handling */
419 rc = msm_property_atomic_set(&c_conn->property_info,
420 c_state->property_values, 0, property, val);
421 if (rc)
422 goto end;
423
424 /* connector-specific property handling */
425 idx = msm_property_index(&c_conn->property_info, property);
426
427 if (idx == CONNECTOR_PROP_OUT_FB) {
428 /* clear old fb, if present */
429 if (c_state->out_fb)
430 _sde_connector_destroy_fb(c_conn, c_state);
431
432 /* convert fb val to drm framebuffer and prepare it */
433 c_state->out_fb =
434 drm_framebuffer_lookup(connector->dev, val);
Alan Kwongae1b1142017-03-05 16:07:10 -0800435 if (!c_state->out_fb && val) {
Clarence Ipdd8021c2016-07-20 16:39:47 -0400436 SDE_ERROR("failed to look up fb %lld\n", val);
437 rc = -EFAULT;
Alan Kwongae1b1142017-03-05 16:07:10 -0800438 } else if (!c_state->out_fb && !val) {
439 SDE_DEBUG("cleared fb_id\n");
440 rc = 0;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400441 } else {
Alan Kwong578cdaf2017-01-28 17:25:43 -0800442 msm_framebuffer_set_kmap(c_state->out_fb,
443 c_conn->fb_kmap);
444
Alan Kwongdfa8c082016-07-29 04:10:00 -0400445 if (c_state->out_fb->flags & DRM_MODE_FB_SECURE)
446 c_state->mmu_id =
447 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE];
448 else
449 c_state->mmu_id =
450 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE];
Clarence Ipdd8021c2016-07-20 16:39:47 -0400451
452 rc = msm_framebuffer_prepare(c_state->out_fb,
453 c_state->mmu_id);
454 if (rc)
455 SDE_ERROR("prep fb failed, %d\n", rc);
456 }
457 }
458
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400459 if (idx == CONNECTOR_PROP_TOPOLOGY_CONTROL) {
460 rc = sde_rm_check_property_topctl(val);
461 if (rc)
462 SDE_ERROR("invalid topology_control: 0x%llX\n", val);
463 }
464
Clarence Ipdd8021c2016-07-20 16:39:47 -0400465 /* check for custom property handling */
466 if (!rc && c_conn->ops.set_property) {
467 rc = c_conn->ops.set_property(connector,
468 state,
469 idx,
470 val,
471 c_conn->display);
472
473 /* potentially clean up out_fb if rc != 0 */
474 if ((idx == CONNECTOR_PROP_OUT_FB) && rc)
475 _sde_connector_destroy_fb(c_conn, c_state);
476 }
477end:
478 return rc;
479}
480
481static int sde_connector_set_property(struct drm_connector *connector,
482 struct drm_property *property,
483 uint64_t val)
484{
485 if (!connector) {
486 SDE_ERROR("invalid connector\n");
487 return -EINVAL;
488 }
489
490 return sde_connector_atomic_set_property(connector,
491 connector->state, property, val);
492}
493
494static int sde_connector_atomic_get_property(struct drm_connector *connector,
495 const struct drm_connector_state *state,
496 struct drm_property *property,
497 uint64_t *val)
498{
499 struct sde_connector *c_conn;
500 struct sde_connector_state *c_state;
501 int idx, rc = -EINVAL;
502
503 if (!connector || !state) {
504 SDE_ERROR("invalid argument(s), conn %pK, state %pK\n",
505 connector, state);
506 return -EINVAL;
507 }
508
509 c_conn = to_sde_connector(connector);
510 c_state = to_sde_connector_state(state);
511
512 idx = msm_property_index(&c_conn->property_info, property);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400513 if (idx == CONNECTOR_PROP_RETIRE_FENCE)
Dhaval Patel5cb59be2017-04-20 20:00:56 -0700514 rc = sde_fence_create(&c_conn->retire_fence, val, 0);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400515 else
516 /* get cached property value */
517 rc = msm_property_atomic_get(&c_conn->property_info,
518 c_state->property_values, 0, property, val);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400519
520 /* allow for custom override */
521 if (c_conn->ops.get_property)
522 rc = c_conn->ops.get_property(connector,
523 (struct drm_connector_state *)state,
524 idx,
525 val,
526 c_conn->display);
527 return rc;
528}
529
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400530void sde_connector_prepare_fence(struct drm_connector *connector)
531{
532 if (!connector) {
533 SDE_ERROR("invalid connector\n");
534 return;
535 }
536
537 sde_fence_prepare(&to_sde_connector(connector)->retire_fence);
538}
539
540void sde_connector_complete_commit(struct drm_connector *connector)
541{
542 if (!connector) {
543 SDE_ERROR("invalid connector\n");
544 return;
545 }
546
547 /* signal connector's retire fence */
548 sde_fence_signal(&to_sde_connector(connector)->retire_fence, 0);
549}
550
Clarence Ipdd8021c2016-07-20 16:39:47 -0400551static enum drm_connector_status
552sde_connector_detect(struct drm_connector *connector, bool force)
553{
554 enum drm_connector_status status = connector_status_unknown;
555 struct sde_connector *c_conn;
556
557 if (!connector) {
558 SDE_ERROR("invalid connector\n");
559 return status;
560 }
561
562 c_conn = to_sde_connector(connector);
563
564 if (c_conn->ops.detect)
565 status = c_conn->ops.detect(connector,
566 force,
567 c_conn->display);
568
569 return status;
570}
571
Alan Kwong578cdaf2017-01-28 17:25:43 -0800572#ifdef CONFIG_DEBUG_FS
573/**
574 * sde_connector_init_debugfs - initialize connector debugfs
575 * @connector: Pointer to drm connector
576 */
577static int sde_connector_init_debugfs(struct drm_connector *connector)
578{
579 struct sde_connector *sde_connector;
580
581 if (!connector || !connector->debugfs_entry) {
582 SDE_ERROR("invalid connector\n");
583 return -EINVAL;
584 }
585
586 sde_connector = to_sde_connector(connector);
587
588 if (!debugfs_create_bool("fb_kmap", 0644, connector->debugfs_entry,
589 &sde_connector->fb_kmap)) {
590 SDE_ERROR("failed to create connector fb_kmap\n");
591 return -ENOMEM;
592 }
593
594 return 0;
595}
596#else
597static int sde_connector_init_debugfs(struct drm_connector *connector)
598{
599 return 0;
600}
601#endif
602
603static int sde_connector_late_register(struct drm_connector *connector)
604{
605 return sde_connector_init_debugfs(connector);
606}
607
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -0700608static void sde_connector_early_unregister(struct drm_connector *connector)
609{
610 /* debugfs under connector->debugfs are deleted by drm_debugfs */
611}
612
Clarence Ipdd8021c2016-07-20 16:39:47 -0400613static const struct drm_connector_funcs sde_connector_ops = {
614 .dpms = drm_atomic_helper_connector_dpms,
615 .reset = sde_connector_atomic_reset,
616 .detect = sde_connector_detect,
617 .destroy = sde_connector_destroy,
618 .fill_modes = drm_helper_probe_single_connector_modes,
619 .atomic_duplicate_state = sde_connector_atomic_duplicate_state,
620 .atomic_destroy_state = sde_connector_atomic_destroy_state,
621 .atomic_set_property = sde_connector_atomic_set_property,
622 .atomic_get_property = sde_connector_atomic_get_property,
623 .set_property = sde_connector_set_property,
Alan Kwong578cdaf2017-01-28 17:25:43 -0800624 .late_register = sde_connector_late_register,
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -0700625 .early_unregister = sde_connector_early_unregister,
Clarence Ipdd8021c2016-07-20 16:39:47 -0400626};
627
628static int sde_connector_get_modes(struct drm_connector *connector)
629{
630 struct sde_connector *c_conn;
631
632 if (!connector) {
633 SDE_ERROR("invalid connector\n");
634 return 0;
635 }
636
637 c_conn = to_sde_connector(connector);
638 if (!c_conn->ops.get_modes) {
639 SDE_DEBUG("missing get_modes callback\n");
640 return 0;
641 }
642
643 return c_conn->ops.get_modes(connector, c_conn->display);
644}
645
646static enum drm_mode_status
647sde_connector_mode_valid(struct drm_connector *connector,
648 struct drm_display_mode *mode)
649{
650 struct sde_connector *c_conn;
651
652 if (!connector || !mode) {
653 SDE_ERROR("invalid argument(s), conn %pK, mode %pK\n",
654 connector, mode);
655 return MODE_ERROR;
656 }
657
658 c_conn = to_sde_connector(connector);
659
660 if (c_conn->ops.mode_valid)
661 return c_conn->ops.mode_valid(connector, mode, c_conn->display);
662
663 /* assume all modes okay by default */
664 return MODE_OK;
665}
666
667static struct drm_encoder *
668sde_connector_best_encoder(struct drm_connector *connector)
669{
670 struct sde_connector *c_conn = to_sde_connector(connector);
671
672 if (!connector) {
673 SDE_ERROR("invalid connector\n");
674 return NULL;
675 }
676
677 /*
678 * This is true for now, revisit this code when multiple encoders are
679 * supported.
680 */
681 return c_conn->encoder;
682}
683
684static const struct drm_connector_helper_funcs sde_connector_helper_ops = {
685 .get_modes = sde_connector_get_modes,
686 .mode_valid = sde_connector_mode_valid,
687 .best_encoder = sde_connector_best_encoder,
688};
689
690struct drm_connector *sde_connector_init(struct drm_device *dev,
691 struct drm_encoder *encoder,
692 struct drm_panel *panel,
693 void *display,
694 const struct sde_connector_ops *ops,
695 int connector_poll,
696 int connector_type)
697{
698 struct msm_drm_private *priv;
699 struct sde_kms *sde_kms;
700 struct sde_kms_info *info;
701 struct sde_connector *c_conn = NULL;
Ping Li898b1bf2017-02-09 18:03:28 -0800702 struct dsi_display *dsi_display;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400703 int rc;
704
705 if (!dev || !dev->dev_private || !encoder) {
706 SDE_ERROR("invalid argument(s), dev %pK, enc %pK\n",
707 dev, encoder);
708 return ERR_PTR(-EINVAL);
709 }
710
711 priv = dev->dev_private;
712 if (!priv->kms) {
713 SDE_ERROR("invalid kms reference\n");
714 return ERR_PTR(-EINVAL);
715 }
716
717 c_conn = kzalloc(sizeof(*c_conn), GFP_KERNEL);
718 if (!c_conn) {
719 SDE_ERROR("failed to alloc sde connector\n");
720 return ERR_PTR(-ENOMEM);
721 }
722
723 rc = drm_connector_init(dev,
724 &c_conn->base,
725 &sde_connector_ops,
726 connector_type);
727 if (rc)
728 goto error_free_conn;
729
Clarence Ipa18d4832017-03-13 12:35:44 -0700730 spin_lock_init(&c_conn->event_lock);
731
Clarence Ipdd8021c2016-07-20 16:39:47 -0400732 c_conn->connector_type = connector_type;
733 c_conn->encoder = encoder;
734 c_conn->panel = panel;
735 c_conn->display = display;
736
Alan Kwongdfa8c082016-07-29 04:10:00 -0400737 /* cache mmu_id's for later */
Clarence Ipdd8021c2016-07-20 16:39:47 -0400738 sde_kms = to_sde_kms(priv->kms);
Alan Kwongdfa8c082016-07-29 04:10:00 -0400739 if (sde_kms->vbif[VBIF_NRT]) {
740 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] =
741 sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_UNSECURE];
742 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE] =
743 sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_SECURE];
744 } else {
745 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] =
746 sde_kms->mmu_id[MSM_SMMU_DOMAIN_UNSECURE];
747 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE] =
748 sde_kms->mmu_id[MSM_SMMU_DOMAIN_SECURE];
749 }
Clarence Ipdd8021c2016-07-20 16:39:47 -0400750
751 if (ops)
752 c_conn->ops = *ops;
753
754 c_conn->base.helper_private = &sde_connector_helper_ops;
755 c_conn->base.polled = connector_poll;
756 c_conn->base.interlace_allowed = 0;
757 c_conn->base.doublescan_allowed = 0;
758
759 snprintf(c_conn->name,
760 SDE_CONNECTOR_NAME_SIZE,
761 "conn%u",
762 c_conn->base.base.id);
763
Lloyd Atkinson5d40d312016-09-06 08:34:13 -0400764 rc = sde_fence_init(&c_conn->retire_fence, c_conn->name,
765 c_conn->base.base.id);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400766 if (rc) {
767 SDE_ERROR("failed to init fence, %d\n", rc);
768 goto error_cleanup_conn;
769 }
770
Clarence Ipdd8021c2016-07-20 16:39:47 -0400771 rc = drm_mode_connector_attach_encoder(&c_conn->base, encoder);
772 if (rc) {
773 SDE_ERROR("failed to attach encoder to connector, %d\n", rc);
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -0800774 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400775 }
776
Shashank Babu Chinta Venkata06c428e2017-04-17 13:52:28 -0700777 rc = sde_backlight_setup(c_conn, dev);
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800778 if (rc) {
779 SDE_ERROR("failed to setup backlight, rc=%d\n", rc);
780 goto error_cleanup_fence;
Vishnuvardhan Prodduturi75b96802016-10-17 18:45:55 +0530781 }
782
Clarence Ipdd8021c2016-07-20 16:39:47 -0400783 /* create properties */
784 msm_property_init(&c_conn->property_info, &c_conn->base.base, dev,
785 priv->conn_property, c_conn->property_data,
786 CONNECTOR_PROP_COUNT, CONNECTOR_PROP_BLOBCOUNT,
787 sizeof(struct sde_connector_state));
788
789 if (c_conn->ops.post_init) {
790 info = kmalloc(sizeof(*info), GFP_KERNEL);
791 if (!info) {
792 SDE_ERROR("failed to allocate info buffer\n");
793 rc = -ENOMEM;
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -0800794 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400795 }
796
797 sde_kms_info_reset(info);
798 rc = c_conn->ops.post_init(&c_conn->base, info, display);
799 if (rc) {
800 SDE_ERROR("post-init failed, %d\n", rc);
801 kfree(info);
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -0800802 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400803 }
804
805 msm_property_install_blob(&c_conn->property_info,
Dhaval Patel4e574842016-08-23 15:11:37 -0700806 "capabilities",
Clarence Ipdd8021c2016-07-20 16:39:47 -0400807 DRM_MODE_PROP_IMMUTABLE,
808 CONNECTOR_PROP_SDE_INFO);
809
810 msm_property_set_blob(&c_conn->property_info,
Dhaval Patel4e574842016-08-23 15:11:37 -0700811 &c_conn->blob_caps,
Clarence Ipdd8021c2016-07-20 16:39:47 -0400812 SDE_KMS_INFO_DATA(info),
813 SDE_KMS_INFO_DATALEN(info),
814 CONNECTOR_PROP_SDE_INFO);
815 kfree(info);
816 }
817
Ping Li898b1bf2017-02-09 18:03:28 -0800818 if (connector_type == DRM_MODE_CONNECTOR_DSI) {
819 dsi_display = (struct dsi_display *)(display);
820 if (dsi_display && dsi_display->panel &&
821 dsi_display->panel->hdr_props.hdr_enabled == true) {
822 msm_property_install_blob(&c_conn->property_info,
823 "hdr_properties",
824 DRM_MODE_PROP_IMMUTABLE,
825 CONNECTOR_PROP_HDR_INFO);
826
827 msm_property_set_blob(&c_conn->property_info,
828 &c_conn->blob_hdr,
829 &dsi_display->panel->hdr_props,
830 sizeof(dsi_display->panel->hdr_props),
831 CONNECTOR_PROP_HDR_INFO);
832 }
833 }
834
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400835 msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE",
Dhaval Patel4e574842016-08-23 15:11:37 -0700836 0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400837
Lloyd Atkinsonb6191972016-08-10 18:31:46 -0400838 /* enum/bitmask properties */
839 msm_property_install_enum(&c_conn->property_info, "topology_name",
840 DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name,
841 ARRAY_SIZE(e_topology_name),
842 CONNECTOR_PROP_TOPOLOGY_NAME);
843 msm_property_install_enum(&c_conn->property_info, "topology_control",
844 0, 1, e_topology_control,
845 ARRAY_SIZE(e_topology_control),
846 CONNECTOR_PROP_TOPOLOGY_CONTROL);
847
Clarence Ipdd8021c2016-07-20 16:39:47 -0400848 rc = msm_property_install_get_status(&c_conn->property_info);
849 if (rc) {
850 SDE_ERROR("failed to create one or more properties\n");
851 goto error_destroy_property;
852 }
853
Lloyd Atkinsonb6191972016-08-10 18:31:46 -0400854 SDE_DEBUG("connector %d attach encoder %d\n",
855 c_conn->base.base.id, encoder->base.id);
856
Clarence Ipdd8021c2016-07-20 16:39:47 -0400857 priv->connectors[priv->num_connectors++] = &c_conn->base;
858
859 return &c_conn->base;
860
861error_destroy_property:
Dhaval Patel4e574842016-08-23 15:11:37 -0700862 if (c_conn->blob_caps)
863 drm_property_unreference_blob(c_conn->blob_caps);
Ping Li898b1bf2017-02-09 18:03:28 -0800864 if (c_conn->blob_hdr)
865 drm_property_unreference_blob(c_conn->blob_hdr);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400866 msm_property_destroy(&c_conn->property_info);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400867error_cleanup_fence:
868 sde_fence_deinit(&c_conn->retire_fence);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400869error_cleanup_conn:
870 drm_connector_cleanup(&c_conn->base);
871error_free_conn:
872 kfree(c_conn);
873
874 return ERR_PTR(rc);
875}
Gopikrishnaiah Anandande2c81b2017-03-15 12:41:29 -0700876
877int sde_connector_register_custom_event(struct sde_kms *kms,
878 struct drm_connector *conn_drm, u32 event, bool val)
879{
880 return -EINVAL;
881}