blob: f13c6c9297232e97512483268bde7457e7db09d5 [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;
Gopikrishnaiah Anandan84b4f672017-04-26 10:28:51 -070062 struct drm_event event;
Dhaval Patel7cdd6662017-03-08 13:10:37 -080063
64 brightness = bd->props.brightness;
65
66 if ((bd->props.power != FB_BLANK_UNBLANK) ||
67 (bd->props.state & BL_CORE_FBBLANK) ||
68 (bd->props.state & BL_CORE_SUSPENDED))
69 brightness = 0;
70
71 c_conn = bl_get_data(bd);
72 display = (struct dsi_display *) c_conn->display;
73 if (brightness > display->panel->bl_config.bl_max_level)
74 brightness = display->panel->bl_config.bl_max_level;
75
76 /* map UI brightness into driver backlight level with rounding */
77 bl_lvl = mult_frac(brightness, display->panel->bl_config.bl_max_level,
78 display->panel->bl_config.brightness_max_level);
79
80 if (!bl_lvl && brightness)
81 bl_lvl = 1;
82
Gopikrishnaiah Anandan84b4f672017-04-26 10:28:51 -070083 if (c_conn->ops.set_backlight) {
84 event.type = DRM_EVENT_SYS_BACKLIGHT;
85 event.length = sizeof(u32);
86 msm_mode_object_event_nofity(&c_conn->base.base,
87 c_conn->base.dev, &event, (u8 *)&brightness);
Dhaval Patel7cdd6662017-03-08 13:10:37 -080088 c_conn->ops.set_backlight(c_conn->display, bl_lvl);
Gopikrishnaiah Anandan84b4f672017-04-26 10:28:51 -070089 }
Dhaval Patel7cdd6662017-03-08 13:10:37 -080090
91 return 0;
92}
93
94static int sde_backlight_device_get_brightness(struct backlight_device *bd)
95{
96 return 0;
97}
98
99static const struct backlight_ops sde_backlight_device_ops = {
100 .update_status = sde_backlight_device_update_status,
101 .get_brightness = sde_backlight_device_get_brightness,
102};
103
Shashank Babu Chinta Venkata06c428e2017-04-17 13:52:28 -0700104static int sde_backlight_setup(struct sde_connector *c_conn,
105 struct drm_device *dev)
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800106{
107 struct backlight_device *bl_device;
108 struct backlight_properties props;
109 struct dsi_display *display;
110 struct dsi_backlight_config *bl_config;
111 static int display_count;
112 char bl_node_name[BL_NODE_NAME_SIZE];
113
Shashank Babu Chinta Venkata06c428e2017-04-17 13:52:28 -0700114 if (!c_conn || !dev || !dev->dev) {
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800115 SDE_ERROR("invalid param\n");
116 return -EINVAL;
117 } else if (c_conn->connector_type != DRM_MODE_CONNECTOR_DSI) {
118 return 0;
119 }
120
121 memset(&props, 0, sizeof(props));
122 props.type = BACKLIGHT_RAW;
123 props.power = FB_BLANK_UNBLANK;
124
125 display = (struct dsi_display *) c_conn->display;
126 bl_config = &display->panel->bl_config;
127 props.max_brightness = bl_config->brightness_max_level;
128 props.brightness = bl_config->brightness_max_level;
129 snprintf(bl_node_name, BL_NODE_NAME_SIZE, "panel%u-backlight",
130 display_count);
Shashank Babu Chinta Venkata06c428e2017-04-17 13:52:28 -0700131 bl_device = backlight_device_register(bl_node_name, dev->dev,
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800132 c_conn, &sde_backlight_device_ops, &props);
133 if (IS_ERR_OR_NULL(bl_device)) {
134 SDE_ERROR("Failed to register backlight: %ld\n",
135 PTR_ERR(bl_device));
136 return -ENODEV;
137 }
138 display_count++;
139
140 return 0;
141}
142
Clarence Ipa18d4832017-03-13 12:35:44 -0700143int sde_connector_trigger_event(void *drm_connector,
144 uint32_t event_idx, uint32_t instance_idx,
145 uint32_t data0, uint32_t data1,
146 uint32_t data2, uint32_t data3)
147{
148 struct sde_connector *c_conn;
149 unsigned long irq_flags;
150 void (*cb_func)(uint32_t event_idx,
151 uint32_t instance_idx, void *usr,
152 uint32_t data0, uint32_t data1,
153 uint32_t data2, uint32_t data3);
154 void *usr;
155 int rc = 0;
156
157 /*
158 * This function may potentially be called from an ISR context, so
159 * avoid excessive logging/etc.
160 */
161 if (!drm_connector)
162 return -EINVAL;
163 else if (event_idx >= SDE_CONN_EVENT_COUNT)
164 return -EINVAL;
165 c_conn = to_sde_connector(drm_connector);
166
167 spin_lock_irqsave(&c_conn->event_lock, irq_flags);
168 cb_func = c_conn->event_table[event_idx].cb_func;
169 usr = c_conn->event_table[event_idx].usr;
170 spin_unlock_irqrestore(&c_conn->event_lock, irq_flags);
171
172 if (cb_func)
173 cb_func(event_idx, instance_idx, usr,
174 data0, data1, data2, data3);
175 else
176 rc = -EAGAIN;
177
178 return rc;
179}
180
181int sde_connector_register_event(struct drm_connector *connector,
182 uint32_t event_idx,
183 void (*cb_func)(uint32_t event_idx,
184 uint32_t instance_idx, void *usr,
185 uint32_t data0, uint32_t data1,
186 uint32_t data2, uint32_t data3),
187 void *usr)
188{
189 struct sde_connector *c_conn;
190 unsigned long irq_flags;
191
192 if (!connector) {
193 SDE_ERROR("invalid connector\n");
194 return -EINVAL;
195 } else if (event_idx >= SDE_CONN_EVENT_COUNT) {
196 SDE_ERROR("conn%d, invalid event %d\n",
197 connector->base.id, event_idx);
198 return -EINVAL;
199 }
200 c_conn = to_sde_connector(connector);
201
202 spin_lock_irqsave(&c_conn->event_lock, irq_flags);
203 c_conn->event_table[event_idx].cb_func = cb_func;
204 c_conn->event_table[event_idx].usr = usr;
205 spin_unlock_irqrestore(&c_conn->event_lock, irq_flags);
206
207 /* optionally notify display of event registration */
208 if (c_conn->ops.enable_event && c_conn->display)
209 c_conn->ops.enable_event(connector, event_idx,
210 cb_func != NULL, c_conn->display);
211 return 0;
212}
213
214void sde_connector_unregister_event(struct drm_connector *connector,
215 uint32_t event_idx)
216{
217 (void)sde_connector_register_event(connector, event_idx, 0, 0);
218}
219
Clarence Ipcb3afd42016-07-15 16:25:34 -0400220int sde_connector_get_info(struct drm_connector *connector,
221 struct msm_display_info *info)
222{
223 struct sde_connector *c_conn;
224
225 if (!connector || !info) {
226 SDE_ERROR("invalid argument(s), conn %pK, info %pK\n",
227 connector, info);
228 return -EINVAL;
229 }
230
231 c_conn = to_sde_connector(connector);
232
233 if (!c_conn->display || !c_conn->ops.get_info) {
234 SDE_ERROR("display info not supported for %pK\n",
235 c_conn->display);
236 return -EINVAL;
237 }
238
239 return c_conn->ops.get_info(info, c_conn->display);
240}
241
Lloyd Atkinson05d75512017-01-17 14:45:51 -0500242int sde_connector_pre_kickoff(struct drm_connector *connector)
243{
244 struct sde_connector *c_conn;
245 struct sde_connector_state *c_state;
246 struct msm_display_kickoff_params params;
247 int rc;
248
249 if (!connector) {
250 SDE_ERROR("invalid argument\n");
251 return -EINVAL;
252 }
253
254 c_conn = to_sde_connector(connector);
255 c_state = to_sde_connector_state(connector->state);
256
257 if (!c_conn->display) {
258 SDE_ERROR("invalid argument\n");
259 return -EINVAL;
260 }
261
262 if (!c_conn->ops.pre_kickoff)
263 return 0;
264
265 params.rois = &c_state->rois;
266
267 SDE_EVT32_VERBOSE(connector->base.id);
268
269 rc = c_conn->ops.pre_kickoff(connector, c_conn->display, &params);
270
271 return rc;
272}
273
Veera Sundaram Sankaranbb2bf9a2017-03-29 18:56:47 -0700274void sde_connector_clk_ctrl(struct drm_connector *connector, bool enable)
275{
276 struct sde_connector *c_conn;
277 struct dsi_display *display;
278 u32 state = enable ? DSI_CLK_ON : DSI_CLK_OFF;
279
280 if (!connector) {
281 SDE_ERROR("invalid connector\n");
282 return;
283 }
284
285 c_conn = to_sde_connector(connector);
286 display = (struct dsi_display *) c_conn->display;
287
288 if (display && c_conn->ops.clk_ctrl)
289 c_conn->ops.clk_ctrl(display->mdp_clk_handle,
290 DSI_ALL_CLKS, state);
291}
292
Clarence Ipdd8021c2016-07-20 16:39:47 -0400293static void sde_connector_destroy(struct drm_connector *connector)
294{
295 struct sde_connector *c_conn;
296
297 if (!connector) {
298 SDE_ERROR("invalid connector\n");
299 return;
300 }
301
302 c_conn = to_sde_connector(connector);
303
Dhaval Patel4e574842016-08-23 15:11:37 -0700304 if (c_conn->blob_caps)
305 drm_property_unreference_blob(c_conn->blob_caps);
Ping Li898b1bf2017-02-09 18:03:28 -0800306 if (c_conn->blob_hdr)
307 drm_property_unreference_blob(c_conn->blob_hdr);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400308 msm_property_destroy(&c_conn->property_info);
309
310 drm_connector_unregister(connector);
Clarence Ip90b282d2017-05-04 10:00:32 -0700311 mutex_destroy(&c_conn->lock);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400312 sde_fence_deinit(&c_conn->retire_fence);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400313 drm_connector_cleanup(connector);
314 kfree(c_conn);
315}
316
317/**
318 * _sde_connector_destroy_fb - clean up connector state's out_fb buffer
319 * @c_conn: Pointer to sde connector structure
320 * @c_state: Pointer to sde connector state structure
321 */
322static void _sde_connector_destroy_fb(struct sde_connector *c_conn,
323 struct sde_connector_state *c_state)
324{
325 if (!c_state || !c_state->out_fb) {
326 SDE_ERROR("invalid state %pK\n", c_state);
327 return;
328 }
329
330 msm_framebuffer_cleanup(c_state->out_fb,
331 c_state->mmu_id);
332 drm_framebuffer_unreference(c_state->out_fb);
333 c_state->out_fb = NULL;
334
335 if (c_conn) {
336 c_state->property_values[CONNECTOR_PROP_OUT_FB] =
337 msm_property_get_default(&c_conn->property_info,
338 CONNECTOR_PROP_OUT_FB);
339 } else {
340 c_state->property_values[CONNECTOR_PROP_OUT_FB] = ~0;
341 }
342}
343
344static void sde_connector_atomic_destroy_state(struct drm_connector *connector,
345 struct drm_connector_state *state)
346{
347 struct sde_connector *c_conn = NULL;
348 struct sde_connector_state *c_state = NULL;
349
350 if (!state) {
351 SDE_ERROR("invalid state\n");
352 return;
353 }
354
355 /*
356 * The base DRM framework currently always passes in a NULL
357 * connector pointer. This is not correct, but attempt to
358 * handle that case as much as possible.
359 */
360 if (connector)
361 c_conn = to_sde_connector(connector);
362 c_state = to_sde_connector_state(state);
363
364 if (c_state->out_fb)
365 _sde_connector_destroy_fb(c_conn, c_state);
366
367 if (!c_conn) {
368 kfree(c_state);
369 } else {
370 /* destroy value helper */
371 msm_property_destroy_state(&c_conn->property_info, c_state,
372 c_state->property_values, 0);
373 }
374}
375
376static void sde_connector_atomic_reset(struct drm_connector *connector)
377{
378 struct sde_connector *c_conn;
379 struct sde_connector_state *c_state;
380
381 if (!connector) {
382 SDE_ERROR("invalid connector\n");
383 return;
384 }
385
386 c_conn = to_sde_connector(connector);
387
388 if (connector->state) {
389 sde_connector_atomic_destroy_state(connector, connector->state);
390 connector->state = 0;
391 }
392
393 c_state = msm_property_alloc_state(&c_conn->property_info);
394 if (!c_state) {
395 SDE_ERROR("state alloc failed\n");
396 return;
397 }
398
399 /* reset value helper, zero out state structure and reset properties */
400 msm_property_reset_state(&c_conn->property_info, c_state,
401 c_state->property_values, 0);
402
403 c_state->base.connector = connector;
404 connector->state = &c_state->base;
405}
406
407static struct drm_connector_state *
408sde_connector_atomic_duplicate_state(struct drm_connector *connector)
409{
410 struct sde_connector *c_conn;
411 struct sde_connector_state *c_state, *c_oldstate;
412 int rc;
413
414 if (!connector || !connector->state) {
415 SDE_ERROR("invalid connector %pK\n", connector);
416 return NULL;
417 }
418
419 c_conn = to_sde_connector(connector);
420 c_oldstate = to_sde_connector_state(connector->state);
421 c_state = msm_property_alloc_state(&c_conn->property_info);
422 if (!c_state) {
423 SDE_ERROR("state alloc failed\n");
424 return NULL;
425 }
426
427 /* duplicate value helper */
428 msm_property_duplicate_state(&c_conn->property_info,
429 c_oldstate, c_state, c_state->property_values, 0);
430
431 /* additional handling for drm framebuffer objects */
432 if (c_state->out_fb) {
433 drm_framebuffer_reference(c_state->out_fb);
434 rc = msm_framebuffer_prepare(c_state->out_fb,
435 c_state->mmu_id);
436 if (rc)
437 SDE_ERROR("failed to prepare fb, %d\n", rc);
438 }
439
440 return &c_state->base;
441}
442
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400443static int _sde_connector_roi_v1_check_roi(
444 struct sde_connector *c_conn,
445 struct drm_clip_rect *roi_conn,
446 const struct msm_roi_caps *caps)
447{
448 const struct msm_roi_alignment *align = &caps->align;
449 int w = roi_conn->x2 - roi_conn->x1;
450 int h = roi_conn->y2 - roi_conn->y1;
451
452 if (w <= 0 || h <= 0) {
453 SDE_ERROR_CONN(c_conn, "invalid conn roi w %d h %d\n", w, h);
454 return -EINVAL;
455 }
456
457 if (w < align->min_width || w % align->width_pix_align) {
458 SDE_ERROR_CONN(c_conn,
459 "invalid conn roi width %d min %d align %d\n",
460 w, align->min_width, align->width_pix_align);
461 return -EINVAL;
462 }
463
464 if (h < align->min_height || h % align->height_pix_align) {
465 SDE_ERROR_CONN(c_conn,
466 "invalid conn roi height %d min %d align %d\n",
467 h, align->min_height, align->height_pix_align);
468 return -EINVAL;
469 }
470
471 if (roi_conn->x1 % align->xstart_pix_align) {
472 SDE_ERROR_CONN(c_conn, "invalid conn roi x1 %d align %d\n",
473 roi_conn->x1, align->xstart_pix_align);
474 return -EINVAL;
475 }
476
477 if (roi_conn->y1 % align->ystart_pix_align) {
478 SDE_ERROR_CONN(c_conn, "invalid conn roi y1 %d align %d\n",
479 roi_conn->y1, align->ystart_pix_align);
480 return -EINVAL;
481 }
482
483 return 0;
484}
485
486static int _sde_connector_set_roi_v1(
487 struct sde_connector *c_conn,
488 struct sde_connector_state *c_state,
489 void *usr_ptr)
490{
491 struct sde_drm_roi_v1 roi_v1;
492 struct msm_display_info display_info;
493 struct msm_roi_caps *caps;
494 int i, rc;
495
496 if (!c_conn || !c_state) {
497 SDE_ERROR("invalid args\n");
498 return -EINVAL;
499 }
500
501 rc = sde_connector_get_info(&c_conn->base, &display_info);
502 if (rc) {
503 SDE_ERROR_CONN(c_conn, "display get info error: %d\n", rc);
504 return rc;
505 }
506
507 caps = &display_info.roi_caps;
508 if (!caps->enabled) {
509 SDE_ERROR_CONN(c_conn, "display roi capability is disabled\n");
510 return -ENOTSUPP;
511 }
512
513 memset(&c_state->rois, 0, sizeof(c_state->rois));
514
515 if (!usr_ptr) {
516 SDE_DEBUG_CONN(c_conn, "rois cleared\n");
517 return 0;
518 }
519
520 if (copy_from_user(&roi_v1, usr_ptr, sizeof(roi_v1))) {
521 SDE_ERROR_CONN(c_conn, "failed to copy roi_v1 data\n");
522 return -EINVAL;
523 }
524
525 SDE_DEBUG_CONN(c_conn, "num_rects %d\n", roi_v1.num_rects);
526
527 if (roi_v1.num_rects == 0) {
528 SDE_DEBUG_CONN(c_conn, "rois cleared\n");
529 return 0;
530 }
531
532 if (roi_v1.num_rects > SDE_MAX_ROI_V1 ||
533 roi_v1.num_rects > caps->num_roi) {
534 SDE_ERROR_CONN(c_conn, "too many rects specified: %d\n",
535 roi_v1.num_rects);
536 return -EINVAL;
537 }
538
539 c_state->rois.num_rects = roi_v1.num_rects;
540 for (i = 0; i < roi_v1.num_rects; ++i) {
541 int rc;
542
543 rc = _sde_connector_roi_v1_check_roi(c_conn, &roi_v1.roi[i],
544 caps);
545 if (rc)
546 return rc;
547
548 c_state->rois.roi[i] = roi_v1.roi[i];
549 SDE_DEBUG_CONN(c_conn, "roi%d: roi 0x%x 0x%x 0x%x 0x%x\n", i,
550 c_state->rois.roi[i].x1,
551 c_state->rois.roi[i].y1,
552 c_state->rois.roi[i].x2,
553 c_state->rois.roi[i].y2);
554 }
555
556 return 0;
557}
558
Clarence Ip90b282d2017-05-04 10:00:32 -0700559static int _sde_connector_update_power_locked(struct sde_connector *c_conn)
560{
561 struct drm_connector *connector;
562 void *display;
563 int (*set_power)(struct drm_connector *, int, void *);
564 int mode, rc = 0;
565
566 if (!c_conn)
567 return -EINVAL;
568 connector = &c_conn->base;
569
570 mode = c_conn->lp_mode;
571 if (c_conn->dpms_mode != DRM_MODE_DPMS_ON)
572 mode = SDE_MODE_DPMS_OFF;
573 switch (c_conn->dpms_mode) {
574 case DRM_MODE_DPMS_ON:
575 mode = c_conn->lp_mode;
576 break;
577 case DRM_MODE_DPMS_STANDBY:
578 mode = SDE_MODE_DPMS_STANDBY;
579 break;
580 case DRM_MODE_DPMS_SUSPEND:
581 mode = SDE_MODE_DPMS_SUSPEND;
582 break;
583 case DRM_MODE_DPMS_OFF:
584 mode = SDE_MODE_DPMS_OFF;
585 break;
586 default:
587 mode = c_conn->lp_mode;
588 SDE_ERROR("conn %d dpms set to unrecognized mode %d\n",
589 connector->base.id, mode);
590 break;
591 }
592
593 SDE_DEBUG("conn %d - dpms %d, lp %d, panel %d\n", connector->base.id,
594 c_conn->dpms_mode, c_conn->lp_mode, mode);
595
596 if (mode != c_conn->last_panel_power_mode && c_conn->ops.set_power) {
597 display = c_conn->display;
598 set_power = c_conn->ops.set_power;
599
600 mutex_unlock(&c_conn->lock);
601 rc = set_power(connector, mode, display);
602 mutex_lock(&c_conn->lock);
603 }
604 c_conn->last_panel_power_mode = mode;
605
606 return rc;
607}
608
Clarence Ipdd8021c2016-07-20 16:39:47 -0400609static int sde_connector_atomic_set_property(struct drm_connector *connector,
610 struct drm_connector_state *state,
611 struct drm_property *property,
612 uint64_t val)
613{
614 struct sde_connector *c_conn;
615 struct sde_connector_state *c_state;
616 int idx, rc;
617
618 if (!connector || !state || !property) {
619 SDE_ERROR("invalid argument(s), conn %pK, state %pK, prp %pK\n",
620 connector, state, property);
621 return -EINVAL;
622 }
623
624 c_conn = to_sde_connector(connector);
625 c_state = to_sde_connector_state(state);
626
627 /* generic property handling */
628 rc = msm_property_atomic_set(&c_conn->property_info,
629 c_state->property_values, 0, property, val);
630 if (rc)
631 goto end;
632
633 /* connector-specific property handling */
634 idx = msm_property_index(&c_conn->property_info, property);
Clarence Ip90b282d2017-05-04 10:00:32 -0700635 switch (idx) {
636 case CONNECTOR_PROP_OUT_FB:
Clarence Ipdd8021c2016-07-20 16:39:47 -0400637 /* clear old fb, if present */
638 if (c_state->out_fb)
639 _sde_connector_destroy_fb(c_conn, c_state);
640
641 /* convert fb val to drm framebuffer and prepare it */
642 c_state->out_fb =
643 drm_framebuffer_lookup(connector->dev, val);
Alan Kwongae1b1142017-03-05 16:07:10 -0800644 if (!c_state->out_fb && val) {
Clarence Ipdd8021c2016-07-20 16:39:47 -0400645 SDE_ERROR("failed to look up fb %lld\n", val);
646 rc = -EFAULT;
Alan Kwongae1b1142017-03-05 16:07:10 -0800647 } else if (!c_state->out_fb && !val) {
648 SDE_DEBUG("cleared fb_id\n");
649 rc = 0;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400650 } else {
Alan Kwong578cdaf2017-01-28 17:25:43 -0800651 msm_framebuffer_set_kmap(c_state->out_fb,
652 c_conn->fb_kmap);
653
Alan Kwongdfa8c082016-07-29 04:10:00 -0400654 if (c_state->out_fb->flags & DRM_MODE_FB_SECURE)
655 c_state->mmu_id =
656 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE];
657 else
658 c_state->mmu_id =
659 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE];
Clarence Ipdd8021c2016-07-20 16:39:47 -0400660
661 rc = msm_framebuffer_prepare(c_state->out_fb,
662 c_state->mmu_id);
663 if (rc)
664 SDE_ERROR("prep fb failed, %d\n", rc);
665 }
Clarence Ip90b282d2017-05-04 10:00:32 -0700666 break;
Clarence Ip90b282d2017-05-04 10:00:32 -0700667 case CONNECTOR_PROP_LP:
668 mutex_lock(&c_conn->lock);
669 c_conn->lp_mode = val;
670 _sde_connector_update_power_locked(c_conn);
671 mutex_unlock(&c_conn->lock);
672 break;
673 default:
674 break;
Lloyd Atkinson11f34442016-08-11 11:19:52 -0400675 }
676
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400677 if (idx == CONNECTOR_PROP_ROI_V1) {
678 rc = _sde_connector_set_roi_v1(c_conn, c_state, (void *)val);
679 if (rc)
680 SDE_ERROR_CONN(c_conn, "invalid roi_v1, rc: %d\n", rc);
681 }
682
Clarence Ipdd8021c2016-07-20 16:39:47 -0400683 /* check for custom property handling */
684 if (!rc && c_conn->ops.set_property) {
685 rc = c_conn->ops.set_property(connector,
686 state,
687 idx,
688 val,
689 c_conn->display);
690
691 /* potentially clean up out_fb if rc != 0 */
692 if ((idx == CONNECTOR_PROP_OUT_FB) && rc)
693 _sde_connector_destroy_fb(c_conn, c_state);
694 }
695end:
696 return rc;
697}
698
699static int sde_connector_set_property(struct drm_connector *connector,
700 struct drm_property *property,
701 uint64_t val)
702{
703 if (!connector) {
704 SDE_ERROR("invalid connector\n");
705 return -EINVAL;
706 }
707
708 return sde_connector_atomic_set_property(connector,
709 connector->state, property, val);
710}
711
712static int sde_connector_atomic_get_property(struct drm_connector *connector,
713 const struct drm_connector_state *state,
714 struct drm_property *property,
715 uint64_t *val)
716{
717 struct sde_connector *c_conn;
718 struct sde_connector_state *c_state;
719 int idx, rc = -EINVAL;
720
721 if (!connector || !state) {
722 SDE_ERROR("invalid argument(s), conn %pK, state %pK\n",
723 connector, state);
724 return -EINVAL;
725 }
726
727 c_conn = to_sde_connector(connector);
728 c_state = to_sde_connector_state(state);
729
730 idx = msm_property_index(&c_conn->property_info, property);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400731 if (idx == CONNECTOR_PROP_RETIRE_FENCE)
Dhaval Patel5cb59be2017-04-20 20:00:56 -0700732 rc = sde_fence_create(&c_conn->retire_fence, val, 0);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400733 else
734 /* get cached property value */
735 rc = msm_property_atomic_get(&c_conn->property_info,
736 c_state->property_values, 0, property, val);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400737
738 /* allow for custom override */
739 if (c_conn->ops.get_property)
740 rc = c_conn->ops.get_property(connector,
741 (struct drm_connector_state *)state,
742 idx,
743 val,
744 c_conn->display);
745 return rc;
746}
747
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400748void sde_connector_prepare_fence(struct drm_connector *connector)
749{
750 if (!connector) {
751 SDE_ERROR("invalid connector\n");
752 return;
753 }
754
755 sde_fence_prepare(&to_sde_connector(connector)->retire_fence);
756}
757
758void sde_connector_complete_commit(struct drm_connector *connector)
759{
760 if (!connector) {
761 SDE_ERROR("invalid connector\n");
762 return;
763 }
764
765 /* signal connector's retire fence */
766 sde_fence_signal(&to_sde_connector(connector)->retire_fence, 0);
767}
768
Clarence Ipdd8021c2016-07-20 16:39:47 -0400769static enum drm_connector_status
770sde_connector_detect(struct drm_connector *connector, bool force)
771{
772 enum drm_connector_status status = connector_status_unknown;
773 struct sde_connector *c_conn;
774
775 if (!connector) {
776 SDE_ERROR("invalid connector\n");
777 return status;
778 }
779
780 c_conn = to_sde_connector(connector);
781
782 if (c_conn->ops.detect)
783 status = c_conn->ops.detect(connector,
784 force,
785 c_conn->display);
786
787 return status;
788}
789
Clarence Ip90b282d2017-05-04 10:00:32 -0700790static int sde_connector_dpms(struct drm_connector *connector,
791 int mode)
792{
793 struct sde_connector *c_conn;
794
795 if (!connector) {
796 SDE_ERROR("invalid connector\n");
797 return -EINVAL;
798 }
799 c_conn = to_sde_connector(connector);
800
801 /* validate incoming dpms request */
802 switch (mode) {
803 case DRM_MODE_DPMS_ON:
804 case DRM_MODE_DPMS_STANDBY:
805 case DRM_MODE_DPMS_SUSPEND:
806 case DRM_MODE_DPMS_OFF:
807 SDE_DEBUG("conn %d dpms set to %d\n", connector->base.id, mode);
808 break;
809 default:
810 SDE_ERROR("conn %d dpms set to unrecognized mode %d\n",
811 connector->base.id, mode);
812 break;
813 }
814
815 mutex_lock(&c_conn->lock);
816 c_conn->dpms_mode = mode;
817 _sde_connector_update_power_locked(c_conn);
818 mutex_unlock(&c_conn->lock);
819
820 /* use helper for boilerplate handling */
821 return drm_atomic_helper_connector_dpms(connector, mode);
822}
823
824int sde_connector_get_dpms(struct drm_connector *connector)
825{
826 struct sde_connector *c_conn;
827 int rc;
828
829 if (!connector) {
830 SDE_DEBUG("invalid connector\n");
831 return DRM_MODE_DPMS_OFF;
832 }
833
834 c_conn = to_sde_connector(connector);
835
836 mutex_lock(&c_conn->lock);
837 rc = c_conn->dpms_mode;
838 mutex_unlock(&c_conn->lock);
839
840 return rc;
841}
842
Alan Kwong578cdaf2017-01-28 17:25:43 -0800843#ifdef CONFIG_DEBUG_FS
844/**
845 * sde_connector_init_debugfs - initialize connector debugfs
846 * @connector: Pointer to drm connector
847 */
848static int sde_connector_init_debugfs(struct drm_connector *connector)
849{
850 struct sde_connector *sde_connector;
851
852 if (!connector || !connector->debugfs_entry) {
853 SDE_ERROR("invalid connector\n");
854 return -EINVAL;
855 }
856
857 sde_connector = to_sde_connector(connector);
858
859 if (!debugfs_create_bool("fb_kmap", 0644, connector->debugfs_entry,
860 &sde_connector->fb_kmap)) {
861 SDE_ERROR("failed to create connector fb_kmap\n");
862 return -ENOMEM;
863 }
864
865 return 0;
866}
867#else
868static int sde_connector_init_debugfs(struct drm_connector *connector)
869{
870 return 0;
871}
872#endif
873
874static int sde_connector_late_register(struct drm_connector *connector)
875{
876 return sde_connector_init_debugfs(connector);
877}
878
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -0700879static void sde_connector_early_unregister(struct drm_connector *connector)
880{
881 /* debugfs under connector->debugfs are deleted by drm_debugfs */
882}
883
Clarence Ipdd8021c2016-07-20 16:39:47 -0400884static const struct drm_connector_funcs sde_connector_ops = {
Clarence Ip90b282d2017-05-04 10:00:32 -0700885 .dpms = sde_connector_dpms,
Clarence Ipdd8021c2016-07-20 16:39:47 -0400886 .reset = sde_connector_atomic_reset,
887 .detect = sde_connector_detect,
888 .destroy = sde_connector_destroy,
889 .fill_modes = drm_helper_probe_single_connector_modes,
890 .atomic_duplicate_state = sde_connector_atomic_duplicate_state,
891 .atomic_destroy_state = sde_connector_atomic_destroy_state,
892 .atomic_set_property = sde_connector_atomic_set_property,
893 .atomic_get_property = sde_connector_atomic_get_property,
894 .set_property = sde_connector_set_property,
Alan Kwong578cdaf2017-01-28 17:25:43 -0800895 .late_register = sde_connector_late_register,
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -0700896 .early_unregister = sde_connector_early_unregister,
Clarence Ipdd8021c2016-07-20 16:39:47 -0400897};
898
899static int sde_connector_get_modes(struct drm_connector *connector)
900{
901 struct sde_connector *c_conn;
902
903 if (!connector) {
904 SDE_ERROR("invalid connector\n");
905 return 0;
906 }
907
908 c_conn = to_sde_connector(connector);
909 if (!c_conn->ops.get_modes) {
910 SDE_DEBUG("missing get_modes callback\n");
911 return 0;
912 }
913
914 return c_conn->ops.get_modes(connector, c_conn->display);
915}
916
917static enum drm_mode_status
918sde_connector_mode_valid(struct drm_connector *connector,
919 struct drm_display_mode *mode)
920{
921 struct sde_connector *c_conn;
922
923 if (!connector || !mode) {
924 SDE_ERROR("invalid argument(s), conn %pK, mode %pK\n",
925 connector, mode);
926 return MODE_ERROR;
927 }
928
929 c_conn = to_sde_connector(connector);
930
931 if (c_conn->ops.mode_valid)
932 return c_conn->ops.mode_valid(connector, mode, c_conn->display);
933
934 /* assume all modes okay by default */
935 return MODE_OK;
936}
937
938static struct drm_encoder *
939sde_connector_best_encoder(struct drm_connector *connector)
940{
941 struct sde_connector *c_conn = to_sde_connector(connector);
942
943 if (!connector) {
944 SDE_ERROR("invalid connector\n");
945 return NULL;
946 }
947
948 /*
949 * This is true for now, revisit this code when multiple encoders are
950 * supported.
951 */
952 return c_conn->encoder;
953}
954
955static const struct drm_connector_helper_funcs sde_connector_helper_ops = {
956 .get_modes = sde_connector_get_modes,
957 .mode_valid = sde_connector_mode_valid,
958 .best_encoder = sde_connector_best_encoder,
959};
960
961struct drm_connector *sde_connector_init(struct drm_device *dev,
962 struct drm_encoder *encoder,
963 struct drm_panel *panel,
964 void *display,
965 const struct sde_connector_ops *ops,
966 int connector_poll,
967 int connector_type)
968{
969 struct msm_drm_private *priv;
970 struct sde_kms *sde_kms;
971 struct sde_kms_info *info;
972 struct sde_connector *c_conn = NULL;
Ping Li898b1bf2017-02-09 18:03:28 -0800973 struct dsi_display *dsi_display;
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400974 struct msm_display_info display_info;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400975 int rc;
976
977 if (!dev || !dev->dev_private || !encoder) {
978 SDE_ERROR("invalid argument(s), dev %pK, enc %pK\n",
979 dev, encoder);
980 return ERR_PTR(-EINVAL);
981 }
982
983 priv = dev->dev_private;
984 if (!priv->kms) {
985 SDE_ERROR("invalid kms reference\n");
986 return ERR_PTR(-EINVAL);
987 }
988
989 c_conn = kzalloc(sizeof(*c_conn), GFP_KERNEL);
990 if (!c_conn) {
991 SDE_ERROR("failed to alloc sde connector\n");
992 return ERR_PTR(-ENOMEM);
993 }
994
995 rc = drm_connector_init(dev,
996 &c_conn->base,
997 &sde_connector_ops,
998 connector_type);
999 if (rc)
1000 goto error_free_conn;
1001
Clarence Ipa18d4832017-03-13 12:35:44 -07001002 spin_lock_init(&c_conn->event_lock);
1003
Clarence Ipdd8021c2016-07-20 16:39:47 -04001004 c_conn->connector_type = connector_type;
1005 c_conn->encoder = encoder;
1006 c_conn->panel = panel;
1007 c_conn->display = display;
1008
Clarence Ip90b282d2017-05-04 10:00:32 -07001009 c_conn->dpms_mode = DRM_MODE_DPMS_ON;
1010 c_conn->lp_mode = 0;
1011 c_conn->last_panel_power_mode = SDE_MODE_DPMS_ON;
1012
Alan Kwongdfa8c082016-07-29 04:10:00 -04001013 /* cache mmu_id's for later */
Clarence Ipdd8021c2016-07-20 16:39:47 -04001014 sde_kms = to_sde_kms(priv->kms);
Alan Kwongdfa8c082016-07-29 04:10:00 -04001015 if (sde_kms->vbif[VBIF_NRT]) {
1016 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] =
1017 sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_UNSECURE];
1018 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE] =
1019 sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_SECURE];
1020 } else {
1021 c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] =
1022 sde_kms->mmu_id[MSM_SMMU_DOMAIN_UNSECURE];
1023 c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE] =
1024 sde_kms->mmu_id[MSM_SMMU_DOMAIN_SECURE];
1025 }
Clarence Ipdd8021c2016-07-20 16:39:47 -04001026
1027 if (ops)
1028 c_conn->ops = *ops;
1029
1030 c_conn->base.helper_private = &sde_connector_helper_ops;
1031 c_conn->base.polled = connector_poll;
1032 c_conn->base.interlace_allowed = 0;
1033 c_conn->base.doublescan_allowed = 0;
1034
1035 snprintf(c_conn->name,
1036 SDE_CONNECTOR_NAME_SIZE,
1037 "conn%u",
1038 c_conn->base.base.id);
1039
Lloyd Atkinson5d40d312016-09-06 08:34:13 -04001040 rc = sde_fence_init(&c_conn->retire_fence, c_conn->name,
1041 c_conn->base.base.id);
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001042 if (rc) {
1043 SDE_ERROR("failed to init fence, %d\n", rc);
1044 goto error_cleanup_conn;
1045 }
1046
Clarence Ip90b282d2017-05-04 10:00:32 -07001047 mutex_init(&c_conn->lock);
1048
Clarence Ipdd8021c2016-07-20 16:39:47 -04001049 rc = drm_mode_connector_attach_encoder(&c_conn->base, encoder);
1050 if (rc) {
1051 SDE_ERROR("failed to attach encoder to connector, %d\n", rc);
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -08001052 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -04001053 }
1054
Shashank Babu Chinta Venkata06c428e2017-04-17 13:52:28 -07001055 rc = sde_backlight_setup(c_conn, dev);
Dhaval Patel7cdd6662017-03-08 13:10:37 -08001056 if (rc) {
1057 SDE_ERROR("failed to setup backlight, rc=%d\n", rc);
1058 goto error_cleanup_fence;
Vishnuvardhan Prodduturi75b96802016-10-17 18:45:55 +05301059 }
1060
Clarence Ipdd8021c2016-07-20 16:39:47 -04001061 /* create properties */
1062 msm_property_init(&c_conn->property_info, &c_conn->base.base, dev,
1063 priv->conn_property, c_conn->property_data,
1064 CONNECTOR_PROP_COUNT, CONNECTOR_PROP_BLOBCOUNT,
1065 sizeof(struct sde_connector_state));
1066
1067 if (c_conn->ops.post_init) {
1068 info = kmalloc(sizeof(*info), GFP_KERNEL);
1069 if (!info) {
1070 SDE_ERROR("failed to allocate info buffer\n");
1071 rc = -ENOMEM;
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -08001072 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -04001073 }
1074
1075 sde_kms_info_reset(info);
1076 rc = c_conn->ops.post_init(&c_conn->base, info, display);
1077 if (rc) {
1078 SDE_ERROR("post-init failed, %d\n", rc);
1079 kfree(info);
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -08001080 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -04001081 }
1082
1083 msm_property_install_blob(&c_conn->property_info,
Dhaval Patel4e574842016-08-23 15:11:37 -07001084 "capabilities",
Clarence Ipdd8021c2016-07-20 16:39:47 -04001085 DRM_MODE_PROP_IMMUTABLE,
1086 CONNECTOR_PROP_SDE_INFO);
1087
1088 msm_property_set_blob(&c_conn->property_info,
Dhaval Patel4e574842016-08-23 15:11:37 -07001089 &c_conn->blob_caps,
Clarence Ipdd8021c2016-07-20 16:39:47 -04001090 SDE_KMS_INFO_DATA(info),
1091 SDE_KMS_INFO_DATALEN(info),
1092 CONNECTOR_PROP_SDE_INFO);
1093 kfree(info);
1094 }
1095
Ping Li898b1bf2017-02-09 18:03:28 -08001096 if (connector_type == DRM_MODE_CONNECTOR_DSI) {
1097 dsi_display = (struct dsi_display *)(display);
1098 if (dsi_display && dsi_display->panel &&
1099 dsi_display->panel->hdr_props.hdr_enabled == true) {
1100 msm_property_install_blob(&c_conn->property_info,
1101 "hdr_properties",
1102 DRM_MODE_PROP_IMMUTABLE,
1103 CONNECTOR_PROP_HDR_INFO);
1104
1105 msm_property_set_blob(&c_conn->property_info,
1106 &c_conn->blob_hdr,
1107 &dsi_display->panel->hdr_props,
1108 sizeof(dsi_display->panel->hdr_props),
1109 CONNECTOR_PROP_HDR_INFO);
1110 }
1111 }
1112
Lloyd Atkinson8ba47032017-03-22 17:13:32 -04001113 rc = sde_connector_get_info(&c_conn->base, &display_info);
1114 if (!rc && display_info.roi_caps.enabled) {
1115 msm_property_install_volatile_range(
1116 &c_conn->property_info, "sde_drm_roi_v1", 0x0,
1117 0, ~0, 0, CONNECTOR_PROP_ROI_V1);
1118 }
1119
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001120 msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE",
Dhaval Patel4e574842016-08-23 15:11:37 -07001121 0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE);
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001122
Lloyd Atkinson77382202017-02-01 14:59:43 -05001123 msm_property_install_range(&c_conn->property_info, "autorefresh",
1124 0x0, 0, AUTOREFRESH_MAX_FRAME_CNT, 0,
1125 CONNECTOR_PROP_AUTOREFRESH);
1126
Lloyd Atkinsonb6191972016-08-10 18:31:46 -04001127 /* enum/bitmask properties */
1128 msm_property_install_enum(&c_conn->property_info, "topology_name",
1129 DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name,
1130 ARRAY_SIZE(e_topology_name),
1131 CONNECTOR_PROP_TOPOLOGY_NAME);
1132 msm_property_install_enum(&c_conn->property_info, "topology_control",
1133 0, 1, e_topology_control,
1134 ARRAY_SIZE(e_topology_control),
1135 CONNECTOR_PROP_TOPOLOGY_CONTROL);
Clarence Ip90b282d2017-05-04 10:00:32 -07001136 msm_property_install_enum(&c_conn->property_info, "LP",
1137 0, 0, e_power_mode,
1138 ARRAY_SIZE(e_power_mode),
1139 CONNECTOR_PROP_LP);
Lloyd Atkinsonb6191972016-08-10 18:31:46 -04001140
Clarence Ipdd8021c2016-07-20 16:39:47 -04001141 rc = msm_property_install_get_status(&c_conn->property_info);
1142 if (rc) {
1143 SDE_ERROR("failed to create one or more properties\n");
1144 goto error_destroy_property;
1145 }
1146
Lloyd Atkinsonb6191972016-08-10 18:31:46 -04001147 SDE_DEBUG("connector %d attach encoder %d\n",
1148 c_conn->base.base.id, encoder->base.id);
1149
Clarence Ipdd8021c2016-07-20 16:39:47 -04001150 priv->connectors[priv->num_connectors++] = &c_conn->base;
1151
1152 return &c_conn->base;
1153
1154error_destroy_property:
Dhaval Patel4e574842016-08-23 15:11:37 -07001155 if (c_conn->blob_caps)
1156 drm_property_unreference_blob(c_conn->blob_caps);
Ping Li898b1bf2017-02-09 18:03:28 -08001157 if (c_conn->blob_hdr)
1158 drm_property_unreference_blob(c_conn->blob_hdr);
Clarence Ipdd8021c2016-07-20 16:39:47 -04001159 msm_property_destroy(&c_conn->property_info);
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001160error_cleanup_fence:
Clarence Ip90b282d2017-05-04 10:00:32 -07001161 mutex_destroy(&c_conn->lock);
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001162 sde_fence_deinit(&c_conn->retire_fence);
Clarence Ipdd8021c2016-07-20 16:39:47 -04001163error_cleanup_conn:
1164 drm_connector_cleanup(&c_conn->base);
1165error_free_conn:
1166 kfree(c_conn);
1167
1168 return ERR_PTR(rc);
1169}
Gopikrishnaiah Anandande2c81b2017-03-15 12:41:29 -07001170
1171int sde_connector_register_custom_event(struct sde_kms *kms,
1172 struct drm_connector *conn_drm, u32 event, bool val)
1173{
Gopikrishnaiah Anandan84b4f672017-04-26 10:28:51 -07001174 int ret = -EINVAL;
1175
1176 switch (event) {
1177 case DRM_EVENT_SYS_BACKLIGHT:
1178 ret = 0;
1179 break;
1180 default:
1181 break;
1182 }
1183 return ret;
Gopikrishnaiah Anandande2c81b2017-03-15 12:41:29 -07001184}