blob: 0227b59abb70bc1ac41362576a1c4ae844a86d9f [file] [log] [blame]
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify it
4 * under the terms of the GNU General Public License version 2 as published by
5 * the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful, but WITHOUT
8 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
10 * more details.
11 *
12 * You should have received a copy of the GNU General Public License along with
13 * this program. If not, see <http://www.gnu.org/licenses/>.
14 */
15
16#define pr_fmt(fmt) "%s: " fmt, __func__
17
18#include <drm/msm_drm_pp.h>
19#include "sde_color_processing.h"
20#include "sde_kms.h"
21#include "sde_crtc.h"
22#include "sde_hw_dspp.h"
23#include "sde_hw_lm.h"
24
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -070025struct sde_cp_node {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -070026 u32 property_id;
27 u32 prop_flags;
28 u32 feature;
29 void *blob_ptr;
30 uint64_t prop_val;
31 const struct sde_pp_blk *pp_blk;
32 struct list_head feature_list;
33 struct list_head active_list;
34 struct list_head dirty_list;
35 void (*dspp_feature_op)(struct sde_hw_dspp *ctx, void *cfg);
36 void (*lm_feature_op)(struct sde_hw_mixer *mixer, void *cfg);
37};
38
39struct sde_cp_prop_attach {
40 struct drm_crtc *crtc;
41 struct drm_property *prop;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -070042 struct sde_cp_node *prop_node;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -070043 const struct sde_pp_blk *pp_blk;
44 u32 feature;
45 void *ops;
46 uint64_t val;
47};
48
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070049static void dspp_pcc_install_property(struct drm_crtc *crtc,
50 struct sde_hw_dspp *hw_dspp);
51
52static void dspp_hsic_install_property(struct drm_crtc *crtc,
53 struct sde_hw_dspp *hw_dspp);
54
55static void dspp_ad_install_property(struct drm_crtc *crtc,
56 struct sde_hw_dspp *hw_dspp);
57
58static void dspp_vlut_install_property(struct drm_crtc *crtc,
59 struct sde_hw_dspp *hw_dspp);
60
61typedef void (*dspp_prop_install_func_t)(struct drm_crtc *crtc,
62 struct sde_hw_dspp *hw_dspp);
63
64static dspp_prop_install_func_t dspp_prop_install_func[SDE_DSPP_MAX];
65
66#define setup_dspp_prop_install_funcs(func) \
67do { \
68 func[SDE_DSPP_PCC] = dspp_pcc_install_property; \
69 func[SDE_DSPP_HSIC] = dspp_hsic_install_property; \
70 func[SDE_DSPP_AD] = dspp_ad_install_property; \
71 func[SDE_DSPP_VLUT] = dspp_vlut_install_property; \
72} while (0)
73
74typedef void (*lm_prop_install_func_t)(struct drm_crtc *crtc,
75 struct sde_hw_mixer *hw_mixer);
76
77static lm_prop_install_func_t lm_prop_install_func[SDE_MIXER_MAX];
78
79static void lm_gc_install_property(struct drm_crtc *crtc,
80 struct sde_hw_mixer *hw_mixer);
81
82#define setup_lm_prop_install_funcs(func) \
83 (func[SDE_MIXER_GC] = lm_gc_install_property)
84
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -070085enum {
86 /* Append new DSPP features before SDE_CP_CRTC_DSPP_MAX */
87 /* DSPP Features start */
88 SDE_CP_CRTC_DSPP_IGC,
89 SDE_CP_CRTC_DSPP_PCC,
90 SDE_CP_CRTC_DSPP_GC,
91 SDE_CP_CRTC_DSPP_HUE,
92 SDE_CP_CRTC_DSPP_SAT,
93 SDE_CP_CRTC_DSPP_VAL,
94 SDE_CP_CRTC_DSPP_CONT,
95 SDE_CP_CRTC_DSPP_MEMCOLOR,
96 SDE_CP_CRTC_DSPP_SIXZONE,
97 SDE_CP_CRTC_DSPP_GAMUT,
98 SDE_CP_CRTC_DSPP_DITHER,
99 SDE_CP_CRTC_DSPP_HIST,
Gopikrishnaiah Anandan41980b42016-06-21 16:01:33 -0700100 SDE_CP_CRTC_DSPP_AD,
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700101 SDE_CP_CRTC_DSPP_VLUT,
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700102 SDE_CP_CRTC_DSPP_MAX,
103 /* DSPP features end */
104
105 /* Append new LM features before SDE_CP_CRTC_MAX_FEATURES */
106 /* LM feature start*/
107 SDE_CP_CRTC_LM_GC,
108 /* LM feature end*/
109
110 SDE_CP_CRTC_MAX_FEATURES,
111};
112
Gopikrishnaiah Anandan41980b42016-06-21 16:01:33 -0700113#define INIT_PROP_ATTACH(p, crtc, prop, node, blk, feature, func, val) \
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700114 do { \
115 (p)->crtc = crtc; \
116 (p)->prop = prop; \
117 (p)->prop_node = node; \
118 (p)->pp_blk = blk; \
119 (p)->feature = feature; \
Gopikrishnaiah Anandan41980b42016-06-21 16:01:33 -0700120 (p)->ops = func; \
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700121 (p)->val = val; \
122 } while (0)
123
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700124static void sde_cp_get_hw_payload(struct sde_cp_node *prop_node,
125 struct sde_hw_cp_cfg *hw_cfg,
126 bool *feature_enabled)
127{
128
129 struct drm_property_blob *blob = NULL;
130
131 memset(hw_cfg, 0, sizeof(*hw_cfg));
132 *feature_enabled = false;
133
134 blob = prop_node->blob_ptr;
135 if (prop_node->prop_flags & DRM_MODE_PROP_BLOB) {
136 if (blob) {
137 hw_cfg->len = blob->length;
138 hw_cfg->payload = blob->data;
139 *feature_enabled = true;
140 }
141 } else if (prop_node->prop_flags & DRM_MODE_PROP_RANGE) {
142 /* Check if local blob is Set */
143 if (!blob) {
144 hw_cfg->len = sizeof(prop_node->prop_val);
145 if (prop_node->prop_val)
146 hw_cfg->payload = &prop_node->prop_val;
147 } else {
148 hw_cfg->len = (prop_node->prop_val) ? blob->length :
149 0;
150 hw_cfg->payload = (prop_node->prop_val) ? blob->data
151 : NULL;
152 }
153 if (prop_node->prop_val)
154 *feature_enabled = true;
155 } else {
156 DRM_ERROR("property type is not supported\n");
157 }
158}
159
160static int sde_cp_disable_crtc_blob_property(struct sde_cp_node *prop_node)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700161{
162 struct drm_property_blob *blob = prop_node->blob_ptr;
163
164 if (!blob)
165 return -EINVAL;
166 drm_property_unreference_blob(blob);
167 prop_node->blob_ptr = NULL;
168 return 0;
169}
170
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700171static int sde_cp_create_local_blob(struct drm_crtc *crtc, u32 feature, int len)
172{
173 int ret = -EINVAL;
174 bool found = false;
175 struct sde_cp_node *prop_node = NULL;
176 struct drm_property_blob *blob_ptr;
177 struct sde_crtc *sde_crtc = to_sde_crtc(crtc);
178
179 list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) {
180 if (prop_node->feature == feature) {
181 found = true;
182 break;
183 }
184 }
185
186 if (!found || prop_node->prop_flags & DRM_MODE_PROP_BLOB) {
187 DRM_ERROR("local blob create failed prop found %d flags %d\n",
188 found, prop_node->prop_flags);
189 return ret;
190 }
191
192 blob_ptr = drm_property_create_blob(crtc->dev, len, NULL);
193 ret = (IS_ERR_OR_NULL(blob_ptr)) ? PTR_ERR(blob_ptr) : 0;
194 if (!ret)
195 prop_node->blob_ptr = blob_ptr;
196
197 return ret;
198}
199
200static void sde_cp_destroy_local_blob(struct sde_cp_node *prop_node)
201{
202 if (!(prop_node->prop_flags & DRM_MODE_PROP_BLOB) &&
203 prop_node->blob_ptr)
204 drm_property_unreference_blob(prop_node->blob_ptr);
205}
206
207static int sde_cp_handle_range_property(struct sde_cp_node *prop_node,
208 uint64_t val)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700209{
210 int ret = 0;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700211 struct drm_property_blob *blob_ptr = prop_node->blob_ptr;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700212
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700213 if (!blob_ptr) {
214 prop_node->prop_val = val;
215 return 0;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700216 }
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700217
218 if (!val) {
219 prop_node->prop_val = 0;
220 return 0;
221 }
222
223 ret = copy_from_user(blob_ptr->data, (void *)val, blob_ptr->length);
224 if (ret) {
225 DRM_ERROR("failed to get the property info ret %d", ret);
226 ret = -EFAULT;
227 } else {
228 prop_node->prop_val = val;
229 }
230
231 return ret;
232}
233
234static int sde_cp_disable_crtc_property(struct drm_crtc *crtc,
235 struct drm_property *property,
236 struct sde_cp_node *prop_node)
237{
238 int ret = -EINVAL;
239
240 if (property->flags & DRM_MODE_PROP_BLOB)
241 ret = sde_cp_disable_crtc_blob_property(prop_node);
242 else if (property->flags & DRM_MODE_PROP_RANGE)
243 ret = sde_cp_handle_range_property(prop_node, 0);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700244 return ret;
245}
246
247static int sde_cp_enable_crtc_blob_property(struct drm_crtc *crtc,
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700248 struct sde_cp_node *prop_node,
249 uint64_t val)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700250{
251 struct drm_property_blob *blob = NULL;
252
253 /**
254 * For non-blob based properties add support to create a blob
255 * using the val and store the blob_ptr in prop_node.
256 */
257 blob = drm_property_lookup_blob(crtc->dev, val);
258 if (!blob) {
259 DRM_ERROR("invalid blob id %lld\n", val);
260 return -EINVAL;
261 }
262 /* Release refernce to existing payload of the property */
263 if (prop_node->blob_ptr)
264 drm_property_unreference_blob(prop_node->blob_ptr);
265
266 prop_node->blob_ptr = blob;
267 return 0;
268}
269
270static int sde_cp_enable_crtc_property(struct drm_crtc *crtc,
271 struct drm_property *property,
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700272 struct sde_cp_node *prop_node,
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700273 uint64_t val)
274{
275 int ret = -EINVAL;
276
277 if (property->flags & DRM_MODE_PROP_BLOB)
278 ret = sde_cp_enable_crtc_blob_property(crtc, prop_node, val);
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700279 else if (property->flags & DRM_MODE_PROP_RANGE)
280 ret = sde_cp_handle_range_property(prop_node, val);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700281 return ret;
282}
283
284static int sde_cp_crtc_get_mixer_idx(struct sde_crtc *sde_crtc)
285{
286 if (sde_crtc->num_mixers)
287 return sde_crtc->mixers[0].hw_lm->idx;
288 else
289 return -EINVAL;
290}
291
292static struct sde_kms *get_kms(struct drm_crtc *crtc)
293{
294 struct msm_drm_private *priv = crtc->dev->dev_private;
295
296 return to_sde_kms(priv->kms);
297}
298
299static void sde_cp_crtc_prop_attach(struct sde_cp_prop_attach *prop_attach)
300{
301
302 struct sde_crtc *sde_crtc = to_sde_crtc(prop_attach->crtc);
303
304 drm_object_attach_property(&prop_attach->crtc->base,
305 prop_attach->prop, prop_attach->val);
306
307 INIT_LIST_HEAD(&prop_attach->prop_node->active_list);
308 INIT_LIST_HEAD(&prop_attach->prop_node->dirty_list);
309
310 prop_attach->prop_node->property_id = prop_attach->prop->base.id;
311 prop_attach->prop_node->prop_flags = prop_attach->prop->flags;
312 prop_attach->prop_node->feature = prop_attach->feature;
313 prop_attach->prop_node->pp_blk = prop_attach->pp_blk;
314
315 if (prop_attach->feature < SDE_CP_CRTC_DSPP_MAX)
316 prop_attach->prop_node->dspp_feature_op = prop_attach->ops;
317 else
318 prop_attach->prop_node->lm_feature_op = prop_attach->ops;
319
320 list_add(&prop_attach->prop_node->feature_list,
321 &sde_crtc->feature_list);
322}
323
324void sde_cp_crtc_init(struct drm_crtc *crtc)
325{
326 struct sde_crtc *sde_crtc = NULL;
327
328 if (!crtc) {
329 DRM_ERROR("invalid crtc %pK\n", crtc);
330 return;
331 }
332
333 sde_crtc = to_sde_crtc(crtc);
334 if (!sde_crtc) {
335 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
336 return;
337 }
338
339 INIT_LIST_HEAD(&sde_crtc->active_list);
340 INIT_LIST_HEAD(&sde_crtc->dirty_list);
341 INIT_LIST_HEAD(&sde_crtc->feature_list);
342}
343
Gopikrishnaiah Anandan41980b42016-06-21 16:01:33 -0700344static void sde_cp_crtc_install_immutable_property(struct drm_crtc *crtc,
345 char *name,
346 u32 feature)
347{
348 struct drm_property *prop;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700349 struct sde_cp_node *prop_node = NULL;
Gopikrishnaiah Anandan41980b42016-06-21 16:01:33 -0700350 struct msm_drm_private *priv;
351 struct sde_cp_prop_attach prop_attach;
352 uint64_t val = 0;
353
354 if (feature >= SDE_CP_CRTC_MAX_FEATURES) {
355 DRM_ERROR("invalid feature %d max %d\n", feature,
356 SDE_CP_CRTC_MAX_FEATURES);
357 return;
358 }
359
360 prop_node = kzalloc(sizeof(*prop_node), GFP_KERNEL);
361 if (!prop_node)
362 return;
363
364 priv = crtc->dev->dev_private;
365 prop = priv->cp_property[feature];
366
367 if (!prop) {
368 prop = drm_property_create(crtc->dev, DRM_MODE_PROP_IMMUTABLE,
369 name, 0);
370 if (!prop) {
371 DRM_ERROR("property create failed: %s\n", name);
372 kfree(prop_node);
373 return;
374 }
375 priv->cp_property[feature] = prop;
376 }
377
378 INIT_PROP_ATTACH(&prop_attach, crtc, prop, prop_node, NULL,
379 feature, NULL, val);
380 sde_cp_crtc_prop_attach(&prop_attach);
381}
382
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700383static void sde_cp_crtc_install_range_property(struct drm_crtc *crtc,
384 char *name,
385 const struct sde_pp_blk *pp_blk,
386 u32 feature, void *ops,
387 uint64_t min, uint64_t max,
388 uint64_t val)
389{
390 struct drm_property *prop;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700391 struct sde_cp_node *prop_node = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700392 struct msm_drm_private *priv;
393 struct sde_cp_prop_attach prop_attach;
394
395 if (feature >= SDE_CP_CRTC_MAX_FEATURES) {
396 DRM_ERROR("invalid feature %d max %d\n", feature,
397 SDE_CP_CRTC_MAX_FEATURES);
398 return;
399 }
400
401 prop_node = kzalloc(sizeof(*prop_node), GFP_KERNEL);
402 if (!prop_node)
403 return;
404
405 priv = crtc->dev->dev_private;
406 prop = priv->cp_property[feature];
407
408 if (!prop) {
409 prop = drm_property_create_range(crtc->dev, 0, name, min, max);
410 if (!prop) {
411 DRM_ERROR("property create failed: %s\n", name);
412 kfree(prop_node);
413 return;
414 }
415 priv->cp_property[feature] = prop;
416 }
417
418 INIT_PROP_ATTACH(&prop_attach, crtc, prop, prop_node, pp_blk,
419 feature, ops, val);
420
421 sde_cp_crtc_prop_attach(&prop_attach);
422}
423
424static void sde_cp_crtc_create_blob_property(struct drm_crtc *crtc, char *name,
425 const struct sde_pp_blk *pp_blk,
426 u32 feature, void *ops)
427{
428 struct drm_property *prop;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700429 struct sde_cp_node *prop_node = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700430 struct msm_drm_private *priv;
431 uint64_t val = 0;
432 struct sde_cp_prop_attach prop_attach;
433
434 if (feature >= SDE_CP_CRTC_MAX_FEATURES) {
435 DRM_ERROR("invalid feature %d max %d\n", feature,
436 SDE_CP_CRTC_MAX_FEATURES);
437 return;
438 }
439
440 prop_node = kzalloc(sizeof(*prop_node), GFP_KERNEL);
441 if (!prop_node)
442 return;
443
444 priv = crtc->dev->dev_private;
445 prop = priv->cp_property[feature];
446
447 if (!prop) {
448 prop = drm_property_create(crtc->dev,
449 DRM_MODE_PROP_BLOB, name, 0);
450 if (!prop) {
451 DRM_ERROR("property create failed: %s\n", name);
452 kfree(prop_node);
453 return;
454 }
455 priv->cp_property[feature] = prop;
456 }
457
458 INIT_PROP_ATTACH(&prop_attach, crtc, prop, prop_node, pp_blk,
459 feature, ops, val);
460
461 sde_cp_crtc_prop_attach(&prop_attach);
462}
463
464
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700465static void sde_cp_crtc_setfeature(struct sde_cp_node *prop_node,
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700466 struct sde_crtc *sde_crtc)
467{
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700468 struct sde_hw_cp_cfg hw_cfg;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700469 u32 num_mixers = sde_crtc->num_mixers;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700470 int i = 0;
471 bool is_dspp = true;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700472 bool feature_enabled = false;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700473
474 if (!prop_node->dspp_feature_op && !prop_node->lm_feature_op) {
475 DRM_ERROR("ops not set for dspp/lm\n");
476 return;
477 }
478
479 is_dspp = !prop_node->lm_feature_op;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700480 sde_cp_get_hw_payload(prop_node, &hw_cfg, &feature_enabled);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700481
482 for (i = 0; i < num_mixers; i++) {
483 if (is_dspp) {
484 if (!sde_crtc->mixers[i].hw_dspp)
485 continue;
486 prop_node->dspp_feature_op(sde_crtc->mixers[i].hw_dspp,
487 &hw_cfg);
488 } else {
489 if (!sde_crtc->mixers[i].hw_lm)
490 continue;
491 prop_node->lm_feature_op(sde_crtc->mixers[i].hw_lm,
492 &hw_cfg);
493 }
494 }
495
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700496 if (feature_enabled) {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700497 DRM_DEBUG_DRIVER("Add feature to active list %d\n",
498 prop_node->property_id);
499 list_add_tail(&prop_node->active_list, &sde_crtc->active_list);
500 } else {
501 DRM_DEBUG_DRIVER("remove feature from active list %d\n",
502 prop_node->property_id);
503 list_del_init(&prop_node->active_list);
504 }
505 /* Programming of feature done remove from dirty list */
506 list_del_init(&prop_node->dirty_list);
507}
508
509void sde_cp_crtc_apply_properties(struct drm_crtc *crtc)
510{
511 struct sde_crtc *sde_crtc = NULL;
512 bool set_dspp_flush = false, set_lm_flush = false;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700513 struct sde_cp_node *prop_node = NULL, *n = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700514 struct sde_hw_ctl *ctl;
515 uint32_t flush_mask = 0;
516 u32 num_mixers = 0, i = 0;
517
518 if (!crtc || !crtc->dev) {
519 DRM_ERROR("invalid crtc %pK dev %pK\n", crtc,
520 (crtc ? crtc->dev : NULL));
521 return;
522 }
523
524 sde_crtc = to_sde_crtc(crtc);
525 if (!sde_crtc) {
526 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
527 return;
528 }
529
530 num_mixers = sde_crtc->num_mixers;
531 if (!num_mixers) {
532 DRM_DEBUG_DRIVER("no mixers for this crtc\n");
533 return;
534 }
535
536 /* Check if dirty list is empty for early return */
537 if (list_empty(&sde_crtc->dirty_list)) {
538 DRM_DEBUG_DRIVER("Dirty list is empty\n");
539 return;
540 }
541
542 list_for_each_entry_safe(prop_node, n, &sde_crtc->dirty_list,
543 dirty_list) {
544 sde_cp_crtc_setfeature(prop_node, sde_crtc);
545 /* Set the flush flag to true */
546 if (prop_node->dspp_feature_op)
547 set_dspp_flush = true;
548 else
549 set_lm_flush = true;
550 }
551
552 for (i = 0; i < num_mixers; i++) {
553 ctl = sde_crtc->mixers[i].hw_ctl;
554 if (!ctl)
555 continue;
556 if (set_dspp_flush && ctl->ops.get_bitmask_dspp
557 && sde_crtc->mixers[i].hw_dspp)
558 ctl->ops.get_bitmask_dspp(ctl,
559 &flush_mask,
560 sde_crtc->mixers[i].hw_dspp->idx);
561 ctl->ops.update_pending_flush(ctl, flush_mask);
562 if (set_lm_flush && ctl->ops.get_bitmask_mixer
563 && sde_crtc->mixers[i].hw_lm)
564 flush_mask = ctl->ops.get_bitmask_mixer(ctl,
565 sde_crtc->mixers[i].hw_lm->idx);
566 ctl->ops.update_pending_flush(ctl, flush_mask);
567 }
568}
569
570void sde_cp_crtc_install_properties(struct drm_crtc *crtc)
571{
572 struct sde_kms *kms = NULL;
573 struct sde_crtc *sde_crtc = NULL;
574 struct sde_mdss_cfg *catalog = NULL;
575 unsigned long features = 0;
576 int idx = 0, i = 0;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700577 struct msm_drm_private *priv;
578 struct sde_hw_dspp *hw_dspp = NULL;
579 struct sde_hw_mixer *hw_mixer = NULL;
580
581 if (!crtc || !crtc->dev || !crtc->dev->dev_private) {
582 DRM_ERROR("invalid crtc %pK dev %pK\n",
583 crtc, ((crtc) ? crtc->dev : NULL));
584 return;
585 }
586
587 sde_crtc = to_sde_crtc(crtc);
Gopikrishnaiah Anandan7f6ef942016-06-20 15:50:00 -0700588 if (!sde_crtc) {
589 DRM_ERROR("sde_crtc %pK\n", sde_crtc);
590 return;
591 }
592
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700593 kms = get_kms(crtc);
594 if (!kms || !kms->catalog || !sde_crtc) {
595 DRM_ERROR("invalid sde kms %pK catalog %pK sde_crtc %pK\n",
596 kms, ((kms) ? kms->catalog : NULL), sde_crtc);
597 return;
598 }
599
600 /**
601 * Function can be called during the atomic_check with test_only flag
602 * and actual commit. Allocate properties only if feature list is
603 * empty during the atomic_check with test_only flag.
604 */
605 if (!list_empty(&sde_crtc->feature_list))
606 return;
607
608 catalog = kms->catalog;
609 idx = sde_cp_crtc_get_mixer_idx(sde_crtc);
610 if (idx < 0 || idx >= catalog->mixer_count) {
611 DRM_ERROR("invalid idx %d\n", idx);
612 return;
613 }
614
615 priv = crtc->dev->dev_private;
616 /**
617 * DSPP/LM properties are global to all the CRTCS.
618 * Properties are created for first CRTC and re-used for later
619 * crtcs.
620 */
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -0700621 if (!priv->cp_property) {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700622 priv->cp_property = kzalloc((sizeof(priv->cp_property) *
623 SDE_CP_CRTC_MAX_FEATURES), GFP_KERNEL);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -0700624 setup_dspp_prop_install_funcs(dspp_prop_install_func);
625 setup_lm_prop_install_funcs(lm_prop_install_func);
626 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700627 if (!priv->cp_property)
628 return;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700629
630 if (idx >= catalog->dspp_count)
631 goto lm_property;
632
633 /* Check for all the DSPP properties and attach it to CRTC */
634 hw_dspp = sde_crtc->mixers[0].hw_dspp;
635 features = (hw_dspp) ? hw_dspp->cap->features : 0;
636
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -0700637 if (!hw_dspp || !hw_dspp->cap->sblk || !features)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700638 goto lm_property;
639
640 for (i = 0; i < SDE_DSPP_MAX; i++) {
641 if (!test_bit(i, &features))
642 continue;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -0700643 if (dspp_prop_install_func[i])
644 dspp_prop_install_func[i](crtc, hw_dspp);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700645 }
646
647lm_property:
648 /* Check for all the LM properties and attach it to CRTC */
649 hw_mixer = sde_crtc->mixers[0].hw_lm;
650 features = (hw_mixer) ? hw_mixer->cap->features : 0;
651
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -0700652 if (!hw_mixer || !hw_mixer->cap->sblk || !features)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700653 return;
654
655 for (i = 0; i < SDE_MIXER_MAX; i++) {
656 if (!test_bit(i, &features))
657 continue;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -0700658 if (lm_prop_install_func[i])
659 lm_prop_install_func[i](crtc, hw_mixer);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700660 }
661}
662
663int sde_cp_crtc_set_property(struct drm_crtc *crtc,
664 struct drm_property *property,
665 uint64_t val)
666{
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700667 struct sde_cp_node *prop_node = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700668 struct sde_crtc *sde_crtc = NULL;
669 int ret = 0;
670 u8 found = 0;
671
672 if (!crtc || !property) {
673 DRM_ERROR("invalid crtc %pK property %pK\n", crtc, property);
674 return -EINVAL;
675 }
676
677 sde_crtc = to_sde_crtc(crtc);
678 if (!sde_crtc) {
679 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
680 return -EINVAL;
681 }
682
683 list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) {
684 if (property->base.id == prop_node->property_id) {
685 found = 1;
686 break;
687 }
688 }
689
690 if (!found)
691 return 0;
692
693 /* remove the property from dirty list */
694 list_del_init(&prop_node->dirty_list);
695
696 if (!val)
697 ret = sde_cp_disable_crtc_property(crtc, property, prop_node);
698 else
699 ret = sde_cp_enable_crtc_property(crtc, property,
700 prop_node, val);
701
702 if (!ret) {
703 /* remove the property from active list */
704 list_del_init(&prop_node->active_list);
705 /* Mark the feature as dirty */
706 list_add_tail(&prop_node->dirty_list, &sde_crtc->dirty_list);
707 }
708 return ret;
709}
710
711int sde_cp_crtc_get_property(struct drm_crtc *crtc,
712 struct drm_property *property, uint64_t *val)
713{
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700714 struct sde_cp_node *prop_node = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700715 struct sde_crtc *sde_crtc = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700716
717 if (!crtc || !property || !val) {
718 DRM_ERROR("invalid crtc %pK property %pK val %pK\n",
719 crtc, property, val);
720 return -EINVAL;
721 }
722
723 sde_crtc = to_sde_crtc(crtc);
724 if (!sde_crtc) {
725 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
726 return -EINVAL;
727 }
Gopikrishnaiah Anandand120b762016-10-05 12:03:42 -0700728 /* Return 0 if property is not supported */
729 *val = 0;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700730 list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) {
731 if (property->base.id == prop_node->property_id) {
732 *val = prop_node->prop_val;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700733 break;
734 }
735 }
Gopikrishnaiah Anandand120b762016-10-05 12:03:42 -0700736 return 0;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700737}
738
739void sde_cp_crtc_destroy_properties(struct drm_crtc *crtc)
740{
741 struct sde_crtc *sde_crtc = NULL;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700742 struct sde_cp_node *prop_node = NULL, *n = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700743
744 if (!crtc) {
745 DRM_ERROR("invalid crtc %pK\n", crtc);
746 return;
747 }
748
749 sde_crtc = to_sde_crtc(crtc);
750 if (!sde_crtc) {
751 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
752 return;
753 }
754
755 list_for_each_entry_safe(prop_node, n, &sde_crtc->feature_list,
756 feature_list) {
757 if (prop_node->prop_flags & DRM_MODE_PROP_BLOB
758 && prop_node->blob_ptr)
759 drm_property_unreference_blob(prop_node->blob_ptr);
760
761 list_del_init(&prop_node->active_list);
762 list_del_init(&prop_node->dirty_list);
763 list_del_init(&prop_node->feature_list);
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700764 sde_cp_destroy_local_blob(prop_node);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700765 kfree(prop_node);
766 }
767
768 INIT_LIST_HEAD(&sde_crtc->active_list);
769 INIT_LIST_HEAD(&sde_crtc->dirty_list);
770 INIT_LIST_HEAD(&sde_crtc->feature_list);
771}
Gopikrishnaiah Anandan7f6ef942016-06-20 15:50:00 -0700772
773void sde_cp_crtc_suspend(struct drm_crtc *crtc)
774{
775 struct sde_crtc *sde_crtc = NULL;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700776 struct sde_cp_node *prop_node = NULL, *n = NULL;
Gopikrishnaiah Anandan7f6ef942016-06-20 15:50:00 -0700777
778 if (!crtc) {
779 DRM_ERROR("crtc %pK\n", crtc);
780 return;
781 }
782 sde_crtc = to_sde_crtc(crtc);
783 if (!sde_crtc) {
784 DRM_ERROR("sde_crtc %pK\n", sde_crtc);
785 return;
786 }
787
788 list_for_each_entry_safe(prop_node, n, &sde_crtc->active_list,
789 active_list) {
790 list_add_tail(&prop_node->dirty_list, &sde_crtc->dirty_list);
791 list_del_init(&prop_node->active_list);
792 }
793}
794
795void sde_cp_crtc_resume(struct drm_crtc *crtc)
796{
797 /* placeholder for operations needed during resume */
798}
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -0700799
800static void dspp_pcc_install_property(struct drm_crtc *crtc,
801 struct sde_hw_dspp *hw_dspp)
802{
803 char feature_name[256];
804 u32 version;
805
806 version = hw_dspp->cap->sblk->pcc.version >> 16;
807 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
808 "SDE_DSPP_PCC_V", version);
809 switch (version) {
810 case 1:
811 sde_cp_crtc_create_blob_property(crtc, feature_name,
812 &hw_dspp->cap->sblk->pcc,
813 SDE_CP_CRTC_DSPP_PCC,
814 hw_dspp->ops.setup_pcc);
815 break;
816 default:
817 DRM_ERROR("version %d not supported\n", version);
818 break;
819 }
820}
821
822static void dspp_hsic_install_property(struct drm_crtc *crtc,
823 struct sde_hw_dspp *hw_dspp)
824{
825 char feature_name[256];
826 u32 version;
827
828 version = hw_dspp->cap->sblk->hsic.version >> 16;
829 switch (version) {
830 case 1:
831 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
832 "SDE_DSPP_HUE_V", version);
833 sde_cp_crtc_install_range_property(crtc, feature_name,
834 &hw_dspp->cap->sblk->hsic,
835 SDE_CP_CRTC_DSPP_HUE, hw_dspp->ops.setup_hue,
836 0, U32_MAX, 0);
837 break;
838 default:
839 DRM_ERROR("version %d not supported\n", version);
840 break;
841 }
842}
843
844static void dspp_vlut_install_property(struct drm_crtc *crtc,
845 struct sde_hw_dspp *hw_dspp)
846{
847 char feature_name[256];
848 u32 version;
849
850 version = hw_dspp->cap->sblk->vlut.version >> 16;
851 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
852 "SDE_DSPP_VLUT_V", version);
853 switch (version) {
854 case 1:
855 sde_cp_crtc_install_range_property(crtc, feature_name,
856 &hw_dspp->cap->sblk->vlut,
857 SDE_CP_CRTC_DSPP_VLUT, hw_dspp->ops.setup_vlut,
858 0, U64_MAX, 0);
859 sde_cp_create_local_blob(crtc,
860 SDE_CP_CRTC_DSPP_VLUT,
861 sizeof(struct drm_msm_pa_vlut));
862 break;
863 default:
864 DRM_ERROR("version %d not supported\n", version);
865 break;
866 }
867}
868
869static void dspp_ad_install_property(struct drm_crtc *crtc,
870 struct sde_hw_dspp *hw_dspp)
871{
872 char feature_name[256];
873 u32 version;
874
875 version = hw_dspp->cap->sblk->ad.version >> 16;
876 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
877 "SDE_DSPP_AD_V", version);
878 switch (version) {
879 case 3:
880 sde_cp_crtc_install_immutable_property(crtc,
881 feature_name, SDE_CP_CRTC_DSPP_AD);
882 break;
883 default:
884 DRM_ERROR("version %d not supported\n", version);
885 break;
886 }
887}
888
889static void lm_gc_install_property(struct drm_crtc *crtc,
890 struct sde_hw_mixer *hw_mixer)
891{
892 char feature_name[256];
893 u32 version;
894
895 version = hw_mixer->cap->sblk->gc.version >> 16;
896 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
897 "SDE_LM_GC_V", version);
898 switch (version) {
899 case 1:
900 sde_cp_crtc_create_blob_property(crtc, feature_name,
901 &hw_mixer->cap->sblk->gc,
902 SDE_CP_CRTC_LM_GC,
903 hw_mixer->ops.setup_gc);
904 break;
905 default:
906 DRM_ERROR("version %d not supported\n", version);
907 break;
908 }
909}