blob: 79b39bd28d7500bb41a4776c14e77c55956c5e4a [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"
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -080024#include "sde_ad4.h"
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -080025#include "sde_hw_interrupts.h"
26#include "sde_core_irq.h"
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -070027
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -070028struct sde_cp_node {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -070029 u32 property_id;
30 u32 prop_flags;
31 u32 feature;
32 void *blob_ptr;
33 uint64_t prop_val;
34 const struct sde_pp_blk *pp_blk;
35 struct list_head feature_list;
36 struct list_head active_list;
37 struct list_head dirty_list;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -070038 bool is_dspp_feature;
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -080039 u32 prop_blob_sz;
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -080040 struct sde_irq_callback *irq;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -070041};
42
43struct sde_cp_prop_attach {
44 struct drm_crtc *crtc;
45 struct drm_property *prop;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -070046 struct sde_cp_node *prop_node;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -070047 u32 feature;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -070048 uint64_t val;
49};
50
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -070051static void dspp_pcc_install_property(struct drm_crtc *crtc);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070052
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -070053static void dspp_hsic_install_property(struct drm_crtc *crtc);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070054
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -070055static void dspp_ad_install_property(struct drm_crtc *crtc);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070056
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -070057static void dspp_vlut_install_property(struct drm_crtc *crtc);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070058
Gopikrishnaiah Anandanfbf75392017-01-16 10:43:36 -080059static void dspp_gamut_install_property(struct drm_crtc *crtc);
60
61static void dspp_gc_install_property(struct drm_crtc *crtc);
62
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -070063typedef void (*dspp_prop_install_func_t)(struct drm_crtc *crtc);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070064
65static dspp_prop_install_func_t dspp_prop_install_func[SDE_DSPP_MAX];
66
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -080067static void sde_cp_update_list(struct sde_cp_node *prop_node,
68 struct sde_crtc *crtc, bool dirty_list);
69
70static int sde_cp_ad_validate_prop(struct sde_cp_node *prop_node,
71 struct sde_crtc *crtc);
72
Gopikrishnaiah Anandanb6b401f2017-03-14 16:39:49 -070073static void sde_cp_notify_ad_event(struct drm_crtc *crtc_drm, void *arg);
74
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070075#define setup_dspp_prop_install_funcs(func) \
76do { \
77 func[SDE_DSPP_PCC] = dspp_pcc_install_property; \
78 func[SDE_DSPP_HSIC] = dspp_hsic_install_property; \
79 func[SDE_DSPP_AD] = dspp_ad_install_property; \
80 func[SDE_DSPP_VLUT] = dspp_vlut_install_property; \
Gopikrishnaiah Anandanfbf75392017-01-16 10:43:36 -080081 func[SDE_DSPP_GAMUT] = dspp_gamut_install_property; \
82 func[SDE_DSPP_GC] = dspp_gc_install_property; \
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070083} while (0)
84
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -070085typedef void (*lm_prop_install_func_t)(struct drm_crtc *crtc);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070086
87static lm_prop_install_func_t lm_prop_install_func[SDE_MIXER_MAX];
88
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -070089static void lm_gc_install_property(struct drm_crtc *crtc);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070090
91#define setup_lm_prop_install_funcs(func) \
92 (func[SDE_MIXER_GC] = lm_gc_install_property)
93
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -070094enum {
95 /* Append new DSPP features before SDE_CP_CRTC_DSPP_MAX */
96 /* DSPP Features start */
97 SDE_CP_CRTC_DSPP_IGC,
98 SDE_CP_CRTC_DSPP_PCC,
99 SDE_CP_CRTC_DSPP_GC,
100 SDE_CP_CRTC_DSPP_HUE,
101 SDE_CP_CRTC_DSPP_SAT,
102 SDE_CP_CRTC_DSPP_VAL,
103 SDE_CP_CRTC_DSPP_CONT,
104 SDE_CP_CRTC_DSPP_MEMCOLOR,
105 SDE_CP_CRTC_DSPP_SIXZONE,
106 SDE_CP_CRTC_DSPP_GAMUT,
107 SDE_CP_CRTC_DSPP_DITHER,
108 SDE_CP_CRTC_DSPP_HIST,
Gopikrishnaiah Anandan41980b42016-06-21 16:01:33 -0700109 SDE_CP_CRTC_DSPP_AD,
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700110 SDE_CP_CRTC_DSPP_VLUT,
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800111 SDE_CP_CRTC_DSPP_AD_MODE,
112 SDE_CP_CRTC_DSPP_AD_INIT,
113 SDE_CP_CRTC_DSPP_AD_CFG,
114 SDE_CP_CRTC_DSPP_AD_INPUT,
115 SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS,
116 SDE_CP_CRTC_DSPP_AD_BACKLIGHT,
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700117 SDE_CP_CRTC_DSPP_MAX,
118 /* DSPP features end */
119
120 /* Append new LM features before SDE_CP_CRTC_MAX_FEATURES */
121 /* LM feature start*/
122 SDE_CP_CRTC_LM_GC,
123 /* LM feature end*/
124
125 SDE_CP_CRTC_MAX_FEATURES,
126};
127
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700128#define INIT_PROP_ATTACH(p, crtc, prop, node, feature, val) \
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700129 do { \
130 (p)->crtc = crtc; \
131 (p)->prop = prop; \
132 (p)->prop_node = node; \
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700133 (p)->feature = feature; \
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700134 (p)->val = val; \
135 } while (0)
136
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700137static void sde_cp_get_hw_payload(struct sde_cp_node *prop_node,
138 struct sde_hw_cp_cfg *hw_cfg,
139 bool *feature_enabled)
140{
141
142 struct drm_property_blob *blob = NULL;
143
144 memset(hw_cfg, 0, sizeof(*hw_cfg));
145 *feature_enabled = false;
146
147 blob = prop_node->blob_ptr;
148 if (prop_node->prop_flags & DRM_MODE_PROP_BLOB) {
149 if (blob) {
150 hw_cfg->len = blob->length;
151 hw_cfg->payload = blob->data;
152 *feature_enabled = true;
153 }
154 } else if (prop_node->prop_flags & DRM_MODE_PROP_RANGE) {
155 /* Check if local blob is Set */
156 if (!blob) {
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800157 if (prop_node->prop_val) {
158 hw_cfg->len = sizeof(prop_node->prop_val);
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700159 hw_cfg->payload = &prop_node->prop_val;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800160 }
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700161 } else {
162 hw_cfg->len = (prop_node->prop_val) ? blob->length :
163 0;
164 hw_cfg->payload = (prop_node->prop_val) ? blob->data
165 : NULL;
166 }
167 if (prop_node->prop_val)
168 *feature_enabled = true;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800169 } else if (prop_node->prop_flags & DRM_MODE_PROP_ENUM) {
170 *feature_enabled = (prop_node->prop_val != 0);
171 hw_cfg->len = sizeof(prop_node->prop_val);
172 hw_cfg->payload = &prop_node->prop_val;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700173 } else {
174 DRM_ERROR("property type is not supported\n");
175 }
176}
177
178static int sde_cp_disable_crtc_blob_property(struct sde_cp_node *prop_node)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700179{
180 struct drm_property_blob *blob = prop_node->blob_ptr;
181
182 if (!blob)
183 return -EINVAL;
184 drm_property_unreference_blob(blob);
185 prop_node->blob_ptr = NULL;
186 return 0;
187}
188
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700189static int sde_cp_create_local_blob(struct drm_crtc *crtc, u32 feature, int len)
190{
191 int ret = -EINVAL;
192 bool found = false;
193 struct sde_cp_node *prop_node = NULL;
194 struct drm_property_blob *blob_ptr;
195 struct sde_crtc *sde_crtc = to_sde_crtc(crtc);
196
197 list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) {
198 if (prop_node->feature == feature) {
199 found = true;
200 break;
201 }
202 }
203
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800204 if (!found || !(prop_node->prop_flags & DRM_MODE_PROP_RANGE)) {
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700205 DRM_ERROR("local blob create failed prop found %d flags %d\n",
206 found, prop_node->prop_flags);
207 return ret;
208 }
209
210 blob_ptr = drm_property_create_blob(crtc->dev, len, NULL);
211 ret = (IS_ERR_OR_NULL(blob_ptr)) ? PTR_ERR(blob_ptr) : 0;
212 if (!ret)
213 prop_node->blob_ptr = blob_ptr;
214
215 return ret;
216}
217
218static void sde_cp_destroy_local_blob(struct sde_cp_node *prop_node)
219{
220 if (!(prop_node->prop_flags & DRM_MODE_PROP_BLOB) &&
221 prop_node->blob_ptr)
222 drm_property_unreference_blob(prop_node->blob_ptr);
223}
224
225static int sde_cp_handle_range_property(struct sde_cp_node *prop_node,
226 uint64_t val)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700227{
228 int ret = 0;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700229 struct drm_property_blob *blob_ptr = prop_node->blob_ptr;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700230
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700231 if (!blob_ptr) {
232 prop_node->prop_val = val;
233 return 0;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700234 }
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700235
236 if (!val) {
237 prop_node->prop_val = 0;
238 return 0;
239 }
240
241 ret = copy_from_user(blob_ptr->data, (void *)val, blob_ptr->length);
242 if (ret) {
243 DRM_ERROR("failed to get the property info ret %d", ret);
244 ret = -EFAULT;
245 } else {
246 prop_node->prop_val = val;
247 }
248
249 return ret;
250}
251
252static int sde_cp_disable_crtc_property(struct drm_crtc *crtc,
253 struct drm_property *property,
254 struct sde_cp_node *prop_node)
255{
256 int ret = -EINVAL;
257
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800258 if (property->flags & DRM_MODE_PROP_BLOB) {
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700259 ret = sde_cp_disable_crtc_blob_property(prop_node);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800260 } else if (property->flags & DRM_MODE_PROP_RANGE) {
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700261 ret = sde_cp_handle_range_property(prop_node, 0);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800262 } else if (property->flags & DRM_MODE_PROP_ENUM) {
263 ret = 0;
264 prop_node->prop_val = 0;
265 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700266 return ret;
267}
268
269static int sde_cp_enable_crtc_blob_property(struct drm_crtc *crtc,
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700270 struct sde_cp_node *prop_node,
271 uint64_t val)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700272{
273 struct drm_property_blob *blob = NULL;
274
275 /**
276 * For non-blob based properties add support to create a blob
277 * using the val and store the blob_ptr in prop_node.
278 */
279 blob = drm_property_lookup_blob(crtc->dev, val);
280 if (!blob) {
281 DRM_ERROR("invalid blob id %lld\n", val);
282 return -EINVAL;
283 }
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -0800284 if (blob->length != prop_node->prop_blob_sz) {
285 DRM_ERROR("invalid blob len %zd exp %d feature %d\n",
286 blob->length, prop_node->prop_blob_sz, prop_node->feature);
287 drm_property_unreference_blob(blob);
288 return -EINVAL;
289 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700290 /* Release refernce to existing payload of the property */
291 if (prop_node->blob_ptr)
292 drm_property_unreference_blob(prop_node->blob_ptr);
293
294 prop_node->blob_ptr = blob;
295 return 0;
296}
297
298static int sde_cp_enable_crtc_property(struct drm_crtc *crtc,
299 struct drm_property *property,
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700300 struct sde_cp_node *prop_node,
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700301 uint64_t val)
302{
303 int ret = -EINVAL;
304
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800305 if (property->flags & DRM_MODE_PROP_BLOB) {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700306 ret = sde_cp_enable_crtc_blob_property(crtc, prop_node, val);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800307 } else if (property->flags & DRM_MODE_PROP_RANGE) {
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700308 ret = sde_cp_handle_range_property(prop_node, val);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800309 } else if (property->flags & DRM_MODE_PROP_ENUM) {
310 ret = 0;
311 prop_node->prop_val = val;
312 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700313 return ret;
314}
315
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700316static struct sde_kms *get_kms(struct drm_crtc *crtc)
317{
318 struct msm_drm_private *priv = crtc->dev->dev_private;
319
320 return to_sde_kms(priv->kms);
321}
322
323static void sde_cp_crtc_prop_attach(struct sde_cp_prop_attach *prop_attach)
324{
325
326 struct sde_crtc *sde_crtc = to_sde_crtc(prop_attach->crtc);
327
328 drm_object_attach_property(&prop_attach->crtc->base,
329 prop_attach->prop, prop_attach->val);
330
331 INIT_LIST_HEAD(&prop_attach->prop_node->active_list);
332 INIT_LIST_HEAD(&prop_attach->prop_node->dirty_list);
333
334 prop_attach->prop_node->property_id = prop_attach->prop->base.id;
335 prop_attach->prop_node->prop_flags = prop_attach->prop->flags;
336 prop_attach->prop_node->feature = prop_attach->feature;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700337
338 if (prop_attach->feature < SDE_CP_CRTC_DSPP_MAX)
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700339 prop_attach->prop_node->is_dspp_feature = true;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700340 else
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700341 prop_attach->prop_node->is_dspp_feature = false;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700342
343 list_add(&prop_attach->prop_node->feature_list,
344 &sde_crtc->feature_list);
345}
346
347void sde_cp_crtc_init(struct drm_crtc *crtc)
348{
349 struct sde_crtc *sde_crtc = NULL;
350
351 if (!crtc) {
352 DRM_ERROR("invalid crtc %pK\n", crtc);
353 return;
354 }
355
356 sde_crtc = to_sde_crtc(crtc);
357 if (!sde_crtc) {
358 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
359 return;
360 }
361
362 INIT_LIST_HEAD(&sde_crtc->active_list);
363 INIT_LIST_HEAD(&sde_crtc->dirty_list);
364 INIT_LIST_HEAD(&sde_crtc->feature_list);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800365 INIT_LIST_HEAD(&sde_crtc->ad_dirty);
366 INIT_LIST_HEAD(&sde_crtc->ad_active);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700367}
368
Gopikrishnaiah Anandan41980b42016-06-21 16:01:33 -0700369static void sde_cp_crtc_install_immutable_property(struct drm_crtc *crtc,
370 char *name,
371 u32 feature)
372{
373 struct drm_property *prop;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700374 struct sde_cp_node *prop_node = NULL;
Gopikrishnaiah Anandan41980b42016-06-21 16:01:33 -0700375 struct msm_drm_private *priv;
376 struct sde_cp_prop_attach prop_attach;
377 uint64_t val = 0;
378
379 if (feature >= SDE_CP_CRTC_MAX_FEATURES) {
380 DRM_ERROR("invalid feature %d max %d\n", feature,
381 SDE_CP_CRTC_MAX_FEATURES);
382 return;
383 }
384
385 prop_node = kzalloc(sizeof(*prop_node), GFP_KERNEL);
386 if (!prop_node)
387 return;
388
389 priv = crtc->dev->dev_private;
390 prop = priv->cp_property[feature];
391
392 if (!prop) {
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800393 prop = drm_property_create_range(crtc->dev,
394 DRM_MODE_PROP_IMMUTABLE, name, 0, 1);
Gopikrishnaiah Anandan41980b42016-06-21 16:01:33 -0700395 if (!prop) {
396 DRM_ERROR("property create failed: %s\n", name);
397 kfree(prop_node);
398 return;
399 }
400 priv->cp_property[feature] = prop;
401 }
402
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700403 INIT_PROP_ATTACH(&prop_attach, crtc, prop, prop_node,
404 feature, val);
Gopikrishnaiah Anandan41980b42016-06-21 16:01:33 -0700405 sde_cp_crtc_prop_attach(&prop_attach);
406}
407
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700408static void sde_cp_crtc_install_range_property(struct drm_crtc *crtc,
409 char *name,
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700410 u32 feature,
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700411 uint64_t min, uint64_t max,
412 uint64_t val)
413{
414 struct drm_property *prop;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700415 struct sde_cp_node *prop_node = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700416 struct msm_drm_private *priv;
417 struct sde_cp_prop_attach prop_attach;
418
419 if (feature >= SDE_CP_CRTC_MAX_FEATURES) {
420 DRM_ERROR("invalid feature %d max %d\n", feature,
421 SDE_CP_CRTC_MAX_FEATURES);
422 return;
423 }
424
425 prop_node = kzalloc(sizeof(*prop_node), GFP_KERNEL);
426 if (!prop_node)
427 return;
428
429 priv = crtc->dev->dev_private;
430 prop = priv->cp_property[feature];
431
432 if (!prop) {
433 prop = drm_property_create_range(crtc->dev, 0, name, min, max);
434 if (!prop) {
435 DRM_ERROR("property create failed: %s\n", name);
436 kfree(prop_node);
437 return;
438 }
439 priv->cp_property[feature] = prop;
440 }
441
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700442 INIT_PROP_ATTACH(&prop_attach, crtc, prop, prop_node,
443 feature, val);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700444
445 sde_cp_crtc_prop_attach(&prop_attach);
446}
447
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800448static void sde_cp_crtc_install_blob_property(struct drm_crtc *crtc, char *name,
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -0800449 u32 feature, u32 blob_sz)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700450{
451 struct drm_property *prop;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700452 struct sde_cp_node *prop_node = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700453 struct msm_drm_private *priv;
454 uint64_t val = 0;
455 struct sde_cp_prop_attach prop_attach;
456
457 if (feature >= SDE_CP_CRTC_MAX_FEATURES) {
458 DRM_ERROR("invalid feature %d max %d\n", feature,
459 SDE_CP_CRTC_MAX_FEATURES);
460 return;
461 }
462
463 prop_node = kzalloc(sizeof(*prop_node), GFP_KERNEL);
464 if (!prop_node)
465 return;
466
467 priv = crtc->dev->dev_private;
468 prop = priv->cp_property[feature];
469
470 if (!prop) {
471 prop = drm_property_create(crtc->dev,
472 DRM_MODE_PROP_BLOB, name, 0);
473 if (!prop) {
474 DRM_ERROR("property create failed: %s\n", name);
475 kfree(prop_node);
476 return;
477 }
478 priv->cp_property[feature] = prop;
479 }
480
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700481 INIT_PROP_ATTACH(&prop_attach, crtc, prop, prop_node,
482 feature, val);
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -0800483 prop_node->prop_blob_sz = blob_sz;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700484
485 sde_cp_crtc_prop_attach(&prop_attach);
486}
487
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800488static void sde_cp_crtc_install_enum_property(struct drm_crtc *crtc,
489 u32 feature, const struct drm_prop_enum_list *list, u32 enum_sz,
490 char *name)
491{
492 struct drm_property *prop;
493 struct sde_cp_node *prop_node = NULL;
494 struct msm_drm_private *priv;
495 uint64_t val = 0;
496 struct sde_cp_prop_attach prop_attach;
497
498 if (feature >= SDE_CP_CRTC_MAX_FEATURES) {
499 DRM_ERROR("invalid feature %d max %d\n", feature,
500 SDE_CP_CRTC_MAX_FEATURES);
501 return;
502 }
503
504 prop_node = kzalloc(sizeof(*prop_node), GFP_KERNEL);
505 if (!prop_node)
506 return;
507
508 priv = crtc->dev->dev_private;
509 prop = priv->cp_property[feature];
510
511 if (!prop) {
512 prop = drm_property_create_enum(crtc->dev, 0, name,
513 list, enum_sz);
514 if (!prop) {
515 DRM_ERROR("property create failed: %s\n", name);
516 kfree(prop_node);
517 return;
518 }
519 priv->cp_property[feature] = prop;
520 }
521
522 INIT_PROP_ATTACH(&prop_attach, crtc, prop, prop_node,
523 feature, val);
524
525 sde_cp_crtc_prop_attach(&prop_attach);
526}
527
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700528static void sde_cp_crtc_setfeature(struct sde_cp_node *prop_node,
Gopikrishnaiah Anandanf5818e02017-01-30 10:46:58 -0800529 struct sde_crtc *sde_crtc, u32 last_feature)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700530{
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700531 struct sde_hw_cp_cfg hw_cfg;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700532 struct sde_hw_mixer *hw_lm;
533 struct sde_hw_dspp *hw_dspp;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700534 u32 num_mixers = sde_crtc->num_mixers;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700535 int i = 0;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700536 bool feature_enabled = false;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700537 int ret = 0;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800538 struct sde_ad_hw_cfg ad_cfg;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700539
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700540 sde_cp_get_hw_payload(prop_node, &hw_cfg, &feature_enabled);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800541 hw_cfg.num_of_mixers = sde_crtc->num_mixers;
542 hw_cfg.displayh = sde_crtc->base.mode.hdisplay;
543 hw_cfg.displayv = sde_crtc->base.mode.vdisplay;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700544
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700545 for (i = 0; i < num_mixers && !ret; i++) {
546 hw_lm = sde_crtc->mixers[i].hw_lm;
547 hw_dspp = sde_crtc->mixers[i].hw_dspp;
Gopikrishnaiah Anandanfbf75392017-01-16 10:43:36 -0800548 hw_cfg.ctl = sde_crtc->mixers[i].hw_ctl;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800549 hw_cfg.mixer_info = hw_lm;
Gopikrishnaiah Anandanf5818e02017-01-30 10:46:58 -0800550 if (i == num_mixers - 1)
551 hw_cfg.last_feature = last_feature;
552 else
553 hw_cfg.last_feature = 0;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700554 switch (prop_node->feature) {
555 case SDE_CP_CRTC_DSPP_VLUT:
556 if (!hw_dspp || !hw_dspp->ops.setup_vlut) {
557 ret = -EINVAL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700558 continue;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700559 }
560 hw_dspp->ops.setup_vlut(hw_dspp, &hw_cfg);
561 break;
562 case SDE_CP_CRTC_DSPP_PCC:
563 if (!hw_dspp || !hw_dspp->ops.setup_pcc) {
564 ret = -EINVAL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700565 continue;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700566 }
567 hw_dspp->ops.setup_pcc(hw_dspp, &hw_cfg);
568 break;
569 case SDE_CP_CRTC_DSPP_IGC:
570 if (!hw_dspp || !hw_dspp->ops.setup_igc) {
571 ret = -EINVAL;
572 continue;
573 }
574 hw_dspp->ops.setup_igc(hw_dspp, &hw_cfg);
575 break;
576 case SDE_CP_CRTC_DSPP_GC:
577 if (!hw_dspp || !hw_dspp->ops.setup_gc) {
578 ret = -EINVAL;
579 continue;
580 }
581 hw_dspp->ops.setup_gc(hw_dspp, &hw_cfg);
582 break;
583 case SDE_CP_CRTC_DSPP_HUE:
584 if (!hw_dspp || !hw_dspp->ops.setup_hue) {
585 ret = -EINVAL;
586 continue;
587 }
588 hw_dspp->ops.setup_hue(hw_dspp, &hw_cfg);
589 break;
590 case SDE_CP_CRTC_DSPP_SAT:
591 if (!hw_dspp || !hw_dspp->ops.setup_sat) {
592 ret = -EINVAL;
593 continue;
594 }
595 hw_dspp->ops.setup_sat(hw_dspp, &hw_cfg);
596 break;
597 case SDE_CP_CRTC_DSPP_VAL:
598 if (!hw_dspp || !hw_dspp->ops.setup_val) {
599 ret = -EINVAL;
600 continue;
601 }
602 hw_dspp->ops.setup_val(hw_dspp, &hw_cfg);
603 break;
604 case SDE_CP_CRTC_DSPP_CONT:
605 if (!hw_dspp || !hw_dspp->ops.setup_cont) {
606 ret = -EINVAL;
607 continue;
608 }
609 hw_dspp->ops.setup_cont(hw_dspp, &hw_cfg);
610 break;
611 case SDE_CP_CRTC_DSPP_MEMCOLOR:
Stephen Boyd22f7b512017-03-01 16:56:35 -0800612 if (!hw_dspp || !hw_dspp->ops.setup_pa_memcolor) {
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700613 ret = -EINVAL;
614 continue;
Stephen Boyd22f7b512017-03-01 16:56:35 -0800615 }
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700616 hw_dspp->ops.setup_pa_memcolor(hw_dspp, &hw_cfg);
617 break;
618 case SDE_CP_CRTC_DSPP_SIXZONE:
619 if (!hw_dspp || !hw_dspp->ops.setup_sixzone) {
620 ret = -EINVAL;
621 continue;
622 }
623 hw_dspp->ops.setup_sixzone(hw_dspp, &hw_cfg);
624 break;
625 case SDE_CP_CRTC_DSPP_GAMUT:
626 if (!hw_dspp || !hw_dspp->ops.setup_gamut) {
627 ret = -EINVAL;
628 continue;
629 }
630 hw_dspp->ops.setup_gamut(hw_dspp, &hw_cfg);
631 break;
632 case SDE_CP_CRTC_LM_GC:
633 if (!hw_lm || !hw_lm->ops.setup_gc) {
634 ret = -EINVAL;
635 continue;
636 }
637 hw_lm->ops.setup_gc(hw_lm, &hw_cfg);
638 break;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800639 case SDE_CP_CRTC_DSPP_AD_MODE:
640 if (!hw_dspp || !hw_dspp->ops.setup_ad) {
641 ret = -EINVAL;
642 continue;
643 }
644 ad_cfg.prop = AD_MODE;
645 ad_cfg.hw_cfg = &hw_cfg;
646 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
647 break;
648 case SDE_CP_CRTC_DSPP_AD_INIT:
649 if (!hw_dspp || !hw_dspp->ops.setup_ad) {
650 ret = -EINVAL;
651 continue;
652 }
653 ad_cfg.prop = AD_INIT;
654 ad_cfg.hw_cfg = &hw_cfg;
655 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
656 break;
657 case SDE_CP_CRTC_DSPP_AD_CFG:
658 if (!hw_dspp || !hw_dspp->ops.setup_ad) {
659 ret = -EINVAL;
660 continue;
661 }
662 ad_cfg.prop = AD_CFG;
663 ad_cfg.hw_cfg = &hw_cfg;
664 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
665 break;
666 case SDE_CP_CRTC_DSPP_AD_INPUT:
667 if (!hw_dspp || !hw_dspp->ops.setup_ad) {
668 ret = -EINVAL;
669 continue;
670 }
671 ad_cfg.prop = AD_INPUT;
672 ad_cfg.hw_cfg = &hw_cfg;
673 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
674 break;
675 case SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS:
676 if (!hw_dspp || !hw_dspp->ops.setup_ad) {
677 ret = -EINVAL;
678 continue;
679 }
680 ad_cfg.prop = AD_ASSERTIVE;
681 ad_cfg.hw_cfg = &hw_cfg;
682 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
683 break;
684 case SDE_CP_CRTC_DSPP_AD_BACKLIGHT:
685 if (!hw_dspp || !hw_dspp->ops.setup_ad) {
686 ret = -EINVAL;
687 continue;
688 }
689 ad_cfg.prop = AD_BACKLIGHT;
690 ad_cfg.hw_cfg = &hw_cfg;
691 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
692 break;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700693 default:
694 ret = -EINVAL;
695 break;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700696 }
697 }
698
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700699 if (ret) {
700 DRM_ERROR("failed to %s feature %d\n",
701 ((feature_enabled) ? "enable" : "disable"),
702 prop_node->feature);
703 return;
704 }
705
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700706 if (feature_enabled) {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700707 DRM_DEBUG_DRIVER("Add feature to active list %d\n",
708 prop_node->property_id);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800709 sde_cp_update_list(prop_node, sde_crtc, false);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700710 } else {
711 DRM_DEBUG_DRIVER("remove feature from active list %d\n",
712 prop_node->property_id);
713 list_del_init(&prop_node->active_list);
714 }
715 /* Programming of feature done remove from dirty list */
716 list_del_init(&prop_node->dirty_list);
717}
718
719void sde_cp_crtc_apply_properties(struct drm_crtc *crtc)
720{
721 struct sde_crtc *sde_crtc = NULL;
722 bool set_dspp_flush = false, set_lm_flush = false;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700723 struct sde_cp_node *prop_node = NULL, *n = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700724 struct sde_hw_ctl *ctl;
725 uint32_t flush_mask = 0;
726 u32 num_mixers = 0, i = 0;
Gopikrishnaiah Anandanf5818e02017-01-30 10:46:58 -0800727 u32 num_of_features;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700728
729 if (!crtc || !crtc->dev) {
730 DRM_ERROR("invalid crtc %pK dev %pK\n", crtc,
731 (crtc ? crtc->dev : NULL));
732 return;
733 }
734
735 sde_crtc = to_sde_crtc(crtc);
736 if (!sde_crtc) {
737 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
738 return;
739 }
740
741 num_mixers = sde_crtc->num_mixers;
742 if (!num_mixers) {
743 DRM_DEBUG_DRIVER("no mixers for this crtc\n");
744 return;
745 }
746
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800747 /* Check if dirty lists are empty and ad features are disabled for
748 * early return. If ad properties are active then we need to issue
749 * dspp flush.
750 **/
751 if (list_empty(&sde_crtc->dirty_list) &&
752 list_empty(&sde_crtc->ad_dirty)) {
753 if (list_empty(&sde_crtc->ad_active)) {
754 DRM_DEBUG_DRIVER("Dirty list is empty\n");
755 return;
756 }
757 set_dspp_flush = true;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700758 }
759
Gopikrishnaiah Anandanf5818e02017-01-30 10:46:58 -0800760 num_of_features = 0;
761 list_for_each_entry(prop_node, &sde_crtc->dirty_list, dirty_list)
762 num_of_features++;
763
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700764 list_for_each_entry_safe(prop_node, n, &sde_crtc->dirty_list,
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800765 dirty_list) {
Gopikrishnaiah Anandanf5818e02017-01-30 10:46:58 -0800766 num_of_features--;
767 sde_cp_crtc_setfeature(prop_node, sde_crtc,
768 (num_of_features == 0));
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700769 /* Set the flush flag to true */
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700770 if (prop_node->is_dspp_feature)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700771 set_dspp_flush = true;
772 else
773 set_lm_flush = true;
774 }
775
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800776 num_of_features = 0;
777 list_for_each_entry(prop_node, &sde_crtc->ad_dirty, dirty_list)
778 num_of_features++;
779
780 list_for_each_entry_safe(prop_node, n, &sde_crtc->ad_dirty,
781 dirty_list) {
782 num_of_features--;
783 set_dspp_flush = true;
784 sde_cp_crtc_setfeature(prop_node, sde_crtc,
785 (num_of_features == 0));
786 }
787
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700788 for (i = 0; i < num_mixers; i++) {
789 ctl = sde_crtc->mixers[i].hw_ctl;
790 if (!ctl)
791 continue;
792 if (set_dspp_flush && ctl->ops.get_bitmask_dspp
Stephen Boyd22f7b512017-03-01 16:56:35 -0800793 && sde_crtc->mixers[i].hw_dspp) {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700794 ctl->ops.get_bitmask_dspp(ctl,
795 &flush_mask,
796 sde_crtc->mixers[i].hw_dspp->idx);
797 ctl->ops.update_pending_flush(ctl, flush_mask);
Stephen Boyd22f7b512017-03-01 16:56:35 -0800798 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700799 if (set_lm_flush && ctl->ops.get_bitmask_mixer
Stephen Boyd22f7b512017-03-01 16:56:35 -0800800 && sde_crtc->mixers[i].hw_lm) {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700801 flush_mask = ctl->ops.get_bitmask_mixer(ctl,
802 sde_crtc->mixers[i].hw_lm->idx);
803 ctl->ops.update_pending_flush(ctl, flush_mask);
Stephen Boyd22f7b512017-03-01 16:56:35 -0800804 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700805 }
806}
807
808void sde_cp_crtc_install_properties(struct drm_crtc *crtc)
809{
810 struct sde_kms *kms = NULL;
811 struct sde_crtc *sde_crtc = NULL;
812 struct sde_mdss_cfg *catalog = NULL;
813 unsigned long features = 0;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700814 int i = 0;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700815 struct msm_drm_private *priv;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700816
817 if (!crtc || !crtc->dev || !crtc->dev->dev_private) {
818 DRM_ERROR("invalid crtc %pK dev %pK\n",
819 crtc, ((crtc) ? crtc->dev : NULL));
820 return;
821 }
822
823 sde_crtc = to_sde_crtc(crtc);
Gopikrishnaiah Anandan7f6ef942016-06-20 15:50:00 -0700824 if (!sde_crtc) {
825 DRM_ERROR("sde_crtc %pK\n", sde_crtc);
826 return;
827 }
828
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700829 kms = get_kms(crtc);
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700830 if (!kms || !kms->catalog) {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700831 DRM_ERROR("invalid sde kms %pK catalog %pK sde_crtc %pK\n",
832 kms, ((kms) ? kms->catalog : NULL), sde_crtc);
833 return;
834 }
835
836 /**
837 * Function can be called during the atomic_check with test_only flag
838 * and actual commit. Allocate properties only if feature list is
839 * empty during the atomic_check with test_only flag.
840 */
841 if (!list_empty(&sde_crtc->feature_list))
842 return;
843
844 catalog = kms->catalog;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700845 priv = crtc->dev->dev_private;
846 /**
847 * DSPP/LM properties are global to all the CRTCS.
848 * Properties are created for first CRTC and re-used for later
849 * crtcs.
850 */
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -0700851 if (!priv->cp_property) {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700852 priv->cp_property = kzalloc((sizeof(priv->cp_property) *
853 SDE_CP_CRTC_MAX_FEATURES), GFP_KERNEL);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -0700854 setup_dspp_prop_install_funcs(dspp_prop_install_func);
855 setup_lm_prop_install_funcs(lm_prop_install_func);
856 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700857 if (!priv->cp_property)
858 return;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700859
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700860 if (!catalog->dspp_count)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700861 goto lm_property;
862
863 /* Check for all the DSPP properties and attach it to CRTC */
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700864 features = catalog->dspp[0].features;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700865 for (i = 0; i < SDE_DSPP_MAX; i++) {
866 if (!test_bit(i, &features))
867 continue;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -0700868 if (dspp_prop_install_func[i])
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700869 dspp_prop_install_func[i](crtc);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700870 }
871
872lm_property:
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700873 if (!catalog->mixer_count)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700874 return;
875
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700876 /* Check for all the LM properties and attach it to CRTC */
877 features = catalog->mixer[0].features;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700878 for (i = 0; i < SDE_MIXER_MAX; i++) {
879 if (!test_bit(i, &features))
880 continue;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -0700881 if (lm_prop_install_func[i])
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700882 lm_prop_install_func[i](crtc);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700883 }
884}
885
886int sde_cp_crtc_set_property(struct drm_crtc *crtc,
887 struct drm_property *property,
888 uint64_t val)
889{
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700890 struct sde_cp_node *prop_node = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700891 struct sde_crtc *sde_crtc = NULL;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700892 int ret = 0, i = 0, dspp_cnt, lm_cnt;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700893 u8 found = 0;
894
895 if (!crtc || !property) {
896 DRM_ERROR("invalid crtc %pK property %pK\n", crtc, property);
897 return -EINVAL;
898 }
899
900 sde_crtc = to_sde_crtc(crtc);
901 if (!sde_crtc) {
902 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
903 return -EINVAL;
904 }
905
906 list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) {
907 if (property->base.id == prop_node->property_id) {
908 found = 1;
909 break;
910 }
911 }
912
913 if (!found)
914 return 0;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700915 /**
916 * sde_crtc is virtual ensure that hardware has been attached to the
917 * crtc. Check LM and dspp counts based on whether feature is a
918 * dspp/lm feature.
919 */
920 if (!sde_crtc->num_mixers ||
921 sde_crtc->num_mixers > ARRAY_SIZE(sde_crtc->mixers)) {
922 DRM_ERROR("Invalid mixer config act cnt %d max cnt %ld\n",
923 sde_crtc->num_mixers, ARRAY_SIZE(sde_crtc->mixers));
924 return -EINVAL;
925 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700926
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700927 dspp_cnt = 0;
928 lm_cnt = 0;
929 for (i = 0; i < sde_crtc->num_mixers; i++) {
930 if (sde_crtc->mixers[i].hw_dspp)
931 dspp_cnt++;
932 if (sde_crtc->mixers[i].hw_lm)
933 lm_cnt++;
934 }
935
936 if (prop_node->is_dspp_feature && dspp_cnt < sde_crtc->num_mixers) {
937 DRM_ERROR("invalid dspp cnt %d mixer cnt %d\n", dspp_cnt,
938 sde_crtc->num_mixers);
939 return -EINVAL;
940 } else if (lm_cnt < sde_crtc->num_mixers) {
941 DRM_ERROR("invalid lm cnt %d mixer cnt %d\n", lm_cnt,
942 sde_crtc->num_mixers);
943 return -EINVAL;
944 }
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800945
946 ret = sde_cp_ad_validate_prop(prop_node, sde_crtc);
947 if (ret) {
948 DRM_ERROR("ad property validation failed ret %d\n", ret);
949 return ret;
950 }
951
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700952 /* remove the property from dirty list */
953 list_del_init(&prop_node->dirty_list);
954
955 if (!val)
956 ret = sde_cp_disable_crtc_property(crtc, property, prop_node);
957 else
958 ret = sde_cp_enable_crtc_property(crtc, property,
959 prop_node, val);
960
961 if (!ret) {
962 /* remove the property from active list */
963 list_del_init(&prop_node->active_list);
964 /* Mark the feature as dirty */
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800965 sde_cp_update_list(prop_node, sde_crtc, true);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700966 }
967 return ret;
968}
969
970int sde_cp_crtc_get_property(struct drm_crtc *crtc,
971 struct drm_property *property, uint64_t *val)
972{
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700973 struct sde_cp_node *prop_node = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700974 struct sde_crtc *sde_crtc = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700975
976 if (!crtc || !property || !val) {
977 DRM_ERROR("invalid crtc %pK property %pK val %pK\n",
978 crtc, property, val);
979 return -EINVAL;
980 }
981
982 sde_crtc = to_sde_crtc(crtc);
983 if (!sde_crtc) {
984 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
985 return -EINVAL;
986 }
Gopikrishnaiah Anandand120b762016-10-05 12:03:42 -0700987 /* Return 0 if property is not supported */
988 *val = 0;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700989 list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) {
990 if (property->base.id == prop_node->property_id) {
991 *val = prop_node->prop_val;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700992 break;
993 }
994 }
Gopikrishnaiah Anandand120b762016-10-05 12:03:42 -0700995 return 0;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700996}
997
998void sde_cp_crtc_destroy_properties(struct drm_crtc *crtc)
999{
1000 struct sde_crtc *sde_crtc = NULL;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -07001001 struct sde_cp_node *prop_node = NULL, *n = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001002
1003 if (!crtc) {
1004 DRM_ERROR("invalid crtc %pK\n", crtc);
1005 return;
1006 }
1007
1008 sde_crtc = to_sde_crtc(crtc);
1009 if (!sde_crtc) {
1010 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
1011 return;
1012 }
1013
1014 list_for_each_entry_safe(prop_node, n, &sde_crtc->feature_list,
1015 feature_list) {
1016 if (prop_node->prop_flags & DRM_MODE_PROP_BLOB
1017 && prop_node->blob_ptr)
1018 drm_property_unreference_blob(prop_node->blob_ptr);
1019
1020 list_del_init(&prop_node->active_list);
1021 list_del_init(&prop_node->dirty_list);
1022 list_del_init(&prop_node->feature_list);
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -07001023 sde_cp_destroy_local_blob(prop_node);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001024 kfree(prop_node);
1025 }
1026
1027 INIT_LIST_HEAD(&sde_crtc->active_list);
1028 INIT_LIST_HEAD(&sde_crtc->dirty_list);
1029 INIT_LIST_HEAD(&sde_crtc->feature_list);
1030}
Gopikrishnaiah Anandan7f6ef942016-06-20 15:50:00 -07001031
1032void sde_cp_crtc_suspend(struct drm_crtc *crtc)
1033{
1034 struct sde_crtc *sde_crtc = NULL;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -07001035 struct sde_cp_node *prop_node = NULL, *n = NULL;
Gopikrishnaiah Anandan7f6ef942016-06-20 15:50:00 -07001036
1037 if (!crtc) {
1038 DRM_ERROR("crtc %pK\n", crtc);
1039 return;
1040 }
1041 sde_crtc = to_sde_crtc(crtc);
1042 if (!sde_crtc) {
1043 DRM_ERROR("sde_crtc %pK\n", sde_crtc);
1044 return;
1045 }
1046
1047 list_for_each_entry_safe(prop_node, n, &sde_crtc->active_list,
1048 active_list) {
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001049 sde_cp_update_list(prop_node, sde_crtc, true);
Gopikrishnaiah Anandan7f6ef942016-06-20 15:50:00 -07001050 list_del_init(&prop_node->active_list);
1051 }
1052}
1053
1054void sde_cp_crtc_resume(struct drm_crtc *crtc)
1055{
1056 /* placeholder for operations needed during resume */
1057}
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001058
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001059static void dspp_pcc_install_property(struct drm_crtc *crtc)
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001060{
1061 char feature_name[256];
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001062 struct sde_kms *kms = NULL;
1063 struct sde_mdss_cfg *catalog = NULL;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001064 u32 version;
1065
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001066 kms = get_kms(crtc);
1067 catalog = kms->catalog;
1068
1069 version = catalog->dspp[0].sblk->pcc.version >> 16;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001070 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1071 "SDE_DSPP_PCC_V", version);
1072 switch (version) {
1073 case 1:
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001074 sde_cp_crtc_install_blob_property(crtc, feature_name,
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -08001075 SDE_CP_CRTC_DSPP_PCC, sizeof(struct drm_msm_pcc));
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001076 break;
1077 default:
1078 DRM_ERROR("version %d not supported\n", version);
1079 break;
1080 }
1081}
1082
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001083static void dspp_hsic_install_property(struct drm_crtc *crtc)
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001084{
1085 char feature_name[256];
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001086 struct sde_kms *kms = NULL;
1087 struct sde_mdss_cfg *catalog = NULL;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001088 u32 version;
1089
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001090 kms = get_kms(crtc);
1091 catalog = kms->catalog;
1092 version = catalog->dspp[0].sblk->hsic.version >> 16;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001093 switch (version) {
1094 case 1:
1095 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1096 "SDE_DSPP_HUE_V", version);
1097 sde_cp_crtc_install_range_property(crtc, feature_name,
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001098 SDE_CP_CRTC_DSPP_HUE, 0, U32_MAX, 0);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001099 break;
1100 default:
1101 DRM_ERROR("version %d not supported\n", version);
1102 break;
1103 }
1104}
1105
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001106static void dspp_vlut_install_property(struct drm_crtc *crtc)
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001107{
1108 char feature_name[256];
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001109 struct sde_kms *kms = NULL;
1110 struct sde_mdss_cfg *catalog = NULL;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001111 u32 version;
1112
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001113 kms = get_kms(crtc);
1114 catalog = kms->catalog;
1115 version = catalog->dspp[0].sblk->vlut.version >> 16;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001116 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1117 "SDE_DSPP_VLUT_V", version);
1118 switch (version) {
1119 case 1:
1120 sde_cp_crtc_install_range_property(crtc, feature_name,
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001121 SDE_CP_CRTC_DSPP_VLUT, 0, U64_MAX, 0);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001122 sde_cp_create_local_blob(crtc,
1123 SDE_CP_CRTC_DSPP_VLUT,
1124 sizeof(struct drm_msm_pa_vlut));
1125 break;
1126 default:
1127 DRM_ERROR("version %d not supported\n", version);
1128 break;
1129 }
1130}
1131
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001132static void dspp_ad_install_property(struct drm_crtc *crtc)
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001133{
1134 char feature_name[256];
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001135 struct sde_kms *kms = NULL;
1136 struct sde_mdss_cfg *catalog = NULL;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001137 u32 version;
1138
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001139 kms = get_kms(crtc);
1140 catalog = kms->catalog;
1141 version = catalog->dspp[0].sblk->ad.version >> 16;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001142 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1143 "SDE_DSPP_AD_V", version);
1144 switch (version) {
1145 case 3:
1146 sde_cp_crtc_install_immutable_property(crtc,
1147 feature_name, SDE_CP_CRTC_DSPP_AD);
1148 break;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001149 case 4:
1150 sde_cp_crtc_install_immutable_property(crtc,
1151 feature_name, SDE_CP_CRTC_DSPP_AD);
1152
1153 sde_cp_crtc_install_enum_property(crtc,
1154 SDE_CP_CRTC_DSPP_AD_MODE, ad4_modes,
1155 ARRAY_SIZE(ad4_modes), "SDE_DSPP_AD_V4_MODE");
1156
1157 sde_cp_crtc_install_range_property(crtc, "SDE_DSPP_AD_V4_INIT",
1158 SDE_CP_CRTC_DSPP_AD_INIT, 0, U64_MAX, 0);
1159 sde_cp_create_local_blob(crtc, SDE_CP_CRTC_DSPP_AD_INIT,
1160 sizeof(struct drm_msm_ad4_init));
1161
1162 sde_cp_crtc_install_range_property(crtc, "SDE_DSPP_AD_V4_CFG",
1163 SDE_CP_CRTC_DSPP_AD_CFG, 0, U64_MAX, 0);
1164 sde_cp_create_local_blob(crtc, SDE_CP_CRTC_DSPP_AD_CFG,
1165 sizeof(struct drm_msm_ad4_cfg));
1166 sde_cp_crtc_install_range_property(crtc,
1167 "SDE_DSPP_AD_V4_ASSERTIVNESS",
1168 SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS, 0, (BIT(8) - 1), 0);
1169 sde_cp_crtc_install_range_property(crtc, "SDE_DSPP_AD_V4_INPUT",
1170 SDE_CP_CRTC_DSPP_AD_INPUT, 0, U16_MAX, 0);
1171 sde_cp_crtc_install_range_property(crtc,
1172 "SDE_DSPP_AD_V4_BACKLIGHT",
1173 SDE_CP_CRTC_DSPP_AD_BACKLIGHT, 0, (BIT(16) - 1),
1174 0);
1175 break;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001176 default:
1177 DRM_ERROR("version %d not supported\n", version);
1178 break;
1179 }
1180}
1181
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001182static void lm_gc_install_property(struct drm_crtc *crtc)
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001183{
1184 char feature_name[256];
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001185 struct sde_kms *kms = NULL;
1186 struct sde_mdss_cfg *catalog = NULL;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001187 u32 version;
1188
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001189 kms = get_kms(crtc);
1190 catalog = kms->catalog;
1191 version = catalog->mixer[0].sblk->gc.version >> 16;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001192 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1193 "SDE_LM_GC_V", version);
1194 switch (version) {
1195 case 1:
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001196 sde_cp_crtc_install_blob_property(crtc, feature_name,
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -08001197 SDE_CP_CRTC_LM_GC, sizeof(struct drm_msm_pgc_lut));
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001198 break;
1199 default:
1200 DRM_ERROR("version %d not supported\n", version);
1201 break;
1202 }
1203}
Gopikrishnaiah Anandanfbf75392017-01-16 10:43:36 -08001204
1205static void dspp_gamut_install_property(struct drm_crtc *crtc)
1206{
1207 char feature_name[256];
1208 struct sde_kms *kms = NULL;
1209 struct sde_mdss_cfg *catalog = NULL;
1210 u32 version;
1211
1212 kms = get_kms(crtc);
1213 catalog = kms->catalog;
1214
1215 version = catalog->dspp[0].sblk->gamut.version >> 16;
1216 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1217 "SDE_DSPP_GAMUT_V", version);
1218 switch (version) {
1219 case 4:
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001220 sde_cp_crtc_install_blob_property(crtc, feature_name,
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -08001221 SDE_CP_CRTC_DSPP_GAMUT,
1222 sizeof(struct drm_msm_3d_gamut));
Gopikrishnaiah Anandanfbf75392017-01-16 10:43:36 -08001223 break;
1224 default:
1225 DRM_ERROR("version %d not supported\n", version);
1226 break;
1227 }
1228}
1229
1230static void dspp_gc_install_property(struct drm_crtc *crtc)
1231{
1232 char feature_name[256];
1233 struct sde_kms *kms = NULL;
1234 struct sde_mdss_cfg *catalog = NULL;
1235 u32 version;
1236
1237 kms = get_kms(crtc);
1238 catalog = kms->catalog;
1239
1240 version = catalog->dspp[0].sblk->gc.version >> 16;
1241 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1242 "SDE_DSPP_GC_V", version);
1243 switch (version) {
1244 case 1:
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001245 sde_cp_crtc_install_blob_property(crtc, feature_name,
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -08001246 SDE_CP_CRTC_DSPP_GC, sizeof(struct drm_msm_pgc_lut));
Gopikrishnaiah Anandanfbf75392017-01-16 10:43:36 -08001247 break;
1248 default:
1249 DRM_ERROR("version %d not supported\n", version);
1250 break;
1251 }
1252}
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001253
1254static void sde_cp_update_list(struct sde_cp_node *prop_node,
1255 struct sde_crtc *crtc, bool dirty_list)
1256{
1257 switch (prop_node->feature) {
1258 case SDE_CP_CRTC_DSPP_AD_MODE:
1259 case SDE_CP_CRTC_DSPP_AD_INIT:
1260 case SDE_CP_CRTC_DSPP_AD_CFG:
1261 case SDE_CP_CRTC_DSPP_AD_INPUT:
1262 case SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS:
1263 case SDE_CP_CRTC_DSPP_AD_BACKLIGHT:
1264 if (dirty_list)
1265 list_add_tail(&prop_node->dirty_list, &crtc->ad_dirty);
1266 else
1267 list_add_tail(&prop_node->active_list,
1268 &crtc->ad_active);
1269 break;
1270 default:
1271 /* color processing properties handle here */
1272 if (dirty_list)
1273 list_add_tail(&prop_node->dirty_list,
1274 &crtc->dirty_list);
1275 else
1276 list_add_tail(&prop_node->active_list,
1277 &crtc->active_list);
1278 break;
1279 };
1280}
1281
1282static int sde_cp_ad_validate_prop(struct sde_cp_node *prop_node,
1283 struct sde_crtc *crtc)
1284{
1285 int i = 0, ret = 0;
1286 u32 ad_prop;
1287
1288 for (i = 0; i < crtc->num_mixers && !ret; i++) {
1289 if (!crtc->mixers[i].hw_dspp) {
1290 ret = -EINVAL;
1291 continue;
1292 }
1293 switch (prop_node->feature) {
1294 case SDE_CP_CRTC_DSPP_AD_MODE:
1295 ad_prop = AD_MODE;
1296 break;
1297 case SDE_CP_CRTC_DSPP_AD_INIT:
1298 ad_prop = AD_INIT;
1299 break;
1300 case SDE_CP_CRTC_DSPP_AD_CFG:
1301 ad_prop = AD_CFG;
1302 break;
1303 case SDE_CP_CRTC_DSPP_AD_INPUT:
1304 ad_prop = AD_INPUT;
1305 break;
1306 case SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS:
1307 ad_prop = AD_ASSERTIVE;
1308 break;
1309 case SDE_CP_CRTC_DSPP_AD_BACKLIGHT:
1310 ad_prop = AD_BACKLIGHT;
1311 break;
1312 default:
1313 /* Not an AD property */
1314 return 0;
1315 }
1316 if (!crtc->mixers[i].hw_dspp->ops.validate_ad)
1317 ret = -EINVAL;
1318 else
1319 ret = crtc->mixers[i].hw_dspp->ops.validate_ad(
1320 crtc->mixers[i].hw_dspp, &ad_prop);
1321 }
1322 return ret;
1323}
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001324
1325static void sde_cp_ad_interrupt_cb(void *arg, int irq_idx)
1326{
1327 struct sde_crtc *crtc = arg;
Gopikrishnaiah Anandanb6b401f2017-03-14 16:39:49 -07001328
1329 sde_crtc_event_queue(&crtc->base, sde_cp_notify_ad_event, NULL);
1330}
1331
1332static void sde_cp_notify_ad_event(struct drm_crtc *crtc_drm, void *arg)
1333{
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001334 uint32_t bl = 0;
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001335 struct sde_hw_mixer *hw_lm = NULL;
1336 struct sde_hw_dspp *hw_dspp = NULL;
Gopikrishnaiah Anandanb6b401f2017-03-14 16:39:49 -07001337 u32 num_mixers;
1338 struct sde_crtc *crtc;
1339 struct drm_event event;
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001340 int i;
1341
Gopikrishnaiah Anandanb6b401f2017-03-14 16:39:49 -07001342 crtc = to_sde_crtc(crtc_drm);
1343 num_mixers = crtc->num_mixers;
1344 if (!num_mixers)
1345 return;
1346
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001347 for (i = 0; i < num_mixers; i++) {
1348 hw_lm = crtc->mixers[i].hw_lm;
1349 hw_dspp = crtc->mixers[i].hw_dspp;
1350 if (!hw_lm->cfg.right_mixer)
1351 break;
1352 }
1353
1354 if (!hw_dspp)
1355 return;
1356
1357 hw_dspp->ops.ad_read_intr_resp(hw_dspp, AD4_BACKLIGHT, &bl);
Gopikrishnaiah Anandanb6b401f2017-03-14 16:39:49 -07001358 event.length = sizeof(u32);
1359 event.type = DRM_EVENT_AD_BACKLIGHT;
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001360 msm_send_crtc_notification(&crtc->base, &event, (u8 *)&bl);
1361}
1362
1363int sde_cp_ad_interrupt(struct drm_crtc *crtc_drm, bool en,
1364 struct sde_irq_callback *ad_irq)
1365{
1366 struct sde_kms *kms = NULL;
1367 u32 num_mixers;
1368 struct sde_hw_mixer *hw_lm;
1369 struct sde_hw_dspp *hw_dspp = NULL;
1370 struct sde_crtc *crtc;
1371 int i;
1372 int irq_idx, ret;
1373 struct sde_cp_node prop_node;
1374
1375 if (!crtc_drm || !ad_irq) {
1376 DRM_ERROR("invalid crtc %pK irq %pK\n", crtc_drm, ad_irq);
1377 return -EINVAL;
1378 }
1379
1380 crtc = to_sde_crtc(crtc_drm);
1381 if (!crtc) {
1382 DRM_ERROR("invalid sde_crtc %pK\n", crtc);
1383 return -EINVAL;
1384 }
1385
1386 mutex_lock(&crtc->crtc_lock);
1387 kms = get_kms(crtc_drm);
1388 num_mixers = crtc->num_mixers;
1389
1390 memset(&prop_node, 0, sizeof(prop_node));
1391 prop_node.feature = SDE_CP_CRTC_DSPP_AD_BACKLIGHT;
1392 ret = sde_cp_ad_validate_prop(&prop_node, crtc);
1393 if (ret) {
1394 DRM_ERROR("Ad not supported ret %d\n", ret);
1395 goto exit;
1396 }
1397
1398 for (i = 0; i < num_mixers; i++) {
1399 hw_lm = crtc->mixers[i].hw_lm;
1400 hw_dspp = crtc->mixers[i].hw_dspp;
1401 if (!hw_lm->cfg.right_mixer)
1402 break;
1403 }
1404
1405 if (!hw_dspp) {
1406 DRM_ERROR("invalid dspp\n");
1407 ret = -EINVAL;
1408 goto exit;
1409 }
1410
1411 irq_idx = sde_core_irq_idx_lookup(kms, SDE_IRQ_TYPE_AD4_BL_DONE,
1412 hw_dspp->idx);
1413 if (irq_idx < 0) {
1414 DRM_ERROR("failed to get the irq idx ret %d\n", irq_idx);
1415 ret = irq_idx;
1416 goto exit;
1417 }
1418
1419 if (!en) {
1420 sde_core_irq_disable(kms, &irq_idx, 1);
1421 sde_core_irq_unregister_callback(kms, irq_idx, ad_irq);
1422 ret = 0;
1423 goto exit;
1424 }
1425
1426 INIT_LIST_HEAD(&ad_irq->list);
1427 ad_irq->arg = crtc;
1428 ad_irq->func = sde_cp_ad_interrupt_cb;
1429 ret = sde_core_irq_register_callback(kms, irq_idx, ad_irq);
1430 if (ret) {
1431 DRM_ERROR("failed to register the callback ret %d\n", ret);
1432 goto exit;
1433 }
1434 ret = sde_core_irq_enable(kms, &irq_idx, 1);
1435 if (ret) {
1436 DRM_ERROR("failed to enable irq ret %d\n", ret);
1437 sde_core_irq_unregister_callback(kms, irq_idx, ad_irq);
1438 }
1439exit:
1440 mutex_unlock(&crtc->crtc_lock);
1441 return ret;
1442}