blob: e2d937bed58cf0e583c4a52739e13c05e9c10d50 [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"
Dhaval Patel959fdab2017-08-25 15:15:39 -070015#include "sde_dbg.h"
Clarence Ipdd8021c2016-07-20 16:39:47 -040016
17#include "sde_kms.h"
18#include "sde_connector.h"
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -070019#include "sde_encoder.h"
Dhaval Patel7cdd6662017-03-08 13:10:37 -080020#include <linux/backlight.h>
21#include "dsi_drm.h"
Ping Li898b1bf2017-02-09 18:03:28 -080022#include "dsi_display.h"
Veera Sundaram Sankarandb43e282017-09-19 18:32:52 -070023#include "sde_crtc.h"
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -070024#include "sde_rm.h"
Dhaval Patel7cdd6662017-03-08 13:10:37 -080025
26#define BL_NODE_NAME_SIZE 32
Clarence Ipdd8021c2016-07-20 16:39:47 -040027
Lloyd Atkinson77382202017-02-01 14:59:43 -050028/* Autorefresh will occur after FRAME_CNT frames. Large values are unlikely */
29#define AUTOREFRESH_MAX_FRAME_CNT 6
30
Lloyd Atkinson8ba47032017-03-22 17:13:32 -040031#define SDE_DEBUG_CONN(c, fmt, ...) SDE_DEBUG("conn%d " fmt,\
32 (c) ? (c)->base.base.id : -1, ##__VA_ARGS__)
33
34#define SDE_ERROR_CONN(c, fmt, ...) SDE_ERROR("conn%d " fmt,\
35 (c) ? (c)->base.base.id : -1, ##__VA_ARGS__)
Ping Li8430ee12017-02-24 14:14:44 -080036static u32 dither_matrix[DITHER_MATRIX_SZ] = {
37 15, 7, 13, 5, 3, 11, 1, 9, 12, 4, 14, 6, 0, 8, 2, 10
38};
Lloyd Atkinson8ba47032017-03-22 17:13:32 -040039
Lloyd Atkinsonb6191972016-08-10 18:31:46 -040040static const struct drm_prop_enum_list e_topology_name[] = {
Jeykumar Sankaran2b098072017-03-16 17:25:59 -070041 {SDE_RM_TOPOLOGY_NONE, "sde_none"},
Lloyd Atkinsonb6191972016-08-10 18:31:46 -040042 {SDE_RM_TOPOLOGY_SINGLEPIPE, "sde_singlepipe"},
Jeykumar Sankaran2b098072017-03-16 17:25:59 -070043 {SDE_RM_TOPOLOGY_SINGLEPIPE_DSC, "sde_singlepipe_dsc"},
Lloyd Atkinsonb6191972016-08-10 18:31:46 -040044 {SDE_RM_TOPOLOGY_DUALPIPE, "sde_dualpipe"},
Jeykumar Sankaran2b098072017-03-16 17:25:59 -070045 {SDE_RM_TOPOLOGY_DUALPIPE_DSC, "sde_dualpipe_dsc"},
46 {SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE, "sde_dualpipemerge"},
47 {SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC, "sde_dualpipemerge_dsc"},
48 {SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE, "sde_dualpipe_dscmerge"},
Lloyd Atkinsonb6191972016-08-10 18:31:46 -040049 {SDE_RM_TOPOLOGY_PPSPLIT, "sde_ppsplit"},
Lloyd Atkinsonb6191972016-08-10 18:31:46 -040050};
51static const struct drm_prop_enum_list e_topology_control[] = {
52 {SDE_RM_TOPCTL_RESERVE_LOCK, "reserve_lock"},
53 {SDE_RM_TOPCTL_RESERVE_CLEAR, "reserve_clear"},
54 {SDE_RM_TOPCTL_DSPP, "dspp"},
Lloyd Atkinsonb6191972016-08-10 18:31:46 -040055};
Clarence Ip90b282d2017-05-04 10:00:32 -070056static const struct drm_prop_enum_list e_power_mode[] = {
57 {SDE_MODE_DPMS_ON, "ON"},
58 {SDE_MODE_DPMS_LP1, "LP1"},
59 {SDE_MODE_DPMS_LP2, "LP2"},
60 {SDE_MODE_DPMS_OFF, "OFF"},
61};
Lloyd Atkinsonb6191972016-08-10 18:31:46 -040062
Dhaval Patel7cdd6662017-03-08 13:10:37 -080063static int sde_backlight_device_update_status(struct backlight_device *bd)
64{
65 int brightness;
66 struct dsi_display *display;
67 struct sde_connector *c_conn;
68 int bl_lvl;
Gopikrishnaiah Anandan84b4f672017-04-26 10:28:51 -070069 struct drm_event event;
Dhaval Patel7cdd6662017-03-08 13:10:37 -080070
71 brightness = bd->props.brightness;
72
73 if ((bd->props.power != FB_BLANK_UNBLANK) ||
74 (bd->props.state & BL_CORE_FBBLANK) ||
75 (bd->props.state & BL_CORE_SUSPENDED))
76 brightness = 0;
77
78 c_conn = bl_get_data(bd);
79 display = (struct dsi_display *) c_conn->display;
80 if (brightness > display->panel->bl_config.bl_max_level)
81 brightness = display->panel->bl_config.bl_max_level;
82
83 /* map UI brightness into driver backlight level with rounding */
84 bl_lvl = mult_frac(brightness, display->panel->bl_config.bl_max_level,
85 display->panel->bl_config.brightness_max_level);
86
87 if (!bl_lvl && brightness)
88 bl_lvl = 1;
89
Gopikrishnaiah Anandan84b4f672017-04-26 10:28:51 -070090 if (c_conn->ops.set_backlight) {
91 event.type = DRM_EVENT_SYS_BACKLIGHT;
92 event.length = sizeof(u32);
Benjamin Chan34a92c72017-06-28 11:01:18 -040093 msm_mode_object_event_notify(&c_conn->base.base,
Gopikrishnaiah Anandan84b4f672017-04-26 10:28:51 -070094 c_conn->base.dev, &event, (u8 *)&brightness);
Dhaval Patel7cdd6662017-03-08 13:10:37 -080095 c_conn->ops.set_backlight(c_conn->display, bl_lvl);
Gopikrishnaiah Anandan84b4f672017-04-26 10:28:51 -070096 }
Dhaval Patel7cdd6662017-03-08 13:10:37 -080097
98 return 0;
99}
100
101static int sde_backlight_device_get_brightness(struct backlight_device *bd)
102{
103 return 0;
104}
105
106static const struct backlight_ops sde_backlight_device_ops = {
107 .update_status = sde_backlight_device_update_status,
108 .get_brightness = sde_backlight_device_get_brightness,
109};
110
Shashank Babu Chinta Venkata06c428e2017-04-17 13:52:28 -0700111static int sde_backlight_setup(struct sde_connector *c_conn,
112 struct drm_device *dev)
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800113{
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800114 struct backlight_properties props;
115 struct dsi_display *display;
116 struct dsi_backlight_config *bl_config;
117 static int display_count;
118 char bl_node_name[BL_NODE_NAME_SIZE];
119
Shashank Babu Chinta Venkata06c428e2017-04-17 13:52:28 -0700120 if (!c_conn || !dev || !dev->dev) {
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800121 SDE_ERROR("invalid param\n");
122 return -EINVAL;
123 } else if (c_conn->connector_type != DRM_MODE_CONNECTOR_DSI) {
124 return 0;
125 }
126
127 memset(&props, 0, sizeof(props));
128 props.type = BACKLIGHT_RAW;
129 props.power = FB_BLANK_UNBLANK;
130
131 display = (struct dsi_display *) c_conn->display;
132 bl_config = &display->panel->bl_config;
133 props.max_brightness = bl_config->brightness_max_level;
134 props.brightness = bl_config->brightness_max_level;
135 snprintf(bl_node_name, BL_NODE_NAME_SIZE, "panel%u-backlight",
136 display_count);
Dhaval Patel959fdab2017-08-25 15:15:39 -0700137 c_conn->bl_device = backlight_device_register(bl_node_name, dev->dev,
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800138 c_conn, &sde_backlight_device_ops, &props);
Dhaval Patel959fdab2017-08-25 15:15:39 -0700139 if (IS_ERR_OR_NULL(c_conn->bl_device)) {
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800140 SDE_ERROR("Failed to register backlight: %ld\n",
Dhaval Patel959fdab2017-08-25 15:15:39 -0700141 PTR_ERR(c_conn->bl_device));
142 c_conn->bl_device = NULL;
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800143 return -ENODEV;
144 }
145 display_count++;
146
147 return 0;
148}
149
Clarence Ipa18d4832017-03-13 12:35:44 -0700150int sde_connector_trigger_event(void *drm_connector,
151 uint32_t event_idx, uint32_t instance_idx,
152 uint32_t data0, uint32_t data1,
153 uint32_t data2, uint32_t data3)
154{
155 struct sde_connector *c_conn;
156 unsigned long irq_flags;
Sandeep Panda11b20d82017-06-19 12:57:27 +0530157 int (*cb_func)(uint32_t event_idx,
Clarence Ipa18d4832017-03-13 12:35:44 -0700158 uint32_t instance_idx, void *usr,
159 uint32_t data0, uint32_t data1,
160 uint32_t data2, uint32_t data3);
161 void *usr;
162 int rc = 0;
163
164 /*
165 * This function may potentially be called from an ISR context, so
166 * avoid excessive logging/etc.
167 */
168 if (!drm_connector)
169 return -EINVAL;
170 else if (event_idx >= SDE_CONN_EVENT_COUNT)
171 return -EINVAL;
172 c_conn = to_sde_connector(drm_connector);
173
174 spin_lock_irqsave(&c_conn->event_lock, irq_flags);
175 cb_func = c_conn->event_table[event_idx].cb_func;
176 usr = c_conn->event_table[event_idx].usr;
177 spin_unlock_irqrestore(&c_conn->event_lock, irq_flags);
178
179 if (cb_func)
Sandeep Panda11b20d82017-06-19 12:57:27 +0530180 rc = cb_func(event_idx, instance_idx, usr,
Clarence Ipa18d4832017-03-13 12:35:44 -0700181 data0, data1, data2, data3);
182 else
183 rc = -EAGAIN;
184
185 return rc;
186}
187
188int sde_connector_register_event(struct drm_connector *connector,
189 uint32_t event_idx,
Sandeep Panda11b20d82017-06-19 12:57:27 +0530190 int (*cb_func)(uint32_t event_idx,
Clarence Ipa18d4832017-03-13 12:35:44 -0700191 uint32_t instance_idx, void *usr,
192 uint32_t data0, uint32_t data1,
193 uint32_t data2, uint32_t data3),
194 void *usr)
195{
196 struct sde_connector *c_conn;
197 unsigned long irq_flags;
198
199 if (!connector) {
200 SDE_ERROR("invalid connector\n");
201 return -EINVAL;
202 } else if (event_idx >= SDE_CONN_EVENT_COUNT) {
203 SDE_ERROR("conn%d, invalid event %d\n",
204 connector->base.id, event_idx);
205 return -EINVAL;
206 }
207 c_conn = to_sde_connector(connector);
208
209 spin_lock_irqsave(&c_conn->event_lock, irq_flags);
210 c_conn->event_table[event_idx].cb_func = cb_func;
211 c_conn->event_table[event_idx].usr = usr;
212 spin_unlock_irqrestore(&c_conn->event_lock, irq_flags);
213
214 /* optionally notify display of event registration */
215 if (c_conn->ops.enable_event && c_conn->display)
216 c_conn->ops.enable_event(connector, event_idx,
217 cb_func != NULL, c_conn->display);
218 return 0;
219}
220
221void sde_connector_unregister_event(struct drm_connector *connector,
222 uint32_t event_idx)
223{
224 (void)sde_connector_register_event(connector, event_idx, 0, 0);
225}
226
Ping Li8430ee12017-02-24 14:14:44 -0800227static int _sde_connector_get_default_dither_cfg_v1(
228 struct sde_connector *c_conn, void *cfg)
229{
230 struct drm_msm_dither *dither_cfg = (struct drm_msm_dither *)cfg;
231 enum dsi_pixel_format dst_format = DSI_PIXEL_FORMAT_MAX;
232
233 if (!c_conn || !cfg) {
234 SDE_ERROR("invalid argument(s), c_conn %pK, cfg %pK\n",
235 c_conn, cfg);
236 return -EINVAL;
237 }
238
239 if (!c_conn->ops.get_dst_format) {
Ping Lie0cfec2e2017-07-13 15:28:15 -0700240 SDE_DEBUG("get_dst_format is unavailable\n");
241 return 0;
Ping Li8430ee12017-02-24 14:14:44 -0800242 }
243
244 dst_format = c_conn->ops.get_dst_format(c_conn->display);
245 switch (dst_format) {
246 case DSI_PIXEL_FORMAT_RGB888:
247 dither_cfg->c0_bitdepth = 8;
248 dither_cfg->c1_bitdepth = 8;
249 dither_cfg->c2_bitdepth = 8;
250 dither_cfg->c3_bitdepth = 8;
251 break;
252 case DSI_PIXEL_FORMAT_RGB666:
253 case DSI_PIXEL_FORMAT_RGB666_LOOSE:
254 dither_cfg->c0_bitdepth = 6;
255 dither_cfg->c1_bitdepth = 6;
256 dither_cfg->c2_bitdepth = 6;
257 dither_cfg->c3_bitdepth = 6;
258 break;
259 default:
260 SDE_DEBUG("no default dither config for dst_format %d\n",
261 dst_format);
262 return -ENODATA;
263 }
264
265 memcpy(&dither_cfg->matrix, dither_matrix,
266 sizeof(u32) * DITHER_MATRIX_SZ);
267 dither_cfg->temporal_en = 0;
268 return 0;
269}
270
271static void _sde_connector_install_dither_property(struct drm_device *dev,
272 struct sde_kms *sde_kms, struct sde_connector *c_conn)
273{
274 char prop_name[DRM_PROP_NAME_LEN];
275 struct sde_mdss_cfg *catalog = NULL;
276 struct drm_property_blob *blob_ptr;
277 void *cfg;
278 int ret = 0;
279 u32 version = 0, len = 0;
280 bool defalut_dither_needed = false;
281
282 if (!dev || !sde_kms || !c_conn) {
283 SDE_ERROR("invld args (s), dev %pK, sde_kms %pK, c_conn %pK\n",
284 dev, sde_kms, c_conn);
285 return;
286 }
287
288 catalog = sde_kms->catalog;
289 version = SDE_COLOR_PROCESS_MAJOR(
290 catalog->pingpong[0].sblk->dither.version);
291 snprintf(prop_name, ARRAY_SIZE(prop_name), "%s%d",
292 "SDE_PP_DITHER_V", version);
293 switch (version) {
294 case 1:
295 msm_property_install_blob(&c_conn->property_info, prop_name,
296 DRM_MODE_PROP_BLOB,
297 CONNECTOR_PROP_PP_DITHER);
298 len = sizeof(struct drm_msm_dither);
299 cfg = kzalloc(len, GFP_KERNEL);
300 if (!cfg)
301 return;
302
303 ret = _sde_connector_get_default_dither_cfg_v1(c_conn, cfg);
304 if (!ret)
305 defalut_dither_needed = true;
306 break;
307 default:
308 SDE_ERROR("unsupported dither version %d\n", version);
309 return;
310 }
311
312 if (defalut_dither_needed) {
313 blob_ptr = drm_property_create_blob(dev, len, cfg);
314 if (IS_ERR_OR_NULL(blob_ptr))
315 goto exit;
316 c_conn->blob_dither = blob_ptr;
317 }
318exit:
319 kfree(cfg);
320}
321
322int sde_connector_get_dither_cfg(struct drm_connector *conn,
323 struct drm_connector_state *state, void **cfg,
324 size_t *len)
325{
326 struct sde_connector *c_conn = NULL;
327 struct sde_connector_state *c_state = NULL;
328 size_t dither_sz = 0;
329
330 if (!conn || !state || !(*cfg))
331 return -EINVAL;
332
333 c_conn = to_sde_connector(conn);
334 c_state = to_sde_connector_state(state);
335
336 /* try to get user config data first */
337 *cfg = msm_property_get_blob(&c_conn->property_info,
Clarence Ip4a2955d2017-07-04 18:04:33 -0400338 &c_state->property_state,
Ping Li8430ee12017-02-24 14:14:44 -0800339 &dither_sz,
340 CONNECTOR_PROP_PP_DITHER);
341 /* if user config data doesn't exist, use default dither blob */
342 if (*cfg == NULL && c_conn->blob_dither) {
343 *cfg = &c_conn->blob_dither->data;
344 dither_sz = c_conn->blob_dither->length;
345 }
346 *len = dither_sz;
347 return 0;
348}
349
Jeykumar Sankaran905ba332017-10-19 10:45:02 -0700350int sde_connector_get_mode_info(struct drm_connector_state *conn_state,
351 struct msm_mode_info *mode_info)
352{
353 struct sde_connector_state *sde_conn_state = NULL;
354
355 if (!conn_state || !mode_info) {
356 SDE_ERROR("Invalid arguments\n");
357 return -EINVAL;
358 }
359
360 sde_conn_state = to_sde_connector_state(conn_state);
361 memcpy(mode_info, &sde_conn_state->mode_info,
362 sizeof(sde_conn_state->mode_info));
363
364 return 0;
365}
366
Sandeep Panda11b20d82017-06-19 12:57:27 +0530367static int sde_connector_handle_disp_recovery(uint32_t event_idx,
368 uint32_t instance_idx, void *usr,
369 uint32_t data0, uint32_t data1,
370 uint32_t data2, uint32_t data3)
371{
372 struct sde_connector *c_conn = usr;
373 int rc = 0;
374
375 if (!c_conn)
376 return -EINVAL;
377
378 rc = sde_kms_handle_recovery(c_conn->encoder);
379
380 return rc;
381}
382
Clarence Ipcb3afd42016-07-15 16:25:34 -0400383int sde_connector_get_info(struct drm_connector *connector,
384 struct msm_display_info *info)
385{
386 struct sde_connector *c_conn;
387
388 if (!connector || !info) {
389 SDE_ERROR("invalid argument(s), conn %pK, info %pK\n",
390 connector, info);
391 return -EINVAL;
392 }
393
394 c_conn = to_sde_connector(connector);
395
396 if (!c_conn->display || !c_conn->ops.get_info) {
397 SDE_ERROR("display info not supported for %pK\n",
398 c_conn->display);
399 return -EINVAL;
400 }
401
402 return c_conn->ops.get_info(info, c_conn->display);
403}
404
Sandeep Panda98d6ab22017-09-05 08:03:16 +0530405void sde_connector_schedule_status_work(struct drm_connector *connector,
406 bool en)
407{
408 struct sde_connector *c_conn;
409 struct msm_display_info info;
410
411 c_conn = to_sde_connector(connector);
412 if (!c_conn)
413 return;
414
415 sde_connector_get_info(connector, &info);
416 if (c_conn->ops.check_status &&
417 (info.capabilities & MSM_DISPLAY_ESD_ENABLED)) {
418 if (en)
419 /* Schedule ESD status check */
420 schedule_delayed_work(&c_conn->status_work,
421 msecs_to_jiffies(STATUS_CHECK_INTERVAL_MS));
422 else
423 /* Cancel any pending ESD status check */
424 cancel_delayed_work_sync(&c_conn->status_work);
425 }
426}
427
Clarence Ip458a5d02017-11-27 18:15:16 -0500428void sde_connector_helper_bridge_disable(struct drm_connector *connector)
429{
430 int rc;
431
432 if (!connector)
433 return;
434
435 /* trigger a final connector pre-kickoff for power mode updates */
436 rc = sde_connector_pre_kickoff(connector);
437 if (rc)
438 SDE_ERROR("conn %d final pre kickoff failed %d\n",
439 connector->base.id, rc);
440}
441
Clarence Ip380b8dc2017-07-27 18:16:13 -0400442static int _sde_connector_update_power_locked(struct sde_connector *c_conn)
443{
444 struct drm_connector *connector;
445 void *display;
446 int (*set_power)(struct drm_connector *, int, void *);
447 int mode, rc = 0;
448
449 if (!c_conn)
450 return -EINVAL;
451 connector = &c_conn->base;
452
453 switch (c_conn->dpms_mode) {
454 case DRM_MODE_DPMS_ON:
455 mode = c_conn->lp_mode;
456 break;
457 case DRM_MODE_DPMS_STANDBY:
458 mode = SDE_MODE_DPMS_STANDBY;
459 break;
460 case DRM_MODE_DPMS_SUSPEND:
461 mode = SDE_MODE_DPMS_SUSPEND;
462 break;
463 case DRM_MODE_DPMS_OFF:
464 mode = SDE_MODE_DPMS_OFF;
465 break;
466 default:
467 mode = c_conn->lp_mode;
468 SDE_ERROR("conn %d dpms set to unrecognized mode %d\n",
469 connector->base.id, mode);
470 break;
471 }
472
473 SDE_EVT32(connector->base.id, c_conn->dpms_mode, c_conn->lp_mode, mode);
474 SDE_DEBUG("conn %d - dpms %d, lp %d, panel %d\n", connector->base.id,
475 c_conn->dpms_mode, c_conn->lp_mode, mode);
476
477 if (mode != c_conn->last_panel_power_mode && c_conn->ops.set_power) {
478 display = c_conn->display;
479 set_power = c_conn->ops.set_power;
480
481 mutex_unlock(&c_conn->lock);
482 rc = set_power(connector, mode, display);
483 mutex_lock(&c_conn->lock);
484 }
485 c_conn->last_panel_power_mode = mode;
486
Sandeep Panda98d6ab22017-09-05 08:03:16 +0530487 if (mode != SDE_MODE_DPMS_ON)
488 sde_connector_schedule_status_work(connector, false);
489
Clarence Ip380b8dc2017-07-27 18:16:13 -0400490 return rc;
491}
492
Xu Yang92377312017-11-23 13:48:08 +0800493static int _sde_connector_update_bl_scale(struct sde_connector *c_conn)
Xu Yang7c42a702017-10-17 10:50:17 +0800494{
Xu Yang7c42a702017-10-17 10:50:17 +0800495 struct dsi_display *dsi_display;
496 struct dsi_backlight_config *bl_config;
Xu Yang7c42a702017-10-17 10:50:17 +0800497 int rc = 0;
498
499 if (!c_conn) {
500 SDE_ERROR("Invalid params sde_connector null\n");
501 return -EINVAL;
502 }
503
Xu Yang7c42a702017-10-17 10:50:17 +0800504 dsi_display = c_conn->display;
505 if (!dsi_display || !dsi_display->panel) {
506 SDE_ERROR("Invalid params(s) dsi_display %pK, panel %pK\n",
507 dsi_display,
508 ((dsi_display) ? dsi_display->panel : NULL));
509 return -EINVAL;
510 }
511
512 bl_config = &dsi_display->panel->bl_config;
Xu Yang7c42a702017-10-17 10:50:17 +0800513
Xu Yang92377312017-11-23 13:48:08 +0800514 if (c_conn->bl_scale > MAX_BL_SCALE_LEVEL)
515 bl_config->bl_scale = MAX_BL_SCALE_LEVEL;
516 else
517 bl_config->bl_scale = c_conn->bl_scale;
518
519 if (c_conn->bl_scale_ad > MAX_AD_BL_SCALE_LEVEL)
520 bl_config->bl_scale_ad = MAX_AD_BL_SCALE_LEVEL;
521 else
522 bl_config->bl_scale_ad = c_conn->bl_scale_ad;
Xu Yang7c42a702017-10-17 10:50:17 +0800523
524 SDE_DEBUG("bl_scale = %u, bl_scale_ad = %u, bl_level = %u\n",
525 bl_config->bl_scale, bl_config->bl_scale_ad,
526 bl_config->bl_level);
527 rc = c_conn->ops.set_backlight(dsi_display, bl_config->bl_level);
528
529 return rc;
530}
531
Lloyd Atkinson05d75512017-01-17 14:45:51 -0500532int sde_connector_pre_kickoff(struct drm_connector *connector)
533{
534 struct sde_connector *c_conn;
535 struct sde_connector_state *c_state;
536 struct msm_display_kickoff_params params;
Clarence Ip380b8dc2017-07-27 18:16:13 -0400537 int idx, rc;
Lloyd Atkinson05d75512017-01-17 14:45:51 -0500538
539 if (!connector) {
540 SDE_ERROR("invalid argument\n");
541 return -EINVAL;
542 }
543
544 c_conn = to_sde_connector(connector);
545 c_state = to_sde_connector_state(connector->state);
546
547 if (!c_conn->display) {
548 SDE_ERROR("invalid argument\n");
549 return -EINVAL;
550 }
551
Clarence Ip380b8dc2017-07-27 18:16:13 -0400552 while ((idx = msm_property_pop_dirty(&c_conn->property_info,
553 &c_state->property_state)) >= 0) {
554 switch (idx) {
555 case CONNECTOR_PROP_LP:
556 mutex_lock(&c_conn->lock);
557 c_conn->lp_mode = sde_connector_get_property(
558 connector->state, CONNECTOR_PROP_LP);
559 _sde_connector_update_power_locked(c_conn);
560 mutex_unlock(&c_conn->lock);
561 break;
Xu Yang7c42a702017-10-17 10:50:17 +0800562 case CONNECTOR_PROP_BL_SCALE:
563 case CONNECTOR_PROP_AD_BL_SCALE:
Xu Yang92377312017-11-23 13:48:08 +0800564 _sde_connector_update_bl_scale(c_conn);
Xu Yang7c42a702017-10-17 10:50:17 +0800565 break;
Clarence Ip380b8dc2017-07-27 18:16:13 -0400566 default:
567 /* nothing to do for most properties */
568 break;
569 }
570 }
571
Xu Yang92377312017-11-23 13:48:08 +0800572 /* Special handling for postproc properties */
573 if (c_conn->bl_scale_dirty) {
574 _sde_connector_update_bl_scale(c_conn);
575 c_conn->bl_scale_dirty = false;
576 }
577
Lloyd Atkinson05d75512017-01-17 14:45:51 -0500578 if (!c_conn->ops.pre_kickoff)
579 return 0;
580
581 params.rois = &c_state->rois;
Ajay Singh Parmare927aa42017-11-01 00:33:20 -0700582 params.hdr_meta = &c_state->hdr_meta;
Lloyd Atkinson05d75512017-01-17 14:45:51 -0500583
584 SDE_EVT32_VERBOSE(connector->base.id);
585
586 rc = c_conn->ops.pre_kickoff(connector, c_conn->display, &params);
587
588 return rc;
589}
590
Alan Kwong1124f1f2017-11-10 18:14:39 -0500591int sde_connector_clk_ctrl(struct drm_connector *connector, bool enable)
Veera Sundaram Sankaranbb2bf9a2017-03-29 18:56:47 -0700592{
593 struct sde_connector *c_conn;
594 struct dsi_display *display;
595 u32 state = enable ? DSI_CLK_ON : DSI_CLK_OFF;
Alan Kwong1124f1f2017-11-10 18:14:39 -0500596 int rc = 0;
Veera Sundaram Sankaranbb2bf9a2017-03-29 18:56:47 -0700597
598 if (!connector) {
599 SDE_ERROR("invalid connector\n");
Alan Kwong1124f1f2017-11-10 18:14:39 -0500600 return -EINVAL;
Veera Sundaram Sankaranbb2bf9a2017-03-29 18:56:47 -0700601 }
602
603 c_conn = to_sde_connector(connector);
604 display = (struct dsi_display *) c_conn->display;
605
606 if (display && c_conn->ops.clk_ctrl)
Alan Kwong1124f1f2017-11-10 18:14:39 -0500607 rc = c_conn->ops.clk_ctrl(display->mdp_clk_handle,
Veera Sundaram Sankaranbb2bf9a2017-03-29 18:56:47 -0700608 DSI_ALL_CLKS, state);
Alan Kwong1124f1f2017-11-10 18:14:39 -0500609
610 return rc;
Veera Sundaram Sankaranbb2bf9a2017-03-29 18:56:47 -0700611}
612
Clarence Ipdd8021c2016-07-20 16:39:47 -0400613static void sde_connector_destroy(struct drm_connector *connector)
614{
615 struct sde_connector *c_conn;
616
617 if (!connector) {
618 SDE_ERROR("invalid connector\n");
619 return;
620 }
621
622 c_conn = to_sde_connector(connector);
623
Sandeep Panda98d6ab22017-09-05 08:03:16 +0530624 /* cancel if any pending esd work */
625 sde_connector_schedule_status_work(connector, false);
626
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -0700627 if (c_conn->ops.put_modes)
628 c_conn->ops.put_modes(connector, c_conn->display);
629
Dhaval Patel4e574842016-08-23 15:11:37 -0700630 if (c_conn->blob_caps)
631 drm_property_unreference_blob(c_conn->blob_caps);
Ping Li898b1bf2017-02-09 18:03:28 -0800632 if (c_conn->blob_hdr)
633 drm_property_unreference_blob(c_conn->blob_hdr);
Ping Li8430ee12017-02-24 14:14:44 -0800634 if (c_conn->blob_dither)
635 drm_property_unreference_blob(c_conn->blob_dither);
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -0700636 if (c_conn->blob_mode_info)
637 drm_property_unreference_blob(c_conn->blob_mode_info);
Ajay Singh Parmar4dabdfc2017-11-09 16:54:25 -0800638 if (c_conn->blob_ext_hdr)
639 drm_property_unreference_blob(c_conn->blob_ext_hdr);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400640 msm_property_destroy(&c_conn->property_info);
641
Dhaval Patel959fdab2017-08-25 15:15:39 -0700642 if (c_conn->bl_device)
643 backlight_device_unregister(c_conn->bl_device);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400644 drm_connector_unregister(connector);
Clarence Ip90b282d2017-05-04 10:00:32 -0700645 mutex_destroy(&c_conn->lock);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400646 sde_fence_deinit(&c_conn->retire_fence);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400647 drm_connector_cleanup(connector);
648 kfree(c_conn);
649}
650
651/**
652 * _sde_connector_destroy_fb - clean up connector state's out_fb buffer
653 * @c_conn: Pointer to sde connector structure
654 * @c_state: Pointer to sde connector state structure
655 */
656static void _sde_connector_destroy_fb(struct sde_connector *c_conn,
657 struct sde_connector_state *c_state)
658{
659 if (!c_state || !c_state->out_fb) {
660 SDE_ERROR("invalid state %pK\n", c_state);
661 return;
662 }
663
Clarence Ipdd8021c2016-07-20 16:39:47 -0400664 drm_framebuffer_unreference(c_state->out_fb);
665 c_state->out_fb = NULL;
666
Clarence Ip4a2955d2017-07-04 18:04:33 -0400667 if (c_conn)
668 c_state->property_values[CONNECTOR_PROP_OUT_FB].value =
Clarence Ipdd8021c2016-07-20 16:39:47 -0400669 msm_property_get_default(&c_conn->property_info,
670 CONNECTOR_PROP_OUT_FB);
Clarence Ip4a2955d2017-07-04 18:04:33 -0400671 else
672 c_state->property_values[CONNECTOR_PROP_OUT_FB].value = ~0;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400673}
674
675static void sde_connector_atomic_destroy_state(struct drm_connector *connector,
676 struct drm_connector_state *state)
677{
678 struct sde_connector *c_conn = NULL;
679 struct sde_connector_state *c_state = NULL;
680
681 if (!state) {
682 SDE_ERROR("invalid state\n");
683 return;
684 }
685
686 /*
687 * The base DRM framework currently always passes in a NULL
688 * connector pointer. This is not correct, but attempt to
689 * handle that case as much as possible.
690 */
691 if (connector)
692 c_conn = to_sde_connector(connector);
693 c_state = to_sde_connector_state(state);
694
695 if (c_state->out_fb)
696 _sde_connector_destroy_fb(c_conn, c_state);
697
Clarence Ipb2c4fd62017-09-21 17:28:38 -0400698 __drm_atomic_helper_connector_destroy_state(&c_state->base);
699
Clarence Ipdd8021c2016-07-20 16:39:47 -0400700 if (!c_conn) {
701 kfree(c_state);
702 } else {
703 /* destroy value helper */
704 msm_property_destroy_state(&c_conn->property_info, c_state,
Clarence Ip4a2955d2017-07-04 18:04:33 -0400705 &c_state->property_state);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400706 }
707}
708
709static void sde_connector_atomic_reset(struct drm_connector *connector)
710{
711 struct sde_connector *c_conn;
712 struct sde_connector_state *c_state;
713
714 if (!connector) {
715 SDE_ERROR("invalid connector\n");
716 return;
717 }
718
719 c_conn = to_sde_connector(connector);
720
Veera Sundaram Sankarandb43e282017-09-19 18:32:52 -0700721 if (connector->state &&
722 !sde_crtc_is_reset_required(connector->state->crtc)) {
723 SDE_DEBUG_CONN(c_conn, "avoid reset for connector\n");
724 return;
725 }
726
Clarence Ipdd8021c2016-07-20 16:39:47 -0400727 if (connector->state) {
728 sde_connector_atomic_destroy_state(connector, connector->state);
729 connector->state = 0;
730 }
731
732 c_state = msm_property_alloc_state(&c_conn->property_info);
733 if (!c_state) {
734 SDE_ERROR("state alloc failed\n");
735 return;
736 }
737
738 /* reset value helper, zero out state structure and reset properties */
739 msm_property_reset_state(&c_conn->property_info, c_state,
Clarence Ip4a2955d2017-07-04 18:04:33 -0400740 &c_state->property_state,
741 c_state->property_values);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400742
Clarence Ipb2c4fd62017-09-21 17:28:38 -0400743 __drm_atomic_helper_connector_reset(connector, &c_state->base);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400744}
745
746static struct drm_connector_state *
747sde_connector_atomic_duplicate_state(struct drm_connector *connector)
748{
749 struct sde_connector *c_conn;
750 struct sde_connector_state *c_state, *c_oldstate;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400751
752 if (!connector || !connector->state) {
753 SDE_ERROR("invalid connector %pK\n", connector);
754 return NULL;
755 }
756
757 c_conn = to_sde_connector(connector);
758 c_oldstate = to_sde_connector_state(connector->state);
759 c_state = msm_property_alloc_state(&c_conn->property_info);
760 if (!c_state) {
761 SDE_ERROR("state alloc failed\n");
762 return NULL;
763 }
764
765 /* duplicate value helper */
766 msm_property_duplicate_state(&c_conn->property_info,
Clarence Ip4a2955d2017-07-04 18:04:33 -0400767 c_oldstate, c_state,
768 &c_state->property_state, c_state->property_values);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400769
Clarence Ipb2c4fd62017-09-21 17:28:38 -0400770 __drm_atomic_helper_connector_duplicate_state(connector,
771 &c_state->base);
772
Clarence Ipdd8021c2016-07-20 16:39:47 -0400773 /* additional handling for drm framebuffer objects */
Alan Kwong03b89842017-08-17 16:32:45 -0400774 if (c_state->out_fb)
Clarence Ipdd8021c2016-07-20 16:39:47 -0400775 drm_framebuffer_reference(c_state->out_fb);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400776
777 return &c_state->base;
778}
779
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -0700780int sde_connector_roi_v1_check_roi(struct drm_connector_state *conn_state)
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400781{
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -0700782 const struct msm_roi_alignment *align = NULL;
783 struct sde_connector *c_conn = NULL;
784 struct msm_mode_info mode_info;
785 struct sde_connector_state *c_state;
Jeykumar Sankaran905ba332017-10-19 10:45:02 -0700786 int i, w, h;
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400787
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -0700788 if (!conn_state)
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400789 return -EINVAL;
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -0700790
791 memset(&mode_info, 0, sizeof(mode_info));
792
793 c_state = to_sde_connector_state(conn_state);
794 c_conn = to_sde_connector(conn_state->connector);
795
Jeykumar Sankaran905ba332017-10-19 10:45:02 -0700796 memcpy(&mode_info, &c_state->mode_info, sizeof(c_state->mode_info));
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400797
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -0700798 if (!mode_info.roi_caps.enabled)
799 return 0;
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400800
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -0700801 if (c_state->rois.num_rects > mode_info.roi_caps.num_roi) {
802 SDE_ERROR_CONN(c_conn, "too many rects specified: %d > %d\n",
803 c_state->rois.num_rects,
804 mode_info.roi_caps.num_roi);
805 return -E2BIG;
806 };
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400807
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -0700808 align = &mode_info.roi_caps.align;
809 for (i = 0; i < c_state->rois.num_rects; ++i) {
810 struct drm_clip_rect *roi_conn;
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400811
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -0700812 roi_conn = &c_state->rois.roi[i];
813 w = roi_conn->x2 - roi_conn->x1;
814 h = roi_conn->y2 - roi_conn->y1;
815
Lloyd Atkinson5ca13aa2017-10-26 18:12:20 -0400816 SDE_EVT32_VERBOSE(DRMID(&c_conn->base),
817 roi_conn->x1, roi_conn->y1,
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -0700818 roi_conn->x2, roi_conn->y2);
819
820 if (w <= 0 || h <= 0) {
821 SDE_ERROR_CONN(c_conn, "invalid conn roi w %d h %d\n",
822 w, h);
823 return -EINVAL;
824 }
825
826 if (w < align->min_width || w % align->width_pix_align) {
827 SDE_ERROR_CONN(c_conn,
828 "invalid conn roi width %d min %d align %d\n",
829 w, align->min_width,
830 align->width_pix_align);
831 return -EINVAL;
832 }
833
834 if (h < align->min_height || h % align->height_pix_align) {
835 SDE_ERROR_CONN(c_conn,
836 "invalid conn roi height %d min %d align %d\n",
837 h, align->min_height,
838 align->height_pix_align);
839 return -EINVAL;
840 }
841
842 if (roi_conn->x1 % align->xstart_pix_align) {
843 SDE_ERROR_CONN(c_conn,
844 "invalid conn roi x1 %d align %d\n",
845 roi_conn->x1, align->xstart_pix_align);
846 return -EINVAL;
847 }
848
849 if (roi_conn->y1 % align->ystart_pix_align) {
850 SDE_ERROR_CONN(c_conn,
851 "invalid conn roi y1 %d align %d\n",
852 roi_conn->y1, align->ystart_pix_align);
853 return -EINVAL;
854 }
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400855 }
856
857 return 0;
858}
859
860static int _sde_connector_set_roi_v1(
861 struct sde_connector *c_conn,
862 struct sde_connector_state *c_state,
863 void *usr_ptr)
864{
865 struct sde_drm_roi_v1 roi_v1;
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -0700866 int i;
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400867
868 if (!c_conn || !c_state) {
869 SDE_ERROR("invalid args\n");
870 return -EINVAL;
871 }
872
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400873 memset(&c_state->rois, 0, sizeof(c_state->rois));
874
875 if (!usr_ptr) {
876 SDE_DEBUG_CONN(c_conn, "rois cleared\n");
877 return 0;
878 }
879
880 if (copy_from_user(&roi_v1, usr_ptr, sizeof(roi_v1))) {
881 SDE_ERROR_CONN(c_conn, "failed to copy roi_v1 data\n");
882 return -EINVAL;
883 }
884
885 SDE_DEBUG_CONN(c_conn, "num_rects %d\n", roi_v1.num_rects);
886
887 if (roi_v1.num_rects == 0) {
888 SDE_DEBUG_CONN(c_conn, "rois cleared\n");
889 return 0;
890 }
891
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -0700892 if (roi_v1.num_rects > SDE_MAX_ROI_V1) {
893 SDE_ERROR_CONN(c_conn, "num roi rects more than supported: %d",
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400894 roi_v1.num_rects);
895 return -EINVAL;
896 }
897
898 c_state->rois.num_rects = roi_v1.num_rects;
899 for (i = 0; i < roi_v1.num_rects; ++i) {
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400900 c_state->rois.roi[i] = roi_v1.roi[i];
Lloyd Atkinsonab5e2b62017-05-09 13:06:51 -0400901 SDE_DEBUG_CONN(c_conn, "roi%d: roi (%d,%d) (%d,%d)\n", i,
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400902 c_state->rois.roi[i].x1,
903 c_state->rois.roi[i].y1,
904 c_state->rois.roi[i].x2,
905 c_state->rois.roi[i].y2);
906 }
907
908 return 0;
909}
910
Ajay Singh Parmare927aa42017-11-01 00:33:20 -0700911static int _sde_connector_set_ext_hdr_info(
912 struct sde_connector *c_conn,
913 struct sde_connector_state *c_state,
914 void *usr_ptr)
915{
916 struct drm_connector *connector;
917 struct drm_msm_ext_hdr_metadata *hdr_meta;
918 int i;
919
920 if (!c_conn || !c_state) {
921 SDE_ERROR_CONN(c_conn, "invalid args\n");
922 return -EINVAL;
923 }
924
925 connector = &c_conn->base;
926
927 if (!connector->hdr_supported) {
928 SDE_ERROR_CONN(c_conn, "sink doesn't support HDR\n");
929 return -ENOTSUPP;
930 }
931
932 memset(&c_state->hdr_meta, 0, sizeof(c_state->hdr_meta));
933
934 if (!usr_ptr) {
935 SDE_DEBUG_CONN(c_conn, "hdr metadata cleared\n");
936 return 0;
937 }
938
939 if (copy_from_user(&c_state->hdr_meta,
940 (void __user *)usr_ptr,
941 sizeof(*hdr_meta))) {
942 SDE_ERROR_CONN(c_conn, "failed to copy hdr metadata\n");
943 return -EFAULT;
944 }
945
946 hdr_meta = &c_state->hdr_meta;
947
948 SDE_DEBUG_CONN(c_conn, "hdr_state %d\n", hdr_meta->hdr_state);
949 SDE_DEBUG_CONN(c_conn, "hdr_supported %d\n", hdr_meta->hdr_supported);
950 SDE_DEBUG_CONN(c_conn, "eotf %d\n", hdr_meta->eotf);
951 SDE_DEBUG_CONN(c_conn, "white_point_x %d\n", hdr_meta->white_point_x);
952 SDE_DEBUG_CONN(c_conn, "white_point_y %d\n", hdr_meta->white_point_y);
953 SDE_DEBUG_CONN(c_conn, "max_luminance %d\n", hdr_meta->max_luminance);
954 SDE_DEBUG_CONN(c_conn, "max_content_light_level %d\n",
955 hdr_meta->max_content_light_level);
956 SDE_DEBUG_CONN(c_conn, "max_average_light_level %d\n",
957 hdr_meta->max_average_light_level);
958
959 for (i = 0; i < HDR_PRIMARIES_COUNT; i++) {
960 SDE_DEBUG_CONN(c_conn, "display_primaries_x [%d]\n",
961 hdr_meta->display_primaries_x[i]);
962 SDE_DEBUG_CONN(c_conn, "display_primaries_y [%d]\n",
963 hdr_meta->display_primaries_y[i]);
964 }
965
966 return 0;
967}
968
Clarence Ipdd8021c2016-07-20 16:39:47 -0400969static int sde_connector_atomic_set_property(struct drm_connector *connector,
970 struct drm_connector_state *state,
971 struct drm_property *property,
972 uint64_t val)
973{
974 struct sde_connector *c_conn;
975 struct sde_connector_state *c_state;
976 int idx, rc;
Dhaval Patelb24b2d62017-11-03 18:10:26 -0700977 uint64_t fence_fd;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400978
979 if (!connector || !state || !property) {
980 SDE_ERROR("invalid argument(s), conn %pK, state %pK, prp %pK\n",
981 connector, state, property);
982 return -EINVAL;
983 }
984
985 c_conn = to_sde_connector(connector);
986 c_state = to_sde_connector_state(state);
987
988 /* generic property handling */
989 rc = msm_property_atomic_set(&c_conn->property_info,
Clarence Ip4a2955d2017-07-04 18:04:33 -0400990 &c_state->property_state, property, val);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400991 if (rc)
992 goto end;
993
994 /* connector-specific property handling */
995 idx = msm_property_index(&c_conn->property_info, property);
Clarence Ip90b282d2017-05-04 10:00:32 -0700996 switch (idx) {
997 case CONNECTOR_PROP_OUT_FB:
Clarence Ipdd8021c2016-07-20 16:39:47 -0400998 /* clear old fb, if present */
999 if (c_state->out_fb)
1000 _sde_connector_destroy_fb(c_conn, c_state);
1001
1002 /* convert fb val to drm framebuffer and prepare it */
1003 c_state->out_fb =
1004 drm_framebuffer_lookup(connector->dev, val);
Alan Kwongae1b1142017-03-05 16:07:10 -08001005 if (!c_state->out_fb && val) {
Clarence Ipdd8021c2016-07-20 16:39:47 -04001006 SDE_ERROR("failed to look up fb %lld\n", val);
1007 rc = -EFAULT;
Alan Kwongae1b1142017-03-05 16:07:10 -08001008 } else if (!c_state->out_fb && !val) {
1009 SDE_DEBUG("cleared fb_id\n");
1010 rc = 0;
Clarence Ipdd8021c2016-07-20 16:39:47 -04001011 } else {
Alan Kwong578cdaf2017-01-28 17:25:43 -08001012 msm_framebuffer_set_kmap(c_state->out_fb,
1013 c_conn->fb_kmap);
Clarence Ipdd8021c2016-07-20 16:39:47 -04001014 }
Clarence Ip90b282d2017-05-04 10:00:32 -07001015 break;
Dhaval Patelb24b2d62017-11-03 18:10:26 -07001016 case CONNECTOR_PROP_RETIRE_FENCE:
Dhaval Pateladbac6f2017-11-16 17:16:18 -08001017 if (!val)
1018 goto end;
1019
Dhaval Patelb24b2d62017-11-03 18:10:26 -07001020 rc = sde_fence_create(&c_conn->retire_fence, &fence_fd, 0);
1021 if (rc) {
1022 SDE_ERROR("fence create failed rc:%d\n", rc);
1023 goto end;
1024 }
Lloyd Atkinson11f34442016-08-11 11:19:52 -04001025
Dhaval Patelb24b2d62017-11-03 18:10:26 -07001026 rc = copy_to_user((uint64_t __user *)val, &fence_fd,
1027 sizeof(uint64_t));
1028 if (rc) {
1029 SDE_ERROR("copy to user failed rc:%d\n", rc);
1030 /* fence will be released with timeline update */
1031 put_unused_fd(fence_fd);
1032 rc = -EFAULT;
1033 goto end;
1034 }
1035 break;
1036 case CONNECTOR_PROP_ROI_V1:
Lloyd Atkinson8ba47032017-03-22 17:13:32 -04001037 rc = _sde_connector_set_roi_v1(c_conn, c_state, (void *)val);
1038 if (rc)
1039 SDE_ERROR_CONN(c_conn, "invalid roi_v1, rc: %d\n", rc);
Dhaval Patelb24b2d62017-11-03 18:10:26 -07001040 break;
Xu Yang92377312017-11-23 13:48:08 +08001041 /* CONNECTOR_PROP_BL_SCALE and CONNECTOR_PROP_AD_BL_SCALE are
1042 * color-processing properties. These two properties require
1043 * special handling since they don't quite fit the current standard
1044 * atomic set property framework.
1045 */
1046 case CONNECTOR_PROP_BL_SCALE:
1047 c_conn->bl_scale = val;
1048 c_conn->bl_scale_dirty = true;
1049 break;
1050 case CONNECTOR_PROP_AD_BL_SCALE:
1051 c_conn->bl_scale_ad = val;
1052 c_conn->bl_scale_dirty = true;
1053 break;
Dhaval Patelb24b2d62017-11-03 18:10:26 -07001054 default:
1055 break;
Lloyd Atkinson8ba47032017-03-22 17:13:32 -04001056 }
1057
Ajay Singh Parmare927aa42017-11-01 00:33:20 -07001058 if (idx == CONNECTOR_PROP_HDR_METADATA) {
1059 rc = _sde_connector_set_ext_hdr_info(c_conn,
1060 c_state, (void *)val);
1061 if (rc)
1062 SDE_ERROR_CONN(c_conn, "cannot set hdr info %d\n", rc);
1063 }
1064
Clarence Ipdd8021c2016-07-20 16:39:47 -04001065 /* check for custom property handling */
1066 if (!rc && c_conn->ops.set_property) {
1067 rc = c_conn->ops.set_property(connector,
1068 state,
1069 idx,
1070 val,
1071 c_conn->display);
1072
1073 /* potentially clean up out_fb if rc != 0 */
1074 if ((idx == CONNECTOR_PROP_OUT_FB) && rc)
1075 _sde_connector_destroy_fb(c_conn, c_state);
1076 }
1077end:
1078 return rc;
1079}
1080
1081static int sde_connector_set_property(struct drm_connector *connector,
1082 struct drm_property *property,
1083 uint64_t val)
1084{
1085 if (!connector) {
1086 SDE_ERROR("invalid connector\n");
1087 return -EINVAL;
1088 }
1089
1090 return sde_connector_atomic_set_property(connector,
1091 connector->state, property, val);
1092}
1093
1094static int sde_connector_atomic_get_property(struct drm_connector *connector,
1095 const struct drm_connector_state *state,
1096 struct drm_property *property,
1097 uint64_t *val)
1098{
1099 struct sde_connector *c_conn;
1100 struct sde_connector_state *c_state;
1101 int idx, rc = -EINVAL;
1102
1103 if (!connector || !state) {
1104 SDE_ERROR("invalid argument(s), conn %pK, state %pK\n",
1105 connector, state);
1106 return -EINVAL;
1107 }
1108
1109 c_conn = to_sde_connector(connector);
1110 c_state = to_sde_connector_state(state);
1111
1112 idx = msm_property_index(&c_conn->property_info, property);
Dhaval Patel1f5a5a22017-11-06 23:06:09 -08001113 if (idx == CONNECTOR_PROP_RETIRE_FENCE) {
1114 *val = ~0;
1115 rc = 0;
1116 } else {
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001117 /* get cached property value */
1118 rc = msm_property_atomic_get(&c_conn->property_info,
Clarence Ip4a2955d2017-07-04 18:04:33 -04001119 &c_state->property_state, property, val);
Dhaval Patel1f5a5a22017-11-06 23:06:09 -08001120 }
Clarence Ipdd8021c2016-07-20 16:39:47 -04001121
1122 /* allow for custom override */
1123 if (c_conn->ops.get_property)
1124 rc = c_conn->ops.get_property(connector,
1125 (struct drm_connector_state *)state,
1126 idx,
1127 val,
1128 c_conn->display);
1129 return rc;
1130}
1131
Dhaval Patel2a3c37a2017-10-25 12:30:36 -07001132void sde_conn_timeline_status(struct drm_connector *conn)
1133{
1134 struct sde_connector *c_conn;
1135
1136 if (!conn) {
1137 SDE_ERROR("invalid connector\n");
1138 return;
1139 }
1140
1141 c_conn = to_sde_connector(conn);
1142 sde_fence_timeline_status(&c_conn->retire_fence, &conn->base);
1143}
1144
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001145void sde_connector_prepare_fence(struct drm_connector *connector)
1146{
1147 if (!connector) {
1148 SDE_ERROR("invalid connector\n");
1149 return;
1150 }
1151
1152 sde_fence_prepare(&to_sde_connector(connector)->retire_fence);
1153}
1154
Veera Sundaram Sankaran675ff622017-06-21 21:44:46 -07001155void sde_connector_complete_commit(struct drm_connector *connector,
1156 ktime_t ts)
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001157{
1158 if (!connector) {
1159 SDE_ERROR("invalid connector\n");
1160 return;
1161 }
1162
1163 /* signal connector's retire fence */
Dhaval Patelfd8f7742017-08-10 13:11:22 -07001164 sde_fence_signal(&to_sde_connector(connector)->retire_fence, ts, false);
1165}
1166
1167void sde_connector_commit_reset(struct drm_connector *connector, ktime_t ts)
1168{
1169 if (!connector) {
1170 SDE_ERROR("invalid connector\n");
1171 return;
1172 }
1173
1174 /* signal connector's retire fence */
1175 sde_fence_signal(&to_sde_connector(connector)->retire_fence, ts, true);
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001176}
1177
Srikanth Rajagopalan30384d12017-06-08 15:23:31 -07001178static void sde_connector_update_hdr_props(struct drm_connector *connector)
1179{
1180 struct sde_connector *c_conn = to_sde_connector(connector);
1181 struct drm_msm_ext_hdr_properties hdr = {};
1182
1183 hdr.hdr_supported = connector->hdr_supported;
1184
1185 if (hdr.hdr_supported) {
1186 hdr.hdr_eotf = connector->hdr_eotf;
1187 hdr.hdr_metadata_type_one = connector->hdr_metadata_type_one;
1188 hdr.hdr_max_luminance = connector->hdr_max_luminance;
1189 hdr.hdr_avg_luminance = connector->hdr_avg_luminance;
1190 hdr.hdr_min_luminance = connector->hdr_min_luminance;
1191
1192 msm_property_set_blob(&c_conn->property_info,
1193 &c_conn->blob_ext_hdr,
1194 &hdr,
1195 sizeof(hdr),
1196 CONNECTOR_PROP_EXT_HDR_INFO);
1197
1198 }
1199}
1200
Clarence Ipdd8021c2016-07-20 16:39:47 -04001201static enum drm_connector_status
1202sde_connector_detect(struct drm_connector *connector, bool force)
1203{
1204 enum drm_connector_status status = connector_status_unknown;
1205 struct sde_connector *c_conn;
1206
1207 if (!connector) {
1208 SDE_ERROR("invalid connector\n");
1209 return status;
1210 }
1211
1212 c_conn = to_sde_connector(connector);
1213
1214 if (c_conn->ops.detect)
1215 status = c_conn->ops.detect(connector,
1216 force,
1217 c_conn->display);
1218
1219 return status;
1220}
1221
Clarence Ip90b282d2017-05-04 10:00:32 -07001222static int sde_connector_dpms(struct drm_connector *connector,
1223 int mode)
1224{
1225 struct sde_connector *c_conn;
1226
1227 if (!connector) {
1228 SDE_ERROR("invalid connector\n");
1229 return -EINVAL;
1230 }
1231 c_conn = to_sde_connector(connector);
1232
1233 /* validate incoming dpms request */
1234 switch (mode) {
1235 case DRM_MODE_DPMS_ON:
1236 case DRM_MODE_DPMS_STANDBY:
1237 case DRM_MODE_DPMS_SUSPEND:
1238 case DRM_MODE_DPMS_OFF:
1239 SDE_DEBUG("conn %d dpms set to %d\n", connector->base.id, mode);
1240 break;
1241 default:
1242 SDE_ERROR("conn %d dpms set to unrecognized mode %d\n",
1243 connector->base.id, mode);
1244 break;
1245 }
1246
1247 mutex_lock(&c_conn->lock);
1248 c_conn->dpms_mode = mode;
1249 _sde_connector_update_power_locked(c_conn);
1250 mutex_unlock(&c_conn->lock);
1251
1252 /* use helper for boilerplate handling */
1253 return drm_atomic_helper_connector_dpms(connector, mode);
1254}
1255
1256int sde_connector_get_dpms(struct drm_connector *connector)
1257{
1258 struct sde_connector *c_conn;
1259 int rc;
1260
1261 if (!connector) {
1262 SDE_DEBUG("invalid connector\n");
1263 return DRM_MODE_DPMS_OFF;
1264 }
1265
1266 c_conn = to_sde_connector(connector);
1267
1268 mutex_lock(&c_conn->lock);
1269 rc = c_conn->dpms_mode;
1270 mutex_unlock(&c_conn->lock);
1271
1272 return rc;
1273}
1274
Clarence Ipd86f6e42017-08-08 18:31:00 -04001275int sde_connector_set_property_for_commit(struct drm_connector *connector,
1276 struct drm_atomic_state *atomic_state,
1277 uint32_t property_idx, uint64_t value)
1278{
1279 struct drm_connector_state *state;
1280 struct drm_property *property;
1281 struct sde_connector *c_conn;
1282
1283 if (!connector || !atomic_state) {
1284 SDE_ERROR("invalid argument(s), conn %d, state %d\n",
1285 connector != NULL, atomic_state != NULL);
1286 return -EINVAL;
1287 }
1288
1289 c_conn = to_sde_connector(connector);
1290 property = msm_property_index_to_drm_property(
1291 &c_conn->property_info, property_idx);
1292 if (!property) {
1293 SDE_ERROR("invalid property index %d\n", property_idx);
1294 return -EINVAL;
1295 }
1296
1297 state = drm_atomic_get_connector_state(atomic_state, connector);
1298 if (IS_ERR_OR_NULL(state)) {
1299 SDE_ERROR("failed to get conn %d state\n",
1300 connector->base.id);
1301 return -EINVAL;
1302 }
1303
1304 return drm_atomic_connector_set_property(
1305 connector, state, property, value);
1306}
1307
Lloyd Atkinsone08229c2017-10-02 17:53:30 -04001308int sde_connector_helper_reset_custom_properties(
1309 struct drm_connector *connector,
1310 struct drm_connector_state *connector_state)
1311{
1312 struct sde_connector *c_conn;
1313 struct sde_connector_state *c_state;
1314 struct drm_property *drm_prop;
1315 enum msm_mdp_conn_property prop_idx;
1316
1317 if (!connector || !connector_state) {
1318 SDE_ERROR("invalid params\n");
1319 return -EINVAL;
1320 }
1321
1322 c_conn = to_sde_connector(connector);
1323 c_state = to_sde_connector_state(connector_state);
1324
1325 for (prop_idx = 0; prop_idx < CONNECTOR_PROP_COUNT; prop_idx++) {
1326 uint64_t val = c_state->property_values[prop_idx].value;
1327 uint64_t def;
1328 int ret;
1329
1330 drm_prop = msm_property_index_to_drm_property(
1331 &c_conn->property_info, prop_idx);
1332 if (!drm_prop) {
1333 /* not all props will be installed, based on caps */
1334 SDE_DEBUG_CONN(c_conn, "invalid property index %d\n",
1335 prop_idx);
1336 continue;
1337 }
1338
1339 def = msm_property_get_default(&c_conn->property_info,
1340 prop_idx);
1341 if (val == def)
1342 continue;
1343
1344 SDE_DEBUG_CONN(c_conn, "set prop %s idx %d from %llu to %llu\n",
1345 drm_prop->name, prop_idx, val, def);
1346
1347 ret = drm_atomic_connector_set_property(connector,
1348 connector_state, drm_prop, def);
1349 if (ret) {
1350 SDE_ERROR_CONN(c_conn,
1351 "set property failed, idx %d ret %d\n",
1352 prop_idx, ret);
1353 continue;
1354 }
1355 }
1356
1357 return 0;
1358}
1359
Alan Kwong578cdaf2017-01-28 17:25:43 -08001360#ifdef CONFIG_DEBUG_FS
1361/**
1362 * sde_connector_init_debugfs - initialize connector debugfs
1363 * @connector: Pointer to drm connector
1364 */
1365static int sde_connector_init_debugfs(struct drm_connector *connector)
1366{
1367 struct sde_connector *sde_connector;
Sandeep Pandaf2274d12017-09-08 19:52:33 +05301368 struct msm_display_info info;
Alan Kwong578cdaf2017-01-28 17:25:43 -08001369
1370 if (!connector || !connector->debugfs_entry) {
1371 SDE_ERROR("invalid connector\n");
1372 return -EINVAL;
1373 }
1374
1375 sde_connector = to_sde_connector(connector);
1376
Sandeep Pandaf2274d12017-09-08 19:52:33 +05301377 sde_connector_get_info(connector, &info);
1378 if (sde_connector->ops.check_status &&
1379 (info.capabilities & MSM_DISPLAY_ESD_ENABLED))
1380 debugfs_create_u32("force_panel_dead", 0600,
1381 connector->debugfs_entry,
1382 &sde_connector->force_panel_dead);
1383
Lloyd Atkinson8de415a2017-05-23 11:31:16 -04001384 if (!debugfs_create_bool("fb_kmap", 0600, connector->debugfs_entry,
Alan Kwong578cdaf2017-01-28 17:25:43 -08001385 &sde_connector->fb_kmap)) {
1386 SDE_ERROR("failed to create connector fb_kmap\n");
1387 return -ENOMEM;
1388 }
1389
1390 return 0;
1391}
1392#else
1393static int sde_connector_init_debugfs(struct drm_connector *connector)
1394{
1395 return 0;
1396}
1397#endif
1398
1399static int sde_connector_late_register(struct drm_connector *connector)
1400{
1401 return sde_connector_init_debugfs(connector);
1402}
1403
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07001404static void sde_connector_early_unregister(struct drm_connector *connector)
1405{
1406 /* debugfs under connector->debugfs are deleted by drm_debugfs */
1407}
1408
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07001409static int sde_connector_fill_modes(struct drm_connector *connector,
1410 uint32_t max_width, uint32_t max_height)
1411{
1412 int rc, mode_count = 0;
1413 struct sde_connector *sde_conn = NULL;
1414
1415 sde_conn = to_sde_connector(connector);
1416 if (!sde_conn) {
1417 SDE_ERROR("invalid arguments\n");
1418 return 0;
1419 }
1420
1421 mode_count = drm_helper_probe_single_connector_modes(connector,
1422 max_width, max_height);
1423
1424 rc = sde_connector_set_blob_data(connector,
1425 connector->state,
1426 CONNECTOR_PROP_MODE_INFO);
1427 if (rc) {
1428 SDE_ERROR_CONN(sde_conn,
1429 "failed to setup mode info prop, rc = %d\n", rc);
1430 return 0;
1431 }
1432
1433 return mode_count;
1434}
1435
Clarence Ipdd8021c2016-07-20 16:39:47 -04001436static const struct drm_connector_funcs sde_connector_ops = {
Clarence Ip90b282d2017-05-04 10:00:32 -07001437 .dpms = sde_connector_dpms,
Clarence Ipdd8021c2016-07-20 16:39:47 -04001438 .reset = sde_connector_atomic_reset,
1439 .detect = sde_connector_detect,
1440 .destroy = sde_connector_destroy,
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07001441 .fill_modes = sde_connector_fill_modes,
Clarence Ipdd8021c2016-07-20 16:39:47 -04001442 .atomic_duplicate_state = sde_connector_atomic_duplicate_state,
1443 .atomic_destroy_state = sde_connector_atomic_destroy_state,
1444 .atomic_set_property = sde_connector_atomic_set_property,
1445 .atomic_get_property = sde_connector_atomic_get_property,
1446 .set_property = sde_connector_set_property,
Alan Kwong578cdaf2017-01-28 17:25:43 -08001447 .late_register = sde_connector_late_register,
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07001448 .early_unregister = sde_connector_early_unregister,
Clarence Ipdd8021c2016-07-20 16:39:47 -04001449};
1450
1451static int sde_connector_get_modes(struct drm_connector *connector)
1452{
1453 struct sde_connector *c_conn;
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07001454 int mode_count = 0;
Clarence Ipdd8021c2016-07-20 16:39:47 -04001455
1456 if (!connector) {
1457 SDE_ERROR("invalid connector\n");
1458 return 0;
1459 }
1460
1461 c_conn = to_sde_connector(connector);
1462 if (!c_conn->ops.get_modes) {
1463 SDE_DEBUG("missing get_modes callback\n");
1464 return 0;
1465 }
1466
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07001467 mode_count = c_conn->ops.get_modes(connector, c_conn->display);
1468 if (!mode_count) {
1469 SDE_ERROR_CONN(c_conn, "failed to get modes\n");
1470 return 0;
1471 }
1472
1473 sde_connector_update_hdr_props(connector);
1474
1475 return mode_count;
Clarence Ipdd8021c2016-07-20 16:39:47 -04001476}
1477
1478static enum drm_mode_status
1479sde_connector_mode_valid(struct drm_connector *connector,
1480 struct drm_display_mode *mode)
1481{
1482 struct sde_connector *c_conn;
1483
1484 if (!connector || !mode) {
1485 SDE_ERROR("invalid argument(s), conn %pK, mode %pK\n",
1486 connector, mode);
1487 return MODE_ERROR;
1488 }
1489
1490 c_conn = to_sde_connector(connector);
1491
1492 if (c_conn->ops.mode_valid)
1493 return c_conn->ops.mode_valid(connector, mode, c_conn->display);
1494
1495 /* assume all modes okay by default */
1496 return MODE_OK;
1497}
1498
1499static struct drm_encoder *
1500sde_connector_best_encoder(struct drm_connector *connector)
1501{
1502 struct sde_connector *c_conn = to_sde_connector(connector);
1503
1504 if (!connector) {
1505 SDE_ERROR("invalid connector\n");
1506 return NULL;
1507 }
1508
1509 /*
1510 * This is true for now, revisit this code when multiple encoders are
1511 * supported.
1512 */
1513 return c_conn->encoder;
1514}
1515
Sandeep Panda98d6ab22017-09-05 08:03:16 +05301516static void sde_connector_check_status_work(struct work_struct *work)
1517{
1518 struct sde_connector *conn;
1519 struct drm_event event;
1520 int rc = 0;
1521 bool panel_dead = false;
1522
1523 conn = container_of(to_delayed_work(work),
1524 struct sde_connector, status_work);
1525 if (!conn) {
1526 SDE_ERROR("not able to get connector object\n");
1527 return;
1528 }
1529
1530 mutex_lock(&conn->lock);
1531 if (!conn->ops.check_status ||
1532 (conn->dpms_mode != DRM_MODE_DPMS_ON)) {
1533 SDE_DEBUG("dpms mode: %d\n", conn->dpms_mode);
1534 mutex_unlock(&conn->lock);
1535 return;
1536 }
1537
1538 rc = conn->ops.check_status(conn->display);
1539 mutex_unlock(&conn->lock);
Sandeep Pandaf2274d12017-09-08 19:52:33 +05301540
1541 if (conn->force_panel_dead) {
1542 conn->force_panel_dead--;
1543 if (!conn->force_panel_dead)
1544 goto status_dead;
1545 }
1546
Sandeep Panda98d6ab22017-09-05 08:03:16 +05301547 if (rc > 0) {
1548 SDE_DEBUG("esd check status success conn_id: %d enc_id: %d\n",
1549 conn->base.base.id, conn->encoder->base.id);
1550 schedule_delayed_work(&conn->status_work,
1551 msecs_to_jiffies(STATUS_CHECK_INTERVAL_MS));
Sandeep Pandaf2274d12017-09-08 19:52:33 +05301552 return;
Sandeep Panda98d6ab22017-09-05 08:03:16 +05301553 }
Sandeep Pandaf2274d12017-09-08 19:52:33 +05301554
1555status_dead:
1556 SDE_EVT32(rc, SDE_EVTLOG_ERROR);
1557 SDE_ERROR("esd check failed report PANEL_DEAD conn_id: %d enc_id: %d\n",
1558 conn->base.base.id, conn->encoder->base.id);
1559 panel_dead = true;
1560 event.type = DRM_EVENT_PANEL_DEAD;
1561 event.length = sizeof(u32);
1562 msm_mode_object_event_notify(&conn->base.base,
1563 conn->base.dev, &event, (u8 *)&panel_dead);
Sandeep Panda98d6ab22017-09-05 08:03:16 +05301564}
1565
Clarence Ipdd8021c2016-07-20 16:39:47 -04001566static const struct drm_connector_helper_funcs sde_connector_helper_ops = {
1567 .get_modes = sde_connector_get_modes,
1568 .mode_valid = sde_connector_mode_valid,
1569 .best_encoder = sde_connector_best_encoder,
1570};
1571
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07001572static int sde_connector_populate_mode_info(struct drm_connector *conn,
1573 struct sde_kms_info *info)
1574{
1575 struct msm_drm_private *priv;
1576 struct sde_kms *sde_kms;
1577 struct sde_connector *c_conn = NULL;
1578 struct drm_display_mode *mode;
1579 struct msm_mode_info mode_info;
1580 int rc = 0;
1581
1582 if (!conn || !conn->dev || !conn->dev->dev_private) {
1583 SDE_ERROR("invalid arguments\n");
1584 return -EINVAL;
1585 }
1586
1587 priv = conn->dev->dev_private;
1588 sde_kms = to_sde_kms(priv->kms);
1589
1590 c_conn = to_sde_connector(conn);
1591 if (!c_conn->ops.get_mode_info) {
1592 SDE_ERROR_CONN(c_conn, "get_mode_info not defined\n");
1593 return -EINVAL;
1594 }
1595
1596 list_for_each_entry(mode, &conn->modes, head) {
1597 int topology_idx = 0;
1598
1599 memset(&mode_info, 0, sizeof(mode_info));
1600
1601 rc = c_conn->ops.get_mode_info(mode, &mode_info,
1602 sde_kms->catalog->max_mixer_width,
1603 c_conn->display);
1604 if (rc) {
1605 SDE_ERROR_CONN(c_conn,
1606 "failed to get mode info for mode %s\n",
1607 mode->name);
1608 continue;
1609 }
1610
1611 sde_kms_info_add_keystr(info, "mode_name", mode->name);
1612
1613 topology_idx = (int)sde_rm_get_topology_name(
1614 mode_info.topology);
1615 if (topology_idx < SDE_RM_TOPOLOGY_MAX) {
1616 sde_kms_info_add_keystr(info, "topology",
1617 e_topology_name[topology_idx].name);
1618 } else {
1619 SDE_ERROR_CONN(c_conn, "invalid topology\n");
1620 continue;
1621 }
1622
1623 if (!mode_info.roi_caps.num_roi)
1624 continue;
1625
1626 sde_kms_info_add_keyint(info, "partial_update_num_roi",
1627 mode_info.roi_caps.num_roi);
1628 sde_kms_info_add_keyint(info, "partial_update_xstart",
1629 mode_info.roi_caps.align.xstart_pix_align);
1630 sde_kms_info_add_keyint(info, "partial_update_walign",
1631 mode_info.roi_caps.align.width_pix_align);
1632 sde_kms_info_add_keyint(info, "partial_update_wmin",
1633 mode_info.roi_caps.align.min_width);
1634 sde_kms_info_add_keyint(info, "partial_update_ystart",
1635 mode_info.roi_caps.align.ystart_pix_align);
1636 sde_kms_info_add_keyint(info, "partial_update_halign",
1637 mode_info.roi_caps.align.height_pix_align);
1638 sde_kms_info_add_keyint(info, "partial_update_hmin",
1639 mode_info.roi_caps.align.min_height);
1640 sde_kms_info_add_keyint(info, "partial_update_roimerge",
1641 mode_info.roi_caps.merge_rois);
1642 }
1643
1644 return rc;
1645}
1646
1647int sde_connector_set_blob_data(struct drm_connector *conn,
1648 struct drm_connector_state *state,
1649 enum msm_mdp_conn_property prop_id)
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07001650{
1651 struct sde_kms_info *info;
1652 struct sde_connector *c_conn = NULL;
Jeykumar Sankaran905ba332017-10-19 10:45:02 -07001653 struct sde_connector_state *sde_conn_state = NULL;
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07001654 struct msm_mode_info mode_info;
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07001655 struct drm_property_blob *blob = NULL;
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07001656 int rc = 0;
1657
1658 c_conn = to_sde_connector(conn);
Jeykumar Sankaran905ba332017-10-19 10:45:02 -07001659 if (!c_conn) {
1660 SDE_ERROR("invalid argument\n");
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07001661 return -EINVAL;
1662 }
1663
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07001664 info = kzalloc(sizeof(*info), GFP_KERNEL);
1665 if (!info)
1666 return -ENOMEM;
1667
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07001668 sde_kms_info_reset(info);
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07001669
1670 switch (prop_id) {
1671 case CONNECTOR_PROP_SDE_INFO:
1672 memset(&mode_info, 0, sizeof(mode_info));
1673
1674 if (state) {
1675 sde_conn_state = to_sde_connector_state(state);
1676 memcpy(&mode_info, &sde_conn_state->mode_info,
1677 sizeof(sde_conn_state->mode_info));
1678 } else {
1679 /**
1680 * connector state is assigned only on first
1681 * atomic_commit. But this function is allowed to be
1682 * invoked during probe/init sequence. So not throwing
1683 * an error.
1684 */
1685 SDE_DEBUG_CONN(c_conn, "invalid connector state\n");
1686 }
1687
Alan Kwong769fba92017-11-13 16:50:36 -05001688 if (c_conn->ops.set_info_blob) {
1689 rc = c_conn->ops.set_info_blob(conn, info,
1690 c_conn->display, &mode_info);
1691 if (rc) {
1692 SDE_ERROR_CONN(c_conn,
1693 "set_info_blob failed, %d\n",
1694 rc);
1695 goto exit;
1696 }
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07001697 }
1698
1699 blob = c_conn->blob_caps;
1700 break;
1701 case CONNECTOR_PROP_MODE_INFO:
1702 rc = sde_connector_populate_mode_info(conn, info);
1703 if (rc) {
1704 SDE_ERROR_CONN(c_conn,
1705 "mode info population failed, %d\n",
1706 rc);
1707 goto exit;
1708 }
1709 blob = c_conn->blob_mode_info;
1710 break;
1711 default:
1712 SDE_ERROR_CONN(c_conn, "invalid prop_id: %d\n", prop_id);
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07001713 goto exit;
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07001714 };
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07001715
1716 msm_property_set_blob(&c_conn->property_info,
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07001717 &blob,
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07001718 SDE_KMS_INFO_DATA(info),
1719 SDE_KMS_INFO_DATALEN(info),
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07001720 prop_id);
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07001721exit:
1722 kfree(info);
1723
1724 return rc;
1725}
1726
Clarence Ipdd8021c2016-07-20 16:39:47 -04001727struct drm_connector *sde_connector_init(struct drm_device *dev,
1728 struct drm_encoder *encoder,
1729 struct drm_panel *panel,
1730 void *display,
1731 const struct sde_connector_ops *ops,
1732 int connector_poll,
1733 int connector_type)
1734{
1735 struct msm_drm_private *priv;
1736 struct sde_kms *sde_kms;
Clarence Ipdd8021c2016-07-20 16:39:47 -04001737 struct sde_connector *c_conn = NULL;
Ping Li898b1bf2017-02-09 18:03:28 -08001738 struct dsi_display *dsi_display;
Lloyd Atkinson8ba47032017-03-22 17:13:32 -04001739 struct msm_display_info display_info;
Clarence Ipdd8021c2016-07-20 16:39:47 -04001740 int rc;
1741
1742 if (!dev || !dev->dev_private || !encoder) {
1743 SDE_ERROR("invalid argument(s), dev %pK, enc %pK\n",
1744 dev, encoder);
1745 return ERR_PTR(-EINVAL);
1746 }
1747
1748 priv = dev->dev_private;
1749 if (!priv->kms) {
1750 SDE_ERROR("invalid kms reference\n");
1751 return ERR_PTR(-EINVAL);
1752 }
1753
1754 c_conn = kzalloc(sizeof(*c_conn), GFP_KERNEL);
1755 if (!c_conn) {
1756 SDE_ERROR("failed to alloc sde connector\n");
1757 return ERR_PTR(-ENOMEM);
1758 }
1759
Jeykumar Sankaran36af6a62017-08-03 14:21:58 -07001760 memset(&display_info, 0, sizeof(display_info));
1761
Clarence Ipdd8021c2016-07-20 16:39:47 -04001762 rc = drm_connector_init(dev,
1763 &c_conn->base,
1764 &sde_connector_ops,
1765 connector_type);
1766 if (rc)
1767 goto error_free_conn;
1768
Clarence Ipa18d4832017-03-13 12:35:44 -07001769 spin_lock_init(&c_conn->event_lock);
1770
Clarence Ipdd8021c2016-07-20 16:39:47 -04001771 c_conn->connector_type = connector_type;
1772 c_conn->encoder = encoder;
1773 c_conn->panel = panel;
1774 c_conn->display = display;
1775
Clarence Ip90b282d2017-05-04 10:00:32 -07001776 c_conn->dpms_mode = DRM_MODE_DPMS_ON;
1777 c_conn->lp_mode = 0;
1778 c_conn->last_panel_power_mode = SDE_MODE_DPMS_ON;
1779
Clarence Ipdd8021c2016-07-20 16:39:47 -04001780 sde_kms = to_sde_kms(priv->kms);
Alan Kwongdfa8c082016-07-29 04:10:00 -04001781 if (sde_kms->vbif[VBIF_NRT]) {
Jordan Croused8e96522017-02-13 10:14:16 -07001782 c_conn->aspace[SDE_IOMMU_DOMAIN_UNSECURE] =
1783 sde_kms->aspace[MSM_SMMU_DOMAIN_NRT_UNSECURE];
1784 c_conn->aspace[SDE_IOMMU_DOMAIN_SECURE] =
1785 sde_kms->aspace[MSM_SMMU_DOMAIN_NRT_SECURE];
Alan Kwongdfa8c082016-07-29 04:10:00 -04001786 } else {
Jordan Croused8e96522017-02-13 10:14:16 -07001787 c_conn->aspace[SDE_IOMMU_DOMAIN_UNSECURE] =
1788 sde_kms->aspace[MSM_SMMU_DOMAIN_UNSECURE];
1789 c_conn->aspace[SDE_IOMMU_DOMAIN_SECURE] =
1790 sde_kms->aspace[MSM_SMMU_DOMAIN_SECURE];
Alan Kwongdfa8c082016-07-29 04:10:00 -04001791 }
Clarence Ipdd8021c2016-07-20 16:39:47 -04001792
1793 if (ops)
1794 c_conn->ops = *ops;
1795
1796 c_conn->base.helper_private = &sde_connector_helper_ops;
1797 c_conn->base.polled = connector_poll;
1798 c_conn->base.interlace_allowed = 0;
1799 c_conn->base.doublescan_allowed = 0;
1800
1801 snprintf(c_conn->name,
1802 SDE_CONNECTOR_NAME_SIZE,
1803 "conn%u",
1804 c_conn->base.base.id);
1805
Lloyd Atkinson5d40d312016-09-06 08:34:13 -04001806 rc = sde_fence_init(&c_conn->retire_fence, c_conn->name,
1807 c_conn->base.base.id);
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001808 if (rc) {
1809 SDE_ERROR("failed to init fence, %d\n", rc);
1810 goto error_cleanup_conn;
1811 }
1812
Clarence Ip90b282d2017-05-04 10:00:32 -07001813 mutex_init(&c_conn->lock);
1814
Clarence Ipdd8021c2016-07-20 16:39:47 -04001815 rc = drm_mode_connector_attach_encoder(&c_conn->base, encoder);
1816 if (rc) {
1817 SDE_ERROR("failed to attach encoder to connector, %d\n", rc);
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -08001818 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -04001819 }
1820
Shashank Babu Chinta Venkata06c428e2017-04-17 13:52:28 -07001821 rc = sde_backlight_setup(c_conn, dev);
Dhaval Patel7cdd6662017-03-08 13:10:37 -08001822 if (rc) {
1823 SDE_ERROR("failed to setup backlight, rc=%d\n", rc);
1824 goto error_cleanup_fence;
Vishnuvardhan Prodduturi75b96802016-10-17 18:45:55 +05301825 }
1826
Clarence Ipdd8021c2016-07-20 16:39:47 -04001827 /* create properties */
1828 msm_property_init(&c_conn->property_info, &c_conn->base.base, dev,
1829 priv->conn_property, c_conn->property_data,
1830 CONNECTOR_PROP_COUNT, CONNECTOR_PROP_BLOBCOUNT,
1831 sizeof(struct sde_connector_state));
1832
Alan Kwong769fba92017-11-13 16:50:36 -05001833 if (c_conn->ops.post_init) {
1834 rc = c_conn->ops.post_init(&c_conn->base, display);
1835 if (rc) {
1836 SDE_ERROR("post-init failed, %d\n", rc);
1837 goto error_cleanup_fence;
1838 }
1839 }
1840
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07001841 msm_property_install_blob(&c_conn->property_info,
1842 "capabilities",
1843 DRM_MODE_PROP_IMMUTABLE,
1844 CONNECTOR_PROP_SDE_INFO);
Clarence Ipdd8021c2016-07-20 16:39:47 -04001845
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07001846 rc = sde_connector_set_blob_data(&c_conn->base,
1847 NULL,
1848 CONNECTOR_PROP_SDE_INFO);
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07001849 if (rc) {
1850 SDE_ERROR_CONN(c_conn,
1851 "failed to setup connector info, rc = %d\n", rc);
1852 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -04001853 }
1854
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07001855 msm_property_install_blob(&c_conn->property_info,
1856 "mode_properties",
1857 DRM_MODE_PROP_IMMUTABLE,
1858 CONNECTOR_PROP_MODE_INFO);
1859
Ping Li898b1bf2017-02-09 18:03:28 -08001860 if (connector_type == DRM_MODE_CONNECTOR_DSI) {
1861 dsi_display = (struct dsi_display *)(display);
1862 if (dsi_display && dsi_display->panel &&
1863 dsi_display->panel->hdr_props.hdr_enabled == true) {
1864 msm_property_install_blob(&c_conn->property_info,
1865 "hdr_properties",
1866 DRM_MODE_PROP_IMMUTABLE,
1867 CONNECTOR_PROP_HDR_INFO);
1868
1869 msm_property_set_blob(&c_conn->property_info,
1870 &c_conn->blob_hdr,
1871 &dsi_display->panel->hdr_props,
1872 sizeof(dsi_display->panel->hdr_props),
1873 CONNECTOR_PROP_HDR_INFO);
1874 }
1875 }
1876
Sandeep Panda11b20d82017-06-19 12:57:27 +05301877 rc = sde_connector_get_info(&c_conn->base, &display_info);
1878 if (!rc && (connector_type == DRM_MODE_CONNECTOR_DSI) &&
1879 (display_info.capabilities & MSM_DISPLAY_CAP_VID_MODE))
1880 sde_connector_register_event(&c_conn->base,
1881 SDE_CONN_EVENT_VID_FIFO_OVERFLOW,
1882 sde_connector_handle_disp_recovery,
1883 c_conn);
1884
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07001885 msm_property_install_volatile_range(
Sandeep Panda11b20d82017-06-19 12:57:27 +05301886 &c_conn->property_info, "sde_drm_roi_v1", 0x0,
1887 0, ~0, 0, CONNECTOR_PROP_ROI_V1);
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07001888
Ping Li8430ee12017-02-24 14:14:44 -08001889 /* install PP_DITHER properties */
1890 _sde_connector_install_dither_property(dev, sde_kms, c_conn);
Lloyd Atkinson8ba47032017-03-22 17:13:32 -04001891
Srikanth Rajagopalan30384d12017-06-08 15:23:31 -07001892 if (connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
Ajay Singh Parmar4dabdfc2017-11-09 16:54:25 -08001893 struct drm_msm_ext_hdr_properties hdr = {0};
1894
Srikanth Rajagopalan30384d12017-06-08 15:23:31 -07001895 msm_property_install_blob(&c_conn->property_info,
1896 "ext_hdr_properties",
1897 DRM_MODE_PROP_IMMUTABLE,
1898 CONNECTOR_PROP_EXT_HDR_INFO);
Ajay Singh Parmar4dabdfc2017-11-09 16:54:25 -08001899
1900 /* set default values to avoid reading uninitialized data */
1901 msm_property_set_blob(&c_conn->property_info,
1902 &c_conn->blob_ext_hdr,
1903 &hdr,
1904 sizeof(hdr),
1905 CONNECTOR_PROP_EXT_HDR_INFO);
Srikanth Rajagopalan30384d12017-06-08 15:23:31 -07001906 }
1907
Ajay Singh Parmare927aa42017-11-01 00:33:20 -07001908 msm_property_install_volatile_range(&c_conn->property_info,
1909 "hdr_metadata", 0x0, 0, ~0, 0, CONNECTOR_PROP_HDR_METADATA);
1910
Dhaval Patelb24b2d62017-11-03 18:10:26 -07001911 msm_property_install_volatile_range(&c_conn->property_info,
1912 "RETIRE_FENCE", 0x0, 0, ~0, 0, CONNECTOR_PROP_RETIRE_FENCE);
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001913
Lloyd Atkinson77382202017-02-01 14:59:43 -05001914 msm_property_install_range(&c_conn->property_info, "autorefresh",
1915 0x0, 0, AUTOREFRESH_MAX_FRAME_CNT, 0,
1916 CONNECTOR_PROP_AUTOREFRESH);
1917
Xu Yangd566d222017-05-19 17:18:12 +08001918 msm_property_install_range(&c_conn->property_info, "bl_scale",
1919 0x0, 0, MAX_BL_SCALE_LEVEL, MAX_BL_SCALE_LEVEL,
1920 CONNECTOR_PROP_BL_SCALE);
1921
1922 msm_property_install_range(&c_conn->property_info, "ad_bl_scale",
1923 0x0, 0, MAX_AD_BL_SCALE_LEVEL, MAX_AD_BL_SCALE_LEVEL,
1924 CONNECTOR_PROP_AD_BL_SCALE);
1925
Xu Yang92377312017-11-23 13:48:08 +08001926 c_conn->bl_scale_dirty = false;
1927 c_conn->bl_scale = MAX_BL_SCALE_LEVEL;
1928 c_conn->bl_scale_ad = MAX_AD_BL_SCALE_LEVEL;
1929
Lloyd Atkinsonb6191972016-08-10 18:31:46 -04001930 /* enum/bitmask properties */
1931 msm_property_install_enum(&c_conn->property_info, "topology_name",
1932 DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name,
1933 ARRAY_SIZE(e_topology_name),
1934 CONNECTOR_PROP_TOPOLOGY_NAME);
1935 msm_property_install_enum(&c_conn->property_info, "topology_control",
1936 0, 1, e_topology_control,
1937 ARRAY_SIZE(e_topology_control),
1938 CONNECTOR_PROP_TOPOLOGY_CONTROL);
Clarence Ip90b282d2017-05-04 10:00:32 -07001939 msm_property_install_enum(&c_conn->property_info, "LP",
1940 0, 0, e_power_mode,
1941 ARRAY_SIZE(e_power_mode),
1942 CONNECTOR_PROP_LP);
Lloyd Atkinsonb6191972016-08-10 18:31:46 -04001943
Clarence Ipdd8021c2016-07-20 16:39:47 -04001944 rc = msm_property_install_get_status(&c_conn->property_info);
1945 if (rc) {
1946 SDE_ERROR("failed to create one or more properties\n");
1947 goto error_destroy_property;
1948 }
1949
Lloyd Atkinsonb6191972016-08-10 18:31:46 -04001950 SDE_DEBUG("connector %d attach encoder %d\n",
1951 c_conn->base.base.id, encoder->base.id);
1952
Clarence Ipdd8021c2016-07-20 16:39:47 -04001953 priv->connectors[priv->num_connectors++] = &c_conn->base;
1954
Sandeep Panda98d6ab22017-09-05 08:03:16 +05301955 INIT_DELAYED_WORK(&c_conn->status_work,
1956 sde_connector_check_status_work);
1957
Clarence Ipdd8021c2016-07-20 16:39:47 -04001958 return &c_conn->base;
1959
1960error_destroy_property:
Dhaval Patel4e574842016-08-23 15:11:37 -07001961 if (c_conn->blob_caps)
1962 drm_property_unreference_blob(c_conn->blob_caps);
Ping Li898b1bf2017-02-09 18:03:28 -08001963 if (c_conn->blob_hdr)
1964 drm_property_unreference_blob(c_conn->blob_hdr);
Ping Li8430ee12017-02-24 14:14:44 -08001965 if (c_conn->blob_dither)
1966 drm_property_unreference_blob(c_conn->blob_dither);
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07001967 if (c_conn->blob_mode_info)
1968 drm_property_unreference_blob(c_conn->blob_mode_info);
Ajay Singh Parmar4dabdfc2017-11-09 16:54:25 -08001969 if (c_conn->blob_ext_hdr)
1970 drm_property_unreference_blob(c_conn->blob_ext_hdr);
Ping Li8430ee12017-02-24 14:14:44 -08001971
Clarence Ipdd8021c2016-07-20 16:39:47 -04001972 msm_property_destroy(&c_conn->property_info);
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001973error_cleanup_fence:
Clarence Ip90b282d2017-05-04 10:00:32 -07001974 mutex_destroy(&c_conn->lock);
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001975 sde_fence_deinit(&c_conn->retire_fence);
Clarence Ipdd8021c2016-07-20 16:39:47 -04001976error_cleanup_conn:
1977 drm_connector_cleanup(&c_conn->base);
1978error_free_conn:
1979 kfree(c_conn);
1980
1981 return ERR_PTR(rc);
1982}
Gopikrishnaiah Anandande2c81b2017-03-15 12:41:29 -07001983
1984int sde_connector_register_custom_event(struct sde_kms *kms,
1985 struct drm_connector *conn_drm, u32 event, bool val)
1986{
Gopikrishnaiah Anandan84b4f672017-04-26 10:28:51 -07001987 int ret = -EINVAL;
1988
1989 switch (event) {
1990 case DRM_EVENT_SYS_BACKLIGHT:
1991 ret = 0;
1992 break;
Sandeep Panda98d6ab22017-09-05 08:03:16 +05301993 case DRM_EVENT_PANEL_DEAD:
1994 ret = 0;
1995 break;
Gopikrishnaiah Anandan84b4f672017-04-26 10:28:51 -07001996 default:
1997 break;
1998 }
1999 return ret;
Gopikrishnaiah Anandande2c81b2017-03-15 12:41:29 -07002000}