blob: 6a67ce99ac435dc4ae6fadff6383d772afc7bd23 [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 Atkinson8ba47032017-03-22 17:13:32 -040024#define SDE_DEBUG_CONN(c, fmt, ...) SDE_DEBUG("conn%d " fmt,\
25 (c) ? (c)->base.base.id : -1, ##__VA_ARGS__)
26
27#define SDE_ERROR_CONN(c, fmt, ...) SDE_ERROR("conn%d " fmt,\
28 (c) ? (c)->base.base.id : -1, ##__VA_ARGS__)
29
Lloyd Atkinsonb6191972016-08-10 18:31:46 -040030static const struct drm_prop_enum_list e_topology_name[] = {
31 {SDE_RM_TOPOLOGY_UNKNOWN, "sde_unknown"},
32 {SDE_RM_TOPOLOGY_SINGLEPIPE, "sde_singlepipe"},
33 {SDE_RM_TOPOLOGY_DUALPIPE, "sde_dualpipe"},
34 {SDE_RM_TOPOLOGY_PPSPLIT, "sde_ppsplit"},
35 {SDE_RM_TOPOLOGY_DUALPIPEMERGE, "sde_dualpipemerge"}
36};
37static const struct drm_prop_enum_list e_topology_control[] = {
38 {SDE_RM_TOPCTL_RESERVE_LOCK, "reserve_lock"},
39 {SDE_RM_TOPCTL_RESERVE_CLEAR, "reserve_clear"},
40 {SDE_RM_TOPCTL_DSPP, "dspp"},
41 {SDE_RM_TOPCTL_FORCE_TILING, "force_tiling"},
42 {SDE_RM_TOPCTL_PPSPLIT, "ppsplit"}
43};
44
Dhaval Patel7cdd6662017-03-08 13:10:37 -080045static int sde_backlight_device_update_status(struct backlight_device *bd)
46{
47 int brightness;
48 struct dsi_display *display;
49 struct sde_connector *c_conn;
50 int bl_lvl;
51
52 brightness = bd->props.brightness;
53
54 if ((bd->props.power != FB_BLANK_UNBLANK) ||
55 (bd->props.state & BL_CORE_FBBLANK) ||
56 (bd->props.state & BL_CORE_SUSPENDED))
57 brightness = 0;
58
59 c_conn = bl_get_data(bd);
60 display = (struct dsi_display *) c_conn->display;
61 if (brightness > display->panel->bl_config.bl_max_level)
62 brightness = display->panel->bl_config.bl_max_level;
63
64 /* map UI brightness into driver backlight level with rounding */
65 bl_lvl = mult_frac(brightness, display->panel->bl_config.bl_max_level,
66 display->panel->bl_config.brightness_max_level);
67
68 if (!bl_lvl && brightness)
69 bl_lvl = 1;
70
71 if (c_conn->ops.set_backlight)
72 c_conn->ops.set_backlight(c_conn->display, bl_lvl);
73
74 return 0;
75}
76
77static int sde_backlight_device_get_brightness(struct backlight_device *bd)
78{
79 return 0;
80}
81
82static const struct backlight_ops sde_backlight_device_ops = {
83 .update_status = sde_backlight_device_update_status,
84 .get_brightness = sde_backlight_device_get_brightness,
85};
86
87static int sde_backlight_setup(struct sde_connector *c_conn)
88{
89 struct backlight_device *bl_device;
90 struct backlight_properties props;
91 struct dsi_display *display;
92 struct dsi_backlight_config *bl_config;
93 static int display_count;
94 char bl_node_name[BL_NODE_NAME_SIZE];
95
96 if (!c_conn) {
97 SDE_ERROR("invalid param\n");
98 return -EINVAL;
99 } else if (c_conn->connector_type != DRM_MODE_CONNECTOR_DSI) {
100 return 0;
101 }
102
103 memset(&props, 0, sizeof(props));
104 props.type = BACKLIGHT_RAW;
105 props.power = FB_BLANK_UNBLANK;
106
107 display = (struct dsi_display *) c_conn->display;
108 bl_config = &display->panel->bl_config;
109 props.max_brightness = bl_config->brightness_max_level;
110 props.brightness = bl_config->brightness_max_level;
111 snprintf(bl_node_name, BL_NODE_NAME_SIZE, "panel%u-backlight",
112 display_count);
113 bl_device = backlight_device_register(bl_node_name, c_conn->base.kdev,
114 c_conn, &sde_backlight_device_ops, &props);
115 if (IS_ERR_OR_NULL(bl_device)) {
116 SDE_ERROR("Failed to register backlight: %ld\n",
117 PTR_ERR(bl_device));
118 return -ENODEV;
119 }
120 display_count++;
121
122 return 0;
123}
124
Clarence Ipa18d4832017-03-13 12:35:44 -0700125int sde_connector_trigger_event(void *drm_connector,
126 uint32_t event_idx, uint32_t instance_idx,
127 uint32_t data0, uint32_t data1,
128 uint32_t data2, uint32_t data3)
129{
130 struct sde_connector *c_conn;
131 unsigned long irq_flags;
132 void (*cb_func)(uint32_t event_idx,
133 uint32_t instance_idx, void *usr,
134 uint32_t data0, uint32_t data1,
135 uint32_t data2, uint32_t data3);
136 void *usr;
137 int rc = 0;
138
139 /*
140 * This function may potentially be called from an ISR context, so
141 * avoid excessive logging/etc.
142 */
143 if (!drm_connector)
144 return -EINVAL;
145 else if (event_idx >= SDE_CONN_EVENT_COUNT)
146 return -EINVAL;
147 c_conn = to_sde_connector(drm_connector);
148
149 spin_lock_irqsave(&c_conn->event_lock, irq_flags);
150 cb_func = c_conn->event_table[event_idx].cb_func;
151 usr = c_conn->event_table[event_idx].usr;
152 spin_unlock_irqrestore(&c_conn->event_lock, irq_flags);
153
154 if (cb_func)
155 cb_func(event_idx, instance_idx, usr,
156 data0, data1, data2, data3);
157 else
158 rc = -EAGAIN;
159
160 return rc;
161}
162
163int sde_connector_register_event(struct drm_connector *connector,
164 uint32_t event_idx,
165 void (*cb_func)(uint32_t event_idx,
166 uint32_t instance_idx, void *usr,
167 uint32_t data0, uint32_t data1,
168 uint32_t data2, uint32_t data3),
169 void *usr)
170{
171 struct sde_connector *c_conn;
172 unsigned long irq_flags;
173
174 if (!connector) {
175 SDE_ERROR("invalid connector\n");
176 return -EINVAL;
177 } else if (event_idx >= SDE_CONN_EVENT_COUNT) {
178 SDE_ERROR("conn%d, invalid event %d\n",
179 connector->base.id, event_idx);
180 return -EINVAL;
181 }
182 c_conn = to_sde_connector(connector);
183
184 spin_lock_irqsave(&c_conn->event_lock, irq_flags);
185 c_conn->event_table[event_idx].cb_func = cb_func;
186 c_conn->event_table[event_idx].usr = usr;
187 spin_unlock_irqrestore(&c_conn->event_lock, irq_flags);
188
189 /* optionally notify display of event registration */
190 if (c_conn->ops.enable_event && c_conn->display)
191 c_conn->ops.enable_event(connector, event_idx,
192 cb_func != NULL, c_conn->display);
193 return 0;
194}
195
196void sde_connector_unregister_event(struct drm_connector *connector,
197 uint32_t event_idx)
198{
199 (void)sde_connector_register_event(connector, event_idx, 0, 0);
200}
201
Clarence Ipcb3afd42016-07-15 16:25:34 -0400202int sde_connector_get_info(struct drm_connector *connector,
203 struct msm_display_info *info)
204{
205 struct sde_connector *c_conn;
206
207 if (!connector || !info) {
208 SDE_ERROR("invalid argument(s), conn %pK, info %pK\n",
209 connector, info);
210 return -EINVAL;
211 }
212
213 c_conn = to_sde_connector(connector);
214
215 if (!c_conn->display || !c_conn->ops.get_info) {
216 SDE_ERROR("display info not supported for %pK\n",
217 c_conn->display);
218 return -EINVAL;
219 }
220
221 return c_conn->ops.get_info(info, c_conn->display);
222}
223
Lloyd Atkinson05d75512017-01-17 14:45:51 -0500224int sde_connector_pre_kickoff(struct drm_connector *connector)
225{
226 struct sde_connector *c_conn;
227 struct sde_connector_state *c_state;
228 struct msm_display_kickoff_params params;
229 int rc;
230
231 if (!connector) {
232 SDE_ERROR("invalid argument\n");
233 return -EINVAL;
234 }
235
236 c_conn = to_sde_connector(connector);
237 c_state = to_sde_connector_state(connector->state);
238
239 if (!c_conn->display) {
240 SDE_ERROR("invalid argument\n");
241 return -EINVAL;
242 }
243
244 if (!c_conn->ops.pre_kickoff)
245 return 0;
246
247 params.rois = &c_state->rois;
248
249 SDE_EVT32_VERBOSE(connector->base.id);
250
251 rc = c_conn->ops.pre_kickoff(connector, c_conn->display, &params);
252
253 return rc;
254}
255
Clarence Ipdd8021c2016-07-20 16:39:47 -0400256static void sde_connector_destroy(struct drm_connector *connector)
257{
258 struct sde_connector *c_conn;
259
260 if (!connector) {
261 SDE_ERROR("invalid connector\n");
262 return;
263 }
264
265 c_conn = to_sde_connector(connector);
266
Dhaval Patel4e574842016-08-23 15:11:37 -0700267 if (c_conn->blob_caps)
268 drm_property_unreference_blob(c_conn->blob_caps);
Ping Li898b1bf2017-02-09 18:03:28 -0800269 if (c_conn->blob_hdr)
270 drm_property_unreference_blob(c_conn->blob_hdr);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400271 msm_property_destroy(&c_conn->property_info);
272
273 drm_connector_unregister(connector);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400274 sde_fence_deinit(&c_conn->retire_fence);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400275 drm_connector_cleanup(connector);
276 kfree(c_conn);
277}
278
279/**
280 * _sde_connector_destroy_fb - clean up connector state's out_fb buffer
281 * @c_conn: Pointer to sde connector structure
282 * @c_state: Pointer to sde connector state structure
283 */
284static void _sde_connector_destroy_fb(struct sde_connector *c_conn,
285 struct sde_connector_state *c_state)
286{
287 if (!c_state || !c_state->out_fb) {
288 SDE_ERROR("invalid state %pK\n", c_state);
289 return;
290 }
291
292 msm_framebuffer_cleanup(c_state->out_fb,
293 c_state->mmu_id);
294 drm_framebuffer_unreference(c_state->out_fb);
295 c_state->out_fb = NULL;
296
297 if (c_conn) {
298 c_state->property_values[CONNECTOR_PROP_OUT_FB] =
299 msm_property_get_default(&c_conn->property_info,
300 CONNECTOR_PROP_OUT_FB);
301 } else {
302 c_state->property_values[CONNECTOR_PROP_OUT_FB] = ~0;
303 }
304}
305
306static void sde_connector_atomic_destroy_state(struct drm_connector *connector,
307 struct drm_connector_state *state)
308{
309 struct sde_connector *c_conn = NULL;
310 struct sde_connector_state *c_state = NULL;
311
312 if (!state) {
313 SDE_ERROR("invalid state\n");
314 return;
315 }
316
317 /*
318 * The base DRM framework currently always passes in a NULL
319 * connector pointer. This is not correct, but attempt to
320 * handle that case as much as possible.
321 */
322 if (connector)
323 c_conn = to_sde_connector(connector);
324 c_state = to_sde_connector_state(state);
325
326 if (c_state->out_fb)
327 _sde_connector_destroy_fb(c_conn, c_state);
328
329 if (!c_conn) {
330 kfree(c_state);
331 } else {
332 /* destroy value helper */
333 msm_property_destroy_state(&c_conn->property_info, c_state,
334 c_state->property_values, 0);
335 }
336}
337
338static void sde_connector_atomic_reset(struct drm_connector *connector)
339{
340 struct sde_connector *c_conn;
341 struct sde_connector_state *c_state;
342
343 if (!connector) {
344 SDE_ERROR("invalid connector\n");
345 return;
346 }
347
348 c_conn = to_sde_connector(connector);
349
350 if (connector->state) {
351 sde_connector_atomic_destroy_state(connector, connector->state);
352 connector->state = 0;
353 }
354
355 c_state = msm_property_alloc_state(&c_conn->property_info);
356 if (!c_state) {
357 SDE_ERROR("state alloc failed\n");
358 return;
359 }
360
361 /* reset value helper, zero out state structure and reset properties */
362 msm_property_reset_state(&c_conn->property_info, c_state,
363 c_state->property_values, 0);
364
365 c_state->base.connector = connector;
366 connector->state = &c_state->base;
367}
368
369static struct drm_connector_state *
370sde_connector_atomic_duplicate_state(struct drm_connector *connector)
371{
372 struct sde_connector *c_conn;
373 struct sde_connector_state *c_state, *c_oldstate;
374 int rc;
375
376 if (!connector || !connector->state) {
377 SDE_ERROR("invalid connector %pK\n", connector);
378 return NULL;
379 }
380
381 c_conn = to_sde_connector(connector);
382 c_oldstate = to_sde_connector_state(connector->state);
383 c_state = msm_property_alloc_state(&c_conn->property_info);
384 if (!c_state) {
385 SDE_ERROR("state alloc failed\n");
386 return NULL;
387 }
388
389 /* duplicate value helper */
390 msm_property_duplicate_state(&c_conn->property_info,
391 c_oldstate, c_state, c_state->property_values, 0);
392
393 /* additional handling for drm framebuffer objects */
394 if (c_state->out_fb) {
395 drm_framebuffer_reference(c_state->out_fb);
396 rc = msm_framebuffer_prepare(c_state->out_fb,
397 c_state->mmu_id);
398 if (rc)
399 SDE_ERROR("failed to prepare fb, %d\n", rc);
400 }
401
402 return &c_state->base;
403}
404
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400405static int _sde_connector_roi_v1_check_roi(
406 struct sde_connector *c_conn,
407 struct drm_clip_rect *roi_conn,
408 const struct msm_roi_caps *caps)
409{
410 const struct msm_roi_alignment *align = &caps->align;
411 int w = roi_conn->x2 - roi_conn->x1;
412 int h = roi_conn->y2 - roi_conn->y1;
413
414 if (w <= 0 || h <= 0) {
415 SDE_ERROR_CONN(c_conn, "invalid conn roi w %d h %d\n", w, h);
416 return -EINVAL;
417 }
418
419 if (w < align->min_width || w % align->width_pix_align) {
420 SDE_ERROR_CONN(c_conn,
421 "invalid conn roi width %d min %d align %d\n",
422 w, align->min_width, align->width_pix_align);
423 return -EINVAL;
424 }
425
426 if (h < align->min_height || h % align->height_pix_align) {
427 SDE_ERROR_CONN(c_conn,
428 "invalid conn roi height %d min %d align %d\n",
429 h, align->min_height, align->height_pix_align);
430 return -EINVAL;
431 }
432
433 if (roi_conn->x1 % align->xstart_pix_align) {
434 SDE_ERROR_CONN(c_conn, "invalid conn roi x1 %d align %d\n",
435 roi_conn->x1, align->xstart_pix_align);
436 return -EINVAL;
437 }
438
439 if (roi_conn->y1 % align->ystart_pix_align) {
440 SDE_ERROR_CONN(c_conn, "invalid conn roi y1 %d align %d\n",
441 roi_conn->y1, align->ystart_pix_align);
442 return -EINVAL;
443 }
444
445 return 0;
446}
447
448static int _sde_connector_set_roi_v1(
449 struct sde_connector *c_conn,
450 struct sde_connector_state *c_state,
451 void *usr_ptr)
452{
453 struct sde_drm_roi_v1 roi_v1;
454 struct msm_display_info display_info;
455 struct msm_roi_caps *caps;
456 int i, rc;
457
458 if (!c_conn || !c_state) {
459 SDE_ERROR("invalid args\n");
460 return -EINVAL;
461 }
462
463 rc = sde_connector_get_info(&c_conn->base, &display_info);
464 if (rc) {
465 SDE_ERROR_CONN(c_conn, "display get info error: %d\n", rc);
466 return rc;
467 }
468
469 caps = &display_info.roi_caps;
470 if (!caps->enabled) {
471 SDE_ERROR_CONN(c_conn, "display roi capability is disabled\n");
472 return -ENOTSUPP;
473 }
474
475 memset(&c_state->rois, 0, sizeof(c_state->rois));
476
477 if (!usr_ptr) {
478 SDE_DEBUG_CONN(c_conn, "rois cleared\n");
479 return 0;
480 }
481
482 if (copy_from_user(&roi_v1, usr_ptr, sizeof(roi_v1))) {
483 SDE_ERROR_CONN(c_conn, "failed to copy roi_v1 data\n");
484 return -EINVAL;
485 }
486
487 SDE_DEBUG_CONN(c_conn, "num_rects %d\n", roi_v1.num_rects);
488
489 if (roi_v1.num_rects == 0) {
490 SDE_DEBUG_CONN(c_conn, "rois cleared\n");
491 return 0;
492 }
493
494 if (roi_v1.num_rects > SDE_MAX_ROI_V1 ||
495 roi_v1.num_rects > caps->num_roi) {
496 SDE_ERROR_CONN(c_conn, "too many rects specified: %d\n",
497 roi_v1.num_rects);
498 return -EINVAL;
499 }
500
501 c_state->rois.num_rects = roi_v1.num_rects;
502 for (i = 0; i < roi_v1.num_rects; ++i) {
503 int rc;
504
505 rc = _sde_connector_roi_v1_check_roi(c_conn, &roi_v1.roi[i],
506 caps);
507 if (rc)
508 return rc;
509
510 c_state->rois.roi[i] = roi_v1.roi[i];
511 SDE_DEBUG_CONN(c_conn, "roi%d: roi 0x%x 0x%x 0x%x 0x%x\n", i,
512 c_state->rois.roi[i].x1,
513 c_state->rois.roi[i].y1,
514 c_state->rois.roi[i].x2,
515 c_state->rois.roi[i].y2);
516 }
517
518 return 0;
519}
520
Clarence Ipdd8021c2016-07-20 16:39:47 -0400521static int sde_connector_atomic_set_property(struct drm_connector *connector,
522 struct drm_connector_state *state,
523 struct drm_property *property,
524 uint64_t val)
525{
526 struct sde_connector *c_conn;
527 struct sde_connector_state *c_state;
528 int idx, rc;
529
530 if (!connector || !state || !property) {
531 SDE_ERROR("invalid argument(s), conn %pK, state %pK, prp %pK\n",
532 connector, state, property);
533 return -EINVAL;
534 }
535
536 c_conn = to_sde_connector(connector);
537 c_state = to_sde_connector_state(state);
538
539 /* generic property handling */
540 rc = msm_property_atomic_set(&c_conn->property_info,
541 c_state->property_values, 0, property, val);
542 if (rc)
543 goto end;
544
545 /* connector-specific property handling */
546 idx = msm_property_index(&c_conn->property_info, property);
547
548 if (idx == CONNECTOR_PROP_OUT_FB) {
549 /* clear old fb, if present */
550 if (c_state->out_fb)
551 _sde_connector_destroy_fb(c_conn, c_state);
552
553 /* convert fb val to drm framebuffer and prepare it */
554 c_state->out_fb =
555 drm_framebuffer_lookup(connector->dev, val);
Alan Kwongae1b1142017-03-05 16:07:10 -0800556 if (!c_state->out_fb && val) {
Clarence Ipdd8021c2016-07-20 16:39:47 -0400557 SDE_ERROR("failed to look up fb %lld\n", val);
558 rc = -EFAULT;
Alan Kwongae1b1142017-03-05 16:07:10 -0800559 } else if (!c_state->out_fb && !val) {
560 SDE_DEBUG("cleared fb_id\n");
561 rc = 0;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400562 } else {
Alan Kwong578cdaf2017-01-28 17:25:43 -0800563 msm_framebuffer_set_kmap(c_state->out_fb,
564 c_conn->fb_kmap);
565
Alan Kwongdfa8c082016-07-29 04:10:00 -0400566 if (c_state->out_fb->flags & DRM_MODE_FB_SECURE)
567 c_state->mmu_id =
568 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE];
569 else
570 c_state->mmu_id =
571 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE];
Clarence Ipdd8021c2016-07-20 16:39:47 -0400572
573 rc = msm_framebuffer_prepare(c_state->out_fb,
574 c_state->mmu_id);
575 if (rc)
576 SDE_ERROR("prep fb failed, %d\n", rc);
577 }
578 }
579
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400580 if (idx == CONNECTOR_PROP_TOPOLOGY_CONTROL) {
581 rc = sde_rm_check_property_topctl(val);
582 if (rc)
583 SDE_ERROR("invalid topology_control: 0x%llX\n", val);
584 }
585
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400586 if (idx == CONNECTOR_PROP_ROI_V1) {
587 rc = _sde_connector_set_roi_v1(c_conn, c_state, (void *)val);
588 if (rc)
589 SDE_ERROR_CONN(c_conn, "invalid roi_v1, rc: %d\n", rc);
590 }
591
Clarence Ipdd8021c2016-07-20 16:39:47 -0400592 /* check for custom property handling */
593 if (!rc && c_conn->ops.set_property) {
594 rc = c_conn->ops.set_property(connector,
595 state,
596 idx,
597 val,
598 c_conn->display);
599
600 /* potentially clean up out_fb if rc != 0 */
601 if ((idx == CONNECTOR_PROP_OUT_FB) && rc)
602 _sde_connector_destroy_fb(c_conn, c_state);
603 }
604end:
605 return rc;
606}
607
608static int sde_connector_set_property(struct drm_connector *connector,
609 struct drm_property *property,
610 uint64_t val)
611{
612 if (!connector) {
613 SDE_ERROR("invalid connector\n");
614 return -EINVAL;
615 }
616
617 return sde_connector_atomic_set_property(connector,
618 connector->state, property, val);
619}
620
621static int sde_connector_atomic_get_property(struct drm_connector *connector,
622 const struct drm_connector_state *state,
623 struct drm_property *property,
624 uint64_t *val)
625{
626 struct sde_connector *c_conn;
627 struct sde_connector_state *c_state;
628 int idx, rc = -EINVAL;
629
630 if (!connector || !state) {
631 SDE_ERROR("invalid argument(s), conn %pK, state %pK\n",
632 connector, state);
633 return -EINVAL;
634 }
635
636 c_conn = to_sde_connector(connector);
637 c_state = to_sde_connector_state(state);
638
639 idx = msm_property_index(&c_conn->property_info, property);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400640 if (idx == CONNECTOR_PROP_RETIRE_FENCE)
Clarence Ip9a74a442016-08-25 18:29:03 -0400641 /*
642 * Set a fence offset if not a virtual connector, so that the
643 * fence signals after one additional commit rather than at the
644 * end of the current one.
645 */
646 rc = sde_fence_create(&c_conn->retire_fence, val,
647 c_conn->connector_type != DRM_MODE_CONNECTOR_VIRTUAL);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400648 else
649 /* get cached property value */
650 rc = msm_property_atomic_get(&c_conn->property_info,
651 c_state->property_values, 0, property, val);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400652
653 /* allow for custom override */
654 if (c_conn->ops.get_property)
655 rc = c_conn->ops.get_property(connector,
656 (struct drm_connector_state *)state,
657 idx,
658 val,
659 c_conn->display);
660 return rc;
661}
662
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400663void sde_connector_prepare_fence(struct drm_connector *connector)
664{
665 if (!connector) {
666 SDE_ERROR("invalid connector\n");
667 return;
668 }
669
670 sde_fence_prepare(&to_sde_connector(connector)->retire_fence);
671}
672
673void sde_connector_complete_commit(struct drm_connector *connector)
674{
675 if (!connector) {
676 SDE_ERROR("invalid connector\n");
677 return;
678 }
679
680 /* signal connector's retire fence */
681 sde_fence_signal(&to_sde_connector(connector)->retire_fence, 0);
682}
683
Clarence Ipdd8021c2016-07-20 16:39:47 -0400684static enum drm_connector_status
685sde_connector_detect(struct drm_connector *connector, bool force)
686{
687 enum drm_connector_status status = connector_status_unknown;
688 struct sde_connector *c_conn;
689
690 if (!connector) {
691 SDE_ERROR("invalid connector\n");
692 return status;
693 }
694
695 c_conn = to_sde_connector(connector);
696
697 if (c_conn->ops.detect)
698 status = c_conn->ops.detect(connector,
699 force,
700 c_conn->display);
701
702 return status;
703}
704
Alan Kwong578cdaf2017-01-28 17:25:43 -0800705#ifdef CONFIG_DEBUG_FS
706/**
707 * sde_connector_init_debugfs - initialize connector debugfs
708 * @connector: Pointer to drm connector
709 */
710static int sde_connector_init_debugfs(struct drm_connector *connector)
711{
712 struct sde_connector *sde_connector;
713
714 if (!connector || !connector->debugfs_entry) {
715 SDE_ERROR("invalid connector\n");
716 return -EINVAL;
717 }
718
719 sde_connector = to_sde_connector(connector);
720
721 if (!debugfs_create_bool("fb_kmap", 0644, connector->debugfs_entry,
722 &sde_connector->fb_kmap)) {
723 SDE_ERROR("failed to create connector fb_kmap\n");
724 return -ENOMEM;
725 }
726
727 return 0;
728}
729#else
730static int sde_connector_init_debugfs(struct drm_connector *connector)
731{
732 return 0;
733}
734#endif
735
736static int sde_connector_late_register(struct drm_connector *connector)
737{
738 return sde_connector_init_debugfs(connector);
739}
740
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -0700741static void sde_connector_early_unregister(struct drm_connector *connector)
742{
743 /* debugfs under connector->debugfs are deleted by drm_debugfs */
744}
745
Clarence Ipdd8021c2016-07-20 16:39:47 -0400746static const struct drm_connector_funcs sde_connector_ops = {
747 .dpms = drm_atomic_helper_connector_dpms,
748 .reset = sde_connector_atomic_reset,
749 .detect = sde_connector_detect,
750 .destroy = sde_connector_destroy,
751 .fill_modes = drm_helper_probe_single_connector_modes,
752 .atomic_duplicate_state = sde_connector_atomic_duplicate_state,
753 .atomic_destroy_state = sde_connector_atomic_destroy_state,
754 .atomic_set_property = sde_connector_atomic_set_property,
755 .atomic_get_property = sde_connector_atomic_get_property,
756 .set_property = sde_connector_set_property,
Alan Kwong578cdaf2017-01-28 17:25:43 -0800757 .late_register = sde_connector_late_register,
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -0700758 .early_unregister = sde_connector_early_unregister,
Clarence Ipdd8021c2016-07-20 16:39:47 -0400759};
760
761static int sde_connector_get_modes(struct drm_connector *connector)
762{
763 struct sde_connector *c_conn;
764
765 if (!connector) {
766 SDE_ERROR("invalid connector\n");
767 return 0;
768 }
769
770 c_conn = to_sde_connector(connector);
771 if (!c_conn->ops.get_modes) {
772 SDE_DEBUG("missing get_modes callback\n");
773 return 0;
774 }
775
776 return c_conn->ops.get_modes(connector, c_conn->display);
777}
778
779static enum drm_mode_status
780sde_connector_mode_valid(struct drm_connector *connector,
781 struct drm_display_mode *mode)
782{
783 struct sde_connector *c_conn;
784
785 if (!connector || !mode) {
786 SDE_ERROR("invalid argument(s), conn %pK, mode %pK\n",
787 connector, mode);
788 return MODE_ERROR;
789 }
790
791 c_conn = to_sde_connector(connector);
792
793 if (c_conn->ops.mode_valid)
794 return c_conn->ops.mode_valid(connector, mode, c_conn->display);
795
796 /* assume all modes okay by default */
797 return MODE_OK;
798}
799
800static struct drm_encoder *
801sde_connector_best_encoder(struct drm_connector *connector)
802{
803 struct sde_connector *c_conn = to_sde_connector(connector);
804
805 if (!connector) {
806 SDE_ERROR("invalid connector\n");
807 return NULL;
808 }
809
810 /*
811 * This is true for now, revisit this code when multiple encoders are
812 * supported.
813 */
814 return c_conn->encoder;
815}
816
817static const struct drm_connector_helper_funcs sde_connector_helper_ops = {
818 .get_modes = sde_connector_get_modes,
819 .mode_valid = sde_connector_mode_valid,
820 .best_encoder = sde_connector_best_encoder,
821};
822
823struct drm_connector *sde_connector_init(struct drm_device *dev,
824 struct drm_encoder *encoder,
825 struct drm_panel *panel,
826 void *display,
827 const struct sde_connector_ops *ops,
828 int connector_poll,
829 int connector_type)
830{
831 struct msm_drm_private *priv;
832 struct sde_kms *sde_kms;
833 struct sde_kms_info *info;
834 struct sde_connector *c_conn = NULL;
Ping Li898b1bf2017-02-09 18:03:28 -0800835 struct dsi_display *dsi_display;
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400836 struct msm_display_info display_info;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400837 int rc;
838
839 if (!dev || !dev->dev_private || !encoder) {
840 SDE_ERROR("invalid argument(s), dev %pK, enc %pK\n",
841 dev, encoder);
842 return ERR_PTR(-EINVAL);
843 }
844
845 priv = dev->dev_private;
846 if (!priv->kms) {
847 SDE_ERROR("invalid kms reference\n");
848 return ERR_PTR(-EINVAL);
849 }
850
851 c_conn = kzalloc(sizeof(*c_conn), GFP_KERNEL);
852 if (!c_conn) {
853 SDE_ERROR("failed to alloc sde connector\n");
854 return ERR_PTR(-ENOMEM);
855 }
856
857 rc = drm_connector_init(dev,
858 &c_conn->base,
859 &sde_connector_ops,
860 connector_type);
861 if (rc)
862 goto error_free_conn;
863
Clarence Ipa18d4832017-03-13 12:35:44 -0700864 spin_lock_init(&c_conn->event_lock);
865
Clarence Ipdd8021c2016-07-20 16:39:47 -0400866 c_conn->connector_type = connector_type;
867 c_conn->encoder = encoder;
868 c_conn->panel = panel;
869 c_conn->display = display;
870
Alan Kwongdfa8c082016-07-29 04:10:00 -0400871 /* cache mmu_id's for later */
Clarence Ipdd8021c2016-07-20 16:39:47 -0400872 sde_kms = to_sde_kms(priv->kms);
Alan Kwongdfa8c082016-07-29 04:10:00 -0400873 if (sde_kms->vbif[VBIF_NRT]) {
874 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] =
875 sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_UNSECURE];
876 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE] =
877 sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_SECURE];
878 } else {
879 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] =
880 sde_kms->mmu_id[MSM_SMMU_DOMAIN_UNSECURE];
881 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE] =
882 sde_kms->mmu_id[MSM_SMMU_DOMAIN_SECURE];
883 }
Clarence Ipdd8021c2016-07-20 16:39:47 -0400884
885 if (ops)
886 c_conn->ops = *ops;
887
888 c_conn->base.helper_private = &sde_connector_helper_ops;
889 c_conn->base.polled = connector_poll;
890 c_conn->base.interlace_allowed = 0;
891 c_conn->base.doublescan_allowed = 0;
892
893 snprintf(c_conn->name,
894 SDE_CONNECTOR_NAME_SIZE,
895 "conn%u",
896 c_conn->base.base.id);
897
Lloyd Atkinson5d40d312016-09-06 08:34:13 -0400898 rc = sde_fence_init(&c_conn->retire_fence, c_conn->name,
899 c_conn->base.base.id);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400900 if (rc) {
901 SDE_ERROR("failed to init fence, %d\n", rc);
902 goto error_cleanup_conn;
903 }
904
Clarence Ipdd8021c2016-07-20 16:39:47 -0400905 rc = drm_mode_connector_attach_encoder(&c_conn->base, encoder);
906 if (rc) {
907 SDE_ERROR("failed to attach encoder to connector, %d\n", rc);
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -0800908 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400909 }
910
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800911 rc = sde_backlight_setup(c_conn);
912 if (rc) {
913 SDE_ERROR("failed to setup backlight, rc=%d\n", rc);
914 goto error_cleanup_fence;
Vishnuvardhan Prodduturi75b96802016-10-17 18:45:55 +0530915 }
916
Clarence Ipdd8021c2016-07-20 16:39:47 -0400917 /* create properties */
918 msm_property_init(&c_conn->property_info, &c_conn->base.base, dev,
919 priv->conn_property, c_conn->property_data,
920 CONNECTOR_PROP_COUNT, CONNECTOR_PROP_BLOBCOUNT,
921 sizeof(struct sde_connector_state));
922
923 if (c_conn->ops.post_init) {
924 info = kmalloc(sizeof(*info), GFP_KERNEL);
925 if (!info) {
926 SDE_ERROR("failed to allocate info buffer\n");
927 rc = -ENOMEM;
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -0800928 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400929 }
930
931 sde_kms_info_reset(info);
932 rc = c_conn->ops.post_init(&c_conn->base, info, display);
933 if (rc) {
934 SDE_ERROR("post-init failed, %d\n", rc);
935 kfree(info);
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -0800936 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400937 }
938
939 msm_property_install_blob(&c_conn->property_info,
Dhaval Patel4e574842016-08-23 15:11:37 -0700940 "capabilities",
Clarence Ipdd8021c2016-07-20 16:39:47 -0400941 DRM_MODE_PROP_IMMUTABLE,
942 CONNECTOR_PROP_SDE_INFO);
943
944 msm_property_set_blob(&c_conn->property_info,
Dhaval Patel4e574842016-08-23 15:11:37 -0700945 &c_conn->blob_caps,
Clarence Ipdd8021c2016-07-20 16:39:47 -0400946 SDE_KMS_INFO_DATA(info),
947 SDE_KMS_INFO_DATALEN(info),
948 CONNECTOR_PROP_SDE_INFO);
949 kfree(info);
950 }
951
Ping Li898b1bf2017-02-09 18:03:28 -0800952 if (connector_type == DRM_MODE_CONNECTOR_DSI) {
953 dsi_display = (struct dsi_display *)(display);
954 if (dsi_display && dsi_display->panel &&
955 dsi_display->panel->hdr_props.hdr_enabled == true) {
956 msm_property_install_blob(&c_conn->property_info,
957 "hdr_properties",
958 DRM_MODE_PROP_IMMUTABLE,
959 CONNECTOR_PROP_HDR_INFO);
960
961 msm_property_set_blob(&c_conn->property_info,
962 &c_conn->blob_hdr,
963 &dsi_display->panel->hdr_props,
964 sizeof(dsi_display->panel->hdr_props),
965 CONNECTOR_PROP_HDR_INFO);
966 }
967 }
968
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400969 rc = sde_connector_get_info(&c_conn->base, &display_info);
970 if (!rc && display_info.roi_caps.enabled) {
971 msm_property_install_volatile_range(
972 &c_conn->property_info, "sde_drm_roi_v1", 0x0,
973 0, ~0, 0, CONNECTOR_PROP_ROI_V1);
974 }
975
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400976 msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE",
Dhaval Patel4e574842016-08-23 15:11:37 -0700977 0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400978
Lloyd Atkinsonb6191972016-08-10 18:31:46 -0400979 /* enum/bitmask properties */
980 msm_property_install_enum(&c_conn->property_info, "topology_name",
981 DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name,
982 ARRAY_SIZE(e_topology_name),
983 CONNECTOR_PROP_TOPOLOGY_NAME);
984 msm_property_install_enum(&c_conn->property_info, "topology_control",
985 0, 1, e_topology_control,
986 ARRAY_SIZE(e_topology_control),
987 CONNECTOR_PROP_TOPOLOGY_CONTROL);
988
Clarence Ipdd8021c2016-07-20 16:39:47 -0400989 rc = msm_property_install_get_status(&c_conn->property_info);
990 if (rc) {
991 SDE_ERROR("failed to create one or more properties\n");
992 goto error_destroy_property;
993 }
994
Lloyd Atkinsonb6191972016-08-10 18:31:46 -0400995 SDE_DEBUG("connector %d attach encoder %d\n",
996 c_conn->base.base.id, encoder->base.id);
997
Clarence Ipdd8021c2016-07-20 16:39:47 -0400998 priv->connectors[priv->num_connectors++] = &c_conn->base;
999
1000 return &c_conn->base;
1001
1002error_destroy_property:
Dhaval Patel4e574842016-08-23 15:11:37 -07001003 if (c_conn->blob_caps)
1004 drm_property_unreference_blob(c_conn->blob_caps);
Ping Li898b1bf2017-02-09 18:03:28 -08001005 if (c_conn->blob_hdr)
1006 drm_property_unreference_blob(c_conn->blob_hdr);
Clarence Ipdd8021c2016-07-20 16:39:47 -04001007 msm_property_destroy(&c_conn->property_info);
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001008error_cleanup_fence:
1009 sde_fence_deinit(&c_conn->retire_fence);
Clarence Ipdd8021c2016-07-20 16:39:47 -04001010error_cleanup_conn:
1011 drm_connector_cleanup(&c_conn->base);
1012error_free_conn:
1013 kfree(c_conn);
1014
1015 return ERR_PTR(rc);
1016}
Gopikrishnaiah Anandande2c81b2017-03-15 12:41:29 -07001017
1018int sde_connector_register_custom_event(struct sde_kms *kms,
1019 struct drm_connector *conn_drm, u32 event, bool val)
1020{
1021 return -EINVAL;
1022}