blob: 0f55b198ce994465938bd721b2750f75fcdebfbc [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"
Ping Lic51f40b2018-01-26 17:19:30 -080028#include "sde_hw_color_processing.h"
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -070029
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -070030struct sde_cp_node {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -070031 u32 property_id;
32 u32 prop_flags;
33 u32 feature;
34 void *blob_ptr;
35 uint64_t prop_val;
36 const struct sde_pp_blk *pp_blk;
37 struct list_head feature_list;
38 struct list_head active_list;
39 struct list_head dirty_list;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -070040 bool is_dspp_feature;
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -080041 u32 prop_blob_sz;
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -080042 struct sde_irq_callback *irq;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -070043};
44
45struct sde_cp_prop_attach {
46 struct drm_crtc *crtc;
47 struct drm_property *prop;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -070048 struct sde_cp_node *prop_node;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -070049 u32 feature;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -070050 uint64_t val;
51};
52
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -070053static void dspp_pcc_install_property(struct drm_crtc *crtc);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070054
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -070055static void dspp_hsic_install_property(struct drm_crtc *crtc);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070056
Rajesh Yadav7b8fbae2017-08-28 14:48:14 +053057static void dspp_memcolor_install_property(struct drm_crtc *crtc);
58
Rajesh Yadav0a92eea2017-07-18 18:18:55 +053059static void dspp_sixzone_install_property(struct drm_crtc *crtc);
60
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -070061static void dspp_ad_install_property(struct drm_crtc *crtc);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070062
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -070063static void dspp_vlut_install_property(struct drm_crtc *crtc);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070064
Gopikrishnaiah Anandanfbf75392017-01-16 10:43:36 -080065static void dspp_gamut_install_property(struct drm_crtc *crtc);
66
67static void dspp_gc_install_property(struct drm_crtc *crtc);
68
Rajesh Yadavec93afb2017-06-08 19:28:33 +053069static void dspp_igc_install_property(struct drm_crtc *crtc);
70
Xu Yang056d39b2017-07-11 16:34:13 +080071static void dspp_hist_install_property(struct drm_crtc *crtc);
72
Xu Yang30f2ccc2018-02-06 15:56:33 +080073static void dspp_dither_install_property(struct drm_crtc *crtc);
74
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -070075typedef void (*dspp_prop_install_func_t)(struct drm_crtc *crtc);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070076
77static dspp_prop_install_func_t dspp_prop_install_func[SDE_DSPP_MAX];
78
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -080079static void sde_cp_update_list(struct sde_cp_node *prop_node,
80 struct sde_crtc *crtc, bool dirty_list);
81
82static int sde_cp_ad_validate_prop(struct sde_cp_node *prop_node,
83 struct sde_crtc *crtc);
84
Gopikrishnaiah Anandanb6b401f2017-03-14 16:39:49 -070085static void sde_cp_notify_ad_event(struct drm_crtc *crtc_drm, void *arg);
86
Ping Lie505f3b2017-06-19 14:19:08 -070087static void sde_cp_ad_set_prop(struct sde_crtc *sde_crtc,
88 enum ad_property ad_prop);
89
Xu Yang5e53c2e2017-07-11 16:46:28 +080090static void sde_cp_notify_hist_event(struct drm_crtc *crtc_drm, void *arg);
91
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070092#define setup_dspp_prop_install_funcs(func) \
93do { \
94 func[SDE_DSPP_PCC] = dspp_pcc_install_property; \
95 func[SDE_DSPP_HSIC] = dspp_hsic_install_property; \
Rajesh Yadav7b8fbae2017-08-28 14:48:14 +053096 func[SDE_DSPP_MEMCOLOR] = dspp_memcolor_install_property; \
Rajesh Yadav0a92eea2017-07-18 18:18:55 +053097 func[SDE_DSPP_SIXZONE] = dspp_sixzone_install_property; \
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -070098 func[SDE_DSPP_AD] = dspp_ad_install_property; \
99 func[SDE_DSPP_VLUT] = dspp_vlut_install_property; \
Gopikrishnaiah Anandanfbf75392017-01-16 10:43:36 -0800100 func[SDE_DSPP_GAMUT] = dspp_gamut_install_property; \
101 func[SDE_DSPP_GC] = dspp_gc_install_property; \
Rajesh Yadavec93afb2017-06-08 19:28:33 +0530102 func[SDE_DSPP_IGC] = dspp_igc_install_property; \
Xu Yang056d39b2017-07-11 16:34:13 +0800103 func[SDE_DSPP_HIST] = dspp_hist_install_property; \
Xu Yang30f2ccc2018-02-06 15:56:33 +0800104 func[SDE_DSPP_DITHER] = dspp_dither_install_property; \
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -0700105} while (0)
106
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700107typedef void (*lm_prop_install_func_t)(struct drm_crtc *crtc);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -0700108
109static lm_prop_install_func_t lm_prop_install_func[SDE_MIXER_MAX];
110
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700111static void lm_gc_install_property(struct drm_crtc *crtc);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -0700112
113#define setup_lm_prop_install_funcs(func) \
114 (func[SDE_MIXER_GC] = lm_gc_install_property)
115
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700116enum {
117 /* Append new DSPP features before SDE_CP_CRTC_DSPP_MAX */
118 /* DSPP Features start */
119 SDE_CP_CRTC_DSPP_IGC,
120 SDE_CP_CRTC_DSPP_PCC,
121 SDE_CP_CRTC_DSPP_GC,
Rajesh Yadav284947c2017-07-21 20:32:13 +0530122 SDE_CP_CRTC_DSPP_HSIC,
Rajesh Yadav7b8fbae2017-08-28 14:48:14 +0530123 SDE_CP_CRTC_DSPP_MEMCOL_SKIN,
124 SDE_CP_CRTC_DSPP_MEMCOL_SKY,
125 SDE_CP_CRTC_DSPP_MEMCOL_FOLIAGE,
126 SDE_CP_CRTC_DSPP_MEMCOL_PROT,
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700127 SDE_CP_CRTC_DSPP_SIXZONE,
128 SDE_CP_CRTC_DSPP_GAMUT,
129 SDE_CP_CRTC_DSPP_DITHER,
Xu Yang056d39b2017-07-11 16:34:13 +0800130 SDE_CP_CRTC_DSPP_HIST_CTRL,
131 SDE_CP_CRTC_DSPP_HIST_IRQ,
Gopikrishnaiah Anandan41980b42016-06-21 16:01:33 -0700132 SDE_CP_CRTC_DSPP_AD,
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700133 SDE_CP_CRTC_DSPP_VLUT,
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800134 SDE_CP_CRTC_DSPP_AD_MODE,
135 SDE_CP_CRTC_DSPP_AD_INIT,
136 SDE_CP_CRTC_DSPP_AD_CFG,
137 SDE_CP_CRTC_DSPP_AD_INPUT,
138 SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS,
139 SDE_CP_CRTC_DSPP_AD_BACKLIGHT,
Xu Yangd59dd922017-12-26 14:22:25 +0800140 SDE_CP_CRTC_DSPP_AD_STRENGTH,
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700141 SDE_CP_CRTC_DSPP_MAX,
142 /* DSPP features end */
143
144 /* Append new LM features before SDE_CP_CRTC_MAX_FEATURES */
145 /* LM feature start*/
146 SDE_CP_CRTC_LM_GC,
147 /* LM feature end*/
148
149 SDE_CP_CRTC_MAX_FEATURES,
150};
151
Ping Lic51f40b2018-01-26 17:19:30 -0800152#define HIGH_BUS_VOTE_NEEDED(feature) ((feature == SDE_CP_CRTC_DSPP_IGC) |\
153 (feature == SDE_CP_CRTC_DSPP_GC) |\
154 (feature == SDE_CP_CRTC_DSPP_SIXZONE) |\
155 (feature == SDE_CP_CRTC_DSPP_GAMUT))
156
157static u32 crtc_feature_map[SDE_CP_CRTC_MAX_FEATURES] = {
158 [SDE_CP_CRTC_DSPP_IGC] = SDE_DSPP_IGC,
159 [SDE_CP_CRTC_DSPP_PCC] = SDE_DSPP_PCC,
160 [SDE_CP_CRTC_DSPP_GC] = SDE_DSPP_GC,
161 [SDE_CP_CRTC_DSPP_MEMCOL_SKIN] = SDE_DSPP_MEMCOLOR,
162 [SDE_CP_CRTC_DSPP_MEMCOL_SKY] = SDE_DSPP_MEMCOLOR,
163 [SDE_CP_CRTC_DSPP_MEMCOL_FOLIAGE] = SDE_DSPP_MEMCOLOR,
164 [SDE_CP_CRTC_DSPP_SIXZONE] = SDE_DSPP_SIXZONE,
165 [SDE_CP_CRTC_DSPP_GAMUT] = SDE_DSPP_GAMUT,
166 [SDE_CP_CRTC_DSPP_DITHER] = SDE_DSPP_DITHER,
167 [SDE_CP_CRTC_DSPP_VLUT] = SDE_DSPP_VLUT,
168};
169
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700170#define INIT_PROP_ATTACH(p, crtc, prop, node, feature, val) \
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700171 do { \
172 (p)->crtc = crtc; \
173 (p)->prop = prop; \
174 (p)->prop_node = node; \
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700175 (p)->feature = feature; \
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700176 (p)->val = val; \
177 } while (0)
178
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700179static void sde_cp_get_hw_payload(struct sde_cp_node *prop_node,
180 struct sde_hw_cp_cfg *hw_cfg,
181 bool *feature_enabled)
182{
183
184 struct drm_property_blob *blob = NULL;
185
186 memset(hw_cfg, 0, sizeof(*hw_cfg));
187 *feature_enabled = false;
188
189 blob = prop_node->blob_ptr;
190 if (prop_node->prop_flags & DRM_MODE_PROP_BLOB) {
191 if (blob) {
192 hw_cfg->len = blob->length;
193 hw_cfg->payload = blob->data;
194 *feature_enabled = true;
195 }
196 } else if (prop_node->prop_flags & DRM_MODE_PROP_RANGE) {
197 /* Check if local blob is Set */
198 if (!blob) {
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800199 if (prop_node->prop_val) {
200 hw_cfg->len = sizeof(prop_node->prop_val);
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700201 hw_cfg->payload = &prop_node->prop_val;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800202 }
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700203 } else {
204 hw_cfg->len = (prop_node->prop_val) ? blob->length :
205 0;
206 hw_cfg->payload = (prop_node->prop_val) ? blob->data
207 : NULL;
208 }
209 if (prop_node->prop_val)
210 *feature_enabled = true;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800211 } else if (prop_node->prop_flags & DRM_MODE_PROP_ENUM) {
212 *feature_enabled = (prop_node->prop_val != 0);
213 hw_cfg->len = sizeof(prop_node->prop_val);
214 hw_cfg->payload = &prop_node->prop_val;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700215 } else {
216 DRM_ERROR("property type is not supported\n");
217 }
218}
219
220static int sde_cp_disable_crtc_blob_property(struct sde_cp_node *prop_node)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700221{
222 struct drm_property_blob *blob = prop_node->blob_ptr;
223
224 if (!blob)
Gopikrishnaiah Anandan8b1498a2017-05-10 16:58:04 -0700225 return 0;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700226 drm_property_unreference_blob(blob);
227 prop_node->blob_ptr = NULL;
228 return 0;
229}
230
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700231static int sde_cp_create_local_blob(struct drm_crtc *crtc, u32 feature, int len)
232{
233 int ret = -EINVAL;
234 bool found = false;
235 struct sde_cp_node *prop_node = NULL;
236 struct drm_property_blob *blob_ptr;
237 struct sde_crtc *sde_crtc = to_sde_crtc(crtc);
238
239 list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) {
240 if (prop_node->feature == feature) {
241 found = true;
242 break;
243 }
244 }
245
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800246 if (!found || !(prop_node->prop_flags & DRM_MODE_PROP_RANGE)) {
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700247 DRM_ERROR("local blob create failed prop found %d flags %d\n",
248 found, prop_node->prop_flags);
249 return ret;
250 }
251
252 blob_ptr = drm_property_create_blob(crtc->dev, len, NULL);
253 ret = (IS_ERR_OR_NULL(blob_ptr)) ? PTR_ERR(blob_ptr) : 0;
254 if (!ret)
255 prop_node->blob_ptr = blob_ptr;
256
257 return ret;
258}
259
260static void sde_cp_destroy_local_blob(struct sde_cp_node *prop_node)
261{
262 if (!(prop_node->prop_flags & DRM_MODE_PROP_BLOB) &&
263 prop_node->blob_ptr)
264 drm_property_unreference_blob(prop_node->blob_ptr);
265}
266
267static int sde_cp_handle_range_property(struct sde_cp_node *prop_node,
268 uint64_t val)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700269{
270 int ret = 0;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700271 struct drm_property_blob *blob_ptr = prop_node->blob_ptr;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700272
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700273 if (!blob_ptr) {
274 prop_node->prop_val = val;
275 return 0;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700276 }
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700277
278 if (!val) {
279 prop_node->prop_val = 0;
280 return 0;
281 }
282
283 ret = copy_from_user(blob_ptr->data, (void *)val, blob_ptr->length);
284 if (ret) {
285 DRM_ERROR("failed to get the property info ret %d", ret);
286 ret = -EFAULT;
287 } else {
288 prop_node->prop_val = val;
289 }
290
291 return ret;
292}
293
294static int sde_cp_disable_crtc_property(struct drm_crtc *crtc,
295 struct drm_property *property,
296 struct sde_cp_node *prop_node)
297{
298 int ret = -EINVAL;
299
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800300 if (property->flags & DRM_MODE_PROP_BLOB) {
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700301 ret = sde_cp_disable_crtc_blob_property(prop_node);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800302 } else if (property->flags & DRM_MODE_PROP_RANGE) {
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700303 ret = sde_cp_handle_range_property(prop_node, 0);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800304 } else if (property->flags & DRM_MODE_PROP_ENUM) {
305 ret = 0;
306 prop_node->prop_val = 0;
307 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700308 return ret;
309}
310
311static int sde_cp_enable_crtc_blob_property(struct drm_crtc *crtc,
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700312 struct sde_cp_node *prop_node,
313 uint64_t val)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700314{
315 struct drm_property_blob *blob = NULL;
316
317 /**
318 * For non-blob based properties add support to create a blob
319 * using the val and store the blob_ptr in prop_node.
320 */
321 blob = drm_property_lookup_blob(crtc->dev, val);
322 if (!blob) {
323 DRM_ERROR("invalid blob id %lld\n", val);
324 return -EINVAL;
325 }
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -0800326 if (blob->length != prop_node->prop_blob_sz) {
327 DRM_ERROR("invalid blob len %zd exp %d feature %d\n",
328 blob->length, prop_node->prop_blob_sz, prop_node->feature);
329 drm_property_unreference_blob(blob);
330 return -EINVAL;
331 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700332 /* Release refernce to existing payload of the property */
333 if (prop_node->blob_ptr)
334 drm_property_unreference_blob(prop_node->blob_ptr);
335
336 prop_node->blob_ptr = blob;
337 return 0;
338}
339
340static int sde_cp_enable_crtc_property(struct drm_crtc *crtc,
341 struct drm_property *property,
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700342 struct sde_cp_node *prop_node,
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700343 uint64_t val)
344{
345 int ret = -EINVAL;
346
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800347 if (property->flags & DRM_MODE_PROP_BLOB) {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700348 ret = sde_cp_enable_crtc_blob_property(crtc, prop_node, val);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800349 } else if (property->flags & DRM_MODE_PROP_RANGE) {
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700350 ret = sde_cp_handle_range_property(prop_node, val);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800351 } else if (property->flags & DRM_MODE_PROP_ENUM) {
352 ret = 0;
353 prop_node->prop_val = val;
354 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700355 return ret;
356}
357
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700358static struct sde_kms *get_kms(struct drm_crtc *crtc)
359{
360 struct msm_drm_private *priv = crtc->dev->dev_private;
361
362 return to_sde_kms(priv->kms);
363}
364
365static void sde_cp_crtc_prop_attach(struct sde_cp_prop_attach *prop_attach)
366{
367
368 struct sde_crtc *sde_crtc = to_sde_crtc(prop_attach->crtc);
369
370 drm_object_attach_property(&prop_attach->crtc->base,
371 prop_attach->prop, prop_attach->val);
372
373 INIT_LIST_HEAD(&prop_attach->prop_node->active_list);
374 INIT_LIST_HEAD(&prop_attach->prop_node->dirty_list);
375
376 prop_attach->prop_node->property_id = prop_attach->prop->base.id;
377 prop_attach->prop_node->prop_flags = prop_attach->prop->flags;
378 prop_attach->prop_node->feature = prop_attach->feature;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700379
380 if (prop_attach->feature < SDE_CP_CRTC_DSPP_MAX)
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700381 prop_attach->prop_node->is_dspp_feature = true;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700382 else
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700383 prop_attach->prop_node->is_dspp_feature = false;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700384
385 list_add(&prop_attach->prop_node->feature_list,
386 &sde_crtc->feature_list);
387}
388
389void sde_cp_crtc_init(struct drm_crtc *crtc)
390{
391 struct sde_crtc *sde_crtc = NULL;
392
393 if (!crtc) {
394 DRM_ERROR("invalid crtc %pK\n", crtc);
395 return;
396 }
397
398 sde_crtc = to_sde_crtc(crtc);
399 if (!sde_crtc) {
400 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
401 return;
402 }
403
Xu Yang5e53c2e2017-07-11 16:46:28 +0800404 /* create blob to store histogram data */
405 sde_crtc->hist_blob = drm_property_create_blob(crtc->dev,
406 sizeof(struct drm_msm_hist), NULL);
407 if (IS_ERR(sde_crtc->hist_blob))
408 sde_crtc->hist_blob = NULL;
409
Xu Yang1b3a5d92017-09-13 11:37:54 +0800410 mutex_init(&sde_crtc->crtc_cp_lock);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700411 INIT_LIST_HEAD(&sde_crtc->active_list);
412 INIT_LIST_HEAD(&sde_crtc->dirty_list);
413 INIT_LIST_HEAD(&sde_crtc->feature_list);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800414 INIT_LIST_HEAD(&sde_crtc->ad_dirty);
415 INIT_LIST_HEAD(&sde_crtc->ad_active);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700416}
417
Gopikrishnaiah Anandan41980b42016-06-21 16:01:33 -0700418static void sde_cp_crtc_install_immutable_property(struct drm_crtc *crtc,
419 char *name,
420 u32 feature)
421{
422 struct drm_property *prop;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700423 struct sde_cp_node *prop_node = NULL;
Gopikrishnaiah Anandan41980b42016-06-21 16:01:33 -0700424 struct msm_drm_private *priv;
425 struct sde_cp_prop_attach prop_attach;
426 uint64_t val = 0;
427
428 if (feature >= SDE_CP_CRTC_MAX_FEATURES) {
429 DRM_ERROR("invalid feature %d max %d\n", feature,
430 SDE_CP_CRTC_MAX_FEATURES);
431 return;
432 }
433
434 prop_node = kzalloc(sizeof(*prop_node), GFP_KERNEL);
435 if (!prop_node)
436 return;
437
438 priv = crtc->dev->dev_private;
439 prop = priv->cp_property[feature];
440
441 if (!prop) {
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800442 prop = drm_property_create_range(crtc->dev,
443 DRM_MODE_PROP_IMMUTABLE, name, 0, 1);
Gopikrishnaiah Anandan41980b42016-06-21 16:01:33 -0700444 if (!prop) {
445 DRM_ERROR("property create failed: %s\n", name);
446 kfree(prop_node);
447 return;
448 }
449 priv->cp_property[feature] = prop;
450 }
451
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700452 INIT_PROP_ATTACH(&prop_attach, crtc, prop, prop_node,
453 feature, val);
Gopikrishnaiah Anandan41980b42016-06-21 16:01:33 -0700454 sde_cp_crtc_prop_attach(&prop_attach);
455}
456
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700457static void sde_cp_crtc_install_range_property(struct drm_crtc *crtc,
458 char *name,
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700459 u32 feature,
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700460 uint64_t min, uint64_t max,
461 uint64_t val)
462{
463 struct drm_property *prop;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700464 struct sde_cp_node *prop_node = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700465 struct msm_drm_private *priv;
466 struct sde_cp_prop_attach prop_attach;
467
468 if (feature >= SDE_CP_CRTC_MAX_FEATURES) {
469 DRM_ERROR("invalid feature %d max %d\n", feature,
470 SDE_CP_CRTC_MAX_FEATURES);
471 return;
472 }
473
474 prop_node = kzalloc(sizeof(*prop_node), GFP_KERNEL);
475 if (!prop_node)
476 return;
477
478 priv = crtc->dev->dev_private;
479 prop = priv->cp_property[feature];
480
481 if (!prop) {
482 prop = drm_property_create_range(crtc->dev, 0, name, min, max);
483 if (!prop) {
484 DRM_ERROR("property create failed: %s\n", name);
485 kfree(prop_node);
486 return;
487 }
488 priv->cp_property[feature] = prop;
489 }
490
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700491 INIT_PROP_ATTACH(&prop_attach, crtc, prop, prop_node,
492 feature, val);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700493
494 sde_cp_crtc_prop_attach(&prop_attach);
495}
496
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800497static void sde_cp_crtc_install_blob_property(struct drm_crtc *crtc, char *name,
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -0800498 u32 feature, u32 blob_sz)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700499{
500 struct drm_property *prop;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700501 struct sde_cp_node *prop_node = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700502 struct msm_drm_private *priv;
503 uint64_t val = 0;
504 struct sde_cp_prop_attach prop_attach;
505
506 if (feature >= SDE_CP_CRTC_MAX_FEATURES) {
507 DRM_ERROR("invalid feature %d max %d\n", feature,
508 SDE_CP_CRTC_MAX_FEATURES);
509 return;
510 }
511
512 prop_node = kzalloc(sizeof(*prop_node), GFP_KERNEL);
513 if (!prop_node)
514 return;
515
516 priv = crtc->dev->dev_private;
517 prop = priv->cp_property[feature];
518
519 if (!prop) {
520 prop = drm_property_create(crtc->dev,
521 DRM_MODE_PROP_BLOB, name, 0);
522 if (!prop) {
523 DRM_ERROR("property create failed: %s\n", name);
524 kfree(prop_node);
525 return;
526 }
527 priv->cp_property[feature] = prop;
528 }
529
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700530 INIT_PROP_ATTACH(&prop_attach, crtc, prop, prop_node,
531 feature, val);
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -0800532 prop_node->prop_blob_sz = blob_sz;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700533
534 sde_cp_crtc_prop_attach(&prop_attach);
535}
536
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800537static void sde_cp_crtc_install_enum_property(struct drm_crtc *crtc,
538 u32 feature, const struct drm_prop_enum_list *list, u32 enum_sz,
539 char *name)
540{
541 struct drm_property *prop;
542 struct sde_cp_node *prop_node = NULL;
543 struct msm_drm_private *priv;
544 uint64_t val = 0;
545 struct sde_cp_prop_attach prop_attach;
546
547 if (feature >= SDE_CP_CRTC_MAX_FEATURES) {
548 DRM_ERROR("invalid feature %d max %d\n", feature,
549 SDE_CP_CRTC_MAX_FEATURES);
550 return;
551 }
552
553 prop_node = kzalloc(sizeof(*prop_node), GFP_KERNEL);
554 if (!prop_node)
555 return;
556
557 priv = crtc->dev->dev_private;
558 prop = priv->cp_property[feature];
559
560 if (!prop) {
561 prop = drm_property_create_enum(crtc->dev, 0, name,
562 list, enum_sz);
563 if (!prop) {
564 DRM_ERROR("property create failed: %s\n", name);
565 kfree(prop_node);
566 return;
567 }
568 priv->cp_property[feature] = prop;
569 }
570
571 INIT_PROP_ATTACH(&prop_attach, crtc, prop, prop_node,
572 feature, val);
573
574 sde_cp_crtc_prop_attach(&prop_attach);
575}
576
Xu Yang5e53c2e2017-07-11 16:46:28 +0800577static struct sde_crtc_irq_info *_sde_cp_get_intr_node(u32 event,
578 struct sde_crtc *sde_crtc)
579{
580 bool found = false;
581 struct sde_crtc_irq_info *node = NULL;
582
583 list_for_each_entry(node, &sde_crtc->user_event_list, list) {
584 if (node->event == event) {
585 found = true;
586 break;
587 }
588 }
589
590 if (!found)
591 node = NULL;
592
593 return node;
594}
595
Xu Yang056d39b2017-07-11 16:34:13 +0800596static void _sde_cp_crtc_enable_hist_irq(struct sde_crtc *sde_crtc)
597{
598 struct drm_crtc *crtc_drm = &sde_crtc->base;
599 struct sde_kms *kms = NULL;
600 struct sde_hw_mixer *hw_lm;
601 struct sde_hw_dspp *hw_dspp = NULL;
Xu Yang5e53c2e2017-07-11 16:46:28 +0800602 struct sde_crtc_irq_info *node = NULL;
603 int i, irq_idx, ret = 0;
604 unsigned long flags;
Xu Yang056d39b2017-07-11 16:34:13 +0800605
606 if (!crtc_drm) {
607 DRM_ERROR("invalid crtc %pK\n", crtc_drm);
608 return;
609 }
610
611 kms = get_kms(crtc_drm);
612
613 for (i = 0; i < sde_crtc->num_mixers; i++) {
614 hw_lm = sde_crtc->mixers[i].hw_lm;
615 hw_dspp = sde_crtc->mixers[i].hw_dspp;
616 if (!hw_lm->cfg.right_mixer)
617 break;
618 }
619
620 if (!hw_dspp) {
621 DRM_ERROR("invalid dspp\n");
622 return;
623 }
624
625 irq_idx = sde_core_irq_idx_lookup(kms, SDE_IRQ_TYPE_HIST_DSPP_DONE,
626 hw_dspp->idx);
627 if (irq_idx < 0) {
628 DRM_ERROR("failed to get irq idx\n");
629 return;
630 }
Xu Yang5e53c2e2017-07-11 16:46:28 +0800631
632 spin_lock_irqsave(&sde_crtc->spin_lock, flags);
633 node = _sde_cp_get_intr_node(DRM_EVENT_HISTOGRAM, sde_crtc);
634 spin_unlock_irqrestore(&sde_crtc->spin_lock, flags);
635
636 if (!node)
637 return;
638
Xu Yanged79cec2018-01-10 21:04:05 +0800639 spin_lock_irqsave(&node->state_lock, flags);
Xu Yang5e53c2e2017-07-11 16:46:28 +0800640 if (node->state == IRQ_DISABLED) {
641 ret = sde_core_irq_enable(kms, &irq_idx, 1);
642 if (ret)
643 DRM_ERROR("failed to enable irq %d\n", irq_idx);
644 else
645 node->state = IRQ_ENABLED;
646 }
Xu Yanged79cec2018-01-10 21:04:05 +0800647 spin_unlock_irqrestore(&node->state_lock, flags);
Xu Yang056d39b2017-07-11 16:34:13 +0800648}
649
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700650static void sde_cp_crtc_setfeature(struct sde_cp_node *prop_node,
Gopikrishnaiah Anandandb90fa12017-05-09 17:56:08 -0700651 struct sde_crtc *sde_crtc)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700652{
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700653 struct sde_hw_cp_cfg hw_cfg;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700654 struct sde_hw_mixer *hw_lm;
655 struct sde_hw_dspp *hw_dspp;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700656 u32 num_mixers = sde_crtc->num_mixers;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700657 int i = 0;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700658 bool feature_enabled = false;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700659 int ret = 0;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800660 struct sde_ad_hw_cfg ad_cfg;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700661
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700662 sde_cp_get_hw_payload(prop_node, &hw_cfg, &feature_enabled);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800663 hw_cfg.num_of_mixers = sde_crtc->num_mixers;
Gopikrishnaiah Anandandb90fa12017-05-09 17:56:08 -0700664 hw_cfg.last_feature = 0;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700665
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700666 for (i = 0; i < num_mixers && !ret; i++) {
667 hw_lm = sde_crtc->mixers[i].hw_lm;
668 hw_dspp = sde_crtc->mixers[i].hw_dspp;
Xu Yangf9c76112017-12-08 14:36:50 +0800669 if (!hw_lm) {
670 ret = -EINVAL;
671 continue;
672 }
Gopikrishnaiah Anandanfbf75392017-01-16 10:43:36 -0800673 hw_cfg.ctl = sde_crtc->mixers[i].hw_ctl;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800674 hw_cfg.mixer_info = hw_lm;
Xu Yangf9c76112017-12-08 14:36:50 +0800675 hw_cfg.displayh = num_mixers * hw_lm->cfg.out_width;
676 hw_cfg.displayv = hw_lm->cfg.out_height;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700677 switch (prop_node->feature) {
678 case SDE_CP_CRTC_DSPP_VLUT:
679 if (!hw_dspp || !hw_dspp->ops.setup_vlut) {
680 ret = -EINVAL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700681 continue;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700682 }
683 hw_dspp->ops.setup_vlut(hw_dspp, &hw_cfg);
684 break;
685 case SDE_CP_CRTC_DSPP_PCC:
686 if (!hw_dspp || !hw_dspp->ops.setup_pcc) {
687 ret = -EINVAL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700688 continue;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700689 }
690 hw_dspp->ops.setup_pcc(hw_dspp, &hw_cfg);
691 break;
692 case SDE_CP_CRTC_DSPP_IGC:
693 if (!hw_dspp || !hw_dspp->ops.setup_igc) {
694 ret = -EINVAL;
695 continue;
696 }
697 hw_dspp->ops.setup_igc(hw_dspp, &hw_cfg);
698 break;
699 case SDE_CP_CRTC_DSPP_GC:
700 if (!hw_dspp || !hw_dspp->ops.setup_gc) {
701 ret = -EINVAL;
702 continue;
703 }
704 hw_dspp->ops.setup_gc(hw_dspp, &hw_cfg);
705 break;
Rajesh Yadav284947c2017-07-21 20:32:13 +0530706 case SDE_CP_CRTC_DSPP_HSIC:
707 if (!hw_dspp || !hw_dspp->ops.setup_pa_hsic) {
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700708 ret = -EINVAL;
709 continue;
710 }
Rajesh Yadav284947c2017-07-21 20:32:13 +0530711 hw_dspp->ops.setup_pa_hsic(hw_dspp, &hw_cfg);
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700712 break;
Rajesh Yadav7b8fbae2017-08-28 14:48:14 +0530713 case SDE_CP_CRTC_DSPP_MEMCOL_SKIN:
714 if (!hw_dspp || !hw_dspp->ops.setup_pa_memcol_skin) {
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700715 ret = -EINVAL;
716 continue;
Stephen Boyd22f7b512017-03-01 16:56:35 -0800717 }
Rajesh Yadav7b8fbae2017-08-28 14:48:14 +0530718 hw_dspp->ops.setup_pa_memcol_skin(hw_dspp, &hw_cfg);
719 break;
720 case SDE_CP_CRTC_DSPP_MEMCOL_SKY:
721 if (!hw_dspp || !hw_dspp->ops.setup_pa_memcol_sky) {
722 ret = -EINVAL;
723 continue;
724 }
725 hw_dspp->ops.setup_pa_memcol_sky(hw_dspp, &hw_cfg);
726 break;
727 case SDE_CP_CRTC_DSPP_MEMCOL_FOLIAGE:
728 if (!hw_dspp || !hw_dspp->ops.setup_pa_memcol_foliage) {
729 ret = -EINVAL;
730 continue;
731 }
732 hw_dspp->ops.setup_pa_memcol_foliage(hw_dspp, &hw_cfg);
733 break;
734 case SDE_CP_CRTC_DSPP_MEMCOL_PROT:
735 if (!hw_dspp || !hw_dspp->ops.setup_pa_memcol_prot) {
736 ret = -EINVAL;
737 continue;
738 }
739 hw_dspp->ops.setup_pa_memcol_prot(hw_dspp, &hw_cfg);
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700740 break;
741 case SDE_CP_CRTC_DSPP_SIXZONE:
742 if (!hw_dspp || !hw_dspp->ops.setup_sixzone) {
743 ret = -EINVAL;
744 continue;
745 }
746 hw_dspp->ops.setup_sixzone(hw_dspp, &hw_cfg);
747 break;
748 case SDE_CP_CRTC_DSPP_GAMUT:
749 if (!hw_dspp || !hw_dspp->ops.setup_gamut) {
750 ret = -EINVAL;
751 continue;
752 }
753 hw_dspp->ops.setup_gamut(hw_dspp, &hw_cfg);
754 break;
755 case SDE_CP_CRTC_LM_GC:
Xu Yangf9c76112017-12-08 14:36:50 +0800756 if (!hw_lm->ops.setup_gc) {
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700757 ret = -EINVAL;
758 continue;
759 }
760 hw_lm->ops.setup_gc(hw_lm, &hw_cfg);
761 break;
Xu Yang30f2ccc2018-02-06 15:56:33 +0800762 case SDE_CP_CRTC_DSPP_DITHER:
763 if (!hw_dspp || !hw_dspp->ops.setup_pa_dither) {
764 ret = -EINVAL;
765 continue;
766 }
767 hw_dspp->ops.setup_pa_dither(hw_dspp, &hw_cfg);
768 break;
Xu Yang056d39b2017-07-11 16:34:13 +0800769 case SDE_CP_CRTC_DSPP_HIST_CTRL:
770 if (!hw_dspp || !hw_dspp->ops.setup_histogram) {
771 ret = -EINVAL;
772 continue;
773 }
774 hw_dspp->ops.setup_histogram(hw_dspp, &feature_enabled);
775 break;
776 case SDE_CP_CRTC_DSPP_HIST_IRQ:
Xu Yangf9c76112017-12-08 14:36:50 +0800777 if (!hw_dspp) {
Xu Yang056d39b2017-07-11 16:34:13 +0800778 ret = -EINVAL;
779 continue;
780 }
781 if (!hw_lm->cfg.right_mixer)
782 _sde_cp_crtc_enable_hist_irq(sde_crtc);
783 break;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800784 case SDE_CP_CRTC_DSPP_AD_MODE:
785 if (!hw_dspp || !hw_dspp->ops.setup_ad) {
786 ret = -EINVAL;
787 continue;
788 }
789 ad_cfg.prop = AD_MODE;
790 ad_cfg.hw_cfg = &hw_cfg;
791 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
792 break;
793 case SDE_CP_CRTC_DSPP_AD_INIT:
794 if (!hw_dspp || !hw_dspp->ops.setup_ad) {
795 ret = -EINVAL;
796 continue;
797 }
798 ad_cfg.prop = AD_INIT;
799 ad_cfg.hw_cfg = &hw_cfg;
800 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
801 break;
802 case SDE_CP_CRTC_DSPP_AD_CFG:
803 if (!hw_dspp || !hw_dspp->ops.setup_ad) {
804 ret = -EINVAL;
805 continue;
806 }
807 ad_cfg.prop = AD_CFG;
808 ad_cfg.hw_cfg = &hw_cfg;
809 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
810 break;
811 case SDE_CP_CRTC_DSPP_AD_INPUT:
812 if (!hw_dspp || !hw_dspp->ops.setup_ad) {
813 ret = -EINVAL;
814 continue;
815 }
816 ad_cfg.prop = AD_INPUT;
817 ad_cfg.hw_cfg = &hw_cfg;
818 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
819 break;
820 case SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS:
821 if (!hw_dspp || !hw_dspp->ops.setup_ad) {
822 ret = -EINVAL;
823 continue;
824 }
825 ad_cfg.prop = AD_ASSERTIVE;
826 ad_cfg.hw_cfg = &hw_cfg;
827 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
828 break;
829 case SDE_CP_CRTC_DSPP_AD_BACKLIGHT:
830 if (!hw_dspp || !hw_dspp->ops.setup_ad) {
831 ret = -EINVAL;
832 continue;
833 }
834 ad_cfg.prop = AD_BACKLIGHT;
835 ad_cfg.hw_cfg = &hw_cfg;
836 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
837 break;
Xu Yangd59dd922017-12-26 14:22:25 +0800838 case SDE_CP_CRTC_DSPP_AD_STRENGTH:
839 if (!hw_dspp || !hw_dspp->ops.setup_ad) {
840 ret = -EINVAL;
841 continue;
842 }
843 ad_cfg.prop = AD_STRENGTH;
844 ad_cfg.hw_cfg = &hw_cfg;
845 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
846 break;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700847 default:
848 ret = -EINVAL;
849 break;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700850 }
851 }
852
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700853 if (ret) {
854 DRM_ERROR("failed to %s feature %d\n",
855 ((feature_enabled) ? "enable" : "disable"),
856 prop_node->feature);
857 return;
858 }
859
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700860 if (feature_enabled) {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700861 DRM_DEBUG_DRIVER("Add feature to active list %d\n",
862 prop_node->property_id);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800863 sde_cp_update_list(prop_node, sde_crtc, false);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700864 } else {
865 DRM_DEBUG_DRIVER("remove feature from active list %d\n",
866 prop_node->property_id);
867 list_del_init(&prop_node->active_list);
868 }
869 /* Programming of feature done remove from dirty list */
870 list_del_init(&prop_node->dirty_list);
871}
872
873void sde_cp_crtc_apply_properties(struct drm_crtc *crtc)
874{
875 struct sde_crtc *sde_crtc = NULL;
876 bool set_dspp_flush = false, set_lm_flush = false;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -0700877 struct sde_cp_node *prop_node = NULL, *n = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700878 struct sde_hw_ctl *ctl;
879 uint32_t flush_mask = 0;
880 u32 num_mixers = 0, i = 0;
Ping Lic51f40b2018-01-26 17:19:30 -0800881 u32 sde_dspp_feature = SDE_DSPP_MAX;
882 struct msm_drm_private *priv = NULL;
883 struct sde_kms *sde_kms = NULL;
884 bool mdss_bus_vote = false;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700885
886 if (!crtc || !crtc->dev) {
887 DRM_ERROR("invalid crtc %pK dev %pK\n", crtc,
888 (crtc ? crtc->dev : NULL));
889 return;
890 }
891
892 sde_crtc = to_sde_crtc(crtc);
893 if (!sde_crtc) {
894 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
895 return;
896 }
897
898 num_mixers = sde_crtc->num_mixers;
899 if (!num_mixers) {
900 DRM_DEBUG_DRIVER("no mixers for this crtc\n");
901 return;
902 }
903
Ping Lic51f40b2018-01-26 17:19:30 -0800904 priv = crtc->dev->dev_private;
905 if (!priv || !priv->kms) {
906 SDE_ERROR("invalid kms\n");
907 return;
908 }
909 sde_kms = to_sde_kms(priv->kms);
910 if (!sde_kms) {
911 SDE_ERROR("invalid sde kms\n");
912 return;
913 }
914
Xu Yang1b3a5d92017-09-13 11:37:54 +0800915 mutex_lock(&sde_crtc->crtc_cp_lock);
916
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800917 /* Check if dirty lists are empty and ad features are disabled for
918 * early return. If ad properties are active then we need to issue
919 * dspp flush.
920 **/
921 if (list_empty(&sde_crtc->dirty_list) &&
922 list_empty(&sde_crtc->ad_dirty)) {
923 if (list_empty(&sde_crtc->ad_active)) {
924 DRM_DEBUG_DRIVER("Dirty list is empty\n");
Xu Yang1b3a5d92017-09-13 11:37:54 +0800925 goto exit;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800926 }
Ping Lie505f3b2017-06-19 14:19:08 -0700927 sde_cp_ad_set_prop(sde_crtc, AD_IPC_RESET);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800928 set_dspp_flush = true;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700929 }
930
931 list_for_each_entry_safe(prop_node, n, &sde_crtc->dirty_list,
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800932 dirty_list) {
Ping Lic51f40b2018-01-26 17:19:30 -0800933 sde_dspp_feature = crtc_feature_map[prop_node->feature];
934 if (!mdss_bus_vote && HIGH_BUS_VOTE_NEEDED(prop_node->feature)
935 && !reg_dmav1_dspp_feature_support(sde_dspp_feature)) {
936 sde_power_scale_reg_bus(&priv->phandle,
937 sde_kms->core_client,
938 VOTE_INDEX_HIGH, false);
939 pr_debug("Vote HIGH for data bus: feature %d\n",
940 prop_node->feature);
941 mdss_bus_vote = true;
942 }
Gopikrishnaiah Anandandb90fa12017-05-09 17:56:08 -0700943 sde_cp_crtc_setfeature(prop_node, sde_crtc);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700944 /* Set the flush flag to true */
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700945 if (prop_node->is_dspp_feature)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700946 set_dspp_flush = true;
947 else
948 set_lm_flush = true;
949 }
Ping Lic51f40b2018-01-26 17:19:30 -0800950 if (mdss_bus_vote) {
951 sde_power_scale_reg_bus(&priv->phandle, sde_kms->core_client,
952 VOTE_INDEX_LOW, false);
953 pr_debug("Vote LOW for data bus\n");
954 mdss_bus_vote = false;
955 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700956
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800957 list_for_each_entry_safe(prop_node, n, &sde_crtc->ad_dirty,
958 dirty_list) {
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800959 set_dspp_flush = true;
Gopikrishnaiah Anandandb90fa12017-05-09 17:56:08 -0700960 sde_cp_crtc_setfeature(prop_node, sde_crtc);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -0800961 }
962
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700963 for (i = 0; i < num_mixers; i++) {
964 ctl = sde_crtc->mixers[i].hw_ctl;
965 if (!ctl)
966 continue;
967 if (set_dspp_flush && ctl->ops.get_bitmask_dspp
Stephen Boyd22f7b512017-03-01 16:56:35 -0800968 && sde_crtc->mixers[i].hw_dspp) {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700969 ctl->ops.get_bitmask_dspp(ctl,
970 &flush_mask,
971 sde_crtc->mixers[i].hw_dspp->idx);
972 ctl->ops.update_pending_flush(ctl, flush_mask);
Stephen Boyd22f7b512017-03-01 16:56:35 -0800973 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700974 if (set_lm_flush && ctl->ops.get_bitmask_mixer
Stephen Boyd22f7b512017-03-01 16:56:35 -0800975 && sde_crtc->mixers[i].hw_lm) {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700976 flush_mask = ctl->ops.get_bitmask_mixer(ctl,
977 sde_crtc->mixers[i].hw_lm->idx);
978 ctl->ops.update_pending_flush(ctl, flush_mask);
Stephen Boyd22f7b512017-03-01 16:56:35 -0800979 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700980 }
Xu Yang1b3a5d92017-09-13 11:37:54 +0800981exit:
982 mutex_unlock(&sde_crtc->crtc_cp_lock);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700983}
984
985void sde_cp_crtc_install_properties(struct drm_crtc *crtc)
986{
987 struct sde_kms *kms = NULL;
988 struct sde_crtc *sde_crtc = NULL;
989 struct sde_mdss_cfg *catalog = NULL;
990 unsigned long features = 0;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -0700991 int i = 0;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700992 struct msm_drm_private *priv;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700993
994 if (!crtc || !crtc->dev || !crtc->dev->dev_private) {
995 DRM_ERROR("invalid crtc %pK dev %pK\n",
996 crtc, ((crtc) ? crtc->dev : NULL));
997 return;
998 }
999
1000 sde_crtc = to_sde_crtc(crtc);
Gopikrishnaiah Anandan7f6ef942016-06-20 15:50:00 -07001001 if (!sde_crtc) {
1002 DRM_ERROR("sde_crtc %pK\n", sde_crtc);
1003 return;
1004 }
1005
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001006 kms = get_kms(crtc);
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001007 if (!kms || !kms->catalog) {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001008 DRM_ERROR("invalid sde kms %pK catalog %pK sde_crtc %pK\n",
1009 kms, ((kms) ? kms->catalog : NULL), sde_crtc);
1010 return;
1011 }
1012
Xu Yang1b3a5d92017-09-13 11:37:54 +08001013 mutex_lock(&sde_crtc->crtc_cp_lock);
1014
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001015 /**
1016 * Function can be called during the atomic_check with test_only flag
1017 * and actual commit. Allocate properties only if feature list is
1018 * empty during the atomic_check with test_only flag.
1019 */
1020 if (!list_empty(&sde_crtc->feature_list))
Xu Yang1b3a5d92017-09-13 11:37:54 +08001021 goto exit;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001022
1023 catalog = kms->catalog;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001024 priv = crtc->dev->dev_private;
1025 /**
1026 * DSPP/LM properties are global to all the CRTCS.
1027 * Properties are created for first CRTC and re-used for later
1028 * crtcs.
1029 */
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001030 if (!priv->cp_property) {
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001031 priv->cp_property = kzalloc((sizeof(priv->cp_property) *
1032 SDE_CP_CRTC_MAX_FEATURES), GFP_KERNEL);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001033 setup_dspp_prop_install_funcs(dspp_prop_install_func);
1034 setup_lm_prop_install_funcs(lm_prop_install_func);
1035 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001036 if (!priv->cp_property)
Xu Yang1b3a5d92017-09-13 11:37:54 +08001037 goto exit;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001038
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001039 if (!catalog->dspp_count)
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001040 goto lm_property;
1041
1042 /* Check for all the DSPP properties and attach it to CRTC */
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001043 features = catalog->dspp[0].features;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001044 for (i = 0; i < SDE_DSPP_MAX; i++) {
1045 if (!test_bit(i, &features))
1046 continue;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001047 if (dspp_prop_install_func[i])
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001048 dspp_prop_install_func[i](crtc);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001049 }
1050
1051lm_property:
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001052 if (!catalog->mixer_count)
Xu Yang1b3a5d92017-09-13 11:37:54 +08001053 goto exit;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001054
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001055 /* Check for all the LM properties and attach it to CRTC */
1056 features = catalog->mixer[0].features;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001057 for (i = 0; i < SDE_MIXER_MAX; i++) {
1058 if (!test_bit(i, &features))
1059 continue;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001060 if (lm_prop_install_func[i])
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001061 lm_prop_install_func[i](crtc);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001062 }
Xu Yang1b3a5d92017-09-13 11:37:54 +08001063exit:
1064 mutex_unlock(&sde_crtc->crtc_cp_lock);
1065
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001066}
1067
1068int sde_cp_crtc_set_property(struct drm_crtc *crtc,
1069 struct drm_property *property,
1070 uint64_t val)
1071{
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -07001072 struct sde_cp_node *prop_node = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001073 struct sde_crtc *sde_crtc = NULL;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001074 int ret = 0, i = 0, dspp_cnt, lm_cnt;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001075 u8 found = 0;
1076
1077 if (!crtc || !property) {
1078 DRM_ERROR("invalid crtc %pK property %pK\n", crtc, property);
1079 return -EINVAL;
1080 }
1081
1082 sde_crtc = to_sde_crtc(crtc);
1083 if (!sde_crtc) {
1084 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
1085 return -EINVAL;
1086 }
1087
Xu Yang1b3a5d92017-09-13 11:37:54 +08001088 mutex_lock(&sde_crtc->crtc_cp_lock);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001089 list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) {
1090 if (property->base.id == prop_node->property_id) {
1091 found = 1;
1092 break;
1093 }
1094 }
1095
Lloyd Atkinsonadd42952017-10-31 14:27:55 -04001096 if (!found) {
1097 ret = -ENOENT;
Xu Yang1b3a5d92017-09-13 11:37:54 +08001098 goto exit;
Lloyd Atkinsonadd42952017-10-31 14:27:55 -04001099 }
Xu Yang1b3a5d92017-09-13 11:37:54 +08001100
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001101 /**
1102 * sde_crtc is virtual ensure that hardware has been attached to the
1103 * crtc. Check LM and dspp counts based on whether feature is a
1104 * dspp/lm feature.
1105 */
1106 if (!sde_crtc->num_mixers ||
1107 sde_crtc->num_mixers > ARRAY_SIZE(sde_crtc->mixers)) {
Xu Yangcbbefd72017-12-14 14:44:00 +08001108 DRM_INFO("Invalid mixer config act cnt %d max cnt %ld\n",
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001109 sde_crtc->num_mixers, ARRAY_SIZE(sde_crtc->mixers));
Xu Yang7e52b172017-10-26 14:28:23 +08001110 ret = -EPERM;
Xu Yang1b3a5d92017-09-13 11:37:54 +08001111 goto exit;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001112 }
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001113
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001114 dspp_cnt = 0;
1115 lm_cnt = 0;
1116 for (i = 0; i < sde_crtc->num_mixers; i++) {
1117 if (sde_crtc->mixers[i].hw_dspp)
1118 dspp_cnt++;
1119 if (sde_crtc->mixers[i].hw_lm)
1120 lm_cnt++;
1121 }
1122
1123 if (prop_node->is_dspp_feature && dspp_cnt < sde_crtc->num_mixers) {
1124 DRM_ERROR("invalid dspp cnt %d mixer cnt %d\n", dspp_cnt,
1125 sde_crtc->num_mixers);
Xu Yang1b3a5d92017-09-13 11:37:54 +08001126 ret = -EINVAL;
1127 goto exit;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001128 } else if (lm_cnt < sde_crtc->num_mixers) {
1129 DRM_ERROR("invalid lm cnt %d mixer cnt %d\n", lm_cnt,
1130 sde_crtc->num_mixers);
Xu Yang1b3a5d92017-09-13 11:37:54 +08001131 ret = -EINVAL;
1132 goto exit;
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001133 }
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001134
1135 ret = sde_cp_ad_validate_prop(prop_node, sde_crtc);
1136 if (ret) {
1137 DRM_ERROR("ad property validation failed ret %d\n", ret);
Xu Yang1b3a5d92017-09-13 11:37:54 +08001138 goto exit;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001139 }
1140
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001141 /* remove the property from dirty list */
1142 list_del_init(&prop_node->dirty_list);
1143
1144 if (!val)
1145 ret = sde_cp_disable_crtc_property(crtc, property, prop_node);
1146 else
1147 ret = sde_cp_enable_crtc_property(crtc, property,
1148 prop_node, val);
1149
1150 if (!ret) {
1151 /* remove the property from active list */
1152 list_del_init(&prop_node->active_list);
1153 /* Mark the feature as dirty */
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001154 sde_cp_update_list(prop_node, sde_crtc, true);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001155 }
Xu Yang1b3a5d92017-09-13 11:37:54 +08001156exit:
1157 mutex_unlock(&sde_crtc->crtc_cp_lock);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001158 return ret;
1159}
1160
1161int sde_cp_crtc_get_property(struct drm_crtc *crtc,
1162 struct drm_property *property, uint64_t *val)
1163{
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -07001164 struct sde_cp_node *prop_node = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001165 struct sde_crtc *sde_crtc = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001166
1167 if (!crtc || !property || !val) {
1168 DRM_ERROR("invalid crtc %pK property %pK val %pK\n",
1169 crtc, property, val);
1170 return -EINVAL;
1171 }
1172
1173 sde_crtc = to_sde_crtc(crtc);
1174 if (!sde_crtc) {
1175 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
1176 return -EINVAL;
1177 }
Gopikrishnaiah Anandand120b762016-10-05 12:03:42 -07001178 /* Return 0 if property is not supported */
1179 *val = 0;
Xu Yang1b3a5d92017-09-13 11:37:54 +08001180 mutex_lock(&sde_crtc->crtc_cp_lock);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001181 list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) {
1182 if (property->base.id == prop_node->property_id) {
1183 *val = prop_node->prop_val;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001184 break;
1185 }
1186 }
Xu Yang1b3a5d92017-09-13 11:37:54 +08001187 mutex_unlock(&sde_crtc->crtc_cp_lock);
Gopikrishnaiah Anandand120b762016-10-05 12:03:42 -07001188 return 0;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001189}
1190
1191void sde_cp_crtc_destroy_properties(struct drm_crtc *crtc)
1192{
1193 struct sde_crtc *sde_crtc = NULL;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -07001194 struct sde_cp_node *prop_node = NULL, *n = NULL;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001195
1196 if (!crtc) {
1197 DRM_ERROR("invalid crtc %pK\n", crtc);
1198 return;
1199 }
1200
1201 sde_crtc = to_sde_crtc(crtc);
1202 if (!sde_crtc) {
1203 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
1204 return;
1205 }
1206
1207 list_for_each_entry_safe(prop_node, n, &sde_crtc->feature_list,
1208 feature_list) {
1209 if (prop_node->prop_flags & DRM_MODE_PROP_BLOB
1210 && prop_node->blob_ptr)
1211 drm_property_unreference_blob(prop_node->blob_ptr);
1212
1213 list_del_init(&prop_node->active_list);
1214 list_del_init(&prop_node->dirty_list);
1215 list_del_init(&prop_node->feature_list);
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -07001216 sde_cp_destroy_local_blob(prop_node);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001217 kfree(prop_node);
1218 }
1219
Xu Yang5e53c2e2017-07-11 16:46:28 +08001220 if (sde_crtc->hist_blob)
1221 drm_property_unreference_blob(sde_crtc->hist_blob);
1222
Xu Yang1b3a5d92017-09-13 11:37:54 +08001223 mutex_destroy(&sde_crtc->crtc_cp_lock);
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -07001224 INIT_LIST_HEAD(&sde_crtc->active_list);
1225 INIT_LIST_HEAD(&sde_crtc->dirty_list);
1226 INIT_LIST_HEAD(&sde_crtc->feature_list);
1227}
Gopikrishnaiah Anandan7f6ef942016-06-20 15:50:00 -07001228
1229void sde_cp_crtc_suspend(struct drm_crtc *crtc)
1230{
1231 struct sde_crtc *sde_crtc = NULL;
Gopikrishnaiah Anandanb67b0d12016-06-23 11:43:08 -07001232 struct sde_cp_node *prop_node = NULL, *n = NULL;
Xu Yang0b8ab812018-01-29 14:03:10 +08001233 bool ad_suspend = false;
Gopikrishnaiah Anandan7f6ef942016-06-20 15:50:00 -07001234
1235 if (!crtc) {
1236 DRM_ERROR("crtc %pK\n", crtc);
1237 return;
1238 }
1239 sde_crtc = to_sde_crtc(crtc);
1240 if (!sde_crtc) {
1241 DRM_ERROR("sde_crtc %pK\n", sde_crtc);
1242 return;
1243 }
1244
Xu Yang1b3a5d92017-09-13 11:37:54 +08001245 mutex_lock(&sde_crtc->crtc_cp_lock);
Gopikrishnaiah Anandan7f6ef942016-06-20 15:50:00 -07001246 list_for_each_entry_safe(prop_node, n, &sde_crtc->active_list,
1247 active_list) {
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001248 sde_cp_update_list(prop_node, sde_crtc, true);
Gopikrishnaiah Anandan7f6ef942016-06-20 15:50:00 -07001249 list_del_init(&prop_node->active_list);
1250 }
Ping Li6d5bf542017-06-27 11:40:28 -07001251
1252 list_for_each_entry_safe(prop_node, n, &sde_crtc->ad_active,
1253 active_list) {
1254 sde_cp_update_list(prop_node, sde_crtc, true);
1255 list_del_init(&prop_node->active_list);
Xu Yang0b8ab812018-01-29 14:03:10 +08001256 ad_suspend = true;
Ping Li6d5bf542017-06-27 11:40:28 -07001257 }
Xu Yang1b3a5d92017-09-13 11:37:54 +08001258 mutex_unlock(&sde_crtc->crtc_cp_lock);
Xu Yang0b8ab812018-01-29 14:03:10 +08001259
1260 if (ad_suspend)
1261 sde_cp_ad_set_prop(sde_crtc, AD_SUSPEND);
Gopikrishnaiah Anandan7f6ef942016-06-20 15:50:00 -07001262}
1263
1264void sde_cp_crtc_resume(struct drm_crtc *crtc)
1265{
1266 /* placeholder for operations needed during resume */
1267}
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001268
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001269static void dspp_pcc_install_property(struct drm_crtc *crtc)
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001270{
1271 char feature_name[256];
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001272 struct sde_kms *kms = NULL;
1273 struct sde_mdss_cfg *catalog = NULL;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001274 u32 version;
1275
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001276 kms = get_kms(crtc);
1277 catalog = kms->catalog;
1278
1279 version = catalog->dspp[0].sblk->pcc.version >> 16;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001280 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1281 "SDE_DSPP_PCC_V", version);
1282 switch (version) {
1283 case 1:
Rajesh Yadavd490cb62017-07-04 13:20:42 +05301284 case 4:
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001285 sde_cp_crtc_install_blob_property(crtc, feature_name,
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -08001286 SDE_CP_CRTC_DSPP_PCC, sizeof(struct drm_msm_pcc));
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001287 break;
1288 default:
1289 DRM_ERROR("version %d not supported\n", version);
1290 break;
1291 }
1292}
1293
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001294static void dspp_hsic_install_property(struct drm_crtc *crtc)
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001295{
1296 char feature_name[256];
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001297 struct sde_kms *kms = NULL;
1298 struct sde_mdss_cfg *catalog = NULL;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001299 u32 version;
1300
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001301 kms = get_kms(crtc);
1302 catalog = kms->catalog;
1303 version = catalog->dspp[0].sblk->hsic.version >> 16;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001304 switch (version) {
1305 case 1:
1306 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
Rajesh Yadav284947c2017-07-21 20:32:13 +05301307 "SDE_DSPP_PA_HSIC_V", version);
1308 sde_cp_crtc_install_blob_property(crtc, feature_name,
1309 SDE_CP_CRTC_DSPP_HSIC, sizeof(struct drm_msm_pa_hsic));
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001310 break;
1311 default:
1312 DRM_ERROR("version %d not supported\n", version);
1313 break;
1314 }
1315}
1316
Rajesh Yadav7b8fbae2017-08-28 14:48:14 +05301317static void dspp_memcolor_install_property(struct drm_crtc *crtc)
1318{
1319 char feature_name[256];
1320 struct sde_kms *kms = NULL;
1321 struct sde_mdss_cfg *catalog = NULL;
1322 u32 version;
1323
1324 kms = get_kms(crtc);
1325 catalog = kms->catalog;
1326 version = catalog->dspp[0].sblk->memcolor.version >> 16;
1327 switch (version) {
1328 case 1:
1329 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1330 "SDE_DSPP_PA_MEMCOL_SKIN_V", version);
1331 sde_cp_crtc_install_blob_property(crtc, feature_name,
1332 SDE_CP_CRTC_DSPP_MEMCOL_SKIN,
1333 sizeof(struct drm_msm_memcol));
1334 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1335 "SDE_DSPP_PA_MEMCOL_SKY_V", version);
1336 sde_cp_crtc_install_blob_property(crtc, feature_name,
1337 SDE_CP_CRTC_DSPP_MEMCOL_SKY,
1338 sizeof(struct drm_msm_memcol));
1339 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1340 "SDE_DSPP_PA_MEMCOL_FOLIAGE_V", version);
1341 sde_cp_crtc_install_blob_property(crtc, feature_name,
1342 SDE_CP_CRTC_DSPP_MEMCOL_FOLIAGE,
1343 sizeof(struct drm_msm_memcol));
1344 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1345 "SDE_DSPP_PA_MEMCOL_PROT_V", version);
1346 sde_cp_crtc_install_blob_property(crtc, feature_name,
1347 SDE_CP_CRTC_DSPP_MEMCOL_PROT,
1348 sizeof(struct drm_msm_memcol));
1349 break;
1350 default:
1351 DRM_ERROR("version %d not supported\n", version);
1352 break;
1353 }
1354}
1355
Rajesh Yadav0a92eea2017-07-18 18:18:55 +05301356static void dspp_sixzone_install_property(struct drm_crtc *crtc)
1357{
1358 char feature_name[256];
1359 struct sde_kms *kms = NULL;
1360 struct sde_mdss_cfg *catalog = NULL;
1361 u32 version;
1362
1363 kms = get_kms(crtc);
1364 catalog = kms->catalog;
1365 version = catalog->dspp[0].sblk->sixzone.version >> 16;
1366 switch (version) {
1367 case 1:
1368 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1369 "SDE_DSPP_PA_SIXZONE_V", version);
1370 sde_cp_crtc_install_blob_property(crtc, feature_name,
1371 SDE_CP_CRTC_DSPP_SIXZONE,
1372 sizeof(struct drm_msm_sixzone));
1373 break;
1374 default:
1375 DRM_ERROR("version %d not supported\n", version);
1376 break;
1377 }
1378}
1379
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001380static void dspp_vlut_install_property(struct drm_crtc *crtc)
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001381{
1382 char feature_name[256];
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001383 struct sde_kms *kms = NULL;
1384 struct sde_mdss_cfg *catalog = NULL;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001385 u32 version;
1386
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001387 kms = get_kms(crtc);
1388 catalog = kms->catalog;
1389 version = catalog->dspp[0].sblk->vlut.version >> 16;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001390 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1391 "SDE_DSPP_VLUT_V", version);
1392 switch (version) {
1393 case 1:
1394 sde_cp_crtc_install_range_property(crtc, feature_name,
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001395 SDE_CP_CRTC_DSPP_VLUT, 0, U64_MAX, 0);
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001396 sde_cp_create_local_blob(crtc,
1397 SDE_CP_CRTC_DSPP_VLUT,
1398 sizeof(struct drm_msm_pa_vlut));
1399 break;
1400 default:
1401 DRM_ERROR("version %d not supported\n", version);
1402 break;
1403 }
1404}
1405
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001406static void dspp_ad_install_property(struct drm_crtc *crtc)
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001407{
1408 char feature_name[256];
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001409 struct sde_kms *kms = NULL;
1410 struct sde_mdss_cfg *catalog = NULL;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001411 u32 version;
1412
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001413 kms = get_kms(crtc);
1414 catalog = kms->catalog;
1415 version = catalog->dspp[0].sblk->ad.version >> 16;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001416 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1417 "SDE_DSPP_AD_V", version);
1418 switch (version) {
1419 case 3:
1420 sde_cp_crtc_install_immutable_property(crtc,
1421 feature_name, SDE_CP_CRTC_DSPP_AD);
1422 break;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001423 case 4:
1424 sde_cp_crtc_install_immutable_property(crtc,
1425 feature_name, SDE_CP_CRTC_DSPP_AD);
1426
1427 sde_cp_crtc_install_enum_property(crtc,
1428 SDE_CP_CRTC_DSPP_AD_MODE, ad4_modes,
1429 ARRAY_SIZE(ad4_modes), "SDE_DSPP_AD_V4_MODE");
1430
1431 sde_cp_crtc_install_range_property(crtc, "SDE_DSPP_AD_V4_INIT",
1432 SDE_CP_CRTC_DSPP_AD_INIT, 0, U64_MAX, 0);
1433 sde_cp_create_local_blob(crtc, SDE_CP_CRTC_DSPP_AD_INIT,
1434 sizeof(struct drm_msm_ad4_init));
1435
1436 sde_cp_crtc_install_range_property(crtc, "SDE_DSPP_AD_V4_CFG",
1437 SDE_CP_CRTC_DSPP_AD_CFG, 0, U64_MAX, 0);
1438 sde_cp_create_local_blob(crtc, SDE_CP_CRTC_DSPP_AD_CFG,
1439 sizeof(struct drm_msm_ad4_cfg));
1440 sde_cp_crtc_install_range_property(crtc,
Ping Lif41c2ef2017-05-04 14:40:45 -07001441 "SDE_DSPP_AD_V4_ASSERTIVENESS",
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001442 SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS, 0, (BIT(8) - 1), 0);
Xu Yangd59dd922017-12-26 14:22:25 +08001443 sde_cp_crtc_install_range_property(crtc,
1444 "SDE_DSPP_AD_V4_STRENGTH",
1445 SDE_CP_CRTC_DSPP_AD_STRENGTH, 0, (BIT(10) - 1), 0);
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001446 sde_cp_crtc_install_range_property(crtc, "SDE_DSPP_AD_V4_INPUT",
1447 SDE_CP_CRTC_DSPP_AD_INPUT, 0, U16_MAX, 0);
1448 sde_cp_crtc_install_range_property(crtc,
1449 "SDE_DSPP_AD_V4_BACKLIGHT",
1450 SDE_CP_CRTC_DSPP_AD_BACKLIGHT, 0, (BIT(16) - 1),
1451 0);
1452 break;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001453 default:
1454 DRM_ERROR("version %d not supported\n", version);
1455 break;
1456 }
1457}
1458
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001459static void lm_gc_install_property(struct drm_crtc *crtc)
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001460{
1461 char feature_name[256];
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001462 struct sde_kms *kms = NULL;
1463 struct sde_mdss_cfg *catalog = NULL;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001464 u32 version;
1465
Gopikrishnaiah Anandan703eb902016-10-06 18:43:57 -07001466 kms = get_kms(crtc);
1467 catalog = kms->catalog;
1468 version = catalog->mixer[0].sblk->gc.version >> 16;
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001469 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1470 "SDE_LM_GC_V", version);
1471 switch (version) {
1472 case 1:
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001473 sde_cp_crtc_install_blob_property(crtc, feature_name,
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -08001474 SDE_CP_CRTC_LM_GC, sizeof(struct drm_msm_pgc_lut));
Gopikrishnaiah Anandanf44cf202016-08-12 15:38:25 -07001475 break;
1476 default:
1477 DRM_ERROR("version %d not supported\n", version);
1478 break;
1479 }
1480}
Gopikrishnaiah Anandanfbf75392017-01-16 10:43:36 -08001481
1482static void dspp_gamut_install_property(struct drm_crtc *crtc)
1483{
1484 char feature_name[256];
1485 struct sde_kms *kms = NULL;
1486 struct sde_mdss_cfg *catalog = NULL;
1487 u32 version;
1488
1489 kms = get_kms(crtc);
1490 catalog = kms->catalog;
1491
1492 version = catalog->dspp[0].sblk->gamut.version >> 16;
1493 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1494 "SDE_DSPP_GAMUT_V", version);
1495 switch (version) {
1496 case 4:
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001497 sde_cp_crtc_install_blob_property(crtc, feature_name,
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -08001498 SDE_CP_CRTC_DSPP_GAMUT,
1499 sizeof(struct drm_msm_3d_gamut));
Gopikrishnaiah Anandanfbf75392017-01-16 10:43:36 -08001500 break;
1501 default:
1502 DRM_ERROR("version %d not supported\n", version);
1503 break;
1504 }
1505}
1506
1507static void dspp_gc_install_property(struct drm_crtc *crtc)
1508{
1509 char feature_name[256];
1510 struct sde_kms *kms = NULL;
1511 struct sde_mdss_cfg *catalog = NULL;
1512 u32 version;
1513
1514 kms = get_kms(crtc);
1515 catalog = kms->catalog;
1516
1517 version = catalog->dspp[0].sblk->gc.version >> 16;
1518 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1519 "SDE_DSPP_GC_V", version);
1520 switch (version) {
1521 case 1:
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001522 sde_cp_crtc_install_blob_property(crtc, feature_name,
Gopikrishnaiah Anandan29ed1512017-01-23 09:53:56 -08001523 SDE_CP_CRTC_DSPP_GC, sizeof(struct drm_msm_pgc_lut));
Gopikrishnaiah Anandanfbf75392017-01-16 10:43:36 -08001524 break;
1525 default:
1526 DRM_ERROR("version %d not supported\n", version);
1527 break;
1528 }
1529}
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001530
Rajesh Yadavec93afb2017-06-08 19:28:33 +05301531static void dspp_igc_install_property(struct drm_crtc *crtc)
1532{
1533 char feature_name[256];
1534 struct sde_kms *kms = NULL;
1535 struct sde_mdss_cfg *catalog = NULL;
1536 u32 version;
1537
1538 kms = get_kms(crtc);
1539 catalog = kms->catalog;
1540
1541 version = catalog->dspp[0].sblk->igc.version >> 16;
1542 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1543 "SDE_DSPP_IGC_V", version);
1544 switch (version) {
1545 case 3:
1546 sde_cp_crtc_install_blob_property(crtc, feature_name,
1547 SDE_CP_CRTC_DSPP_IGC, sizeof(struct drm_msm_igc_lut));
1548 break;
1549 default:
1550 DRM_ERROR("version %d not supported\n", version);
1551 break;
1552 }
1553}
1554
Xu Yang056d39b2017-07-11 16:34:13 +08001555static void dspp_hist_install_property(struct drm_crtc *crtc)
1556{
1557 struct sde_kms *kms = NULL;
1558 struct sde_mdss_cfg *catalog = NULL;
1559 u32 version;
1560
1561 kms = get_kms(crtc);
1562 catalog = kms->catalog;
1563
1564 version = catalog->dspp[0].sblk->hist.version >> 16;
1565 switch (version) {
1566 case 1:
1567 sde_cp_crtc_install_enum_property(crtc,
1568 SDE_CP_CRTC_DSPP_HIST_CTRL, sde_hist_modes,
1569 ARRAY_SIZE(sde_hist_modes), "SDE_DSPP_HIST_CTRL_V1");
1570 sde_cp_crtc_install_range_property(crtc, "SDE_DSPP_HIST_IRQ_V1",
1571 SDE_CP_CRTC_DSPP_HIST_IRQ, 0, U16_MAX, 0);
1572 break;
1573 default:
1574 DRM_ERROR("version %d not supported\n", version);
1575 break;
1576 }
1577}
1578
Xu Yang30f2ccc2018-02-06 15:56:33 +08001579static void dspp_dither_install_property(struct drm_crtc *crtc)
1580{
1581 char feature_name[256];
1582 struct sde_kms *kms = NULL;
1583 struct sde_mdss_cfg *catalog = NULL;
1584 u32 version;
1585
1586 kms = get_kms(crtc);
1587 catalog = kms->catalog;
1588
1589 version = catalog->dspp[0].sblk->dither.version >> 16;
1590 snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
1591 "SDE_DSPP_PA_DITHER_V", version);
1592 switch (version) {
1593 case 1:
1594 sde_cp_crtc_install_blob_property(crtc, feature_name,
1595 SDE_CP_CRTC_DSPP_DITHER,
1596 sizeof(struct drm_msm_pa_dither));
1597 break;
1598 default:
1599 DRM_ERROR("version %d not supported\n", version);
1600 break;
1601 }
1602}
1603
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001604static void sde_cp_update_list(struct sde_cp_node *prop_node,
1605 struct sde_crtc *crtc, bool dirty_list)
1606{
1607 switch (prop_node->feature) {
1608 case SDE_CP_CRTC_DSPP_AD_MODE:
1609 case SDE_CP_CRTC_DSPP_AD_INIT:
1610 case SDE_CP_CRTC_DSPP_AD_CFG:
1611 case SDE_CP_CRTC_DSPP_AD_INPUT:
1612 case SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS:
1613 case SDE_CP_CRTC_DSPP_AD_BACKLIGHT:
Xu Yangd59dd922017-12-26 14:22:25 +08001614 case SDE_CP_CRTC_DSPP_AD_STRENGTH:
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001615 if (dirty_list)
1616 list_add_tail(&prop_node->dirty_list, &crtc->ad_dirty);
1617 else
1618 list_add_tail(&prop_node->active_list,
1619 &crtc->ad_active);
1620 break;
1621 default:
1622 /* color processing properties handle here */
1623 if (dirty_list)
1624 list_add_tail(&prop_node->dirty_list,
1625 &crtc->dirty_list);
1626 else
1627 list_add_tail(&prop_node->active_list,
1628 &crtc->active_list);
1629 break;
1630 };
1631}
1632
1633static int sde_cp_ad_validate_prop(struct sde_cp_node *prop_node,
1634 struct sde_crtc *crtc)
1635{
1636 int i = 0, ret = 0;
1637 u32 ad_prop;
1638
1639 for (i = 0; i < crtc->num_mixers && !ret; i++) {
1640 if (!crtc->mixers[i].hw_dspp) {
1641 ret = -EINVAL;
1642 continue;
1643 }
1644 switch (prop_node->feature) {
1645 case SDE_CP_CRTC_DSPP_AD_MODE:
1646 ad_prop = AD_MODE;
1647 break;
1648 case SDE_CP_CRTC_DSPP_AD_INIT:
1649 ad_prop = AD_INIT;
1650 break;
1651 case SDE_CP_CRTC_DSPP_AD_CFG:
1652 ad_prop = AD_CFG;
1653 break;
1654 case SDE_CP_CRTC_DSPP_AD_INPUT:
1655 ad_prop = AD_INPUT;
1656 break;
1657 case SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS:
1658 ad_prop = AD_ASSERTIVE;
1659 break;
1660 case SDE_CP_CRTC_DSPP_AD_BACKLIGHT:
1661 ad_prop = AD_BACKLIGHT;
1662 break;
Xu Yangd59dd922017-12-26 14:22:25 +08001663 case SDE_CP_CRTC_DSPP_AD_STRENGTH:
1664 ad_prop = AD_STRENGTH;
1665 break;
Gopikrishnaiah Anandan9ba43782017-01-31 18:23:08 -08001666 default:
1667 /* Not an AD property */
1668 return 0;
1669 }
1670 if (!crtc->mixers[i].hw_dspp->ops.validate_ad)
1671 ret = -EINVAL;
1672 else
1673 ret = crtc->mixers[i].hw_dspp->ops.validate_ad(
1674 crtc->mixers[i].hw_dspp, &ad_prop);
1675 }
1676 return ret;
1677}
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001678
1679static void sde_cp_ad_interrupt_cb(void *arg, int irq_idx)
1680{
1681 struct sde_crtc *crtc = arg;
Gopikrishnaiah Anandanb6b401f2017-03-14 16:39:49 -07001682
Raviteja Tamatam1345f2e2018-02-08 16:15:51 +05301683 sde_crtc_event_queue(&crtc->base, sde_cp_notify_ad_event,
1684 NULL, true);
Gopikrishnaiah Anandanb6b401f2017-03-14 16:39:49 -07001685}
1686
1687static void sde_cp_notify_ad_event(struct drm_crtc *crtc_drm, void *arg)
1688{
Yuchao Ma9991ece2017-12-01 15:02:00 +08001689 uint32_t input_bl = 0, output_bl = 0;
1690 uint32_t scale = MAX_AD_BL_SCALE_LEVEL;
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001691 struct sde_hw_mixer *hw_lm = NULL;
1692 struct sde_hw_dspp *hw_dspp = NULL;
Gopikrishnaiah Anandanb6b401f2017-03-14 16:39:49 -07001693 u32 num_mixers;
1694 struct sde_crtc *crtc;
1695 struct drm_event event;
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001696 int i;
Ch Ganesh Kumar750b51d2018-02-09 11:44:42 +05301697 struct msm_drm_private *priv;
1698 struct sde_kms *kms;
1699 int ret;
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001700
Gopikrishnaiah Anandanb6b401f2017-03-14 16:39:49 -07001701 crtc = to_sde_crtc(crtc_drm);
1702 num_mixers = crtc->num_mixers;
1703 if (!num_mixers)
1704 return;
1705
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001706 for (i = 0; i < num_mixers; i++) {
1707 hw_lm = crtc->mixers[i].hw_lm;
1708 hw_dspp = crtc->mixers[i].hw_dspp;
1709 if (!hw_lm->cfg.right_mixer)
1710 break;
1711 }
1712
1713 if (!hw_dspp)
1714 return;
1715
Ch Ganesh Kumar750b51d2018-02-09 11:44:42 +05301716 kms = get_kms(crtc_drm);
1717 if (!kms || !kms->dev) {
1718 SDE_ERROR("invalid arg(s)\n");
1719 return;
1720 }
1721
1722 priv = kms->dev->dev_private;
1723 ret = sde_power_resource_enable(&priv->phandle, kms->core_client, true);
1724 if (ret) {
1725 SDE_ERROR("failed to enable power resource %d\n", ret);
1726 SDE_EVT32(ret, SDE_EVTLOG_ERROR);
1727 return;
1728 }
1729
Yuchao Ma9991ece2017-12-01 15:02:00 +08001730 hw_dspp->ops.ad_read_intr_resp(hw_dspp, AD4_IN_OUT_BACKLIGHT,
1731 &input_bl, &output_bl);
1732
Ch Ganesh Kumar750b51d2018-02-09 11:44:42 +05301733 sde_power_resource_enable(&priv->phandle, kms->core_client,
1734 false);
Yuchao Ma9991ece2017-12-01 15:02:00 +08001735 if (!input_bl || input_bl < output_bl)
1736 return;
1737
1738 scale = (output_bl * MAX_AD_BL_SCALE_LEVEL) / input_bl;
Gopikrishnaiah Anandanb6b401f2017-03-14 16:39:49 -07001739 event.length = sizeof(u32);
1740 event.type = DRM_EVENT_AD_BACKLIGHT;
Benjamin Chan34a92c72017-06-28 11:01:18 -04001741 msm_mode_object_event_notify(&crtc_drm->base, crtc_drm->dev,
Yuchao Ma9991ece2017-12-01 15:02:00 +08001742 &event, (u8 *)&scale);
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001743}
1744
1745int sde_cp_ad_interrupt(struct drm_crtc *crtc_drm, bool en,
1746 struct sde_irq_callback *ad_irq)
1747{
1748 struct sde_kms *kms = NULL;
1749 u32 num_mixers;
1750 struct sde_hw_mixer *hw_lm;
1751 struct sde_hw_dspp *hw_dspp = NULL;
1752 struct sde_crtc *crtc;
1753 int i;
1754 int irq_idx, ret;
Xu Yanged79cec2018-01-10 21:04:05 +08001755 unsigned long flags;
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001756 struct sde_cp_node prop_node;
Xu Yangda310e32017-08-25 15:12:46 +08001757 struct sde_crtc_irq_info *node = NULL;
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001758
1759 if (!crtc_drm || !ad_irq) {
1760 DRM_ERROR("invalid crtc %pK irq %pK\n", crtc_drm, ad_irq);
1761 return -EINVAL;
1762 }
1763
1764 crtc = to_sde_crtc(crtc_drm);
1765 if (!crtc) {
1766 DRM_ERROR("invalid sde_crtc %pK\n", crtc);
1767 return -EINVAL;
1768 }
1769
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001770 kms = get_kms(crtc_drm);
1771 num_mixers = crtc->num_mixers;
1772
1773 memset(&prop_node, 0, sizeof(prop_node));
1774 prop_node.feature = SDE_CP_CRTC_DSPP_AD_BACKLIGHT;
1775 ret = sde_cp_ad_validate_prop(&prop_node, crtc);
1776 if (ret) {
1777 DRM_ERROR("Ad not supported ret %d\n", ret);
1778 goto exit;
1779 }
1780
1781 for (i = 0; i < num_mixers; i++) {
1782 hw_lm = crtc->mixers[i].hw_lm;
1783 hw_dspp = crtc->mixers[i].hw_dspp;
1784 if (!hw_lm->cfg.right_mixer)
1785 break;
1786 }
1787
1788 if (!hw_dspp) {
1789 DRM_ERROR("invalid dspp\n");
1790 ret = -EINVAL;
1791 goto exit;
1792 }
1793
1794 irq_idx = sde_core_irq_idx_lookup(kms, SDE_IRQ_TYPE_AD4_BL_DONE,
1795 hw_dspp->idx);
1796 if (irq_idx < 0) {
1797 DRM_ERROR("failed to get the irq idx ret %d\n", irq_idx);
1798 ret = irq_idx;
1799 goto exit;
1800 }
1801
Xu Yangdca8eeb2018-03-26 14:16:09 +08001802 node = container_of(ad_irq, struct sde_crtc_irq_info, irq);
Xu Yangda310e32017-08-25 15:12:46 +08001803
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001804 if (!en) {
Xu Yangdca8eeb2018-03-26 14:16:09 +08001805 spin_lock_irqsave(&node->state_lock, flags);
1806 if (node->state == IRQ_ENABLED) {
1807 ret = sde_core_irq_disable(kms, &irq_idx, 1);
1808 if (ret)
1809 DRM_ERROR("disable irq %d error %d\n",
1810 irq_idx, ret);
1811 else
Xu Yangda310e32017-08-25 15:12:46 +08001812 node->state = IRQ_NOINIT;
Xu Yangda310e32017-08-25 15:12:46 +08001813 } else {
Xu Yangdca8eeb2018-03-26 14:16:09 +08001814 node->state = IRQ_NOINIT;
Xu Yangda310e32017-08-25 15:12:46 +08001815 }
Xu Yangdca8eeb2018-03-26 14:16:09 +08001816 spin_unlock_irqrestore(&node->state_lock, flags);
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001817 sde_core_irq_unregister_callback(kms, irq_idx, ad_irq);
1818 ret = 0;
1819 goto exit;
1820 }
1821
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001822 ad_irq->arg = crtc;
1823 ad_irq->func = sde_cp_ad_interrupt_cb;
1824 ret = sde_core_irq_register_callback(kms, irq_idx, ad_irq);
1825 if (ret) {
1826 DRM_ERROR("failed to register the callback ret %d\n", ret);
1827 goto exit;
1828 }
Xu Yangda310e32017-08-25 15:12:46 +08001829
Xu Yangdca8eeb2018-03-26 14:16:09 +08001830 spin_lock_irqsave(&node->state_lock, flags);
1831 if (node->state == IRQ_DISABLED || node->state == IRQ_NOINIT) {
Xu Yangda310e32017-08-25 15:12:46 +08001832 ret = sde_core_irq_enable(kms, &irq_idx, 1);
1833 if (ret) {
Xu Yangdca8eeb2018-03-26 14:16:09 +08001834 DRM_ERROR("enable irq %d error %d\n", irq_idx, ret);
1835 sde_core_irq_unregister_callback(kms, irq_idx, ad_irq);
1836 } else {
1837 node->state = IRQ_ENABLED;
Xu Yangda310e32017-08-25 15:12:46 +08001838 }
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001839 }
Xu Yangdca8eeb2018-03-26 14:16:09 +08001840 spin_unlock_irqrestore(&node->state_lock, flags);
1841
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001842exit:
Gopikrishnaiah Anandan5154c712017-02-27 17:48:24 -08001843 return ret;
1844}
Ping Lie505f3b2017-06-19 14:19:08 -07001845
1846static void sde_cp_ad_set_prop(struct sde_crtc *sde_crtc,
1847 enum ad_property ad_prop)
1848{
1849 struct sde_ad_hw_cfg ad_cfg;
1850 struct sde_hw_cp_cfg hw_cfg;
1851 struct sde_hw_dspp *hw_dspp = NULL;
1852 struct sde_hw_mixer *hw_lm = NULL;
1853 u32 num_mixers = sde_crtc->num_mixers;
1854 int i = 0, ret = 0;
1855
1856 hw_cfg.num_of_mixers = sde_crtc->num_mixers;
Ping Lie505f3b2017-06-19 14:19:08 -07001857
1858 for (i = 0; i < num_mixers && !ret; i++) {
1859 hw_lm = sde_crtc->mixers[i].hw_lm;
1860 hw_dspp = sde_crtc->mixers[i].hw_dspp;
1861 if (!hw_lm || !hw_dspp || !hw_dspp->ops.validate_ad ||
1862 !hw_dspp->ops.setup_ad) {
1863 ret = -EINVAL;
1864 continue;
1865 }
1866
Xu Yangf9c76112017-12-08 14:36:50 +08001867 hw_cfg.displayh = num_mixers * hw_lm->cfg.out_width;
1868 hw_cfg.displayv = hw_lm->cfg.out_height;
Ping Lie505f3b2017-06-19 14:19:08 -07001869 hw_cfg.mixer_info = hw_lm;
1870 ad_cfg.prop = ad_prop;
1871 ad_cfg.hw_cfg = &hw_cfg;
1872 ret = hw_dspp->ops.validate_ad(hw_dspp, (u32 *)&ad_prop);
1873 if (!ret)
1874 hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
1875 }
1876}
1877
1878void sde_cp_crtc_pre_ipc(struct drm_crtc *drm_crtc)
1879{
1880 struct sde_crtc *sde_crtc;
1881
1882 sde_crtc = to_sde_crtc(drm_crtc);
1883 if (!sde_crtc) {
1884 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
1885 return;
1886 }
1887
1888 sde_cp_ad_set_prop(sde_crtc, AD_IPC_SUSPEND);
1889}
1890
1891void sde_cp_crtc_post_ipc(struct drm_crtc *drm_crtc)
1892{
1893 struct sde_crtc *sde_crtc;
1894
1895 sde_crtc = to_sde_crtc(drm_crtc);
1896 if (!sde_crtc) {
1897 DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
1898 return;
1899 }
1900
1901 sde_cp_ad_set_prop(sde_crtc, AD_IPC_RESUME);
1902}
Xu Yang5e53c2e2017-07-11 16:46:28 +08001903
1904static void sde_cp_hist_interrupt_cb(void *arg, int irq_idx)
1905{
1906 struct sde_crtc *crtc = arg;
1907 struct drm_crtc *crtc_drm = &crtc->base;
1908 struct sde_hw_dspp *hw_dspp;
1909 struct sde_kms *kms;
1910 struct sde_crtc_irq_info *node = NULL;
1911 u32 i;
1912 int ret = 0;
1913 unsigned long flags;
1914
1915 /* disable histogram irq */
1916 kms = get_kms(crtc_drm);
1917 spin_lock_irqsave(&crtc->spin_lock, flags);
1918 node = _sde_cp_get_intr_node(DRM_EVENT_HISTOGRAM, crtc);
1919 spin_unlock_irqrestore(&crtc->spin_lock, flags);
1920
1921 if (!node) {
Xu Yangdca8eeb2018-03-26 14:16:09 +08001922 DRM_DEBUG_DRIVER("cannot find histogram event node in crtc\n");
Xu Yang5e53c2e2017-07-11 16:46:28 +08001923 return;
1924 }
1925
Xu Yanged79cec2018-01-10 21:04:05 +08001926 spin_lock_irqsave(&node->state_lock, flags);
Xu Yang5e53c2e2017-07-11 16:46:28 +08001927 if (node->state == IRQ_ENABLED) {
1928 if (sde_core_irq_disable_nolock(kms, irq_idx)) {
1929 DRM_ERROR("failed to disable irq %d, ret %d\n",
1930 irq_idx, ret);
Xu Yanged79cec2018-01-10 21:04:05 +08001931 spin_unlock_irqrestore(&node->state_lock, flags);
Xu Yang5e53c2e2017-07-11 16:46:28 +08001932 return;
1933 }
1934 node->state = IRQ_DISABLED;
1935 }
Xu Yanged79cec2018-01-10 21:04:05 +08001936 spin_unlock_irqrestore(&node->state_lock, flags);
Xu Yang5e53c2e2017-07-11 16:46:28 +08001937
1938 /* lock histogram buffer */
1939 for (i = 0; i < crtc->num_mixers; i++) {
1940 hw_dspp = crtc->mixers[i].hw_dspp;
1941 if (hw_dspp && hw_dspp->ops.lock_histogram)
1942 hw_dspp->ops.lock_histogram(hw_dspp, NULL);
1943 }
1944
1945 /* notify histogram event */
Raviteja Tamatam1345f2e2018-02-08 16:15:51 +05301946 sde_crtc_event_queue(crtc_drm, sde_cp_notify_hist_event,
1947 NULL, true);
Xu Yang5e53c2e2017-07-11 16:46:28 +08001948}
1949
1950static void sde_cp_notify_hist_event(struct drm_crtc *crtc_drm, void *arg)
1951{
1952 struct sde_hw_dspp *hw_dspp = NULL;
1953 struct sde_crtc *crtc;
1954 struct drm_event event;
1955 struct drm_msm_hist *hist_data;
1956 struct drm_msm_hist tmp_hist_data;
Ch Ganesh Kumar750b51d2018-02-09 11:44:42 +05301957 struct msm_drm_private *priv;
1958 struct sde_kms *kms;
1959 int ret;
Xu Yang5e53c2e2017-07-11 16:46:28 +08001960 u32 i, j;
1961
1962 if (!crtc_drm) {
1963 DRM_ERROR("invalid crtc %pK\n", crtc_drm);
1964 return;
1965 }
1966
1967 crtc = to_sde_crtc(crtc_drm);
1968 if (!crtc) {
1969 DRM_ERROR("invalid sde_crtc %pK\n", crtc);
1970 return;
1971 }
1972
1973 if (!crtc->hist_blob)
1974 return;
1975
Ch Ganesh Kumar750b51d2018-02-09 11:44:42 +05301976 kms = get_kms(crtc_drm);
1977 if (!kms || !kms->dev) {
1978 SDE_ERROR("invalid arg(s)\n");
1979 return;
1980 }
1981
1982 priv = kms->dev->dev_private;
1983 ret = sde_power_resource_enable(&priv->phandle, kms->core_client, true);
1984 if (ret) {
1985 SDE_ERROR("failed to enable power resource %d\n", ret);
1986 SDE_EVT32(ret, SDE_EVTLOG_ERROR);
1987 return;
1988 }
1989
Xu Yang5e53c2e2017-07-11 16:46:28 +08001990 /* read histogram data into blob */
1991 hist_data = (struct drm_msm_hist *)crtc->hist_blob->data;
1992 for (i = 0; i < crtc->num_mixers; i++) {
1993 hw_dspp = crtc->mixers[i].hw_dspp;
1994 if (!hw_dspp || !hw_dspp->ops.read_histogram) {
1995 DRM_ERROR("invalid dspp %pK or read_histogram func\n",
1996 hw_dspp);
Ch Ganesh Kumar750b51d2018-02-09 11:44:42 +05301997 sde_power_resource_enable(&priv->phandle,
1998 kms->core_client, false);
Xu Yang5e53c2e2017-07-11 16:46:28 +08001999 return;
2000 }
2001 if (!i) {
2002 hw_dspp->ops.read_histogram(hw_dspp, hist_data);
2003 } else {
2004 /* Merge hist data for DSPP0 and DSPP1 */
2005 hw_dspp->ops.read_histogram(hw_dspp, &tmp_hist_data);
2006 for (j = 0; j < HIST_V_SIZE; j++)
2007 hist_data->data[j] += tmp_hist_data.data[j];
2008 }
2009 }
2010
Ch Ganesh Kumar750b51d2018-02-09 11:44:42 +05302011 sde_power_resource_enable(&priv->phandle, kms->core_client,
2012 false);
Xu Yang5e53c2e2017-07-11 16:46:28 +08002013 /* send histogram event with blob id */
2014 event.length = sizeof(u32);
2015 event.type = DRM_EVENT_HISTOGRAM;
2016 msm_mode_object_event_notify(&crtc_drm->base, crtc_drm->dev,
2017 &event, (u8 *)(&crtc->hist_blob->base.id));
2018}
2019
2020int sde_cp_hist_interrupt(struct drm_crtc *crtc_drm, bool en,
2021 struct sde_irq_callback *hist_irq)
2022{
2023 struct sde_kms *kms = NULL;
2024 u32 num_mixers;
2025 struct sde_hw_mixer *hw_lm;
2026 struct sde_hw_dspp *hw_dspp = NULL;
2027 struct sde_crtc *crtc;
2028 struct sde_crtc_irq_info *node = NULL;
2029 int i, irq_idx, ret = 0;
Xu Yanged79cec2018-01-10 21:04:05 +08002030 unsigned long flags;
Xu Yang5e53c2e2017-07-11 16:46:28 +08002031
2032 if (!crtc_drm || !hist_irq) {
2033 DRM_ERROR("invalid crtc %pK irq %pK\n", crtc_drm, hist_irq);
2034 return -EINVAL;
2035 }
2036
2037 crtc = to_sde_crtc(crtc_drm);
2038 if (!crtc) {
2039 DRM_ERROR("invalid sde_crtc %pK\n", crtc);
2040 return -EINVAL;
2041 }
2042
2043 kms = get_kms(crtc_drm);
2044 num_mixers = crtc->num_mixers;
2045
2046 for (i = 0; i < num_mixers; i++) {
2047 hw_lm = crtc->mixers[i].hw_lm;
2048 hw_dspp = crtc->mixers[i].hw_dspp;
2049 if (!hw_lm->cfg.right_mixer)
2050 break;
2051 }
2052
2053 if (!hw_dspp) {
2054 DRM_ERROR("invalid dspp\n");
Xu Yang7e52b172017-10-26 14:28:23 +08002055 ret = -EPERM;
Xu Yang5e53c2e2017-07-11 16:46:28 +08002056 goto exit;
2057 }
2058
2059 irq_idx = sde_core_irq_idx_lookup(kms, SDE_IRQ_TYPE_HIST_DSPP_DONE,
2060 hw_dspp->idx);
2061 if (irq_idx < 0) {
2062 DRM_ERROR("failed to get the irq idx ret %d\n", irq_idx);
2063 ret = irq_idx;
2064 goto exit;
2065 }
2066
Xu Yangdca8eeb2018-03-26 14:16:09 +08002067 node = container_of(hist_irq, struct sde_crtc_irq_info, irq);
Xu Yang5e53c2e2017-07-11 16:46:28 +08002068
2069 /* deregister histogram irq */
2070 if (!en) {
Xu Yangdca8eeb2018-03-26 14:16:09 +08002071 spin_lock_irqsave(&node->state_lock, flags);
2072 if (node->state == IRQ_ENABLED) {
2073 node->state = IRQ_DISABLING;
2074 spin_unlock_irqrestore(&node->state_lock, flags);
2075 ret = sde_core_irq_disable(kms, &irq_idx, 1);
Xu Yanged79cec2018-01-10 21:04:05 +08002076 spin_lock_irqsave(&node->state_lock, flags);
Xu Yangdca8eeb2018-03-26 14:16:09 +08002077 if (ret) {
2078 DRM_ERROR("disable irq %d error %d\n",
2079 irq_idx, ret);
2080 node->state = IRQ_ENABLED;
Xu Yang5e53c2e2017-07-11 16:46:28 +08002081 } else {
2082 node->state = IRQ_NOINIT;
2083 }
Xu Yanged79cec2018-01-10 21:04:05 +08002084 spin_unlock_irqrestore(&node->state_lock, flags);
Xu Yangdca8eeb2018-03-26 14:16:09 +08002085 } else if (node->state == IRQ_DISABLED) {
2086 node->state = IRQ_NOINIT;
2087 spin_unlock_irqrestore(&node->state_lock, flags);
Xu Yang5e53c2e2017-07-11 16:46:28 +08002088 } else {
Xu Yangdca8eeb2018-03-26 14:16:09 +08002089 spin_unlock_irqrestore(&node->state_lock, flags);
Xu Yang5e53c2e2017-07-11 16:46:28 +08002090 }
2091
2092 sde_core_irq_unregister_callback(kms, irq_idx, hist_irq);
2093 goto exit;
2094 }
2095
2096 /* register histogram irq */
2097 hist_irq->arg = crtc;
2098 hist_irq->func = sde_cp_hist_interrupt_cb;
2099 ret = sde_core_irq_register_callback(kms, irq_idx, hist_irq);
2100 if (ret) {
2101 DRM_ERROR("failed to register the callback ret %d\n", ret);
2102 goto exit;
2103 }
2104
Xu Yangdca8eeb2018-03-26 14:16:09 +08002105 spin_lock_irqsave(&node->state_lock, flags);
2106 if (node->state == IRQ_DISABLED || node->state == IRQ_NOINIT) {
Xu Yang5e53c2e2017-07-11 16:46:28 +08002107 ret = sde_core_irq_enable(kms, &irq_idx, 1);
2108 if (ret) {
Xu Yangdca8eeb2018-03-26 14:16:09 +08002109 DRM_ERROR("enable irq %d error %d\n", irq_idx, ret);
Xu Yang5e53c2e2017-07-11 16:46:28 +08002110 sde_core_irq_unregister_callback(kms,
2111 irq_idx, hist_irq);
Xu Yangdca8eeb2018-03-26 14:16:09 +08002112 } else {
2113 node->state = IRQ_ENABLED;
Xu Yang5e53c2e2017-07-11 16:46:28 +08002114 }
2115 }
Xu Yangdca8eeb2018-03-26 14:16:09 +08002116 spin_unlock_irqrestore(&node->state_lock, flags);
2117
Xu Yang5e53c2e2017-07-11 16:46:28 +08002118exit:
2119 return ret;
2120}