blob: 2d2f352a11ce4c204b829118043bf8cf360ee120 [file] [log] [blame]
Narender Ankam1afbd172020-03-16 17:27:44 +05301/* Copyright (c) 2016-2020, 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>
Govinda Rajulu Chennab95b9c32017-10-13 15:00:32 -040021#include <linux/string.h>
Dhaval Patel7cdd6662017-03-08 13:10:37 -080022#include "dsi_drm.h"
Ping Li898b1bf2017-02-09 18:03:28 -080023#include "dsi_display.h"
Veera Sundaram Sankarandb43e282017-09-19 18:32:52 -070024#include "sde_crtc.h"
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -070025#include "sde_rm.h"
Dhaval Patel7cdd6662017-03-08 13:10:37 -080026
27#define BL_NODE_NAME_SIZE 32
Clarence Ipdd8021c2016-07-20 16:39:47 -040028
Lloyd Atkinson77382202017-02-01 14:59:43 -050029/* Autorefresh will occur after FRAME_CNT frames. Large values are unlikely */
30#define AUTOREFRESH_MAX_FRAME_CNT 6
31
Lloyd Atkinson8ba47032017-03-22 17:13:32 -040032#define SDE_DEBUG_CONN(c, fmt, ...) SDE_DEBUG("conn%d " fmt,\
33 (c) ? (c)->base.base.id : -1, ##__VA_ARGS__)
34
35#define SDE_ERROR_CONN(c, fmt, ...) SDE_ERROR("conn%d " fmt,\
36 (c) ? (c)->base.base.id : -1, ##__VA_ARGS__)
Ping Li8430ee12017-02-24 14:14:44 -080037static u32 dither_matrix[DITHER_MATRIX_SZ] = {
38 15, 7, 13, 5, 3, 11, 1, 9, 12, 4, 14, 6, 0, 8, 2, 10
39};
Lloyd Atkinson8ba47032017-03-22 17:13:32 -040040
Lloyd Atkinsonb6191972016-08-10 18:31:46 -040041static const struct drm_prop_enum_list e_topology_name[] = {
Jeykumar Sankaran2b098072017-03-16 17:25:59 -070042 {SDE_RM_TOPOLOGY_NONE, "sde_none"},
Lloyd Atkinsonb6191972016-08-10 18:31:46 -040043 {SDE_RM_TOPOLOGY_SINGLEPIPE, "sde_singlepipe"},
Jeykumar Sankaran2b098072017-03-16 17:25:59 -070044 {SDE_RM_TOPOLOGY_SINGLEPIPE_DSC, "sde_singlepipe_dsc"},
Lloyd Atkinsonb6191972016-08-10 18:31:46 -040045 {SDE_RM_TOPOLOGY_DUALPIPE, "sde_dualpipe"},
Jeykumar Sankaran2b098072017-03-16 17:25:59 -070046 {SDE_RM_TOPOLOGY_DUALPIPE_DSC, "sde_dualpipe_dsc"},
47 {SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE, "sde_dualpipemerge"},
48 {SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC, "sde_dualpipemerge_dsc"},
49 {SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE, "sde_dualpipe_dscmerge"},
Lloyd Atkinsonb6191972016-08-10 18:31:46 -040050 {SDE_RM_TOPOLOGY_PPSPLIT, "sde_ppsplit"},
Kalyan Thota27ec06c2019-03-18 13:19:59 +053051 {SDE_RM_TOPOLOGY_QUADPIPE_3DMERGE, "sde_quadpipemerge"},
52 {SDE_RM_TOPOLOGY_QUADPIPE_DSCMERGE, "sde_quadpipe_dscmerge"},
53 {SDE_RM_TOPOLOGY_QUADPIPE_3DMERGE_DSC, "sde_quadpipe_3dmerge_dsc"}
Lloyd Atkinsonb6191972016-08-10 18:31:46 -040054};
55static const struct drm_prop_enum_list e_topology_control[] = {
56 {SDE_RM_TOPCTL_RESERVE_LOCK, "reserve_lock"},
57 {SDE_RM_TOPCTL_RESERVE_CLEAR, "reserve_clear"},
58 {SDE_RM_TOPCTL_DSPP, "dspp"},
Lloyd Atkinsonb6191972016-08-10 18:31:46 -040059};
Clarence Ip90b282d2017-05-04 10:00:32 -070060static const struct drm_prop_enum_list e_power_mode[] = {
61 {SDE_MODE_DPMS_ON, "ON"},
62 {SDE_MODE_DPMS_LP1, "LP1"},
63 {SDE_MODE_DPMS_LP2, "LP2"},
64 {SDE_MODE_DPMS_OFF, "OFF"},
65};
Lloyd Atkinsonb6191972016-08-10 18:31:46 -040066
Dhaval Patel7cdd6662017-03-08 13:10:37 -080067static int sde_backlight_device_update_status(struct backlight_device *bd)
68{
69 int brightness;
70 struct dsi_display *display;
71 struct sde_connector *c_conn;
72 int bl_lvl;
Gopikrishnaiah Anandan84b4f672017-04-26 10:28:51 -070073 struct drm_event event;
Sandeep Pandabbe7fa42018-01-27 08:51:57 +053074 int rc = 0;
Dhaval Patel7cdd6662017-03-08 13:10:37 -080075
76 brightness = bd->props.brightness;
77
78 if ((bd->props.power != FB_BLANK_UNBLANK) ||
79 (bd->props.state & BL_CORE_FBBLANK) ||
80 (bd->props.state & BL_CORE_SUSPENDED))
81 brightness = 0;
82
83 c_conn = bl_get_data(bd);
84 display = (struct dsi_display *) c_conn->display;
85 if (brightness > display->panel->bl_config.bl_max_level)
86 brightness = display->panel->bl_config.bl_max_level;
87
88 /* map UI brightness into driver backlight level with rounding */
89 bl_lvl = mult_frac(brightness, display->panel->bl_config.bl_max_level,
90 display->panel->bl_config.brightness_max_level);
91
92 if (!bl_lvl && brightness)
93 bl_lvl = 1;
94
Tharun Raj Soma87208052018-05-18 20:52:10 +053095 if (display->panel->bl_config.bl_update ==
96 BL_UPDATE_DELAY_UNTIL_FIRST_FRAME && !c_conn->allow_bl_update) {
97 c_conn->unset_bl_level = bl_lvl;
98 return 0;
99 }
100
Gopikrishnaiah Anandan84b4f672017-04-26 10:28:51 -0700101 if (c_conn->ops.set_backlight) {
102 event.type = DRM_EVENT_SYS_BACKLIGHT;
103 event.length = sizeof(u32);
Benjamin Chan34a92c72017-06-28 11:01:18 -0400104 msm_mode_object_event_notify(&c_conn->base.base,
Gopikrishnaiah Anandan84b4f672017-04-26 10:28:51 -0700105 c_conn->base.dev, &event, (u8 *)&brightness);
Sandeep Pandabbe7fa42018-01-27 08:51:57 +0530106 rc = c_conn->ops.set_backlight(c_conn->display, bl_lvl);
Tharun Raj Soma87208052018-05-18 20:52:10 +0530107 c_conn->unset_bl_level = 0;
Gopikrishnaiah Anandan84b4f672017-04-26 10:28:51 -0700108 }
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800109
Sandeep Pandabbe7fa42018-01-27 08:51:57 +0530110 return rc;
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800111}
112
113static int sde_backlight_device_get_brightness(struct backlight_device *bd)
114{
115 return 0;
116}
117
118static const struct backlight_ops sde_backlight_device_ops = {
119 .update_status = sde_backlight_device_update_status,
120 .get_brightness = sde_backlight_device_get_brightness,
121};
122
Shashank Babu Chinta Venkata06c428e2017-04-17 13:52:28 -0700123static int sde_backlight_setup(struct sde_connector *c_conn,
124 struct drm_device *dev)
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800125{
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800126 struct backlight_properties props;
127 struct dsi_display *display;
128 struct dsi_backlight_config *bl_config;
129 static int display_count;
130 char bl_node_name[BL_NODE_NAME_SIZE];
131
Shashank Babu Chinta Venkata06c428e2017-04-17 13:52:28 -0700132 if (!c_conn || !dev || !dev->dev) {
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800133 SDE_ERROR("invalid param\n");
134 return -EINVAL;
135 } else if (c_conn->connector_type != DRM_MODE_CONNECTOR_DSI) {
136 return 0;
137 }
138
139 memset(&props, 0, sizeof(props));
140 props.type = BACKLIGHT_RAW;
141 props.power = FB_BLANK_UNBLANK;
142
143 display = (struct dsi_display *) c_conn->display;
144 bl_config = &display->panel->bl_config;
145 props.max_brightness = bl_config->brightness_max_level;
146 props.brightness = bl_config->brightness_max_level;
147 snprintf(bl_node_name, BL_NODE_NAME_SIZE, "panel%u-backlight",
148 display_count);
Dhaval Patel959fdab2017-08-25 15:15:39 -0700149 c_conn->bl_device = backlight_device_register(bl_node_name, dev->dev,
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800150 c_conn, &sde_backlight_device_ops, &props);
Dhaval Patel959fdab2017-08-25 15:15:39 -0700151 if (IS_ERR_OR_NULL(c_conn->bl_device)) {
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800152 SDE_ERROR("Failed to register backlight: %ld\n",
Dhaval Patel959fdab2017-08-25 15:15:39 -0700153 PTR_ERR(c_conn->bl_device));
154 c_conn->bl_device = NULL;
Dhaval Patel7cdd6662017-03-08 13:10:37 -0800155 return -ENODEV;
156 }
157 display_count++;
158
159 return 0;
160}
161
Clarence Ipa18d4832017-03-13 12:35:44 -0700162int sde_connector_trigger_event(void *drm_connector,
163 uint32_t event_idx, uint32_t instance_idx,
164 uint32_t data0, uint32_t data1,
165 uint32_t data2, uint32_t data3)
166{
167 struct sde_connector *c_conn;
168 unsigned long irq_flags;
Sandeep Panda11b20d82017-06-19 12:57:27 +0530169 int (*cb_func)(uint32_t event_idx,
Clarence Ipa18d4832017-03-13 12:35:44 -0700170 uint32_t instance_idx, void *usr,
171 uint32_t data0, uint32_t data1,
172 uint32_t data2, uint32_t data3);
173 void *usr;
174 int rc = 0;
175
176 /*
177 * This function may potentially be called from an ISR context, so
178 * avoid excessive logging/etc.
179 */
180 if (!drm_connector)
181 return -EINVAL;
182 else if (event_idx >= SDE_CONN_EVENT_COUNT)
183 return -EINVAL;
184 c_conn = to_sde_connector(drm_connector);
185
186 spin_lock_irqsave(&c_conn->event_lock, irq_flags);
187 cb_func = c_conn->event_table[event_idx].cb_func;
188 usr = c_conn->event_table[event_idx].usr;
189 spin_unlock_irqrestore(&c_conn->event_lock, irq_flags);
190
191 if (cb_func)
Sandeep Panda11b20d82017-06-19 12:57:27 +0530192 rc = cb_func(event_idx, instance_idx, usr,
Clarence Ipa18d4832017-03-13 12:35:44 -0700193 data0, data1, data2, data3);
194 else
195 rc = -EAGAIN;
196
197 return rc;
198}
199
200int sde_connector_register_event(struct drm_connector *connector,
201 uint32_t event_idx,
Sandeep Panda11b20d82017-06-19 12:57:27 +0530202 int (*cb_func)(uint32_t event_idx,
Clarence Ipa18d4832017-03-13 12:35:44 -0700203 uint32_t instance_idx, void *usr,
204 uint32_t data0, uint32_t data1,
205 uint32_t data2, uint32_t data3),
206 void *usr)
207{
208 struct sde_connector *c_conn;
209 unsigned long irq_flags;
210
211 if (!connector) {
212 SDE_ERROR("invalid connector\n");
213 return -EINVAL;
214 } else if (event_idx >= SDE_CONN_EVENT_COUNT) {
215 SDE_ERROR("conn%d, invalid event %d\n",
216 connector->base.id, event_idx);
217 return -EINVAL;
218 }
219 c_conn = to_sde_connector(connector);
220
221 spin_lock_irqsave(&c_conn->event_lock, irq_flags);
222 c_conn->event_table[event_idx].cb_func = cb_func;
223 c_conn->event_table[event_idx].usr = usr;
224 spin_unlock_irqrestore(&c_conn->event_lock, irq_flags);
225
226 /* optionally notify display of event registration */
227 if (c_conn->ops.enable_event && c_conn->display)
228 c_conn->ops.enable_event(connector, event_idx,
229 cb_func != NULL, c_conn->display);
230 return 0;
231}
232
233void sde_connector_unregister_event(struct drm_connector *connector,
234 uint32_t event_idx)
235{
236 (void)sde_connector_register_event(connector, event_idx, 0, 0);
237}
238
Ping Li8430ee12017-02-24 14:14:44 -0800239static int _sde_connector_get_default_dither_cfg_v1(
240 struct sde_connector *c_conn, void *cfg)
241{
242 struct drm_msm_dither *dither_cfg = (struct drm_msm_dither *)cfg;
243 enum dsi_pixel_format dst_format = DSI_PIXEL_FORMAT_MAX;
244
245 if (!c_conn || !cfg) {
246 SDE_ERROR("invalid argument(s), c_conn %pK, cfg %pK\n",
247 c_conn, cfg);
248 return -EINVAL;
249 }
250
251 if (!c_conn->ops.get_dst_format) {
Ping Lie0cfec2e2017-07-13 15:28:15 -0700252 SDE_DEBUG("get_dst_format is unavailable\n");
253 return 0;
Ping Li8430ee12017-02-24 14:14:44 -0800254 }
255
256 dst_format = c_conn->ops.get_dst_format(c_conn->display);
257 switch (dst_format) {
258 case DSI_PIXEL_FORMAT_RGB888:
259 dither_cfg->c0_bitdepth = 8;
260 dither_cfg->c1_bitdepth = 8;
261 dither_cfg->c2_bitdepth = 8;
262 dither_cfg->c3_bitdepth = 8;
263 break;
264 case DSI_PIXEL_FORMAT_RGB666:
265 case DSI_PIXEL_FORMAT_RGB666_LOOSE:
266 dither_cfg->c0_bitdepth = 6;
267 dither_cfg->c1_bitdepth = 6;
268 dither_cfg->c2_bitdepth = 6;
269 dither_cfg->c3_bitdepth = 6;
270 break;
271 default:
272 SDE_DEBUG("no default dither config for dst_format %d\n",
273 dst_format);
274 return -ENODATA;
275 }
276
277 memcpy(&dither_cfg->matrix, dither_matrix,
278 sizeof(u32) * DITHER_MATRIX_SZ);
279 dither_cfg->temporal_en = 0;
280 return 0;
281}
282
283static void _sde_connector_install_dither_property(struct drm_device *dev,
284 struct sde_kms *sde_kms, struct sde_connector *c_conn)
285{
286 char prop_name[DRM_PROP_NAME_LEN];
287 struct sde_mdss_cfg *catalog = NULL;
288 struct drm_property_blob *blob_ptr;
289 void *cfg;
290 int ret = 0;
291 u32 version = 0, len = 0;
292 bool defalut_dither_needed = false;
293
294 if (!dev || !sde_kms || !c_conn) {
295 SDE_ERROR("invld args (s), dev %pK, sde_kms %pK, c_conn %pK\n",
296 dev, sde_kms, c_conn);
297 return;
298 }
299
300 catalog = sde_kms->catalog;
301 version = SDE_COLOR_PROCESS_MAJOR(
302 catalog->pingpong[0].sblk->dither.version);
303 snprintf(prop_name, ARRAY_SIZE(prop_name), "%s%d",
304 "SDE_PP_DITHER_V", version);
305 switch (version) {
306 case 1:
307 msm_property_install_blob(&c_conn->property_info, prop_name,
308 DRM_MODE_PROP_BLOB,
309 CONNECTOR_PROP_PP_DITHER);
310 len = sizeof(struct drm_msm_dither);
311 cfg = kzalloc(len, GFP_KERNEL);
312 if (!cfg)
313 return;
314
315 ret = _sde_connector_get_default_dither_cfg_v1(c_conn, cfg);
316 if (!ret)
317 defalut_dither_needed = true;
318 break;
319 default:
320 SDE_ERROR("unsupported dither version %d\n", version);
321 return;
322 }
323
324 if (defalut_dither_needed) {
325 blob_ptr = drm_property_create_blob(dev, len, cfg);
326 if (IS_ERR_OR_NULL(blob_ptr))
327 goto exit;
328 c_conn->blob_dither = blob_ptr;
329 }
330exit:
331 kfree(cfg);
332}
333
334int sde_connector_get_dither_cfg(struct drm_connector *conn,
335 struct drm_connector_state *state, void **cfg,
336 size_t *len)
337{
338 struct sde_connector *c_conn = NULL;
339 struct sde_connector_state *c_state = NULL;
340 size_t dither_sz = 0;
341
342 if (!conn || !state || !(*cfg))
343 return -EINVAL;
344
345 c_conn = to_sde_connector(conn);
346 c_state = to_sde_connector_state(state);
347
348 /* try to get user config data first */
349 *cfg = msm_property_get_blob(&c_conn->property_info,
Clarence Ip4a2955d2017-07-04 18:04:33 -0400350 &c_state->property_state,
Ping Li8430ee12017-02-24 14:14:44 -0800351 &dither_sz,
352 CONNECTOR_PROP_PP_DITHER);
353 /* if user config data doesn't exist, use default dither blob */
354 if (*cfg == NULL && c_conn->blob_dither) {
355 *cfg = &c_conn->blob_dither->data;
356 dither_sz = c_conn->blob_dither->length;
357 }
358 *len = dither_sz;
359 return 0;
360}
361
Jeykumar Sankaran905ba332017-10-19 10:45:02 -0700362int sde_connector_get_mode_info(struct drm_connector_state *conn_state,
363 struct msm_mode_info *mode_info)
364{
365 struct sde_connector_state *sde_conn_state = NULL;
366
367 if (!conn_state || !mode_info) {
368 SDE_ERROR("Invalid arguments\n");
369 return -EINVAL;
370 }
371
372 sde_conn_state = to_sde_connector_state(conn_state);
373 memcpy(mode_info, &sde_conn_state->mode_info,
374 sizeof(sde_conn_state->mode_info));
375
376 return 0;
377}
378
Sandeep Panda11b20d82017-06-19 12:57:27 +0530379static int sde_connector_handle_disp_recovery(uint32_t event_idx,
380 uint32_t instance_idx, void *usr,
381 uint32_t data0, uint32_t data1,
382 uint32_t data2, uint32_t data3)
383{
384 struct sde_connector *c_conn = usr;
385 int rc = 0;
386
387 if (!c_conn)
388 return -EINVAL;
389
390 rc = sde_kms_handle_recovery(c_conn->encoder);
391
392 return rc;
393}
394
Clarence Ipcb3afd42016-07-15 16:25:34 -0400395int sde_connector_get_info(struct drm_connector *connector,
396 struct msm_display_info *info)
397{
398 struct sde_connector *c_conn;
399
400 if (!connector || !info) {
401 SDE_ERROR("invalid argument(s), conn %pK, info %pK\n",
402 connector, info);
403 return -EINVAL;
404 }
405
406 c_conn = to_sde_connector(connector);
407
408 if (!c_conn->display || !c_conn->ops.get_info) {
409 SDE_ERROR("display info not supported for %pK\n",
410 c_conn->display);
411 return -EINVAL;
412 }
413
414 return c_conn->ops.get_info(info, c_conn->display);
415}
416
Sandeep Panda98d6ab22017-09-05 08:03:16 +0530417void sde_connector_schedule_status_work(struct drm_connector *connector,
418 bool en)
419{
420 struct sde_connector *c_conn;
421 struct msm_display_info info;
422
423 c_conn = to_sde_connector(connector);
424 if (!c_conn)
425 return;
426
Tharun Raj Somaa658c2e2018-03-16 06:14:08 +0530427 /* Return if there is no change in ESD status check condition */
428 if (en == c_conn->esd_status_check)
429 return;
430
Sandeep Panda98d6ab22017-09-05 08:03:16 +0530431 sde_connector_get_info(connector, &info);
432 if (c_conn->ops.check_status &&
433 (info.capabilities & MSM_DISPLAY_ESD_ENABLED)) {
Jayant Shekhar2c95cfe2018-03-09 11:14:39 +0530434 if (en) {
435 u32 interval;
436
437 /*
438 * If debugfs property is not set then take
439 * default value
440 */
441 interval = c_conn->esd_status_interval ?
442 c_conn->esd_status_interval :
443 STATUS_CHECK_INTERVAL_MS;
Sandeep Panda98d6ab22017-09-05 08:03:16 +0530444 /* Schedule ESD status check */
445 schedule_delayed_work(&c_conn->status_work,
Jayant Shekhar2c95cfe2018-03-09 11:14:39 +0530446 msecs_to_jiffies(interval));
Tharun Raj Somaa658c2e2018-03-16 06:14:08 +0530447 c_conn->esd_status_check = true;
Jayant Shekhar2c95cfe2018-03-09 11:14:39 +0530448 } else {
Sandeep Panda98d6ab22017-09-05 08:03:16 +0530449 /* Cancel any pending ESD status check */
450 cancel_delayed_work_sync(&c_conn->status_work);
Tharun Raj Somaa658c2e2018-03-16 06:14:08 +0530451 c_conn->esd_status_check = false;
Jayant Shekhar2c95cfe2018-03-09 11:14:39 +0530452 }
Sandeep Panda98d6ab22017-09-05 08:03:16 +0530453 }
454}
455
Clarence Ip380b8dc2017-07-27 18:16:13 -0400456static int _sde_connector_update_power_locked(struct sde_connector *c_conn)
457{
458 struct drm_connector *connector;
459 void *display;
460 int (*set_power)(struct drm_connector *, int, void *);
461 int mode, rc = 0;
462
463 if (!c_conn)
464 return -EINVAL;
465 connector = &c_conn->base;
466
467 switch (c_conn->dpms_mode) {
468 case DRM_MODE_DPMS_ON:
469 mode = c_conn->lp_mode;
470 break;
471 case DRM_MODE_DPMS_STANDBY:
472 mode = SDE_MODE_DPMS_STANDBY;
473 break;
474 case DRM_MODE_DPMS_SUSPEND:
475 mode = SDE_MODE_DPMS_SUSPEND;
476 break;
477 case DRM_MODE_DPMS_OFF:
478 mode = SDE_MODE_DPMS_OFF;
479 break;
480 default:
481 mode = c_conn->lp_mode;
482 SDE_ERROR("conn %d dpms set to unrecognized mode %d\n",
483 connector->base.id, mode);
484 break;
485 }
486
487 SDE_EVT32(connector->base.id, c_conn->dpms_mode, c_conn->lp_mode, mode);
488 SDE_DEBUG("conn %d - dpms %d, lp %d, panel %d\n", connector->base.id,
489 c_conn->dpms_mode, c_conn->lp_mode, mode);
490
491 if (mode != c_conn->last_panel_power_mode && c_conn->ops.set_power) {
492 display = c_conn->display;
493 set_power = c_conn->ops.set_power;
494
495 mutex_unlock(&c_conn->lock);
496 rc = set_power(connector, mode, display);
497 mutex_lock(&c_conn->lock);
498 }
499 c_conn->last_panel_power_mode = mode;
500
Tharun Raj Somaa658c2e2018-03-16 06:14:08 +0530501 mutex_unlock(&c_conn->lock);
502 if (mode != SDE_MODE_DPMS_ON)
Sandeep Panda98d6ab22017-09-05 08:03:16 +0530503 sde_connector_schedule_status_work(connector, false);
Tharun Raj Somaa658c2e2018-03-16 06:14:08 +0530504 else
505 sde_connector_schedule_status_work(connector, true);
506 mutex_lock(&c_conn->lock);
Sandeep Panda98d6ab22017-09-05 08:03:16 +0530507
Clarence Ip380b8dc2017-07-27 18:16:13 -0400508 return rc;
509}
510
Xu Yang92377312017-11-23 13:48:08 +0800511static int _sde_connector_update_bl_scale(struct sde_connector *c_conn)
Xu Yang7c42a702017-10-17 10:50:17 +0800512{
Xu Yang7c42a702017-10-17 10:50:17 +0800513 struct dsi_display *dsi_display;
514 struct dsi_backlight_config *bl_config;
Xu Yang7c42a702017-10-17 10:50:17 +0800515 int rc = 0;
516
517 if (!c_conn) {
518 SDE_ERROR("Invalid params sde_connector null\n");
519 return -EINVAL;
520 }
521
Xu Yang7c42a702017-10-17 10:50:17 +0800522 dsi_display = c_conn->display;
523 if (!dsi_display || !dsi_display->panel) {
524 SDE_ERROR("Invalid params(s) dsi_display %pK, panel %pK\n",
525 dsi_display,
526 ((dsi_display) ? dsi_display->panel : NULL));
527 return -EINVAL;
528 }
529
530 bl_config = &dsi_display->panel->bl_config;
Xu Yang7c42a702017-10-17 10:50:17 +0800531
Tharun Raj Soma87208052018-05-18 20:52:10 +0530532 if (dsi_display->panel->bl_config.bl_update ==
533 BL_UPDATE_DELAY_UNTIL_FIRST_FRAME && !c_conn->allow_bl_update) {
534 c_conn->unset_bl_level = bl_config->bl_level;
535 return 0;
536 }
537
538 if (c_conn->unset_bl_level)
539 bl_config->bl_level = c_conn->unset_bl_level;
540
Xu Yang92377312017-11-23 13:48:08 +0800541 if (c_conn->bl_scale > MAX_BL_SCALE_LEVEL)
542 bl_config->bl_scale = MAX_BL_SCALE_LEVEL;
543 else
544 bl_config->bl_scale = c_conn->bl_scale;
545
546 if (c_conn->bl_scale_ad > MAX_AD_BL_SCALE_LEVEL)
547 bl_config->bl_scale_ad = MAX_AD_BL_SCALE_LEVEL;
548 else
549 bl_config->bl_scale_ad = c_conn->bl_scale_ad;
Xu Yang7c42a702017-10-17 10:50:17 +0800550
551 SDE_DEBUG("bl_scale = %u, bl_scale_ad = %u, bl_level = %u\n",
552 bl_config->bl_scale, bl_config->bl_scale_ad,
553 bl_config->bl_level);
554 rc = c_conn->ops.set_backlight(dsi_display, bl_config->bl_level);
Tharun Raj Soma87208052018-05-18 20:52:10 +0530555 c_conn->unset_bl_level = 0;
Xu Yang7c42a702017-10-17 10:50:17 +0800556
557 return rc;
558}
559
Dhaval Patel481babc2017-12-12 22:52:41 -0800560static int _sde_connector_update_dirty_properties(
561 struct drm_connector *connector)
Lloyd Atkinson05d75512017-01-17 14:45:51 -0500562{
563 struct sde_connector *c_conn;
564 struct sde_connector_state *c_state;
Dhaval Patel481babc2017-12-12 22:52:41 -0800565 int idx;
Lloyd Atkinson05d75512017-01-17 14:45:51 -0500566
567 if (!connector) {
568 SDE_ERROR("invalid argument\n");
569 return -EINVAL;
570 }
571
572 c_conn = to_sde_connector(connector);
573 c_state = to_sde_connector_state(connector->state);
574
Clarence Ip380b8dc2017-07-27 18:16:13 -0400575 while ((idx = msm_property_pop_dirty(&c_conn->property_info,
576 &c_state->property_state)) >= 0) {
577 switch (idx) {
578 case CONNECTOR_PROP_LP:
579 mutex_lock(&c_conn->lock);
580 c_conn->lp_mode = sde_connector_get_property(
581 connector->state, CONNECTOR_PROP_LP);
582 _sde_connector_update_power_locked(c_conn);
583 mutex_unlock(&c_conn->lock);
584 break;
Xu Yang7c42a702017-10-17 10:50:17 +0800585 case CONNECTOR_PROP_BL_SCALE:
586 case CONNECTOR_PROP_AD_BL_SCALE:
Xu Yang92377312017-11-23 13:48:08 +0800587 _sde_connector_update_bl_scale(c_conn);
Xu Yang7c42a702017-10-17 10:50:17 +0800588 break;
Clarence Ip380b8dc2017-07-27 18:16:13 -0400589 default:
590 /* nothing to do for most properties */
591 break;
592 }
593 }
594
Tharun Raj Soma87208052018-05-18 20:52:10 +0530595 /*
596 * Special handling for postproc properties and
597 * for updating backlight if any unset backlight level is present
598 */
599 if (c_conn->bl_scale_dirty || c_conn->unset_bl_level) {
Xu Yang92377312017-11-23 13:48:08 +0800600 _sde_connector_update_bl_scale(c_conn);
601 c_conn->bl_scale_dirty = false;
602 }
603
Dhaval Patel481babc2017-12-12 22:52:41 -0800604 return 0;
605}
606
607int sde_connector_pre_kickoff(struct drm_connector *connector)
608{
609 struct sde_connector *c_conn;
610 struct sde_connector_state *c_state;
611 struct msm_display_kickoff_params params;
612 int rc;
613
614 if (!connector) {
615 SDE_ERROR("invalid argument\n");
616 return -EINVAL;
617 }
618
619 c_conn = to_sde_connector(connector);
620 c_state = to_sde_connector_state(connector->state);
621 if (!c_conn->display) {
622 SDE_ERROR("invalid connector display\n");
623 return -EINVAL;
624 }
625
626 rc = _sde_connector_update_dirty_properties(connector);
627 if (rc) {
628 SDE_EVT32(connector->base.id, SDE_EVTLOG_ERROR);
629 goto end;
630 }
631
Lloyd Atkinson05d75512017-01-17 14:45:51 -0500632 if (!c_conn->ops.pre_kickoff)
633 return 0;
634
635 params.rois = &c_state->rois;
Ajay Singh Parmare927aa42017-11-01 00:33:20 -0700636 params.hdr_meta = &c_state->hdr_meta;
Lloyd Atkinson05d75512017-01-17 14:45:51 -0500637
638 SDE_EVT32_VERBOSE(connector->base.id);
639
640 rc = c_conn->ops.pre_kickoff(connector, c_conn->display, &params);
641
Dhaval Patel481babc2017-12-12 22:52:41 -0800642end:
Lloyd Atkinson05d75512017-01-17 14:45:51 -0500643 return rc;
644}
645
Dhaval Patel481babc2017-12-12 22:52:41 -0800646void sde_connector_helper_bridge_disable(struct drm_connector *connector)
647{
648 int rc;
Sandeep Panda9eee1932018-04-25 11:25:42 +0530649 struct sde_connector *c_conn = NULL;
Dhaval Patel481babc2017-12-12 22:52:41 -0800650
651 if (!connector)
652 return;
653
654 rc = _sde_connector_update_dirty_properties(connector);
655 if (rc) {
656 SDE_ERROR("conn %d final pre kickoff failed %d\n",
657 connector->base.id, rc);
658 SDE_EVT32(connector->base.id, SDE_EVTLOG_ERROR);
659 }
Sandeep Panda9eee1932018-04-25 11:25:42 +0530660
Sandeep Pandaf20db722018-05-04 10:56:59 +0530661 /* Disable ESD thread */
662 sde_connector_schedule_status_work(connector, false);
663
Sandeep Panda9eee1932018-04-25 11:25:42 +0530664 c_conn = to_sde_connector(connector);
Tharun Raj Soma87208052018-05-18 20:52:10 +0530665 if (c_conn->bl_device) {
Sandeep Panda9eee1932018-04-25 11:25:42 +0530666 c_conn->bl_device->props.power = FB_BLANK_POWERDOWN;
667 c_conn->bl_device->props.state |= BL_CORE_FBBLANK;
668 backlight_update_status(c_conn->bl_device);
669 }
Tharun Raj Soma87208052018-05-18 20:52:10 +0530670
671 c_conn->allow_bl_update = false;
Sandeep Panda9eee1932018-04-25 11:25:42 +0530672}
673
674void sde_connector_helper_bridge_enable(struct drm_connector *connector)
675{
676 struct sde_connector *c_conn = NULL;
Tharun Raj Soma87208052018-05-18 20:52:10 +0530677 struct dsi_display *display;
Sandeep Panda9eee1932018-04-25 11:25:42 +0530678
679 if (!connector)
680 return;
681
682 c_conn = to_sde_connector(connector);
Tharun Raj Soma87208052018-05-18 20:52:10 +0530683 display = (struct dsi_display *) c_conn->display;
Sandeep Panda9eee1932018-04-25 11:25:42 +0530684
Tharun Raj Soma87208052018-05-18 20:52:10 +0530685 /*
686 * Special handling for some panels which need atleast
687 * one frame to be transferred to GRAM before enabling backlight.
688 * So delay backlight update to these panels until the
689 * first frame commit is received from the HW.
690 */
691 if (display->panel->bl_config.bl_update ==
692 BL_UPDATE_DELAY_UNTIL_FIRST_FRAME)
693 sde_encoder_wait_for_event(c_conn->encoder,
694 MSM_ENC_TX_COMPLETE);
695 c_conn->allow_bl_update = true;
696
697 if (c_conn->bl_device) {
Sandeep Panda9eee1932018-04-25 11:25:42 +0530698 c_conn->bl_device->props.power = FB_BLANK_UNBLANK;
699 c_conn->bl_device->props.state &= ~BL_CORE_FBBLANK;
700 backlight_update_status(c_conn->bl_device);
Sandeep Panda9eee1932018-04-25 11:25:42 +0530701 }
Tharun Raj Soma87208052018-05-18 20:52:10 +0530702 c_conn->panel_dead = false;
Dhaval Patel481babc2017-12-12 22:52:41 -0800703}
704
Alan Kwong1124f1f2017-11-10 18:14:39 -0500705int sde_connector_clk_ctrl(struct drm_connector *connector, bool enable)
Veera Sundaram Sankaranbb2bf9a2017-03-29 18:56:47 -0700706{
707 struct sde_connector *c_conn;
708 struct dsi_display *display;
709 u32 state = enable ? DSI_CLK_ON : DSI_CLK_OFF;
Alan Kwong1124f1f2017-11-10 18:14:39 -0500710 int rc = 0;
Veera Sundaram Sankaranbb2bf9a2017-03-29 18:56:47 -0700711
712 if (!connector) {
713 SDE_ERROR("invalid connector\n");
Alan Kwong1124f1f2017-11-10 18:14:39 -0500714 return -EINVAL;
Veera Sundaram Sankaranbb2bf9a2017-03-29 18:56:47 -0700715 }
716
717 c_conn = to_sde_connector(connector);
718 display = (struct dsi_display *) c_conn->display;
719
720 if (display && c_conn->ops.clk_ctrl)
Alan Kwong1124f1f2017-11-10 18:14:39 -0500721 rc = c_conn->ops.clk_ctrl(display->mdp_clk_handle,
Veera Sundaram Sankaranbb2bf9a2017-03-29 18:56:47 -0700722 DSI_ALL_CLKS, state);
Alan Kwong1124f1f2017-11-10 18:14:39 -0500723
724 return rc;
Veera Sundaram Sankaranbb2bf9a2017-03-29 18:56:47 -0700725}
726
Narender Ankam1afbd172020-03-16 17:27:44 +0530727enum sde_csc_type sde_connector_get_csc_type(struct drm_connector *conn)
728{
729 struct sde_connector *c_conn;
730
731 if (!conn) {
732 SDE_ERROR("invalid argument\n");
733 return -EINVAL;
734 }
735
736 c_conn = to_sde_connector(conn);
737
738 if (!c_conn->display) {
739 SDE_ERROR("invalid argument\n");
740 return -EINVAL;
741 }
742
743 if (!c_conn->ops.get_csc_type)
744 return SDE_CSC_RGB2YUV_601L;
745
746 return c_conn->ops.get_csc_type(conn, c_conn->display);
747}
748
Chirag Khuranace2aa512019-11-20 18:27:03 +0530749bool sde_connector_mode_needs_full_range(struct drm_connector *connector)
750{
751 struct sde_connector *c_conn;
752
753 if (!connector) {
754 SDE_ERROR("invalid argument\n");
755 return false;
756 }
757
758 c_conn = to_sde_connector(connector);
759
760 if (!c_conn->display) {
761 SDE_ERROR("invalid argument\n");
762 return false;
763 }
764
765 if (!c_conn->ops.mode_needs_full_range)
766 return false;
767
768 return c_conn->ops.mode_needs_full_range(c_conn->display);
769}
770
Clarence Ipdd8021c2016-07-20 16:39:47 -0400771static void sde_connector_destroy(struct drm_connector *connector)
772{
773 struct sde_connector *c_conn;
774
775 if (!connector) {
776 SDE_ERROR("invalid connector\n");
777 return;
778 }
779
780 c_conn = to_sde_connector(connector);
781
Sandeep Panda98d6ab22017-09-05 08:03:16 +0530782 /* cancel if any pending esd work */
783 sde_connector_schedule_status_work(connector, false);
784
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -0700785 if (c_conn->ops.put_modes)
786 c_conn->ops.put_modes(connector, c_conn->display);
787
Dhaval Patel4e574842016-08-23 15:11:37 -0700788 if (c_conn->blob_caps)
789 drm_property_unreference_blob(c_conn->blob_caps);
Ping Li898b1bf2017-02-09 18:03:28 -0800790 if (c_conn->blob_hdr)
791 drm_property_unreference_blob(c_conn->blob_hdr);
Ping Li8430ee12017-02-24 14:14:44 -0800792 if (c_conn->blob_dither)
793 drm_property_unreference_blob(c_conn->blob_dither);
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -0700794 if (c_conn->blob_mode_info)
795 drm_property_unreference_blob(c_conn->blob_mode_info);
Ajay Singh Parmar4dabdfc2017-11-09 16:54:25 -0800796 if (c_conn->blob_ext_hdr)
797 drm_property_unreference_blob(c_conn->blob_ext_hdr);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400798 msm_property_destroy(&c_conn->property_info);
799
Dhaval Patel959fdab2017-08-25 15:15:39 -0700800 if (c_conn->bl_device)
801 backlight_device_unregister(c_conn->bl_device);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400802 drm_connector_unregister(connector);
Clarence Ip90b282d2017-05-04 10:00:32 -0700803 mutex_destroy(&c_conn->lock);
Clarence Ipe59fb3f2016-07-26 13:39:59 -0400804 sde_fence_deinit(&c_conn->retire_fence);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400805 drm_connector_cleanup(connector);
806 kfree(c_conn);
807}
808
809/**
810 * _sde_connector_destroy_fb - clean up connector state's out_fb buffer
811 * @c_conn: Pointer to sde connector structure
812 * @c_state: Pointer to sde connector state structure
813 */
814static void _sde_connector_destroy_fb(struct sde_connector *c_conn,
815 struct sde_connector_state *c_state)
816{
817 if (!c_state || !c_state->out_fb) {
818 SDE_ERROR("invalid state %pK\n", c_state);
819 return;
820 }
821
Clarence Ipdd8021c2016-07-20 16:39:47 -0400822 drm_framebuffer_unreference(c_state->out_fb);
823 c_state->out_fb = NULL;
824
Clarence Ip4a2955d2017-07-04 18:04:33 -0400825 if (c_conn)
826 c_state->property_values[CONNECTOR_PROP_OUT_FB].value =
Clarence Ipdd8021c2016-07-20 16:39:47 -0400827 msm_property_get_default(&c_conn->property_info,
828 CONNECTOR_PROP_OUT_FB);
Clarence Ip4a2955d2017-07-04 18:04:33 -0400829 else
830 c_state->property_values[CONNECTOR_PROP_OUT_FB].value = ~0;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400831}
832
833static void sde_connector_atomic_destroy_state(struct drm_connector *connector,
834 struct drm_connector_state *state)
835{
836 struct sde_connector *c_conn = NULL;
837 struct sde_connector_state *c_state = NULL;
838
839 if (!state) {
840 SDE_ERROR("invalid state\n");
841 return;
842 }
843
844 /*
845 * The base DRM framework currently always passes in a NULL
846 * connector pointer. This is not correct, but attempt to
847 * handle that case as much as possible.
848 */
849 if (connector)
850 c_conn = to_sde_connector(connector);
851 c_state = to_sde_connector_state(state);
852
853 if (c_state->out_fb)
854 _sde_connector_destroy_fb(c_conn, c_state);
855
Clarence Ipb2c4fd62017-09-21 17:28:38 -0400856 __drm_atomic_helper_connector_destroy_state(&c_state->base);
857
Clarence Ipdd8021c2016-07-20 16:39:47 -0400858 if (!c_conn) {
859 kfree(c_state);
860 } else {
861 /* destroy value helper */
862 msm_property_destroy_state(&c_conn->property_info, c_state,
Clarence Ip4a2955d2017-07-04 18:04:33 -0400863 &c_state->property_state);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400864 }
865}
866
867static void sde_connector_atomic_reset(struct drm_connector *connector)
868{
869 struct sde_connector *c_conn;
870 struct sde_connector_state *c_state;
871
872 if (!connector) {
873 SDE_ERROR("invalid connector\n");
874 return;
875 }
876
877 c_conn = to_sde_connector(connector);
878
Veera Sundaram Sankarandb43e282017-09-19 18:32:52 -0700879 if (connector->state &&
880 !sde_crtc_is_reset_required(connector->state->crtc)) {
881 SDE_DEBUG_CONN(c_conn, "avoid reset for connector\n");
882 return;
883 }
884
Clarence Ipdd8021c2016-07-20 16:39:47 -0400885 if (connector->state) {
886 sde_connector_atomic_destroy_state(connector, connector->state);
887 connector->state = 0;
888 }
889
890 c_state = msm_property_alloc_state(&c_conn->property_info);
891 if (!c_state) {
892 SDE_ERROR("state alloc failed\n");
893 return;
894 }
895
896 /* reset value helper, zero out state structure and reset properties */
897 msm_property_reset_state(&c_conn->property_info, c_state,
Clarence Ip4a2955d2017-07-04 18:04:33 -0400898 &c_state->property_state,
899 c_state->property_values);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400900
Clarence Ipb2c4fd62017-09-21 17:28:38 -0400901 __drm_atomic_helper_connector_reset(connector, &c_state->base);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400902}
903
904static struct drm_connector_state *
905sde_connector_atomic_duplicate_state(struct drm_connector *connector)
906{
907 struct sde_connector *c_conn;
908 struct sde_connector_state *c_state, *c_oldstate;
Clarence Ipdd8021c2016-07-20 16:39:47 -0400909
910 if (!connector || !connector->state) {
911 SDE_ERROR("invalid connector %pK\n", connector);
912 return NULL;
913 }
914
915 c_conn = to_sde_connector(connector);
916 c_oldstate = to_sde_connector_state(connector->state);
917 c_state = msm_property_alloc_state(&c_conn->property_info);
918 if (!c_state) {
919 SDE_ERROR("state alloc failed\n");
920 return NULL;
921 }
922
923 /* duplicate value helper */
924 msm_property_duplicate_state(&c_conn->property_info,
Clarence Ip4a2955d2017-07-04 18:04:33 -0400925 c_oldstate, c_state,
926 &c_state->property_state, c_state->property_values);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400927
Clarence Ipb2c4fd62017-09-21 17:28:38 -0400928 __drm_atomic_helper_connector_duplicate_state(connector,
929 &c_state->base);
930
Clarence Ipdd8021c2016-07-20 16:39:47 -0400931 /* additional handling for drm framebuffer objects */
Alan Kwong03b89842017-08-17 16:32:45 -0400932 if (c_state->out_fb)
Clarence Ipdd8021c2016-07-20 16:39:47 -0400933 drm_framebuffer_reference(c_state->out_fb);
Clarence Ipdd8021c2016-07-20 16:39:47 -0400934
935 return &c_state->base;
936}
937
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -0700938int sde_connector_roi_v1_check_roi(struct drm_connector_state *conn_state)
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400939{
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -0700940 const struct msm_roi_alignment *align = NULL;
941 struct sde_connector *c_conn = NULL;
942 struct msm_mode_info mode_info;
943 struct sde_connector_state *c_state;
Jeykumar Sankaran905ba332017-10-19 10:45:02 -0700944 int i, w, h;
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400945
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -0700946 if (!conn_state)
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400947 return -EINVAL;
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -0700948
949 memset(&mode_info, 0, sizeof(mode_info));
950
951 c_state = to_sde_connector_state(conn_state);
952 c_conn = to_sde_connector(conn_state->connector);
953
Jeykumar Sankaran905ba332017-10-19 10:45:02 -0700954 memcpy(&mode_info, &c_state->mode_info, sizeof(c_state->mode_info));
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400955
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -0700956 if (!mode_info.roi_caps.enabled)
957 return 0;
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400958
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -0700959 if (c_state->rois.num_rects > mode_info.roi_caps.num_roi) {
960 SDE_ERROR_CONN(c_conn, "too many rects specified: %d > %d\n",
961 c_state->rois.num_rects,
962 mode_info.roi_caps.num_roi);
963 return -E2BIG;
964 };
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400965
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -0700966 align = &mode_info.roi_caps.align;
967 for (i = 0; i < c_state->rois.num_rects; ++i) {
968 struct drm_clip_rect *roi_conn;
Lloyd Atkinson8ba47032017-03-22 17:13:32 -0400969
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -0700970 roi_conn = &c_state->rois.roi[i];
971 w = roi_conn->x2 - roi_conn->x1;
972 h = roi_conn->y2 - roi_conn->y1;
973
Lloyd Atkinson5ca13aa2017-10-26 18:12:20 -0400974 SDE_EVT32_VERBOSE(DRMID(&c_conn->base),
975 roi_conn->x1, roi_conn->y1,
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -0700976 roi_conn->x2, roi_conn->y2);
977
978 if (w <= 0 || h <= 0) {
979 SDE_ERROR_CONN(c_conn, "invalid conn roi w %d h %d\n",
980 w, h);
981 return -EINVAL;
982 }
983
984 if (w < align->min_width || w % align->width_pix_align) {
985 SDE_ERROR_CONN(c_conn,
986 "invalid conn roi width %d min %d align %d\n",
987 w, align->min_width,
988 align->width_pix_align);
989 return -EINVAL;
990 }
991
992 if (h < align->min_height || h % align->height_pix_align) {
993 SDE_ERROR_CONN(c_conn,
994 "invalid conn roi height %d min %d align %d\n",
995 h, align->min_height,
996 align->height_pix_align);
997 return -EINVAL;
998 }
999
1000 if (roi_conn->x1 % align->xstart_pix_align) {
1001 SDE_ERROR_CONN(c_conn,
1002 "invalid conn roi x1 %d align %d\n",
1003 roi_conn->x1, align->xstart_pix_align);
1004 return -EINVAL;
1005 }
1006
1007 if (roi_conn->y1 % align->ystart_pix_align) {
1008 SDE_ERROR_CONN(c_conn,
1009 "invalid conn roi y1 %d align %d\n",
1010 roi_conn->y1, align->ystart_pix_align);
1011 return -EINVAL;
1012 }
Lloyd Atkinson8ba47032017-03-22 17:13:32 -04001013 }
1014
1015 return 0;
1016}
1017
1018static int _sde_connector_set_roi_v1(
1019 struct sde_connector *c_conn,
1020 struct sde_connector_state *c_state,
1021 void *usr_ptr)
1022{
1023 struct sde_drm_roi_v1 roi_v1;
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07001024 int i;
Lloyd Atkinson8ba47032017-03-22 17:13:32 -04001025
1026 if (!c_conn || !c_state) {
1027 SDE_ERROR("invalid args\n");
1028 return -EINVAL;
1029 }
1030
Lloyd Atkinson8ba47032017-03-22 17:13:32 -04001031 memset(&c_state->rois, 0, sizeof(c_state->rois));
1032
1033 if (!usr_ptr) {
1034 SDE_DEBUG_CONN(c_conn, "rois cleared\n");
1035 return 0;
1036 }
1037
1038 if (copy_from_user(&roi_v1, usr_ptr, sizeof(roi_v1))) {
1039 SDE_ERROR_CONN(c_conn, "failed to copy roi_v1 data\n");
1040 return -EINVAL;
1041 }
1042
1043 SDE_DEBUG_CONN(c_conn, "num_rects %d\n", roi_v1.num_rects);
1044
1045 if (roi_v1.num_rects == 0) {
1046 SDE_DEBUG_CONN(c_conn, "rois cleared\n");
1047 return 0;
1048 }
1049
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07001050 if (roi_v1.num_rects > SDE_MAX_ROI_V1) {
1051 SDE_ERROR_CONN(c_conn, "num roi rects more than supported: %d",
Lloyd Atkinson8ba47032017-03-22 17:13:32 -04001052 roi_v1.num_rects);
1053 return -EINVAL;
1054 }
1055
1056 c_state->rois.num_rects = roi_v1.num_rects;
1057 for (i = 0; i < roi_v1.num_rects; ++i) {
Lloyd Atkinson8ba47032017-03-22 17:13:32 -04001058 c_state->rois.roi[i] = roi_v1.roi[i];
Lloyd Atkinsonab5e2b62017-05-09 13:06:51 -04001059 SDE_DEBUG_CONN(c_conn, "roi%d: roi (%d,%d) (%d,%d)\n", i,
Lloyd Atkinson8ba47032017-03-22 17:13:32 -04001060 c_state->rois.roi[i].x1,
1061 c_state->rois.roi[i].y1,
1062 c_state->rois.roi[i].x2,
1063 c_state->rois.roi[i].y2);
1064 }
1065
1066 return 0;
1067}
1068
Ajay Singh Parmare927aa42017-11-01 00:33:20 -07001069static int _sde_connector_set_ext_hdr_info(
1070 struct sde_connector *c_conn,
1071 struct sde_connector_state *c_state,
1072 void *usr_ptr)
1073{
Ajay Singh Parmar87af50b2017-12-22 22:22:55 -08001074 int rc = 0;
Ajay Singh Parmare927aa42017-11-01 00:33:20 -07001075 struct drm_connector *connector;
1076 struct drm_msm_ext_hdr_metadata *hdr_meta;
1077 int i;
1078
1079 if (!c_conn || !c_state) {
1080 SDE_ERROR_CONN(c_conn, "invalid args\n");
Ajay Singh Parmar87af50b2017-12-22 22:22:55 -08001081 rc = -EINVAL;
1082 goto end;
Ajay Singh Parmare927aa42017-11-01 00:33:20 -07001083 }
1084
1085 connector = &c_conn->base;
1086
1087 if (!connector->hdr_supported) {
1088 SDE_ERROR_CONN(c_conn, "sink doesn't support HDR\n");
Ajay Singh Parmar87af50b2017-12-22 22:22:55 -08001089 rc = -ENOTSUPP;
1090 goto end;
Ajay Singh Parmare927aa42017-11-01 00:33:20 -07001091 }
1092
1093 memset(&c_state->hdr_meta, 0, sizeof(c_state->hdr_meta));
1094
1095 if (!usr_ptr) {
1096 SDE_DEBUG_CONN(c_conn, "hdr metadata cleared\n");
Ajay Singh Parmar87af50b2017-12-22 22:22:55 -08001097 goto end;
Ajay Singh Parmare927aa42017-11-01 00:33:20 -07001098 }
1099
1100 if (copy_from_user(&c_state->hdr_meta,
1101 (void __user *)usr_ptr,
1102 sizeof(*hdr_meta))) {
1103 SDE_ERROR_CONN(c_conn, "failed to copy hdr metadata\n");
Ajay Singh Parmar87af50b2017-12-22 22:22:55 -08001104 rc = -EFAULT;
1105 goto end;
Ajay Singh Parmare927aa42017-11-01 00:33:20 -07001106 }
1107
1108 hdr_meta = &c_state->hdr_meta;
1109
1110 SDE_DEBUG_CONN(c_conn, "hdr_state %d\n", hdr_meta->hdr_state);
1111 SDE_DEBUG_CONN(c_conn, "hdr_supported %d\n", hdr_meta->hdr_supported);
1112 SDE_DEBUG_CONN(c_conn, "eotf %d\n", hdr_meta->eotf);
1113 SDE_DEBUG_CONN(c_conn, "white_point_x %d\n", hdr_meta->white_point_x);
1114 SDE_DEBUG_CONN(c_conn, "white_point_y %d\n", hdr_meta->white_point_y);
1115 SDE_DEBUG_CONN(c_conn, "max_luminance %d\n", hdr_meta->max_luminance);
1116 SDE_DEBUG_CONN(c_conn, "max_content_light_level %d\n",
1117 hdr_meta->max_content_light_level);
1118 SDE_DEBUG_CONN(c_conn, "max_average_light_level %d\n",
1119 hdr_meta->max_average_light_level);
1120
1121 for (i = 0; i < HDR_PRIMARIES_COUNT; i++) {
1122 SDE_DEBUG_CONN(c_conn, "display_primaries_x [%d]\n",
1123 hdr_meta->display_primaries_x[i]);
1124 SDE_DEBUG_CONN(c_conn, "display_primaries_y [%d]\n",
1125 hdr_meta->display_primaries_y[i]);
1126 }
1127
Ajay Singh Parmar87af50b2017-12-22 22:22:55 -08001128 if (c_conn->ops.config_hdr)
1129 rc = c_conn->ops.config_hdr(c_conn->display, c_state);
1130end:
1131 return rc;
Ajay Singh Parmare927aa42017-11-01 00:33:20 -07001132}
1133
Clarence Ipdd8021c2016-07-20 16:39:47 -04001134static int sde_connector_atomic_set_property(struct drm_connector *connector,
1135 struct drm_connector_state *state,
1136 struct drm_property *property,
1137 uint64_t val)
1138{
1139 struct sde_connector *c_conn;
1140 struct sde_connector_state *c_state;
1141 int idx, rc;
Dhaval Patelb24b2d62017-11-03 18:10:26 -07001142 uint64_t fence_fd;
Clarence Ipdd8021c2016-07-20 16:39:47 -04001143
1144 if (!connector || !state || !property) {
1145 SDE_ERROR("invalid argument(s), conn %pK, state %pK, prp %pK\n",
1146 connector, state, property);
1147 return -EINVAL;
1148 }
1149
1150 c_conn = to_sde_connector(connector);
1151 c_state = to_sde_connector_state(state);
1152
1153 /* generic property handling */
1154 rc = msm_property_atomic_set(&c_conn->property_info,
Clarence Ip4a2955d2017-07-04 18:04:33 -04001155 &c_state->property_state, property, val);
Clarence Ipdd8021c2016-07-20 16:39:47 -04001156 if (rc)
1157 goto end;
1158
1159 /* connector-specific property handling */
1160 idx = msm_property_index(&c_conn->property_info, property);
Clarence Ip90b282d2017-05-04 10:00:32 -07001161 switch (idx) {
1162 case CONNECTOR_PROP_OUT_FB:
Clarence Ipdd8021c2016-07-20 16:39:47 -04001163 /* clear old fb, if present */
1164 if (c_state->out_fb)
1165 _sde_connector_destroy_fb(c_conn, c_state);
1166
1167 /* convert fb val to drm framebuffer and prepare it */
1168 c_state->out_fb =
1169 drm_framebuffer_lookup(connector->dev, val);
Alan Kwongae1b1142017-03-05 16:07:10 -08001170 if (!c_state->out_fb && val) {
Clarence Ipdd8021c2016-07-20 16:39:47 -04001171 SDE_ERROR("failed to look up fb %lld\n", val);
1172 rc = -EFAULT;
Alan Kwongae1b1142017-03-05 16:07:10 -08001173 } else if (!c_state->out_fb && !val) {
1174 SDE_DEBUG("cleared fb_id\n");
1175 rc = 0;
Clarence Ipdd8021c2016-07-20 16:39:47 -04001176 } else {
Alan Kwong578cdaf2017-01-28 17:25:43 -08001177 msm_framebuffer_set_kmap(c_state->out_fb,
1178 c_conn->fb_kmap);
Clarence Ipdd8021c2016-07-20 16:39:47 -04001179 }
Clarence Ip90b282d2017-05-04 10:00:32 -07001180 break;
Dhaval Patelb24b2d62017-11-03 18:10:26 -07001181 case CONNECTOR_PROP_RETIRE_FENCE:
Dhaval Pateladbac6f2017-11-16 17:16:18 -08001182 if (!val)
1183 goto end;
1184
Dhaval Patelb24b2d62017-11-03 18:10:26 -07001185 rc = sde_fence_create(&c_conn->retire_fence, &fence_fd, 0);
1186 if (rc) {
1187 SDE_ERROR("fence create failed rc:%d\n", rc);
1188 goto end;
1189 }
Lloyd Atkinson11f34442016-08-11 11:19:52 -04001190
Jayant Shekhar82e3c882018-06-22 18:04:09 +05301191 rc = copy_to_user((uint64_t __user *)(uintptr_t)val, &fence_fd,
Dhaval Patelb24b2d62017-11-03 18:10:26 -07001192 sizeof(uint64_t));
1193 if (rc) {
1194 SDE_ERROR("copy to user failed rc:%d\n", rc);
1195 /* fence will be released with timeline update */
1196 put_unused_fd(fence_fd);
1197 rc = -EFAULT;
1198 goto end;
1199 }
1200 break;
1201 case CONNECTOR_PROP_ROI_V1:
Jayant Shekhar82e3c882018-06-22 18:04:09 +05301202 rc = _sde_connector_set_roi_v1(c_conn, c_state,
1203 (void *)(uintptr_t)val);
Lloyd Atkinson8ba47032017-03-22 17:13:32 -04001204 if (rc)
1205 SDE_ERROR_CONN(c_conn, "invalid roi_v1, rc: %d\n", rc);
Dhaval Patelb24b2d62017-11-03 18:10:26 -07001206 break;
Xu Yang92377312017-11-23 13:48:08 +08001207 /* CONNECTOR_PROP_BL_SCALE and CONNECTOR_PROP_AD_BL_SCALE are
1208 * color-processing properties. These two properties require
1209 * special handling since they don't quite fit the current standard
1210 * atomic set property framework.
1211 */
1212 case CONNECTOR_PROP_BL_SCALE:
1213 c_conn->bl_scale = val;
1214 c_conn->bl_scale_dirty = true;
1215 break;
1216 case CONNECTOR_PROP_AD_BL_SCALE:
1217 c_conn->bl_scale_ad = val;
1218 c_conn->bl_scale_dirty = true;
1219 break;
Dhaval Patelb24b2d62017-11-03 18:10:26 -07001220 default:
1221 break;
Lloyd Atkinson8ba47032017-03-22 17:13:32 -04001222 }
1223
Ajay Singh Parmare927aa42017-11-01 00:33:20 -07001224 if (idx == CONNECTOR_PROP_HDR_METADATA) {
1225 rc = _sde_connector_set_ext_hdr_info(c_conn,
Jayant Shekhar82e3c882018-06-22 18:04:09 +05301226 c_state, (void *)(uintptr_t)val);
Ajay Singh Parmare927aa42017-11-01 00:33:20 -07001227 if (rc)
1228 SDE_ERROR_CONN(c_conn, "cannot set hdr info %d\n", rc);
1229 }
1230
Clarence Ipdd8021c2016-07-20 16:39:47 -04001231 /* check for custom property handling */
1232 if (!rc && c_conn->ops.set_property) {
1233 rc = c_conn->ops.set_property(connector,
1234 state,
1235 idx,
1236 val,
1237 c_conn->display);
1238
1239 /* potentially clean up out_fb if rc != 0 */
1240 if ((idx == CONNECTOR_PROP_OUT_FB) && rc)
1241 _sde_connector_destroy_fb(c_conn, c_state);
1242 }
1243end:
1244 return rc;
1245}
1246
1247static int sde_connector_set_property(struct drm_connector *connector,
1248 struct drm_property *property,
1249 uint64_t val)
1250{
1251 if (!connector) {
1252 SDE_ERROR("invalid connector\n");
1253 return -EINVAL;
1254 }
1255
1256 return sde_connector_atomic_set_property(connector,
1257 connector->state, property, val);
1258}
1259
1260static int sde_connector_atomic_get_property(struct drm_connector *connector,
1261 const struct drm_connector_state *state,
1262 struct drm_property *property,
1263 uint64_t *val)
1264{
1265 struct sde_connector *c_conn;
1266 struct sde_connector_state *c_state;
1267 int idx, rc = -EINVAL;
1268
1269 if (!connector || !state) {
1270 SDE_ERROR("invalid argument(s), conn %pK, state %pK\n",
1271 connector, state);
1272 return -EINVAL;
1273 }
1274
1275 c_conn = to_sde_connector(connector);
1276 c_state = to_sde_connector_state(state);
1277
1278 idx = msm_property_index(&c_conn->property_info, property);
Dhaval Patel1f5a5a22017-11-06 23:06:09 -08001279 if (idx == CONNECTOR_PROP_RETIRE_FENCE) {
1280 *val = ~0;
1281 rc = 0;
1282 } else {
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001283 /* get cached property value */
1284 rc = msm_property_atomic_get(&c_conn->property_info,
Clarence Ip4a2955d2017-07-04 18:04:33 -04001285 &c_state->property_state, property, val);
Dhaval Patel1f5a5a22017-11-06 23:06:09 -08001286 }
Clarence Ipdd8021c2016-07-20 16:39:47 -04001287
1288 /* allow for custom override */
1289 if (c_conn->ops.get_property)
1290 rc = c_conn->ops.get_property(connector,
1291 (struct drm_connector_state *)state,
1292 idx,
1293 val,
1294 c_conn->display);
1295 return rc;
1296}
1297
Dhaval Patel2a3c37a2017-10-25 12:30:36 -07001298void sde_conn_timeline_status(struct drm_connector *conn)
1299{
1300 struct sde_connector *c_conn;
1301
1302 if (!conn) {
1303 SDE_ERROR("invalid connector\n");
1304 return;
1305 }
1306
1307 c_conn = to_sde_connector(conn);
1308 sde_fence_timeline_status(&c_conn->retire_fence, &conn->base);
1309}
1310
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001311void sde_connector_prepare_fence(struct drm_connector *connector)
1312{
1313 if (!connector) {
1314 SDE_ERROR("invalid connector\n");
1315 return;
1316 }
1317
1318 sde_fence_prepare(&to_sde_connector(connector)->retire_fence);
1319}
1320
Veera Sundaram Sankaran675ff622017-06-21 21:44:46 -07001321void sde_connector_complete_commit(struct drm_connector *connector,
Prabhanjan Kandula33151182018-03-28 11:44:09 -07001322 ktime_t ts, enum sde_fence_event fence_event)
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001323{
1324 if (!connector) {
1325 SDE_ERROR("invalid connector\n");
1326 return;
1327 }
1328
1329 /* signal connector's retire fence */
Prabhanjan Kandula33151182018-03-28 11:44:09 -07001330 sde_fence_signal(&to_sde_connector(connector)->retire_fence,
1331 ts, fence_event);
Dhaval Patelfd8f7742017-08-10 13:11:22 -07001332}
1333
1334void sde_connector_commit_reset(struct drm_connector *connector, ktime_t ts)
1335{
1336 if (!connector) {
1337 SDE_ERROR("invalid connector\n");
1338 return;
1339 }
1340
1341 /* signal connector's retire fence */
Prabhanjan Kandula33151182018-03-28 11:44:09 -07001342 sde_fence_signal(&to_sde_connector(connector)->retire_fence,
1343 ts, SDE_FENCE_RESET_TIMELINE);
Clarence Ipe59fb3f2016-07-26 13:39:59 -04001344}
1345
Srikanth Rajagopalan30384d12017-06-08 15:23:31 -07001346static void sde_connector_update_hdr_props(struct drm_connector *connector)
1347{
1348 struct sde_connector *c_conn = to_sde_connector(connector);
1349 struct drm_msm_ext_hdr_properties hdr = {};
1350
1351 hdr.hdr_supported = connector->hdr_supported;
1352
1353 if (hdr.hdr_supported) {
1354 hdr.hdr_eotf = connector->hdr_eotf;
1355 hdr.hdr_metadata_type_one = connector->hdr_metadata_type_one;
1356 hdr.hdr_max_luminance = connector->hdr_max_luminance;
1357 hdr.hdr_avg_luminance = connector->hdr_avg_luminance;
1358 hdr.hdr_min_luminance = connector->hdr_min_luminance;
1359
1360 msm_property_set_blob(&c_conn->property_info,
1361 &c_conn->blob_ext_hdr,
1362 &hdr,
1363 sizeof(hdr),
1364 CONNECTOR_PROP_EXT_HDR_INFO);
1365
1366 }
1367}
1368
Clarence Ipdd8021c2016-07-20 16:39:47 -04001369static enum drm_connector_status
1370sde_connector_detect(struct drm_connector *connector, bool force)
1371{
1372 enum drm_connector_status status = connector_status_unknown;
1373 struct sde_connector *c_conn;
1374
1375 if (!connector) {
1376 SDE_ERROR("invalid connector\n");
1377 return status;
1378 }
1379
1380 c_conn = to_sde_connector(connector);
1381
1382 if (c_conn->ops.detect)
1383 status = c_conn->ops.detect(connector,
1384 force,
1385 c_conn->display);
1386
1387 return status;
1388}
1389
Clarence Ip90b282d2017-05-04 10:00:32 -07001390static int sde_connector_dpms(struct drm_connector *connector,
1391 int mode)
1392{
1393 struct sde_connector *c_conn;
1394
1395 if (!connector) {
1396 SDE_ERROR("invalid connector\n");
1397 return -EINVAL;
1398 }
1399 c_conn = to_sde_connector(connector);
1400
1401 /* validate incoming dpms request */
1402 switch (mode) {
1403 case DRM_MODE_DPMS_ON:
1404 case DRM_MODE_DPMS_STANDBY:
1405 case DRM_MODE_DPMS_SUSPEND:
1406 case DRM_MODE_DPMS_OFF:
1407 SDE_DEBUG("conn %d dpms set to %d\n", connector->base.id, mode);
1408 break;
1409 default:
1410 SDE_ERROR("conn %d dpms set to unrecognized mode %d\n",
1411 connector->base.id, mode);
1412 break;
1413 }
1414
1415 mutex_lock(&c_conn->lock);
1416 c_conn->dpms_mode = mode;
1417 _sde_connector_update_power_locked(c_conn);
1418 mutex_unlock(&c_conn->lock);
1419
1420 /* use helper for boilerplate handling */
1421 return drm_atomic_helper_connector_dpms(connector, mode);
1422}
1423
1424int sde_connector_get_dpms(struct drm_connector *connector)
1425{
1426 struct sde_connector *c_conn;
1427 int rc;
1428
1429 if (!connector) {
1430 SDE_DEBUG("invalid connector\n");
1431 return DRM_MODE_DPMS_OFF;
1432 }
1433
1434 c_conn = to_sde_connector(connector);
1435
1436 mutex_lock(&c_conn->lock);
1437 rc = c_conn->dpms_mode;
1438 mutex_unlock(&c_conn->lock);
1439
1440 return rc;
1441}
1442
Clarence Ipd86f6e42017-08-08 18:31:00 -04001443int sde_connector_set_property_for_commit(struct drm_connector *connector,
1444 struct drm_atomic_state *atomic_state,
1445 uint32_t property_idx, uint64_t value)
1446{
1447 struct drm_connector_state *state;
1448 struct drm_property *property;
1449 struct sde_connector *c_conn;
1450
1451 if (!connector || !atomic_state) {
1452 SDE_ERROR("invalid argument(s), conn %d, state %d\n",
1453 connector != NULL, atomic_state != NULL);
1454 return -EINVAL;
1455 }
1456
1457 c_conn = to_sde_connector(connector);
1458 property = msm_property_index_to_drm_property(
1459 &c_conn->property_info, property_idx);
1460 if (!property) {
1461 SDE_ERROR("invalid property index %d\n", property_idx);
1462 return -EINVAL;
1463 }
1464
1465 state = drm_atomic_get_connector_state(atomic_state, connector);
1466 if (IS_ERR_OR_NULL(state)) {
1467 SDE_ERROR("failed to get conn %d state\n",
1468 connector->base.id);
1469 return -EINVAL;
1470 }
1471
1472 return drm_atomic_connector_set_property(
1473 connector, state, property, value);
1474}
1475
Lloyd Atkinsone08229c2017-10-02 17:53:30 -04001476int sde_connector_helper_reset_custom_properties(
1477 struct drm_connector *connector,
1478 struct drm_connector_state *connector_state)
1479{
1480 struct sde_connector *c_conn;
1481 struct sde_connector_state *c_state;
1482 struct drm_property *drm_prop;
1483 enum msm_mdp_conn_property prop_idx;
1484
1485 if (!connector || !connector_state) {
1486 SDE_ERROR("invalid params\n");
1487 return -EINVAL;
1488 }
1489
1490 c_conn = to_sde_connector(connector);
1491 c_state = to_sde_connector_state(connector_state);
1492
1493 for (prop_idx = 0; prop_idx < CONNECTOR_PROP_COUNT; prop_idx++) {
1494 uint64_t val = c_state->property_values[prop_idx].value;
1495 uint64_t def;
1496 int ret;
1497
1498 drm_prop = msm_property_index_to_drm_property(
1499 &c_conn->property_info, prop_idx);
1500 if (!drm_prop) {
1501 /* not all props will be installed, based on caps */
1502 SDE_DEBUG_CONN(c_conn, "invalid property index %d\n",
1503 prop_idx);
1504 continue;
1505 }
1506
1507 def = msm_property_get_default(&c_conn->property_info,
1508 prop_idx);
1509 if (val == def)
1510 continue;
1511
1512 SDE_DEBUG_CONN(c_conn, "set prop %s idx %d from %llu to %llu\n",
1513 drm_prop->name, prop_idx, val, def);
1514
1515 ret = drm_atomic_connector_set_property(connector,
1516 connector_state, drm_prop, def);
1517 if (ret) {
1518 SDE_ERROR_CONN(c_conn,
1519 "set property failed, idx %d ret %d\n",
1520 prop_idx, ret);
1521 continue;
1522 }
1523 }
1524
1525 return 0;
1526}
1527
Kalyan Thota6a9f3b72018-01-18 18:00:02 +05301528int sde_connector_get_panel_vfp(struct drm_connector *connector,
1529 struct drm_display_mode *mode)
1530{
1531 struct sde_connector *c_conn;
1532 int vfp = -EINVAL;
1533
1534 if (!connector || !mode) {
1535 SDE_ERROR("invalid connector\n");
1536 return vfp;
1537 }
1538 c_conn = to_sde_connector(connector);
1539 if (!c_conn->ops.get_panel_vfp)
1540 return vfp;
1541
1542 vfp = c_conn->ops.get_panel_vfp(c_conn->display,
1543 mode->hdisplay, mode->vdisplay);
1544 if (vfp <= 0)
1545 SDE_ERROR("Failed get_panel_vfp %d\n", vfp);
1546
1547 return vfp;
1548}
1549
Govinda Rajulu Chennab95b9c32017-10-13 15:00:32 -04001550static int _sde_debugfs_conn_cmd_tx_open(struct inode *inode, struct file *file)
1551{
1552 /* non-seekable */
1553 file->private_data = inode->i_private;
1554 return nonseekable_open(inode, file);
1555}
1556
1557static ssize_t _sde_debugfs_conn_cmd_tx_sts_read(struct file *file,
1558 char __user *buf, size_t count, loff_t *ppos)
1559{
1560 struct drm_connector *connector = file->private_data;
1561 struct sde_connector *c_conn;
1562 char buffer[MAX_CMD_PAYLOAD_SIZE];
1563 int blen = 0;
1564
1565 if (*ppos)
1566 return 0;
1567
1568 if (!connector) {
1569 SDE_ERROR("invalid argument, conn is NULL\n");
1570 return 0;
1571 }
1572
1573 c_conn = to_sde_connector(connector);
1574
1575 mutex_lock(&c_conn->lock);
1576 blen = snprintf(buffer, MAX_CMD_PAYLOAD_SIZE,
1577 "last_cmd_tx_sts:0x%x",
1578 c_conn->last_cmd_tx_sts);
1579 mutex_unlock(&c_conn->lock);
1580
1581 SDE_DEBUG("output: %s\n", buffer);
1582 if (blen <= 0) {
1583 SDE_ERROR("snprintf failed, blen %d\n", blen);
1584 return 0;
1585 }
1586
Rahul Sharma4a35a492019-08-20 17:12:57 +05301587 if (blen > count)
1588 blen = count;
1589
Govinda Rajulu Chennab95b9c32017-10-13 15:00:32 -04001590 if (copy_to_user(buf, buffer, blen)) {
1591 SDE_ERROR("copy to user buffer failed\n");
1592 return -EFAULT;
1593 }
1594
1595 *ppos += blen;
1596 return blen;
1597}
1598
1599static ssize_t _sde_debugfs_conn_cmd_tx_write(struct file *file,
1600 const char __user *p, size_t count, loff_t *ppos)
1601{
1602 struct drm_connector *connector = file->private_data;
1603 struct sde_connector *c_conn;
1604 char *input, *token, *input_copy, *input_dup = NULL;
1605 const char *delim = " ";
1606 u32 buf_size = 0;
1607 char buffer[MAX_CMD_PAYLOAD_SIZE];
1608 int rc = 0, strtoint;
1609
1610 if (*ppos || !connector) {
1611 SDE_ERROR("invalid argument(s), conn %d\n", connector != NULL);
1612 return 0;
1613 }
1614
1615 c_conn = to_sde_connector(connector);
1616
1617 if (!c_conn->ops.cmd_transfer) {
1618 SDE_ERROR("no cmd transfer support for connector name %s\n",
1619 c_conn->name);
1620 return 0;
1621 }
1622
1623 input = kmalloc(count + 1, GFP_KERNEL);
1624 if (!input)
1625 return -ENOMEM;
1626
1627 if (copy_from_user(input, p, count)) {
1628 SDE_ERROR("copy from user failed\n");
1629 rc = -EFAULT;
1630 goto end;
1631 }
1632 input[count] = '\0';
1633
1634 SDE_DEBUG("input: %s\n", input);
1635
1636 input_copy = kstrdup(input, GFP_KERNEL);
1637 if (!input_copy) {
1638 rc = -ENOMEM;
1639 goto end;
1640 }
1641
1642 input_dup = input_copy;
1643 token = strsep(&input_copy, delim);
1644 while (token) {
1645 rc = kstrtoint(token, 0, &strtoint);
1646 if (rc) {
1647 SDE_ERROR("input buffer conversion failed\n");
1648 goto end;
1649 }
1650
1651 if (buf_size >= MAX_CMD_PAYLOAD_SIZE) {
1652 SDE_ERROR("buffer size exceeding the limit %d\n",
1653 MAX_CMD_PAYLOAD_SIZE);
1654 goto end;
1655 }
1656 buffer[buf_size++] = (strtoint & 0xff);
1657 token = strsep(&input_copy, delim);
1658 }
1659 SDE_DEBUG("command packet size in bytes: %u\n", buf_size);
1660 if (!buf_size)
1661 goto end;
1662
1663 mutex_lock(&c_conn->lock);
1664 rc = c_conn->ops.cmd_transfer(c_conn->display, buffer,
1665 buf_size);
1666 c_conn->last_cmd_tx_sts = !rc ? true : false;
1667 mutex_unlock(&c_conn->lock);
1668
1669 rc = count;
1670end:
1671 kfree(input_dup);
1672 kfree(input);
1673 return rc;
1674}
1675
1676static const struct file_operations conn_cmd_tx_fops = {
1677 .open = _sde_debugfs_conn_cmd_tx_open,
1678 .read = _sde_debugfs_conn_cmd_tx_sts_read,
1679 .write = _sde_debugfs_conn_cmd_tx_write,
1680};
1681
Alan Kwong578cdaf2017-01-28 17:25:43 -08001682#ifdef CONFIG_DEBUG_FS
1683/**
1684 * sde_connector_init_debugfs - initialize connector debugfs
1685 * @connector: Pointer to drm connector
1686 */
1687static int sde_connector_init_debugfs(struct drm_connector *connector)
1688{
1689 struct sde_connector *sde_connector;
Sandeep Pandaf2274d12017-09-08 19:52:33 +05301690 struct msm_display_info info;
Alan Kwong578cdaf2017-01-28 17:25:43 -08001691
1692 if (!connector || !connector->debugfs_entry) {
1693 SDE_ERROR("invalid connector\n");
1694 return -EINVAL;
1695 }
1696
1697 sde_connector = to_sde_connector(connector);
1698
Sandeep Pandaf2274d12017-09-08 19:52:33 +05301699 sde_connector_get_info(connector, &info);
1700 if (sde_connector->ops.check_status &&
Jayant Shekhar2c95cfe2018-03-09 11:14:39 +05301701 (info.capabilities & MSM_DISPLAY_ESD_ENABLED)) {
Sandeep Pandaf2274d12017-09-08 19:52:33 +05301702 debugfs_create_u32("force_panel_dead", 0600,
1703 connector->debugfs_entry,
1704 &sde_connector->force_panel_dead);
Jayant Shekhar2c95cfe2018-03-09 11:14:39 +05301705 debugfs_create_u32("esd_status_interval", 0600,
1706 connector->debugfs_entry,
1707 &sde_connector->esd_status_interval);
1708 }
Sandeep Pandaf2274d12017-09-08 19:52:33 +05301709
Lloyd Atkinson8de415a2017-05-23 11:31:16 -04001710 if (!debugfs_create_bool("fb_kmap", 0600, connector->debugfs_entry,
Alan Kwong578cdaf2017-01-28 17:25:43 -08001711 &sde_connector->fb_kmap)) {
1712 SDE_ERROR("failed to create connector fb_kmap\n");
1713 return -ENOMEM;
1714 }
1715
Govinda Rajulu Chennab95b9c32017-10-13 15:00:32 -04001716 if (sde_connector->ops.cmd_transfer) {
1717 if (!debugfs_create_file("tx_cmd", 0600,
1718 connector->debugfs_entry,
1719 connector, &conn_cmd_tx_fops)) {
1720 SDE_ERROR("failed to create connector cmd_tx\n");
1721 return -ENOMEM;
1722 }
1723 }
1724
Alan Kwong578cdaf2017-01-28 17:25:43 -08001725 return 0;
1726}
1727#else
1728static int sde_connector_init_debugfs(struct drm_connector *connector)
1729{
1730 return 0;
1731}
1732#endif
1733
1734static int sde_connector_late_register(struct drm_connector *connector)
1735{
1736 return sde_connector_init_debugfs(connector);
1737}
1738
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07001739static void sde_connector_early_unregister(struct drm_connector *connector)
1740{
1741 /* debugfs under connector->debugfs are deleted by drm_debugfs */
1742}
1743
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07001744static int sde_connector_fill_modes(struct drm_connector *connector,
1745 uint32_t max_width, uint32_t max_height)
1746{
1747 int rc, mode_count = 0;
1748 struct sde_connector *sde_conn = NULL;
1749
1750 sde_conn = to_sde_connector(connector);
1751 if (!sde_conn) {
1752 SDE_ERROR("invalid arguments\n");
1753 return 0;
1754 }
1755
1756 mode_count = drm_helper_probe_single_connector_modes(connector,
1757 max_width, max_height);
1758
1759 rc = sde_connector_set_blob_data(connector,
1760 connector->state,
1761 CONNECTOR_PROP_MODE_INFO);
1762 if (rc) {
1763 SDE_ERROR_CONN(sde_conn,
1764 "failed to setup mode info prop, rc = %d\n", rc);
1765 return 0;
1766 }
1767
1768 return mode_count;
1769}
1770
Clarence Ipdd8021c2016-07-20 16:39:47 -04001771static const struct drm_connector_funcs sde_connector_ops = {
Clarence Ip90b282d2017-05-04 10:00:32 -07001772 .dpms = sde_connector_dpms,
Clarence Ipdd8021c2016-07-20 16:39:47 -04001773 .reset = sde_connector_atomic_reset,
1774 .detect = sde_connector_detect,
1775 .destroy = sde_connector_destroy,
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07001776 .fill_modes = sde_connector_fill_modes,
Clarence Ipdd8021c2016-07-20 16:39:47 -04001777 .atomic_duplicate_state = sde_connector_atomic_duplicate_state,
1778 .atomic_destroy_state = sde_connector_atomic_destroy_state,
1779 .atomic_set_property = sde_connector_atomic_set_property,
1780 .atomic_get_property = sde_connector_atomic_get_property,
1781 .set_property = sde_connector_set_property,
Alan Kwong578cdaf2017-01-28 17:25:43 -08001782 .late_register = sde_connector_late_register,
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07001783 .early_unregister = sde_connector_early_unregister,
Clarence Ipdd8021c2016-07-20 16:39:47 -04001784};
1785
1786static int sde_connector_get_modes(struct drm_connector *connector)
1787{
1788 struct sde_connector *c_conn;
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07001789 int mode_count = 0;
Clarence Ipdd8021c2016-07-20 16:39:47 -04001790
1791 if (!connector) {
1792 SDE_ERROR("invalid connector\n");
1793 return 0;
1794 }
1795
1796 c_conn = to_sde_connector(connector);
1797 if (!c_conn->ops.get_modes) {
1798 SDE_DEBUG("missing get_modes callback\n");
1799 return 0;
1800 }
1801
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07001802 mode_count = c_conn->ops.get_modes(connector, c_conn->display);
1803 if (!mode_count) {
1804 SDE_ERROR_CONN(c_conn, "failed to get modes\n");
1805 return 0;
1806 }
1807
1808 sde_connector_update_hdr_props(connector);
1809
1810 return mode_count;
Clarence Ipdd8021c2016-07-20 16:39:47 -04001811}
1812
1813static enum drm_mode_status
1814sde_connector_mode_valid(struct drm_connector *connector,
1815 struct drm_display_mode *mode)
1816{
1817 struct sde_connector *c_conn;
1818
1819 if (!connector || !mode) {
1820 SDE_ERROR("invalid argument(s), conn %pK, mode %pK\n",
1821 connector, mode);
1822 return MODE_ERROR;
1823 }
1824
1825 c_conn = to_sde_connector(connector);
1826
1827 if (c_conn->ops.mode_valid)
1828 return c_conn->ops.mode_valid(connector, mode, c_conn->display);
1829
1830 /* assume all modes okay by default */
1831 return MODE_OK;
1832}
1833
1834static struct drm_encoder *
1835sde_connector_best_encoder(struct drm_connector *connector)
1836{
1837 struct sde_connector *c_conn = to_sde_connector(connector);
1838
1839 if (!connector) {
1840 SDE_ERROR("invalid connector\n");
1841 return NULL;
1842 }
1843
1844 /*
1845 * This is true for now, revisit this code when multiple encoders are
1846 * supported.
1847 */
1848 return c_conn->encoder;
1849}
1850
Sandeep Panda979009e2018-02-13 17:58:05 +05301851static void _sde_connector_report_panel_dead(struct sde_connector *conn)
1852{
1853 struct drm_event event;
Sandeep Panda979009e2018-02-13 17:58:05 +05301854
1855 if (!conn)
1856 return;
1857
Jayant Shekhar00a28e92018-06-04 12:15:23 +05301858 /* Panel dead notification can come:
1859 * 1) ESD thread
1860 * 2) Commit thread (if TE stops coming)
1861 * So such case, avoid failure notification twice.
1862 */
1863 if (conn->panel_dead)
1864 return;
1865
Sandeep Panda9eee1932018-04-25 11:25:42 +05301866 conn->panel_dead = true;
Sandeep Panda979009e2018-02-13 17:58:05 +05301867 event.type = DRM_EVENT_PANEL_DEAD;
1868 event.length = sizeof(bool);
1869 msm_mode_object_event_notify(&conn->base.base,
Sandeep Panda9eee1932018-04-25 11:25:42 +05301870 conn->base.dev, &event, (u8 *)&conn->panel_dead);
Sandeep Panda979009e2018-02-13 17:58:05 +05301871 sde_encoder_display_failure_notification(conn->encoder);
1872 SDE_EVT32(SDE_EVTLOG_ERROR);
1873 SDE_ERROR("esd check failed report PANEL_DEAD conn_id: %d enc_id: %d\n",
1874 conn->base.base.id, conn->encoder->base.id);
1875}
1876
1877int sde_connector_esd_status(struct drm_connector *conn)
1878{
1879 struct sde_connector *sde_conn = NULL;
1880 int ret = 0;
1881
1882 if (!conn)
1883 return ret;
1884
1885 sde_conn = to_sde_connector(conn);
1886 if (!sde_conn || !sde_conn->ops.check_status)
1887 return ret;
1888
1889 /* protect this call with ESD status check call */
1890 mutex_lock(&sde_conn->lock);
1891 ret = sde_conn->ops.check_status(sde_conn->display, true);
1892 mutex_unlock(&sde_conn->lock);
1893
1894 if (ret <= 0) {
1895 /* cancel if any pending esd work */
1896 sde_connector_schedule_status_work(conn, false);
1897 _sde_connector_report_panel_dead(sde_conn);
1898 ret = -ETIMEDOUT;
1899 } else {
1900 SDE_DEBUG("Successfully received TE from panel\n");
1901 ret = 0;
1902 }
1903 SDE_EVT32(ret);
1904
1905 return ret;
1906}
1907
Sandeep Panda98d6ab22017-09-05 08:03:16 +05301908static void sde_connector_check_status_work(struct work_struct *work)
1909{
1910 struct sde_connector *conn;
Sandeep Panda98d6ab22017-09-05 08:03:16 +05301911 int rc = 0;
Sandeep Panda98d6ab22017-09-05 08:03:16 +05301912
1913 conn = container_of(to_delayed_work(work),
1914 struct sde_connector, status_work);
1915 if (!conn) {
1916 SDE_ERROR("not able to get connector object\n");
1917 return;
1918 }
1919
1920 mutex_lock(&conn->lock);
1921 if (!conn->ops.check_status ||
1922 (conn->dpms_mode != DRM_MODE_DPMS_ON)) {
1923 SDE_DEBUG("dpms mode: %d\n", conn->dpms_mode);
1924 mutex_unlock(&conn->lock);
1925 return;
1926 }
1927
Sandeep Panda979009e2018-02-13 17:58:05 +05301928 rc = conn->ops.check_status(conn->display, false);
Sandeep Panda98d6ab22017-09-05 08:03:16 +05301929 mutex_unlock(&conn->lock);
Sandeep Pandaf2274d12017-09-08 19:52:33 +05301930
1931 if (conn->force_panel_dead) {
1932 conn->force_panel_dead--;
1933 if (!conn->force_panel_dead)
1934 goto status_dead;
1935 }
1936
Sandeep Panda98d6ab22017-09-05 08:03:16 +05301937 if (rc > 0) {
Jayant Shekhar2c95cfe2018-03-09 11:14:39 +05301938 u32 interval;
1939
Sandeep Panda98d6ab22017-09-05 08:03:16 +05301940 SDE_DEBUG("esd check status success conn_id: %d enc_id: %d\n",
1941 conn->base.base.id, conn->encoder->base.id);
Jayant Shekhar2c95cfe2018-03-09 11:14:39 +05301942
1943 /* If debugfs property is not set then take default value */
1944 interval = conn->esd_status_interval ?
1945 conn->esd_status_interval : STATUS_CHECK_INTERVAL_MS;
Sandeep Panda98d6ab22017-09-05 08:03:16 +05301946 schedule_delayed_work(&conn->status_work,
Jayant Shekhar2c95cfe2018-03-09 11:14:39 +05301947 msecs_to_jiffies(interval));
Sandeep Pandaf2274d12017-09-08 19:52:33 +05301948 return;
Sandeep Panda98d6ab22017-09-05 08:03:16 +05301949 }
Sandeep Pandaf2274d12017-09-08 19:52:33 +05301950
1951status_dead:
Sandeep Panda979009e2018-02-13 17:58:05 +05301952 _sde_connector_report_panel_dead(conn);
Sandeep Panda98d6ab22017-09-05 08:03:16 +05301953}
1954
Clarence Ipdd8021c2016-07-20 16:39:47 -04001955static const struct drm_connector_helper_funcs sde_connector_helper_ops = {
1956 .get_modes = sde_connector_get_modes,
1957 .mode_valid = sde_connector_mode_valid,
1958 .best_encoder = sde_connector_best_encoder,
1959};
1960
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07001961static int sde_connector_populate_mode_info(struct drm_connector *conn,
1962 struct sde_kms_info *info)
1963{
1964 struct msm_drm_private *priv;
1965 struct sde_kms *sde_kms;
1966 struct sde_connector *c_conn = NULL;
1967 struct drm_display_mode *mode;
1968 struct msm_mode_info mode_info;
1969 int rc = 0;
1970
1971 if (!conn || !conn->dev || !conn->dev->dev_private) {
1972 SDE_ERROR("invalid arguments\n");
1973 return -EINVAL;
1974 }
1975
1976 priv = conn->dev->dev_private;
1977 sde_kms = to_sde_kms(priv->kms);
1978
1979 c_conn = to_sde_connector(conn);
1980 if (!c_conn->ops.get_mode_info) {
1981 SDE_ERROR_CONN(c_conn, "get_mode_info not defined\n");
1982 return -EINVAL;
1983 }
1984
1985 list_for_each_entry(mode, &conn->modes, head) {
1986 int topology_idx = 0;
1987
1988 memset(&mode_info, 0, sizeof(mode_info));
1989
1990 rc = c_conn->ops.get_mode_info(mode, &mode_info,
1991 sde_kms->catalog->max_mixer_width,
1992 c_conn->display);
1993 if (rc) {
1994 SDE_ERROR_CONN(c_conn,
1995 "failed to get mode info for mode %s\n",
1996 mode->name);
1997 continue;
1998 }
1999
2000 sde_kms_info_add_keystr(info, "mode_name", mode->name);
2001
Sandeep Panda97c89dd2018-10-25 15:49:16 +05302002 sde_kms_info_add_keyint(info, "bit_clk_rate",
2003 mode_info.clk_rate);
2004
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07002005 topology_idx = (int)sde_rm_get_topology_name(
2006 mode_info.topology);
2007 if (topology_idx < SDE_RM_TOPOLOGY_MAX) {
2008 sde_kms_info_add_keystr(info, "topology",
2009 e_topology_name[topology_idx].name);
2010 } else {
2011 SDE_ERROR_CONN(c_conn, "invalid topology\n");
2012 continue;
2013 }
2014
2015 if (!mode_info.roi_caps.num_roi)
2016 continue;
2017
2018 sde_kms_info_add_keyint(info, "partial_update_num_roi",
2019 mode_info.roi_caps.num_roi);
2020 sde_kms_info_add_keyint(info, "partial_update_xstart",
2021 mode_info.roi_caps.align.xstart_pix_align);
2022 sde_kms_info_add_keyint(info, "partial_update_walign",
2023 mode_info.roi_caps.align.width_pix_align);
2024 sde_kms_info_add_keyint(info, "partial_update_wmin",
2025 mode_info.roi_caps.align.min_width);
2026 sde_kms_info_add_keyint(info, "partial_update_ystart",
2027 mode_info.roi_caps.align.ystart_pix_align);
2028 sde_kms_info_add_keyint(info, "partial_update_halign",
2029 mode_info.roi_caps.align.height_pix_align);
2030 sde_kms_info_add_keyint(info, "partial_update_hmin",
2031 mode_info.roi_caps.align.min_height);
2032 sde_kms_info_add_keyint(info, "partial_update_roimerge",
2033 mode_info.roi_caps.merge_rois);
2034 }
2035
2036 return rc;
2037}
2038
2039int sde_connector_set_blob_data(struct drm_connector *conn,
2040 struct drm_connector_state *state,
2041 enum msm_mdp_conn_property prop_id)
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07002042{
2043 struct sde_kms_info *info;
2044 struct sde_connector *c_conn = NULL;
Jeykumar Sankaran905ba332017-10-19 10:45:02 -07002045 struct sde_connector_state *sde_conn_state = NULL;
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07002046 struct msm_mode_info mode_info;
Jayant Shekharc35960b2017-12-19 18:01:34 +05302047 struct drm_property_blob **blob = NULL;
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07002048 int rc = 0;
2049
2050 c_conn = to_sde_connector(conn);
Jeykumar Sankaran905ba332017-10-19 10:45:02 -07002051 if (!c_conn) {
2052 SDE_ERROR("invalid argument\n");
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07002053 return -EINVAL;
2054 }
2055
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07002056 info = kzalloc(sizeof(*info), GFP_KERNEL);
2057 if (!info)
2058 return -ENOMEM;
2059
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07002060 sde_kms_info_reset(info);
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07002061
2062 switch (prop_id) {
2063 case CONNECTOR_PROP_SDE_INFO:
2064 memset(&mode_info, 0, sizeof(mode_info));
2065
2066 if (state) {
2067 sde_conn_state = to_sde_connector_state(state);
2068 memcpy(&mode_info, &sde_conn_state->mode_info,
2069 sizeof(sde_conn_state->mode_info));
2070 } else {
2071 /**
2072 * connector state is assigned only on first
2073 * atomic_commit. But this function is allowed to be
2074 * invoked during probe/init sequence. So not throwing
2075 * an error.
2076 */
2077 SDE_DEBUG_CONN(c_conn, "invalid connector state\n");
2078 }
2079
Alan Kwong769fba92017-11-13 16:50:36 -05002080 if (c_conn->ops.set_info_blob) {
2081 rc = c_conn->ops.set_info_blob(conn, info,
2082 c_conn->display, &mode_info);
2083 if (rc) {
2084 SDE_ERROR_CONN(c_conn,
2085 "set_info_blob failed, %d\n",
2086 rc);
2087 goto exit;
2088 }
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07002089 }
2090
Jayant Shekharc35960b2017-12-19 18:01:34 +05302091 blob = &c_conn->blob_caps;
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07002092 break;
2093 case CONNECTOR_PROP_MODE_INFO:
2094 rc = sde_connector_populate_mode_info(conn, info);
2095 if (rc) {
2096 SDE_ERROR_CONN(c_conn,
2097 "mode info population failed, %d\n",
2098 rc);
2099 goto exit;
2100 }
Jayant Shekharc35960b2017-12-19 18:01:34 +05302101 blob = &c_conn->blob_mode_info;
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07002102 break;
2103 default:
2104 SDE_ERROR_CONN(c_conn, "invalid prop_id: %d\n", prop_id);
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07002105 goto exit;
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07002106 };
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07002107
2108 msm_property_set_blob(&c_conn->property_info,
Jayant Shekharc35960b2017-12-19 18:01:34 +05302109 blob,
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07002110 SDE_KMS_INFO_DATA(info),
2111 SDE_KMS_INFO_DATALEN(info),
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07002112 prop_id);
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07002113exit:
2114 kfree(info);
2115
2116 return rc;
2117}
2118
Clarence Ipdd8021c2016-07-20 16:39:47 -04002119struct drm_connector *sde_connector_init(struct drm_device *dev,
2120 struct drm_encoder *encoder,
2121 struct drm_panel *panel,
2122 void *display,
2123 const struct sde_connector_ops *ops,
2124 int connector_poll,
2125 int connector_type)
2126{
2127 struct msm_drm_private *priv;
2128 struct sde_kms *sde_kms;
Clarence Ipdd8021c2016-07-20 16:39:47 -04002129 struct sde_connector *c_conn = NULL;
Ping Li898b1bf2017-02-09 18:03:28 -08002130 struct dsi_display *dsi_display;
Lloyd Atkinson8ba47032017-03-22 17:13:32 -04002131 struct msm_display_info display_info;
Clarence Ipdd8021c2016-07-20 16:39:47 -04002132 int rc;
2133
2134 if (!dev || !dev->dev_private || !encoder) {
2135 SDE_ERROR("invalid argument(s), dev %pK, enc %pK\n",
2136 dev, encoder);
2137 return ERR_PTR(-EINVAL);
2138 }
2139
2140 priv = dev->dev_private;
2141 if (!priv->kms) {
2142 SDE_ERROR("invalid kms reference\n");
2143 return ERR_PTR(-EINVAL);
2144 }
2145
2146 c_conn = kzalloc(sizeof(*c_conn), GFP_KERNEL);
2147 if (!c_conn) {
2148 SDE_ERROR("failed to alloc sde connector\n");
2149 return ERR_PTR(-ENOMEM);
2150 }
2151
Jeykumar Sankaran36af6a62017-08-03 14:21:58 -07002152 memset(&display_info, 0, sizeof(display_info));
2153
Clarence Ipdd8021c2016-07-20 16:39:47 -04002154 rc = drm_connector_init(dev,
2155 &c_conn->base,
2156 &sde_connector_ops,
2157 connector_type);
2158 if (rc)
2159 goto error_free_conn;
2160
Clarence Ipa18d4832017-03-13 12:35:44 -07002161 spin_lock_init(&c_conn->event_lock);
2162
Clarence Ipdd8021c2016-07-20 16:39:47 -04002163 c_conn->connector_type = connector_type;
2164 c_conn->encoder = encoder;
2165 c_conn->panel = panel;
2166 c_conn->display = display;
2167
Clarence Ip90b282d2017-05-04 10:00:32 -07002168 c_conn->dpms_mode = DRM_MODE_DPMS_ON;
2169 c_conn->lp_mode = 0;
2170 c_conn->last_panel_power_mode = SDE_MODE_DPMS_ON;
2171
Clarence Ipdd8021c2016-07-20 16:39:47 -04002172 sde_kms = to_sde_kms(priv->kms);
Alan Kwongdfa8c082016-07-29 04:10:00 -04002173 if (sde_kms->vbif[VBIF_NRT]) {
Jordan Croused8e96522017-02-13 10:14:16 -07002174 c_conn->aspace[SDE_IOMMU_DOMAIN_UNSECURE] =
2175 sde_kms->aspace[MSM_SMMU_DOMAIN_NRT_UNSECURE];
2176 c_conn->aspace[SDE_IOMMU_DOMAIN_SECURE] =
2177 sde_kms->aspace[MSM_SMMU_DOMAIN_NRT_SECURE];
Alan Kwongdfa8c082016-07-29 04:10:00 -04002178 } else {
Jordan Croused8e96522017-02-13 10:14:16 -07002179 c_conn->aspace[SDE_IOMMU_DOMAIN_UNSECURE] =
2180 sde_kms->aspace[MSM_SMMU_DOMAIN_UNSECURE];
2181 c_conn->aspace[SDE_IOMMU_DOMAIN_SECURE] =
2182 sde_kms->aspace[MSM_SMMU_DOMAIN_SECURE];
Alan Kwongdfa8c082016-07-29 04:10:00 -04002183 }
Clarence Ipdd8021c2016-07-20 16:39:47 -04002184
2185 if (ops)
2186 c_conn->ops = *ops;
2187
2188 c_conn->base.helper_private = &sde_connector_helper_ops;
2189 c_conn->base.polled = connector_poll;
2190 c_conn->base.interlace_allowed = 0;
2191 c_conn->base.doublescan_allowed = 0;
2192
2193 snprintf(c_conn->name,
2194 SDE_CONNECTOR_NAME_SIZE,
2195 "conn%u",
2196 c_conn->base.base.id);
2197
Lloyd Atkinson5d40d312016-09-06 08:34:13 -04002198 rc = sde_fence_init(&c_conn->retire_fence, c_conn->name,
2199 c_conn->base.base.id);
Clarence Ipe59fb3f2016-07-26 13:39:59 -04002200 if (rc) {
2201 SDE_ERROR("failed to init fence, %d\n", rc);
2202 goto error_cleanup_conn;
2203 }
2204
Clarence Ip90b282d2017-05-04 10:00:32 -07002205 mutex_init(&c_conn->lock);
2206
Clarence Ipdd8021c2016-07-20 16:39:47 -04002207 rc = drm_mode_connector_attach_encoder(&c_conn->base, encoder);
2208 if (rc) {
2209 SDE_ERROR("failed to attach encoder to connector, %d\n", rc);
Lloyd Atkinsonab3dd302017-02-13 10:44:55 -08002210 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -04002211 }
2212
Shashank Babu Chinta Venkata06c428e2017-04-17 13:52:28 -07002213 rc = sde_backlight_setup(c_conn, dev);
Dhaval Patel7cdd6662017-03-08 13:10:37 -08002214 if (rc) {
2215 SDE_ERROR("failed to setup backlight, rc=%d\n", rc);
2216 goto error_cleanup_fence;
Vishnuvardhan Prodduturi75b96802016-10-17 18:45:55 +05302217 }
2218
Clarence Ipdd8021c2016-07-20 16:39:47 -04002219 /* create properties */
2220 msm_property_init(&c_conn->property_info, &c_conn->base.base, dev,
2221 priv->conn_property, c_conn->property_data,
2222 CONNECTOR_PROP_COUNT, CONNECTOR_PROP_BLOBCOUNT,
2223 sizeof(struct sde_connector_state));
2224
Alan Kwong769fba92017-11-13 16:50:36 -05002225 if (c_conn->ops.post_init) {
2226 rc = c_conn->ops.post_init(&c_conn->base, display);
2227 if (rc) {
2228 SDE_ERROR("post-init failed, %d\n", rc);
2229 goto error_cleanup_fence;
2230 }
2231 }
2232
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07002233 msm_property_install_blob(&c_conn->property_info,
2234 "capabilities",
2235 DRM_MODE_PROP_IMMUTABLE,
2236 CONNECTOR_PROP_SDE_INFO);
Clarence Ipdd8021c2016-07-20 16:39:47 -04002237
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07002238 rc = sde_connector_set_blob_data(&c_conn->base,
2239 NULL,
2240 CONNECTOR_PROP_SDE_INFO);
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07002241 if (rc) {
2242 SDE_ERROR_CONN(c_conn,
2243 "failed to setup connector info, rc = %d\n", rc);
2244 goto error_cleanup_fence;
Clarence Ipdd8021c2016-07-20 16:39:47 -04002245 }
2246
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07002247 msm_property_install_blob(&c_conn->property_info,
2248 "mode_properties",
2249 DRM_MODE_PROP_IMMUTABLE,
2250 CONNECTOR_PROP_MODE_INFO);
2251
Ping Li898b1bf2017-02-09 18:03:28 -08002252 if (connector_type == DRM_MODE_CONNECTOR_DSI) {
2253 dsi_display = (struct dsi_display *)(display);
2254 if (dsi_display && dsi_display->panel &&
2255 dsi_display->panel->hdr_props.hdr_enabled == true) {
2256 msm_property_install_blob(&c_conn->property_info,
2257 "hdr_properties",
2258 DRM_MODE_PROP_IMMUTABLE,
2259 CONNECTOR_PROP_HDR_INFO);
2260
2261 msm_property_set_blob(&c_conn->property_info,
2262 &c_conn->blob_hdr,
2263 &dsi_display->panel->hdr_props,
2264 sizeof(dsi_display->panel->hdr_props),
2265 CONNECTOR_PROP_HDR_INFO);
2266 }
2267 }
2268
Sandeep Panda11b20d82017-06-19 12:57:27 +05302269 rc = sde_connector_get_info(&c_conn->base, &display_info);
2270 if (!rc && (connector_type == DRM_MODE_CONNECTOR_DSI) &&
2271 (display_info.capabilities & MSM_DISPLAY_CAP_VID_MODE))
2272 sde_connector_register_event(&c_conn->base,
2273 SDE_CONN_EVENT_VID_FIFO_OVERFLOW,
2274 sde_connector_handle_disp_recovery,
2275 c_conn);
2276
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07002277 msm_property_install_volatile_range(
Sandeep Panda11b20d82017-06-19 12:57:27 +05302278 &c_conn->property_info, "sde_drm_roi_v1", 0x0,
2279 0, ~0, 0, CONNECTOR_PROP_ROI_V1);
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07002280
Ping Li8430ee12017-02-24 14:14:44 -08002281 /* install PP_DITHER properties */
2282 _sde_connector_install_dither_property(dev, sde_kms, c_conn);
Lloyd Atkinson8ba47032017-03-22 17:13:32 -04002283
Srikanth Rajagopalan30384d12017-06-08 15:23:31 -07002284 if (connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
Ajay Singh Parmar4dabdfc2017-11-09 16:54:25 -08002285 struct drm_msm_ext_hdr_properties hdr = {0};
2286
Srikanth Rajagopalan30384d12017-06-08 15:23:31 -07002287 msm_property_install_blob(&c_conn->property_info,
2288 "ext_hdr_properties",
2289 DRM_MODE_PROP_IMMUTABLE,
2290 CONNECTOR_PROP_EXT_HDR_INFO);
Ajay Singh Parmar4dabdfc2017-11-09 16:54:25 -08002291
2292 /* set default values to avoid reading uninitialized data */
2293 msm_property_set_blob(&c_conn->property_info,
2294 &c_conn->blob_ext_hdr,
2295 &hdr,
2296 sizeof(hdr),
2297 CONNECTOR_PROP_EXT_HDR_INFO);
Srikanth Rajagopalan30384d12017-06-08 15:23:31 -07002298 }
2299
Ajay Singh Parmare927aa42017-11-01 00:33:20 -07002300 msm_property_install_volatile_range(&c_conn->property_info,
2301 "hdr_metadata", 0x0, 0, ~0, 0, CONNECTOR_PROP_HDR_METADATA);
2302
Dhaval Patelb24b2d62017-11-03 18:10:26 -07002303 msm_property_install_volatile_range(&c_conn->property_info,
2304 "RETIRE_FENCE", 0x0, 0, ~0, 0, CONNECTOR_PROP_RETIRE_FENCE);
Clarence Ipe59fb3f2016-07-26 13:39:59 -04002305
Lloyd Atkinson77382202017-02-01 14:59:43 -05002306 msm_property_install_range(&c_conn->property_info, "autorefresh",
2307 0x0, 0, AUTOREFRESH_MAX_FRAME_CNT, 0,
2308 CONNECTOR_PROP_AUTOREFRESH);
2309
Xu Yangd566d222017-05-19 17:18:12 +08002310 msm_property_install_range(&c_conn->property_info, "bl_scale",
2311 0x0, 0, MAX_BL_SCALE_LEVEL, MAX_BL_SCALE_LEVEL,
2312 CONNECTOR_PROP_BL_SCALE);
2313
2314 msm_property_install_range(&c_conn->property_info, "ad_bl_scale",
2315 0x0, 0, MAX_AD_BL_SCALE_LEVEL, MAX_AD_BL_SCALE_LEVEL,
2316 CONNECTOR_PROP_AD_BL_SCALE);
2317
Xu Yang92377312017-11-23 13:48:08 +08002318 c_conn->bl_scale_dirty = false;
2319 c_conn->bl_scale = MAX_BL_SCALE_LEVEL;
2320 c_conn->bl_scale_ad = MAX_AD_BL_SCALE_LEVEL;
2321
Lloyd Atkinsonb6191972016-08-10 18:31:46 -04002322 /* enum/bitmask properties */
2323 msm_property_install_enum(&c_conn->property_info, "topology_name",
2324 DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name,
2325 ARRAY_SIZE(e_topology_name),
2326 CONNECTOR_PROP_TOPOLOGY_NAME);
2327 msm_property_install_enum(&c_conn->property_info, "topology_control",
2328 0, 1, e_topology_control,
2329 ARRAY_SIZE(e_topology_control),
2330 CONNECTOR_PROP_TOPOLOGY_CONTROL);
Clarence Ip90b282d2017-05-04 10:00:32 -07002331 msm_property_install_enum(&c_conn->property_info, "LP",
2332 0, 0, e_power_mode,
2333 ARRAY_SIZE(e_power_mode),
2334 CONNECTOR_PROP_LP);
Lloyd Atkinsonb6191972016-08-10 18:31:46 -04002335
Clarence Ipdd8021c2016-07-20 16:39:47 -04002336 rc = msm_property_install_get_status(&c_conn->property_info);
2337 if (rc) {
2338 SDE_ERROR("failed to create one or more properties\n");
2339 goto error_destroy_property;
2340 }
2341
Lloyd Atkinsonb6191972016-08-10 18:31:46 -04002342 SDE_DEBUG("connector %d attach encoder %d\n",
2343 c_conn->base.base.id, encoder->base.id);
2344
Clarence Ipdd8021c2016-07-20 16:39:47 -04002345 priv->connectors[priv->num_connectors++] = &c_conn->base;
2346
Sandeep Panda98d6ab22017-09-05 08:03:16 +05302347 INIT_DELAYED_WORK(&c_conn->status_work,
2348 sde_connector_check_status_work);
2349
Clarence Ipdd8021c2016-07-20 16:39:47 -04002350 return &c_conn->base;
2351
2352error_destroy_property:
Dhaval Patel4e574842016-08-23 15:11:37 -07002353 if (c_conn->blob_caps)
2354 drm_property_unreference_blob(c_conn->blob_caps);
Ping Li898b1bf2017-02-09 18:03:28 -08002355 if (c_conn->blob_hdr)
2356 drm_property_unreference_blob(c_conn->blob_hdr);
Ping Li8430ee12017-02-24 14:14:44 -08002357 if (c_conn->blob_dither)
2358 drm_property_unreference_blob(c_conn->blob_dither);
Jeykumar Sankaran83ddcb02017-10-27 11:34:50 -07002359 if (c_conn->blob_mode_info)
2360 drm_property_unreference_blob(c_conn->blob_mode_info);
Ajay Singh Parmar4dabdfc2017-11-09 16:54:25 -08002361 if (c_conn->blob_ext_hdr)
2362 drm_property_unreference_blob(c_conn->blob_ext_hdr);
Ping Li8430ee12017-02-24 14:14:44 -08002363
Clarence Ipdd8021c2016-07-20 16:39:47 -04002364 msm_property_destroy(&c_conn->property_info);
Clarence Ipe59fb3f2016-07-26 13:39:59 -04002365error_cleanup_fence:
Clarence Ip90b282d2017-05-04 10:00:32 -07002366 mutex_destroy(&c_conn->lock);
Clarence Ipe59fb3f2016-07-26 13:39:59 -04002367 sde_fence_deinit(&c_conn->retire_fence);
Clarence Ipdd8021c2016-07-20 16:39:47 -04002368error_cleanup_conn:
2369 drm_connector_cleanup(&c_conn->base);
2370error_free_conn:
2371 kfree(c_conn);
2372
2373 return ERR_PTR(rc);
2374}
Gopikrishnaiah Anandande2c81b2017-03-15 12:41:29 -07002375
2376int sde_connector_register_custom_event(struct sde_kms *kms,
2377 struct drm_connector *conn_drm, u32 event, bool val)
2378{
Gopikrishnaiah Anandan84b4f672017-04-26 10:28:51 -07002379 int ret = -EINVAL;
2380
2381 switch (event) {
2382 case DRM_EVENT_SYS_BACKLIGHT:
2383 ret = 0;
2384 break;
Sandeep Panda98d6ab22017-09-05 08:03:16 +05302385 case DRM_EVENT_PANEL_DEAD:
2386 ret = 0;
2387 break;
Gopikrishnaiah Anandan84b4f672017-04-26 10:28:51 -07002388 default:
2389 break;
2390 }
2391 return ret;
Gopikrishnaiah Anandande2c81b2017-03-15 12:41:29 -07002392}