blob: 905ad937c96fe0c506f45cc169b093b0a44f8b8b [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[] = {
34 {SDE_RM_TOPOLOGY_UNKNOWN, "sde_unknown"},
35 {SDE_RM_TOPOLOGY_SINGLEPIPE, "sde_singlepipe"},
36 {SDE_RM_TOPOLOGY_DUALPIPE, "sde_dualpipe"},
37 {SDE_RM_TOPOLOGY_PPSPLIT, "sde_ppsplit"},
38 {SDE_RM_TOPOLOGY_DUALPIPEMERGE, "sde_dualpipemerge"}
39};
40static const struct drm_prop_enum_list e_topology_control[] = {
41 {SDE_RM_TOPCTL_RESERVE_LOCK, "reserve_lock"},
42 {SDE_RM_TOPCTL_RESERVE_CLEAR, "reserve_clear"},
43 {SDE_RM_TOPCTL_DSPP, "dspp"},
44 {SDE_RM_TOPCTL_FORCE_TILING, "force_tiling"},
45 {SDE_RM_TOPCTL_PPSPLIT, "ppsplit"}
46};
Clarence Ip90b282d2017-05-04 10:00:32 -070047static const struct drm_prop_enum_list e_power_mode[] = {
48 {SDE_MODE_DPMS_ON, "ON"},
49 {SDE_MODE_DPMS_LP1, "LP1"},
50 {SDE_MODE_DPMS_LP2, "LP2"},
51 {SDE_MODE_DPMS_OFF, "OFF"},
52};
Lloyd Atkinsonb6191972016-08-10 18:31:46 -040053
Dhaval Patel7cdd6662017-03-08 13:10:37 -080054static int sde_backlight_device_update_status(struct backlight_device *bd)
55{
56 int brightness;
57 struct dsi_display *display;
58 struct sde_connector *c_conn;
59 int bl_lvl;
Gopikrishnaiah Anandan84b4f672017-04-26 10:28:51 -070060 struct drm_event event;
Dhaval Patel7cdd6662017-03-08 13:10:37 -080061
62 brightness = bd->props.brightness;
63
64 if ((bd->props.power != FB_BLANK_UNBLANK) ||
65 (bd->props.state & BL_CORE_FBBLANK) ||
66 (bd->props.state & BL_CORE_SUSPENDED))
67 brightness = 0;
68
69 c_conn = bl_get_data(bd);
70 display = (struct dsi_display *) c_conn->display;
71 if (brightness > display->panel->bl_config.bl_max_level)
72 brightness = display->panel->bl_config.bl_max_level;
73
74 /* map UI brightness into driver backlight level with rounding */
75 bl_lvl = mult_frac(brightness, display->panel->bl_config.bl_max_level,
76 display->panel->bl_config.brightness_max_level);
77
78 if (!bl_lvl && brightness)
79 bl_lvl = 1;
80
Gopikrishnaiah Anandan84b4f672017-04-26 10:28:51 -070081 if (c_conn->ops.set_backlight) {
82 event.type = DRM_EVENT_SYS_BACKLIGHT;
83 event.length = sizeof(u32);
84 msm_mode_object_event_nofity(&c_conn->base.base,
85 c_conn->base.dev, &event, (u8 *)&brightness);
Dhaval Patel7cdd6662017-03-08 13:10:37 -080086 c_conn->ops.set_backlight(c_conn->display, bl_lvl);
Gopikrishnaiah Anandan84b4f672017-04-26 10:28:51 -070087 }
Dhaval Patel7cdd6662017-03-08 13:10:37 -080088
89 return 0;
90}
91
92static int sde_backlight_device_get_brightness(struct backlight_device *bd)
93{
94 return 0;
95}
96
97static const struct backlight_ops sde_backlight_device_ops = {
98 .update_status = sde_backlight_device_update_status,
99 .get_brightness = sde_backlight_device_get_brightness,
100};
101
Shashank Babu Chinta Venkata06c428e2017-04-17 13:52:28 -0700102static int sde_backlight_setup(struct sde_connector *c_conn,
103 struct drm_device *dev)
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800104{
105 struct backlight_device *bl_device;
106 struct backlight_properties props;
107 struct dsi_display *display;
108 struct dsi_backlight_config *bl_config;
109 static int display_count;
110 char bl_node_name[BL_NODE_NAME_SIZE];
111
Shashank Babu Chinta Venkata06c428e2017-04-17 13:52:28 -0700112 if (!c_conn || !dev || !dev->dev) {
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800113 SDE_ERROR("invalid param\n");
114 return -EINVAL;
115 } else if (c_conn->connector_type != DRM_MODE_CONNECTOR_DSI) {
116 return 0;
117 }
118
119 memset(&props, 0, sizeof(props));
120 props.type = BACKLIGHT_RAW;
121 props.power = FB_BLANK_UNBLANK;
122
123 display = (struct dsi_display *) c_conn->display;
124 bl_config = &display->panel->bl_config;
125 props.max_brightness = bl_config->brightness_max_level;
126 props.brightness = bl_config->brightness_max_level;
127 snprintf(bl_node_name, BL_NODE_NAME_SIZE, "panel%u-backlight",
128 display_count);
Shashank Babu Chinta Venkata06c428e2017-04-17 13:52:28 -0700129 bl_device = backlight_device_register(bl_node_name, dev->dev,
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800130 c_conn, &sde_backlight_device_ops, &props);
131 if (IS_ERR_OR_NULL(bl_device)) {
132 SDE_ERROR("Failed to register backlight: %ld\n",
133 PTR_ERR(bl_device));
134 return -ENODEV;
135 }
136 display_count++;
137
138 return 0;
139}
140
Clarence Ipa18d4832017-03-13 12:35:44 -0700141int sde_connector_trigger_event(void *drm_connector,
142 uint32_t event_idx, uint32_t instance_idx,
143 uint32_t data0, uint32_t data1,
144 uint32_t data2, uint32_t data3)
145{
146 struct sde_connector *c_conn;
147 unsigned long irq_flags;
148 void (*cb_func)(uint32_t event_idx,
149 uint32_t instance_idx, void *usr,
150 uint32_t data0, uint32_t data1,
151 uint32_t data2, uint32_t data3);
152 void *usr;
153 int rc = 0;
154
155 /*
156 * This function may potentially be called from an ISR context, so
157 * avoid excessive logging/etc.
158 */
159 if (!drm_connector)
160 return -EINVAL;
161 else if (event_idx >= SDE_CONN_EVENT_COUNT)
162 return -EINVAL;
163 c_conn = to_sde_connector(drm_connector);
164
165 spin_lock_irqsave(&c_conn->event_lock, irq_flags);
166 cb_func = c_conn->event_table[event_idx].cb_func;
167 usr = c_conn->event_table[event_idx].usr;
168 spin_unlock_irqrestore(&c_conn->event_lock, irq_flags);
169
170 if (cb_func)
171 cb_func(event_idx, instance_idx, usr,
172 data0, data1, data2, data3);
173 else
174 rc = -EAGAIN;
175
176 return rc;
177}
178
179int sde_connector_register_event(struct drm_connector *connector,
180 uint32_t event_idx,
181 void (*cb_func)(uint32_t event_idx,
182 uint32_t instance_idx, void *usr,
183 uint32_t data0, uint32_t data1,
184 uint32_t data2, uint32_t data3),
185 void *usr)
186{
187 struct sde_connector *c_conn;
188 unsigned long irq_flags;
189
190 if (!connector) {
191 SDE_ERROR("invalid connector\n");
192 return -EINVAL;
193 } else if (event_idx >= SDE_CONN_EVENT_COUNT) {
194 SDE_ERROR("conn%d, invalid event %d\n",
195 connector->base.id, event_idx);
196 return -EINVAL;
197 }
198 c_conn = to_sde_connector(connector);
199
200 spin_lock_irqsave(&c_conn->event_lock, irq_flags);
201 c_conn->event_table[event_idx].cb_func = cb_func;
202 c_conn->event_table[event_idx].usr = usr;
203 spin_unlock_irqrestore(&c_conn->event_lock, irq_flags);
204
205 /* optionally notify display of event registration */
206 if (c_conn->ops.enable_event && c_conn->display)
207 c_conn->ops.enable_event(connector, event_idx,
208 cb_func != NULL, c_conn->display);
209 return 0;
210}
211
212void sde_connector_unregister_event(struct drm_connector *connector,
213 uint32_t event_idx)
214{
215 (void)sde_connector_register_event(connector, event_idx, 0, 0);
216}
217
Clarence Ipcb3afd42016-07-15 16:25:34 -0400218int sde_connector_get_info(struct drm_connector *connector,
219 struct msm_display_info *info)
220{
221 struct sde_connector *c_conn;
222
223 if (!connector || !info) {
224 SDE_ERROR("invalid argument(s), conn %pK, info %pK\n",
225 connector, info);
226 return -EINVAL;
227 }
228
229 c_conn = to_sde_connector(connector);
230
231 if (!c_conn->display || !c_conn->ops.get_info) {
232 SDE_ERROR("display info not supported for %pK\n",
233 c_conn->display);
234 return -EINVAL;
235 }
236
237 return c_conn->ops.get_info(info, c_conn->display);
238}
239
Lloyd Atkinson05d75512017-01-17 14:45:51 -0500240int sde_connector_pre_kickoff(struct drm_connector *connector)
241{
242 struct sde_connector *c_conn;
243 struct sde_connector_state *c_state;
244 struct msm_display_kickoff_params params;
245 int rc;
246
247 if (!connector) {
248 SDE_ERROR("invalid argument\n");
249 return -EINVAL;
250 }
251
252 c_conn = to_sde_connector(connector);
253 c_state = to_sde_connector_state(connector->state);
254
255 if (!c_conn->display) {
256 SDE_ERROR("invalid argument\n");
257 return -EINVAL;
258 }
259
260 if (!c_conn->ops.pre_kickoff)
261 return 0;
262
263 params.rois = &c_state->rois;
264
265 SDE_EVT32_VERBOSE(connector->base.id);
266
267 rc = c_conn->ops.pre_kickoff(connector, c_conn->display, &params);
268
269 return rc;
270}
271
Veera Sundaram Sankaranbb2bf9a2017-03-29 18:56:47 -0700272void sde_connector_clk_ctrl(struct drm_connector *connector, bool enable)
273{
274 struct sde_connector *c_conn;
275 struct dsi_display *display;
276 u32 state = enable ? DSI_CLK_ON : DSI_CLK_OFF;
277
278 if (!connector) {
279 SDE_ERROR("invalid connector\n");
280 return;
281 }
282
283 c_conn = to_sde_connector(connector);
284 display = (struct dsi_display *) c_conn->display;
285
286 if (display && c_conn->ops.clk_ctrl)
287 c_conn->ops.clk_ctrl(display->mdp_clk_handle,
288 DSI_ALL_CLKS, state);
289}
290
Clarence Ipdd8021c2016-07-20 16:39:47 -0400291static void sde_connector_destroy(struct drm_connector *connector)
292{
293 struct sde_connector *c_conn;
294
295 if (!connector) {
296 SDE_ERROR("invalid connector\n");
297 return;
298 }
299
300 c_conn = to_sde_connector(connector);
301
Dhaval Patel4e574842016-08-23 15:11:37 -0700302 if (c_conn->blob_caps)
303 drm_property_unreference_blob(c_conn->blob_caps);
Ping Li898b1bf2017-02-09 18:03:28 -0800304 if (c_conn->blob_hdr)
305 drm_property_unreference_blob(c_conn->blob_hdr);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400306 msm_property_destroy(&c_conn->property_info);
307
308 drm_connector_unregister(connector);
Clarence Ip90b282d2017-05-04 10:00:32 -0700309 mutex_destroy(&c_conn->lock);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400310 sde_fence_deinit(&c_conn->retire_fence);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400311 drm_connector_cleanup(connector);
312 kfree(c_conn);
313}
314
315/**
316 * _sde_connector_destroy_fb - clean up connector state's out_fb buffer
317 * @c_conn: Pointer to sde connector structure
318 * @c_state: Pointer to sde connector state structure
319 */
320static void _sde_connector_destroy_fb(struct sde_connector *c_conn,
321 struct sde_connector_state *c_state)
322{
323 if (!c_state || !c_state->out_fb) {
324 SDE_ERROR("invalid state %pK\n", c_state);
325 return;
326 }
327
328 msm_framebuffer_cleanup(c_state->out_fb,
329 c_state->mmu_id);
330 drm_framebuffer_unreference(c_state->out_fb);
331 c_state->out_fb = NULL;
332
333 if (c_conn) {
334 c_state->property_values[CONNECTOR_PROP_OUT_FB] =
335 msm_property_get_default(&c_conn->property_info,
336 CONNECTOR_PROP_OUT_FB);
337 } else {
338 c_state->property_values[CONNECTOR_PROP_OUT_FB] = ~0;
339 }
340}
341
342static void sde_connector_atomic_destroy_state(struct drm_connector *connector,
343 struct drm_connector_state *state)
344{
345 struct sde_connector *c_conn = NULL;
346 struct sde_connector_state *c_state = NULL;
347
348 if (!state) {
349 SDE_ERROR("invalid state\n");
350 return;
351 }
352
353 /*
354 * The base DRM framework currently always passes in a NULL
355 * connector pointer. This is not correct, but attempt to
356 * handle that case as much as possible.
357 */
358 if (connector)
359 c_conn = to_sde_connector(connector);
360 c_state = to_sde_connector_state(state);
361
362 if (c_state->out_fb)
363 _sde_connector_destroy_fb(c_conn, c_state);
364
365 if (!c_conn) {
366 kfree(c_state);
367 } else {
368 /* destroy value helper */
369 msm_property_destroy_state(&c_conn->property_info, c_state,
370 c_state->property_values, 0);
371 }
372}
373
374static void sde_connector_atomic_reset(struct drm_connector *connector)
375{
376 struct sde_connector *c_conn;
377 struct sde_connector_state *c_state;
378
379 if (!connector) {
380 SDE_ERROR("invalid connector\n");
381 return;
382 }
383
384 c_conn = to_sde_connector(connector);
385
386 if (connector->state) {
387 sde_connector_atomic_destroy_state(connector, connector->state);
388 connector->state = 0;
389 }
390
391 c_state = msm_property_alloc_state(&c_conn->property_info);
392 if (!c_state) {
393 SDE_ERROR("state alloc failed\n");
394 return;
395 }
396
397 /* reset value helper, zero out state structure and reset properties */
398 msm_property_reset_state(&c_conn->property_info, c_state,
399 c_state->property_values, 0);
400
401 c_state->base.connector = connector;
402 connector->state = &c_state->base;
403}
404
405static struct drm_connector_state *
406sde_connector_atomic_duplicate_state(struct drm_connector *connector)
407{
408 struct sde_connector *c_conn;
409 struct sde_connector_state *c_state, *c_oldstate;
410 int rc;
411
412 if (!connector || !connector->state) {
413 SDE_ERROR("invalid connector %pK\n", connector);
414 return NULL;
415 }
416
417 c_conn = to_sde_connector(connector);
418 c_oldstate = to_sde_connector_state(connector->state);
419 c_state = msm_property_alloc_state(&c_conn->property_info);
420 if (!c_state) {
421 SDE_ERROR("state alloc failed\n");
422 return NULL;
423 }
424
425 /* duplicate value helper */
426 msm_property_duplicate_state(&c_conn->property_info,
427 c_oldstate, c_state, c_state->property_values, 0);
428
429 /* additional handling for drm framebuffer objects */
430 if (c_state->out_fb) {
431 drm_framebuffer_reference(c_state->out_fb);
432 rc = msm_framebuffer_prepare(c_state->out_fb,
433 c_state->mmu_id);
434 if (rc)
435 SDE_ERROR("failed to prepare fb, %d\n", rc);
436 }
437
438 return &c_state->base;
439}
440
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400441static int _sde_connector_roi_v1_check_roi(
442 struct sde_connector *c_conn,
443 struct drm_clip_rect *roi_conn,
444 const struct msm_roi_caps *caps)
445{
446 const struct msm_roi_alignment *align = &caps->align;
447 int w = roi_conn->x2 - roi_conn->x1;
448 int h = roi_conn->y2 - roi_conn->y1;
449
450 if (w <= 0 || h <= 0) {
451 SDE_ERROR_CONN(c_conn, "invalid conn roi w %d h %d\n", w, h);
452 return -EINVAL;
453 }
454
455 if (w < align->min_width || w % align->width_pix_align) {
456 SDE_ERROR_CONN(c_conn,
457 "invalid conn roi width %d min %d align %d\n",
458 w, align->min_width, align->width_pix_align);
459 return -EINVAL;
460 }
461
462 if (h < align->min_height || h % align->height_pix_align) {
463 SDE_ERROR_CONN(c_conn,
464 "invalid conn roi height %d min %d align %d\n",
465 h, align->min_height, align->height_pix_align);
466 return -EINVAL;
467 }
468
469 if (roi_conn->x1 % align->xstart_pix_align) {
470 SDE_ERROR_CONN(c_conn, "invalid conn roi x1 %d align %d\n",
471 roi_conn->x1, align->xstart_pix_align);
472 return -EINVAL;
473 }
474
475 if (roi_conn->y1 % align->ystart_pix_align) {
476 SDE_ERROR_CONN(c_conn, "invalid conn roi y1 %d align %d\n",
477 roi_conn->y1, align->ystart_pix_align);
478 return -EINVAL;
479 }
480
481 return 0;
482}
483
484static int _sde_connector_set_roi_v1(
485 struct sde_connector *c_conn,
486 struct sde_connector_state *c_state,
487 void *usr_ptr)
488{
489 struct sde_drm_roi_v1 roi_v1;
490 struct msm_display_info display_info;
491 struct msm_roi_caps *caps;
492 int i, rc;
493
494 if (!c_conn || !c_state) {
495 SDE_ERROR("invalid args\n");
496 return -EINVAL;
497 }
498
499 rc = sde_connector_get_info(&c_conn->base, &display_info);
500 if (rc) {
501 SDE_ERROR_CONN(c_conn, "display get info error: %d\n", rc);
502 return rc;
503 }
504
505 caps = &display_info.roi_caps;
506 if (!caps->enabled) {
507 SDE_ERROR_CONN(c_conn, "display roi capability is disabled\n");
508 return -ENOTSUPP;
509 }
510
511 memset(&c_state->rois, 0, sizeof(c_state->rois));
512
513 if (!usr_ptr) {
514 SDE_DEBUG_CONN(c_conn, "rois cleared\n");
515 return 0;
516 }
517
518 if (copy_from_user(&roi_v1, usr_ptr, sizeof(roi_v1))) {
519 SDE_ERROR_CONN(c_conn, "failed to copy roi_v1 data\n");
520 return -EINVAL;
521 }
522
523 SDE_DEBUG_CONN(c_conn, "num_rects %d\n", roi_v1.num_rects);
524
525 if (roi_v1.num_rects == 0) {
526 SDE_DEBUG_CONN(c_conn, "rois cleared\n");
527 return 0;
528 }
529
530 if (roi_v1.num_rects > SDE_MAX_ROI_V1 ||
531 roi_v1.num_rects > caps->num_roi) {
532 SDE_ERROR_CONN(c_conn, "too many rects specified: %d\n",
533 roi_v1.num_rects);
534 return -EINVAL;
535 }
536
537 c_state->rois.num_rects = roi_v1.num_rects;
538 for (i = 0; i < roi_v1.num_rects; ++i) {
539 int rc;
540
541 rc = _sde_connector_roi_v1_check_roi(c_conn, &roi_v1.roi[i],
542 caps);
543 if (rc)
544 return rc;
545
546 c_state->rois.roi[i] = roi_v1.roi[i];
547 SDE_DEBUG_CONN(c_conn, "roi%d: roi 0x%x 0x%x 0x%x 0x%x\n", i,
548 c_state->rois.roi[i].x1,
549 c_state->rois.roi[i].y1,
550 c_state->rois.roi[i].x2,
551 c_state->rois.roi[i].y2);
552 }
553
554 return 0;
555}
556
Clarence Ip90b282d2017-05-04 10:00:32 -0700557static int _sde_connector_update_power_locked(struct sde_connector *c_conn)
558{
559 struct drm_connector *connector;
560 void *display;
561 int (*set_power)(struct drm_connector *, int, void *);
562 int mode, rc = 0;
563
564 if (!c_conn)
565 return -EINVAL;
566 connector = &c_conn->base;
567
568 mode = c_conn->lp_mode;
569 if (c_conn->dpms_mode != DRM_MODE_DPMS_ON)
570 mode = SDE_MODE_DPMS_OFF;
571 switch (c_conn->dpms_mode) {
572 case DRM_MODE_DPMS_ON:
573 mode = c_conn->lp_mode;
574 break;
575 case DRM_MODE_DPMS_STANDBY:
576 mode = SDE_MODE_DPMS_STANDBY;
577 break;
578 case DRM_MODE_DPMS_SUSPEND:
579 mode = SDE_MODE_DPMS_SUSPEND;
580 break;
581 case DRM_MODE_DPMS_OFF:
582 mode = SDE_MODE_DPMS_OFF;
583 break;
584 default:
585 mode = c_conn->lp_mode;
586 SDE_ERROR("conn %d dpms set to unrecognized mode %d\n",
587 connector->base.id, mode);
588 break;
589 }
590
591 SDE_DEBUG("conn %d - dpms %d, lp %d, panel %d\n", connector->base.id,
592 c_conn->dpms_mode, c_conn->lp_mode, mode);
593
594 if (mode != c_conn->last_panel_power_mode && c_conn->ops.set_power) {
595 display = c_conn->display;
596 set_power = c_conn->ops.set_power;
597
598 mutex_unlock(&c_conn->lock);
599 rc = set_power(connector, mode, display);
600 mutex_lock(&c_conn->lock);
601 }
602 c_conn->last_panel_power_mode = mode;
603
604 return rc;
605}
606
Clarence Ipdd8021c2016-07-20 16:39:47 -0400607static int sde_connector_atomic_set_property(struct drm_connector *connector,
608 struct drm_connector_state *state,
609 struct drm_property *property,
610 uint64_t val)
611{
612 struct sde_connector *c_conn;
613 struct sde_connector_state *c_state;
614 int idx, rc;
615
616 if (!connector || !state || !property) {
617 SDE_ERROR("invalid argument(s), conn %pK, state %pK, prp %pK\n",
618 connector, state, property);
619 return -EINVAL;
620 }
621
622 c_conn = to_sde_connector(connector);
623 c_state = to_sde_connector_state(state);
624
625 /* generic property handling */
626 rc = msm_property_atomic_set(&c_conn->property_info,
627 c_state->property_values, 0, property, val);
628 if (rc)
629 goto end;
630
631 /* connector-specific property handling */
632 idx = msm_property_index(&c_conn->property_info, property);
Clarence Ip90b282d2017-05-04 10:00:32 -0700633 switch (idx) {
634 case CONNECTOR_PROP_OUT_FB:
Clarence Ipdd8021c2016-07-20 16:39:47 -0400635 /* clear old fb, if present */
636 if (c_state->out_fb)
637 _sde_connector_destroy_fb(c_conn, c_state);
638
639 /* convert fb val to drm framebuffer and prepare it */
640 c_state->out_fb =
641 drm_framebuffer_lookup(connector->dev, val);
Alan Kwongae1b1142017-03-05 16:07:10 -0800642 if (!c_state->out_fb && val) {
Clarence Ipdd8021c2016-07-20 16:39:47 -0400643 SDE_ERROR("failed to look up fb %lld\n", val);
644 rc = -EFAULT;
Alan Kwongae1b1142017-03-05 16:07:10 -0800645 } else if (!c_state->out_fb && !val) {
646 SDE_DEBUG("cleared fb_id\n");
647 rc = 0;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400648 } else {
Alan Kwong578cdaf2017-01-28 17:25:43 -0800649 msm_framebuffer_set_kmap(c_state->out_fb,
650 c_conn->fb_kmap);
651
Alan Kwongdfa8c082016-07-29 04:10:00 -0400652 if (c_state->out_fb->flags & DRM_MODE_FB_SECURE)
653 c_state->mmu_id =
654 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE];
655 else
656 c_state->mmu_id =
657 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE];
Clarence Ipdd8021c2016-07-20 16:39:47 -0400658
659 rc = msm_framebuffer_prepare(c_state->out_fb,
660 c_state->mmu_id);
661 if (rc)
662 SDE_ERROR("prep fb failed, %d\n", rc);
663 }
Clarence Ip90b282d2017-05-04 10:00:32 -0700664 break;
665 case CONNECTOR_PROP_TOPOLOGY_CONTROL:
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400666 rc = sde_rm_check_property_topctl(val);
667 if (rc)
668 SDE_ERROR("invalid topology_control: 0x%llX\n", val);
Clarence Ip90b282d2017-05-04 10:00:32 -0700669 break;
670 case CONNECTOR_PROP_LP:
671 mutex_lock(&c_conn->lock);
672 c_conn->lp_mode = val;
673 _sde_connector_update_power_locked(c_conn);
674 mutex_unlock(&c_conn->lock);
675 break;
676 default:
677 break;
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400678 }
679
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400680 if (idx == CONNECTOR_PROP_ROI_V1) {
681 rc = _sde_connector_set_roi_v1(c_conn, c_state, (void *)val);
682 if (rc)
683 SDE_ERROR_CONN(c_conn, "invalid roi_v1, rc: %d\n", rc);
684 }
685
Clarence Ipdd8021c2016-07-20 16:39:47 -0400686 /* check for custom property handling */
687 if (!rc && c_conn->ops.set_property) {
688 rc = c_conn->ops.set_property(connector,
689 state,
690 idx,
691 val,
692 c_conn->display);
693
694 /* potentially clean up out_fb if rc != 0 */
695 if ((idx == CONNECTOR_PROP_OUT_FB) && rc)
696 _sde_connector_destroy_fb(c_conn, c_state);
697 }
698end:
699 return rc;
700}
701
702static int sde_connector_set_property(struct drm_connector *connector,
703 struct drm_property *property,
704 uint64_t val)
705{
706 if (!connector) {
707 SDE_ERROR("invalid connector\n");
708 return -EINVAL;
709 }
710
711 return sde_connector_atomic_set_property(connector,
712 connector->state, property, val);
713}
714
715static int sde_connector_atomic_get_property(struct drm_connector *connector,
716 const struct drm_connector_state *state,
717 struct drm_property *property,
718 uint64_t *val)
719{
720 struct sde_connector *c_conn;
721 struct sde_connector_state *c_state;
722 int idx, rc = -EINVAL;
723
724 if (!connector || !state) {
725 SDE_ERROR("invalid argument(s), conn %pK, state %pK\n",
726 connector, state);
727 return -EINVAL;
728 }
729
730 c_conn = to_sde_connector(connector);
731 c_state = to_sde_connector_state(state);
732
733 idx = msm_property_index(&c_conn->property_info, property);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400734 if (idx == CONNECTOR_PROP_RETIRE_FENCE)
Dhaval Patel5cb59be2017-04-20 20:00:56 -0700735 rc = sde_fence_create(&c_conn->retire_fence, val, 0);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400736 else
737 /* get cached property value */
738 rc = msm_property_atomic_get(&c_conn->property_info,
739 c_state->property_values, 0, property, val);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400740
741 /* allow for custom override */
742 if (c_conn->ops.get_property)
743 rc = c_conn->ops.get_property(connector,
744 (struct drm_connector_state *)state,
745 idx,
746 val,
747 c_conn->display);
748 return rc;
749}
750
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400751void sde_connector_prepare_fence(struct drm_connector *connector)
752{
753 if (!connector) {
754 SDE_ERROR("invalid connector\n");
755 return;
756 }
757
758 sde_fence_prepare(&to_sde_connector(connector)->retire_fence);
759}
760
761void sde_connector_complete_commit(struct drm_connector *connector)
762{
763 if (!connector) {
764 SDE_ERROR("invalid connector\n");
765 return;
766 }
767
768 /* signal connector's retire fence */
769 sde_fence_signal(&to_sde_connector(connector)->retire_fence, 0);
770}
771
Clarence Ipdd8021c2016-07-20 16:39:47 -0400772static enum drm_connector_status
773sde_connector_detect(struct drm_connector *connector, bool force)
774{
775 enum drm_connector_status status = connector_status_unknown;
776 struct sde_connector *c_conn;
777
778 if (!connector) {
779 SDE_ERROR("invalid connector\n");
780 return status;
781 }
782
783 c_conn = to_sde_connector(connector);
784
785 if (c_conn->ops.detect)
786 status = c_conn->ops.detect(connector,
787 force,
788 c_conn->display);
789
790 return status;
791}
792
Clarence Ip90b282d2017-05-04 10:00:32 -0700793static int sde_connector_dpms(struct drm_connector *connector,
794 int mode)
795{
796 struct sde_connector *c_conn;
797
798 if (!connector) {
799 SDE_ERROR("invalid connector\n");
800 return -EINVAL;
801 }
802 c_conn = to_sde_connector(connector);
803
804 /* validate incoming dpms request */
805 switch (mode) {
806 case DRM_MODE_DPMS_ON:
807 case DRM_MODE_DPMS_STANDBY:
808 case DRM_MODE_DPMS_SUSPEND:
809 case DRM_MODE_DPMS_OFF:
810 SDE_DEBUG("conn %d dpms set to %d\n", connector->base.id, mode);
811 break;
812 default:
813 SDE_ERROR("conn %d dpms set to unrecognized mode %d\n",
814 connector->base.id, mode);
815 break;
816 }
817
818 mutex_lock(&c_conn->lock);
819 c_conn->dpms_mode = mode;
820 _sde_connector_update_power_locked(c_conn);
821 mutex_unlock(&c_conn->lock);
822
823 /* use helper for boilerplate handling */
824 return drm_atomic_helper_connector_dpms(connector, mode);
825}
826
827int sde_connector_get_dpms(struct drm_connector *connector)
828{
829 struct sde_connector *c_conn;
830 int rc;
831
832 if (!connector) {
833 SDE_DEBUG("invalid connector\n");
834 return DRM_MODE_DPMS_OFF;
835 }
836
837 c_conn = to_sde_connector(connector);
838
839 mutex_lock(&c_conn->lock);
840 rc = c_conn->dpms_mode;
841 mutex_unlock(&c_conn->lock);
842
843 return rc;
844}
845
Alan Kwong578cdaf2017-01-28 17:25:43 -0800846#ifdef CONFIG_DEBUG_FS
847/**
848 * sde_connector_init_debugfs - initialize connector debugfs
849 * @connector: Pointer to drm connector
850 */
851static int sde_connector_init_debugfs(struct drm_connector *connector)
852{
853 struct sde_connector *sde_connector;
854
855 if (!connector || !connector->debugfs_entry) {
856 SDE_ERROR("invalid connector\n");
857 return -EINVAL;
858 }
859
860 sde_connector = to_sde_connector(connector);
861
862 if (!debugfs_create_bool("fb_kmap", 0644, connector->debugfs_entry,
863 &sde_connector->fb_kmap)) {
864 SDE_ERROR("failed to create connector fb_kmap\n");
865 return -ENOMEM;
866 }
867
868 return 0;
869}
870#else
871static int sde_connector_init_debugfs(struct drm_connector *connector)
872{
873 return 0;
874}
875#endif
876
877static int sde_connector_late_register(struct drm_connector *connector)
878{
879 return sde_connector_init_debugfs(connector);
880}
881
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -0700882static void sde_connector_early_unregister(struct drm_connector *connector)
883{
884 /* debugfs under connector->debugfs are deleted by drm_debugfs */
885}
886
Clarence Ipdd8021c2016-07-20 16:39:47 -0400887static const struct drm_connector_funcs sde_connector_ops = {
Clarence Ip90b282d2017-05-04 10:00:32 -0700888 .dpms = sde_connector_dpms,
Clarence Ipdd8021c2016-07-20 16:39:47 -0400889 .reset = sde_connector_atomic_reset,
890 .detect = sde_connector_detect,
891 .destroy = sde_connector_destroy,
892 .fill_modes = drm_helper_probe_single_connector_modes,
893 .atomic_duplicate_state = sde_connector_atomic_duplicate_state,
894 .atomic_destroy_state = sde_connector_atomic_destroy_state,
895 .atomic_set_property = sde_connector_atomic_set_property,
896 .atomic_get_property = sde_connector_atomic_get_property,
897 .set_property = sde_connector_set_property,
Alan Kwong578cdaf2017-01-28 17:25:43 -0800898 .late_register = sde_connector_late_register,
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -0700899 .early_unregister = sde_connector_early_unregister,
Clarence Ipdd8021c2016-07-20 16:39:47 -0400900};
901
902static int sde_connector_get_modes(struct drm_connector *connector)
903{
904 struct sde_connector *c_conn;
905
906 if (!connector) {
907 SDE_ERROR("invalid connector\n");
908 return 0;
909 }
910
911 c_conn = to_sde_connector(connector);
912 if (!c_conn->ops.get_modes) {
913 SDE_DEBUG("missing get_modes callback\n");
914 return 0;
915 }
916
917 return c_conn->ops.get_modes(connector, c_conn->display);
918}
919
920static enum drm_mode_status
921sde_connector_mode_valid(struct drm_connector *connector,
922 struct drm_display_mode *mode)
923{
924 struct sde_connector *c_conn;
925
926 if (!connector || !mode) {
927 SDE_ERROR("invalid argument(s), conn %pK, mode %pK\n",
928 connector, mode);
929 return MODE_ERROR;
930 }
931
932 c_conn = to_sde_connector(connector);
933
934 if (c_conn->ops.mode_valid)
935 return c_conn->ops.mode_valid(connector, mode, c_conn->display);
936
937 /* assume all modes okay by default */
938 return MODE_OK;
939}
940
941static struct drm_encoder *
942sde_connector_best_encoder(struct drm_connector *connector)
943{
944 struct sde_connector *c_conn = to_sde_connector(connector);
945
946 if (!connector) {
947 SDE_ERROR("invalid connector\n");
948 return NULL;
949 }
950
951 /*
952 * This is true for now, revisit this code when multiple encoders are
953 * supported.
954 */
955 return c_conn->encoder;
956}
957
958static const struct drm_connector_helper_funcs sde_connector_helper_ops = {
959 .get_modes = sde_connector_get_modes,
960 .mode_valid = sde_connector_mode_valid,
961 .best_encoder = sde_connector_best_encoder,
962};
963
964struct drm_connector *sde_connector_init(struct drm_device *dev,
965 struct drm_encoder *encoder,
966 struct drm_panel *panel,
967 void *display,
968 const struct sde_connector_ops *ops,
969 int connector_poll,
970 int connector_type)
971{
972 struct msm_drm_private *priv;
973 struct sde_kms *sde_kms;
974 struct sde_kms_info *info;
975 struct sde_connector *c_conn = NULL;
Ping Li898b1bf2017-02-09 18:03:28 -0800976 struct dsi_display *dsi_display;
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400977 struct msm_display_info display_info;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400978 int rc;
979
980 if (!dev || !dev->dev_private || !encoder) {
981 SDE_ERROR("invalid argument(s), dev %pK, enc %pK\n",
982 dev, encoder);
983 return ERR_PTR(-EINVAL);
984 }
985
986 priv = dev->dev_private;
987 if (!priv->kms) {
988 SDE_ERROR("invalid kms reference\n");
989 return ERR_PTR(-EINVAL);
990 }
991
992 c_conn = kzalloc(sizeof(*c_conn), GFP_KERNEL);
993 if (!c_conn) {
994 SDE_ERROR("failed to alloc sde connector\n");
995 return ERR_PTR(-ENOMEM);
996 }
997
998 rc = drm_connector_init(dev,
999 &c_conn->base,
1000 &sde_connector_ops,
1001 connector_type);
1002 if (rc)
1003 goto error_free_conn;
1004
Clarence Ipa18d4832017-03-13 12:35:44 -07001005 spin_lock_init(&c_conn->event_lock);
1006
Clarence Ipdd8021c2016-07-20 16:39:47 -04001007 c_conn->connector_type = connector_type;
1008 c_conn->encoder = encoder;
1009 c_conn->panel = panel;
1010 c_conn->display = display;
1011
Clarence Ip90b282d2017-05-04 10:00:32 -07001012 c_conn->dpms_mode = DRM_MODE_DPMS_ON;
1013 c_conn->lp_mode = 0;
1014 c_conn->last_panel_power_mode = SDE_MODE_DPMS_ON;
1015
Alan Kwongdfa8c082016-07-29 04:10:00 -04001016 /* cache mmu_id's for later */
Clarence Ipdd8021c2016-07-20 16:39:47 -04001017 sde_kms = to_sde_kms(priv->kms);
Alan Kwongdfa8c082016-07-29 04:10:00 -04001018 if (sde_kms->vbif[VBIF_NRT]) {
1019 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] =
1020 sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_UNSECURE];
1021 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE] =
1022 sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_SECURE];
1023 } else {
1024 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] =
1025 sde_kms->mmu_id[MSM_SMMU_DOMAIN_UNSECURE];
1026 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE] =
1027 sde_kms->mmu_id[MSM_SMMU_DOMAIN_SECURE];
1028 }
Clarence Ipdd8021c2016-07-20 16:39:47 -04001029
1030 if (ops)
1031 c_conn->ops = *ops;
1032
1033 c_conn->base.helper_private = &sde_connector_helper_ops;
1034 c_conn->base.polled = connector_poll;
1035 c_conn->base.interlace_allowed = 0;
1036 c_conn->base.doublescan_allowed = 0;
1037
1038 snprintf(c_conn->name,
1039 SDE_CONNECTOR_NAME_SIZE,
1040 "conn%u",
1041 c_conn->base.base.id);
1042
Lloyd Atkinson5d40d312016-09-06 08:34:13 -04001043 rc = sde_fence_init(&c_conn->retire_fence, c_conn->name,
1044 c_conn->base.base.id);
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001045 if (rc) {
1046 SDE_ERROR("failed to init fence, %d\n", rc);
1047 goto error_cleanup_conn;
1048 }
1049
Clarence Ip90b282d2017-05-04 10:00:32 -07001050 mutex_init(&c_conn->lock);
1051
Clarence Ipdd8021c2016-07-20 16:39:47 -04001052 rc = drm_mode_connector_attach_encoder(&c_conn->base, encoder);
1053 if (rc) {
1054 SDE_ERROR("failed to attach encoder to connector, %d\n", rc);
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -08001055 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -04001056 }
1057
Shashank Babu Chinta Venkata06c428e2017-04-17 13:52:28 -07001058 rc = sde_backlight_setup(c_conn, dev);
Dhaval Patel7cdd6662017-03-08 13:10:37 -08001059 if (rc) {
1060 SDE_ERROR("failed to setup backlight, rc=%d\n", rc);
1061 goto error_cleanup_fence;
Vishnuvardhan Prodduturi75b96802016-10-17 18:45:55 +05301062 }
1063
Clarence Ipdd8021c2016-07-20 16:39:47 -04001064 /* create properties */
1065 msm_property_init(&c_conn->property_info, &c_conn->base.base, dev,
1066 priv->conn_property, c_conn->property_data,
1067 CONNECTOR_PROP_COUNT, CONNECTOR_PROP_BLOBCOUNT,
1068 sizeof(struct sde_connector_state));
1069
1070 if (c_conn->ops.post_init) {
1071 info = kmalloc(sizeof(*info), GFP_KERNEL);
1072 if (!info) {
1073 SDE_ERROR("failed to allocate info buffer\n");
1074 rc = -ENOMEM;
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -08001075 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -04001076 }
1077
1078 sde_kms_info_reset(info);
1079 rc = c_conn->ops.post_init(&c_conn->base, info, display);
1080 if (rc) {
1081 SDE_ERROR("post-init failed, %d\n", rc);
1082 kfree(info);
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -08001083 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -04001084 }
1085
1086 msm_property_install_blob(&c_conn->property_info,
Dhaval Patel4e574842016-08-23 15:11:37 -07001087 "capabilities",
Clarence Ipdd8021c2016-07-20 16:39:47 -04001088 DRM_MODE_PROP_IMMUTABLE,
1089 CONNECTOR_PROP_SDE_INFO);
1090
1091 msm_property_set_blob(&c_conn->property_info,
Dhaval Patel4e574842016-08-23 15:11:37 -07001092 &c_conn->blob_caps,
Clarence Ipdd8021c2016-07-20 16:39:47 -04001093 SDE_KMS_INFO_DATA(info),
1094 SDE_KMS_INFO_DATALEN(info),
1095 CONNECTOR_PROP_SDE_INFO);
1096 kfree(info);
1097 }
1098
Ping Li898b1bf2017-02-09 18:03:28 -08001099 if (connector_type == DRM_MODE_CONNECTOR_DSI) {
1100 dsi_display = (struct dsi_display *)(display);
1101 if (dsi_display && dsi_display->panel &&
1102 dsi_display->panel->hdr_props.hdr_enabled == true) {
1103 msm_property_install_blob(&c_conn->property_info,
1104 "hdr_properties",
1105 DRM_MODE_PROP_IMMUTABLE,
1106 CONNECTOR_PROP_HDR_INFO);
1107
1108 msm_property_set_blob(&c_conn->property_info,
1109 &c_conn->blob_hdr,
1110 &dsi_display->panel->hdr_props,
1111 sizeof(dsi_display->panel->hdr_props),
1112 CONNECTOR_PROP_HDR_INFO);
1113 }
1114 }
1115
Lloyd Atkinson8ba47032017-03-22 17:13:32 -04001116 rc = sde_connector_get_info(&c_conn->base, &display_info);
1117 if (!rc && display_info.roi_caps.enabled) {
1118 msm_property_install_volatile_range(
1119 &c_conn->property_info, "sde_drm_roi_v1", 0x0,
1120 0, ~0, 0, CONNECTOR_PROP_ROI_V1);
1121 }
1122
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001123 msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE",
Dhaval Patel4e574842016-08-23 15:11:37 -07001124 0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE);
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001125
Lloyd Atkinson77382202017-02-01 14:59:43 -05001126 msm_property_install_range(&c_conn->property_info, "autorefresh",
1127 0x0, 0, AUTOREFRESH_MAX_FRAME_CNT, 0,
1128 CONNECTOR_PROP_AUTOREFRESH);
1129
Lloyd Atkinsonb6191972016-08-10 18:31:46 -04001130 /* enum/bitmask properties */
1131 msm_property_install_enum(&c_conn->property_info, "topology_name",
1132 DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name,
1133 ARRAY_SIZE(e_topology_name),
1134 CONNECTOR_PROP_TOPOLOGY_NAME);
1135 msm_property_install_enum(&c_conn->property_info, "topology_control",
1136 0, 1, e_topology_control,
1137 ARRAY_SIZE(e_topology_control),
1138 CONNECTOR_PROP_TOPOLOGY_CONTROL);
Clarence Ip90b282d2017-05-04 10:00:32 -07001139 msm_property_install_enum(&c_conn->property_info, "LP",
1140 0, 0, e_power_mode,
1141 ARRAY_SIZE(e_power_mode),
1142 CONNECTOR_PROP_LP);
Lloyd Atkinsonb6191972016-08-10 18:31:46 -04001143
Clarence Ipdd8021c2016-07-20 16:39:47 -04001144 rc = msm_property_install_get_status(&c_conn->property_info);
1145 if (rc) {
1146 SDE_ERROR("failed to create one or more properties\n");
1147 goto error_destroy_property;
1148 }
1149
Lloyd Atkinsonb6191972016-08-10 18:31:46 -04001150 SDE_DEBUG("connector %d attach encoder %d\n",
1151 c_conn->base.base.id, encoder->base.id);
1152
Clarence Ipdd8021c2016-07-20 16:39:47 -04001153 priv->connectors[priv->num_connectors++] = &c_conn->base;
1154
1155 return &c_conn->base;
1156
1157error_destroy_property:
Dhaval Patel4e574842016-08-23 15:11:37 -07001158 if (c_conn->blob_caps)
1159 drm_property_unreference_blob(c_conn->blob_caps);
Ping Li898b1bf2017-02-09 18:03:28 -08001160 if (c_conn->blob_hdr)
1161 drm_property_unreference_blob(c_conn->blob_hdr);
Clarence Ipdd8021c2016-07-20 16:39:47 -04001162 msm_property_destroy(&c_conn->property_info);
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001163error_cleanup_fence:
Clarence Ip90b282d2017-05-04 10:00:32 -07001164 mutex_destroy(&c_conn->lock);
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001165 sde_fence_deinit(&c_conn->retire_fence);
Clarence Ipdd8021c2016-07-20 16:39:47 -04001166error_cleanup_conn:
1167 drm_connector_cleanup(&c_conn->base);
1168error_free_conn:
1169 kfree(c_conn);
1170
1171 return ERR_PTR(rc);
1172}
Gopikrishnaiah Anandande2c81b2017-03-15 12:41:29 -07001173
1174int sde_connector_register_custom_event(struct sde_kms *kms,
1175 struct drm_connector *conn_drm, u32 event, bool val)
1176{
Gopikrishnaiah Anandan84b4f672017-04-26 10:28:51 -07001177 int ret = -EINVAL;
1178
1179 switch (event) {
1180 case DRM_EVENT_SYS_BACKLIGHT:
1181 ret = 0;
1182 break;
1183 default:
1184 break;
1185 }
1186 return ret;
Gopikrishnaiah Anandande2c81b2017-03-15 12:41:29 -07001187}