blob: 6593b47745de153f2bac1adaa8690dd85973e48f [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
Clarence Ip90b282d2017-05-04 10:00:32 -070013#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
Clarence Ipdd8021c2016-07-20 16:39:47 -040014#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 Atkinson77382202017-02-01 14:59:43 -050024/* Autorefresh will occur after FRAME_CNT frames. Large values are unlikely */
25#define AUTOREFRESH_MAX_FRAME_CNT 6
26
Lloyd Atkinson8ba47032017-03-22 17:13:32 -040027#define SDE_DEBUG_CONN(c, fmt, ...) SDE_DEBUG("conn%d " fmt,\
28 (c) ? (c)->base.base.id : -1, ##__VA_ARGS__)
29
30#define SDE_ERROR_CONN(c, fmt, ...) SDE_ERROR("conn%d " fmt,\
31 (c) ? (c)->base.base.id : -1, ##__VA_ARGS__)
32
Lloyd Atkinsonb6191972016-08-10 18:31:46 -040033static const struct drm_prop_enum_list e_topology_name[] = {
Jeykumar Sankaran2b098072017-03-16 17:25:59 -070034 {SDE_RM_TOPOLOGY_NONE, "sde_none"},
Lloyd Atkinsonb6191972016-08-10 18:31:46 -040035 {SDE_RM_TOPOLOGY_SINGLEPIPE, "sde_singlepipe"},
Jeykumar Sankaran2b098072017-03-16 17:25:59 -070036 {SDE_RM_TOPOLOGY_SINGLEPIPE_DSC, "sde_singlepipe_dsc"},
Lloyd Atkinsonb6191972016-08-10 18:31:46 -040037 {SDE_RM_TOPOLOGY_DUALPIPE, "sde_dualpipe"},
Jeykumar Sankaran2b098072017-03-16 17:25:59 -070038 {SDE_RM_TOPOLOGY_DUALPIPE_DSC, "sde_dualpipe_dsc"},
39 {SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE, "sde_dualpipemerge"},
40 {SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC, "sde_dualpipemerge_dsc"},
41 {SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE, "sde_dualpipe_dscmerge"},
Lloyd Atkinsonb6191972016-08-10 18:31:46 -040042 {SDE_RM_TOPOLOGY_PPSPLIT, "sde_ppsplit"},
Lloyd Atkinsonb6191972016-08-10 18:31:46 -040043};
44static const struct drm_prop_enum_list e_topology_control[] = {
45 {SDE_RM_TOPCTL_RESERVE_LOCK, "reserve_lock"},
46 {SDE_RM_TOPCTL_RESERVE_CLEAR, "reserve_clear"},
47 {SDE_RM_TOPCTL_DSPP, "dspp"},
Lloyd Atkinsonb6191972016-08-10 18:31:46 -040048};
Clarence Ip90b282d2017-05-04 10:00:32 -070049static const struct drm_prop_enum_list e_power_mode[] = {
50 {SDE_MODE_DPMS_ON, "ON"},
51 {SDE_MODE_DPMS_LP1, "LP1"},
52 {SDE_MODE_DPMS_LP2, "LP2"},
53 {SDE_MODE_DPMS_OFF, "OFF"},
54};
Lloyd Atkinsonb6191972016-08-10 18:31:46 -040055
Dhaval Patel7cdd6662017-03-08 13:10:37 -080056static int sde_backlight_device_update_status(struct backlight_device *bd)
57{
58 int brightness;
59 struct dsi_display *display;
60 struct sde_connector *c_conn;
61 int bl_lvl;
62
63 brightness = bd->props.brightness;
64
65 if ((bd->props.power != FB_BLANK_UNBLANK) ||
66 (bd->props.state & BL_CORE_FBBLANK) ||
67 (bd->props.state & BL_CORE_SUSPENDED))
68 brightness = 0;
69
70 c_conn = bl_get_data(bd);
71 display = (struct dsi_display *) c_conn->display;
72 if (brightness > display->panel->bl_config.bl_max_level)
73 brightness = display->panel->bl_config.bl_max_level;
74
75 /* map UI brightness into driver backlight level with rounding */
76 bl_lvl = mult_frac(brightness, display->panel->bl_config.bl_max_level,
77 display->panel->bl_config.brightness_max_level);
78
79 if (!bl_lvl && brightness)
80 bl_lvl = 1;
81
82 if (c_conn->ops.set_backlight)
83 c_conn->ops.set_backlight(c_conn->display, bl_lvl);
84
85 return 0;
86}
87
88static int sde_backlight_device_get_brightness(struct backlight_device *bd)
89{
90 return 0;
91}
92
93static const struct backlight_ops sde_backlight_device_ops = {
94 .update_status = sde_backlight_device_update_status,
95 .get_brightness = sde_backlight_device_get_brightness,
96};
97
Shashank Babu Chinta Venkata06c428e2017-04-17 13:52:28 -070098static int sde_backlight_setup(struct sde_connector *c_conn,
99 struct drm_device *dev)
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800100{
101 struct backlight_device *bl_device;
102 struct backlight_properties props;
103 struct dsi_display *display;
104 struct dsi_backlight_config *bl_config;
105 static int display_count;
106 char bl_node_name[BL_NODE_NAME_SIZE];
107
Shashank Babu Chinta Venkata06c428e2017-04-17 13:52:28 -0700108 if (!c_conn || !dev || !dev->dev) {
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800109 SDE_ERROR("invalid param\n");
110 return -EINVAL;
111 } else if (c_conn->connector_type != DRM_MODE_CONNECTOR_DSI) {
112 return 0;
113 }
114
115 memset(&props, 0, sizeof(props));
116 props.type = BACKLIGHT_RAW;
117 props.power = FB_BLANK_UNBLANK;
118
119 display = (struct dsi_display *) c_conn->display;
120 bl_config = &display->panel->bl_config;
121 props.max_brightness = bl_config->brightness_max_level;
122 props.brightness = bl_config->brightness_max_level;
123 snprintf(bl_node_name, BL_NODE_NAME_SIZE, "panel%u-backlight",
124 display_count);
Shashank Babu Chinta Venkata06c428e2017-04-17 13:52:28 -0700125 bl_device = backlight_device_register(bl_node_name, dev->dev,
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800126 c_conn, &sde_backlight_device_ops, &props);
127 if (IS_ERR_OR_NULL(bl_device)) {
128 SDE_ERROR("Failed to register backlight: %ld\n",
129 PTR_ERR(bl_device));
130 return -ENODEV;
131 }
132 display_count++;
133
134 return 0;
135}
136
Clarence Ipa18d4832017-03-13 12:35:44 -0700137int sde_connector_trigger_event(void *drm_connector,
138 uint32_t event_idx, uint32_t instance_idx,
139 uint32_t data0, uint32_t data1,
140 uint32_t data2, uint32_t data3)
141{
142 struct sde_connector *c_conn;
143 unsigned long irq_flags;
144 void (*cb_func)(uint32_t event_idx,
145 uint32_t instance_idx, void *usr,
146 uint32_t data0, uint32_t data1,
147 uint32_t data2, uint32_t data3);
148 void *usr;
149 int rc = 0;
150
151 /*
152 * This function may potentially be called from an ISR context, so
153 * avoid excessive logging/etc.
154 */
155 if (!drm_connector)
156 return -EINVAL;
157 else if (event_idx >= SDE_CONN_EVENT_COUNT)
158 return -EINVAL;
159 c_conn = to_sde_connector(drm_connector);
160
161 spin_lock_irqsave(&c_conn->event_lock, irq_flags);
162 cb_func = c_conn->event_table[event_idx].cb_func;
163 usr = c_conn->event_table[event_idx].usr;
164 spin_unlock_irqrestore(&c_conn->event_lock, irq_flags);
165
166 if (cb_func)
167 cb_func(event_idx, instance_idx, usr,
168 data0, data1, data2, data3);
169 else
170 rc = -EAGAIN;
171
172 return rc;
173}
174
175int sde_connector_register_event(struct drm_connector *connector,
176 uint32_t event_idx,
177 void (*cb_func)(uint32_t event_idx,
178 uint32_t instance_idx, void *usr,
179 uint32_t data0, uint32_t data1,
180 uint32_t data2, uint32_t data3),
181 void *usr)
182{
183 struct sde_connector *c_conn;
184 unsigned long irq_flags;
185
186 if (!connector) {
187 SDE_ERROR("invalid connector\n");
188 return -EINVAL;
189 } else if (event_idx >= SDE_CONN_EVENT_COUNT) {
190 SDE_ERROR("conn%d, invalid event %d\n",
191 connector->base.id, event_idx);
192 return -EINVAL;
193 }
194 c_conn = to_sde_connector(connector);
195
196 spin_lock_irqsave(&c_conn->event_lock, irq_flags);
197 c_conn->event_table[event_idx].cb_func = cb_func;
198 c_conn->event_table[event_idx].usr = usr;
199 spin_unlock_irqrestore(&c_conn->event_lock, irq_flags);
200
201 /* optionally notify display of event registration */
202 if (c_conn->ops.enable_event && c_conn->display)
203 c_conn->ops.enable_event(connector, event_idx,
204 cb_func != NULL, c_conn->display);
205 return 0;
206}
207
208void sde_connector_unregister_event(struct drm_connector *connector,
209 uint32_t event_idx)
210{
211 (void)sde_connector_register_event(connector, event_idx, 0, 0);
212}
213
Clarence Ipcb3afd42016-07-15 16:25:34 -0400214int sde_connector_get_info(struct drm_connector *connector,
215 struct msm_display_info *info)
216{
217 struct sde_connector *c_conn;
218
219 if (!connector || !info) {
220 SDE_ERROR("invalid argument(s), conn %pK, info %pK\n",
221 connector, info);
222 return -EINVAL;
223 }
224
225 c_conn = to_sde_connector(connector);
226
227 if (!c_conn->display || !c_conn->ops.get_info) {
228 SDE_ERROR("display info not supported for %pK\n",
229 c_conn->display);
230 return -EINVAL;
231 }
232
233 return c_conn->ops.get_info(info, c_conn->display);
234}
235
Lloyd Atkinson05d75512017-01-17 14:45:51 -0500236int sde_connector_pre_kickoff(struct drm_connector *connector)
237{
238 struct sde_connector *c_conn;
239 struct sde_connector_state *c_state;
240 struct msm_display_kickoff_params params;
241 int rc;
242
243 if (!connector) {
244 SDE_ERROR("invalid argument\n");
245 return -EINVAL;
246 }
247
248 c_conn = to_sde_connector(connector);
249 c_state = to_sde_connector_state(connector->state);
250
251 if (!c_conn->display) {
252 SDE_ERROR("invalid argument\n");
253 return -EINVAL;
254 }
255
256 if (!c_conn->ops.pre_kickoff)
257 return 0;
258
259 params.rois = &c_state->rois;
260
261 SDE_EVT32_VERBOSE(connector->base.id);
262
263 rc = c_conn->ops.pre_kickoff(connector, c_conn->display, &params);
264
265 return rc;
266}
267
Veera Sundaram Sankaranbb2bf9a2017-03-29 18:56:47 -0700268void sde_connector_clk_ctrl(struct drm_connector *connector, bool enable)
269{
270 struct sde_connector *c_conn;
271 struct dsi_display *display;
272 u32 state = enable ? DSI_CLK_ON : DSI_CLK_OFF;
273
274 if (!connector) {
275 SDE_ERROR("invalid connector\n");
276 return;
277 }
278
279 c_conn = to_sde_connector(connector);
280 display = (struct dsi_display *) c_conn->display;
281
282 if (display && c_conn->ops.clk_ctrl)
283 c_conn->ops.clk_ctrl(display->mdp_clk_handle,
284 DSI_ALL_CLKS, state);
285}
286
Clarence Ipdd8021c2016-07-20 16:39:47 -0400287static void sde_connector_destroy(struct drm_connector *connector)
288{
289 struct sde_connector *c_conn;
290
291 if (!connector) {
292 SDE_ERROR("invalid connector\n");
293 return;
294 }
295
296 c_conn = to_sde_connector(connector);
297
Dhaval Patel4e574842016-08-23 15:11:37 -0700298 if (c_conn->blob_caps)
299 drm_property_unreference_blob(c_conn->blob_caps);
Ping Li898b1bf2017-02-09 18:03:28 -0800300 if (c_conn->blob_hdr)
301 drm_property_unreference_blob(c_conn->blob_hdr);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400302 msm_property_destroy(&c_conn->property_info);
303
304 drm_connector_unregister(connector);
Clarence Ip90b282d2017-05-04 10:00:32 -0700305 mutex_destroy(&c_conn->lock);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400306 sde_fence_deinit(&c_conn->retire_fence);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400307 drm_connector_cleanup(connector);
308 kfree(c_conn);
309}
310
311/**
312 * _sde_connector_destroy_fb - clean up connector state's out_fb buffer
313 * @c_conn: Pointer to sde connector structure
314 * @c_state: Pointer to sde connector state structure
315 */
316static void _sde_connector_destroy_fb(struct sde_connector *c_conn,
317 struct sde_connector_state *c_state)
318{
319 if (!c_state || !c_state->out_fb) {
320 SDE_ERROR("invalid state %pK\n", c_state);
321 return;
322 }
323
324 msm_framebuffer_cleanup(c_state->out_fb,
325 c_state->mmu_id);
326 drm_framebuffer_unreference(c_state->out_fb);
327 c_state->out_fb = NULL;
328
329 if (c_conn) {
330 c_state->property_values[CONNECTOR_PROP_OUT_FB] =
331 msm_property_get_default(&c_conn->property_info,
332 CONNECTOR_PROP_OUT_FB);
333 } else {
334 c_state->property_values[CONNECTOR_PROP_OUT_FB] = ~0;
335 }
336}
337
338static void sde_connector_atomic_destroy_state(struct drm_connector *connector,
339 struct drm_connector_state *state)
340{
341 struct sde_connector *c_conn = NULL;
342 struct sde_connector_state *c_state = NULL;
343
344 if (!state) {
345 SDE_ERROR("invalid state\n");
346 return;
347 }
348
349 /*
350 * The base DRM framework currently always passes in a NULL
351 * connector pointer. This is not correct, but attempt to
352 * handle that case as much as possible.
353 */
354 if (connector)
355 c_conn = to_sde_connector(connector);
356 c_state = to_sde_connector_state(state);
357
358 if (c_state->out_fb)
359 _sde_connector_destroy_fb(c_conn, c_state);
360
361 if (!c_conn) {
362 kfree(c_state);
363 } else {
364 /* destroy value helper */
365 msm_property_destroy_state(&c_conn->property_info, c_state,
366 c_state->property_values, 0);
367 }
368}
369
370static void sde_connector_atomic_reset(struct drm_connector *connector)
371{
372 struct sde_connector *c_conn;
373 struct sde_connector_state *c_state;
374
375 if (!connector) {
376 SDE_ERROR("invalid connector\n");
377 return;
378 }
379
380 c_conn = to_sde_connector(connector);
381
382 if (connector->state) {
383 sde_connector_atomic_destroy_state(connector, connector->state);
384 connector->state = 0;
385 }
386
387 c_state = msm_property_alloc_state(&c_conn->property_info);
388 if (!c_state) {
389 SDE_ERROR("state alloc failed\n");
390 return;
391 }
392
393 /* reset value helper, zero out state structure and reset properties */
394 msm_property_reset_state(&c_conn->property_info, c_state,
395 c_state->property_values, 0);
396
397 c_state->base.connector = connector;
398 connector->state = &c_state->base;
399}
400
401static struct drm_connector_state *
402sde_connector_atomic_duplicate_state(struct drm_connector *connector)
403{
404 struct sde_connector *c_conn;
405 struct sde_connector_state *c_state, *c_oldstate;
406 int rc;
407
408 if (!connector || !connector->state) {
409 SDE_ERROR("invalid connector %pK\n", connector);
410 return NULL;
411 }
412
413 c_conn = to_sde_connector(connector);
414 c_oldstate = to_sde_connector_state(connector->state);
415 c_state = msm_property_alloc_state(&c_conn->property_info);
416 if (!c_state) {
417 SDE_ERROR("state alloc failed\n");
418 return NULL;
419 }
420
421 /* duplicate value helper */
422 msm_property_duplicate_state(&c_conn->property_info,
423 c_oldstate, c_state, c_state->property_values, 0);
424
425 /* additional handling for drm framebuffer objects */
426 if (c_state->out_fb) {
427 drm_framebuffer_reference(c_state->out_fb);
428 rc = msm_framebuffer_prepare(c_state->out_fb,
429 c_state->mmu_id);
430 if (rc)
431 SDE_ERROR("failed to prepare fb, %d\n", rc);
432 }
433
434 return &c_state->base;
435}
436
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400437static int _sde_connector_roi_v1_check_roi(
438 struct sde_connector *c_conn,
439 struct drm_clip_rect *roi_conn,
440 const struct msm_roi_caps *caps)
441{
442 const struct msm_roi_alignment *align = &caps->align;
443 int w = roi_conn->x2 - roi_conn->x1;
444 int h = roi_conn->y2 - roi_conn->y1;
445
446 if (w <= 0 || h <= 0) {
447 SDE_ERROR_CONN(c_conn, "invalid conn roi w %d h %d\n", w, h);
448 return -EINVAL;
449 }
450
451 if (w < align->min_width || w % align->width_pix_align) {
452 SDE_ERROR_CONN(c_conn,
453 "invalid conn roi width %d min %d align %d\n",
454 w, align->min_width, align->width_pix_align);
455 return -EINVAL;
456 }
457
458 if (h < align->min_height || h % align->height_pix_align) {
459 SDE_ERROR_CONN(c_conn,
460 "invalid conn roi height %d min %d align %d\n",
461 h, align->min_height, align->height_pix_align);
462 return -EINVAL;
463 }
464
465 if (roi_conn->x1 % align->xstart_pix_align) {
466 SDE_ERROR_CONN(c_conn, "invalid conn roi x1 %d align %d\n",
467 roi_conn->x1, align->xstart_pix_align);
468 return -EINVAL;
469 }
470
471 if (roi_conn->y1 % align->ystart_pix_align) {
472 SDE_ERROR_CONN(c_conn, "invalid conn roi y1 %d align %d\n",
473 roi_conn->y1, align->ystart_pix_align);
474 return -EINVAL;
475 }
476
477 return 0;
478}
479
480static int _sde_connector_set_roi_v1(
481 struct sde_connector *c_conn,
482 struct sde_connector_state *c_state,
483 void *usr_ptr)
484{
485 struct sde_drm_roi_v1 roi_v1;
486 struct msm_display_info display_info;
487 struct msm_roi_caps *caps;
488 int i, rc;
489
490 if (!c_conn || !c_state) {
491 SDE_ERROR("invalid args\n");
492 return -EINVAL;
493 }
494
495 rc = sde_connector_get_info(&c_conn->base, &display_info);
496 if (rc) {
497 SDE_ERROR_CONN(c_conn, "display get info error: %d\n", rc);
498 return rc;
499 }
500
501 caps = &display_info.roi_caps;
502 if (!caps->enabled) {
503 SDE_ERROR_CONN(c_conn, "display roi capability is disabled\n");
504 return -ENOTSUPP;
505 }
506
507 memset(&c_state->rois, 0, sizeof(c_state->rois));
508
509 if (!usr_ptr) {
510 SDE_DEBUG_CONN(c_conn, "rois cleared\n");
511 return 0;
512 }
513
514 if (copy_from_user(&roi_v1, usr_ptr, sizeof(roi_v1))) {
515 SDE_ERROR_CONN(c_conn, "failed to copy roi_v1 data\n");
516 return -EINVAL;
517 }
518
519 SDE_DEBUG_CONN(c_conn, "num_rects %d\n", roi_v1.num_rects);
520
521 if (roi_v1.num_rects == 0) {
522 SDE_DEBUG_CONN(c_conn, "rois cleared\n");
523 return 0;
524 }
525
526 if (roi_v1.num_rects > SDE_MAX_ROI_V1 ||
527 roi_v1.num_rects > caps->num_roi) {
528 SDE_ERROR_CONN(c_conn, "too many rects specified: %d\n",
529 roi_v1.num_rects);
530 return -EINVAL;
531 }
532
533 c_state->rois.num_rects = roi_v1.num_rects;
534 for (i = 0; i < roi_v1.num_rects; ++i) {
535 int rc;
536
537 rc = _sde_connector_roi_v1_check_roi(c_conn, &roi_v1.roi[i],
538 caps);
539 if (rc)
540 return rc;
541
542 c_state->rois.roi[i] = roi_v1.roi[i];
543 SDE_DEBUG_CONN(c_conn, "roi%d: roi 0x%x 0x%x 0x%x 0x%x\n", i,
544 c_state->rois.roi[i].x1,
545 c_state->rois.roi[i].y1,
546 c_state->rois.roi[i].x2,
547 c_state->rois.roi[i].y2);
548 }
549
550 return 0;
551}
552
Clarence Ip90b282d2017-05-04 10:00:32 -0700553static int _sde_connector_update_power_locked(struct sde_connector *c_conn)
554{
555 struct drm_connector *connector;
556 void *display;
557 int (*set_power)(struct drm_connector *, int, void *);
558 int mode, rc = 0;
559
560 if (!c_conn)
561 return -EINVAL;
562 connector = &c_conn->base;
563
564 mode = c_conn->lp_mode;
565 if (c_conn->dpms_mode != DRM_MODE_DPMS_ON)
566 mode = SDE_MODE_DPMS_OFF;
567 switch (c_conn->dpms_mode) {
568 case DRM_MODE_DPMS_ON:
569 mode = c_conn->lp_mode;
570 break;
571 case DRM_MODE_DPMS_STANDBY:
572 mode = SDE_MODE_DPMS_STANDBY;
573 break;
574 case DRM_MODE_DPMS_SUSPEND:
575 mode = SDE_MODE_DPMS_SUSPEND;
576 break;
577 case DRM_MODE_DPMS_OFF:
578 mode = SDE_MODE_DPMS_OFF;
579 break;
580 default:
581 mode = c_conn->lp_mode;
582 SDE_ERROR("conn %d dpms set to unrecognized mode %d\n",
583 connector->base.id, mode);
584 break;
585 }
586
587 SDE_DEBUG("conn %d - dpms %d, lp %d, panel %d\n", connector->base.id,
588 c_conn->dpms_mode, c_conn->lp_mode, mode);
589
590 if (mode != c_conn->last_panel_power_mode && c_conn->ops.set_power) {
591 display = c_conn->display;
592 set_power = c_conn->ops.set_power;
593
594 mutex_unlock(&c_conn->lock);
595 rc = set_power(connector, mode, display);
596 mutex_lock(&c_conn->lock);
597 }
598 c_conn->last_panel_power_mode = mode;
599
600 return rc;
601}
602
Clarence Ipdd8021c2016-07-20 16:39:47 -0400603static int sde_connector_atomic_set_property(struct drm_connector *connector,
604 struct drm_connector_state *state,
605 struct drm_property *property,
606 uint64_t val)
607{
608 struct sde_connector *c_conn;
609 struct sde_connector_state *c_state;
610 int idx, rc;
611
612 if (!connector || !state || !property) {
613 SDE_ERROR("invalid argument(s), conn %pK, state %pK, prp %pK\n",
614 connector, state, property);
615 return -EINVAL;
616 }
617
618 c_conn = to_sde_connector(connector);
619 c_state = to_sde_connector_state(state);
620
621 /* generic property handling */
622 rc = msm_property_atomic_set(&c_conn->property_info,
623 c_state->property_values, 0, property, val);
624 if (rc)
625 goto end;
626
627 /* connector-specific property handling */
628 idx = msm_property_index(&c_conn->property_info, property);
Clarence Ip90b282d2017-05-04 10:00:32 -0700629 switch (idx) {
630 case CONNECTOR_PROP_OUT_FB:
Clarence Ipdd8021c2016-07-20 16:39:47 -0400631 /* clear old fb, if present */
632 if (c_state->out_fb)
633 _sde_connector_destroy_fb(c_conn, c_state);
634
635 /* convert fb val to drm framebuffer and prepare it */
636 c_state->out_fb =
637 drm_framebuffer_lookup(connector->dev, val);
Alan Kwongae1b1142017-03-05 16:07:10 -0800638 if (!c_state->out_fb && val) {
Clarence Ipdd8021c2016-07-20 16:39:47 -0400639 SDE_ERROR("failed to look up fb %lld\n", val);
640 rc = -EFAULT;
Alan Kwongae1b1142017-03-05 16:07:10 -0800641 } else if (!c_state->out_fb && !val) {
642 SDE_DEBUG("cleared fb_id\n");
643 rc = 0;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400644 } else {
Alan Kwong578cdaf2017-01-28 17:25:43 -0800645 msm_framebuffer_set_kmap(c_state->out_fb,
646 c_conn->fb_kmap);
647
Alan Kwongdfa8c082016-07-29 04:10:00 -0400648 if (c_state->out_fb->flags & DRM_MODE_FB_SECURE)
649 c_state->mmu_id =
650 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE];
651 else
652 c_state->mmu_id =
653 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE];
Clarence Ipdd8021c2016-07-20 16:39:47 -0400654
655 rc = msm_framebuffer_prepare(c_state->out_fb,
656 c_state->mmu_id);
657 if (rc)
658 SDE_ERROR("prep fb failed, %d\n", rc);
659 }
Clarence Ip90b282d2017-05-04 10:00:32 -0700660 break;
Clarence Ip90b282d2017-05-04 10:00:32 -0700661 case CONNECTOR_PROP_LP:
662 mutex_lock(&c_conn->lock);
663 c_conn->lp_mode = val;
664 _sde_connector_update_power_locked(c_conn);
665 mutex_unlock(&c_conn->lock);
666 break;
667 default:
668 break;
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400669 }
670
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400671 if (idx == CONNECTOR_PROP_ROI_V1) {
672 rc = _sde_connector_set_roi_v1(c_conn, c_state, (void *)val);
673 if (rc)
674 SDE_ERROR_CONN(c_conn, "invalid roi_v1, rc: %d\n", rc);
675 }
676
Clarence Ipdd8021c2016-07-20 16:39:47 -0400677 /* check for custom property handling */
678 if (!rc && c_conn->ops.set_property) {
679 rc = c_conn->ops.set_property(connector,
680 state,
681 idx,
682 val,
683 c_conn->display);
684
685 /* potentially clean up out_fb if rc != 0 */
686 if ((idx == CONNECTOR_PROP_OUT_FB) && rc)
687 _sde_connector_destroy_fb(c_conn, c_state);
688 }
689end:
690 return rc;
691}
692
693static int sde_connector_set_property(struct drm_connector *connector,
694 struct drm_property *property,
695 uint64_t val)
696{
697 if (!connector) {
698 SDE_ERROR("invalid connector\n");
699 return -EINVAL;
700 }
701
702 return sde_connector_atomic_set_property(connector,
703 connector->state, property, val);
704}
705
706static int sde_connector_atomic_get_property(struct drm_connector *connector,
707 const struct drm_connector_state *state,
708 struct drm_property *property,
709 uint64_t *val)
710{
711 struct sde_connector *c_conn;
712 struct sde_connector_state *c_state;
713 int idx, rc = -EINVAL;
714
715 if (!connector || !state) {
716 SDE_ERROR("invalid argument(s), conn %pK, state %pK\n",
717 connector, state);
718 return -EINVAL;
719 }
720
721 c_conn = to_sde_connector(connector);
722 c_state = to_sde_connector_state(state);
723
724 idx = msm_property_index(&c_conn->property_info, property);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400725 if (idx == CONNECTOR_PROP_RETIRE_FENCE)
Dhaval Patel5cb59be2017-04-20 20:00:56 -0700726 rc = sde_fence_create(&c_conn->retire_fence, val, 0);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400727 else
728 /* get cached property value */
729 rc = msm_property_atomic_get(&c_conn->property_info,
730 c_state->property_values, 0, property, val);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400731
732 /* allow for custom override */
733 if (c_conn->ops.get_property)
734 rc = c_conn->ops.get_property(connector,
735 (struct drm_connector_state *)state,
736 idx,
737 val,
738 c_conn->display);
739 return rc;
740}
741
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400742void sde_connector_prepare_fence(struct drm_connector *connector)
743{
744 if (!connector) {
745 SDE_ERROR("invalid connector\n");
746 return;
747 }
748
749 sde_fence_prepare(&to_sde_connector(connector)->retire_fence);
750}
751
752void sde_connector_complete_commit(struct drm_connector *connector)
753{
754 if (!connector) {
755 SDE_ERROR("invalid connector\n");
756 return;
757 }
758
759 /* signal connector's retire fence */
760 sde_fence_signal(&to_sde_connector(connector)->retire_fence, 0);
761}
762
Clarence Ipdd8021c2016-07-20 16:39:47 -0400763static enum drm_connector_status
764sde_connector_detect(struct drm_connector *connector, bool force)
765{
766 enum drm_connector_status status = connector_status_unknown;
767 struct sde_connector *c_conn;
768
769 if (!connector) {
770 SDE_ERROR("invalid connector\n");
771 return status;
772 }
773
774 c_conn = to_sde_connector(connector);
775
776 if (c_conn->ops.detect)
777 status = c_conn->ops.detect(connector,
778 force,
779 c_conn->display);
780
781 return status;
782}
783
Clarence Ip90b282d2017-05-04 10:00:32 -0700784static int sde_connector_dpms(struct drm_connector *connector,
785 int mode)
786{
787 struct sde_connector *c_conn;
788
789 if (!connector) {
790 SDE_ERROR("invalid connector\n");
791 return -EINVAL;
792 }
793 c_conn = to_sde_connector(connector);
794
795 /* validate incoming dpms request */
796 switch (mode) {
797 case DRM_MODE_DPMS_ON:
798 case DRM_MODE_DPMS_STANDBY:
799 case DRM_MODE_DPMS_SUSPEND:
800 case DRM_MODE_DPMS_OFF:
801 SDE_DEBUG("conn %d dpms set to %d\n", connector->base.id, mode);
802 break;
803 default:
804 SDE_ERROR("conn %d dpms set to unrecognized mode %d\n",
805 connector->base.id, mode);
806 break;
807 }
808
809 mutex_lock(&c_conn->lock);
810 c_conn->dpms_mode = mode;
811 _sde_connector_update_power_locked(c_conn);
812 mutex_unlock(&c_conn->lock);
813
814 /* use helper for boilerplate handling */
815 return drm_atomic_helper_connector_dpms(connector, mode);
816}
817
818int sde_connector_get_dpms(struct drm_connector *connector)
819{
820 struct sde_connector *c_conn;
821 int rc;
822
823 if (!connector) {
824 SDE_DEBUG("invalid connector\n");
825 return DRM_MODE_DPMS_OFF;
826 }
827
828 c_conn = to_sde_connector(connector);
829
830 mutex_lock(&c_conn->lock);
831 rc = c_conn->dpms_mode;
832 mutex_unlock(&c_conn->lock);
833
834 return rc;
835}
836
Alan Kwong578cdaf2017-01-28 17:25:43 -0800837#ifdef CONFIG_DEBUG_FS
838/**
839 * sde_connector_init_debugfs - initialize connector debugfs
840 * @connector: Pointer to drm connector
841 */
842static int sde_connector_init_debugfs(struct drm_connector *connector)
843{
844 struct sde_connector *sde_connector;
845
846 if (!connector || !connector->debugfs_entry) {
847 SDE_ERROR("invalid connector\n");
848 return -EINVAL;
849 }
850
851 sde_connector = to_sde_connector(connector);
852
853 if (!debugfs_create_bool("fb_kmap", 0644, connector->debugfs_entry,
854 &sde_connector->fb_kmap)) {
855 SDE_ERROR("failed to create connector fb_kmap\n");
856 return -ENOMEM;
857 }
858
859 return 0;
860}
861#else
862static int sde_connector_init_debugfs(struct drm_connector *connector)
863{
864 return 0;
865}
866#endif
867
868static int sde_connector_late_register(struct drm_connector *connector)
869{
870 return sde_connector_init_debugfs(connector);
871}
872
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -0700873static void sde_connector_early_unregister(struct drm_connector *connector)
874{
875 /* debugfs under connector->debugfs are deleted by drm_debugfs */
876}
877
Clarence Ipdd8021c2016-07-20 16:39:47 -0400878static const struct drm_connector_funcs sde_connector_ops = {
Clarence Ip90b282d2017-05-04 10:00:32 -0700879 .dpms = sde_connector_dpms,
Clarence Ipdd8021c2016-07-20 16:39:47 -0400880 .reset = sde_connector_atomic_reset,
881 .detect = sde_connector_detect,
882 .destroy = sde_connector_destroy,
883 .fill_modes = drm_helper_probe_single_connector_modes,
884 .atomic_duplicate_state = sde_connector_atomic_duplicate_state,
885 .atomic_destroy_state = sde_connector_atomic_destroy_state,
886 .atomic_set_property = sde_connector_atomic_set_property,
887 .atomic_get_property = sde_connector_atomic_get_property,
888 .set_property = sde_connector_set_property,
Alan Kwong578cdaf2017-01-28 17:25:43 -0800889 .late_register = sde_connector_late_register,
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -0700890 .early_unregister = sde_connector_early_unregister,
Clarence Ipdd8021c2016-07-20 16:39:47 -0400891};
892
893static int sde_connector_get_modes(struct drm_connector *connector)
894{
895 struct sde_connector *c_conn;
896
897 if (!connector) {
898 SDE_ERROR("invalid connector\n");
899 return 0;
900 }
901
902 c_conn = to_sde_connector(connector);
903 if (!c_conn->ops.get_modes) {
904 SDE_DEBUG("missing get_modes callback\n");
905 return 0;
906 }
907
908 return c_conn->ops.get_modes(connector, c_conn->display);
909}
910
911static enum drm_mode_status
912sde_connector_mode_valid(struct drm_connector *connector,
913 struct drm_display_mode *mode)
914{
915 struct sde_connector *c_conn;
916
917 if (!connector || !mode) {
918 SDE_ERROR("invalid argument(s), conn %pK, mode %pK\n",
919 connector, mode);
920 return MODE_ERROR;
921 }
922
923 c_conn = to_sde_connector(connector);
924
925 if (c_conn->ops.mode_valid)
926 return c_conn->ops.mode_valid(connector, mode, c_conn->display);
927
928 /* assume all modes okay by default */
929 return MODE_OK;
930}
931
932static struct drm_encoder *
933sde_connector_best_encoder(struct drm_connector *connector)
934{
935 struct sde_connector *c_conn = to_sde_connector(connector);
936
937 if (!connector) {
938 SDE_ERROR("invalid connector\n");
939 return NULL;
940 }
941
942 /*
943 * This is true for now, revisit this code when multiple encoders are
944 * supported.
945 */
946 return c_conn->encoder;
947}
948
949static const struct drm_connector_helper_funcs sde_connector_helper_ops = {
950 .get_modes = sde_connector_get_modes,
951 .mode_valid = sde_connector_mode_valid,
952 .best_encoder = sde_connector_best_encoder,
953};
954
955struct drm_connector *sde_connector_init(struct drm_device *dev,
956 struct drm_encoder *encoder,
957 struct drm_panel *panel,
958 void *display,
959 const struct sde_connector_ops *ops,
960 int connector_poll,
961 int connector_type)
962{
963 struct msm_drm_private *priv;
964 struct sde_kms *sde_kms;
965 struct sde_kms_info *info;
966 struct sde_connector *c_conn = NULL;
Ping Li898b1bf2017-02-09 18:03:28 -0800967 struct dsi_display *dsi_display;
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400968 struct msm_display_info display_info;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400969 int rc;
970
971 if (!dev || !dev->dev_private || !encoder) {
972 SDE_ERROR("invalid argument(s), dev %pK, enc %pK\n",
973 dev, encoder);
974 return ERR_PTR(-EINVAL);
975 }
976
977 priv = dev->dev_private;
978 if (!priv->kms) {
979 SDE_ERROR("invalid kms reference\n");
980 return ERR_PTR(-EINVAL);
981 }
982
983 c_conn = kzalloc(sizeof(*c_conn), GFP_KERNEL);
984 if (!c_conn) {
985 SDE_ERROR("failed to alloc sde connector\n");
986 return ERR_PTR(-ENOMEM);
987 }
988
989 rc = drm_connector_init(dev,
990 &c_conn->base,
991 &sde_connector_ops,
992 connector_type);
993 if (rc)
994 goto error_free_conn;
995
Clarence Ipa18d4832017-03-13 12:35:44 -0700996 spin_lock_init(&c_conn->event_lock);
997
Clarence Ipdd8021c2016-07-20 16:39:47 -0400998 c_conn->connector_type = connector_type;
999 c_conn->encoder = encoder;
1000 c_conn->panel = panel;
1001 c_conn->display = display;
1002
Clarence Ip90b282d2017-05-04 10:00:32 -07001003 c_conn->dpms_mode = DRM_MODE_DPMS_ON;
1004 c_conn->lp_mode = 0;
1005 c_conn->last_panel_power_mode = SDE_MODE_DPMS_ON;
1006
Alan Kwongdfa8c082016-07-29 04:10:00 -04001007 /* cache mmu_id's for later */
Clarence Ipdd8021c2016-07-20 16:39:47 -04001008 sde_kms = to_sde_kms(priv->kms);
Alan Kwongdfa8c082016-07-29 04:10:00 -04001009 if (sde_kms->vbif[VBIF_NRT]) {
1010 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] =
1011 sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_UNSECURE];
1012 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE] =
1013 sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_SECURE];
1014 } else {
1015 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] =
1016 sde_kms->mmu_id[MSM_SMMU_DOMAIN_UNSECURE];
1017 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE] =
1018 sde_kms->mmu_id[MSM_SMMU_DOMAIN_SECURE];
1019 }
Clarence Ipdd8021c2016-07-20 16:39:47 -04001020
1021 if (ops)
1022 c_conn->ops = *ops;
1023
1024 c_conn->base.helper_private = &sde_connector_helper_ops;
1025 c_conn->base.polled = connector_poll;
1026 c_conn->base.interlace_allowed = 0;
1027 c_conn->base.doublescan_allowed = 0;
1028
1029 snprintf(c_conn->name,
1030 SDE_CONNECTOR_NAME_SIZE,
1031 "conn%u",
1032 c_conn->base.base.id);
1033
Lloyd Atkinson5d40d312016-09-06 08:34:13 -04001034 rc = sde_fence_init(&c_conn->retire_fence, c_conn->name,
1035 c_conn->base.base.id);
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001036 if (rc) {
1037 SDE_ERROR("failed to init fence, %d\n", rc);
1038 goto error_cleanup_conn;
1039 }
1040
Clarence Ip90b282d2017-05-04 10:00:32 -07001041 mutex_init(&c_conn->lock);
1042
Clarence Ipdd8021c2016-07-20 16:39:47 -04001043 rc = drm_mode_connector_attach_encoder(&c_conn->base, encoder);
1044 if (rc) {
1045 SDE_ERROR("failed to attach encoder to connector, %d\n", rc);
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -08001046 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -04001047 }
1048
Shashank Babu Chinta Venkata06c428e2017-04-17 13:52:28 -07001049 rc = sde_backlight_setup(c_conn, dev);
Dhaval Patel7cdd6662017-03-08 13:10:37 -08001050 if (rc) {
1051 SDE_ERROR("failed to setup backlight, rc=%d\n", rc);
1052 goto error_cleanup_fence;
Vishnuvardhan Prodduturi75b96802016-10-17 18:45:55 +05301053 }
1054
Clarence Ipdd8021c2016-07-20 16:39:47 -04001055 /* create properties */
1056 msm_property_init(&c_conn->property_info, &c_conn->base.base, dev,
1057 priv->conn_property, c_conn->property_data,
1058 CONNECTOR_PROP_COUNT, CONNECTOR_PROP_BLOBCOUNT,
1059 sizeof(struct sde_connector_state));
1060
1061 if (c_conn->ops.post_init) {
1062 info = kmalloc(sizeof(*info), GFP_KERNEL);
1063 if (!info) {
1064 SDE_ERROR("failed to allocate info buffer\n");
1065 rc = -ENOMEM;
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -08001066 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -04001067 }
1068
1069 sde_kms_info_reset(info);
1070 rc = c_conn->ops.post_init(&c_conn->base, info, display);
1071 if (rc) {
1072 SDE_ERROR("post-init failed, %d\n", rc);
1073 kfree(info);
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -08001074 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -04001075 }
1076
1077 msm_property_install_blob(&c_conn->property_info,
Dhaval Patel4e574842016-08-23 15:11:37 -07001078 "capabilities",
Clarence Ipdd8021c2016-07-20 16:39:47 -04001079 DRM_MODE_PROP_IMMUTABLE,
1080 CONNECTOR_PROP_SDE_INFO);
1081
1082 msm_property_set_blob(&c_conn->property_info,
Dhaval Patel4e574842016-08-23 15:11:37 -07001083 &c_conn->blob_caps,
Clarence Ipdd8021c2016-07-20 16:39:47 -04001084 SDE_KMS_INFO_DATA(info),
1085 SDE_KMS_INFO_DATALEN(info),
1086 CONNECTOR_PROP_SDE_INFO);
1087 kfree(info);
1088 }
1089
Ping Li898b1bf2017-02-09 18:03:28 -08001090 if (connector_type == DRM_MODE_CONNECTOR_DSI) {
1091 dsi_display = (struct dsi_display *)(display);
1092 if (dsi_display && dsi_display->panel &&
1093 dsi_display->panel->hdr_props.hdr_enabled == true) {
1094 msm_property_install_blob(&c_conn->property_info,
1095 "hdr_properties",
1096 DRM_MODE_PROP_IMMUTABLE,
1097 CONNECTOR_PROP_HDR_INFO);
1098
1099 msm_property_set_blob(&c_conn->property_info,
1100 &c_conn->blob_hdr,
1101 &dsi_display->panel->hdr_props,
1102 sizeof(dsi_display->panel->hdr_props),
1103 CONNECTOR_PROP_HDR_INFO);
1104 }
1105 }
1106
Lloyd Atkinson8ba47032017-03-22 17:13:32 -04001107 rc = sde_connector_get_info(&c_conn->base, &display_info);
1108 if (!rc && display_info.roi_caps.enabled) {
1109 msm_property_install_volatile_range(
1110 &c_conn->property_info, "sde_drm_roi_v1", 0x0,
1111 0, ~0, 0, CONNECTOR_PROP_ROI_V1);
1112 }
1113
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001114 msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE",
Dhaval Patel4e574842016-08-23 15:11:37 -07001115 0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE);
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001116
Lloyd Atkinson77382202017-02-01 14:59:43 -05001117 msm_property_install_range(&c_conn->property_info, "autorefresh",
1118 0x0, 0, AUTOREFRESH_MAX_FRAME_CNT, 0,
1119 CONNECTOR_PROP_AUTOREFRESH);
1120
Lloyd Atkinsonb6191972016-08-10 18:31:46 -04001121 /* enum/bitmask properties */
1122 msm_property_install_enum(&c_conn->property_info, "topology_name",
1123 DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name,
1124 ARRAY_SIZE(e_topology_name),
1125 CONNECTOR_PROP_TOPOLOGY_NAME);
1126 msm_property_install_enum(&c_conn->property_info, "topology_control",
1127 0, 1, e_topology_control,
1128 ARRAY_SIZE(e_topology_control),
1129 CONNECTOR_PROP_TOPOLOGY_CONTROL);
Clarence Ip90b282d2017-05-04 10:00:32 -07001130 msm_property_install_enum(&c_conn->property_info, "LP",
1131 0, 0, e_power_mode,
1132 ARRAY_SIZE(e_power_mode),
1133 CONNECTOR_PROP_LP);
Lloyd Atkinsonb6191972016-08-10 18:31:46 -04001134
Clarence Ipdd8021c2016-07-20 16:39:47 -04001135 rc = msm_property_install_get_status(&c_conn->property_info);
1136 if (rc) {
1137 SDE_ERROR("failed to create one or more properties\n");
1138 goto error_destroy_property;
1139 }
1140
Lloyd Atkinsonb6191972016-08-10 18:31:46 -04001141 SDE_DEBUG("connector %d attach encoder %d\n",
1142 c_conn->base.base.id, encoder->base.id);
1143
Clarence Ipdd8021c2016-07-20 16:39:47 -04001144 priv->connectors[priv->num_connectors++] = &c_conn->base;
1145
1146 return &c_conn->base;
1147
1148error_destroy_property:
Dhaval Patel4e574842016-08-23 15:11:37 -07001149 if (c_conn->blob_caps)
1150 drm_property_unreference_blob(c_conn->blob_caps);
Ping Li898b1bf2017-02-09 18:03:28 -08001151 if (c_conn->blob_hdr)
1152 drm_property_unreference_blob(c_conn->blob_hdr);
Clarence Ipdd8021c2016-07-20 16:39:47 -04001153 msm_property_destroy(&c_conn->property_info);
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001154error_cleanup_fence:
Clarence Ip90b282d2017-05-04 10:00:32 -07001155 mutex_destroy(&c_conn->lock);
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001156 sde_fence_deinit(&c_conn->retire_fence);
Clarence Ipdd8021c2016-07-20 16:39:47 -04001157error_cleanup_conn:
1158 drm_connector_cleanup(&c_conn->base);
1159error_free_conn:
1160 kfree(c_conn);
1161
1162 return ERR_PTR(rc);
1163}
Gopikrishnaiah Anandande2c81b2017-03-15 12:41:29 -07001164
1165int sde_connector_register_custom_event(struct sde_kms *kms,
1166 struct drm_connector *conn_drm, u32 event, bool val)
1167{
1168 return -EINVAL;
1169}