blob: 3e084d59a8a2ec9ccc4173f86ceb4a53527b5346 [file] [log] [blame]
Xu Yanged79cec2018-01-10 21:04:05 +08001/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07002 *
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"
Yuchao Ma9991ece2017-12-01 15:02:00 +080027#include "dsi_panel.h"
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -070028
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -070029struct sde_cp_node {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -070030 u32 property_id;
31 u32 prop_flags;
32 u32 feature;
33 void *blob_ptr;
34 uint64_t prop_val;
35 const struct sde_pp_blk *pp_blk;
36 struct list_head feature_list;
37 struct list_head active_list;
38 struct list_head dirty_list;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -070039 bool is_dspp_feature;
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -080040 u32 prop_blob_sz;
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -080041 struct sde_irq_callback *irq;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -070042};
43
44struct sde_cp_prop_attach {
45 struct drm_crtc *crtc;
46 struct drm_property *prop;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -070047 struct sde_cp_node *prop_node;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -070048 u32 feature;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -070049 uint64_t val;
50};
51
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -070052static void dspp_pcc_install_property(struct drm_crtc *crtc);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070053
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -070054static void dspp_hsic_install_property(struct drm_crtc *crtc);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070055
Rajesh Yadav7b8fbae2017-08-28 14:48:14 +053056static void dspp_memcolor_install_property(struct drm_crtc *crtc);
57
Rajesh Yadav0a92eea2017-07-18 18:18:55 +053058static void dspp_sixzone_install_property(struct drm_crtc *crtc);
59
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -070060static void dspp_ad_install_property(struct drm_crtc *crtc);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070061
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -070062static void dspp_vlut_install_property(struct drm_crtc *crtc);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070063
Gopikrishnaiah Anandanfbf75392017-01-16 10:43:36 -080064static void dspp_gamut_install_property(struct drm_crtc *crtc);
65
66static void dspp_gc_install_property(struct drm_crtc *crtc);
67
Rajesh Yadavec93afb2017-06-08 19:28:33 +053068static void dspp_igc_install_property(struct drm_crtc *crtc);
69
Xu Yang056d39b2017-07-11 16:34:13 +080070static void dspp_hist_install_property(struct drm_crtc *crtc);
71
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -070072typedef void (*dspp_prop_install_func_t)(struct drm_crtc *crtc);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070073
74static dspp_prop_install_func_t dspp_prop_install_func[SDE_DSPP_MAX];
75
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -080076static void sde_cp_update_list(struct sde_cp_node *prop_node,
77 struct sde_crtc *crtc, bool dirty_list);
78
79static int sde_cp_ad_validate_prop(struct sde_cp_node *prop_node,
80 struct sde_crtc *crtc);
81
Gopikrishnaiah Anandanb6b401f2017-03-14 16:39:49 -070082static void sde_cp_notify_ad_event(struct drm_crtc *crtc_drm, void *arg);
83
Ping Lie505f3b2017-06-19 14:19:08 -070084static void sde_cp_ad_set_prop(struct sde_crtc *sde_crtc,
85 enum ad_property ad_prop);
86
Xu Yang5e53c2e2017-07-11 16:46:28 +080087static void sde_cp_notify_hist_event(struct drm_crtc *crtc_drm, void *arg);
88
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070089#define setup_dspp_prop_install_funcs(func) \
90do { \
91 func[SDE_DSPP_PCC] = dspp_pcc_install_property; \
92 func[SDE_DSPP_HSIC] = dspp_hsic_install_property; \
Rajesh Yadav7b8fbae2017-08-28 14:48:14 +053093 func[SDE_DSPP_MEMCOLOR] = dspp_memcolor_install_property; \
Rajesh Yadav0a92eea2017-07-18 18:18:55 +053094 func[SDE_DSPP_SIXZONE] = dspp_sixzone_install_property; \
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070095 func[SDE_DSPP_AD] = dspp_ad_install_property; \
96 func[SDE_DSPP_VLUT] = dspp_vlut_install_property; \
Gopikrishnaiah Anandanfbf75392017-01-16 10:43:36 -080097 func[SDE_DSPP_GAMUT] = dspp_gamut_install_property; \
98 func[SDE_DSPP_GC] = dspp_gc_install_property; \
Rajesh Yadavec93afb2017-06-08 19:28:33 +053099 func[SDE_DSPP_IGC] = dspp_igc_install_property; \
Xu Yang056d39b2017-07-11 16:34:13 +0800100 func[SDE_DSPP_HIST] = dspp_hist_install_property; \
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -0700101} while (0)
102
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700103typedef void (*lm_prop_install_func_t)(struct drm_crtc *crtc);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -0700104
105static lm_prop_install_func_t lm_prop_install_func[SDE_MIXER_MAX];
106
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700107static void lm_gc_install_property(struct drm_crtc *crtc);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -0700108
109#define setup_lm_prop_install_funcs(func) \
110 (func[SDE_MIXER_GC] = lm_gc_install_property)
111
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700112enum {
113 /* Append new DSPP features before SDE_CP_CRTC_DSPP_MAX */
114 /* DSPP Features start */
115 SDE_CP_CRTC_DSPP_IGC,
116 SDE_CP_CRTC_DSPP_PCC,
117 SDE_CP_CRTC_DSPP_GC,
Rajesh Yadav284947c2017-07-21 20:32:13 +0530118 SDE_CP_CRTC_DSPP_HSIC,
Rajesh Yadav7b8fbae2017-08-28 14:48:14 +0530119 SDE_CP_CRTC_DSPP_MEMCOL_SKIN,
120 SDE_CP_CRTC_DSPP_MEMCOL_SKY,
121 SDE_CP_CRTC_DSPP_MEMCOL_FOLIAGE,
122 SDE_CP_CRTC_DSPP_MEMCOL_PROT,
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700123 SDE_CP_CRTC_DSPP_SIXZONE,
124 SDE_CP_CRTC_DSPP_GAMUT,
125 SDE_CP_CRTC_DSPP_DITHER,
Xu Yang056d39b2017-07-11 16:34:13 +0800126 SDE_CP_CRTC_DSPP_HIST_CTRL,
127 SDE_CP_CRTC_DSPP_HIST_IRQ,
Gopikrishnaiah Anandan41980b42016-06-21 16:01:33 -0700128 SDE_CP_CRTC_DSPP_AD,
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700129 SDE_CP_CRTC_DSPP_VLUT,
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800130 SDE_CP_CRTC_DSPP_AD_MODE,
131 SDE_CP_CRTC_DSPP_AD_INIT,
132 SDE_CP_CRTC_DSPP_AD_CFG,
133 SDE_CP_CRTC_DSPP_AD_INPUT,
134 SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS,
135 SDE_CP_CRTC_DSPP_AD_BACKLIGHT,
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700136 SDE_CP_CRTC_DSPP_MAX,
137 /* DSPP features end */
138
139 /* Append new LM features before SDE_CP_CRTC_MAX_FEATURES */
140 /* LM feature start*/
141 SDE_CP_CRTC_LM_GC,
142 /* LM feature end*/
143
144 SDE_CP_CRTC_MAX_FEATURES,
145};
146
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700147#define INIT_PROP_ATTACH(p, crtc, prop, node, feature, val) \
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700148 do { \
149 (p)->crtc = crtc; \
150 (p)->prop = prop; \
151 (p)->prop_node = node; \
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700152 (p)->feature = feature; \
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700153 (p)->val = val; \
154 } while (0)
155
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700156static void sde_cp_get_hw_payload(struct sde_cp_node *prop_node,
157 struct sde_hw_cp_cfg *hw_cfg,
158 bool *feature_enabled)
159{
160
161 struct drm_property_blob *blob = NULL;
162
163 memset(hw_cfg, 0, sizeof(*hw_cfg));
164 *feature_enabled = false;
165
166 blob = prop_node->blob_ptr;
167 if (prop_node->prop_flags & DRM_MODE_PROP_BLOB) {
168 if (blob) {
169 hw_cfg->len = blob->length;
170 hw_cfg->payload = blob->data;
171 *feature_enabled = true;
172 }
173 } else if (prop_node->prop_flags & DRM_MODE_PROP_RANGE) {
174 /* Check if local blob is Set */
175 if (!blob) {
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800176 if (prop_node->prop_val) {
177 hw_cfg->len = sizeof(prop_node->prop_val);
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700178 hw_cfg->payload = &prop_node->prop_val;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800179 }
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700180 } else {
181 hw_cfg->len = (prop_node->prop_val) ? blob->length :
182 0;
183 hw_cfg->payload = (prop_node->prop_val) ? blob->data
184 : NULL;
185 }
186 if (prop_node->prop_val)
187 *feature_enabled = true;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800188 } else if (prop_node->prop_flags & DRM_MODE_PROP_ENUM) {
189 *feature_enabled = (prop_node->prop_val != 0);
190 hw_cfg->len = sizeof(prop_node->prop_val);
191 hw_cfg->payload = &prop_node->prop_val;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700192 } else {
193 DRM_ERROR("property type is not supported\n");
194 }
195}
196
197static int sde_cp_disable_crtc_blob_property(struct sde_cp_node *prop_node)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700198{
199 struct drm_property_blob *blob = prop_node->blob_ptr;
200
201 if (!blob)
Gopikrishnaiah Anandan8b1498a2017-05-10 16:58:04 -0700202 return 0;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700203 drm_property_unreference_blob(blob);
204 prop_node->blob_ptr = NULL;
205 return 0;
206}
207
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700208static int sde_cp_create_local_blob(struct drm_crtc *crtc, u32 feature, int len)
209{
210 int ret = -EINVAL;
211 bool found = false;
212 struct sde_cp_node *prop_node = NULL;
213 struct drm_property_blob *blob_ptr;
214 struct sde_crtc *sde_crtc = to_sde_crtc(crtc);
215
216 list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) {
217 if (prop_node->feature == feature) {
218 found = true;
219 break;
220 }
221 }
222
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800223 if (!found || !(prop_node->prop_flags & DRM_MODE_PROP_RANGE)) {
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700224 DRM_ERROR("local blob create failed prop found %d flags %d\n",
225 found, prop_node->prop_flags);
226 return ret;
227 }
228
229 blob_ptr = drm_property_create_blob(crtc->dev, len, NULL);
230 ret = (IS_ERR_OR_NULL(blob_ptr)) ? PTR_ERR(blob_ptr) : 0;
231 if (!ret)
232 prop_node->blob_ptr = blob_ptr;
233
234 return ret;
235}
236
237static void sde_cp_destroy_local_blob(struct sde_cp_node *prop_node)
238{
239 if (!(prop_node->prop_flags & DRM_MODE_PROP_BLOB) &&
240 prop_node->blob_ptr)
241 drm_property_unreference_blob(prop_node->blob_ptr);
242}
243
244static int sde_cp_handle_range_property(struct sde_cp_node *prop_node,
245 uint64_t val)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700246{
247 int ret = 0;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700248 struct drm_property_blob *blob_ptr = prop_node->blob_ptr;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700249
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700250 if (!blob_ptr) {
251 prop_node->prop_val = val;
252 return 0;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700253 }
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700254
255 if (!val) {
256 prop_node->prop_val = 0;
257 return 0;
258 }
259
260 ret = copy_from_user(blob_ptr->data, (void *)val, blob_ptr->length);
261 if (ret) {
262 DRM_ERROR("failed to get the property info ret %d", ret);
263 ret = -EFAULT;
264 } else {
265 prop_node->prop_val = val;
266 }
267
268 return ret;
269}
270
271static int sde_cp_disable_crtc_property(struct drm_crtc *crtc,
272 struct drm_property *property,
273 struct sde_cp_node *prop_node)
274{
275 int ret = -EINVAL;
276
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800277 if (property->flags & DRM_MODE_PROP_BLOB) {
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700278 ret = sde_cp_disable_crtc_blob_property(prop_node);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800279 } else if (property->flags & DRM_MODE_PROP_RANGE) {
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700280 ret = sde_cp_handle_range_property(prop_node, 0);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800281 } else if (property->flags & DRM_MODE_PROP_ENUM) {
282 ret = 0;
283 prop_node->prop_val = 0;
284 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700285 return ret;
286}
287
288static int sde_cp_enable_crtc_blob_property(struct drm_crtc *crtc,
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700289 struct sde_cp_node *prop_node,
290 uint64_t val)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700291{
292 struct drm_property_blob *blob = NULL;
293
294 /**
295 * For non-blob based properties add support to create a blob
296 * using the val and store the blob_ptr in prop_node.
297 */
298 blob = drm_property_lookup_blob(crtc->dev, val);
299 if (!blob) {
300 DRM_ERROR("invalid blob id %lld\n", val);
301 return -EINVAL;
302 }
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -0800303 if (blob->length != prop_node->prop_blob_sz) {
304 DRM_ERROR("invalid blob len %zd exp %d feature %d\n",
305 blob->length, prop_node->prop_blob_sz, prop_node->feature);
306 drm_property_unreference_blob(blob);
307 return -EINVAL;
308 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700309 /* Release refernce to existing payload of the property */
310 if (prop_node->blob_ptr)
311 drm_property_unreference_blob(prop_node->blob_ptr);
312
313 prop_node->blob_ptr = blob;
314 return 0;
315}
316
317static int sde_cp_enable_crtc_property(struct drm_crtc *crtc,
318 struct drm_property *property,
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700319 struct sde_cp_node *prop_node,
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700320 uint64_t val)
321{
322 int ret = -EINVAL;
323
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800324 if (property->flags & DRM_MODE_PROP_BLOB) {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700325 ret = sde_cp_enable_crtc_blob_property(crtc, prop_node, val);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800326 } else if (property->flags & DRM_MODE_PROP_RANGE) {
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700327 ret = sde_cp_handle_range_property(prop_node, val);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800328 } else if (property->flags & DRM_MODE_PROP_ENUM) {
329 ret = 0;
330 prop_node->prop_val = val;
331 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700332 return ret;
333}
334
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700335static struct sde_kms *get_kms(struct drm_crtc *crtc)
336{
337 struct msm_drm_private *priv = crtc->dev->dev_private;
338
339 return to_sde_kms(priv->kms);
340}
341
342static void sde_cp_crtc_prop_attach(struct sde_cp_prop_attach *prop_attach)
343{
344
345 struct sde_crtc *sde_crtc = to_sde_crtc(prop_attach->crtc);
346
347 drm_object_attach_property(&prop_attach->crtc->base,
348 prop_attach->prop, prop_attach->val);
349
350 INIT_LIST_HEAD(&prop_attach->prop_node->active_list);
351 INIT_LIST_HEAD(&prop_attach->prop_node->dirty_list);
352
353 prop_attach->prop_node->property_id = prop_attach->prop->base.id;
354 prop_attach->prop_node->prop_flags = prop_attach->prop->flags;
355 prop_attach->prop_node->feature = prop_attach->feature;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700356
357 if (prop_attach->feature < SDE_CP_CRTC_DSPP_MAX)
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700358 prop_attach->prop_node->is_dspp_feature = true;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700359 else
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700360 prop_attach->prop_node->is_dspp_feature = false;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700361
362 list_add(&prop_attach->prop_node->feature_list,
363 &sde_crtc->feature_list);
364}
365
366void sde_cp_crtc_init(struct drm_crtc *crtc)
367{
368 struct sde_crtc *sde_crtc = NULL;
369
370 if (!crtc) {
371 DRM_ERROR("invalid crtc %pK\n", crtc);
372 return;
373 }
374
375 sde_crtc = to_sde_crtc(crtc);
376 if (!sde_crtc) {
377 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
378 return;
379 }
380
Xu Yang5e53c2e2017-07-11 16:46:28 +0800381 /* create blob to store histogram data */
382 sde_crtc->hist_blob = drm_property_create_blob(crtc->dev,
383 sizeof(struct drm_msm_hist), NULL);
384 if (IS_ERR(sde_crtc->hist_blob))
385 sde_crtc->hist_blob = NULL;
386
Xu Yang1b3a5d92017-09-13 11:37:54 +0800387 mutex_init(&sde_crtc->crtc_cp_lock);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700388 INIT_LIST_HEAD(&sde_crtc->active_list);
389 INIT_LIST_HEAD(&sde_crtc->dirty_list);
390 INIT_LIST_HEAD(&sde_crtc->feature_list);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800391 INIT_LIST_HEAD(&sde_crtc->ad_dirty);
392 INIT_LIST_HEAD(&sde_crtc->ad_active);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700393}
394
Gopikrishnaiah Anandan41980b42016-06-21 16:01:33 -0700395static void sde_cp_crtc_install_immutable_property(struct drm_crtc *crtc,
396 char *name,
397 u32 feature)
398{
399 struct drm_property *prop;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700400 struct sde_cp_node *prop_node = NULL;
Gopikrishnaiah Anandan41980b42016-06-21 16:01:33 -0700401 struct msm_drm_private *priv;
402 struct sde_cp_prop_attach prop_attach;
403 uint64_t val = 0;
404
405 if (feature >= SDE_CP_CRTC_MAX_FEATURES) {
406 DRM_ERROR("invalid feature %d max %d\n", feature,
407 SDE_CP_CRTC_MAX_FEATURES);
408 return;
409 }
410
411 prop_node = kzalloc(sizeof(*prop_node), GFP_KERNEL);
412 if (!prop_node)
413 return;
414
415 priv = crtc->dev->dev_private;
416 prop = priv->cp_property[feature];
417
418 if (!prop) {
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800419 prop = drm_property_create_range(crtc->dev,
420 DRM_MODE_PROP_IMMUTABLE, name, 0, 1);
Gopikrishnaiah Anandan41980b42016-06-21 16:01:33 -0700421 if (!prop) {
422 DRM_ERROR("property create failed: %s\n", name);
423 kfree(prop_node);
424 return;
425 }
426 priv->cp_property[feature] = prop;
427 }
428
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700429 INIT_PROP_ATTACH(&prop_attach, crtc, prop, prop_node,
430 feature, val);
Gopikrishnaiah Anandan41980b42016-06-21 16:01:33 -0700431 sde_cp_crtc_prop_attach(&prop_attach);
432}
433
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700434static void sde_cp_crtc_install_range_property(struct drm_crtc *crtc,
435 char *name,
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700436 u32 feature,
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700437 uint64_t min, uint64_t max,
438 uint64_t val)
439{
440 struct drm_property *prop;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700441 struct sde_cp_node *prop_node = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700442 struct msm_drm_private *priv;
443 struct sde_cp_prop_attach prop_attach;
444
445 if (feature >= SDE_CP_CRTC_MAX_FEATURES) {
446 DRM_ERROR("invalid feature %d max %d\n", feature,
447 SDE_CP_CRTC_MAX_FEATURES);
448 return;
449 }
450
451 prop_node = kzalloc(sizeof(*prop_node), GFP_KERNEL);
452 if (!prop_node)
453 return;
454
455 priv = crtc->dev->dev_private;
456 prop = priv->cp_property[feature];
457
458 if (!prop) {
459 prop = drm_property_create_range(crtc->dev, 0, name, min, max);
460 if (!prop) {
461 DRM_ERROR("property create failed: %s\n", name);
462 kfree(prop_node);
463 return;
464 }
465 priv->cp_property[feature] = prop;
466 }
467
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700468 INIT_PROP_ATTACH(&prop_attach, crtc, prop, prop_node,
469 feature, val);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700470
471 sde_cp_crtc_prop_attach(&prop_attach);
472}
473
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800474static void sde_cp_crtc_install_blob_property(struct drm_crtc *crtc, char *name,
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -0800475 u32 feature, u32 blob_sz)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700476{
477 struct drm_property *prop;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700478 struct sde_cp_node *prop_node = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700479 struct msm_drm_private *priv;
480 uint64_t val = 0;
481 struct sde_cp_prop_attach prop_attach;
482
483 if (feature >= SDE_CP_CRTC_MAX_FEATURES) {
484 DRM_ERROR("invalid feature %d max %d\n", feature,
485 SDE_CP_CRTC_MAX_FEATURES);
486 return;
487 }
488
489 prop_node = kzalloc(sizeof(*prop_node), GFP_KERNEL);
490 if (!prop_node)
491 return;
492
493 priv = crtc->dev->dev_private;
494 prop = priv->cp_property[feature];
495
496 if (!prop) {
497 prop = drm_property_create(crtc->dev,
498 DRM_MODE_PROP_BLOB, name, 0);
499 if (!prop) {
500 DRM_ERROR("property create failed: %s\n", name);
501 kfree(prop_node);
502 return;
503 }
504 priv->cp_property[feature] = prop;
505 }
506
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700507 INIT_PROP_ATTACH(&prop_attach, crtc, prop, prop_node,
508 feature, val);
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -0800509 prop_node->prop_blob_sz = blob_sz;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700510
511 sde_cp_crtc_prop_attach(&prop_attach);
512}
513
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800514static void sde_cp_crtc_install_enum_property(struct drm_crtc *crtc,
515 u32 feature, const struct drm_prop_enum_list *list, u32 enum_sz,
516 char *name)
517{
518 struct drm_property *prop;
519 struct sde_cp_node *prop_node = NULL;
520 struct msm_drm_private *priv;
521 uint64_t val = 0;
522 struct sde_cp_prop_attach prop_attach;
523
524 if (feature >= SDE_CP_CRTC_MAX_FEATURES) {
525 DRM_ERROR("invalid feature %d max %d\n", feature,
526 SDE_CP_CRTC_MAX_FEATURES);
527 return;
528 }
529
530 prop_node = kzalloc(sizeof(*prop_node), GFP_KERNEL);
531 if (!prop_node)
532 return;
533
534 priv = crtc->dev->dev_private;
535 prop = priv->cp_property[feature];
536
537 if (!prop) {
538 prop = drm_property_create_enum(crtc->dev, 0, name,
539 list, enum_sz);
540 if (!prop) {
541 DRM_ERROR("property create failed: %s\n", name);
542 kfree(prop_node);
543 return;
544 }
545 priv->cp_property[feature] = prop;
546 }
547
548 INIT_PROP_ATTACH(&prop_attach, crtc, prop, prop_node,
549 feature, val);
550
551 sde_cp_crtc_prop_attach(&prop_attach);
552}
553
Xu Yang5e53c2e2017-07-11 16:46:28 +0800554static struct sde_crtc_irq_info *_sde_cp_get_intr_node(u32 event,
555 struct sde_crtc *sde_crtc)
556{
557 bool found = false;
558 struct sde_crtc_irq_info *node = NULL;
559
560 list_for_each_entry(node, &sde_crtc->user_event_list, list) {
561 if (node->event == event) {
562 found = true;
563 break;
564 }
565 }
566
567 if (!found)
568 node = NULL;
569
570 return node;
571}
572
Xu Yang056d39b2017-07-11 16:34:13 +0800573static void _sde_cp_crtc_enable_hist_irq(struct sde_crtc *sde_crtc)
574{
575 struct drm_crtc *crtc_drm = &sde_crtc->base;
576 struct sde_kms *kms = NULL;
577 struct sde_hw_mixer *hw_lm;
578 struct sde_hw_dspp *hw_dspp = NULL;
Xu Yang5e53c2e2017-07-11 16:46:28 +0800579 struct sde_crtc_irq_info *node = NULL;
580 int i, irq_idx, ret = 0;
581 unsigned long flags;
Xu Yang056d39b2017-07-11 16:34:13 +0800582
583 if (!crtc_drm) {
584 DRM_ERROR("invalid crtc %pK\n", crtc_drm);
585 return;
586 }
587
588 kms = get_kms(crtc_drm);
589
590 for (i = 0; i < sde_crtc->num_mixers; i++) {
591 hw_lm = sde_crtc->mixers[i].hw_lm;
592 hw_dspp = sde_crtc->mixers[i].hw_dspp;
593 if (!hw_lm->cfg.right_mixer)
594 break;
595 }
596
597 if (!hw_dspp) {
598 DRM_ERROR("invalid dspp\n");
599 return;
600 }
601
602 irq_idx = sde_core_irq_idx_lookup(kms, SDE_IRQ_TYPE_HIST_DSPP_DONE,
603 hw_dspp->idx);
604 if (irq_idx < 0) {
605 DRM_ERROR("failed to get irq idx\n");
606 return;
607 }
Xu Yang5e53c2e2017-07-11 16:46:28 +0800608
609 spin_lock_irqsave(&sde_crtc->spin_lock, flags);
610 node = _sde_cp_get_intr_node(DRM_EVENT_HISTOGRAM, sde_crtc);
611 spin_unlock_irqrestore(&sde_crtc->spin_lock, flags);
612
613 if (!node)
614 return;
615
Xu Yanged79cec2018-01-10 21:04:05 +0800616 spin_lock_irqsave(&node->state_lock, flags);
Xu Yang5e53c2e2017-07-11 16:46:28 +0800617 if (node->state == IRQ_DISABLED) {
618 ret = sde_core_irq_enable(kms, &irq_idx, 1);
619 if (ret)
620 DRM_ERROR("failed to enable irq %d\n", irq_idx);
621 else
622 node->state = IRQ_ENABLED;
623 }
Xu Yanged79cec2018-01-10 21:04:05 +0800624 spin_unlock_irqrestore(&node->state_lock, flags);
Xu Yang056d39b2017-07-11 16:34:13 +0800625}
626
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700627static void sde_cp_crtc_setfeature(struct sde_cp_node *prop_node,
Gopikrishnaiah Anandandb90fa12017-05-09 17:56:08 -0700628 struct sde_crtc *sde_crtc)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700629{
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700630 struct sde_hw_cp_cfg hw_cfg;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700631 struct sde_hw_mixer *hw_lm;
632 struct sde_hw_dspp *hw_dspp;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700633 u32 num_mixers = sde_crtc->num_mixers;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700634 int i = 0;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700635 bool feature_enabled = false;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700636 int ret = 0;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800637 struct sde_ad_hw_cfg ad_cfg;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700638
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700639 sde_cp_get_hw_payload(prop_node, &hw_cfg, &feature_enabled);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800640 hw_cfg.num_of_mixers = sde_crtc->num_mixers;
Gopikrishnaiah Anandandb90fa12017-05-09 17:56:08 -0700641 hw_cfg.last_feature = 0;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700642
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700643 for (i = 0; i < num_mixers && !ret; i++) {
644 hw_lm = sde_crtc->mixers[i].hw_lm;
645 hw_dspp = sde_crtc->mixers[i].hw_dspp;
Xu Yangf9c76112017-12-08 14:36:50 +0800646 if (!hw_lm) {
647 ret = -EINVAL;
648 continue;
649 }
Gopikrishnaiah Anandanfbf75392017-01-16 10:43:36 -0800650 hw_cfg.ctl = sde_crtc->mixers[i].hw_ctl;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800651 hw_cfg.mixer_info = hw_lm;
Xu Yangf9c76112017-12-08 14:36:50 +0800652 hw_cfg.displayh = num_mixers * hw_lm->cfg.out_width;
653 hw_cfg.displayv = hw_lm->cfg.out_height;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700654 switch (prop_node->feature) {
655 case SDE_CP_CRTC_DSPP_VLUT:
656 if (!hw_dspp || !hw_dspp->ops.setup_vlut) {
657 ret = -EINVAL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700658 continue;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700659 }
660 hw_dspp->ops.setup_vlut(hw_dspp, &hw_cfg);
661 break;
662 case SDE_CP_CRTC_DSPP_PCC:
663 if (!hw_dspp || !hw_dspp->ops.setup_pcc) {
664 ret = -EINVAL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700665 continue;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700666 }
667 hw_dspp->ops.setup_pcc(hw_dspp, &hw_cfg);
668 break;
669 case SDE_CP_CRTC_DSPP_IGC:
670 if (!hw_dspp || !hw_dspp->ops.setup_igc) {
671 ret = -EINVAL;
672 continue;
673 }
674 hw_dspp->ops.setup_igc(hw_dspp, &hw_cfg);
675 break;
676 case SDE_CP_CRTC_DSPP_GC:
677 if (!hw_dspp || !hw_dspp->ops.setup_gc) {
678 ret = -EINVAL;
679 continue;
680 }
681 hw_dspp->ops.setup_gc(hw_dspp, &hw_cfg);
682 break;
Rajesh Yadav284947c2017-07-21 20:32:13 +0530683 case SDE_CP_CRTC_DSPP_HSIC:
684 if (!hw_dspp || !hw_dspp->ops.setup_pa_hsic) {
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700685 ret = -EINVAL;
686 continue;
687 }
Rajesh Yadav284947c2017-07-21 20:32:13 +0530688 hw_dspp->ops.setup_pa_hsic(hw_dspp, &hw_cfg);
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700689 break;
Rajesh Yadav7b8fbae2017-08-28 14:48:14 +0530690 case SDE_CP_CRTC_DSPP_MEMCOL_SKIN:
691 if (!hw_dspp || !hw_dspp->ops.setup_pa_memcol_skin) {
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700692 ret = -EINVAL;
693 continue;
Stephen Boyd22f7b512017-03-01 16:56:35 -0800694 }
Rajesh Yadav7b8fbae2017-08-28 14:48:14 +0530695 hw_dspp->ops.setup_pa_memcol_skin(hw_dspp, &hw_cfg);
696 break;
697 case SDE_CP_CRTC_DSPP_MEMCOL_SKY:
698 if (!hw_dspp || !hw_dspp->ops.setup_pa_memcol_sky) {
699 ret = -EINVAL;
700 continue;
701 }
702 hw_dspp->ops.setup_pa_memcol_sky(hw_dspp, &hw_cfg);
703 break;
704 case SDE_CP_CRTC_DSPP_MEMCOL_FOLIAGE:
705 if (!hw_dspp || !hw_dspp->ops.setup_pa_memcol_foliage) {
706 ret = -EINVAL;
707 continue;
708 }
709 hw_dspp->ops.setup_pa_memcol_foliage(hw_dspp, &hw_cfg);
710 break;
711 case SDE_CP_CRTC_DSPP_MEMCOL_PROT:
712 if (!hw_dspp || !hw_dspp->ops.setup_pa_memcol_prot) {
713 ret = -EINVAL;
714 continue;
715 }
716 hw_dspp->ops.setup_pa_memcol_prot(hw_dspp, &hw_cfg);
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700717 break;
718 case SDE_CP_CRTC_DSPP_SIXZONE:
719 if (!hw_dspp || !hw_dspp->ops.setup_sixzone) {
720 ret = -EINVAL;
721 continue;
722 }
723 hw_dspp->ops.setup_sixzone(hw_dspp, &hw_cfg);
724 break;
725 case SDE_CP_CRTC_DSPP_GAMUT:
726 if (!hw_dspp || !hw_dspp->ops.setup_gamut) {
727 ret = -EINVAL;
728 continue;
729 }
730 hw_dspp->ops.setup_gamut(hw_dspp, &hw_cfg);
731 break;
732 case SDE_CP_CRTC_LM_GC:
Xu Yangf9c76112017-12-08 14:36:50 +0800733 if (!hw_lm->ops.setup_gc) {
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700734 ret = -EINVAL;
735 continue;
736 }
737 hw_lm->ops.setup_gc(hw_lm, &hw_cfg);
738 break;
Xu Yang056d39b2017-07-11 16:34:13 +0800739 case SDE_CP_CRTC_DSPP_HIST_CTRL:
740 if (!hw_dspp || !hw_dspp->ops.setup_histogram) {
741 ret = -EINVAL;
742 continue;
743 }
744 hw_dspp->ops.setup_histogram(hw_dspp, &feature_enabled);
745 break;
746 case SDE_CP_CRTC_DSPP_HIST_IRQ:
Xu Yangf9c76112017-12-08 14:36:50 +0800747 if (!hw_dspp) {
Xu Yang056d39b2017-07-11 16:34:13 +0800748 ret = -EINVAL;
749 continue;
750 }
751 if (!hw_lm->cfg.right_mixer)
752 _sde_cp_crtc_enable_hist_irq(sde_crtc);
753 break;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800754 case SDE_CP_CRTC_DSPP_AD_MODE:
755 if (!hw_dspp || !hw_dspp->ops.setup_ad) {
756 ret = -EINVAL;
757 continue;
758 }
759 ad_cfg.prop = AD_MODE;
760 ad_cfg.hw_cfg = &hw_cfg;
761 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
762 break;
763 case SDE_CP_CRTC_DSPP_AD_INIT:
764 if (!hw_dspp || !hw_dspp->ops.setup_ad) {
765 ret = -EINVAL;
766 continue;
767 }
768 ad_cfg.prop = AD_INIT;
769 ad_cfg.hw_cfg = &hw_cfg;
770 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
771 break;
772 case SDE_CP_CRTC_DSPP_AD_CFG:
773 if (!hw_dspp || !hw_dspp->ops.setup_ad) {
774 ret = -EINVAL;
775 continue;
776 }
777 ad_cfg.prop = AD_CFG;
778 ad_cfg.hw_cfg = &hw_cfg;
779 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
780 break;
781 case SDE_CP_CRTC_DSPP_AD_INPUT:
782 if (!hw_dspp || !hw_dspp->ops.setup_ad) {
783 ret = -EINVAL;
784 continue;
785 }
786 ad_cfg.prop = AD_INPUT;
787 ad_cfg.hw_cfg = &hw_cfg;
788 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
789 break;
790 case SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS:
791 if (!hw_dspp || !hw_dspp->ops.setup_ad) {
792 ret = -EINVAL;
793 continue;
794 }
795 ad_cfg.prop = AD_ASSERTIVE;
796 ad_cfg.hw_cfg = &hw_cfg;
797 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
798 break;
799 case SDE_CP_CRTC_DSPP_AD_BACKLIGHT:
800 if (!hw_dspp || !hw_dspp->ops.setup_ad) {
801 ret = -EINVAL;
802 continue;
803 }
804 ad_cfg.prop = AD_BACKLIGHT;
805 ad_cfg.hw_cfg = &hw_cfg;
806 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
807 break;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700808 default:
809 ret = -EINVAL;
810 break;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700811 }
812 }
813
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700814 if (ret) {
815 DRM_ERROR("failed to %s feature %d\n",
816 ((feature_enabled) ? "enable" : "disable"),
817 prop_node->feature);
818 return;
819 }
820
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700821 if (feature_enabled) {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700822 DRM_DEBUG_DRIVER("Add feature to active list %d\n",
823 prop_node->property_id);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800824 sde_cp_update_list(prop_node, sde_crtc, false);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700825 } else {
826 DRM_DEBUG_DRIVER("remove feature from active list %d\n",
827 prop_node->property_id);
828 list_del_init(&prop_node->active_list);
829 }
830 /* Programming of feature done remove from dirty list */
831 list_del_init(&prop_node->dirty_list);
832}
833
834void sde_cp_crtc_apply_properties(struct drm_crtc *crtc)
835{
836 struct sde_crtc *sde_crtc = NULL;
837 bool set_dspp_flush = false, set_lm_flush = false;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700838 struct sde_cp_node *prop_node = NULL, *n = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700839 struct sde_hw_ctl *ctl;
840 uint32_t flush_mask = 0;
841 u32 num_mixers = 0, i = 0;
842
843 if (!crtc || !crtc->dev) {
844 DRM_ERROR("invalid crtc %pK dev %pK\n", crtc,
845 (crtc ? crtc->dev : NULL));
846 return;
847 }
848
849 sde_crtc = to_sde_crtc(crtc);
850 if (!sde_crtc) {
851 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
852 return;
853 }
854
855 num_mixers = sde_crtc->num_mixers;
856 if (!num_mixers) {
857 DRM_DEBUG_DRIVER("no mixers for this crtc\n");
858 return;
859 }
860
Xu Yang1b3a5d92017-09-13 11:37:54 +0800861 mutex_lock(&sde_crtc->crtc_cp_lock);
862
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800863 /* Check if dirty lists are empty and ad features are disabled for
864 * early return. If ad properties are active then we need to issue
865 * dspp flush.
866 **/
867 if (list_empty(&sde_crtc->dirty_list) &&
868 list_empty(&sde_crtc->ad_dirty)) {
869 if (list_empty(&sde_crtc->ad_active)) {
870 DRM_DEBUG_DRIVER("Dirty list is empty\n");
Xu Yang1b3a5d92017-09-13 11:37:54 +0800871 goto exit;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800872 }
Ping Lie505f3b2017-06-19 14:19:08 -0700873 sde_cp_ad_set_prop(sde_crtc, AD_IPC_RESET);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800874 set_dspp_flush = true;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700875 }
876
877 list_for_each_entry_safe(prop_node, n, &sde_crtc->dirty_list,
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800878 dirty_list) {
Gopikrishnaiah Anandandb90fa12017-05-09 17:56:08 -0700879 sde_cp_crtc_setfeature(prop_node, sde_crtc);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700880 /* Set the flush flag to true */
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700881 if (prop_node->is_dspp_feature)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700882 set_dspp_flush = true;
883 else
884 set_lm_flush = true;
885 }
886
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800887 list_for_each_entry_safe(prop_node, n, &sde_crtc->ad_dirty,
888 dirty_list) {
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800889 set_dspp_flush = true;
Gopikrishnaiah Anandandb90fa12017-05-09 17:56:08 -0700890 sde_cp_crtc_setfeature(prop_node, sde_crtc);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800891 }
892
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700893 for (i = 0; i < num_mixers; i++) {
894 ctl = sde_crtc->mixers[i].hw_ctl;
895 if (!ctl)
896 continue;
897 if (set_dspp_flush && ctl->ops.get_bitmask_dspp
Stephen Boyd22f7b512017-03-01 16:56:35 -0800898 && sde_crtc->mixers[i].hw_dspp) {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700899 ctl->ops.get_bitmask_dspp(ctl,
900 &flush_mask,
901 sde_crtc->mixers[i].hw_dspp->idx);
902 ctl->ops.update_pending_flush(ctl, flush_mask);
Stephen Boyd22f7b512017-03-01 16:56:35 -0800903 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700904 if (set_lm_flush && ctl->ops.get_bitmask_mixer
Stephen Boyd22f7b512017-03-01 16:56:35 -0800905 && sde_crtc->mixers[i].hw_lm) {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700906 flush_mask = ctl->ops.get_bitmask_mixer(ctl,
907 sde_crtc->mixers[i].hw_lm->idx);
908 ctl->ops.update_pending_flush(ctl, flush_mask);
Stephen Boyd22f7b512017-03-01 16:56:35 -0800909 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700910 }
Xu Yang1b3a5d92017-09-13 11:37:54 +0800911exit:
912 mutex_unlock(&sde_crtc->crtc_cp_lock);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700913}
914
915void sde_cp_crtc_install_properties(struct drm_crtc *crtc)
916{
917 struct sde_kms *kms = NULL;
918 struct sde_crtc *sde_crtc = NULL;
919 struct sde_mdss_cfg *catalog = NULL;
920 unsigned long features = 0;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700921 int i = 0;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700922 struct msm_drm_private *priv;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700923
924 if (!crtc || !crtc->dev || !crtc->dev->dev_private) {
925 DRM_ERROR("invalid crtc %pK dev %pK\n",
926 crtc, ((crtc) ? crtc->dev : NULL));
927 return;
928 }
929
930 sde_crtc = to_sde_crtc(crtc);
Gopikrishnaiah Anandan7f6ef942016-06-20 15:50:00 -0700931 if (!sde_crtc) {
932 DRM_ERROR("sde_crtc %pK\n", sde_crtc);
933 return;
934 }
935
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700936 kms = get_kms(crtc);
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700937 if (!kms || !kms->catalog) {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700938 DRM_ERROR("invalid sde kms %pK catalog %pK sde_crtc %pK\n",
939 kms, ((kms) ? kms->catalog : NULL), sde_crtc);
940 return;
941 }
942
Xu Yang1b3a5d92017-09-13 11:37:54 +0800943 mutex_lock(&sde_crtc->crtc_cp_lock);
944
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700945 /**
946 * Function can be called during the atomic_check with test_only flag
947 * and actual commit. Allocate properties only if feature list is
948 * empty during the atomic_check with test_only flag.
949 */
950 if (!list_empty(&sde_crtc->feature_list))
Xu Yang1b3a5d92017-09-13 11:37:54 +0800951 goto exit;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700952
953 catalog = kms->catalog;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700954 priv = crtc->dev->dev_private;
955 /**
956 * DSPP/LM properties are global to all the CRTCS.
957 * Properties are created for first CRTC and re-used for later
958 * crtcs.
959 */
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -0700960 if (!priv->cp_property) {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700961 priv->cp_property = kzalloc((sizeof(priv->cp_property) *
962 SDE_CP_CRTC_MAX_FEATURES), GFP_KERNEL);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -0700963 setup_dspp_prop_install_funcs(dspp_prop_install_func);
964 setup_lm_prop_install_funcs(lm_prop_install_func);
965 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700966 if (!priv->cp_property)
Xu Yang1b3a5d92017-09-13 11:37:54 +0800967 goto exit;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700968
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700969 if (!catalog->dspp_count)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700970 goto lm_property;
971
972 /* Check for all the DSPP properties and attach it to CRTC */
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700973 features = catalog->dspp[0].features;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700974 for (i = 0; i < SDE_DSPP_MAX; i++) {
975 if (!test_bit(i, &features))
976 continue;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -0700977 if (dspp_prop_install_func[i])
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700978 dspp_prop_install_func[i](crtc);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700979 }
980
981lm_property:
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700982 if (!catalog->mixer_count)
Xu Yang1b3a5d92017-09-13 11:37:54 +0800983 goto exit;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700984
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700985 /* Check for all the LM properties and attach it to CRTC */
986 features = catalog->mixer[0].features;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700987 for (i = 0; i < SDE_MIXER_MAX; i++) {
988 if (!test_bit(i, &features))
989 continue;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -0700990 if (lm_prop_install_func[i])
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700991 lm_prop_install_func[i](crtc);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700992 }
Xu Yang1b3a5d92017-09-13 11:37:54 +0800993exit:
994 mutex_unlock(&sde_crtc->crtc_cp_lock);
995
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700996}
997
998int sde_cp_crtc_set_property(struct drm_crtc *crtc,
999 struct drm_property *property,
1000 uint64_t val)
1001{
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -07001002 struct sde_cp_node *prop_node = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001003 struct sde_crtc *sde_crtc = NULL;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001004 int ret = 0, i = 0, dspp_cnt, lm_cnt;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001005 u8 found = 0;
1006
1007 if (!crtc || !property) {
1008 DRM_ERROR("invalid crtc %pK property %pK\n", crtc, property);
1009 return -EINVAL;
1010 }
1011
1012 sde_crtc = to_sde_crtc(crtc);
1013 if (!sde_crtc) {
1014 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
1015 return -EINVAL;
1016 }
1017
Xu Yang1b3a5d92017-09-13 11:37:54 +08001018 mutex_lock(&sde_crtc->crtc_cp_lock);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001019 list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) {
1020 if (property->base.id == prop_node->property_id) {
1021 found = 1;
1022 break;
1023 }
1024 }
1025
Lloyd Atkinsonadd42952017-10-31 14:27:55 -04001026 if (!found) {
1027 ret = -ENOENT;
Xu Yang1b3a5d92017-09-13 11:37:54 +08001028 goto exit;
Lloyd Atkinsonadd42952017-10-31 14:27:55 -04001029 }
Xu Yang1b3a5d92017-09-13 11:37:54 +08001030
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001031 /**
1032 * sde_crtc is virtual ensure that hardware has been attached to the
1033 * crtc. Check LM and dspp counts based on whether feature is a
1034 * dspp/lm feature.
1035 */
1036 if (!sde_crtc->num_mixers ||
1037 sde_crtc->num_mixers > ARRAY_SIZE(sde_crtc->mixers)) {
Xu Yangcbbefd72017-12-14 14:44:00 +08001038 DRM_INFO("Invalid mixer config act cnt %d max cnt %ld\n",
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001039 sde_crtc->num_mixers, ARRAY_SIZE(sde_crtc->mixers));
Xu Yang7e52b172017-10-26 14:28:23 +08001040 ret = -EPERM;
Xu Yang1b3a5d92017-09-13 11:37:54 +08001041 goto exit;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001042 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001043
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001044 dspp_cnt = 0;
1045 lm_cnt = 0;
1046 for (i = 0; i < sde_crtc->num_mixers; i++) {
1047 if (sde_crtc->mixers[i].hw_dspp)
1048 dspp_cnt++;
1049 if (sde_crtc->mixers[i].hw_lm)
1050 lm_cnt++;
1051 }
1052
1053 if (prop_node->is_dspp_feature && dspp_cnt < sde_crtc->num_mixers) {
1054 DRM_ERROR("invalid dspp cnt %d mixer cnt %d\n", dspp_cnt,
1055 sde_crtc->num_mixers);
Xu Yang1b3a5d92017-09-13 11:37:54 +08001056 ret = -EINVAL;
1057 goto exit;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001058 } else if (lm_cnt < sde_crtc->num_mixers) {
1059 DRM_ERROR("invalid lm cnt %d mixer cnt %d\n", lm_cnt,
1060 sde_crtc->num_mixers);
Xu Yang1b3a5d92017-09-13 11:37:54 +08001061 ret = -EINVAL;
1062 goto exit;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001063 }
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001064
1065 ret = sde_cp_ad_validate_prop(prop_node, sde_crtc);
1066 if (ret) {
1067 DRM_ERROR("ad property validation failed ret %d\n", ret);
Xu Yang1b3a5d92017-09-13 11:37:54 +08001068 goto exit;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001069 }
1070
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001071 /* remove the property from dirty list */
1072 list_del_init(&prop_node->dirty_list);
1073
1074 if (!val)
1075 ret = sde_cp_disable_crtc_property(crtc, property, prop_node);
1076 else
1077 ret = sde_cp_enable_crtc_property(crtc, property,
1078 prop_node, val);
1079
1080 if (!ret) {
1081 /* remove the property from active list */
1082 list_del_init(&prop_node->active_list);
1083 /* Mark the feature as dirty */
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001084 sde_cp_update_list(prop_node, sde_crtc, true);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001085 }
Xu Yang1b3a5d92017-09-13 11:37:54 +08001086exit:
1087 mutex_unlock(&sde_crtc->crtc_cp_lock);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001088 return ret;
1089}
1090
1091int sde_cp_crtc_get_property(struct drm_crtc *crtc,
1092 struct drm_property *property, uint64_t *val)
1093{
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -07001094 struct sde_cp_node *prop_node = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001095 struct sde_crtc *sde_crtc = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001096
1097 if (!crtc || !property || !val) {
1098 DRM_ERROR("invalid crtc %pK property %pK val %pK\n",
1099 crtc, property, val);
1100 return -EINVAL;
1101 }
1102
1103 sde_crtc = to_sde_crtc(crtc);
1104 if (!sde_crtc) {
1105 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
1106 return -EINVAL;
1107 }
Gopikrishnaiah Anandand120b762016-10-05 12:03:42 -07001108 /* Return 0 if property is not supported */
1109 *val = 0;
Xu Yang1b3a5d92017-09-13 11:37:54 +08001110 mutex_lock(&sde_crtc->crtc_cp_lock);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001111 list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) {
1112 if (property->base.id == prop_node->property_id) {
1113 *val = prop_node->prop_val;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001114 break;
1115 }
1116 }
Xu Yang1b3a5d92017-09-13 11:37:54 +08001117 mutex_unlock(&sde_crtc->crtc_cp_lock);
Gopikrishnaiah Anandand120b762016-10-05 12:03:42 -07001118 return 0;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001119}
1120
1121void sde_cp_crtc_destroy_properties(struct drm_crtc *crtc)
1122{
1123 struct sde_crtc *sde_crtc = NULL;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -07001124 struct sde_cp_node *prop_node = NULL, *n = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001125
1126 if (!crtc) {
1127 DRM_ERROR("invalid crtc %pK\n", crtc);
1128 return;
1129 }
1130
1131 sde_crtc = to_sde_crtc(crtc);
1132 if (!sde_crtc) {
1133 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
1134 return;
1135 }
1136
1137 list_for_each_entry_safe(prop_node, n, &sde_crtc->feature_list,
1138 feature_list) {
1139 if (prop_node->prop_flags & DRM_MODE_PROP_BLOB
1140 && prop_node->blob_ptr)
1141 drm_property_unreference_blob(prop_node->blob_ptr);
1142
1143 list_del_init(&prop_node->active_list);
1144 list_del_init(&prop_node->dirty_list);
1145 list_del_init(&prop_node->feature_list);
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -07001146 sde_cp_destroy_local_blob(prop_node);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001147 kfree(prop_node);
1148 }
1149
Xu Yang5e53c2e2017-07-11 16:46:28 +08001150 if (sde_crtc->hist_blob)
1151 drm_property_unreference_blob(sde_crtc->hist_blob);
1152
Xu Yang1b3a5d92017-09-13 11:37:54 +08001153 mutex_destroy(&sde_crtc->crtc_cp_lock);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001154 INIT_LIST_HEAD(&sde_crtc->active_list);
1155 INIT_LIST_HEAD(&sde_crtc->dirty_list);
1156 INIT_LIST_HEAD(&sde_crtc->feature_list);
1157}
Gopikrishnaiah Anandan7f6ef942016-06-20 15:50:00 -07001158
1159void sde_cp_crtc_suspend(struct drm_crtc *crtc)
1160{
1161 struct sde_crtc *sde_crtc = NULL;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -07001162 struct sde_cp_node *prop_node = NULL, *n = NULL;
Gopikrishnaiah Anandan7f6ef942016-06-20 15:50:00 -07001163
1164 if (!crtc) {
1165 DRM_ERROR("crtc %pK\n", crtc);
1166 return;
1167 }
1168 sde_crtc = to_sde_crtc(crtc);
1169 if (!sde_crtc) {
1170 DRM_ERROR("sde_crtc %pK\n", sde_crtc);
1171 return;
1172 }
1173
Xu Yang1b3a5d92017-09-13 11:37:54 +08001174 mutex_lock(&sde_crtc->crtc_cp_lock);
Gopikrishnaiah Anandan7f6ef942016-06-20 15:50:00 -07001175 list_for_each_entry_safe(prop_node, n, &sde_crtc->active_list,
1176 active_list) {
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001177 sde_cp_update_list(prop_node, sde_crtc, true);
Gopikrishnaiah Anandan7f6ef942016-06-20 15:50:00 -07001178 list_del_init(&prop_node->active_list);
1179 }
Ping Li6d5bf542017-06-27 11:40:28 -07001180
1181 list_for_each_entry_safe(prop_node, n, &sde_crtc->ad_active,
1182 active_list) {
1183 sde_cp_update_list(prop_node, sde_crtc, true);
1184 list_del_init(&prop_node->active_list);
1185 }
Xu Yang1b3a5d92017-09-13 11:37:54 +08001186 mutex_unlock(&sde_crtc->crtc_cp_lock);
Gopikrishnaiah Anandan7f6ef942016-06-20 15:50:00 -07001187}
1188
1189void sde_cp_crtc_resume(struct drm_crtc *crtc)
1190{
1191 /* placeholder for operations needed during resume */
1192}
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001193
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001194static void dspp_pcc_install_property(struct drm_crtc *crtc)
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001195{
1196 char feature_name[256];
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001197 struct sde_kms *kms = NULL;
1198 struct sde_mdss_cfg *catalog = NULL;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001199 u32 version;
1200
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001201 kms = get_kms(crtc);
1202 catalog = kms->catalog;
1203
1204 version = catalog->dspp[0].sblk->pcc.version >> 16;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001205 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1206 "SDE_DSPP_PCC_V", version);
1207 switch (version) {
1208 case 1:
Rajesh Yadavd490cb62017-07-04 13:20:42 +05301209 case 4:
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001210 sde_cp_crtc_install_blob_property(crtc, feature_name,
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -08001211 SDE_CP_CRTC_DSPP_PCC, sizeof(struct drm_msm_pcc));
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001212 break;
1213 default:
1214 DRM_ERROR("version %d not supported\n", version);
1215 break;
1216 }
1217}
1218
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001219static void dspp_hsic_install_property(struct drm_crtc *crtc)
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001220{
1221 char feature_name[256];
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001222 struct sde_kms *kms = NULL;
1223 struct sde_mdss_cfg *catalog = NULL;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001224 u32 version;
1225
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001226 kms = get_kms(crtc);
1227 catalog = kms->catalog;
1228 version = catalog->dspp[0].sblk->hsic.version >> 16;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001229 switch (version) {
1230 case 1:
1231 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
Rajesh Yadav284947c2017-07-21 20:32:13 +05301232 "SDE_DSPP_PA_HSIC_V", version);
1233 sde_cp_crtc_install_blob_property(crtc, feature_name,
1234 SDE_CP_CRTC_DSPP_HSIC, sizeof(struct drm_msm_pa_hsic));
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001235 break;
1236 default:
1237 DRM_ERROR("version %d not supported\n", version);
1238 break;
1239 }
1240}
1241
Rajesh Yadav7b8fbae2017-08-28 14:48:14 +05301242static void dspp_memcolor_install_property(struct drm_crtc *crtc)
1243{
1244 char feature_name[256];
1245 struct sde_kms *kms = NULL;
1246 struct sde_mdss_cfg *catalog = NULL;
1247 u32 version;
1248
1249 kms = get_kms(crtc);
1250 catalog = kms->catalog;
1251 version = catalog->dspp[0].sblk->memcolor.version >> 16;
1252 switch (version) {
1253 case 1:
1254 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1255 "SDE_DSPP_PA_MEMCOL_SKIN_V", version);
1256 sde_cp_crtc_install_blob_property(crtc, feature_name,
1257 SDE_CP_CRTC_DSPP_MEMCOL_SKIN,
1258 sizeof(struct drm_msm_memcol));
1259 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1260 "SDE_DSPP_PA_MEMCOL_SKY_V", version);
1261 sde_cp_crtc_install_blob_property(crtc, feature_name,
1262 SDE_CP_CRTC_DSPP_MEMCOL_SKY,
1263 sizeof(struct drm_msm_memcol));
1264 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1265 "SDE_DSPP_PA_MEMCOL_FOLIAGE_V", version);
1266 sde_cp_crtc_install_blob_property(crtc, feature_name,
1267 SDE_CP_CRTC_DSPP_MEMCOL_FOLIAGE,
1268 sizeof(struct drm_msm_memcol));
1269 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1270 "SDE_DSPP_PA_MEMCOL_PROT_V", version);
1271 sde_cp_crtc_install_blob_property(crtc, feature_name,
1272 SDE_CP_CRTC_DSPP_MEMCOL_PROT,
1273 sizeof(struct drm_msm_memcol));
1274 break;
1275 default:
1276 DRM_ERROR("version %d not supported\n", version);
1277 break;
1278 }
1279}
1280
Rajesh Yadav0a92eea2017-07-18 18:18:55 +05301281static void dspp_sixzone_install_property(struct drm_crtc *crtc)
1282{
1283 char feature_name[256];
1284 struct sde_kms *kms = NULL;
1285 struct sde_mdss_cfg *catalog = NULL;
1286 u32 version;
1287
1288 kms = get_kms(crtc);
1289 catalog = kms->catalog;
1290 version = catalog->dspp[0].sblk->sixzone.version >> 16;
1291 switch (version) {
1292 case 1:
1293 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1294 "SDE_DSPP_PA_SIXZONE_V", version);
1295 sde_cp_crtc_install_blob_property(crtc, feature_name,
1296 SDE_CP_CRTC_DSPP_SIXZONE,
1297 sizeof(struct drm_msm_sixzone));
1298 break;
1299 default:
1300 DRM_ERROR("version %d not supported\n", version);
1301 break;
1302 }
1303}
1304
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001305static void dspp_vlut_install_property(struct drm_crtc *crtc)
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001306{
1307 char feature_name[256];
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001308 struct sde_kms *kms = NULL;
1309 struct sde_mdss_cfg *catalog = NULL;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001310 u32 version;
1311
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001312 kms = get_kms(crtc);
1313 catalog = kms->catalog;
1314 version = catalog->dspp[0].sblk->vlut.version >> 16;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001315 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1316 "SDE_DSPP_VLUT_V", version);
1317 switch (version) {
1318 case 1:
1319 sde_cp_crtc_install_range_property(crtc, feature_name,
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001320 SDE_CP_CRTC_DSPP_VLUT, 0, U64_MAX, 0);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001321 sde_cp_create_local_blob(crtc,
1322 SDE_CP_CRTC_DSPP_VLUT,
1323 sizeof(struct drm_msm_pa_vlut));
1324 break;
1325 default:
1326 DRM_ERROR("version %d not supported\n", version);
1327 break;
1328 }
1329}
1330
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001331static void dspp_ad_install_property(struct drm_crtc *crtc)
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001332{
1333 char feature_name[256];
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001334 struct sde_kms *kms = NULL;
1335 struct sde_mdss_cfg *catalog = NULL;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001336 u32 version;
1337
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001338 kms = get_kms(crtc);
1339 catalog = kms->catalog;
1340 version = catalog->dspp[0].sblk->ad.version >> 16;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001341 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1342 "SDE_DSPP_AD_V", version);
1343 switch (version) {
1344 case 3:
1345 sde_cp_crtc_install_immutable_property(crtc,
1346 feature_name, SDE_CP_CRTC_DSPP_AD);
1347 break;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001348 case 4:
1349 sde_cp_crtc_install_immutable_property(crtc,
1350 feature_name, SDE_CP_CRTC_DSPP_AD);
1351
1352 sde_cp_crtc_install_enum_property(crtc,
1353 SDE_CP_CRTC_DSPP_AD_MODE, ad4_modes,
1354 ARRAY_SIZE(ad4_modes), "SDE_DSPP_AD_V4_MODE");
1355
1356 sde_cp_crtc_install_range_property(crtc, "SDE_DSPP_AD_V4_INIT",
1357 SDE_CP_CRTC_DSPP_AD_INIT, 0, U64_MAX, 0);
1358 sde_cp_create_local_blob(crtc, SDE_CP_CRTC_DSPP_AD_INIT,
1359 sizeof(struct drm_msm_ad4_init));
1360
1361 sde_cp_crtc_install_range_property(crtc, "SDE_DSPP_AD_V4_CFG",
1362 SDE_CP_CRTC_DSPP_AD_CFG, 0, U64_MAX, 0);
1363 sde_cp_create_local_blob(crtc, SDE_CP_CRTC_DSPP_AD_CFG,
1364 sizeof(struct drm_msm_ad4_cfg));
1365 sde_cp_crtc_install_range_property(crtc,
Ping Lif41c2ef2017-05-04 14:40:45 -07001366 "SDE_DSPP_AD_V4_ASSERTIVENESS",
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001367 SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS, 0, (BIT(8) - 1), 0);
1368 sde_cp_crtc_install_range_property(crtc, "SDE_DSPP_AD_V4_INPUT",
1369 SDE_CP_CRTC_DSPP_AD_INPUT, 0, U16_MAX, 0);
1370 sde_cp_crtc_install_range_property(crtc,
1371 "SDE_DSPP_AD_V4_BACKLIGHT",
1372 SDE_CP_CRTC_DSPP_AD_BACKLIGHT, 0, (BIT(16) - 1),
1373 0);
1374 break;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001375 default:
1376 DRM_ERROR("version %d not supported\n", version);
1377 break;
1378 }
1379}
1380
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001381static void lm_gc_install_property(struct drm_crtc *crtc)
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001382{
1383 char feature_name[256];
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001384 struct sde_kms *kms = NULL;
1385 struct sde_mdss_cfg *catalog = NULL;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001386 u32 version;
1387
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001388 kms = get_kms(crtc);
1389 catalog = kms->catalog;
1390 version = catalog->mixer[0].sblk->gc.version >> 16;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001391 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1392 "SDE_LM_GC_V", version);
1393 switch (version) {
1394 case 1:
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001395 sde_cp_crtc_install_blob_property(crtc, feature_name,
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -08001396 SDE_CP_CRTC_LM_GC, sizeof(struct drm_msm_pgc_lut));
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001397 break;
1398 default:
1399 DRM_ERROR("version %d not supported\n", version);
1400 break;
1401 }
1402}
Gopikrishnaiah Anandanfbf75392017-01-16 10:43:36 -08001403
1404static void dspp_gamut_install_property(struct drm_crtc *crtc)
1405{
1406 char feature_name[256];
1407 struct sde_kms *kms = NULL;
1408 struct sde_mdss_cfg *catalog = NULL;
1409 u32 version;
1410
1411 kms = get_kms(crtc);
1412 catalog = kms->catalog;
1413
1414 version = catalog->dspp[0].sblk->gamut.version >> 16;
1415 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1416 "SDE_DSPP_GAMUT_V", version);
1417 switch (version) {
1418 case 4:
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001419 sde_cp_crtc_install_blob_property(crtc, feature_name,
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -08001420 SDE_CP_CRTC_DSPP_GAMUT,
1421 sizeof(struct drm_msm_3d_gamut));
Gopikrishnaiah Anandanfbf75392017-01-16 10:43:36 -08001422 break;
1423 default:
1424 DRM_ERROR("version %d not supported\n", version);
1425 break;
1426 }
1427}
1428
1429static void dspp_gc_install_property(struct drm_crtc *crtc)
1430{
1431 char feature_name[256];
1432 struct sde_kms *kms = NULL;
1433 struct sde_mdss_cfg *catalog = NULL;
1434 u32 version;
1435
1436 kms = get_kms(crtc);
1437 catalog = kms->catalog;
1438
1439 version = catalog->dspp[0].sblk->gc.version >> 16;
1440 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1441 "SDE_DSPP_GC_V", version);
1442 switch (version) {
1443 case 1:
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001444 sde_cp_crtc_install_blob_property(crtc, feature_name,
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -08001445 SDE_CP_CRTC_DSPP_GC, sizeof(struct drm_msm_pgc_lut));
Gopikrishnaiah Anandanfbf75392017-01-16 10:43:36 -08001446 break;
1447 default:
1448 DRM_ERROR("version %d not supported\n", version);
1449 break;
1450 }
1451}
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001452
Rajesh Yadavec93afb2017-06-08 19:28:33 +05301453static void dspp_igc_install_property(struct drm_crtc *crtc)
1454{
1455 char feature_name[256];
1456 struct sde_kms *kms = NULL;
1457 struct sde_mdss_cfg *catalog = NULL;
1458 u32 version;
1459
1460 kms = get_kms(crtc);
1461 catalog = kms->catalog;
1462
1463 version = catalog->dspp[0].sblk->igc.version >> 16;
1464 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1465 "SDE_DSPP_IGC_V", version);
1466 switch (version) {
1467 case 3:
1468 sde_cp_crtc_install_blob_property(crtc, feature_name,
1469 SDE_CP_CRTC_DSPP_IGC, sizeof(struct drm_msm_igc_lut));
1470 break;
1471 default:
1472 DRM_ERROR("version %d not supported\n", version);
1473 break;
1474 }
1475}
1476
Xu Yang056d39b2017-07-11 16:34:13 +08001477static void dspp_hist_install_property(struct drm_crtc *crtc)
1478{
1479 struct sde_kms *kms = NULL;
1480 struct sde_mdss_cfg *catalog = NULL;
1481 u32 version;
1482
1483 kms = get_kms(crtc);
1484 catalog = kms->catalog;
1485
1486 version = catalog->dspp[0].sblk->hist.version >> 16;
1487 switch (version) {
1488 case 1:
1489 sde_cp_crtc_install_enum_property(crtc,
1490 SDE_CP_CRTC_DSPP_HIST_CTRL, sde_hist_modes,
1491 ARRAY_SIZE(sde_hist_modes), "SDE_DSPP_HIST_CTRL_V1");
1492 sde_cp_crtc_install_range_property(crtc, "SDE_DSPP_HIST_IRQ_V1",
1493 SDE_CP_CRTC_DSPP_HIST_IRQ, 0, U16_MAX, 0);
1494 break;
1495 default:
1496 DRM_ERROR("version %d not supported\n", version);
1497 break;
1498 }
1499}
1500
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001501static void sde_cp_update_list(struct sde_cp_node *prop_node,
1502 struct sde_crtc *crtc, bool dirty_list)
1503{
1504 switch (prop_node->feature) {
1505 case SDE_CP_CRTC_DSPP_AD_MODE:
1506 case SDE_CP_CRTC_DSPP_AD_INIT:
1507 case SDE_CP_CRTC_DSPP_AD_CFG:
1508 case SDE_CP_CRTC_DSPP_AD_INPUT:
1509 case SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS:
1510 case SDE_CP_CRTC_DSPP_AD_BACKLIGHT:
1511 if (dirty_list)
1512 list_add_tail(&prop_node->dirty_list, &crtc->ad_dirty);
1513 else
1514 list_add_tail(&prop_node->active_list,
1515 &crtc->ad_active);
1516 break;
1517 default:
1518 /* color processing properties handle here */
1519 if (dirty_list)
1520 list_add_tail(&prop_node->dirty_list,
1521 &crtc->dirty_list);
1522 else
1523 list_add_tail(&prop_node->active_list,
1524 &crtc->active_list);
1525 break;
1526 };
1527}
1528
1529static int sde_cp_ad_validate_prop(struct sde_cp_node *prop_node,
1530 struct sde_crtc *crtc)
1531{
1532 int i = 0, ret = 0;
1533 u32 ad_prop;
1534
1535 for (i = 0; i < crtc->num_mixers && !ret; i++) {
1536 if (!crtc->mixers[i].hw_dspp) {
1537 ret = -EINVAL;
1538 continue;
1539 }
1540 switch (prop_node->feature) {
1541 case SDE_CP_CRTC_DSPP_AD_MODE:
1542 ad_prop = AD_MODE;
1543 break;
1544 case SDE_CP_CRTC_DSPP_AD_INIT:
1545 ad_prop = AD_INIT;
1546 break;
1547 case SDE_CP_CRTC_DSPP_AD_CFG:
1548 ad_prop = AD_CFG;
1549 break;
1550 case SDE_CP_CRTC_DSPP_AD_INPUT:
1551 ad_prop = AD_INPUT;
1552 break;
1553 case SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS:
1554 ad_prop = AD_ASSERTIVE;
1555 break;
1556 case SDE_CP_CRTC_DSPP_AD_BACKLIGHT:
1557 ad_prop = AD_BACKLIGHT;
1558 break;
1559 default:
1560 /* Not an AD property */
1561 return 0;
1562 }
1563 if (!crtc->mixers[i].hw_dspp->ops.validate_ad)
1564 ret = -EINVAL;
1565 else
1566 ret = crtc->mixers[i].hw_dspp->ops.validate_ad(
1567 crtc->mixers[i].hw_dspp, &ad_prop);
1568 }
1569 return ret;
1570}
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001571
1572static void sde_cp_ad_interrupt_cb(void *arg, int irq_idx)
1573{
1574 struct sde_crtc *crtc = arg;
Gopikrishnaiah Anandanb6b401f2017-03-14 16:39:49 -07001575
1576 sde_crtc_event_queue(&crtc->base, sde_cp_notify_ad_event, NULL);
1577}
1578
1579static void sde_cp_notify_ad_event(struct drm_crtc *crtc_drm, void *arg)
1580{
Yuchao Ma9991ece2017-12-01 15:02:00 +08001581 uint32_t input_bl = 0, output_bl = 0;
1582 uint32_t scale = MAX_AD_BL_SCALE_LEVEL;
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001583 struct sde_hw_mixer *hw_lm = NULL;
1584 struct sde_hw_dspp *hw_dspp = NULL;
Gopikrishnaiah Anandanb6b401f2017-03-14 16:39:49 -07001585 u32 num_mixers;
1586 struct sde_crtc *crtc;
1587 struct drm_event event;
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001588 int i;
1589
Gopikrishnaiah Anandanb6b401f2017-03-14 16:39:49 -07001590 crtc = to_sde_crtc(crtc_drm);
1591 num_mixers = crtc->num_mixers;
1592 if (!num_mixers)
1593 return;
1594
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001595 for (i = 0; i < num_mixers; i++) {
1596 hw_lm = crtc->mixers[i].hw_lm;
1597 hw_dspp = crtc->mixers[i].hw_dspp;
1598 if (!hw_lm->cfg.right_mixer)
1599 break;
1600 }
1601
1602 if (!hw_dspp)
1603 return;
1604
Yuchao Ma9991ece2017-12-01 15:02:00 +08001605 hw_dspp->ops.ad_read_intr_resp(hw_dspp, AD4_IN_OUT_BACKLIGHT,
1606 &input_bl, &output_bl);
1607
1608 if (!input_bl || input_bl < output_bl)
1609 return;
1610
1611 scale = (output_bl * MAX_AD_BL_SCALE_LEVEL) / input_bl;
Gopikrishnaiah Anandanb6b401f2017-03-14 16:39:49 -07001612 event.length = sizeof(u32);
1613 event.type = DRM_EVENT_AD_BACKLIGHT;
Benjamin Chan34a92c72017-06-28 11:01:18 -04001614 msm_mode_object_event_notify(&crtc_drm->base, crtc_drm->dev,
Yuchao Ma9991ece2017-12-01 15:02:00 +08001615 &event, (u8 *)&scale);
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001616}
1617
1618int sde_cp_ad_interrupt(struct drm_crtc *crtc_drm, bool en,
1619 struct sde_irq_callback *ad_irq)
1620{
1621 struct sde_kms *kms = NULL;
1622 u32 num_mixers;
1623 struct sde_hw_mixer *hw_lm;
1624 struct sde_hw_dspp *hw_dspp = NULL;
1625 struct sde_crtc *crtc;
1626 int i;
1627 int irq_idx, ret;
Xu Yanged79cec2018-01-10 21:04:05 +08001628 unsigned long flags;
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001629 struct sde_cp_node prop_node;
Xu Yangda310e32017-08-25 15:12:46 +08001630 struct sde_crtc_irq_info *node = NULL;
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001631
1632 if (!crtc_drm || !ad_irq) {
1633 DRM_ERROR("invalid crtc %pK irq %pK\n", crtc_drm, ad_irq);
1634 return -EINVAL;
1635 }
1636
1637 crtc = to_sde_crtc(crtc_drm);
1638 if (!crtc) {
1639 DRM_ERROR("invalid sde_crtc %pK\n", crtc);
1640 return -EINVAL;
1641 }
1642
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001643 kms = get_kms(crtc_drm);
1644 num_mixers = crtc->num_mixers;
1645
1646 memset(&prop_node, 0, sizeof(prop_node));
1647 prop_node.feature = SDE_CP_CRTC_DSPP_AD_BACKLIGHT;
1648 ret = sde_cp_ad_validate_prop(&prop_node, crtc);
1649 if (ret) {
1650 DRM_ERROR("Ad not supported ret %d\n", ret);
1651 goto exit;
1652 }
1653
1654 for (i = 0; i < num_mixers; i++) {
1655 hw_lm = crtc->mixers[i].hw_lm;
1656 hw_dspp = crtc->mixers[i].hw_dspp;
1657 if (!hw_lm->cfg.right_mixer)
1658 break;
1659 }
1660
1661 if (!hw_dspp) {
1662 DRM_ERROR("invalid dspp\n");
1663 ret = -EINVAL;
1664 goto exit;
1665 }
1666
1667 irq_idx = sde_core_irq_idx_lookup(kms, SDE_IRQ_TYPE_AD4_BL_DONE,
1668 hw_dspp->idx);
1669 if (irq_idx < 0) {
1670 DRM_ERROR("failed to get the irq idx ret %d\n", irq_idx);
1671 ret = irq_idx;
1672 goto exit;
1673 }
1674
Xu Yangda310e32017-08-25 15:12:46 +08001675 node = _sde_cp_get_intr_node(DRM_EVENT_AD_BACKLIGHT, crtc);
1676
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001677 if (!en) {
Xu Yangda310e32017-08-25 15:12:46 +08001678 if (node) {
Xu Yanged79cec2018-01-10 21:04:05 +08001679 spin_lock_irqsave(&node->state_lock, flags);
Xu Yangda310e32017-08-25 15:12:46 +08001680 if (node->state == IRQ_ENABLED) {
1681 ret = sde_core_irq_disable(kms, &irq_idx, 1);
1682 if (ret)
1683 DRM_ERROR("disable irq %d error %d\n",
1684 irq_idx, ret);
1685 else
1686 node->state = IRQ_NOINIT;
1687 } else {
1688 node->state = IRQ_NOINIT;
1689 }
Xu Yanged79cec2018-01-10 21:04:05 +08001690 spin_unlock_irqrestore(&node->state_lock, flags);
Xu Yangda310e32017-08-25 15:12:46 +08001691 } else {
1692 DRM_ERROR("failed to get node from crtc event list\n");
1693 }
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001694 sde_core_irq_unregister_callback(kms, irq_idx, ad_irq);
1695 ret = 0;
1696 goto exit;
1697 }
1698
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001699 ad_irq->arg = crtc;
1700 ad_irq->func = sde_cp_ad_interrupt_cb;
1701 ret = sde_core_irq_register_callback(kms, irq_idx, ad_irq);
1702 if (ret) {
1703 DRM_ERROR("failed to register the callback ret %d\n", ret);
1704 goto exit;
1705 }
Xu Yangda310e32017-08-25 15:12:46 +08001706
1707 if (node) {
1708 /* device resume or resume from IPC cases */
Xu Yanged79cec2018-01-10 21:04:05 +08001709 spin_lock_irqsave(&node->state_lock, flags);
Xu Yangda310e32017-08-25 15:12:46 +08001710 if (node->state == IRQ_DISABLED || node->state == IRQ_NOINIT) {
1711 ret = sde_core_irq_enable(kms, &irq_idx, 1);
1712 if (ret) {
1713 DRM_ERROR("enable irq %d error %d\n",
1714 irq_idx, ret);
1715 sde_core_irq_unregister_callback(kms,
1716 irq_idx, ad_irq);
1717 } else {
1718 node->state = IRQ_ENABLED;
1719 }
1720 }
Xu Yanged79cec2018-01-10 21:04:05 +08001721 spin_unlock_irqrestore(&node->state_lock, flags);
Xu Yangda310e32017-08-25 15:12:46 +08001722 } else {
1723 /* request from userspace to register the event
1724 * in this case, node has not been added into the event list
1725 */
1726 ret = sde_core_irq_enable(kms, &irq_idx, 1);
1727 if (ret) {
1728 DRM_ERROR("failed to enable irq ret %d\n", ret);
1729 sde_core_irq_unregister_callback(kms,
1730 irq_idx, ad_irq);
1731 }
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001732 }
1733exit:
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001734 return ret;
1735}
Ping Lie505f3b2017-06-19 14:19:08 -07001736
1737static void sde_cp_ad_set_prop(struct sde_crtc *sde_crtc,
1738 enum ad_property ad_prop)
1739{
1740 struct sde_ad_hw_cfg ad_cfg;
1741 struct sde_hw_cp_cfg hw_cfg;
1742 struct sde_hw_dspp *hw_dspp = NULL;
1743 struct sde_hw_mixer *hw_lm = NULL;
1744 u32 num_mixers = sde_crtc->num_mixers;
1745 int i = 0, ret = 0;
1746
1747 hw_cfg.num_of_mixers = sde_crtc->num_mixers;
Ping Lie505f3b2017-06-19 14:19:08 -07001748
1749 for (i = 0; i < num_mixers && !ret; i++) {
1750 hw_lm = sde_crtc->mixers[i].hw_lm;
1751 hw_dspp = sde_crtc->mixers[i].hw_dspp;
1752 if (!hw_lm || !hw_dspp || !hw_dspp->ops.validate_ad ||
1753 !hw_dspp->ops.setup_ad) {
1754 ret = -EINVAL;
1755 continue;
1756 }
1757
Xu Yangf9c76112017-12-08 14:36:50 +08001758 hw_cfg.displayh = num_mixers * hw_lm->cfg.out_width;
1759 hw_cfg.displayv = hw_lm->cfg.out_height;
Ping Lie505f3b2017-06-19 14:19:08 -07001760 hw_cfg.mixer_info = hw_lm;
1761 ad_cfg.prop = ad_prop;
1762 ad_cfg.hw_cfg = &hw_cfg;
1763 ret = hw_dspp->ops.validate_ad(hw_dspp, (u32 *)&ad_prop);
1764 if (!ret)
1765 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
1766 }
1767}
1768
1769void sde_cp_crtc_pre_ipc(struct drm_crtc *drm_crtc)
1770{
1771 struct sde_crtc *sde_crtc;
1772
1773 sde_crtc = to_sde_crtc(drm_crtc);
1774 if (!sde_crtc) {
1775 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
1776 return;
1777 }
1778
1779 sde_cp_ad_set_prop(sde_crtc, AD_IPC_SUSPEND);
1780}
1781
1782void sde_cp_crtc_post_ipc(struct drm_crtc *drm_crtc)
1783{
1784 struct sde_crtc *sde_crtc;
1785
1786 sde_crtc = to_sde_crtc(drm_crtc);
1787 if (!sde_crtc) {
1788 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
1789 return;
1790 }
1791
1792 sde_cp_ad_set_prop(sde_crtc, AD_IPC_RESUME);
1793}
Xu Yang5e53c2e2017-07-11 16:46:28 +08001794
1795static void sde_cp_hist_interrupt_cb(void *arg, int irq_idx)
1796{
1797 struct sde_crtc *crtc = arg;
1798 struct drm_crtc *crtc_drm = &crtc->base;
1799 struct sde_hw_dspp *hw_dspp;
1800 struct sde_kms *kms;
1801 struct sde_crtc_irq_info *node = NULL;
1802 u32 i;
1803 int ret = 0;
1804 unsigned long flags;
1805
1806 /* disable histogram irq */
1807 kms = get_kms(crtc_drm);
1808 spin_lock_irqsave(&crtc->spin_lock, flags);
1809 node = _sde_cp_get_intr_node(DRM_EVENT_HISTOGRAM, crtc);
1810 spin_unlock_irqrestore(&crtc->spin_lock, flags);
1811
1812 if (!node) {
1813 DRM_ERROR("cannot find histogram event node in crtc\n");
1814 return;
1815 }
1816
Xu Yanged79cec2018-01-10 21:04:05 +08001817 spin_lock_irqsave(&node->state_lock, flags);
Xu Yang5e53c2e2017-07-11 16:46:28 +08001818 if (node->state == IRQ_ENABLED) {
1819 if (sde_core_irq_disable_nolock(kms, irq_idx)) {
1820 DRM_ERROR("failed to disable irq %d, ret %d\n",
1821 irq_idx, ret);
Xu Yanged79cec2018-01-10 21:04:05 +08001822 spin_unlock_irqrestore(&node->state_lock, flags);
Xu Yang5e53c2e2017-07-11 16:46:28 +08001823 return;
1824 }
1825 node->state = IRQ_DISABLED;
1826 }
Xu Yanged79cec2018-01-10 21:04:05 +08001827 spin_unlock_irqrestore(&node->state_lock, flags);
Xu Yang5e53c2e2017-07-11 16:46:28 +08001828
1829 /* lock histogram buffer */
1830 for (i = 0; i < crtc->num_mixers; i++) {
1831 hw_dspp = crtc->mixers[i].hw_dspp;
1832 if (hw_dspp && hw_dspp->ops.lock_histogram)
1833 hw_dspp->ops.lock_histogram(hw_dspp, NULL);
1834 }
1835
1836 /* notify histogram event */
1837 sde_crtc_event_queue(crtc_drm, sde_cp_notify_hist_event, NULL);
1838}
1839
1840static void sde_cp_notify_hist_event(struct drm_crtc *crtc_drm, void *arg)
1841{
1842 struct sde_hw_dspp *hw_dspp = NULL;
1843 struct sde_crtc *crtc;
1844 struct drm_event event;
1845 struct drm_msm_hist *hist_data;
1846 struct drm_msm_hist tmp_hist_data;
1847 u32 i, j;
1848
1849 if (!crtc_drm) {
1850 DRM_ERROR("invalid crtc %pK\n", crtc_drm);
1851 return;
1852 }
1853
1854 crtc = to_sde_crtc(crtc_drm);
1855 if (!crtc) {
1856 DRM_ERROR("invalid sde_crtc %pK\n", crtc);
1857 return;
1858 }
1859
1860 if (!crtc->hist_blob)
1861 return;
1862
1863 /* read histogram data into blob */
1864 hist_data = (struct drm_msm_hist *)crtc->hist_blob->data;
1865 for (i = 0; i < crtc->num_mixers; i++) {
1866 hw_dspp = crtc->mixers[i].hw_dspp;
1867 if (!hw_dspp || !hw_dspp->ops.read_histogram) {
1868 DRM_ERROR("invalid dspp %pK or read_histogram func\n",
1869 hw_dspp);
1870 return;
1871 }
1872 if (!i) {
1873 hw_dspp->ops.read_histogram(hw_dspp, hist_data);
1874 } else {
1875 /* Merge hist data for DSPP0 and DSPP1 */
1876 hw_dspp->ops.read_histogram(hw_dspp, &tmp_hist_data);
1877 for (j = 0; j < HIST_V_SIZE; j++)
1878 hist_data->data[j] += tmp_hist_data.data[j];
1879 }
1880 }
1881
1882 /* send histogram event with blob id */
1883 event.length = sizeof(u32);
1884 event.type = DRM_EVENT_HISTOGRAM;
1885 msm_mode_object_event_notify(&crtc_drm->base, crtc_drm->dev,
1886 &event, (u8 *)(&crtc->hist_blob->base.id));
1887}
1888
1889int sde_cp_hist_interrupt(struct drm_crtc *crtc_drm, bool en,
1890 struct sde_irq_callback *hist_irq)
1891{
1892 struct sde_kms *kms = NULL;
1893 u32 num_mixers;
1894 struct sde_hw_mixer *hw_lm;
1895 struct sde_hw_dspp *hw_dspp = NULL;
1896 struct sde_crtc *crtc;
1897 struct sde_crtc_irq_info *node = NULL;
1898 int i, irq_idx, ret = 0;
Xu Yanged79cec2018-01-10 21:04:05 +08001899 unsigned long flags;
Xu Yang5e53c2e2017-07-11 16:46:28 +08001900
1901 if (!crtc_drm || !hist_irq) {
1902 DRM_ERROR("invalid crtc %pK irq %pK\n", crtc_drm, hist_irq);
1903 return -EINVAL;
1904 }
1905
1906 crtc = to_sde_crtc(crtc_drm);
1907 if (!crtc) {
1908 DRM_ERROR("invalid sde_crtc %pK\n", crtc);
1909 return -EINVAL;
1910 }
1911
1912 kms = get_kms(crtc_drm);
1913 num_mixers = crtc->num_mixers;
1914
1915 for (i = 0; i < num_mixers; i++) {
1916 hw_lm = crtc->mixers[i].hw_lm;
1917 hw_dspp = crtc->mixers[i].hw_dspp;
1918 if (!hw_lm->cfg.right_mixer)
1919 break;
1920 }
1921
1922 if (!hw_dspp) {
1923 DRM_ERROR("invalid dspp\n");
Xu Yang7e52b172017-10-26 14:28:23 +08001924 ret = -EPERM;
Xu Yang5e53c2e2017-07-11 16:46:28 +08001925 goto exit;
1926 }
1927
1928 irq_idx = sde_core_irq_idx_lookup(kms, SDE_IRQ_TYPE_HIST_DSPP_DONE,
1929 hw_dspp->idx);
1930 if (irq_idx < 0) {
1931 DRM_ERROR("failed to get the irq idx ret %d\n", irq_idx);
1932 ret = irq_idx;
1933 goto exit;
1934 }
1935
1936 node = _sde_cp_get_intr_node(DRM_EVENT_HISTOGRAM, crtc);
1937
1938 /* deregister histogram irq */
1939 if (!en) {
1940 if (node) {
1941 /* device suspend case or suspend to IPC cases */
Xu Yanged79cec2018-01-10 21:04:05 +08001942 spin_lock_irqsave(&node->state_lock, flags);
Xu Yang5e53c2e2017-07-11 16:46:28 +08001943 if (node->state == IRQ_ENABLED) {
1944 ret = sde_core_irq_disable(kms, &irq_idx, 1);
1945 if (ret)
1946 DRM_ERROR("disable irq %d error %d\n",
1947 irq_idx, ret);
1948 else
1949 node->state = IRQ_NOINIT;
1950 } else {
1951 node->state = IRQ_NOINIT;
1952 }
Xu Yanged79cec2018-01-10 21:04:05 +08001953 spin_unlock_irqrestore(&node->state_lock, flags);
Xu Yang5e53c2e2017-07-11 16:46:28 +08001954 } else {
1955 DRM_ERROR("failed to get node from crtc event list\n");
1956 }
1957
1958 sde_core_irq_unregister_callback(kms, irq_idx, hist_irq);
1959 goto exit;
1960 }
1961
1962 /* register histogram irq */
1963 hist_irq->arg = crtc;
1964 hist_irq->func = sde_cp_hist_interrupt_cb;
1965 ret = sde_core_irq_register_callback(kms, irq_idx, hist_irq);
1966 if (ret) {
1967 DRM_ERROR("failed to register the callback ret %d\n", ret);
1968 goto exit;
1969 }
1970
1971 if (node) {
1972 /* device resume or resume from IPC cases */
Xu Yanged79cec2018-01-10 21:04:05 +08001973 spin_lock_irqsave(&node->state_lock, flags);
Xu Yang5e53c2e2017-07-11 16:46:28 +08001974 if (node->state == IRQ_DISABLED || node->state == IRQ_NOINIT) {
1975 ret = sde_core_irq_enable(kms, &irq_idx, 1);
1976 if (ret) {
1977 DRM_ERROR("enable irq %d error %d\n",
1978 irq_idx, ret);
1979 sde_core_irq_unregister_callback(kms,
1980 irq_idx, hist_irq);
1981 } else {
1982 node->state = IRQ_ENABLED;
1983 }
1984 }
Xu Yanged79cec2018-01-10 21:04:05 +08001985 spin_unlock_irqrestore(&node->state_lock, flags);
Xu Yang5e53c2e2017-07-11 16:46:28 +08001986 } else {
1987 /* request from userspace to register the event
1988 * in this case, node has not been added into the event list
1989 */
1990 ret = sde_core_irq_enable(kms, &irq_idx, 1);
1991 if (ret) {
1992 DRM_ERROR("failed to enable irq ret %d\n", ret);
1993 sde_core_irq_unregister_callback(kms,
1994 irq_idx, hist_irq);
1995 }
1996 }
1997exit:
1998 return ret;
1999}