blob: 8de4510129432d88d4a96ec87c3c867c5a69db70 [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
Rajesh Yadavec93afb2017-06-08 19:28:33 +053063static void dspp_igc_install_property(struct drm_crtc *crtc);
64
Xu Yang056d39b2017-07-11 16:34:13 +080065static void dspp_hist_install_property(struct drm_crtc *crtc);
66
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -070067typedef void (*dspp_prop_install_func_t)(struct drm_crtc *crtc);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070068
69static dspp_prop_install_func_t dspp_prop_install_func[SDE_DSPP_MAX];
70
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -080071static void sde_cp_update_list(struct sde_cp_node *prop_node,
72 struct sde_crtc *crtc, bool dirty_list);
73
74static int sde_cp_ad_validate_prop(struct sde_cp_node *prop_node,
75 struct sde_crtc *crtc);
76
Gopikrishnaiah Anandanb6b401f2017-03-14 16:39:49 -070077static void sde_cp_notify_ad_event(struct drm_crtc *crtc_drm, void *arg);
78
Ping Lie505f3b2017-06-19 14:19:08 -070079static void sde_cp_ad_set_prop(struct sde_crtc *sde_crtc,
80 enum ad_property ad_prop);
81
Xu Yang5e53c2e2017-07-11 16:46:28 +080082static void sde_cp_notify_hist_event(struct drm_crtc *crtc_drm, void *arg);
83
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070084#define setup_dspp_prop_install_funcs(func) \
85do { \
86 func[SDE_DSPP_PCC] = dspp_pcc_install_property; \
87 func[SDE_DSPP_HSIC] = dspp_hsic_install_property; \
88 func[SDE_DSPP_AD] = dspp_ad_install_property; \
89 func[SDE_DSPP_VLUT] = dspp_vlut_install_property; \
Gopikrishnaiah Anandanfbf75392017-01-16 10:43:36 -080090 func[SDE_DSPP_GAMUT] = dspp_gamut_install_property; \
91 func[SDE_DSPP_GC] = dspp_gc_install_property; \
Rajesh Yadavec93afb2017-06-08 19:28:33 +053092 func[SDE_DSPP_IGC] = dspp_igc_install_property; \
Xu Yang056d39b2017-07-11 16:34:13 +080093 func[SDE_DSPP_HIST] = dspp_hist_install_property; \
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070094} while (0)
95
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -070096typedef void (*lm_prop_install_func_t)(struct drm_crtc *crtc);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070097
98static lm_prop_install_func_t lm_prop_install_func[SDE_MIXER_MAX];
99
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700100static void lm_gc_install_property(struct drm_crtc *crtc);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -0700101
102#define setup_lm_prop_install_funcs(func) \
103 (func[SDE_MIXER_GC] = lm_gc_install_property)
104
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700105enum {
106 /* Append new DSPP features before SDE_CP_CRTC_DSPP_MAX */
107 /* DSPP Features start */
108 SDE_CP_CRTC_DSPP_IGC,
109 SDE_CP_CRTC_DSPP_PCC,
110 SDE_CP_CRTC_DSPP_GC,
111 SDE_CP_CRTC_DSPP_HUE,
112 SDE_CP_CRTC_DSPP_SAT,
113 SDE_CP_CRTC_DSPP_VAL,
114 SDE_CP_CRTC_DSPP_CONT,
115 SDE_CP_CRTC_DSPP_MEMCOLOR,
116 SDE_CP_CRTC_DSPP_SIXZONE,
117 SDE_CP_CRTC_DSPP_GAMUT,
118 SDE_CP_CRTC_DSPP_DITHER,
Xu Yang056d39b2017-07-11 16:34:13 +0800119 SDE_CP_CRTC_DSPP_HIST_CTRL,
120 SDE_CP_CRTC_DSPP_HIST_IRQ,
Gopikrishnaiah Anandan41980b42016-06-21 16:01:33 -0700121 SDE_CP_CRTC_DSPP_AD,
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700122 SDE_CP_CRTC_DSPP_VLUT,
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800123 SDE_CP_CRTC_DSPP_AD_MODE,
124 SDE_CP_CRTC_DSPP_AD_INIT,
125 SDE_CP_CRTC_DSPP_AD_CFG,
126 SDE_CP_CRTC_DSPP_AD_INPUT,
127 SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS,
128 SDE_CP_CRTC_DSPP_AD_BACKLIGHT,
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700129 SDE_CP_CRTC_DSPP_MAX,
130 /* DSPP features end */
131
132 /* Append new LM features before SDE_CP_CRTC_MAX_FEATURES */
133 /* LM feature start*/
134 SDE_CP_CRTC_LM_GC,
135 /* LM feature end*/
136
137 SDE_CP_CRTC_MAX_FEATURES,
138};
139
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700140#define INIT_PROP_ATTACH(p, crtc, prop, node, feature, val) \
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700141 do { \
142 (p)->crtc = crtc; \
143 (p)->prop = prop; \
144 (p)->prop_node = node; \
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700145 (p)->feature = feature; \
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700146 (p)->val = val; \
147 } while (0)
148
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700149static void sde_cp_get_hw_payload(struct sde_cp_node *prop_node,
150 struct sde_hw_cp_cfg *hw_cfg,
151 bool *feature_enabled)
152{
153
154 struct drm_property_blob *blob = NULL;
155
156 memset(hw_cfg, 0, sizeof(*hw_cfg));
157 *feature_enabled = false;
158
159 blob = prop_node->blob_ptr;
160 if (prop_node->prop_flags & DRM_MODE_PROP_BLOB) {
161 if (blob) {
162 hw_cfg->len = blob->length;
163 hw_cfg->payload = blob->data;
164 *feature_enabled = true;
165 }
166 } else if (prop_node->prop_flags & DRM_MODE_PROP_RANGE) {
167 /* Check if local blob is Set */
168 if (!blob) {
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800169 if (prop_node->prop_val) {
170 hw_cfg->len = sizeof(prop_node->prop_val);
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700171 hw_cfg->payload = &prop_node->prop_val;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800172 }
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700173 } else {
174 hw_cfg->len = (prop_node->prop_val) ? blob->length :
175 0;
176 hw_cfg->payload = (prop_node->prop_val) ? blob->data
177 : NULL;
178 }
179 if (prop_node->prop_val)
180 *feature_enabled = true;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800181 } else if (prop_node->prop_flags & DRM_MODE_PROP_ENUM) {
182 *feature_enabled = (prop_node->prop_val != 0);
183 hw_cfg->len = sizeof(prop_node->prop_val);
184 hw_cfg->payload = &prop_node->prop_val;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700185 } else {
186 DRM_ERROR("property type is not supported\n");
187 }
188}
189
190static int sde_cp_disable_crtc_blob_property(struct sde_cp_node *prop_node)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700191{
192 struct drm_property_blob *blob = prop_node->blob_ptr;
193
194 if (!blob)
Gopikrishnaiah Anandan8b1498a2017-05-10 16:58:04 -0700195 return 0;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700196 drm_property_unreference_blob(blob);
197 prop_node->blob_ptr = NULL;
198 return 0;
199}
200
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700201static int sde_cp_create_local_blob(struct drm_crtc *crtc, u32 feature, int len)
202{
203 int ret = -EINVAL;
204 bool found = false;
205 struct sde_cp_node *prop_node = NULL;
206 struct drm_property_blob *blob_ptr;
207 struct sde_crtc *sde_crtc = to_sde_crtc(crtc);
208
209 list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) {
210 if (prop_node->feature == feature) {
211 found = true;
212 break;
213 }
214 }
215
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800216 if (!found || !(prop_node->prop_flags & DRM_MODE_PROP_RANGE)) {
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700217 DRM_ERROR("local blob create failed prop found %d flags %d\n",
218 found, prop_node->prop_flags);
219 return ret;
220 }
221
222 blob_ptr = drm_property_create_blob(crtc->dev, len, NULL);
223 ret = (IS_ERR_OR_NULL(blob_ptr)) ? PTR_ERR(blob_ptr) : 0;
224 if (!ret)
225 prop_node->blob_ptr = blob_ptr;
226
227 return ret;
228}
229
230static void sde_cp_destroy_local_blob(struct sde_cp_node *prop_node)
231{
232 if (!(prop_node->prop_flags & DRM_MODE_PROP_BLOB) &&
233 prop_node->blob_ptr)
234 drm_property_unreference_blob(prop_node->blob_ptr);
235}
236
237static int sde_cp_handle_range_property(struct sde_cp_node *prop_node,
238 uint64_t val)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700239{
240 int ret = 0;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700241 struct drm_property_blob *blob_ptr = prop_node->blob_ptr;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700242
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700243 if (!blob_ptr) {
244 prop_node->prop_val = val;
245 return 0;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700246 }
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700247
248 if (!val) {
249 prop_node->prop_val = 0;
250 return 0;
251 }
252
253 ret = copy_from_user(blob_ptr->data, (void *)val, blob_ptr->length);
254 if (ret) {
255 DRM_ERROR("failed to get the property info ret %d", ret);
256 ret = -EFAULT;
257 } else {
258 prop_node->prop_val = val;
259 }
260
261 return ret;
262}
263
264static int sde_cp_disable_crtc_property(struct drm_crtc *crtc,
265 struct drm_property *property,
266 struct sde_cp_node *prop_node)
267{
268 int ret = -EINVAL;
269
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800270 if (property->flags & DRM_MODE_PROP_BLOB) {
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700271 ret = sde_cp_disable_crtc_blob_property(prop_node);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800272 } else if (property->flags & DRM_MODE_PROP_RANGE) {
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700273 ret = sde_cp_handle_range_property(prop_node, 0);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800274 } else if (property->flags & DRM_MODE_PROP_ENUM) {
275 ret = 0;
276 prop_node->prop_val = 0;
277 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700278 return ret;
279}
280
281static int sde_cp_enable_crtc_blob_property(struct drm_crtc *crtc,
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700282 struct sde_cp_node *prop_node,
283 uint64_t val)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700284{
285 struct drm_property_blob *blob = NULL;
286
287 /**
288 * For non-blob based properties add support to create a blob
289 * using the val and store the blob_ptr in prop_node.
290 */
291 blob = drm_property_lookup_blob(crtc->dev, val);
292 if (!blob) {
293 DRM_ERROR("invalid blob id %lld\n", val);
294 return -EINVAL;
295 }
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -0800296 if (blob->length != prop_node->prop_blob_sz) {
297 DRM_ERROR("invalid blob len %zd exp %d feature %d\n",
298 blob->length, prop_node->prop_blob_sz, prop_node->feature);
299 drm_property_unreference_blob(blob);
300 return -EINVAL;
301 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700302 /* Release refernce to existing payload of the property */
303 if (prop_node->blob_ptr)
304 drm_property_unreference_blob(prop_node->blob_ptr);
305
306 prop_node->blob_ptr = blob;
307 return 0;
308}
309
310static int sde_cp_enable_crtc_property(struct drm_crtc *crtc,
311 struct drm_property *property,
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700312 struct sde_cp_node *prop_node,
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700313 uint64_t val)
314{
315 int ret = -EINVAL;
316
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800317 if (property->flags & DRM_MODE_PROP_BLOB) {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700318 ret = sde_cp_enable_crtc_blob_property(crtc, prop_node, val);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800319 } else if (property->flags & DRM_MODE_PROP_RANGE) {
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700320 ret = sde_cp_handle_range_property(prop_node, val);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800321 } else if (property->flags & DRM_MODE_PROP_ENUM) {
322 ret = 0;
323 prop_node->prop_val = val;
324 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700325 return ret;
326}
327
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700328static struct sde_kms *get_kms(struct drm_crtc *crtc)
329{
330 struct msm_drm_private *priv = crtc->dev->dev_private;
331
332 return to_sde_kms(priv->kms);
333}
334
335static void sde_cp_crtc_prop_attach(struct sde_cp_prop_attach *prop_attach)
336{
337
338 struct sde_crtc *sde_crtc = to_sde_crtc(prop_attach->crtc);
339
340 drm_object_attach_property(&prop_attach->crtc->base,
341 prop_attach->prop, prop_attach->val);
342
343 INIT_LIST_HEAD(&prop_attach->prop_node->active_list);
344 INIT_LIST_HEAD(&prop_attach->prop_node->dirty_list);
345
346 prop_attach->prop_node->property_id = prop_attach->prop->base.id;
347 prop_attach->prop_node->prop_flags = prop_attach->prop->flags;
348 prop_attach->prop_node->feature = prop_attach->feature;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700349
350 if (prop_attach->feature < SDE_CP_CRTC_DSPP_MAX)
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700351 prop_attach->prop_node->is_dspp_feature = true;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700352 else
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700353 prop_attach->prop_node->is_dspp_feature = false;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700354
355 list_add(&prop_attach->prop_node->feature_list,
356 &sde_crtc->feature_list);
357}
358
359void sde_cp_crtc_init(struct drm_crtc *crtc)
360{
361 struct sde_crtc *sde_crtc = NULL;
362
363 if (!crtc) {
364 DRM_ERROR("invalid crtc %pK\n", crtc);
365 return;
366 }
367
368 sde_crtc = to_sde_crtc(crtc);
369 if (!sde_crtc) {
370 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
371 return;
372 }
373
Xu Yang5e53c2e2017-07-11 16:46:28 +0800374 /* create blob to store histogram data */
375 sde_crtc->hist_blob = drm_property_create_blob(crtc->dev,
376 sizeof(struct drm_msm_hist), NULL);
377 if (IS_ERR(sde_crtc->hist_blob))
378 sde_crtc->hist_blob = NULL;
379
Xu Yang1b3a5d92017-09-13 11:37:54 +0800380 mutex_init(&sde_crtc->crtc_cp_lock);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700381 INIT_LIST_HEAD(&sde_crtc->active_list);
382 INIT_LIST_HEAD(&sde_crtc->dirty_list);
383 INIT_LIST_HEAD(&sde_crtc->feature_list);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800384 INIT_LIST_HEAD(&sde_crtc->ad_dirty);
385 INIT_LIST_HEAD(&sde_crtc->ad_active);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700386}
387
Gopikrishnaiah Anandan41980b42016-06-21 16:01:33 -0700388static void sde_cp_crtc_install_immutable_property(struct drm_crtc *crtc,
389 char *name,
390 u32 feature)
391{
392 struct drm_property *prop;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700393 struct sde_cp_node *prop_node = NULL;
Gopikrishnaiah Anandan41980b42016-06-21 16:01:33 -0700394 struct msm_drm_private *priv;
395 struct sde_cp_prop_attach prop_attach;
396 uint64_t val = 0;
397
398 if (feature >= SDE_CP_CRTC_MAX_FEATURES) {
399 DRM_ERROR("invalid feature %d max %d\n", feature,
400 SDE_CP_CRTC_MAX_FEATURES);
401 return;
402 }
403
404 prop_node = kzalloc(sizeof(*prop_node), GFP_KERNEL);
405 if (!prop_node)
406 return;
407
408 priv = crtc->dev->dev_private;
409 prop = priv->cp_property[feature];
410
411 if (!prop) {
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800412 prop = drm_property_create_range(crtc->dev,
413 DRM_MODE_PROP_IMMUTABLE, name, 0, 1);
Gopikrishnaiah Anandan41980b42016-06-21 16:01:33 -0700414 if (!prop) {
415 DRM_ERROR("property create failed: %s\n", name);
416 kfree(prop_node);
417 return;
418 }
419 priv->cp_property[feature] = prop;
420 }
421
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700422 INIT_PROP_ATTACH(&prop_attach, crtc, prop, prop_node,
423 feature, val);
Gopikrishnaiah Anandan41980b42016-06-21 16:01:33 -0700424 sde_cp_crtc_prop_attach(&prop_attach);
425}
426
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700427static void sde_cp_crtc_install_range_property(struct drm_crtc *crtc,
428 char *name,
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700429 u32 feature,
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700430 uint64_t min, uint64_t max,
431 uint64_t val)
432{
433 struct drm_property *prop;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700434 struct sde_cp_node *prop_node = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700435 struct msm_drm_private *priv;
436 struct sde_cp_prop_attach prop_attach;
437
438 if (feature >= SDE_CP_CRTC_MAX_FEATURES) {
439 DRM_ERROR("invalid feature %d max %d\n", feature,
440 SDE_CP_CRTC_MAX_FEATURES);
441 return;
442 }
443
444 prop_node = kzalloc(sizeof(*prop_node), GFP_KERNEL);
445 if (!prop_node)
446 return;
447
448 priv = crtc->dev->dev_private;
449 prop = priv->cp_property[feature];
450
451 if (!prop) {
452 prop = drm_property_create_range(crtc->dev, 0, name, min, max);
453 if (!prop) {
454 DRM_ERROR("property create failed: %s\n", name);
455 kfree(prop_node);
456 return;
457 }
458 priv->cp_property[feature] = prop;
459 }
460
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700461 INIT_PROP_ATTACH(&prop_attach, crtc, prop, prop_node,
462 feature, val);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700463
464 sde_cp_crtc_prop_attach(&prop_attach);
465}
466
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800467static void sde_cp_crtc_install_blob_property(struct drm_crtc *crtc, char *name,
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -0800468 u32 feature, u32 blob_sz)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700469{
470 struct drm_property *prop;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700471 struct sde_cp_node *prop_node = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700472 struct msm_drm_private *priv;
473 uint64_t val = 0;
474 struct sde_cp_prop_attach prop_attach;
475
476 if (feature >= SDE_CP_CRTC_MAX_FEATURES) {
477 DRM_ERROR("invalid feature %d max %d\n", feature,
478 SDE_CP_CRTC_MAX_FEATURES);
479 return;
480 }
481
482 prop_node = kzalloc(sizeof(*prop_node), GFP_KERNEL);
483 if (!prop_node)
484 return;
485
486 priv = crtc->dev->dev_private;
487 prop = priv->cp_property[feature];
488
489 if (!prop) {
490 prop = drm_property_create(crtc->dev,
491 DRM_MODE_PROP_BLOB, name, 0);
492 if (!prop) {
493 DRM_ERROR("property create failed: %s\n", name);
494 kfree(prop_node);
495 return;
496 }
497 priv->cp_property[feature] = prop;
498 }
499
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700500 INIT_PROP_ATTACH(&prop_attach, crtc, prop, prop_node,
501 feature, val);
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -0800502 prop_node->prop_blob_sz = blob_sz;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700503
504 sde_cp_crtc_prop_attach(&prop_attach);
505}
506
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800507static void sde_cp_crtc_install_enum_property(struct drm_crtc *crtc,
508 u32 feature, const struct drm_prop_enum_list *list, u32 enum_sz,
509 char *name)
510{
511 struct drm_property *prop;
512 struct sde_cp_node *prop_node = NULL;
513 struct msm_drm_private *priv;
514 uint64_t val = 0;
515 struct sde_cp_prop_attach prop_attach;
516
517 if (feature >= SDE_CP_CRTC_MAX_FEATURES) {
518 DRM_ERROR("invalid feature %d max %d\n", feature,
519 SDE_CP_CRTC_MAX_FEATURES);
520 return;
521 }
522
523 prop_node = kzalloc(sizeof(*prop_node), GFP_KERNEL);
524 if (!prop_node)
525 return;
526
527 priv = crtc->dev->dev_private;
528 prop = priv->cp_property[feature];
529
530 if (!prop) {
531 prop = drm_property_create_enum(crtc->dev, 0, name,
532 list, enum_sz);
533 if (!prop) {
534 DRM_ERROR("property create failed: %s\n", name);
535 kfree(prop_node);
536 return;
537 }
538 priv->cp_property[feature] = prop;
539 }
540
541 INIT_PROP_ATTACH(&prop_attach, crtc, prop, prop_node,
542 feature, val);
543
544 sde_cp_crtc_prop_attach(&prop_attach);
545}
546
Xu Yang5e53c2e2017-07-11 16:46:28 +0800547static struct sde_crtc_irq_info *_sde_cp_get_intr_node(u32 event,
548 struct sde_crtc *sde_crtc)
549{
550 bool found = false;
551 struct sde_crtc_irq_info *node = NULL;
552
553 list_for_each_entry(node, &sde_crtc->user_event_list, list) {
554 if (node->event == event) {
555 found = true;
556 break;
557 }
558 }
559
560 if (!found)
561 node = NULL;
562
563 return node;
564}
565
Xu Yang056d39b2017-07-11 16:34:13 +0800566static void _sde_cp_crtc_enable_hist_irq(struct sde_crtc *sde_crtc)
567{
568 struct drm_crtc *crtc_drm = &sde_crtc->base;
569 struct sde_kms *kms = NULL;
570 struct sde_hw_mixer *hw_lm;
571 struct sde_hw_dspp *hw_dspp = NULL;
Xu Yang5e53c2e2017-07-11 16:46:28 +0800572 struct sde_crtc_irq_info *node = NULL;
573 int i, irq_idx, ret = 0;
574 unsigned long flags;
Xu Yang056d39b2017-07-11 16:34:13 +0800575
576 if (!crtc_drm) {
577 DRM_ERROR("invalid crtc %pK\n", crtc_drm);
578 return;
579 }
580
581 kms = get_kms(crtc_drm);
582
583 for (i = 0; i < sde_crtc->num_mixers; i++) {
584 hw_lm = sde_crtc->mixers[i].hw_lm;
585 hw_dspp = sde_crtc->mixers[i].hw_dspp;
586 if (!hw_lm->cfg.right_mixer)
587 break;
588 }
589
590 if (!hw_dspp) {
591 DRM_ERROR("invalid dspp\n");
592 return;
593 }
594
595 irq_idx = sde_core_irq_idx_lookup(kms, SDE_IRQ_TYPE_HIST_DSPP_DONE,
596 hw_dspp->idx);
597 if (irq_idx < 0) {
598 DRM_ERROR("failed to get irq idx\n");
599 return;
600 }
Xu Yang5e53c2e2017-07-11 16:46:28 +0800601
602 spin_lock_irqsave(&sde_crtc->spin_lock, flags);
603 node = _sde_cp_get_intr_node(DRM_EVENT_HISTOGRAM, sde_crtc);
604 spin_unlock_irqrestore(&sde_crtc->spin_lock, flags);
605
606 if (!node)
607 return;
608
609 if (node->state == IRQ_DISABLED) {
610 ret = sde_core_irq_enable(kms, &irq_idx, 1);
611 if (ret)
612 DRM_ERROR("failed to enable irq %d\n", irq_idx);
613 else
614 node->state = IRQ_ENABLED;
615 }
Xu Yang056d39b2017-07-11 16:34:13 +0800616}
617
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700618static void sde_cp_crtc_setfeature(struct sde_cp_node *prop_node,
Gopikrishnaiah Anandandb90fa12017-05-09 17:56:08 -0700619 struct sde_crtc *sde_crtc)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700620{
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700621 struct sde_hw_cp_cfg hw_cfg;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700622 struct sde_hw_mixer *hw_lm;
623 struct sde_hw_dspp *hw_dspp;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700624 u32 num_mixers = sde_crtc->num_mixers;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700625 int i = 0;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700626 bool feature_enabled = false;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700627 int ret = 0;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800628 struct sde_ad_hw_cfg ad_cfg;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700629
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700630 sde_cp_get_hw_payload(prop_node, &hw_cfg, &feature_enabled);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800631 hw_cfg.num_of_mixers = sde_crtc->num_mixers;
632 hw_cfg.displayh = sde_crtc->base.mode.hdisplay;
633 hw_cfg.displayv = sde_crtc->base.mode.vdisplay;
Gopikrishnaiah Anandandb90fa12017-05-09 17:56:08 -0700634 hw_cfg.last_feature = 0;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700635
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700636 for (i = 0; i < num_mixers && !ret; i++) {
637 hw_lm = sde_crtc->mixers[i].hw_lm;
638 hw_dspp = sde_crtc->mixers[i].hw_dspp;
Gopikrishnaiah Anandanfbf75392017-01-16 10:43:36 -0800639 hw_cfg.ctl = sde_crtc->mixers[i].hw_ctl;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800640 hw_cfg.mixer_info = hw_lm;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700641 switch (prop_node->feature) {
642 case SDE_CP_CRTC_DSPP_VLUT:
643 if (!hw_dspp || !hw_dspp->ops.setup_vlut) {
644 ret = -EINVAL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700645 continue;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700646 }
647 hw_dspp->ops.setup_vlut(hw_dspp, &hw_cfg);
648 break;
649 case SDE_CP_CRTC_DSPP_PCC:
650 if (!hw_dspp || !hw_dspp->ops.setup_pcc) {
651 ret = -EINVAL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700652 continue;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700653 }
654 hw_dspp->ops.setup_pcc(hw_dspp, &hw_cfg);
655 break;
656 case SDE_CP_CRTC_DSPP_IGC:
657 if (!hw_dspp || !hw_dspp->ops.setup_igc) {
658 ret = -EINVAL;
659 continue;
660 }
661 hw_dspp->ops.setup_igc(hw_dspp, &hw_cfg);
662 break;
663 case SDE_CP_CRTC_DSPP_GC:
664 if (!hw_dspp || !hw_dspp->ops.setup_gc) {
665 ret = -EINVAL;
666 continue;
667 }
668 hw_dspp->ops.setup_gc(hw_dspp, &hw_cfg);
669 break;
670 case SDE_CP_CRTC_DSPP_HUE:
671 if (!hw_dspp || !hw_dspp->ops.setup_hue) {
672 ret = -EINVAL;
673 continue;
674 }
675 hw_dspp->ops.setup_hue(hw_dspp, &hw_cfg);
676 break;
677 case SDE_CP_CRTC_DSPP_SAT:
678 if (!hw_dspp || !hw_dspp->ops.setup_sat) {
679 ret = -EINVAL;
680 continue;
681 }
682 hw_dspp->ops.setup_sat(hw_dspp, &hw_cfg);
683 break;
684 case SDE_CP_CRTC_DSPP_VAL:
685 if (!hw_dspp || !hw_dspp->ops.setup_val) {
686 ret = -EINVAL;
687 continue;
688 }
689 hw_dspp->ops.setup_val(hw_dspp, &hw_cfg);
690 break;
691 case SDE_CP_CRTC_DSPP_CONT:
692 if (!hw_dspp || !hw_dspp->ops.setup_cont) {
693 ret = -EINVAL;
694 continue;
695 }
696 hw_dspp->ops.setup_cont(hw_dspp, &hw_cfg);
697 break;
698 case SDE_CP_CRTC_DSPP_MEMCOLOR:
Stephen Boyd22f7b512017-03-01 16:56:35 -0800699 if (!hw_dspp || !hw_dspp->ops.setup_pa_memcolor) {
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700700 ret = -EINVAL;
701 continue;
Stephen Boyd22f7b512017-03-01 16:56:35 -0800702 }
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700703 hw_dspp->ops.setup_pa_memcolor(hw_dspp, &hw_cfg);
704 break;
705 case SDE_CP_CRTC_DSPP_SIXZONE:
706 if (!hw_dspp || !hw_dspp->ops.setup_sixzone) {
707 ret = -EINVAL;
708 continue;
709 }
710 hw_dspp->ops.setup_sixzone(hw_dspp, &hw_cfg);
711 break;
712 case SDE_CP_CRTC_DSPP_GAMUT:
713 if (!hw_dspp || !hw_dspp->ops.setup_gamut) {
714 ret = -EINVAL;
715 continue;
716 }
717 hw_dspp->ops.setup_gamut(hw_dspp, &hw_cfg);
718 break;
719 case SDE_CP_CRTC_LM_GC:
720 if (!hw_lm || !hw_lm->ops.setup_gc) {
721 ret = -EINVAL;
722 continue;
723 }
724 hw_lm->ops.setup_gc(hw_lm, &hw_cfg);
725 break;
Xu Yang056d39b2017-07-11 16:34:13 +0800726 case SDE_CP_CRTC_DSPP_HIST_CTRL:
727 if (!hw_dspp || !hw_dspp->ops.setup_histogram) {
728 ret = -EINVAL;
729 continue;
730 }
731 hw_dspp->ops.setup_histogram(hw_dspp, &feature_enabled);
732 break;
733 case SDE_CP_CRTC_DSPP_HIST_IRQ:
734 if (!hw_dspp || !hw_lm) {
735 ret = -EINVAL;
736 continue;
737 }
738 if (!hw_lm->cfg.right_mixer)
739 _sde_cp_crtc_enable_hist_irq(sde_crtc);
740 break;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800741 case SDE_CP_CRTC_DSPP_AD_MODE:
742 if (!hw_dspp || !hw_dspp->ops.setup_ad) {
743 ret = -EINVAL;
744 continue;
745 }
746 ad_cfg.prop = AD_MODE;
747 ad_cfg.hw_cfg = &hw_cfg;
748 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
749 break;
750 case SDE_CP_CRTC_DSPP_AD_INIT:
751 if (!hw_dspp || !hw_dspp->ops.setup_ad) {
752 ret = -EINVAL;
753 continue;
754 }
755 ad_cfg.prop = AD_INIT;
756 ad_cfg.hw_cfg = &hw_cfg;
757 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
758 break;
759 case SDE_CP_CRTC_DSPP_AD_CFG:
760 if (!hw_dspp || !hw_dspp->ops.setup_ad) {
761 ret = -EINVAL;
762 continue;
763 }
764 ad_cfg.prop = AD_CFG;
765 ad_cfg.hw_cfg = &hw_cfg;
766 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
767 break;
768 case SDE_CP_CRTC_DSPP_AD_INPUT:
769 if (!hw_dspp || !hw_dspp->ops.setup_ad) {
770 ret = -EINVAL;
771 continue;
772 }
773 ad_cfg.prop = AD_INPUT;
774 ad_cfg.hw_cfg = &hw_cfg;
775 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
776 break;
777 case SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS:
778 if (!hw_dspp || !hw_dspp->ops.setup_ad) {
779 ret = -EINVAL;
780 continue;
781 }
782 ad_cfg.prop = AD_ASSERTIVE;
783 ad_cfg.hw_cfg = &hw_cfg;
784 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
785 break;
786 case SDE_CP_CRTC_DSPP_AD_BACKLIGHT:
787 if (!hw_dspp || !hw_dspp->ops.setup_ad) {
788 ret = -EINVAL;
789 continue;
790 }
791 ad_cfg.prop = AD_BACKLIGHT;
792 ad_cfg.hw_cfg = &hw_cfg;
793 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
794 break;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700795 default:
796 ret = -EINVAL;
797 break;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700798 }
799 }
800
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700801 if (ret) {
802 DRM_ERROR("failed to %s feature %d\n",
803 ((feature_enabled) ? "enable" : "disable"),
804 prop_node->feature);
805 return;
806 }
807
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700808 if (feature_enabled) {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700809 DRM_DEBUG_DRIVER("Add feature to active list %d\n",
810 prop_node->property_id);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800811 sde_cp_update_list(prop_node, sde_crtc, false);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700812 } else {
813 DRM_DEBUG_DRIVER("remove feature from active list %d\n",
814 prop_node->property_id);
815 list_del_init(&prop_node->active_list);
816 }
817 /* Programming of feature done remove from dirty list */
818 list_del_init(&prop_node->dirty_list);
819}
820
821void sde_cp_crtc_apply_properties(struct drm_crtc *crtc)
822{
823 struct sde_crtc *sde_crtc = NULL;
824 bool set_dspp_flush = false, set_lm_flush = false;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700825 struct sde_cp_node *prop_node = NULL, *n = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700826 struct sde_hw_ctl *ctl;
827 uint32_t flush_mask = 0;
828 u32 num_mixers = 0, i = 0;
829
830 if (!crtc || !crtc->dev) {
831 DRM_ERROR("invalid crtc %pK dev %pK\n", crtc,
832 (crtc ? crtc->dev : NULL));
833 return;
834 }
835
836 sde_crtc = to_sde_crtc(crtc);
837 if (!sde_crtc) {
838 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
839 return;
840 }
841
842 num_mixers = sde_crtc->num_mixers;
843 if (!num_mixers) {
844 DRM_DEBUG_DRIVER("no mixers for this crtc\n");
845 return;
846 }
847
Xu Yang1b3a5d92017-09-13 11:37:54 +0800848 mutex_lock(&sde_crtc->crtc_cp_lock);
849
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800850 /* Check if dirty lists are empty and ad features are disabled for
851 * early return. If ad properties are active then we need to issue
852 * dspp flush.
853 **/
854 if (list_empty(&sde_crtc->dirty_list) &&
855 list_empty(&sde_crtc->ad_dirty)) {
856 if (list_empty(&sde_crtc->ad_active)) {
857 DRM_DEBUG_DRIVER("Dirty list is empty\n");
Xu Yang1b3a5d92017-09-13 11:37:54 +0800858 goto exit;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800859 }
Ping Lie505f3b2017-06-19 14:19:08 -0700860 sde_cp_ad_set_prop(sde_crtc, AD_IPC_RESET);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800861 set_dspp_flush = true;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700862 }
863
864 list_for_each_entry_safe(prop_node, n, &sde_crtc->dirty_list,
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800865 dirty_list) {
Gopikrishnaiah Anandandb90fa12017-05-09 17:56:08 -0700866 sde_cp_crtc_setfeature(prop_node, sde_crtc);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700867 /* Set the flush flag to true */
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700868 if (prop_node->is_dspp_feature)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700869 set_dspp_flush = true;
870 else
871 set_lm_flush = true;
872 }
873
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800874 list_for_each_entry_safe(prop_node, n, &sde_crtc->ad_dirty,
875 dirty_list) {
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800876 set_dspp_flush = true;
Gopikrishnaiah Anandandb90fa12017-05-09 17:56:08 -0700877 sde_cp_crtc_setfeature(prop_node, sde_crtc);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800878 }
879
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700880 for (i = 0; i < num_mixers; i++) {
881 ctl = sde_crtc->mixers[i].hw_ctl;
882 if (!ctl)
883 continue;
884 if (set_dspp_flush && ctl->ops.get_bitmask_dspp
Stephen Boyd22f7b512017-03-01 16:56:35 -0800885 && sde_crtc->mixers[i].hw_dspp) {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700886 ctl->ops.get_bitmask_dspp(ctl,
887 &flush_mask,
888 sde_crtc->mixers[i].hw_dspp->idx);
889 ctl->ops.update_pending_flush(ctl, flush_mask);
Stephen Boyd22f7b512017-03-01 16:56:35 -0800890 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700891 if (set_lm_flush && ctl->ops.get_bitmask_mixer
Stephen Boyd22f7b512017-03-01 16:56:35 -0800892 && sde_crtc->mixers[i].hw_lm) {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700893 flush_mask = ctl->ops.get_bitmask_mixer(ctl,
894 sde_crtc->mixers[i].hw_lm->idx);
895 ctl->ops.update_pending_flush(ctl, flush_mask);
Stephen Boyd22f7b512017-03-01 16:56:35 -0800896 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700897 }
Xu Yang1b3a5d92017-09-13 11:37:54 +0800898exit:
899 mutex_unlock(&sde_crtc->crtc_cp_lock);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700900}
901
902void sde_cp_crtc_install_properties(struct drm_crtc *crtc)
903{
904 struct sde_kms *kms = NULL;
905 struct sde_crtc *sde_crtc = NULL;
906 struct sde_mdss_cfg *catalog = NULL;
907 unsigned long features = 0;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700908 int i = 0;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700909 struct msm_drm_private *priv;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700910
911 if (!crtc || !crtc->dev || !crtc->dev->dev_private) {
912 DRM_ERROR("invalid crtc %pK dev %pK\n",
913 crtc, ((crtc) ? crtc->dev : NULL));
914 return;
915 }
916
917 sde_crtc = to_sde_crtc(crtc);
Gopikrishnaiah Anandan7f6ef942016-06-20 15:50:00 -0700918 if (!sde_crtc) {
919 DRM_ERROR("sde_crtc %pK\n", sde_crtc);
920 return;
921 }
922
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700923 kms = get_kms(crtc);
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700924 if (!kms || !kms->catalog) {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700925 DRM_ERROR("invalid sde kms %pK catalog %pK sde_crtc %pK\n",
926 kms, ((kms) ? kms->catalog : NULL), sde_crtc);
927 return;
928 }
929
Xu Yang1b3a5d92017-09-13 11:37:54 +0800930 mutex_lock(&sde_crtc->crtc_cp_lock);
931
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700932 /**
933 * Function can be called during the atomic_check with test_only flag
934 * and actual commit. Allocate properties only if feature list is
935 * empty during the atomic_check with test_only flag.
936 */
937 if (!list_empty(&sde_crtc->feature_list))
Xu Yang1b3a5d92017-09-13 11:37:54 +0800938 goto exit;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700939
940 catalog = kms->catalog;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700941 priv = crtc->dev->dev_private;
942 /**
943 * DSPP/LM properties are global to all the CRTCS.
944 * Properties are created for first CRTC and re-used for later
945 * crtcs.
946 */
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -0700947 if (!priv->cp_property) {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700948 priv->cp_property = kzalloc((sizeof(priv->cp_property) *
949 SDE_CP_CRTC_MAX_FEATURES), GFP_KERNEL);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -0700950 setup_dspp_prop_install_funcs(dspp_prop_install_func);
951 setup_lm_prop_install_funcs(lm_prop_install_func);
952 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700953 if (!priv->cp_property)
Xu Yang1b3a5d92017-09-13 11:37:54 +0800954 goto exit;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700955
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700956 if (!catalog->dspp_count)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700957 goto lm_property;
958
959 /* Check for all the DSPP properties and attach it to CRTC */
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700960 features = catalog->dspp[0].features;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700961 for (i = 0; i < SDE_DSPP_MAX; i++) {
962 if (!test_bit(i, &features))
963 continue;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -0700964 if (dspp_prop_install_func[i])
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700965 dspp_prop_install_func[i](crtc);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700966 }
967
968lm_property:
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700969 if (!catalog->mixer_count)
Xu Yang1b3a5d92017-09-13 11:37:54 +0800970 goto exit;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700971
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700972 /* Check for all the LM properties and attach it to CRTC */
973 features = catalog->mixer[0].features;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700974 for (i = 0; i < SDE_MIXER_MAX; i++) {
975 if (!test_bit(i, &features))
976 continue;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -0700977 if (lm_prop_install_func[i])
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700978 lm_prop_install_func[i](crtc);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700979 }
Xu Yang1b3a5d92017-09-13 11:37:54 +0800980exit:
981 mutex_unlock(&sde_crtc->crtc_cp_lock);
982
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700983}
984
985int sde_cp_crtc_set_property(struct drm_crtc *crtc,
986 struct drm_property *property,
987 uint64_t val)
988{
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700989 struct sde_cp_node *prop_node = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700990 struct sde_crtc *sde_crtc = NULL;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700991 int ret = 0, i = 0, dspp_cnt, lm_cnt;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700992 u8 found = 0;
993
994 if (!crtc || !property) {
995 DRM_ERROR("invalid crtc %pK property %pK\n", crtc, property);
996 return -EINVAL;
997 }
998
999 sde_crtc = to_sde_crtc(crtc);
1000 if (!sde_crtc) {
1001 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
1002 return -EINVAL;
1003 }
1004
Xu Yang1b3a5d92017-09-13 11:37:54 +08001005 mutex_lock(&sde_crtc->crtc_cp_lock);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001006 list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) {
1007 if (property->base.id == prop_node->property_id) {
1008 found = 1;
1009 break;
1010 }
1011 }
1012
1013 if (!found)
Xu Yang1b3a5d92017-09-13 11:37:54 +08001014 goto exit;
1015
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001016 /**
1017 * sde_crtc is virtual ensure that hardware has been attached to the
1018 * crtc. Check LM and dspp counts based on whether feature is a
1019 * dspp/lm feature.
1020 */
1021 if (!sde_crtc->num_mixers ||
1022 sde_crtc->num_mixers > ARRAY_SIZE(sde_crtc->mixers)) {
1023 DRM_ERROR("Invalid mixer config act cnt %d max cnt %ld\n",
1024 sde_crtc->num_mixers, ARRAY_SIZE(sde_crtc->mixers));
Xu Yang1b3a5d92017-09-13 11:37:54 +08001025 ret = -EINVAL;
1026 goto exit;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001027 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001028
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001029 dspp_cnt = 0;
1030 lm_cnt = 0;
1031 for (i = 0; i < sde_crtc->num_mixers; i++) {
1032 if (sde_crtc->mixers[i].hw_dspp)
1033 dspp_cnt++;
1034 if (sde_crtc->mixers[i].hw_lm)
1035 lm_cnt++;
1036 }
1037
1038 if (prop_node->is_dspp_feature && dspp_cnt < sde_crtc->num_mixers) {
1039 DRM_ERROR("invalid dspp cnt %d mixer cnt %d\n", dspp_cnt,
1040 sde_crtc->num_mixers);
Xu Yang1b3a5d92017-09-13 11:37:54 +08001041 ret = -EINVAL;
1042 goto exit;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001043 } else if (lm_cnt < sde_crtc->num_mixers) {
1044 DRM_ERROR("invalid lm cnt %d mixer cnt %d\n", lm_cnt,
1045 sde_crtc->num_mixers);
Xu Yang1b3a5d92017-09-13 11:37:54 +08001046 ret = -EINVAL;
1047 goto exit;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001048 }
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001049
1050 ret = sde_cp_ad_validate_prop(prop_node, sde_crtc);
1051 if (ret) {
1052 DRM_ERROR("ad property validation failed ret %d\n", ret);
Xu Yang1b3a5d92017-09-13 11:37:54 +08001053 goto exit;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001054 }
1055
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001056 /* remove the property from dirty list */
1057 list_del_init(&prop_node->dirty_list);
1058
1059 if (!val)
1060 ret = sde_cp_disable_crtc_property(crtc, property, prop_node);
1061 else
1062 ret = sde_cp_enable_crtc_property(crtc, property,
1063 prop_node, val);
1064
1065 if (!ret) {
1066 /* remove the property from active list */
1067 list_del_init(&prop_node->active_list);
1068 /* Mark the feature as dirty */
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001069 sde_cp_update_list(prop_node, sde_crtc, true);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001070 }
Xu Yang1b3a5d92017-09-13 11:37:54 +08001071exit:
1072 mutex_unlock(&sde_crtc->crtc_cp_lock);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001073 return ret;
1074}
1075
1076int sde_cp_crtc_get_property(struct drm_crtc *crtc,
1077 struct drm_property *property, uint64_t *val)
1078{
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -07001079 struct sde_cp_node *prop_node = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001080 struct sde_crtc *sde_crtc = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001081
1082 if (!crtc || !property || !val) {
1083 DRM_ERROR("invalid crtc %pK property %pK val %pK\n",
1084 crtc, property, val);
1085 return -EINVAL;
1086 }
1087
1088 sde_crtc = to_sde_crtc(crtc);
1089 if (!sde_crtc) {
1090 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
1091 return -EINVAL;
1092 }
Gopikrishnaiah Anandand120b762016-10-05 12:03:42 -07001093 /* Return 0 if property is not supported */
1094 *val = 0;
Xu Yang1b3a5d92017-09-13 11:37:54 +08001095 mutex_lock(&sde_crtc->crtc_cp_lock);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001096 list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) {
1097 if (property->base.id == prop_node->property_id) {
1098 *val = prop_node->prop_val;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001099 break;
1100 }
1101 }
Xu Yang1b3a5d92017-09-13 11:37:54 +08001102 mutex_unlock(&sde_crtc->crtc_cp_lock);
Gopikrishnaiah Anandand120b762016-10-05 12:03:42 -07001103 return 0;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001104}
1105
1106void sde_cp_crtc_destroy_properties(struct drm_crtc *crtc)
1107{
1108 struct sde_crtc *sde_crtc = NULL;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -07001109 struct sde_cp_node *prop_node = NULL, *n = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001110
1111 if (!crtc) {
1112 DRM_ERROR("invalid crtc %pK\n", crtc);
1113 return;
1114 }
1115
1116 sde_crtc = to_sde_crtc(crtc);
1117 if (!sde_crtc) {
1118 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
1119 return;
1120 }
1121
1122 list_for_each_entry_safe(prop_node, n, &sde_crtc->feature_list,
1123 feature_list) {
1124 if (prop_node->prop_flags & DRM_MODE_PROP_BLOB
1125 && prop_node->blob_ptr)
1126 drm_property_unreference_blob(prop_node->blob_ptr);
1127
1128 list_del_init(&prop_node->active_list);
1129 list_del_init(&prop_node->dirty_list);
1130 list_del_init(&prop_node->feature_list);
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -07001131 sde_cp_destroy_local_blob(prop_node);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001132 kfree(prop_node);
1133 }
1134
Xu Yang5e53c2e2017-07-11 16:46:28 +08001135 if (sde_crtc->hist_blob)
1136 drm_property_unreference_blob(sde_crtc->hist_blob);
1137
Xu Yang1b3a5d92017-09-13 11:37:54 +08001138 mutex_destroy(&sde_crtc->crtc_cp_lock);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001139 INIT_LIST_HEAD(&sde_crtc->active_list);
1140 INIT_LIST_HEAD(&sde_crtc->dirty_list);
1141 INIT_LIST_HEAD(&sde_crtc->feature_list);
1142}
Gopikrishnaiah Anandan7f6ef942016-06-20 15:50:00 -07001143
1144void sde_cp_crtc_suspend(struct drm_crtc *crtc)
1145{
1146 struct sde_crtc *sde_crtc = NULL;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -07001147 struct sde_cp_node *prop_node = NULL, *n = NULL;
Gopikrishnaiah Anandan7f6ef942016-06-20 15:50:00 -07001148
1149 if (!crtc) {
1150 DRM_ERROR("crtc %pK\n", crtc);
1151 return;
1152 }
1153 sde_crtc = to_sde_crtc(crtc);
1154 if (!sde_crtc) {
1155 DRM_ERROR("sde_crtc %pK\n", sde_crtc);
1156 return;
1157 }
1158
Xu Yang1b3a5d92017-09-13 11:37:54 +08001159 mutex_lock(&sde_crtc->crtc_cp_lock);
Gopikrishnaiah Anandan7f6ef942016-06-20 15:50:00 -07001160 list_for_each_entry_safe(prop_node, n, &sde_crtc->active_list,
1161 active_list) {
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001162 sde_cp_update_list(prop_node, sde_crtc, true);
Gopikrishnaiah Anandan7f6ef942016-06-20 15:50:00 -07001163 list_del_init(&prop_node->active_list);
1164 }
Ping Li6d5bf542017-06-27 11:40:28 -07001165
1166 list_for_each_entry_safe(prop_node, n, &sde_crtc->ad_active,
1167 active_list) {
1168 sde_cp_update_list(prop_node, sde_crtc, true);
1169 list_del_init(&prop_node->active_list);
1170 }
Xu Yang1b3a5d92017-09-13 11:37:54 +08001171 mutex_unlock(&sde_crtc->crtc_cp_lock);
Gopikrishnaiah Anandan7f6ef942016-06-20 15:50:00 -07001172}
1173
1174void sde_cp_crtc_resume(struct drm_crtc *crtc)
1175{
1176 /* placeholder for operations needed during resume */
1177}
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001178
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001179static void dspp_pcc_install_property(struct drm_crtc *crtc)
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001180{
1181 char feature_name[256];
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001182 struct sde_kms *kms = NULL;
1183 struct sde_mdss_cfg *catalog = NULL;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001184 u32 version;
1185
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001186 kms = get_kms(crtc);
1187 catalog = kms->catalog;
1188
1189 version = catalog->dspp[0].sblk->pcc.version >> 16;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001190 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1191 "SDE_DSPP_PCC_V", version);
1192 switch (version) {
1193 case 1:
Rajesh Yadavd490cb62017-07-04 13:20:42 +05301194 case 4:
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001195 sde_cp_crtc_install_blob_property(crtc, feature_name,
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -08001196 SDE_CP_CRTC_DSPP_PCC, sizeof(struct drm_msm_pcc));
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001197 break;
1198 default:
1199 DRM_ERROR("version %d not supported\n", version);
1200 break;
1201 }
1202}
1203
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001204static void dspp_hsic_install_property(struct drm_crtc *crtc)
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001205{
1206 char feature_name[256];
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001207 struct sde_kms *kms = NULL;
1208 struct sde_mdss_cfg *catalog = NULL;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001209 u32 version;
1210
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001211 kms = get_kms(crtc);
1212 catalog = kms->catalog;
1213 version = catalog->dspp[0].sblk->hsic.version >> 16;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001214 switch (version) {
1215 case 1:
1216 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1217 "SDE_DSPP_HUE_V", version);
1218 sde_cp_crtc_install_range_property(crtc, feature_name,
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001219 SDE_CP_CRTC_DSPP_HUE, 0, U32_MAX, 0);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001220 break;
1221 default:
1222 DRM_ERROR("version %d not supported\n", version);
1223 break;
1224 }
1225}
1226
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001227static void dspp_vlut_install_property(struct drm_crtc *crtc)
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001228{
1229 char feature_name[256];
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001230 struct sde_kms *kms = NULL;
1231 struct sde_mdss_cfg *catalog = NULL;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001232 u32 version;
1233
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001234 kms = get_kms(crtc);
1235 catalog = kms->catalog;
1236 version = catalog->dspp[0].sblk->vlut.version >> 16;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001237 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1238 "SDE_DSPP_VLUT_V", version);
1239 switch (version) {
1240 case 1:
1241 sde_cp_crtc_install_range_property(crtc, feature_name,
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001242 SDE_CP_CRTC_DSPP_VLUT, 0, U64_MAX, 0);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001243 sde_cp_create_local_blob(crtc,
1244 SDE_CP_CRTC_DSPP_VLUT,
1245 sizeof(struct drm_msm_pa_vlut));
1246 break;
1247 default:
1248 DRM_ERROR("version %d not supported\n", version);
1249 break;
1250 }
1251}
1252
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001253static void dspp_ad_install_property(struct drm_crtc *crtc)
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001254{
1255 char feature_name[256];
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001256 struct sde_kms *kms = NULL;
1257 struct sde_mdss_cfg *catalog = NULL;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001258 u32 version;
1259
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001260 kms = get_kms(crtc);
1261 catalog = kms->catalog;
1262 version = catalog->dspp[0].sblk->ad.version >> 16;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001263 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1264 "SDE_DSPP_AD_V", version);
1265 switch (version) {
1266 case 3:
1267 sde_cp_crtc_install_immutable_property(crtc,
1268 feature_name, SDE_CP_CRTC_DSPP_AD);
1269 break;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001270 case 4:
1271 sde_cp_crtc_install_immutable_property(crtc,
1272 feature_name, SDE_CP_CRTC_DSPP_AD);
1273
1274 sde_cp_crtc_install_enum_property(crtc,
1275 SDE_CP_CRTC_DSPP_AD_MODE, ad4_modes,
1276 ARRAY_SIZE(ad4_modes), "SDE_DSPP_AD_V4_MODE");
1277
1278 sde_cp_crtc_install_range_property(crtc, "SDE_DSPP_AD_V4_INIT",
1279 SDE_CP_CRTC_DSPP_AD_INIT, 0, U64_MAX, 0);
1280 sde_cp_create_local_blob(crtc, SDE_CP_CRTC_DSPP_AD_INIT,
1281 sizeof(struct drm_msm_ad4_init));
1282
1283 sde_cp_crtc_install_range_property(crtc, "SDE_DSPP_AD_V4_CFG",
1284 SDE_CP_CRTC_DSPP_AD_CFG, 0, U64_MAX, 0);
1285 sde_cp_create_local_blob(crtc, SDE_CP_CRTC_DSPP_AD_CFG,
1286 sizeof(struct drm_msm_ad4_cfg));
1287 sde_cp_crtc_install_range_property(crtc,
Ping Lif41c2ef2017-05-04 14:40:45 -07001288 "SDE_DSPP_AD_V4_ASSERTIVENESS",
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001289 SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS, 0, (BIT(8) - 1), 0);
1290 sde_cp_crtc_install_range_property(crtc, "SDE_DSPP_AD_V4_INPUT",
1291 SDE_CP_CRTC_DSPP_AD_INPUT, 0, U16_MAX, 0);
1292 sde_cp_crtc_install_range_property(crtc,
1293 "SDE_DSPP_AD_V4_BACKLIGHT",
1294 SDE_CP_CRTC_DSPP_AD_BACKLIGHT, 0, (BIT(16) - 1),
1295 0);
1296 break;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001297 default:
1298 DRM_ERROR("version %d not supported\n", version);
1299 break;
1300 }
1301}
1302
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001303static void lm_gc_install_property(struct drm_crtc *crtc)
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001304{
1305 char feature_name[256];
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001306 struct sde_kms *kms = NULL;
1307 struct sde_mdss_cfg *catalog = NULL;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001308 u32 version;
1309
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001310 kms = get_kms(crtc);
1311 catalog = kms->catalog;
1312 version = catalog->mixer[0].sblk->gc.version >> 16;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001313 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1314 "SDE_LM_GC_V", version);
1315 switch (version) {
1316 case 1:
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001317 sde_cp_crtc_install_blob_property(crtc, feature_name,
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -08001318 SDE_CP_CRTC_LM_GC, sizeof(struct drm_msm_pgc_lut));
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001319 break;
1320 default:
1321 DRM_ERROR("version %d not supported\n", version);
1322 break;
1323 }
1324}
Gopikrishnaiah Anandanfbf75392017-01-16 10:43:36 -08001325
1326static void dspp_gamut_install_property(struct drm_crtc *crtc)
1327{
1328 char feature_name[256];
1329 struct sde_kms *kms = NULL;
1330 struct sde_mdss_cfg *catalog = NULL;
1331 u32 version;
1332
1333 kms = get_kms(crtc);
1334 catalog = kms->catalog;
1335
1336 version = catalog->dspp[0].sblk->gamut.version >> 16;
1337 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1338 "SDE_DSPP_GAMUT_V", version);
1339 switch (version) {
1340 case 4:
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001341 sde_cp_crtc_install_blob_property(crtc, feature_name,
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -08001342 SDE_CP_CRTC_DSPP_GAMUT,
1343 sizeof(struct drm_msm_3d_gamut));
Gopikrishnaiah Anandanfbf75392017-01-16 10:43:36 -08001344 break;
1345 default:
1346 DRM_ERROR("version %d not supported\n", version);
1347 break;
1348 }
1349}
1350
1351static void dspp_gc_install_property(struct drm_crtc *crtc)
1352{
1353 char feature_name[256];
1354 struct sde_kms *kms = NULL;
1355 struct sde_mdss_cfg *catalog = NULL;
1356 u32 version;
1357
1358 kms = get_kms(crtc);
1359 catalog = kms->catalog;
1360
1361 version = catalog->dspp[0].sblk->gc.version >> 16;
1362 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1363 "SDE_DSPP_GC_V", version);
1364 switch (version) {
1365 case 1:
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001366 sde_cp_crtc_install_blob_property(crtc, feature_name,
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -08001367 SDE_CP_CRTC_DSPP_GC, sizeof(struct drm_msm_pgc_lut));
Gopikrishnaiah Anandanfbf75392017-01-16 10:43:36 -08001368 break;
1369 default:
1370 DRM_ERROR("version %d not supported\n", version);
1371 break;
1372 }
1373}
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001374
Rajesh Yadavec93afb2017-06-08 19:28:33 +05301375static void dspp_igc_install_property(struct drm_crtc *crtc)
1376{
1377 char feature_name[256];
1378 struct sde_kms *kms = NULL;
1379 struct sde_mdss_cfg *catalog = NULL;
1380 u32 version;
1381
1382 kms = get_kms(crtc);
1383 catalog = kms->catalog;
1384
1385 version = catalog->dspp[0].sblk->igc.version >> 16;
1386 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1387 "SDE_DSPP_IGC_V", version);
1388 switch (version) {
1389 case 3:
1390 sde_cp_crtc_install_blob_property(crtc, feature_name,
1391 SDE_CP_CRTC_DSPP_IGC, sizeof(struct drm_msm_igc_lut));
1392 break;
1393 default:
1394 DRM_ERROR("version %d not supported\n", version);
1395 break;
1396 }
1397}
1398
Xu Yang056d39b2017-07-11 16:34:13 +08001399static void dspp_hist_install_property(struct drm_crtc *crtc)
1400{
1401 struct sde_kms *kms = NULL;
1402 struct sde_mdss_cfg *catalog = NULL;
1403 u32 version;
1404
1405 kms = get_kms(crtc);
1406 catalog = kms->catalog;
1407
1408 version = catalog->dspp[0].sblk->hist.version >> 16;
1409 switch (version) {
1410 case 1:
1411 sde_cp_crtc_install_enum_property(crtc,
1412 SDE_CP_CRTC_DSPP_HIST_CTRL, sde_hist_modes,
1413 ARRAY_SIZE(sde_hist_modes), "SDE_DSPP_HIST_CTRL_V1");
1414 sde_cp_crtc_install_range_property(crtc, "SDE_DSPP_HIST_IRQ_V1",
1415 SDE_CP_CRTC_DSPP_HIST_IRQ, 0, U16_MAX, 0);
1416 break;
1417 default:
1418 DRM_ERROR("version %d not supported\n", version);
1419 break;
1420 }
1421}
1422
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001423static void sde_cp_update_list(struct sde_cp_node *prop_node,
1424 struct sde_crtc *crtc, bool dirty_list)
1425{
1426 switch (prop_node->feature) {
1427 case SDE_CP_CRTC_DSPP_AD_MODE:
1428 case SDE_CP_CRTC_DSPP_AD_INIT:
1429 case SDE_CP_CRTC_DSPP_AD_CFG:
1430 case SDE_CP_CRTC_DSPP_AD_INPUT:
1431 case SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS:
1432 case SDE_CP_CRTC_DSPP_AD_BACKLIGHT:
1433 if (dirty_list)
1434 list_add_tail(&prop_node->dirty_list, &crtc->ad_dirty);
1435 else
1436 list_add_tail(&prop_node->active_list,
1437 &crtc->ad_active);
1438 break;
1439 default:
1440 /* color processing properties handle here */
1441 if (dirty_list)
1442 list_add_tail(&prop_node->dirty_list,
1443 &crtc->dirty_list);
1444 else
1445 list_add_tail(&prop_node->active_list,
1446 &crtc->active_list);
1447 break;
1448 };
1449}
1450
1451static int sde_cp_ad_validate_prop(struct sde_cp_node *prop_node,
1452 struct sde_crtc *crtc)
1453{
1454 int i = 0, ret = 0;
1455 u32 ad_prop;
1456
1457 for (i = 0; i < crtc->num_mixers && !ret; i++) {
1458 if (!crtc->mixers[i].hw_dspp) {
1459 ret = -EINVAL;
1460 continue;
1461 }
1462 switch (prop_node->feature) {
1463 case SDE_CP_CRTC_DSPP_AD_MODE:
1464 ad_prop = AD_MODE;
1465 break;
1466 case SDE_CP_CRTC_DSPP_AD_INIT:
1467 ad_prop = AD_INIT;
1468 break;
1469 case SDE_CP_CRTC_DSPP_AD_CFG:
1470 ad_prop = AD_CFG;
1471 break;
1472 case SDE_CP_CRTC_DSPP_AD_INPUT:
1473 ad_prop = AD_INPUT;
1474 break;
1475 case SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS:
1476 ad_prop = AD_ASSERTIVE;
1477 break;
1478 case SDE_CP_CRTC_DSPP_AD_BACKLIGHT:
1479 ad_prop = AD_BACKLIGHT;
1480 break;
1481 default:
1482 /* Not an AD property */
1483 return 0;
1484 }
1485 if (!crtc->mixers[i].hw_dspp->ops.validate_ad)
1486 ret = -EINVAL;
1487 else
1488 ret = crtc->mixers[i].hw_dspp->ops.validate_ad(
1489 crtc->mixers[i].hw_dspp, &ad_prop);
1490 }
1491 return ret;
1492}
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001493
1494static void sde_cp_ad_interrupt_cb(void *arg, int irq_idx)
1495{
1496 struct sde_crtc *crtc = arg;
Gopikrishnaiah Anandanb6b401f2017-03-14 16:39:49 -07001497
1498 sde_crtc_event_queue(&crtc->base, sde_cp_notify_ad_event, NULL);
1499}
1500
1501static void sde_cp_notify_ad_event(struct drm_crtc *crtc_drm, void *arg)
1502{
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001503 uint32_t bl = 0;
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001504 struct sde_hw_mixer *hw_lm = NULL;
1505 struct sde_hw_dspp *hw_dspp = NULL;
Gopikrishnaiah Anandanb6b401f2017-03-14 16:39:49 -07001506 u32 num_mixers;
1507 struct sde_crtc *crtc;
1508 struct drm_event event;
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001509 int i;
1510
Gopikrishnaiah Anandanb6b401f2017-03-14 16:39:49 -07001511 crtc = to_sde_crtc(crtc_drm);
1512 num_mixers = crtc->num_mixers;
1513 if (!num_mixers)
1514 return;
1515
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001516 for (i = 0; i < num_mixers; i++) {
1517 hw_lm = crtc->mixers[i].hw_lm;
1518 hw_dspp = crtc->mixers[i].hw_dspp;
1519 if (!hw_lm->cfg.right_mixer)
1520 break;
1521 }
1522
1523 if (!hw_dspp)
1524 return;
1525
1526 hw_dspp->ops.ad_read_intr_resp(hw_dspp, AD4_BACKLIGHT, &bl);
Gopikrishnaiah Anandanb6b401f2017-03-14 16:39:49 -07001527 event.length = sizeof(u32);
1528 event.type = DRM_EVENT_AD_BACKLIGHT;
Benjamin Chan34a92c72017-06-28 11:01:18 -04001529 msm_mode_object_event_notify(&crtc_drm->base, crtc_drm->dev,
Gopikrishnaiah Anandan84b4f672017-04-26 10:28:51 -07001530 &event, (u8 *)&bl);
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001531}
1532
1533int sde_cp_ad_interrupt(struct drm_crtc *crtc_drm, bool en,
1534 struct sde_irq_callback *ad_irq)
1535{
1536 struct sde_kms *kms = NULL;
1537 u32 num_mixers;
1538 struct sde_hw_mixer *hw_lm;
1539 struct sde_hw_dspp *hw_dspp = NULL;
1540 struct sde_crtc *crtc;
1541 int i;
1542 int irq_idx, ret;
1543 struct sde_cp_node prop_node;
1544
1545 if (!crtc_drm || !ad_irq) {
1546 DRM_ERROR("invalid crtc %pK irq %pK\n", crtc_drm, ad_irq);
1547 return -EINVAL;
1548 }
1549
1550 crtc = to_sde_crtc(crtc_drm);
1551 if (!crtc) {
1552 DRM_ERROR("invalid sde_crtc %pK\n", crtc);
1553 return -EINVAL;
1554 }
1555
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001556 kms = get_kms(crtc_drm);
1557 num_mixers = crtc->num_mixers;
1558
1559 memset(&prop_node, 0, sizeof(prop_node));
1560 prop_node.feature = SDE_CP_CRTC_DSPP_AD_BACKLIGHT;
1561 ret = sde_cp_ad_validate_prop(&prop_node, crtc);
1562 if (ret) {
1563 DRM_ERROR("Ad not supported ret %d\n", ret);
1564 goto exit;
1565 }
1566
1567 for (i = 0; i < num_mixers; i++) {
1568 hw_lm = crtc->mixers[i].hw_lm;
1569 hw_dspp = crtc->mixers[i].hw_dspp;
1570 if (!hw_lm->cfg.right_mixer)
1571 break;
1572 }
1573
1574 if (!hw_dspp) {
1575 DRM_ERROR("invalid dspp\n");
1576 ret = -EINVAL;
1577 goto exit;
1578 }
1579
1580 irq_idx = sde_core_irq_idx_lookup(kms, SDE_IRQ_TYPE_AD4_BL_DONE,
1581 hw_dspp->idx);
1582 if (irq_idx < 0) {
1583 DRM_ERROR("failed to get the irq idx ret %d\n", irq_idx);
1584 ret = irq_idx;
1585 goto exit;
1586 }
1587
1588 if (!en) {
1589 sde_core_irq_disable(kms, &irq_idx, 1);
1590 sde_core_irq_unregister_callback(kms, irq_idx, ad_irq);
1591 ret = 0;
1592 goto exit;
1593 }
1594
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001595 ad_irq->arg = crtc;
1596 ad_irq->func = sde_cp_ad_interrupt_cb;
1597 ret = sde_core_irq_register_callback(kms, irq_idx, ad_irq);
1598 if (ret) {
1599 DRM_ERROR("failed to register the callback ret %d\n", ret);
1600 goto exit;
1601 }
1602 ret = sde_core_irq_enable(kms, &irq_idx, 1);
1603 if (ret) {
1604 DRM_ERROR("failed to enable irq ret %d\n", ret);
1605 sde_core_irq_unregister_callback(kms, irq_idx, ad_irq);
1606 }
1607exit:
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001608 return ret;
1609}
Ping Lie505f3b2017-06-19 14:19:08 -07001610
1611static void sde_cp_ad_set_prop(struct sde_crtc *sde_crtc,
1612 enum ad_property ad_prop)
1613{
1614 struct sde_ad_hw_cfg ad_cfg;
1615 struct sde_hw_cp_cfg hw_cfg;
1616 struct sde_hw_dspp *hw_dspp = NULL;
1617 struct sde_hw_mixer *hw_lm = NULL;
1618 u32 num_mixers = sde_crtc->num_mixers;
1619 int i = 0, ret = 0;
1620
1621 hw_cfg.num_of_mixers = sde_crtc->num_mixers;
1622 hw_cfg.displayh = sde_crtc->base.mode.hdisplay;
1623 hw_cfg.displayv = sde_crtc->base.mode.vdisplay;
1624
1625 for (i = 0; i < num_mixers && !ret; i++) {
1626 hw_lm = sde_crtc->mixers[i].hw_lm;
1627 hw_dspp = sde_crtc->mixers[i].hw_dspp;
1628 if (!hw_lm || !hw_dspp || !hw_dspp->ops.validate_ad ||
1629 !hw_dspp->ops.setup_ad) {
1630 ret = -EINVAL;
1631 continue;
1632 }
1633
1634 hw_cfg.mixer_info = hw_lm;
1635 ad_cfg.prop = ad_prop;
1636 ad_cfg.hw_cfg = &hw_cfg;
1637 ret = hw_dspp->ops.validate_ad(hw_dspp, (u32 *)&ad_prop);
1638 if (!ret)
1639 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
1640 }
1641}
1642
1643void sde_cp_crtc_pre_ipc(struct drm_crtc *drm_crtc)
1644{
1645 struct sde_crtc *sde_crtc;
1646
1647 sde_crtc = to_sde_crtc(drm_crtc);
1648 if (!sde_crtc) {
1649 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
1650 return;
1651 }
1652
1653 sde_cp_ad_set_prop(sde_crtc, AD_IPC_SUSPEND);
1654}
1655
1656void sde_cp_crtc_post_ipc(struct drm_crtc *drm_crtc)
1657{
1658 struct sde_crtc *sde_crtc;
1659
1660 sde_crtc = to_sde_crtc(drm_crtc);
1661 if (!sde_crtc) {
1662 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
1663 return;
1664 }
1665
1666 sde_cp_ad_set_prop(sde_crtc, AD_IPC_RESUME);
1667}
Xu Yang5e53c2e2017-07-11 16:46:28 +08001668
1669static void sde_cp_hist_interrupt_cb(void *arg, int irq_idx)
1670{
1671 struct sde_crtc *crtc = arg;
1672 struct drm_crtc *crtc_drm = &crtc->base;
1673 struct sde_hw_dspp *hw_dspp;
1674 struct sde_kms *kms;
1675 struct sde_crtc_irq_info *node = NULL;
1676 u32 i;
1677 int ret = 0;
1678 unsigned long flags;
1679
1680 /* disable histogram irq */
1681 kms = get_kms(crtc_drm);
1682 spin_lock_irqsave(&crtc->spin_lock, flags);
1683 node = _sde_cp_get_intr_node(DRM_EVENT_HISTOGRAM, crtc);
1684 spin_unlock_irqrestore(&crtc->spin_lock, flags);
1685
1686 if (!node) {
1687 DRM_ERROR("cannot find histogram event node in crtc\n");
1688 return;
1689 }
1690
1691 if (node->state == IRQ_ENABLED) {
1692 if (sde_core_irq_disable_nolock(kms, irq_idx)) {
1693 DRM_ERROR("failed to disable irq %d, ret %d\n",
1694 irq_idx, ret);
1695 return;
1696 }
1697 node->state = IRQ_DISABLED;
1698 }
1699
1700 /* lock histogram buffer */
1701 for (i = 0; i < crtc->num_mixers; i++) {
1702 hw_dspp = crtc->mixers[i].hw_dspp;
1703 if (hw_dspp && hw_dspp->ops.lock_histogram)
1704 hw_dspp->ops.lock_histogram(hw_dspp, NULL);
1705 }
1706
1707 /* notify histogram event */
1708 sde_crtc_event_queue(crtc_drm, sde_cp_notify_hist_event, NULL);
1709}
1710
1711static void sde_cp_notify_hist_event(struct drm_crtc *crtc_drm, void *arg)
1712{
1713 struct sde_hw_dspp *hw_dspp = NULL;
1714 struct sde_crtc *crtc;
1715 struct drm_event event;
1716 struct drm_msm_hist *hist_data;
1717 struct drm_msm_hist tmp_hist_data;
1718 u32 i, j;
1719
1720 if (!crtc_drm) {
1721 DRM_ERROR("invalid crtc %pK\n", crtc_drm);
1722 return;
1723 }
1724
1725 crtc = to_sde_crtc(crtc_drm);
1726 if (!crtc) {
1727 DRM_ERROR("invalid sde_crtc %pK\n", crtc);
1728 return;
1729 }
1730
1731 if (!crtc->hist_blob)
1732 return;
1733
1734 /* read histogram data into blob */
1735 hist_data = (struct drm_msm_hist *)crtc->hist_blob->data;
1736 for (i = 0; i < crtc->num_mixers; i++) {
1737 hw_dspp = crtc->mixers[i].hw_dspp;
1738 if (!hw_dspp || !hw_dspp->ops.read_histogram) {
1739 DRM_ERROR("invalid dspp %pK or read_histogram func\n",
1740 hw_dspp);
1741 return;
1742 }
1743 if (!i) {
1744 hw_dspp->ops.read_histogram(hw_dspp, hist_data);
1745 } else {
1746 /* Merge hist data for DSPP0 and DSPP1 */
1747 hw_dspp->ops.read_histogram(hw_dspp, &tmp_hist_data);
1748 for (j = 0; j < HIST_V_SIZE; j++)
1749 hist_data->data[j] += tmp_hist_data.data[j];
1750 }
1751 }
1752
1753 /* send histogram event with blob id */
1754 event.length = sizeof(u32);
1755 event.type = DRM_EVENT_HISTOGRAM;
1756 msm_mode_object_event_notify(&crtc_drm->base, crtc_drm->dev,
1757 &event, (u8 *)(&crtc->hist_blob->base.id));
1758}
1759
1760int sde_cp_hist_interrupt(struct drm_crtc *crtc_drm, bool en,
1761 struct sde_irq_callback *hist_irq)
1762{
1763 struct sde_kms *kms = NULL;
1764 u32 num_mixers;
1765 struct sde_hw_mixer *hw_lm;
1766 struct sde_hw_dspp *hw_dspp = NULL;
1767 struct sde_crtc *crtc;
1768 struct sde_crtc_irq_info *node = NULL;
1769 int i, irq_idx, ret = 0;
1770
1771 if (!crtc_drm || !hist_irq) {
1772 DRM_ERROR("invalid crtc %pK irq %pK\n", crtc_drm, hist_irq);
1773 return -EINVAL;
1774 }
1775
1776 crtc = to_sde_crtc(crtc_drm);
1777 if (!crtc) {
1778 DRM_ERROR("invalid sde_crtc %pK\n", crtc);
1779 return -EINVAL;
1780 }
1781
1782 kms = get_kms(crtc_drm);
1783 num_mixers = crtc->num_mixers;
1784
1785 for (i = 0; i < num_mixers; i++) {
1786 hw_lm = crtc->mixers[i].hw_lm;
1787 hw_dspp = crtc->mixers[i].hw_dspp;
1788 if (!hw_lm->cfg.right_mixer)
1789 break;
1790 }
1791
1792 if (!hw_dspp) {
1793 DRM_ERROR("invalid dspp\n");
1794 ret = -EINVAL;
1795 goto exit;
1796 }
1797
1798 irq_idx = sde_core_irq_idx_lookup(kms, SDE_IRQ_TYPE_HIST_DSPP_DONE,
1799 hw_dspp->idx);
1800 if (irq_idx < 0) {
1801 DRM_ERROR("failed to get the irq idx ret %d\n", irq_idx);
1802 ret = irq_idx;
1803 goto exit;
1804 }
1805
1806 node = _sde_cp_get_intr_node(DRM_EVENT_HISTOGRAM, crtc);
1807
1808 /* deregister histogram irq */
1809 if (!en) {
1810 if (node) {
1811 /* device suspend case or suspend to IPC cases */
1812 if (node->state == IRQ_ENABLED) {
1813 ret = sde_core_irq_disable(kms, &irq_idx, 1);
1814 if (ret)
1815 DRM_ERROR("disable irq %d error %d\n",
1816 irq_idx, ret);
1817 else
1818 node->state = IRQ_NOINIT;
1819 } else {
1820 node->state = IRQ_NOINIT;
1821 }
1822 } else {
1823 DRM_ERROR("failed to get node from crtc event list\n");
1824 }
1825
1826 sde_core_irq_unregister_callback(kms, irq_idx, hist_irq);
1827 goto exit;
1828 }
1829
1830 /* register histogram irq */
1831 hist_irq->arg = crtc;
1832 hist_irq->func = sde_cp_hist_interrupt_cb;
1833 ret = sde_core_irq_register_callback(kms, irq_idx, hist_irq);
1834 if (ret) {
1835 DRM_ERROR("failed to register the callback ret %d\n", ret);
1836 goto exit;
1837 }
1838
1839 if (node) {
1840 /* device resume or resume from IPC cases */
1841 if (node->state == IRQ_DISABLED || node->state == IRQ_NOINIT) {
1842 ret = sde_core_irq_enable(kms, &irq_idx, 1);
1843 if (ret) {
1844 DRM_ERROR("enable irq %d error %d\n",
1845 irq_idx, ret);
1846 sde_core_irq_unregister_callback(kms,
1847 irq_idx, hist_irq);
1848 } else {
1849 node->state = IRQ_ENABLED;
1850 }
1851 }
1852 } else {
1853 /* request from userspace to register the event
1854 * in this case, node has not been added into the event list
1855 */
1856 ret = sde_core_irq_enable(kms, &irq_idx, 1);
1857 if (ret) {
1858 DRM_ERROR("failed to enable irq ret %d\n", ret);
1859 sde_core_irq_unregister_callback(kms,
1860 irq_idx, hist_irq);
1861 }
1862 }
1863exit:
1864 return ret;
1865}