blob: 6ac2c4b894c582940ed97c677f9ba66fbc67b282 [file] [log] [blame]
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#define pr_fmt(fmt) "%s: " fmt, __func__
15
16#include "mdss_fb.h"
17#include "mdss_mdp.h"
18#include "mdss_mdp_pp.h"
19#include <linux/uaccess.h>
20#include <linux/spinlock.h>
21#include <linux/delay.h>
22#include <linux/msm-bus.h>
23#include <linux/msm-bus-board.h>
24#include "mdss_mdp_pp_cache_config.h"
25
26struct mdp_csc_cfg mdp_csc_8bit_convert[MDSS_MDP_MAX_CSC] = {
27 [MDSS_MDP_CSC_YUV2RGB_601L] = {
28 0,
29 {
30 0x0254, 0x0000, 0x0331,
31 0x0254, 0xff37, 0xfe60,
32 0x0254, 0x0409, 0x0000,
33 },
34 { 0xfff0, 0xff80, 0xff80,},
35 { 0x0, 0x0, 0x0,},
36 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,},
37 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
38 },
39 [MDSS_MDP_CSC_YUV2RGB_601FR] = {
40 0,
41 {
42 0x0200, 0x0000, 0x02ce,
43 0x0200, 0xff50, 0xfe92,
44 0x0200, 0x038b, 0x0000,
45 },
46 { 0x0000, 0xff80, 0xff80,},
47 { 0x0, 0x0, 0x0,},
48 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
49 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
50 },
51 [MDSS_MDP_CSC_YUV2RGB_709L] = {
52 0,
53 {
54 0x0254, 0x0000, 0x0396,
55 0x0254, 0xff93, 0xfeef,
56 0x0254, 0x043e, 0x0000,
57 },
58 { 0xfff0, 0xff80, 0xff80,},
59 { 0x0, 0x0, 0x0,},
60 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,},
61 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
62 },
63 [MDSS_MDP_CSC_YUV2RGB_2020L] = {
64 0,
65 {
66 0x0256, 0x0000, 0x035e,
67 0x0256, 0xffa0, 0xfeb2,
68 0x0256, 0x044c, 0x0000,
69 },
70 { 0xfff0, 0xff80, 0xff80,},
71 { 0x0, 0x0, 0x0,},
72 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,},
73 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
74 },
75 [MDSS_MDP_CSC_YUV2RGB_2020FR] = {
76 0,
77 {
78 0x0200, 0x0000, 0x02f3,
79 0x0200, 0xffac, 0xfedb,
80 0x0200, 0x03c3, 0x0000,
81 },
82 { 0x0000, 0xff80, 0xff80,},
83 { 0x0, 0x0, 0x0,},
84 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
85 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
86 },
87 [MDSS_MDP_CSC_RGB2YUV_601L] = {
88 0,
89 {
90 0x0083, 0x0102, 0x0032,
91 0xffb4, 0xff6b, 0x00e1,
92 0x00e1, 0xff44, 0xffdb
93 },
94 { 0x0, 0x0, 0x0,},
95 { 0x0010, 0x0080, 0x0080,},
96 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
97 { 0x0010, 0x00eb, 0x0010, 0x00f0, 0x0010, 0x00f0,},
98 },
99 [MDSS_MDP_CSC_RGB2YUV_601FR] = {
100 0,
101 {
102 0x0099, 0x012d, 0x003a,
103 0xffaa, 0xff56, 0x0100,
104 0x0100, 0xff2a, 0xffd6
105 },
106 { 0x0, 0x0, 0x0,},
107 { 0x0000, 0x0080, 0x0080,},
108 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
109 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
110 },
111 [MDSS_MDP_CSC_RGB2YUV_709L] = {
112 0,
113 {
114 0x005d, 0x013a, 0x0020,
115 0xffcc, 0xff53, 0x00e1,
116 0x00e1, 0xff34, 0xffeb
117 },
118 { 0x0, 0x0, 0x0,},
119 { 0x0010, 0x0080, 0x0080,},
120 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
121 { 0x0010, 0x00eb, 0x0010, 0x00f0, 0x0010, 0x00f0,},
122 },
123 [MDSS_MDP_CSC_RGB2YUV_2020L] = {
124 0,
125 {
126 0x0073, 0x0129, 0x001a,
127 0xffc1, 0xff5e, 0x00e0,
128 0x00e0, 0xff32, 0xffee
129 },
130 { 0x0, 0x0, 0x0,},
131 { 0x0010, 0x0080, 0x0080,},
132 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
133 { 0x0010, 0x00eb, 0x0010, 0x00f0, 0x0010, 0x00f0,},
134 },
135 [MDSS_MDP_CSC_RGB2YUV_2020FR] = {
136 0,
137 {
138 0x0086, 0x015b, 0x001e,
139 0xffb9, 0xff47, 0x0100,
140 0x0100, 0xff15, 0xffeb
141 },
142 { 0x0, 0x0, 0x0,},
143 { 0x0, 0x0080, 0x0080,},
144 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
145 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
146 },
147 [MDSS_MDP_CSC_YUV2YUV] = {
148 0,
149 {
150 0x0200, 0x0000, 0x0000,
151 0x0000, 0x0200, 0x0000,
152 0x0000, 0x0000, 0x0200,
153 },
154 { 0x0, 0x0, 0x0,},
155 { 0x0, 0x0, 0x0,},
156 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
157 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
158 },
159 [MDSS_MDP_CSC_RGB2RGB] = {
160 0,
161 {
162 0x0200, 0x0000, 0x0000,
163 0x0000, 0x0200, 0x0000,
164 0x0000, 0x0000, 0x0200,
165 },
166 { 0x0, 0x0, 0x0,},
167 { 0x0, 0x0, 0x0,},
168 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
169 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
170 },
171};
172
173struct mdp_csc_cfg mdp_csc_10bit_convert[MDSS_MDP_MAX_CSC] = {
174 [MDSS_MDP_CSC_YUV2RGB_601L] = {
175 0,
176 {
177 0x0254, 0x0000, 0x0331,
178 0x0254, 0xff37, 0xfe60,
179 0x0254, 0x0409, 0x0000,
180 },
181 { 0xffc0, 0xfe00, 0xfe00,},
182 { 0x0, 0x0, 0x0,},
183 { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,},
184 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
185 },
186 [MDSS_MDP_CSC_YUV2RGB_601FR] = {
187 0,
188 {
189 0x0200, 0x0000, 0x02ce,
190 0x0200, 0xff50, 0xfe92,
191 0x0200, 0x038b, 0x0000,
192 },
193 { 0x0000, 0xfe00, 0xfe00,},
194 { 0x0, 0x0, 0x0,},
195 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
196 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
197 },
198 [MDSS_MDP_CSC_YUV2RGB_709L] = {
199 0,
200 {
201 0x0254, 0x0000, 0x0396,
202 0x0254, 0xff93, 0xfeef,
203 0x0254, 0x043a, 0x0000,
204 },
205 { 0xffc0, 0xfe00, 0xfe00,},
206 { 0x0, 0x0, 0x0,},
207 { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,},
208 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
209 },
210 [MDSS_MDP_CSC_YUV2RGB_2020L] = {
211 0,
212 {
213 0x0256, 0x0000, 0x035e,
214 0x0256, 0xffa0, 0xfeb2,
215 0x0256, 0x044c, 0x0000,
216 },
217 { 0xffc0, 0xfe00, 0xfe00,},
218 { 0x0, 0x0, 0x0,},
219 { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,},
220 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
221 },
222 [MDSS_MDP_CSC_YUV2RGB_2020FR] = {
223 0,
224 {
225 0x0200, 0x0000, 0x02f3,
226 0x0200, 0xffac, 0xfedb,
227 0x0200, 0x03c3, 0x0000,
228 },
229 { 0x0000, 0xfe00, 0xfe00,},
230 { 0x0, 0x0, 0x0,},
231 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
232 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
233 },
234 [MDSS_MDP_CSC_RGB2YUV_601L] = {
235 0,
236 {
237 0x0083, 0x0102, 0x0032,
238 0xffb4, 0xff6b, 0x00e1,
239 0x00e1, 0xff44, 0xffdb
240 },
241 { 0x0, 0x0, 0x0,},
242 { 0x0040, 0x0200, 0x0200,},
243 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
244 { 0x0040, 0x03ac, 0x0040, 0x03c0, 0x0040, 0x03c0,},
245 },
246 [MDSS_MDP_CSC_RGB2YUV_601FR] = {
247 0,
248 {
249 0x0099, 0x012d, 0x003a,
250 0xffaa, 0xff56, 0x0100,
251 0x0100, 0xff2a, 0xffd6
252 },
253 { 0x0, 0x0, 0x0,},
254 { 0x0000, 0x0200, 0x0200,},
255 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
256 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
257 },
258 [MDSS_MDP_CSC_RGB2YUV_709L] = {
259 0,
260 {
261 0x005d, 0x013a, 0x0020,
262 0xffcc, 0xff53, 0x00e1,
263 0x00e1, 0xff34, 0xffeb
264 },
265 { 0x0, 0x0, 0x0,},
266 { 0x0040, 0x0200, 0x0200,},
267 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
268 { 0x0040, 0x03ac, 0x0040, 0x03c0, 0x0040, 0x03c0,},
269 },
270 [MDSS_MDP_CSC_RGB2YUV_2020L] = {
271 0,
272 {
273 0x0073, 0x0129, 0x001a,
274 0xffc1, 0xff5e, 0x00e0,
275 0x00e0, 0xff32, 0xffee
276 },
277 { 0x0, 0x0, 0x0,},
278 { 0x0040, 0x0200, 0x0200,},
279 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
280 { 0x0040, 0x03ac, 0x0040, 0x03c0, 0x0040, 0x03c0,},
281 },
282 [MDSS_MDP_CSC_RGB2YUV_2020FR] = {
283 0,
284 {
285 0x0086, 0x015b, 0x001e,
286 0xffb9, 0xff47, 0x0100,
287 0x0100, 0xff15, 0xffeb
288 },
289 { 0x0, 0x0, 0x0,},
290 { 0x0, 0x0200, 0x0200,},
291 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
292 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
293 },
294 [MDSS_MDP_CSC_YUV2YUV] = {
295 0,
296 {
297 0x0200, 0x0000, 0x0000,
298 0x0000, 0x0200, 0x0000,
299 0x0000, 0x0000, 0x0200,
300 },
301 { 0x0, 0x0, 0x0,},
302 { 0x0, 0x0, 0x0,},
303 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
304 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
305 },
306 [MDSS_MDP_CSC_RGB2RGB] = {
307 0,
308 {
309 0x0200, 0x0000, 0x0000,
310 0x0000, 0x0200, 0x0000,
311 0x0000, 0x0000, 0x0200,
312 },
313 { 0x0, 0x0, 0x0,},
314 { 0x0, 0x0, 0x0,},
315 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
316 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
317 },
318};
319
320#define CSC_MV_OFF 0x0
321#define CSC_BV_OFF 0x2C
322#define CSC_LV_OFF 0x14
323#define CSC_POST_OFF 0xC
324#define CSC_10BIT_LV_SHIFT 16
325#define CSC_8BIT_LV_SHIFT 8
326
327
328#define HIST_INTR_DSPP_MASK 0xFFF000
329#define HIST_V2_INTR_BIT_MASK 0xF33000
330#define HIST_V1_INTR_BIT_MASK 0X333333
331#define HIST_WAIT_TIMEOUT(frame) ((75 * HZ * (frame)) / 1000)
332#define HIST_KICKOFF_WAIT_FRACTION 4
333
334/* hist collect state */
335enum {
336 HIST_UNKNOWN,
337 HIST_IDLE,
338 HIST_READY,
339};
340
341static u32 dither_matrix[16] = {
342 15, 7, 13, 5, 3, 11, 1, 9, 12, 4, 14, 6, 0, 8, 2, 10};
343static u32 dither_depth_map[9] = {
344 0, 0, 0, 0, 0, 1, 2, 3, 3};
345
346static u32 igc_limited[IGC_LUT_ENTRIES] = {
347 16777472, 17826064, 18874656, 19923248,
348 19923248, 20971840, 22020432, 23069024,
349 24117616, 25166208, 26214800, 26214800,
350 27263392, 28311984, 29360576, 30409168,
351 31457760, 32506352, 32506352, 33554944,
352 34603536, 35652128, 36700720, 37749312,
353 38797904, 38797904, 39846496, 40895088,
354 41943680, 42992272, 44040864, 45089456,
355 45089456, 46138048, 47186640, 48235232,
356 49283824, 50332416, 51381008, 51381008,
357 52429600, 53478192, 54526784, 55575376,
358 56623968, 57672560, 58721152, 58721152,
359 59769744, 60818336, 61866928, 62915520,
360 63964112, 65012704, 65012704, 66061296,
361 67109888, 68158480, 69207072, 70255664,
362 71304256, 71304256, 72352848, 73401440,
363 74450032, 75498624, 76547216, 77595808,
364 77595808, 78644400, 79692992, 80741584,
365 81790176, 82838768, 83887360, 83887360,
366 84935952, 85984544, 87033136, 88081728,
367 89130320, 90178912, 90178912, 91227504,
368 92276096, 93324688, 94373280, 95421872,
369 96470464, 96470464, 97519056, 98567648,
370 99616240, 100664832, 101713424, 102762016,
371 102762016, 103810608, 104859200, 105907792,
372 106956384, 108004976, 109053568, 109053568,
373 110102160, 111150752, 112199344, 113247936,
374 114296528, 115345120, 115345120, 116393712,
375 117442304, 118490896, 119539488, 120588080,
376 121636672, 121636672, 122685264, 123733856,
377 124782448, 125831040, 126879632, 127928224,
378 127928224, 128976816, 130025408, 131074000,
379 132122592, 133171184, 134219776, 135268368,
380 135268368, 136316960, 137365552, 138414144,
381 139462736, 140511328, 141559920, 141559920,
382 142608512, 143657104, 144705696, 145754288,
383 146802880, 147851472, 147851472, 148900064,
384 149948656, 150997248, 152045840, 153094432,
385 154143024, 154143024, 155191616, 156240208,
386 157288800, 158337392, 159385984, 160434576,
387 160434576, 161483168, 162531760, 163580352,
388 164628944, 165677536, 166726128, 166726128,
389 167774720, 168823312, 169871904, 170920496,
390 171969088, 173017680, 173017680, 174066272,
391 175114864, 176163456, 177212048, 178260640,
392 179309232, 179309232, 180357824, 181406416,
393 182455008, 183503600, 184552192, 185600784,
394 185600784, 186649376, 187697968, 188746560,
395 189795152, 190843744, 191892336, 191892336,
396 192940928, 193989520, 195038112, 196086704,
397 197135296, 198183888, 198183888, 199232480,
398 200281072, 201329664, 202378256, 203426848,
399 204475440, 204475440, 205524032, 206572624,
400 207621216, 208669808, 209718400, 210766992,
401 211815584, 211815584, 212864176, 213912768,
402 214961360, 216009952, 217058544, 218107136,
403 218107136, 219155728, 220204320, 221252912,
404 222301504, 223350096, 224398688, 224398688,
405 225447280, 226495872, 227544464, 228593056,
406 229641648, 230690240, 230690240, 231738832,
407 232787424, 233836016, 234884608, 235933200,
408 236981792, 236981792, 238030384, 239078976,
409 240127568, 241176160, 242224752, 243273344,
410 243273344, 244321936, 245370528, 246419120};
411
412
413#define MDSS_MDP_PA_SIZE 0xC
414#define MDSS_MDP_SIX_ZONE_SIZE 0xC
415#define MDSS_MDP_MEM_COL_SIZE 0x3C
416#define MDSS_MDP_GC_SIZE 0x28
417#define MDSS_MDP_PCC_SIZE 0xB8
418#define MDSS_MDP_GAMUT_SIZE 0x5C
419#define MDSS_MDP_IGC_DSPP_SIZE 0x28
420#define MDSS_MDP_IGC_SSPP_SIZE 0x88
421#define MDSS_MDP_VIG_QSEED2_SHARP_SIZE 0x0C
422#define TOTAL_BLEND_STAGES 0x4
423
424#define PP_FLAGS_DIRTY_PA 0x1
425#define PP_FLAGS_DIRTY_PCC 0x2
426#define PP_FLAGS_DIRTY_IGC 0x4
427#define PP_FLAGS_DIRTY_ARGC 0x8
428#define PP_FLAGS_DIRTY_ENHIST 0x10
429#define PP_FLAGS_DIRTY_DITHER 0x20
430#define PP_FLAGS_DIRTY_GAMUT 0x40
431#define PP_FLAGS_DIRTY_HIST_COL 0x80
432#define PP_FLAGS_DIRTY_PGC 0x100
433#define PP_FLAGS_DIRTY_SHARP 0x200
434/* Leave space for future features */
435#define PP_FLAGS_RESUME_COMMIT 0x10000000
436
437#define IS_PP_RESUME_COMMIT(x) ((x) & PP_FLAGS_RESUME_COMMIT)
438#define PP_FLAGS_LUT_BASED (PP_FLAGS_DIRTY_IGC | PP_FLAGS_DIRTY_GAMUT | \
439 PP_FLAGS_DIRTY_PGC | PP_FLAGS_DIRTY_ARGC)
440#define IS_PP_LUT_DIRTY(x) ((x) & PP_FLAGS_LUT_BASED)
441#define IS_SIX_ZONE_DIRTY(d, pa) (((d) & PP_FLAGS_DIRTY_PA) && \
442 ((pa) & MDP_PP_PA_SIX_ZONE_ENABLE))
443
444#define PP_SSPP 0
445#define PP_DSPP 1
446
447#define PP_AD_BAD_HW_NUM 255
448
449#define PP_AD_STATE_INIT 0x2
450#define PP_AD_STATE_CFG 0x4
451#define PP_AD_STATE_DATA 0x8
452#define PP_AD_STATE_RUN 0x10
453#define PP_AD_STATE_VSYNC 0x20
454#define PP_AD_STATE_BL_LIN 0x40
455#define PP_AD_STATE_IPC_RESUME 0x80
456#define PP_AD_STATE_IPC_RESET 0x100
457
458#define PP_AD_STATE_IS_INITCFG(st) (((st) & PP_AD_STATE_INIT) &&\
459 ((st) & PP_AD_STATE_CFG))
460
461#define PP_AD_STATE_IS_READY(st) (((st) & PP_AD_STATE_INIT) &&\
462 ((st) & PP_AD_STATE_CFG) &&\
463 ((st) & PP_AD_STATE_DATA))
464
465#define PP_AD_STS_DIRTY_INIT 0x2
466#define PP_AD_STS_DIRTY_CFG 0x4
467#define PP_AD_STS_DIRTY_DATA 0x8
468#define PP_AD_STS_DIRTY_VSYNC 0x10
469#define PP_AD_STS_DIRTY_ENABLE 0x20
470
471#define PP_AD_STS_IS_DIRTY(sts) (((sts) & PP_AD_STS_DIRTY_INIT) ||\
472 ((sts) & PP_AD_STS_DIRTY_CFG))
473
474/* Bits 0 and 1 and 5 */
475#define MDSS_AD_INPUT_AMBIENT (0x23)
476/* Bits 3 and 7 */
477#define MDSS_AD_INPUT_STRENGTH (0x88)
478/*
479 * Check data by shifting by mode to see if it matches to the
480 * MDSS_AD_INPUT_* bitfields
481 */
482#define MDSS_AD_MODE_DATA_MATCH(mode, data) ((1 << (mode)) & (data))
483#define MDSS_AD_RUNNING_AUTO_BL(ad) (((ad)->state & PP_AD_STATE_RUN) &&\
484 ((ad)->cfg.mode == MDSS_AD_MODE_AUTO_BL))
485#define MDSS_AD_RUNNING_AUTO_STR(ad) (((ad)->state & PP_AD_STATE_RUN) &&\
486 ((ad)->cfg.mode == MDSS_AD_MODE_AUTO_STR))
487#define MDSS_AD_AUTO_TRIGGER 0x80
488#define MDSS_AD_T_FILTER_CTRL_0 0
489#define MDSS_AD_IPC_FRAME_COUNT 2
490#define MDSS_AD_MODE_IPC_BIT 0x4
491#define MDSS_AD_MODE_MAN_IPC 0x5
492
493#define SHARP_STRENGTH_DEFAULT 32
494#define SHARP_EDGE_THR_DEFAULT 112
495#define SHARP_SMOOTH_THR_DEFAULT 8
496#define SHARP_NOISE_THR_DEFAULT 2
497
498static struct mdp_pp_driver_ops pp_driver_ops;
499static struct mdp_pp_feature_ops *pp_ops;
500
501static DEFINE_MUTEX(mdss_pp_mutex);
502static struct mdss_pp_res_type *mdss_pp_res;
503
504static u32 pp_hist_read(char __iomem *v_addr,
505 struct pp_hist_col_info *hist_info);
506static int pp_hist_setup(u32 *op, u32 block, struct mdss_mdp_mixer *mix,
507 struct pp_sts_type *pp_sts);
508static int pp_hist_disable(struct pp_hist_col_info *hist_info);
509static void pp_update_pcc_regs(char __iomem *addr,
510 struct mdp_pcc_cfg_data *cfg_ptr);
511static void pp_update_igc_lut(struct mdp_igc_lut_data *cfg,
512 char __iomem *addr, u32 blk_idx,
513 u32 total_idx);
514static void pp_update_gc_one_lut(char __iomem *addr,
515 struct mdp_ar_gc_lut_data *lut_data,
516 uint8_t num_stages);
517static void pp_update_argc_lut(char __iomem *addr,
518 struct mdp_pgc_lut_data *config);
519static void pp_update_hist_lut(char __iomem *base,
520 struct mdp_hist_lut_data *cfg);
521static int pp_gm_has_invalid_lut_size(struct mdp_gamut_cfg_data *config);
522static void pp_gamut_config(struct mdp_gamut_cfg_data *gamut_cfg,
523 char __iomem *base,
524 struct pp_sts_type *pp_sts);
525static void pp_pa_config(unsigned long flags, char __iomem *addr,
526 struct pp_sts_type *pp_sts,
527 struct mdp_pa_cfg *pa_config);
528static void pp_pa_v2_config(unsigned long flags, char __iomem *addr,
529 struct pp_sts_type *pp_sts,
530 struct mdp_pa_v2_data *pa_v2_config,
531 int mdp_location);
532static void pp_pcc_config(unsigned long flags, char __iomem *addr,
533 struct pp_sts_type *pp_sts,
534 struct mdp_pcc_cfg_data *pcc_config);
535static void pp_igc_config(unsigned long flags, char __iomem *addr,
536 struct pp_sts_type *pp_sts,
537 struct mdp_igc_lut_data *igc_config,
538 u32 pipe_num, u32 pipe_cnt);
539static void pp_enhist_config(unsigned long flags, char __iomem *addr,
540 struct pp_sts_type *pp_sts,
541 struct mdp_hist_lut_data *enhist_cfg);
542static void pp_dither_config(char __iomem *addr,
543 struct pp_sts_type *pp_sts,
544 struct mdp_dither_cfg_data *dither_cfg);
545static void pp_dspp_opmode_config(struct mdss_mdp_ctl *ctl, u32 num,
546 struct pp_sts_type *pp_sts, int mdp_rev,
547 u32 *opmode);
548static void pp_sharp_config(char __iomem *addr,
549 struct pp_sts_type *pp_sts,
550 struct mdp_sharp_cfg *sharp_config);
551static void pp_update_pa_v2_vig_opmode(struct pp_sts_type *pp_sts,
552 u32 *opmode);
553static int pp_copy_pa_six_zone_lut(struct mdp_pa_v2_cfg_data *pa_v2_config,
554 u32 disp_num);
555static void pp_update_pa_v2_global_adj_regs(char __iomem *addr,
556 struct mdp_pa_v2_data *pa_config);
557static void pp_update_pa_v2_mem_col(char __iomem *addr,
558 struct mdp_pa_v2_data *pa_v2_config);
559static void pp_update_pa_v2_mem_col_regs(char __iomem *addr,
560 struct mdp_pa_mem_col_cfg *cfg);
561static void pp_update_pa_v2_six_zone_regs(char __iomem *addr,
562 struct mdp_pa_v2_data *pa_v2_config);
563static void pp_update_pa_v2_sts(struct pp_sts_type *pp_sts,
564 struct mdp_pa_v2_data *pa_v2_config);
565static int pp_read_pa_v2_regs(char __iomem *addr,
566 struct mdp_pa_v2_data *pa_v2_config,
567 u32 disp_num);
568static void pp_read_pa_mem_col_regs(char __iomem *addr,
569 struct mdp_pa_mem_col_cfg *mem_col_cfg);
570static struct msm_fb_data_type *mdss_get_mfd_from_index(int index);
571static int mdss_mdp_mfd_valid_ad(struct msm_fb_data_type *mfd);
572static int mdss_mdp_get_ad(struct msm_fb_data_type *mfd,
573 struct mdss_ad_info **ad);
574static int pp_ad_invalidate_input(struct msm_fb_data_type *mfd);
575static void pp_ad_vsync_handler(struct mdss_mdp_ctl *ctl, ktime_t t);
576static void pp_ad_cfg_write(struct mdss_mdp_ad *ad_hw,
577 struct mdss_ad_info *ad);
578static void pp_ad_init_write(struct mdss_mdp_ad *ad_hw,
579 struct mdss_ad_info *ad, struct mdss_mdp_ctl *ctl);
580static void pp_ad_input_write(struct mdss_mdp_ad *ad_hw,
581 struct mdss_ad_info *ad);
582static int pp_ad_setup_hw_nums(struct msm_fb_data_type *mfd,
583 struct mdss_ad_info *ad);
584static void pp_ad_bypass_config(struct mdss_ad_info *ad,
585 struct mdss_mdp_ctl *ctl, u32 num, u32 *opmode);
586static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd);
587static void pp_ad_cfg_lut(char __iomem *addr, u32 *data);
588static int pp_ad_attenuate_bl(struct mdss_ad_info *ad, u32 bl, u32 *bl_out);
589static int pp_ad_linearize_bl(struct mdss_ad_info *ad, u32 bl, u32 *bl_out,
590 int inv);
591static int pp_ad_calc_bl(struct msm_fb_data_type *mfd, int bl_in, int *bl_out,
592 bool *bl_out_notify);
593static int pp_num_to_side(struct mdss_mdp_ctl *ctl, u32 num);
594static int pp_update_pcc_pipe_setup(struct mdss_mdp_pipe *pipe, u32 location);
595static void mdss_mdp_hist_irq_set_mask(u32 irq);
596static void mdss_mdp_hist_irq_clear_mask(u32 irq);
597static void mdss_mdp_hist_intr_notify(u32 disp);
598static int mdss_mdp_panel_default_dither_config(struct msm_fb_data_type *mfd,
599 u32 panel_bpp, bool enable);
600static int mdss_mdp_limited_lut_igc_config(struct msm_fb_data_type *mfd,
601 bool enable);
602static inline int pp_validate_dspp_mfd_block(struct msm_fb_data_type *mfd,
603 int block);
604static int pp_mfd_release_all(struct msm_fb_data_type *mfd);
605static int pp_mfd_ad_release_all(struct msm_fb_data_type *mfd);
606static int mdss_mdp_ad_ipc_reset(struct msm_fb_data_type *mfd);
607static int pp_get_driver_ops(struct mdp_pp_driver_ops *ops);
608static int pp_ppb_setup(struct mdss_mdp_mixer *mixer);
609
610static u32 last_sts, last_state;
611
612static inline void mdss_mdp_pp_get_dcm_state(struct mdss_mdp_pipe *pipe,
613 u32 *dcm_state)
614{
615 if (pipe && pipe->mixer_left && pipe->mixer_left->ctl &&
616 pipe->mixer_left->ctl->mfd)
617 *dcm_state = pipe->mixer_left->ctl->mfd->dcm_state;
618}
619
620inline int linear_map(int in, int *out, int in_max, int out_max)
621{
622 if (in < 0 || !out || in_max <= 0 || out_max <= 0)
623 return -EINVAL;
624 *out = ((2 * (in * out_max) + in_max) / (2 * in_max));
625 pr_debug("in = %d, out = %d, in_max = %d, out_max = %d\n",
626 in, *out, in_max, out_max);
627 if ((in > 0) && (*out == 0))
628 *out = 1;
629 return 0;
630
631}
632
633/**
634 * __get_hist_pipe() - get a pipe only if histogram is supported on it
635 * @pnum: pipe number desired
636 *
637 * returns the pipe with id only if the pipe supports sspp histogram
638 */
639static inline struct mdss_mdp_pipe *__get_hist_pipe(int pnum)
640{
641 enum mdss_mdp_pipe_type ptype;
642
643 ptype = get_pipe_type_from_num(pnum);
644
645 /* only VIG pipes support histogram */
646 if (ptype != MDSS_MDP_PIPE_TYPE_VIG)
647 return NULL;
648
649 return mdss_mdp_pipe_get(BIT(pnum), MDSS_MDP_PIPE_RECT0);
650}
651
652int mdss_mdp_csc_setup_data(u32 block, u32 blk_idx, struct mdp_csc_cfg *data)
653{
654 int i, ret = 0;
655 char __iomem *base, *addr;
656 u32 val = 0, lv_shift = 0;
657 struct mdss_data_type *mdata;
658 struct mdss_mdp_pipe *pipe;
659 struct mdss_mdp_cdm *cdm;
660 struct mdss_mdp_writeback *wb;
661
662 if (data == NULL) {
663 pr_err("no csc matrix specified\n");
664 return -EINVAL;
665 }
666
667 mdata = mdss_mdp_get_mdata();
668 switch (block) {
669 case MDSS_MDP_BLOCK_SSPP:
670 lv_shift = CSC_8BIT_LV_SHIFT;
671 /*
672 * CSC is used on VIG pipes and currently VIG pipes do not
673 * support multirect so always use RECT0.
674 */
675 pipe = mdss_mdp_pipe_search(mdata, BIT(blk_idx),
676 MDSS_MDP_PIPE_RECT0);
677 if (!pipe) {
678 pr_err("invalid blk index=%d\n", blk_idx);
679 ret = -EINVAL;
680 break;
681 }
682 if (mdss_mdp_pipe_is_yuv(pipe)) {
683 base = pipe->base + MDSS_MDP_REG_VIG_CSC_1_BASE;
684 } else {
685 pr_err("non ViG pipe %d for CSC is not allowed\n",
686 blk_idx);
687 ret = -EINVAL;
688 }
689 break;
690 case MDSS_MDP_BLOCK_WB:
691 lv_shift = CSC_8BIT_LV_SHIFT;
692 if (blk_idx < mdata->nwb) {
693 wb = mdata->wb + blk_idx;
694 if (wb->base)
695 base = wb->base + MDSS_MDP_REG_WB_CSC_BASE;
696 else
697 ret = -EINVAL;
698 } else {
699 ret = -EINVAL;
700 }
701 break;
702 case MDSS_MDP_BLOCK_CDM:
703 lv_shift = CSC_10BIT_LV_SHIFT;
704 if (blk_idx < mdata->ncdm) {
705 cdm = mdata->cdm_off + blk_idx;
706 if (cdm->base)
707 base = cdm->base +
708 MDSS_MDP_REG_CDM_CSC_10_BASE;
709 else
710 ret = -EINVAL;
711 } else {
712 ret = -EINVAL;
713 }
714 break;
715 case MDSS_MDP_BLOCK_SSPP_10:
716 lv_shift = CSC_10BIT_LV_SHIFT;
717
718 /* CSC can be applied only on VIG which RECT0 only */
719 pipe = mdss_mdp_pipe_search(mdata, BIT(blk_idx),
720 MDSS_MDP_PIPE_RECT0);
721 if (!pipe) {
722 pr_err("invalid blk index=%d\n", blk_idx);
723 ret = -EINVAL;
724 break;
725 }
726 if (mdss_mdp_pipe_is_yuv(pipe)) {
727 base = pipe->base + MDSS_MDP_REG_VIG_CSC_10_BASE;
728 } else {
729 pr_err("non ViG pipe %d for CSC is not allowed\n",
730 blk_idx);
731 ret = -EINVAL;
732 }
733 break;
734 default:
735 ret = -EINVAL;
736 break;
737 }
738 if (ret != 0) {
739 pr_err("unsupported block id %d for csc\n", blk_idx);
740 return ret;
741 }
742
743 addr = base + CSC_MV_OFF;
744 for (i = 0; i < 9; i++) {
745 if (i & 0x1) {
746 val |= data->csc_mv[i] << 16;
747 writel_relaxed(val, addr);
748 addr += sizeof(u32);
749 } else {
750 val = data->csc_mv[i];
751 }
752 }
753 writel_relaxed(val, addr); /* COEFF_33 */
754
755 addr = base + CSC_BV_OFF;
756 for (i = 0; i < 3; i++) {
757 writel_relaxed(data->csc_pre_bv[i], addr);
758 writel_relaxed(data->csc_post_bv[i], addr + CSC_POST_OFF);
759 addr += sizeof(u32);
760 }
761
762 addr = base + CSC_LV_OFF;
763 for (i = 0; i < 6; i += 2) {
764 val = (data->csc_pre_lv[i] << lv_shift) | data->csc_pre_lv[i+1];
765 writel_relaxed(val, addr);
766
767 val = (data->csc_post_lv[i] << lv_shift) |
768 data->csc_post_lv[i+1];
769 writel_relaxed(val, addr + CSC_POST_OFF);
770 addr += sizeof(u32);
771 }
772
773 return ret;
774}
775
776int mdss_mdp_csc_setup(u32 block, u32 blk_idx, u32 csc_type)
777{
778 struct mdp_csc_cfg *data;
779
780 if (csc_type >= MDSS_MDP_MAX_CSC) {
781 pr_err("invalid csc matrix index %d\n", csc_type);
782 return -ERANGE;
783 }
784
785 pr_debug("csc type=%d blk=%d idx=%d\n", csc_type,
786 block, blk_idx);
787
788 if (block == MDSS_MDP_BLOCK_CDM || block == MDSS_MDP_BLOCK_SSPP_10)
789 data = &mdp_csc_10bit_convert[csc_type];
790 else
791 data = &mdp_csc_8bit_convert[csc_type];
792 return mdss_mdp_csc_setup_data(block, blk_idx, data);
793}
794
795static void pp_gamut_config(struct mdp_gamut_cfg_data *gamut_cfg,
796 char __iomem *base, struct pp_sts_type *pp_sts)
797{
798 char __iomem *addr;
799 int i, j;
800
801 if (gamut_cfg->flags & MDP_PP_OPS_WRITE) {
802 addr = base + MDSS_MDP_REG_DSPP_GAMUT_BASE;
803 for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
804 for (j = 0; j < gamut_cfg->tbl_size[i]; j++)
805 writel_relaxed((u32)gamut_cfg->r_tbl[i][j]
806 & 0x1FFF, addr);
807 addr += 4;
808 }
809 for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
810 for (j = 0; j < gamut_cfg->tbl_size[i]; j++)
811 writel_relaxed((u32)gamut_cfg->g_tbl[i][j]
812 & 0x1FFF, addr);
813 addr += 4;
814 }
815 for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
816 for (j = 0; j < gamut_cfg->tbl_size[i]; j++)
817 writel_relaxed((u32)gamut_cfg->b_tbl[i][j]
818 & 0x1FFF, addr);
819 addr += 4;
820 }
821 if (gamut_cfg->gamut_first)
822 pp_sts->gamut_sts |= PP_STS_GAMUT_FIRST;
823 }
824
825 if (gamut_cfg->flags & MDP_PP_OPS_DISABLE)
826 pp_sts->gamut_sts &= ~PP_STS_ENABLE;
827 else if (gamut_cfg->flags & MDP_PP_OPS_ENABLE)
828 pp_sts->gamut_sts |= PP_STS_ENABLE;
829 pp_sts_set_split_bits(&pp_sts->gamut_sts, gamut_cfg->flags);
830}
831
832static void pp_pa_config(unsigned long flags, char __iomem *addr,
833 struct pp_sts_type *pp_sts,
834 struct mdp_pa_cfg *pa_config)
835{
836 if (flags & PP_FLAGS_DIRTY_PA) {
837 if (pa_config->flags & MDP_PP_OPS_WRITE) {
838 writel_relaxed(pa_config->hue_adj, addr);
839 addr += 4;
840 writel_relaxed(pa_config->sat_adj, addr);
841 addr += 4;
842 writel_relaxed(pa_config->val_adj, addr);
843 addr += 4;
844 writel_relaxed(pa_config->cont_adj, addr);
845 }
846 if (pa_config->flags & MDP_PP_OPS_DISABLE)
847 pp_sts->pa_sts &= ~PP_STS_ENABLE;
848 else if (pa_config->flags & MDP_PP_OPS_ENABLE)
849 pp_sts->pa_sts |= PP_STS_ENABLE;
850 }
851}
852
853static void pp_pa_v2_config(unsigned long flags, char __iomem *addr,
854 struct pp_sts_type *pp_sts,
855 struct mdp_pa_v2_data *pa_v2_config,
856 int mdp_location)
857{
858 if ((flags & PP_FLAGS_DIRTY_PA) &&
859 (pa_v2_config->flags & MDP_PP_OPS_WRITE)) {
860 pp_update_pa_v2_global_adj_regs(addr,
861 pa_v2_config);
862 /* Update PA DSPP Regs */
863 if (mdp_location == PP_DSPP) {
864 addr += 0x10;
865 pp_update_pa_v2_six_zone_regs(addr, pa_v2_config);
866 addr += 0xC;
867 pp_update_pa_v2_mem_col(addr, pa_v2_config);
868 } else if (mdp_location == PP_SSPP) { /* Update PA SSPP Regs */
869 addr -= MDSS_MDP_REG_VIG_PA_BASE;
870 addr += MDSS_MDP_REG_VIG_MEM_COL_BASE;
871 pp_update_pa_v2_mem_col(addr, pa_v2_config);
872 }
873 pp_update_pa_v2_sts(pp_sts, pa_v2_config);
874 }
875}
876
877static void pp_update_pa_v2_global_adj_regs(char __iomem *addr,
878 struct mdp_pa_v2_data *pa_v2_config)
879{
880 if (pa_v2_config->flags & MDP_PP_PA_HUE_ENABLE)
881 writel_relaxed(pa_v2_config->global_hue_adj, addr);
882 addr += 4;
883 if (pa_v2_config->flags & MDP_PP_PA_SAT_ENABLE)
884 /* Sat Global Adjust reg includes Sat Threshold */
885 writel_relaxed(pa_v2_config->global_sat_adj, addr);
886 addr += 4;
887 if (pa_v2_config->flags & MDP_PP_PA_VAL_ENABLE)
888 writel_relaxed(pa_v2_config->global_val_adj, addr);
889 addr += 4;
890 if (pa_v2_config->flags & MDP_PP_PA_CONT_ENABLE)
891 writel_relaxed(pa_v2_config->global_cont_adj, addr);
892}
893
894static void pp_update_pa_v2_mem_col(char __iomem *addr,
895 struct mdp_pa_v2_data *pa_v2_config)
896{
897 /* Update skin zone memory color registers */
898 if (pa_v2_config->flags & MDP_PP_PA_SKIN_ENABLE)
899 pp_update_pa_v2_mem_col_regs(addr, &pa_v2_config->skin_cfg);
900 addr += 0x14;
901 /* Update sky zone memory color registers */
902 if (pa_v2_config->flags & MDP_PP_PA_SKY_ENABLE)
903 pp_update_pa_v2_mem_col_regs(addr, &pa_v2_config->sky_cfg);
904 addr += 0x14;
905 /* Update foliage zone memory color registers */
906 if (pa_v2_config->flags & MDP_PP_PA_FOL_ENABLE)
907 pp_update_pa_v2_mem_col_regs(addr, &pa_v2_config->fol_cfg);
908}
909
910static void pp_update_pa_v2_mem_col_regs(char __iomem *addr,
911 struct mdp_pa_mem_col_cfg *cfg)
912{
913 writel_relaxed(cfg->color_adjust_p0, addr);
914 addr += 4;
915 writel_relaxed(cfg->color_adjust_p1, addr);
916 addr += 4;
917 writel_relaxed(cfg->hue_region, addr);
918 addr += 4;
919 writel_relaxed(cfg->sat_region, addr);
920 addr += 4;
921 writel_relaxed(cfg->val_region, addr);
922}
923
924static void pp_update_pa_v2_six_zone_regs(char __iomem *addr,
925 struct mdp_pa_v2_data *pa_v2_config)
926{
927 int i;
928 u32 data;
929 /* Update six zone memory color registers */
930 if (pa_v2_config->flags & MDP_PP_PA_SIX_ZONE_ENABLE) {
931 addr += 4;
932 writel_relaxed(pa_v2_config->six_zone_curve_p1[0], addr);
933 addr -= 4;
934 /* Index Update to trigger auto-incrementing LUT accesses */
935 data = (1 << 26);
936 writel_relaxed((pa_v2_config->six_zone_curve_p0[0] & 0xFFF) |
937 data, addr);
938
939 /* Remove Index Update */
940 for (i = 1; i < MDP_SIX_ZONE_LUT_SIZE; i++) {
941 addr += 4;
942 writel_relaxed(pa_v2_config->six_zone_curve_p1[i],
943 addr);
944 addr -= 4;
945 writel_relaxed(pa_v2_config->six_zone_curve_p0[i] &
946 0xFFF, addr);
947 }
948 addr += 8;
949 writel_relaxed(pa_v2_config->six_zone_thresh, addr);
950 }
951}
952
953static void pp_update_pa_v2_sts(struct pp_sts_type *pp_sts,
954 struct mdp_pa_v2_data *pa_v2_config)
955{
956 pp_sts->pa_sts = 0;
957 /* PA STS update */
958 if (pa_v2_config->flags & MDP_PP_OPS_ENABLE)
959 pp_sts->pa_sts |= PP_STS_ENABLE;
960 else
961 pp_sts->pa_sts &= ~PP_STS_ENABLE;
962
963 /* Global HSV STS update */
964 if (pa_v2_config->flags & MDP_PP_PA_HUE_MASK)
965 pp_sts->pa_sts |= PP_STS_PA_HUE_MASK;
966 if (pa_v2_config->flags & MDP_PP_PA_SAT_MASK)
967 pp_sts->pa_sts |= PP_STS_PA_SAT_MASK;
968 if (pa_v2_config->flags & MDP_PP_PA_VAL_MASK)
969 pp_sts->pa_sts |= PP_STS_PA_VAL_MASK;
970 if (pa_v2_config->flags & MDP_PP_PA_CONT_MASK)
971 pp_sts->pa_sts |= PP_STS_PA_CONT_MASK;
972 if (pa_v2_config->flags & MDP_PP_PA_MEM_PROTECT_EN)
973 pp_sts->pa_sts |= PP_STS_PA_MEM_PROTECT_EN;
974 if (pa_v2_config->flags & MDP_PP_PA_SAT_ZERO_EXP_EN)
975 pp_sts->pa_sts |= PP_STS_PA_SAT_ZERO_EXP_EN;
976
977 /* Memory Color STS update */
978 if (pa_v2_config->flags & MDP_PP_PA_MEM_COL_SKIN_MASK)
979 pp_sts->pa_sts |= PP_STS_PA_MEM_COL_SKIN_MASK;
980 if (pa_v2_config->flags & MDP_PP_PA_MEM_COL_SKY_MASK)
981 pp_sts->pa_sts |= PP_STS_PA_MEM_COL_SKY_MASK;
982 if (pa_v2_config->flags & MDP_PP_PA_MEM_COL_FOL_MASK)
983 pp_sts->pa_sts |= PP_STS_PA_MEM_COL_FOL_MASK;
984
985 /* Six Zone STS update */
986 if (pa_v2_config->flags & MDP_PP_PA_SIX_ZONE_HUE_MASK)
987 pp_sts->pa_sts |= PP_STS_PA_SIX_ZONE_HUE_MASK;
988 if (pa_v2_config->flags & MDP_PP_PA_SIX_ZONE_SAT_MASK)
989 pp_sts->pa_sts |= PP_STS_PA_SIX_ZONE_SAT_MASK;
990 if (pa_v2_config->flags & MDP_PP_PA_SIX_ZONE_VAL_MASK)
991 pp_sts->pa_sts |= PP_STS_PA_SIX_ZONE_VAL_MASK;
992
993 pp_sts_set_split_bits(&pp_sts->pa_sts, pa_v2_config->flags);
994}
995
996static void pp_pcc_config(unsigned long flags, char __iomem *addr,
997 struct pp_sts_type *pp_sts,
998 struct mdp_pcc_cfg_data *pcc_config)
999{
1000 if (flags & PP_FLAGS_DIRTY_PCC) {
1001 if (pcc_config->ops & MDP_PP_OPS_WRITE)
1002 pp_update_pcc_regs(addr, pcc_config);
1003
1004 if (pcc_config->ops & MDP_PP_OPS_DISABLE)
1005 pp_sts->pcc_sts &= ~PP_STS_ENABLE;
1006 else if (pcc_config->ops & MDP_PP_OPS_ENABLE)
1007 pp_sts->pcc_sts |= PP_STS_ENABLE;
1008 pp_sts_set_split_bits(&pp_sts->pcc_sts, pcc_config->ops);
1009 }
1010}
1011
1012static void pp_igc_config(unsigned long flags, char __iomem *addr,
1013 struct pp_sts_type *pp_sts,
1014 struct mdp_igc_lut_data *igc_config,
1015 u32 pipe_num, u32 pipe_cnt)
1016{
1017 u32 tbl_idx;
1018
1019 if (igc_config->ops & MDP_PP_OPS_WRITE)
1020 pp_update_igc_lut(igc_config, addr, pipe_num,
1021 pipe_cnt);
1022
1023 if (igc_config->ops & MDP_PP_IGC_FLAG_ROM0) {
1024 pp_sts->igc_sts |= PP_STS_ENABLE;
1025 tbl_idx = 1;
1026 } else if (igc_config->ops & MDP_PP_IGC_FLAG_ROM1) {
1027 pp_sts->igc_sts |= PP_STS_ENABLE;
1028 tbl_idx = 2;
1029 } else {
1030 tbl_idx = 0;
1031 }
1032 pp_sts->igc_tbl_idx = tbl_idx;
1033 if (igc_config->ops & MDP_PP_OPS_DISABLE)
1034 pp_sts->igc_sts &= ~PP_STS_ENABLE;
1035 else if (igc_config->ops & MDP_PP_OPS_ENABLE)
1036 pp_sts->igc_sts |= PP_STS_ENABLE;
1037 pp_sts_set_split_bits(&pp_sts->igc_sts, igc_config->ops);
1038}
1039
1040static void pp_enhist_config(unsigned long flags, char __iomem *addr,
1041 struct pp_sts_type *pp_sts,
1042 struct mdp_hist_lut_data *enhist_cfg)
1043{
1044 if (flags & PP_FLAGS_DIRTY_ENHIST) {
1045 if (enhist_cfg->ops & MDP_PP_OPS_WRITE)
1046 pp_update_hist_lut(addr, enhist_cfg);
1047
1048 if (enhist_cfg->ops & MDP_PP_OPS_DISABLE)
1049 pp_sts->enhist_sts &= ~PP_STS_ENABLE;
1050 else if (enhist_cfg->ops & MDP_PP_OPS_ENABLE)
1051 pp_sts->enhist_sts |= PP_STS_ENABLE;
1052 }
1053}
1054
1055/*the below function doesn't do error checking on the input params*/
1056static void pp_sharp_config(char __iomem *addr,
1057 struct pp_sts_type *pp_sts,
1058 struct mdp_sharp_cfg *sharp_config)
1059{
1060 if (sharp_config->flags & MDP_PP_OPS_WRITE) {
1061 writel_relaxed(sharp_config->strength, addr);
1062 addr += 4;
1063 writel_relaxed(sharp_config->edge_thr, addr);
1064 addr += 4;
1065 writel_relaxed(sharp_config->smooth_thr, addr);
1066 addr += 4;
1067 writel_relaxed(sharp_config->noise_thr, addr);
1068 }
1069 if (sharp_config->flags & MDP_PP_OPS_DISABLE)
1070 pp_sts->sharp_sts &= ~PP_STS_ENABLE;
1071 else if (sharp_config->flags & MDP_PP_OPS_ENABLE)
1072 pp_sts->sharp_sts |= PP_STS_ENABLE;
1073
1074}
1075
1076static void pp_vig_pipe_opmode_config(struct pp_sts_type *pp_sts, u32 *opmode)
1077{
1078 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
1079
1080 if ((mdata->mdp_rev < MDSS_MDP_HW_REV_103) &&
1081 (pp_sts->pa_sts & PP_STS_ENABLE))
1082 *opmode |= MDSS_MDP_VIG_OP_PA_EN;
1083 else if (mdata->mdp_rev >= MDSS_MDP_HW_REV_103)
1084 pp_update_pa_v2_vig_opmode(pp_sts,
1085 opmode);
1086
1087 if (pp_sts->enhist_sts & PP_STS_ENABLE)
1088 /* Enable HistLUT and PA */
1089 *opmode |= MDSS_MDP_VIG_OP_HIST_LUTV_EN |
1090 MDSS_MDP_VIG_OP_PA_EN;
1091}
1092
1093static int pp_vig_pipe_setup(struct mdss_mdp_pipe *pipe, u32 *op)
1094{
1095 unsigned long flags = 0;
1096 char __iomem *offset;
1097 struct mdss_data_type *mdata;
1098 u32 dcm_state = DCM_UNINIT, current_opmode, csc_reset;
1099 int ret = 0;
1100 u32 csc_op;
1101
1102 pr_debug("pnum=%x\n", pipe->num);
1103
1104 mdss_mdp_pp_get_dcm_state(pipe, &dcm_state);
1105
1106 mdata = mdss_mdp_get_mdata();
1107 if (IS_MDSS_MAJOR_MINOR_SAME(mdata->mdp_rev, MDSS_MDP_HW_REV_301) ||
1108 IS_MDSS_MAJOR_MINOR_SAME(mdata->mdp_rev, MDSS_MDP_HW_REV_300)) {
1109 if (pipe->src_fmt->is_yuv) {
1110 /* TODO: check csc cfg from PP block */
1111 mdss_mdp_csc_setup(MDSS_MDP_BLOCK_SSPP_10, pipe->num,
1112 pp_vig_csc_pipe_val(pipe));
1113 csc_op = ((0 << 2) | /* DST_DATA=RGB */
1114 (1 << 1) | /* SRC_DATA=YCBCR*/
1115 (1 << 0)); /* CSC_10_EN */
1116 } else {
1117 csc_op = 0; /* CSC_10_DISABLE */
1118 }
1119 writel_relaxed(csc_op, pipe->base +
1120 MDSS_MDP_REG_VIG_CSC_10_OP_MODE);
1121 } else if ((pipe->flags & MDP_OVERLAY_PP_CFG_EN) &&
1122 (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_CSC_CFG)) {
1123 *op |= !!(pipe->pp_cfg.csc_cfg.flags &
1124 MDP_CSC_FLAG_ENABLE) << 17;
1125 *op |= !!(pipe->pp_cfg.csc_cfg.flags &
1126 MDP_CSC_FLAG_YUV_IN) << 18;
1127 *op |= !!(pipe->pp_cfg.csc_cfg.flags &
1128 MDP_CSC_FLAG_YUV_OUT) << 19;
1129 /*
1130 * TODO: Allow pipe to be programmed whenever new CSC is
1131 * applied (i.e. dirty bit)
1132 */
1133 mdss_mdp_csc_setup_data(MDSS_MDP_BLOCK_SSPP, pipe->num,
1134 &pipe->pp_cfg.csc_cfg);
1135 } else if (pipe->src_fmt->is_yuv) {
1136 *op |= (0 << 19) | /* DST_DATA=RGB */
1137 (1 << 18) | /* SRC_DATA=YCBCR */
1138 (1 << 17); /* CSC_1_EN */
1139 /*
1140 * TODO: Needs to be part of dirty bit logic: if there
1141 * is a previously configured pipe need to re-configure
1142 * CSC matrix
1143 */
1144 mdss_mdp_csc_setup(MDSS_MDP_BLOCK_SSPP, pipe->num,
1145 pp_vig_csc_pipe_val(pipe));
1146 }
1147
1148 /* Update CSC state only if tuning mode is enable */
1149 if (dcm_state == DTM_ENTER) {
1150 /* Reset bit 16 to 19 for CSC_STATE in VIG_OP_MODE */
1151 csc_reset = 0xFFF0FFFF;
1152 current_opmode = readl_relaxed(pipe->base +
1153 MDSS_MDP_REG_VIG_OP_MODE);
1154 *op |= (current_opmode & csc_reset);
1155 return 0;
1156 }
1157
1158 /* Histogram collection enabled checked inside pp_hist_setup */
1159 pp_hist_setup(op, MDSS_PP_SSPP_CFG | pipe->num, pipe->mixer_left,
1160 &pipe->pp_res.pp_sts);
1161
1162 if (!(pipe->flags & MDP_OVERLAY_PP_CFG_EN)) {
1163 pr_debug("Overlay PP CFG enable not set\n");
1164 return 0;
1165 }
1166
1167 if ((pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_PA_CFG) &&
1168 (mdata->mdp_rev < MDSS_MDP_HW_REV_103)) {
1169 flags = PP_FLAGS_DIRTY_PA;
1170 pp_pa_config(flags,
1171 pipe->base + MDSS_MDP_REG_VIG_PA_BASE,
1172 &pipe->pp_res.pp_sts,
1173 &pipe->pp_cfg.pa_cfg);
1174 }
1175 if ((pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_PA_V2_CFG) &&
1176 (mdata->mdp_rev >= MDSS_MDP_HW_REV_103)) {
1177 flags = PP_FLAGS_DIRTY_PA;
1178 if (!pp_ops[PA].pp_set_config)
1179 pp_pa_v2_config(flags,
1180 pipe->base + MDSS_MDP_REG_VIG_PA_BASE,
1181 &pipe->pp_res.pp_sts,
1182 &pipe->pp_cfg.pa_v2_cfg,
1183 PP_SSPP);
1184 else
1185 pp_ops[PA].pp_set_config(pipe->base,
1186 &pipe->pp_res.pp_sts,
1187 &pipe->pp_cfg.pa_v2_cfg_data,
1188 SSPP_VIG);
1189 }
1190
1191 if (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_HIST_LUT_CFG) {
1192 flags = PP_FLAGS_DIRTY_ENHIST;
1193 if (!pp_ops[HIST_LUT].pp_set_config) {
1194 pp_enhist_config(flags,
1195 pipe->base + MDSS_MDP_REG_VIG_HIST_LUT_BASE,
1196 &pipe->pp_res.pp_sts,
1197 &pipe->pp_cfg.hist_lut_cfg);
1198 if ((pipe->pp_res.pp_sts.enhist_sts & PP_STS_ENABLE) &&
1199 !(pipe->pp_res.pp_sts.pa_sts & PP_STS_ENABLE)) {
1200 /* Program default value */
1201 offset = pipe->base + MDSS_MDP_REG_VIG_PA_BASE;
1202 writel_relaxed(0, offset);
1203 writel_relaxed(0, offset + 4);
1204 writel_relaxed(0, offset + 8);
1205 writel_relaxed(0, offset + 12);
1206 }
1207 } else {
1208 pp_ops[HIST_LUT].pp_set_config(pipe->base,
1209 &pipe->pp_res.pp_sts,
1210 &pipe->pp_cfg.hist_lut_cfg,
1211 SSPP_VIG);
1212 }
1213 }
1214
1215 if (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_PCC_CFG) {
1216 ret = pp_update_pcc_pipe_setup(pipe, SSPP_VIG);
1217 if (ret)
1218 pr_err("error in enabling the pcc ret %d pipe type %d pipe num %d\n",
1219 ret, pipe->type, pipe->num);
1220 }
1221 if (pp_driver_ops.pp_opmode_config)
1222 pp_driver_ops.pp_opmode_config(SSPP_VIG, &pipe->pp_res.pp_sts,
1223 op, 0);
1224 else
1225 pp_vig_pipe_opmode_config(&pipe->pp_res.pp_sts, op);
1226
1227 return 0;
1228}
1229
1230static void pp_update_pa_v2_vig_opmode(struct pp_sts_type *pp_sts,
1231 u32 *opmode)
1232{
1233 if (pp_sts->pa_sts & PP_STS_ENABLE)
1234 *opmode |= MDSS_MDP_VIG_OP_PA_EN;
1235 if (pp_sts->pa_sts & PP_STS_PA_HUE_MASK)
1236 *opmode |= MDSS_MDP_VIG_OP_PA_HUE_MASK;
1237 if (pp_sts->pa_sts & PP_STS_PA_SAT_MASK)
1238 *opmode |= MDSS_MDP_VIG_OP_PA_SAT_MASK;
1239 if (pp_sts->pa_sts & PP_STS_PA_VAL_MASK)
1240 *opmode |= MDSS_MDP_VIG_OP_PA_VAL_MASK;
1241 if (pp_sts->pa_sts & PP_STS_PA_CONT_MASK)
1242 *opmode |= MDSS_MDP_VIG_OP_PA_CONT_MASK;
1243 if (pp_sts->pa_sts & PP_STS_PA_MEM_PROTECT_EN)
1244 *opmode |= MDSS_MDP_VIG_OP_PA_MEM_PROTECT_EN;
1245 if (pp_sts->pa_sts & PP_STS_PA_SAT_ZERO_EXP_EN)
1246 *opmode |= MDSS_MDP_VIG_OP_PA_SAT_ZERO_EXP_EN;
1247 if (pp_sts->pa_sts & PP_STS_PA_MEM_COL_SKIN_MASK)
1248 *opmode |= MDSS_MDP_VIG_OP_PA_MEM_COL_SKIN_MASK;
1249 if (pp_sts->pa_sts & PP_STS_PA_MEM_COL_SKY_MASK)
1250 *opmode |= MDSS_MDP_VIG_OP_PA_MEM_COL_SKY_MASK;
1251 if (pp_sts->pa_sts & PP_STS_PA_MEM_COL_FOL_MASK)
1252 *opmode |= MDSS_MDP_VIG_OP_PA_MEM_COL_FOL_MASK;
1253}
1254
1255static int pp_rgb_pipe_setup(struct mdss_mdp_pipe *pipe, u32 *op)
1256{
1257 int ret = 0;
1258
1259 if (!pipe) {
1260 pr_err("invalid param pipe %pK\n", pipe);
1261 return -EINVAL;
1262 }
1263 if (pipe->flags & MDP_OVERLAY_PP_CFG_EN &&
1264 pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_PCC_CFG) {
1265 ret = pp_update_pcc_pipe_setup(pipe, SSPP_RGB);
1266 if (ret)
1267 pr_err("error in enabling the pcc ret %d pipe type %d pipe num %d\n",
1268 ret, pipe->type, pipe->num);
1269 }
1270 return 0;
1271}
1272
1273static int pp_dma_pipe_setup(struct mdss_mdp_pipe *pipe, u32 *op)
1274{
1275 int ret = 0;
1276
1277 if (!pipe) {
1278 pr_err("invalid param pipe %pK\n", pipe);
1279 return -EINVAL;
1280 }
1281 if (pipe->flags & MDP_OVERLAY_PP_CFG_EN &&
1282 pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_PCC_CFG) {
1283 ret = pp_update_pcc_pipe_setup(pipe, SSPP_DMA);
1284 if (ret)
1285 pr_err("error in enabling the pcc ret %d pipe type %d pipe num %d\n",
1286 ret, pipe->type, pipe->num);
1287 }
1288 return 0;
1289}
1290
1291static int mdss_mdp_qseed2_setup(struct mdss_mdp_pipe *pipe)
1292{
1293 u32 scale_config = 0;
1294 int init_phasex = 0, init_phasey = 0;
1295 int phasex_step = 0, phasey_step = 0;
1296 u32 chroma_sample;
1297 u32 filter_mode;
1298 struct mdss_data_type *mdata;
1299 u32 src_w, src_h;
1300 u32 dcm_state = DCM_UNINIT;
1301 u32 chroma_shift_x = 0, chroma_shift_y = 0;
1302
1303 pr_debug("pipe=%d, change pxl ext=%d\n", pipe->num,
1304 pipe->scaler.enable);
1305 mdata = mdss_mdp_get_mdata();
1306
1307 if (pipe->type == MDSS_MDP_PIPE_TYPE_DMA ||
1308 pipe->type == MDSS_MDP_PIPE_TYPE_CURSOR) {
1309 if (pipe->dst.h != pipe->src.h || pipe->dst.w != pipe->src.w) {
1310 pr_err("no scaling supported on dma/cursor pipe, num:%d\n",
1311 pipe->num);
1312 return -EINVAL;
1313 } else {
1314 return 0;
1315 }
1316 }
1317
1318 mdss_mdp_pp_get_dcm_state(pipe, &dcm_state);
1319
1320 if (mdata->mdp_rev >= MDSS_MDP_HW_REV_102 && pipe->src_fmt->is_yuv)
1321 filter_mode = MDSS_MDP_SCALE_FILTER_CA;
1322 else
1323 filter_mode = MDSS_MDP_SCALE_FILTER_BIL;
1324
1325 src_w = DECIMATED_DIMENSION(pipe->src.w, pipe->horz_deci);
1326 src_h = DECIMATED_DIMENSION(pipe->src.h, pipe->vert_deci);
1327
1328 chroma_sample = pipe->src_fmt->chroma_sample;
1329 if (pipe->flags & MDP_SOURCE_ROTATED_90) {
1330 if (chroma_sample == MDSS_MDP_CHROMA_H1V2)
1331 chroma_sample = MDSS_MDP_CHROMA_H2V1;
1332 else if (chroma_sample == MDSS_MDP_CHROMA_H2V1)
1333 chroma_sample = MDSS_MDP_CHROMA_H1V2;
1334 }
1335
1336 if (!(pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_SHARP_CFG)) {
1337 pipe->pp_cfg.sharp_cfg.flags = MDP_PP_OPS_ENABLE |
1338 MDP_PP_OPS_WRITE;
1339 pipe->pp_cfg.sharp_cfg.strength = SHARP_STRENGTH_DEFAULT;
1340 pipe->pp_cfg.sharp_cfg.edge_thr = SHARP_EDGE_THR_DEFAULT;
1341 pipe->pp_cfg.sharp_cfg.smooth_thr = SHARP_SMOOTH_THR_DEFAULT;
1342 pipe->pp_cfg.sharp_cfg.noise_thr = SHARP_NOISE_THR_DEFAULT;
1343 }
1344
1345 if (dcm_state != DTM_ENTER &&
1346 ((pipe->src_fmt->is_yuv) &&
1347 !((pipe->dst.w < src_w) || (pipe->dst.h < src_h)))) {
1348 pp_sharp_config(pipe->base +
1349 MDSS_MDP_REG_VIG_QSEED2_SHARP,
1350 &pipe->pp_res.pp_sts,
1351 &pipe->pp_cfg.sharp_cfg);
1352 }
1353
1354 if ((src_h != pipe->dst.h) ||
1355 (pipe->src_fmt->is_yuv &&
1356 (pipe->pp_res.pp_sts.sharp_sts & PP_STS_ENABLE)) ||
1357 (chroma_sample == MDSS_MDP_CHROMA_420) ||
1358 (chroma_sample == MDSS_MDP_CHROMA_H1V2) ||
1359 (pipe->scaler.enable && (src_h != pipe->dst.h))) {
1360 pr_debug("scale y - src_h=%d dst_h=%d\n", src_h, pipe->dst.h);
1361
1362 if ((src_h / MAX_DOWNSCALE_RATIO) > pipe->dst.h) {
1363 pr_err("too much downscaling height=%d->%d\n",
1364 src_h, pipe->dst.h);
1365 return -EINVAL;
1366 }
1367
1368 scale_config |= MDSS_MDP_SCALEY_EN;
1369 phasey_step = pipe->scaler.phase_step_y[0];
1370 init_phasey = pipe->scaler.init_phase_y[0];
1371
1372 if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
1373 if (!pipe->vert_deci &&
1374 ((chroma_sample == MDSS_MDP_CHROMA_420) ||
1375 (chroma_sample == MDSS_MDP_CHROMA_H1V2)))
1376 chroma_shift_y = 1; /* 2x upsample chroma */
1377
1378 if (src_h <= pipe->dst.h)
1379 scale_config |= /* G/Y, A */
1380 (filter_mode << 10) |
1381 (MDSS_MDP_SCALE_FILTER_BIL << 18);
1382 else
1383 scale_config |= /* G/Y, A */
1384 (MDSS_MDP_SCALE_FILTER_PCMN << 10) |
1385 (MDSS_MDP_SCALE_FILTER_PCMN << 18);
1386
1387 if ((src_h >> chroma_shift_y) <= pipe->dst.h)
1388 scale_config |= /* CrCb */
1389 (MDSS_MDP_SCALE_FILTER_BIL << 14);
1390 else
1391 scale_config |= /* CrCb */
1392 (MDSS_MDP_SCALE_FILTER_PCMN << 14);
1393
1394 writel_relaxed(init_phasey, pipe->base +
1395 MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEY);
1396 writel_relaxed(phasey_step >> chroma_shift_y,
1397 pipe->base +
1398 MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPY);
1399 } else {
1400 if (src_h <= pipe->dst.h)
1401 scale_config |= /* RGB, A */
1402 (MDSS_MDP_SCALE_FILTER_BIL << 10) |
1403 (MDSS_MDP_SCALE_FILTER_BIL << 18);
1404 else
1405 scale_config |= /* RGB, A */
1406 (MDSS_MDP_SCALE_FILTER_PCMN << 10) |
1407 (MDSS_MDP_SCALE_FILTER_PCMN << 18);
1408 }
1409 }
1410
1411 if ((src_w != pipe->dst.w) ||
1412 (pipe->src_fmt->is_yuv &&
1413 (pipe->pp_res.pp_sts.sharp_sts & PP_STS_ENABLE)) ||
1414 (chroma_sample == MDSS_MDP_CHROMA_420) ||
1415 (chroma_sample == MDSS_MDP_CHROMA_H2V1) ||
1416 (pipe->scaler.enable && (src_w != pipe->dst.w))) {
1417 pr_debug("scale x - src_w=%d dst_w=%d\n", src_w, pipe->dst.w);
1418
1419 if ((src_w / MAX_DOWNSCALE_RATIO) > pipe->dst.w) {
1420 pr_err("too much downscaling width=%d->%d\n",
1421 src_w, pipe->dst.w);
1422 return -EINVAL;
1423 }
1424
1425 scale_config |= MDSS_MDP_SCALEX_EN;
1426 init_phasex = pipe->scaler.init_phase_x[0];
1427 phasex_step = pipe->scaler.phase_step_x[0];
1428
1429 if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
1430 if (!pipe->horz_deci &&
1431 ((chroma_sample == MDSS_MDP_CHROMA_420) ||
1432 (chroma_sample == MDSS_MDP_CHROMA_H2V1)))
1433 chroma_shift_x = 1; /* 2x upsample chroma */
1434
1435 if (src_w <= pipe->dst.w)
1436 scale_config |= /* G/Y, A */
1437 (filter_mode << 8) |
1438 (MDSS_MDP_SCALE_FILTER_BIL << 16);
1439 else
1440 scale_config |= /* G/Y, A */
1441 (MDSS_MDP_SCALE_FILTER_PCMN << 8) |
1442 (MDSS_MDP_SCALE_FILTER_PCMN << 16);
1443
1444 if ((src_w >> chroma_shift_x) <= pipe->dst.w)
1445 scale_config |= /* CrCb */
1446 (MDSS_MDP_SCALE_FILTER_BIL << 12);
1447 else
1448 scale_config |= /* CrCb */
1449 (MDSS_MDP_SCALE_FILTER_PCMN << 12);
1450
1451 writel_relaxed(init_phasex, pipe->base +
1452 MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEX);
1453 writel_relaxed(phasex_step >> chroma_shift_x,
1454 pipe->base +
1455 MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPX);
1456 } else {
1457 if (src_w <= pipe->dst.w)
1458 scale_config |= /* RGB, A */
1459 (MDSS_MDP_SCALE_FILTER_BIL << 8) |
1460 (MDSS_MDP_SCALE_FILTER_BIL << 16);
1461 else
1462 scale_config |= /* RGB, A */
1463 (MDSS_MDP_SCALE_FILTER_PCMN << 8) |
1464 (MDSS_MDP_SCALE_FILTER_PCMN << 16);
1465 }
1466 }
1467
1468 if (pipe->scaler.enable) {
1469 if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
1470 /*program x,y initial phase and phase step*/
1471 writel_relaxed(pipe->scaler.init_phase_x[0],
1472 pipe->base +
1473 MDSS_MDP_REG_VIG_QSEED2_C03_INIT_PHASEX);
1474 writel_relaxed(pipe->scaler.phase_step_x[0],
1475 pipe->base +
1476 MDSS_MDP_REG_VIG_QSEED2_C03_PHASESTEPX);
1477 writel_relaxed(pipe->scaler.init_phase_x[1],
1478 pipe->base +
1479 MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEX);
1480 writel_relaxed(pipe->scaler.phase_step_x[1],
1481 pipe->base +
1482 MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPX);
1483
1484 writel_relaxed(pipe->scaler.init_phase_y[0],
1485 pipe->base +
1486 MDSS_MDP_REG_VIG_QSEED2_C03_INIT_PHASEY);
1487 writel_relaxed(pipe->scaler.phase_step_y[0],
1488 pipe->base +
1489 MDSS_MDP_REG_VIG_QSEED2_C03_PHASESTEPY);
1490 writel_relaxed(pipe->scaler.init_phase_y[1],
1491 pipe->base +
1492 MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEY);
1493 writel_relaxed(pipe->scaler.phase_step_y[1],
1494 pipe->base +
1495 MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPY);
1496 } else {
1497
1498 writel_relaxed(pipe->scaler.phase_step_x[0],
1499 pipe->base +
1500 MDSS_MDP_REG_SCALE_PHASE_STEP_X);
1501 writel_relaxed(pipe->scaler.phase_step_y[0],
1502 pipe->base +
1503 MDSS_MDP_REG_SCALE_PHASE_STEP_Y);
1504 writel_relaxed(pipe->scaler.init_phase_x[0],
1505 pipe->base +
1506 MDSS_MDP_REG_SCALE_INIT_PHASE_X);
1507 writel_relaxed(pipe->scaler.init_phase_y[0],
1508 pipe->base +
1509 MDSS_MDP_REG_SCALE_INIT_PHASE_Y);
1510 }
1511 } else {
1512 if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
1513 /*program x,y initial phase and phase step*/
1514 writel_relaxed(0,
1515 pipe->base +
1516 MDSS_MDP_REG_VIG_QSEED2_C03_INIT_PHASEX);
1517 writel_relaxed(init_phasex,
1518 pipe->base +
1519 MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEX);
1520 writel_relaxed(phasex_step,
1521 pipe->base +
1522 MDSS_MDP_REG_VIG_QSEED2_C03_PHASESTEPX);
1523 writel_relaxed(phasex_step >> chroma_shift_x,
1524 pipe->base +
1525 MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPX);
1526
1527 writel_relaxed(0,
1528 pipe->base +
1529 MDSS_MDP_REG_VIG_QSEED2_C03_INIT_PHASEY);
1530 writel_relaxed(init_phasey,
1531 pipe->base +
1532 MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEY);
1533 writel_relaxed(phasey_step,
1534 pipe->base +
1535 MDSS_MDP_REG_VIG_QSEED2_C03_PHASESTEPY);
1536 writel_relaxed(phasey_step >> chroma_shift_y,
1537 pipe->base +
1538 MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPY);
1539 } else {
1540
1541 writel_relaxed(phasex_step,
1542 pipe->base +
1543 MDSS_MDP_REG_SCALE_PHASE_STEP_X);
1544 writel_relaxed(phasey_step,
1545 pipe->base +
1546 MDSS_MDP_REG_SCALE_PHASE_STEP_Y);
1547 writel_relaxed(0,
1548 pipe->base +
1549 MDSS_MDP_REG_SCALE_INIT_PHASE_X);
1550 writel_relaxed(0,
1551 pipe->base +
1552 MDSS_MDP_REG_SCALE_INIT_PHASE_Y);
1553 }
1554 }
1555
1556 writel_relaxed(scale_config, pipe->base +
1557 MDSS_MDP_REG_SCALE_CONFIG);
1558
1559 return 0;
1560}
1561
1562int mdss_mdp_scaler_lut_cfg(struct mdp_scale_data_v2 *scaler,
1563 char __iomem *offset)
1564{
1565 int i, j, filter;
1566 struct mdss_data_type *mdata;
1567 char __iomem *lut_addr;
1568 uint32_t *lut_type[QSEED3_FILTERS] = {NULL, NULL, NULL, NULL, NULL};
1569 uint32_t lut_offset, lut_len;
1570 struct mdss_mdp_qseed3_lut_tbl *lut_tbl;
1571 /* for each filter, 4 lut regions offset and length table */
1572 static uint32_t offset_tbl[QSEED3_FILTERS][QSEED3_LUT_REGIONS][2] = {
1573 {{18, 0x000}, {12, 0x120}, {12, 0x1E0}, {8, 0x2A0} },
1574 {{6, 0x320}, {3, 0x3E0}, {3, 0x440}, {3, 0x4A0} },
1575 {{6, 0x380}, {3, 0x410}, {3, 0x470}, {3, 0x4d0} },
1576 {{6, 0x500}, {3, 0x5c0}, {3, 0x620}, {3, 0x680} },
1577 {{6, 0x560}, {3, 0x5f0}, {3, 0x650}, {3, 0x6b0} },
1578 };
1579
1580 mdata = mdss_mdp_get_mdata();
1581 lut_tbl = &mdata->scaler_off->lut_tbl;
1582 if ((!lut_tbl) || (!lut_tbl->valid)) {
1583 pr_err("%s:Invalid QSEED3 LUT TABLE\n", __func__);
1584 return -EINVAL;
1585 }
1586 if ((scaler->lut_flag & SCALER_LUT_DIR_WR) ||
1587 (scaler->lut_flag & SCALER_LUT_Y_CIR_WR) ||
1588 (scaler->lut_flag & SCALER_LUT_UV_CIR_WR) ||
1589 (scaler->lut_flag & SCALER_LUT_Y_SEP_WR) ||
1590 (scaler->lut_flag & SCALER_LUT_UV_SEP_WR)) {
1591
1592 if (scaler->lut_flag & SCALER_LUT_DIR_WR)
1593 lut_type[0] = lut_tbl->dir_lut;
1594 if (scaler->lut_flag & SCALER_LUT_Y_CIR_WR)
1595 lut_type[1] =
1596 lut_tbl->cir_lut + scaler->y_rgb_cir_lut_idx *
1597 CIR_LUT_COEFFS;
1598 if (scaler->lut_flag & SCALER_LUT_UV_CIR_WR)
1599 lut_type[2] = lut_tbl->cir_lut +
1600 scaler->uv_cir_lut_idx * CIR_LUT_COEFFS;
1601 if (scaler->lut_flag & SCALER_LUT_Y_SEP_WR)
1602 lut_type[3] =
1603 lut_tbl->sep_lut + scaler->y_rgb_sep_lut_idx *
1604 SEP_LUT_COEFFS;
1605 if (scaler->lut_flag & SCALER_LUT_UV_SEP_WR)
1606 lut_type[4] =
1607 lut_tbl->sep_lut + scaler->uv_sep_lut_idx *
1608 SEP_LUT_COEFFS;
1609
1610 /* for each filter per plane */
1611 for (filter = 0; filter < QSEED3_FILTERS; filter++) {
1612 if (!lut_type[filter])
1613 continue;
1614 lut_offset = 0;
1615 /* for each lut region */
1616 for (i = 0; i < 4; i++) {
1617 lut_addr = offset +
1618 offset_tbl[filter][i][1];
1619 lut_len =
1620 offset_tbl[filter][i][0] << 2;
1621 for (j = 0; j < lut_len; j++) {
1622 writel_relaxed(
1623 (lut_type[filter])
1624 [lut_offset++],
1625 lut_addr);
1626 lut_addr += 4;
1627 }
1628 }
1629 }
1630 }
1631
1632 if (scaler->lut_flag & SCALER_LUT_SWAP)
1633 writel_relaxed(BIT(0), MDSS_MDP_REG_SCALER_COEF_LUT_CTRL +
1634 offset);
1635
1636 return 0;
1637}
1638
1639static void mdss_mdp_scaler_detail_enhance_cfg(
1640 struct mdp_det_enhance_data *detail_en,
1641 char __iomem *offset)
1642{
1643
1644 uint32_t sharp_lvl, sharp_ctl, shape_ctl;
1645 uint32_t de_thr;
1646 uint32_t adjust_a, adjust_b, adjust_c;
1647
1648 if (detail_en->enable) {
1649 sharp_lvl = (detail_en->sharpen_level1 & 0x1FF) |
1650 ((detail_en->sharpen_level2 & 0x1FF) << 16);
1651
1652 sharp_ctl = ((detail_en->limit & 0xF) << 9) |
1653 ((detail_en->prec_shift & 0x7) << 13) |
1654 ((detail_en->clip & 0x7) << 16);
1655
1656 shape_ctl = (detail_en->thr_quiet & 0xFF) |
1657 ((detail_en->thr_dieout & 0x3FF) << 16);
1658
1659 de_thr = (detail_en->thr_low & 0x3FF) |
1660 ((detail_en->thr_high & 0x3FF) << 16);
1661
1662 adjust_a = (detail_en->adjust_a[0] & 0x3FF) |
1663 ((detail_en->adjust_a[1] & 0x3FF) << 10) |
1664 ((detail_en->adjust_a[2] & 0x3FF) << 20);
1665
1666 adjust_b = (detail_en->adjust_b[0] & 0x3FF) |
1667 ((detail_en->adjust_b[1] & 0x3FF) << 10) |
1668 ((detail_en->adjust_b[2] & 0x3FF) << 20);
1669
1670 adjust_c = (detail_en->adjust_c[0] & 0x3FF) |
1671 ((detail_en->adjust_c[1] & 0x3FF) << 10) |
1672 ((detail_en->adjust_c[2] & 0x3FF) << 20);
1673
1674 writel_relaxed(sharp_lvl, MDSS_MDP_REG_SCALER_DE_SHARPEN +
1675 offset);
1676 writel_relaxed(sharp_ctl, MDSS_MDP_REG_SCALER_DE_SHARPEN_CTL +
1677 offset);
1678 writel_relaxed(shape_ctl, MDSS_MDP_REG_SCALER_DE_SHAPE_CTL +
1679 offset);
1680 writel_relaxed(de_thr, MDSS_MDP_REG_SCALER_DE_THRESHOLD +
1681 offset);
1682 writel_relaxed(adjust_a, MDSS_MDP_REG_SCALER_DE_ADJUST_DATA_0
1683 + offset);
1684 writel_relaxed(adjust_b, MDSS_MDP_REG_SCALER_DE_ADJUST_DATA_1
1685 + offset);
1686 writel_relaxed(adjust_c, MDSS_MDP_REG_SCALER_DE_ADJUST_DATA_2
1687 + offset);
1688 }
1689}
1690
1691int mdss_mdp_qseed3_setup(struct mdss_mdp_pipe *pipe,
1692 int location, int id)
1693{
1694 int rc = 0;
1695 struct mdp_scale_data_v2 *scaler;
1696 struct mdss_data_type *mdata;
1697 char __iomem *offset, *lut_offset;
1698 struct mdss_mdp_format_params *fmt;
1699 uint32_t op_mode;
1700 uint32_t phase_init, preload, src_y_rgb, src_uv, dst;
1701
1702 mdata = mdss_mdp_get_mdata();
1703 /* SRC pipe QSEED3 Configuration */
1704 if (location == SSPP_VIG) {
1705 scaler = &pipe->scaler;
1706 offset = pipe->base + mdata->scaler_off->vig_scaler_off;
1707 lut_offset = pipe->base + mdata->scaler_off->vig_scaler_lut_off;
1708 fmt = pipe->src_fmt;
1709 } else if (location == DSPP) {
1710 /* Destination scaler QSEED3 Configuration */
1711 if ((mdata->scaler_off->has_dest_scaler) &&
1712 (id < mdata->scaler_off->ndest_scalers)) {
1713 /* TODO :point to the destination params */
1714 scaler = NULL;
1715 offset = mdata->scaler_off->dest_base +
1716 mdata->scaler_off->dest_scaler_off[id];
1717 lut_offset = mdata->scaler_off->dest_base +
1718 mdata->scaler_off->dest_scaler_lut_off[id];
1719 /*TODO : set pixel fmt to RGB101010 */
Sachin Bhayare3d3767e2018-01-02 21:10:57 +05301720 return -ENOTSUPP;
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301721 } else {
1722 return -EINVAL;
1723 }
1724 } else {
1725 return -EINVAL;
1726 }
1727
1728 pr_debug("scaler->enable=%d", scaler->enable);
1729 op_mode = readl_relaxed(MDSS_MDP_REG_SCALER_OP_MODE +
1730 offset);
1731
1732 if (scaler->enable) {
1733 op_mode |= SCALER_EN;
1734 op_mode |= (scaler->y_rgb_filter_cfg & 0x3) <<
1735 Y_FILTER_CFG;
1736
1737 if (fmt->is_yuv) {
1738 op_mode |= (1 << SCALER_COLOR_SPACE);
1739 op_mode |= (scaler->uv_filter_cfg & 0x3) <<
1740 UV_FILTER_CFG;
1741 }
1742
1743 if (fmt->alpha_enable) {
1744 op_mode |= SCALER_ALPHA_EN;
1745 op_mode |= (scaler->alpha_filter_cfg & 1) <<
1746 ALPHA_FILTER_CFG;
1747 }
1748
1749 /* TODO:if src_fmt is 10 bits program the bitwidth
1750 * accordingly
1751 */
1752 if (!fmt->unpack_dx_format)
1753 op_mode |= 0x1 << SCALER_BIT_WIDTH;
1754
1755 op_mode |= (scaler->blend_cfg & 1) <<
1756 SCALER_BLEND_CFG;
1757
1758 op_mode |= (scaler->enable & ENABLE_DIRECTION_DETECTION) ?
1759 (1 << SCALER_DIR_EN) : 0;
1760 phase_init =
1761 ((scaler->init_phase_x[0] & PHASE_BITS)
1762 << Y_PHASE_INIT_H) |
1763 ((scaler->init_phase_y[0] & PHASE_BITS) <<
1764 Y_PHASE_INIT_V) |
1765 ((scaler->init_phase_x[1] & PHASE_BITS) <<
1766 UV_PHASE_INIT_H) |
1767 ((scaler->init_phase_y[1] & PHASE_BITS) <<
1768 UV_PHASE_INIT_V);
1769
1770 preload =
1771 ((scaler->preload_x[0] & PRELOAD_BITS)
1772 << Y_PRELOAD_H) |
1773 ((scaler->preload_y[0] & PRELOAD_BITS) <<
1774 Y_PRELOAD_V) |
1775 ((scaler->preload_x[1] & PRELOAD_BITS) <<
1776 UV_PRELOAD_H) |
1777 ((scaler->preload_y[1] & PRELOAD_BITS) <<
1778 UV_PRELOAD_V);
1779
1780 src_y_rgb = (scaler->src_width[0] & 0x1FFFF) |
1781 ((scaler->src_height[0] & 0x1FFFF) << 16);
1782
1783 src_uv = (scaler->src_width[1] & 0x1FFFF) |
1784 ((scaler->src_height[1] & 0x1FFFF) << 16);
1785
1786 dst = (scaler->dst_width & 0x1FFFF) |
1787 ((scaler->dst_height & 0x1FFFF) << 16);
1788
1789 if (scaler->detail_enhance.enable) {
1790 mdss_mdp_scaler_detail_enhance_cfg(
1791 &scaler->detail_enhance,
1792 offset);
1793 op_mode |= SCALER_DE_EN;
1794 }
1795
1796 /* LUT Config */
1797 if (scaler->lut_flag) {
1798 rc = mdss_mdp_scaler_lut_cfg(scaler, lut_offset);
1799 if (rc) {
1800 pr_err("%s:Failed QSEED3 LUT cfg\n",
1801 __func__);
1802 return -EINVAL;
1803 }
1804 }
1805
1806 writel_relaxed(phase_init,
1807 MDSS_MDP_REG_SCALER_PHASE_INIT +
1808 offset);
1809 writel_relaxed(scaler->phase_step_x[0] &
1810 PHASE_STEP_BITS,
1811 MDSS_MDP_REG_SCALER_PHASE_STEP_Y_H +
1812 offset);
1813
1814 writel_relaxed(scaler->phase_step_y[0] &
1815 PHASE_STEP_BITS,
1816 MDSS_MDP_REG_SCALER_PHASE_STEP_Y_V + offset);
1817
1818 writel_relaxed(scaler->phase_step_x[1] &
1819 PHASE_STEP_BITS,
1820 MDSS_MDP_REG_SCALER_PHASE_STEP_UV_H + offset);
1821
1822 writel_relaxed(scaler->phase_step_y[1] &
1823 PHASE_STEP_BITS,
1824 MDSS_MDP_REG_SCALER_PHASE_STEP_UV_V + offset);
1825
1826 writel_relaxed(preload, MDSS_MDP_REG_SCALER_PRELOAD +
1827 offset);
1828 writel_relaxed(src_y_rgb,
1829 MDSS_MDP_REG_SCALER_SRC_SIZE_Y_RGB_A +
1830 offset);
1831 writel_relaxed(src_uv, MDSS_MDP_REG_SCALER_SRC_SIZE_UV
1832 + offset);
1833
1834 writel_relaxed(dst, MDSS_MDP_REG_SCALER_DST_SIZE +
1835 offset);
1836 } else {
1837 op_mode &= ~SCALER_EN;
1838 }
1839
1840 writel_relaxed(op_mode, MDSS_MDP_REG_SCALER_OP_MODE +
1841 offset);
1842 return rc;
1843}
1844
1845static int mdss_mdp_scale_setup(struct mdss_mdp_pipe *pipe)
1846{
1847 struct mdss_data_type *mdata;
1848 int rc = 0;
1849
1850 mdata = mdss_mdp_get_mdata();
1851 if (test_bit(MDSS_CAPS_QSEED3, mdata->mdss_caps_map))
1852 rc = mdss_mdp_qseed3_setup(pipe, SSPP_VIG, 0);
1853 else
1854 rc = mdss_mdp_qseed2_setup(pipe);
1855
1856 return rc;
1857}
1858
1859int mdss_mdp_pipe_pp_setup(struct mdss_mdp_pipe *pipe, u32 *op)
1860{
1861 int ret = 0;
1862
1863 if (!pipe)
1864 return -ENODEV;
1865
1866 ret = mdss_mdp_scale_setup(pipe);
1867 if (ret) {
1868 pr_err("scale setup on pipe %d type %d failed ret %d\n",
1869 pipe->num, pipe->type, ret);
1870 return -EINVAL;
1871 }
1872
1873 switch (pipe->type) {
1874 case MDSS_MDP_PIPE_TYPE_VIG:
1875 ret = pp_vig_pipe_setup(pipe, op);
1876 break;
1877 case MDSS_MDP_PIPE_TYPE_RGB:
1878 ret = pp_rgb_pipe_setup(pipe, op);
1879 break;
1880 case MDSS_MDP_PIPE_TYPE_DMA:
1881 ret = pp_dma_pipe_setup(pipe, op);
1882 break;
1883 default:
1884 pr_debug("no PP setup for pipe type %d\n",
1885 pipe->type);
1886 break;
1887 }
1888
1889 return ret;
1890}
1891
1892void mdss_mdp_pipe_pp_clear(struct mdss_mdp_pipe *pipe)
1893{
1894 struct pp_hist_col_info *hist_info;
1895
1896 if (!pipe) {
1897 pr_err("Invalid pipe context passed, %pK\n",
1898 pipe);
1899 return;
1900 }
1901
1902 if (mdss_mdp_pipe_is_yuv(pipe)) {
1903 hist_info = &pipe->pp_res.hist;
1904 pp_hist_disable(hist_info);
1905 }
1906
1907 kfree(pipe->pp_res.pa_cfg_payload);
1908 pipe->pp_res.pa_cfg_payload = NULL;
1909 pipe->pp_cfg.pa_v2_cfg_data.cfg_payload = NULL;
1910 kfree(pipe->pp_res.igc_cfg_payload);
1911 pipe->pp_res.igc_cfg_payload = NULL;
1912 pipe->pp_cfg.igc_cfg.cfg_payload = NULL;
1913 kfree(pipe->pp_res.pcc_cfg_payload);
1914 pipe->pp_res.pcc_cfg_payload = NULL;
1915 pipe->pp_cfg.pcc_cfg_data.cfg_payload = NULL;
1916 kfree(pipe->pp_res.hist_lut_cfg_payload);
1917 pipe->pp_res.hist_lut_cfg_payload = NULL;
1918 pipe->pp_cfg.hist_lut_cfg.cfg_payload = NULL;
1919
1920 memset(&pipe->pp_res.pp_sts, 0, sizeof(struct pp_sts_type));
1921 pipe->pp_cfg.config_ops = 0;
1922}
1923
1924int mdss_mdp_pipe_sspp_setup(struct mdss_mdp_pipe *pipe, u32 *op)
1925{
1926 int i, ret = 0;
1927 unsigned long flags = 0;
1928 char __iomem *pipe_base;
1929 u32 pipe_num, pipe_cnt;
1930 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
1931 u32 current_opmode, location;
1932 u32 dcm_state = DCM_UNINIT;
1933 struct mdss_mdp_pipe *pipe_list;
1934
1935 if (pipe == NULL)
1936 return -EINVAL;
1937
1938 mdss_mdp_pp_get_dcm_state(pipe, &dcm_state);
1939
1940 /* Read IGC state and update the same if tuning mode is enable */
1941 if (dcm_state == DTM_ENTER) {
1942 current_opmode = readl_relaxed(pipe->base +
1943 MDSS_MDP_REG_SSPP_SRC_OP_MODE);
1944 *op |= (current_opmode & BIT(16));
1945 return ret;
1946 }
1947
1948 /*
1949 * TODO: should this function be responsible for masking multiple
1950 * pipes to be written in dual pipe case?
1951 * if so, requires rework of update_igc_lut
1952 */
1953 switch (pipe->type) {
1954 case MDSS_MDP_PIPE_TYPE_VIG:
1955 pipe_base = mdata->mdp_base + MDSS_MDP_REG_IGC_VIG_BASE;
1956 pipe_cnt = mdata->nvig_pipes;
1957 pipe_list = mdata->vig_pipes;
1958 location = SSPP_VIG;
1959 break;
1960 case MDSS_MDP_PIPE_TYPE_RGB:
1961 pipe_base = mdata->mdp_base + MDSS_MDP_REG_IGC_RGB_BASE;
1962 pipe_cnt = mdata->nrgb_pipes;
1963 pipe_list = mdata->rgb_pipes;
1964 location = SSPP_RGB;
1965 break;
1966 case MDSS_MDP_PIPE_TYPE_DMA:
1967 pipe_base = mdata->mdp_base + MDSS_MDP_REG_IGC_DMA_BASE;
1968 pipe_cnt = mdata->ndma_pipes;
1969 pipe_list = mdata->dma_pipes;
1970 location = SSPP_DMA;
1971 break;
1972 case MDSS_MDP_PIPE_TYPE_CURSOR:
1973 /* cursor does not support the feature */
1974 return 0;
1975 default:
1976 pr_err("Invalid pipe type %d\n", pipe->type);
1977 return -EINVAL;
1978 }
1979
1980 for (i = 0, pipe_num = 0; pipe_num < pipe_cnt; pipe_num++) {
1981 if (pipe->num == pipe_list[i].num)
1982 break;
1983 i += pipe->multirect.max_rects;
1984 }
1985
1986 if (pipe_num == pipe_cnt) {
1987 pr_err("Invalid pipe num %d pipe type %d\n",
1988 pipe->num, pipe->type);
1989 return -EINVAL;
1990 }
1991
1992 if (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_IGC_CFG) {
1993 flags |= PP_FLAGS_DIRTY_IGC;
1994 if (!pp_ops[IGC].pp_set_config) {
1995 pp_igc_config(flags, pipe_base, &pipe->pp_res.pp_sts,
1996 &pipe->pp_cfg.igc_cfg, pipe_num, pipe_cnt);
1997 } else {
1998 pipe->pp_cfg.igc_cfg.block = pipe_num;
1999 pipe_base = mdata->mdp_base +
2000 mdata->pp_block_off.sspp_igc_lut_off;
2001 pp_ops[IGC].pp_set_config(pipe_base,
2002 &pipe->pp_res.pp_sts, &pipe->pp_cfg.igc_cfg,
2003 location);
2004 }
2005 }
2006
2007 if (pipe->pp_res.pp_sts.igc_sts & PP_STS_ENABLE)
2008 *op |= (1 << 16); /* IGC_LUT_EN */
2009
2010 return ret;
2011}
2012
2013static int pp_mixer_setup(struct mdss_mdp_mixer *mixer)
2014{
2015 u32 flags, disp_num, opmode = 0, lm_bitmask = 0;
2016 struct mdp_pgc_lut_data *pgc_config;
2017 struct pp_sts_type *pp_sts;
2018 struct mdss_mdp_ctl *ctl;
2019 char __iomem *addr;
2020 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
2021
2022 if (!mixer || !mixer->ctl || !mixer->ctl->mfd || !mdata) {
2023 pr_err("invalid parameters, mixer %pK ctl %pK mfd %pK mdata %pK\n",
2024 mixer, (mixer ? mixer->ctl : NULL),
2025 (mixer ? (mixer->ctl ? mixer->ctl->mfd : NULL) : NULL),
2026 mdata);
2027 return -EINVAL;
2028 }
2029 ctl = mixer->ctl;
2030 disp_num = ctl->mfd->index;
2031
2032 if (disp_num < MDSS_BLOCK_DISP_NUM)
2033 flags = mdss_pp_res->pp_disp_flags[disp_num];
2034 else
2035 flags = 0;
2036
2037 if (mixer->num == MDSS_MDP_INTF_LAYERMIXER3)
2038 lm_bitmask = BIT(20);
2039 else if (mixer->type == MDSS_MDP_MIXER_TYPE_WRITEBACK)
2040 lm_bitmask = BIT(9) << mixer->num;
2041 else
2042 lm_bitmask = BIT(6) << mixer->num;
2043
2044 pp_sts = &mdss_pp_res->pp_disp_sts[disp_num];
2045 /* GC_LUT is in layer mixer */
2046 if (flags & PP_FLAGS_DIRTY_ARGC) {
2047 if (pp_ops[GC].pp_set_config) {
2048 if (mdata->pp_block_off.lm_pgc_off == U32_MAX) {
2049 pr_err("invalid pgc offset %d\n", U32_MAX);
2050 } else {
2051 addr = mixer->base +
2052 mdata->pp_block_off.lm_pgc_off;
2053 pp_ops[GC].pp_set_config(addr, pp_sts,
2054 &mdss_pp_res->argc_disp_cfg[disp_num], LM);
2055 }
2056 } else {
2057 pgc_config = &mdss_pp_res->argc_disp_cfg[disp_num];
2058 if (pgc_config->flags & MDP_PP_OPS_WRITE) {
2059 addr = mixer->base +
2060 MDSS_MDP_REG_LM_GC_LUT_BASE;
2061 pp_update_argc_lut(addr, pgc_config);
2062 }
2063 if (pgc_config->flags & MDP_PP_OPS_DISABLE)
2064 pp_sts->argc_sts &= ~PP_STS_ENABLE;
2065 else if (pgc_config->flags & MDP_PP_OPS_ENABLE)
2066 pp_sts->argc_sts |= PP_STS_ENABLE;
2067 }
2068 ctl->flush_bits |= lm_bitmask;
2069 }
2070
2071 /* update LM opmode if LM needs flush */
2072 if ((pp_sts->argc_sts & PP_STS_ENABLE) &&
2073 (ctl->flush_bits & lm_bitmask)) {
2074 if (pp_driver_ops.pp_opmode_config) {
2075 pp_driver_ops.pp_opmode_config(LM, pp_sts,
2076 &opmode, 0);
2077 } else {
2078 addr = mixer->base + MDSS_MDP_REG_LM_OP_MODE;
2079 opmode = readl_relaxed(addr);
2080 opmode |= (1 << 0); /* GC_LUT_EN */
2081 writel_relaxed(opmode, addr);
2082 }
2083 }
2084 return 0;
2085}
2086
2087static char __iomem *mdss_mdp_get_mixer_addr_off(u32 mixer_num)
2088{
2089 struct mdss_data_type *mdata;
2090 struct mdss_mdp_mixer *mixer;
2091
2092 mdata = mdss_mdp_get_mdata();
2093 if (mdata->nmixers_intf <= mixer_num) {
2094 pr_err("Invalid mixer_num=%d\n", mixer_num);
2095 return ERR_PTR(-EINVAL);
2096 }
2097 mixer = mdata->mixer_intf + mixer_num;
2098 return mixer->base;
2099}
2100
2101static char __iomem *mdss_mdp_get_dspp_addr_off(u32 dspp_num)
2102{
2103 struct mdss_data_type *mdata;
2104 struct mdss_mdp_mixer *mixer;
2105
2106 mdata = mdss_mdp_get_mdata();
2107 if (mdata->ndspp <= dspp_num) {
2108 pr_debug("destination not supported dspp_num=%d\n",
2109 dspp_num);
2110 return ERR_PTR(-EINVAL);
2111 }
2112 mixer = mdata->mixer_intf + dspp_num;
2113 return mixer->dspp_base;
2114}
2115
2116/* Assumes that function will be called from within clock enabled space*/
2117static int pp_hist_setup(u32 *op, u32 block, struct mdss_mdp_mixer *mix,
2118 struct pp_sts_type *pp_sts)
2119{
2120 int ret = 0;
2121 char __iomem *base;
2122 u32 op_flags = 0, block_type = 0;
2123 struct mdss_mdp_pipe *pipe;
2124 struct pp_hist_col_info *hist_info;
2125 unsigned long flag;
2126 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
2127 u32 intr_mask;
2128
2129 if (!mdata)
2130 return -EPERM;
2131
2132 intr_mask = 1;
2133 if (mix && (PP_LOCAT(block) == MDSS_PP_DSPP_CFG)) {
2134 /* HIST_EN */
2135 block_type = DSPP;
2136 op_flags = BIT(16);
2137 hist_info = &mdss_pp_res->dspp_hist[mix->num];
2138 base = mdss_mdp_get_dspp_addr_off(PP_BLOCK(block));
2139 if (IS_ERR(base)) {
2140 ret = -EPERM;
2141 goto error;
2142 }
2143 } else if (PP_LOCAT(block) == MDSS_PP_SSPP_CFG &&
2144 (pp_driver_ops.is_sspp_hist_supp) &&
2145 (pp_driver_ops.is_sspp_hist_supp())) {
2146 block_type = SSPP_VIG;
2147 pipe = __get_hist_pipe(PP_BLOCK(block));
2148 if (IS_ERR_OR_NULL(pipe)) {
2149 pr_debug("pipe DNE (%d)\n",
2150 (u32) PP_BLOCK(block));
2151 ret = -ENODEV;
2152 goto error;
2153 }
2154 op_flags = BIT(8);
2155 hist_info = &pipe->pp_res.hist;
2156 base = pipe->base;
2157 mdss_mdp_pipe_unmap(pipe);
2158 } else {
2159 ret = -EINVAL;
2160 goto error;
2161 }
2162
2163 mutex_lock(&hist_info->hist_mutex);
2164 spin_lock_irqsave(&hist_info->hist_lock, flag);
2165 /*
2166 * Set histogram interrupt if histogram collection is enabled. The
2167 * interrupt register offsets are the same across different mdss
2168 * versions so far, hence mdss_mdp_hist_irq_set_mask is used for
2169 * all the mdss versions.
2170 */
2171 if (hist_info->col_en)
2172 mdss_mdp_hist_irq_set_mask(intr_mask << hist_info->intr_shift);
2173 /*
2174 * Starting from msmcobalt, the histogram enable bit has been moved
2175 * from DSPP opmode register to PA_HIST opmode register, hence we need
2176 * to update the histogram enable bit differently based on mdss version.
2177 * If HIST pp_set_config is defined, we will enable or disable the
2178 * hist_en bit in PA_HIST opmode register inside HIST pp_set_config
2179 * function; else, we only need to add the hist_en bit to the *op when
2180 * histogram collection is enable, and *op will be passed to
2181 * pp_dspp_setup to update the DSPP opmode register.
2182 */
2183 if (pp_ops[HIST].pp_set_config)
2184 ret = pp_ops[HIST].pp_set_config(base, pp_sts, hist_info,
2185 block_type);
2186 else if (hist_info->col_en)
2187 *op |= op_flags;
2188
2189 spin_unlock_irqrestore(&hist_info->hist_lock, flag);
2190 mutex_unlock(&hist_info->hist_mutex);
2191error:
2192 return ret;
2193}
2194
2195static void pp_dither_config(char __iomem *addr,
2196 struct pp_sts_type *pp_sts,
2197 struct mdp_dither_cfg_data *dither_cfg)
2198{
2199 u32 data;
2200 int i;
2201
2202 if (dither_cfg->flags & MDP_PP_OPS_WRITE) {
2203 data = dither_depth_map[dither_cfg->g_y_depth];
2204 data |= dither_depth_map[dither_cfg->b_cb_depth] << 2;
2205 data |= dither_depth_map[dither_cfg->r_cr_depth] << 4;
2206 writel_relaxed(data, addr);
2207 addr += 0x14;
2208 for (i = 0; i < 16; i += 4) {
2209 data = dither_matrix[i] |
2210 (dither_matrix[i + 1] << 4) |
2211 (dither_matrix[i + 2] << 8) |
2212 (dither_matrix[i + 3] << 12);
2213 writel_relaxed(data, addr);
2214 addr += 4;
2215 }
2216 }
2217 if (dither_cfg->flags & MDP_PP_OPS_DISABLE)
2218 pp_sts->dither_sts &= ~PP_STS_ENABLE;
2219 else if (dither_cfg->flags & MDP_PP_OPS_ENABLE)
2220 pp_sts->dither_sts |= PP_STS_ENABLE;
2221 pp_sts_set_split_bits(&pp_sts->dither_sts, dither_cfg->flags);
2222}
2223
2224static void pp_dspp_opmode_config(struct mdss_mdp_ctl *ctl, u32 num,
2225 struct pp_sts_type *pp_sts, int mdp_rev,
2226 u32 *opmode)
2227{
2228 int side;
2229 bool pa_side_enabled = false;
2230
2231 side = pp_num_to_side(ctl, num);
2232
2233 if (side < 0)
2234 return;
2235
2236 if (pp_driver_ops.pp_opmode_config) {
2237 pp_driver_ops.pp_opmode_config(DSPP,
2238 pp_sts, opmode, side);
2239 return;
2240 }
2241
2242 if (pp_sts_is_enabled(pp_sts->pa_sts, side)) {
2243 *opmode |= MDSS_MDP_DSPP_OP_PA_EN; /* PA_EN */
2244 pa_side_enabled = true;
2245 }
2246 if (mdp_rev >= MDSS_MDP_HW_REV_103 && pa_side_enabled) {
2247 if (pp_sts->pa_sts & PP_STS_PA_HUE_MASK)
2248 *opmode |= MDSS_MDP_DSPP_OP_PA_HUE_MASK;
2249 if (pp_sts->pa_sts & PP_STS_PA_SAT_MASK)
2250 *opmode |= MDSS_MDP_DSPP_OP_PA_SAT_MASK;
2251 if (pp_sts->pa_sts & PP_STS_PA_VAL_MASK)
2252 *opmode |= MDSS_MDP_DSPP_OP_PA_VAL_MASK;
2253 if (pp_sts->pa_sts & PP_STS_PA_CONT_MASK)
2254 *opmode |= MDSS_MDP_DSPP_OP_PA_CONT_MASK;
2255 if (pp_sts->pa_sts & PP_STS_PA_MEM_PROTECT_EN)
2256 *opmode |= MDSS_MDP_DSPP_OP_PA_MEM_PROTECT_EN;
2257 if (pp_sts->pa_sts & PP_STS_PA_SAT_ZERO_EXP_EN)
2258 *opmode |= MDSS_MDP_DSPP_OP_PA_SAT_ZERO_EXP_EN;
2259 if (pp_sts->pa_sts & PP_STS_PA_MEM_COL_SKIN_MASK)
2260 *opmode |= MDSS_MDP_DSPP_OP_PA_MEM_COL_SKIN_MASK;
2261 if (pp_sts->pa_sts & PP_STS_PA_MEM_COL_FOL_MASK)
2262 *opmode |= MDSS_MDP_DSPP_OP_PA_MEM_COL_FOL_MASK;
2263 if (pp_sts->pa_sts & PP_STS_PA_MEM_COL_SKY_MASK)
2264 *opmode |= MDSS_MDP_DSPP_OP_PA_MEM_COL_SKY_MASK;
2265 if (pp_sts->pa_sts & PP_STS_PA_SIX_ZONE_HUE_MASK)
2266 *opmode |= MDSS_MDP_DSPP_OP_PA_SIX_ZONE_HUE_MASK;
2267 if (pp_sts->pa_sts & PP_STS_PA_SIX_ZONE_SAT_MASK)
2268 *opmode |= MDSS_MDP_DSPP_OP_PA_SIX_ZONE_SAT_MASK;
2269 if (pp_sts->pa_sts & PP_STS_PA_SIX_ZONE_VAL_MASK)
2270 *opmode |= MDSS_MDP_DSPP_OP_PA_SIX_ZONE_VAL_MASK;
2271 }
2272 if (pp_sts_is_enabled(pp_sts->pcc_sts, side))
2273 *opmode |= MDSS_MDP_DSPP_OP_PCC_EN; /* PCC_EN */
2274
2275 if (pp_sts_is_enabled(pp_sts->igc_sts, side)) {
2276 *opmode |= MDSS_MDP_DSPP_OP_IGC_LUT_EN | /* IGC_LUT_EN */
2277 (pp_sts->igc_tbl_idx << 1);
2278 }
2279 if (pp_sts->enhist_sts & PP_STS_ENABLE) {
2280 *opmode |= MDSS_MDP_DSPP_OP_HIST_LUTV_EN | /* HIST_LUT_EN */
2281 MDSS_MDP_DSPP_OP_PA_EN; /* PA_EN */
2282 }
2283 if (pp_sts_is_enabled(pp_sts->dither_sts, side))
2284 *opmode |= MDSS_MDP_DSPP_OP_DST_DITHER_EN; /* DITHER_EN */
2285 if (pp_sts_is_enabled(pp_sts->gamut_sts, side)) {
2286 *opmode |= MDSS_MDP_DSPP_OP_GAMUT_EN; /* GAMUT_EN */
2287 if (pp_sts->gamut_sts & PP_STS_GAMUT_FIRST)
2288 *opmode |= MDSS_MDP_DSPP_OP_GAMUT_PCC_ORDER;
2289 }
2290 if (pp_sts_is_enabled(pp_sts->pgc_sts, side))
2291 *opmode |= MDSS_MDP_DSPP_OP_ARGC_LUT_EN;
2292}
2293
2294static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_mixer *mixer)
2295{
2296 u32 ad_flags, flags, dspp_num, opmode = 0, ad_bypass;
2297 struct mdp_pgc_lut_data *pgc_config;
2298 struct pp_sts_type *pp_sts = NULL;
2299 char __iomem *base, *addr = NULL;
2300 int ret = 0;
2301 struct mdss_data_type *mdata;
2302 struct mdss_ad_info *ad = NULL;
2303 struct mdss_mdp_ad *ad_hw = NULL;
2304 struct mdp_pa_v2_cfg_data *pa_v2_cfg_data = NULL;
2305 struct mdss_mdp_ctl *ctl;
2306 u32 mixer_cnt;
2307 u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
2308 int side;
2309
2310 if (!mixer || !mixer->ctl || !mixer->ctl->mdata)
2311 return -EINVAL;
2312 ctl = mixer->ctl;
2313 mdata = ctl->mdata;
2314 dspp_num = mixer->num;
2315 /* no corresponding dspp */
2316 if ((mixer->type != MDSS_MDP_MIXER_TYPE_INTF) ||
2317 (dspp_num >= mdata->ndspp))
2318 return -EINVAL;
2319 base = mdss_mdp_get_dspp_addr_off(dspp_num);
2320 if (IS_ERR(base))
2321 return -EINVAL;
2322
2323 side = pp_num_to_side(ctl, dspp_num);
2324 if (side < 0) {
2325 pr_err("invalid side information for dspp_num %d", dspp_num);
2326 return -EINVAL;
2327 }
2328
2329 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
2330 if ((mdata->pp_block_off.dspp_gamut_off != U32_MAX) &&
2331 (pp_driver_ops.gamut_clk_gate_en))
2332 pp_driver_ops.gamut_clk_gate_en(base +
2333 mdata->pp_block_off.dspp_gamut_off);
2334
2335 if (disp_num < MDSS_BLOCK_DISP_NUM) {
2336 pp_sts = &mdss_pp_res->pp_disp_sts[disp_num];
2337 pp_sts->side_sts = side;
2338
2339 ret = pp_hist_setup(&opmode, MDSS_PP_DSPP_CFG | dspp_num, mixer,
2340 pp_sts);
2341 if (ret)
2342 goto dspp_exit;
2343
2344 flags = mdss_pp_res->pp_disp_flags[disp_num];
2345 } else {
2346 flags = 0;
2347 }
2348
2349 mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
2350 if (dspp_num < mdata->nad_cfgs && disp_num < mdata->nad_cfgs &&
2351 (mixer_cnt <= mdata->nmax_concurrent_ad_hw)) {
2352 ad = &mdata->ad_cfgs[disp_num];
2353 ad_flags = ad->reg_sts;
2354 ad_hw = &mdata->ad_off[dspp_num];
2355 } else {
2356 ad_flags = 0;
2357 }
2358
2359 /* nothing to update */
2360 if ((!flags) && (!(opmode)) && (!ad_flags))
2361 goto dspp_exit;
2362
2363 if (flags & PP_FLAGS_DIRTY_PA) {
2364 if (!pp_ops[PA].pp_set_config) {
2365 if (mdata->mdp_rev >= MDSS_MDP_HW_REV_103) {
2366 pa_v2_cfg_data =
2367 &mdss_pp_res->pa_v2_disp_cfg[disp_num];
2368 pp_pa_v2_config(flags,
2369 base + MDSS_MDP_REG_DSPP_PA_BASE,
2370 pp_sts,
2371 &pa_v2_cfg_data->pa_v2_data,
2372 PP_DSPP);
2373 } else
2374 pp_pa_config(flags,
2375 base + MDSS_MDP_REG_DSPP_PA_BASE,
2376 pp_sts,
2377 &mdss_pp_res->pa_disp_cfg[disp_num]);
2378 } else {
2379 pp_ops[PA].pp_set_config(base, pp_sts,
2380 &mdss_pp_res->pa_v2_disp_cfg[disp_num],
2381 DSPP);
2382 }
2383 }
2384 if (flags & PP_FLAGS_DIRTY_PCC) {
2385 if (!pp_ops[PCC].pp_set_config)
2386 pp_pcc_config(flags, base + MDSS_MDP_REG_DSPP_PCC_BASE,
2387 pp_sts,
2388 &mdss_pp_res->pcc_disp_cfg[disp_num]);
2389 else {
2390 if (mdata->pp_block_off.dspp_pcc_off == U32_MAX) {
2391 pr_err("invalid pcc off %d\n", U32_MAX);
2392 } else {
2393 addr = base + mdata->pp_block_off.dspp_pcc_off;
2394 pp_ops[PCC].pp_set_config(addr, pp_sts,
2395 &mdss_pp_res->pcc_disp_cfg[disp_num],
2396 DSPP);
2397 }
2398 }
2399 }
2400
2401 if (flags & PP_FLAGS_DIRTY_IGC) {
2402 if (!pp_ops[IGC].pp_set_config) {
2403 pp_igc_config(flags,
2404 mdata->mdp_base + MDSS_MDP_REG_IGC_DSPP_BASE,
2405 pp_sts, &mdss_pp_res->igc_disp_cfg[disp_num],
2406 dspp_num, mdata->ndspp);
2407 } else {
2408 addr = mdata->mdp_base + MDSS_MDP_REG_IGC_DSPP_BASE;
2409 /* Pass dspp num using block */
2410 mdss_pp_res->igc_disp_cfg[disp_num].block = dspp_num;
2411 pp_ops[IGC].pp_set_config(addr, pp_sts,
2412 &mdss_pp_res->igc_disp_cfg[disp_num],
2413 DSPP);
2414 }
2415 }
2416
2417 if (flags & PP_FLAGS_DIRTY_ENHIST) {
2418 if (!pp_ops[HIST_LUT].pp_set_config) {
2419 pp_enhist_config(flags,
2420 base + MDSS_MDP_REG_DSPP_HIST_LUT_BASE,
2421 pp_sts,
2422 &mdss_pp_res->enhist_disp_cfg[disp_num]);
2423
2424 if ((pp_sts->enhist_sts & PP_STS_ENABLE) &&
2425 !(pp_sts->pa_sts & PP_STS_ENABLE)) {
2426 /* Program default value */
2427 addr = base + MDSS_MDP_REG_DSPP_PA_BASE;
2428 writel_relaxed(0, addr);
2429 writel_relaxed(0, addr + 4);
2430 writel_relaxed(0, addr + 8);
2431 writel_relaxed(0, addr + 12);
2432 }
2433 } else {
2434 /* Pass dspp num using block */
2435 mdss_pp_res->enhist_disp_cfg[disp_num].block = dspp_num;
2436 pp_ops[HIST_LUT].pp_set_config(base, pp_sts,
2437 &mdss_pp_res->enhist_disp_cfg[disp_num], DSPP);
2438 }
2439 }
2440
2441 if (flags & PP_FLAGS_DIRTY_DITHER) {
2442 if (!pp_ops[DITHER].pp_set_config) {
2443 pp_dither_config(addr, pp_sts,
2444 &mdss_pp_res->dither_disp_cfg[disp_num]);
2445 } else {
2446 addr = base + MDSS_MDP_REG_DSPP_DITHER_DEPTH;
2447 pp_ops[DITHER].pp_set_config(addr, pp_sts,
2448 &mdss_pp_res->dither_disp_cfg[disp_num], DSPP);
2449 }
2450 }
2451 if (flags & PP_FLAGS_DIRTY_GAMUT) {
2452 if (!pp_ops[GAMUT].pp_set_config) {
2453 pp_gamut_config(&mdss_pp_res->gamut_disp_cfg[disp_num],
2454 base, pp_sts);
2455 } else {
2456 if (mdata->pp_block_off.dspp_gamut_off == U32_MAX) {
2457 pr_err("invalid gamut off %d\n", U32_MAX);
2458 } else {
2459 addr = base +
2460 mdata->pp_block_off.dspp_gamut_off;
2461 pp_ops[GAMUT].pp_set_config(addr, pp_sts,
2462 &mdss_pp_res->gamut_disp_cfg[disp_num],
2463 DSPP);
2464 }
2465 }
2466 }
2467
2468 if (flags & PP_FLAGS_DIRTY_PGC) {
2469 pgc_config = &mdss_pp_res->pgc_disp_cfg[disp_num];
2470 if (pp_ops[GC].pp_set_config) {
2471 if (mdata->pp_block_off.dspp_pgc_off == U32_MAX) {
2472 pr_err("invalid pgc offset %d\n", U32_MAX);
2473 } else {
2474 addr = base +
2475 mdata->pp_block_off.dspp_pgc_off;
2476 pp_ops[GC].pp_set_config(addr, pp_sts,
2477 &mdss_pp_res->pgc_disp_cfg[disp_num],
2478 DSPP);
2479 }
2480 } else {
2481 if (pgc_config->flags & MDP_PP_OPS_WRITE) {
2482 addr = base + MDSS_MDP_REG_DSPP_GC_BASE;
2483 pp_update_argc_lut(addr, pgc_config);
2484 }
2485 if (pgc_config->flags & MDP_PP_OPS_DISABLE)
2486 pp_sts->pgc_sts &= ~PP_STS_ENABLE;
2487 else if (pgc_config->flags & MDP_PP_OPS_ENABLE)
2488 pp_sts->pgc_sts |= PP_STS_ENABLE;
2489 pp_sts_set_split_bits(&pp_sts->pgc_sts,
2490 pgc_config->flags);
2491 }
2492 }
2493
2494 if (pp_sts != NULL)
2495 pp_dspp_opmode_config(ctl, dspp_num, pp_sts, mdata->mdp_rev,
2496 &opmode);
2497
2498 if (ad_hw) {
2499 mutex_lock(&ad->lock);
2500 ad_flags = ad->reg_sts;
2501 if (ad_flags & PP_AD_STS_DIRTY_DATA)
2502 pp_ad_input_write(ad_hw, ad);
2503 if (ad_flags & PP_AD_STS_DIRTY_INIT)
2504 pp_ad_init_write(ad_hw, ad, ctl);
2505 if (ad_flags & PP_AD_STS_DIRTY_CFG)
2506 pp_ad_cfg_write(ad_hw, ad);
2507
2508 if (ad->state & PP_AD_STATE_IPC_RESET) {
2509 writel_relaxed(ad->cfg.t_filter_recursion,
2510 ad_hw->base + MDSS_MDP_REG_AD_TFILT_CTRL);
2511 writel_relaxed(ad->cfg.mode | MDSS_AD_AUTO_TRIGGER,
2512 ad_hw->base + MDSS_MDP_REG_AD_MODE_SEL);
2513 }
2514
2515 pp_ad_bypass_config(ad, ctl, ad_hw->num, &ad_bypass);
2516 writel_relaxed(ad_bypass, ad_hw->base);
2517 mutex_unlock(&ad->lock);
2518 }
2519
2520 writel_relaxed(opmode, base + MDSS_MDP_REG_DSPP_OP_MODE);
2521
2522 if (dspp_num == MDSS_MDP_DSPP3)
2523 ctl->flush_bits |= BIT(21);
2524 else
2525 ctl->flush_bits |= BIT(13 + dspp_num);
2526
2527 wmb(); /* ensure write is finished before progressing */
2528dspp_exit:
2529 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
2530 return ret;
2531}
2532
2533int mdss_mdp_pp_setup(struct mdss_mdp_ctl *ctl)
2534{
2535 int ret = 0;
2536
2537 if ((!ctl->mfd) || (!mdss_pp_res))
2538 return -EINVAL;
2539
2540 /* TODO: have some sort of reader/writer lock to prevent unclocked
2541 * access while display power is toggled
2542 */
2543 mutex_lock(&ctl->lock);
2544 if (!mdss_mdp_ctl_is_power_on(ctl)) {
2545 ret = -EPERM;
2546 goto error;
2547 }
2548 ret = mdss_mdp_pp_setup_locked(ctl);
2549error:
2550 mutex_unlock(&ctl->lock);
2551
2552 return ret;
2553}
2554
2555int mdss_mdp_pp_setup_locked(struct mdss_mdp_ctl *ctl)
2556{
2557 struct mdss_data_type *mdata;
2558 int ret = 0, i;
2559 u32 flags, pa_v2_flags;
2560 u32 max_bw_needed;
2561 u32 mixer_cnt;
2562 u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
2563 u32 disp_num;
2564 bool valid_mixers = true;
2565 bool valid_ad_panel = true;
2566
2567 if ((!ctl) || (!ctl->mfd) || (!mdss_pp_res) || (!ctl->mdata))
2568 return -EINVAL;
2569
2570 mdata = ctl->mdata;
2571 /* treat fb_num the same as block logical id*/
2572 disp_num = ctl->mfd->index;
2573
2574 mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
2575 if (!mixer_cnt) {
2576 valid_mixers = false;
2577 ret = -EINVAL;
2578 pr_warn("Configuring post processing without mixers, err = %d\n",
2579 ret);
2580 goto exit;
2581 }
2582 if (mdata->nad_cfgs == 0)
2583 valid_mixers = false;
2584 for (i = 0; i < mixer_cnt && valid_mixers; i++) {
2585 if (mixer_id[i] >= mdata->nad_cfgs)
2586 valid_mixers = false;
2587 }
2588 valid_ad_panel = (ctl->mfd->panel_info->type != DTV_PANEL) &&
2589 (((mdata->mdp_rev < MDSS_MDP_HW_REV_103) &&
2590 (ctl->mfd->panel_info->type == WRITEBACK_PANEL)) ||
2591 (ctl->mfd->panel_info->type != WRITEBACK_PANEL));
2592
2593 if (valid_mixers && (mixer_cnt <= mdata->nmax_concurrent_ad_hw) &&
2594 valid_ad_panel) {
2595 ret = mdss_mdp_ad_setup(ctl->mfd);
2596 if (ret < 0)
2597 pr_warn("ad_setup(disp%d) returns %d\n", disp_num, ret);
2598 }
2599
2600 mutex_lock(&mdss_pp_mutex);
2601
2602 flags = mdss_pp_res->pp_disp_flags[disp_num];
2603 if (pp_ops[PA].pp_set_config)
2604 pa_v2_flags = mdss_pp_res->pa_v2_disp_cfg[disp_num].flags;
2605 else
2606 pa_v2_flags =
2607 mdss_pp_res->pa_v2_disp_cfg[disp_num].pa_v2_data.flags;
2608 /*
2609 * If a LUT based PP feature needs to be reprogrammed during resume,
2610 * increase the register bus bandwidth to maximum frequency
2611 * in order to speed up the register reprogramming.
2612 */
2613 max_bw_needed = (IS_PP_RESUME_COMMIT(flags) &&
2614 (IS_PP_LUT_DIRTY(flags) ||
2615 IS_SIX_ZONE_DIRTY(flags, pa_v2_flags)));
2616 if (mdata->pp_reg_bus_clt && max_bw_needed) {
2617 ret = mdss_update_reg_bus_vote(mdata->pp_reg_bus_clt,
2618 VOTE_INDEX_HIGH);
2619 if (ret)
2620 pr_err("Updated reg_bus_scale failed, ret = %d", ret);
2621 }
2622
2623 if (ctl->mixer_left) {
2624 pp_mixer_setup(ctl->mixer_left);
2625 pp_dspp_setup(disp_num, ctl->mixer_left);
2626 pp_ppb_setup(ctl->mixer_left);
2627 }
2628 if (ctl->mixer_right) {
2629 pp_mixer_setup(ctl->mixer_right);
2630 pp_dspp_setup(disp_num, ctl->mixer_right);
2631 pp_ppb_setup(ctl->mixer_right);
2632 }
2633
2634 if (valid_mixers && (mixer_cnt <= mdata->nmax_concurrent_ad_hw) &&
2635 valid_ad_panel) {
2636 ret = mdss_mdp_ad_ipc_reset(ctl->mfd);
2637 if (ret < 0)
2638 pr_warn("ad_setup(disp%d) returns %d\n", disp_num, ret);
2639 }
2640
2641 /* clear dirty flag */
2642 if (disp_num < MDSS_BLOCK_DISP_NUM) {
2643 mdss_pp_res->pp_disp_flags[disp_num] = 0;
2644 if (disp_num < mdata->nad_cfgs)
2645 mdata->ad_cfgs[disp_num].reg_sts = 0;
2646 }
2647
2648 if (mdata->pp_reg_bus_clt && max_bw_needed) {
2649 ret = mdss_update_reg_bus_vote(mdata->pp_reg_bus_clt,
2650 VOTE_INDEX_DISABLE);
2651 if (ret)
2652 pr_err("Updated reg_bus_scale failed, ret = %d", ret);
2653 }
2654 if (IS_PP_RESUME_COMMIT(flags))
2655 mdss_pp_res->pp_disp_flags[disp_num] &=
2656 ~PP_FLAGS_RESUME_COMMIT;
2657 mutex_unlock(&mdss_pp_mutex);
2658exit:
2659 return ret;
2660}
2661
2662/*
2663 * Set dirty and write bits on features that were enabled so they will be
2664 * reconfigured
2665 */
2666int mdss_mdp_pp_resume(struct msm_fb_data_type *mfd)
2667{
2668 u32 flags = 0, disp_num, ret = 0;
2669 struct pp_sts_type pp_sts;
2670 struct mdss_ad_info *ad;
2671 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
2672 struct mdp_pa_v2_cfg_data *pa_v2_cache_cfg = NULL;
2673
2674 if (!mfd) {
2675 pr_err("invalid input: mfd = 0x%pK\n", mfd);
2676 return -EINVAL;
2677 }
2678
2679 if (!mdss_mdp_mfd_valid_dspp(mfd)) {
2680 pr_debug("PP not supported on display num %d hw config\n",
2681 mfd->index);
2682 return -EPERM;
2683 }
2684
2685 disp_num = mfd->index;
2686 pp_sts = mdss_pp_res->pp_disp_sts[disp_num];
2687
2688 if (pp_sts.pa_sts & PP_STS_ENABLE) {
2689 flags |= PP_FLAGS_DIRTY_PA;
2690 pa_v2_cache_cfg = &mdss_pp_res->pa_v2_disp_cfg[disp_num];
2691 if (pp_ops[PA].pp_set_config) {
2692 if (!(pa_v2_cache_cfg->flags & MDP_PP_OPS_DISABLE))
2693 pa_v2_cache_cfg->flags |= MDP_PP_OPS_WRITE;
2694 } else if (mdata->mdp_rev >= MDSS_MDP_HW_REV_103) {
2695 if (!(pa_v2_cache_cfg->pa_v2_data.flags
2696 & MDP_PP_OPS_DISABLE))
2697 pa_v2_cache_cfg->pa_v2_data.flags |=
2698 MDP_PP_OPS_WRITE;
2699 } else {
2700 if (!(mdss_pp_res->pa_disp_cfg[disp_num].flags
2701 & MDP_PP_OPS_DISABLE))
2702 mdss_pp_res->pa_disp_cfg[disp_num].flags |=
2703 MDP_PP_OPS_WRITE;
2704 }
2705 }
2706 if (pp_sts.pcc_sts & PP_STS_ENABLE) {
2707 flags |= PP_FLAGS_DIRTY_PCC;
2708 if (!(mdss_pp_res->pcc_disp_cfg[disp_num].ops
2709 & MDP_PP_OPS_DISABLE))
2710 mdss_pp_res->pcc_disp_cfg[disp_num].ops |=
2711 MDP_PP_OPS_WRITE;
2712 }
2713 if (pp_sts.igc_sts & PP_STS_ENABLE) {
2714 flags |= PP_FLAGS_DIRTY_IGC;
2715 if (!(mdss_pp_res->igc_disp_cfg[disp_num].ops
2716 & MDP_PP_OPS_DISABLE))
2717 mdss_pp_res->igc_disp_cfg[disp_num].ops |=
2718 MDP_PP_OPS_WRITE;
2719 }
2720 if (pp_sts.argc_sts & PP_STS_ENABLE) {
2721 flags |= PP_FLAGS_DIRTY_ARGC;
2722 if (!(mdss_pp_res->argc_disp_cfg[disp_num].flags
2723 & MDP_PP_OPS_DISABLE))
2724 mdss_pp_res->argc_disp_cfg[disp_num].flags |=
2725 MDP_PP_OPS_WRITE;
2726 }
2727 if (pp_sts.enhist_sts & PP_STS_ENABLE) {
2728 flags |= PP_FLAGS_DIRTY_ENHIST;
2729 if (!(mdss_pp_res->enhist_disp_cfg[disp_num].ops
2730 & MDP_PP_OPS_DISABLE))
2731 mdss_pp_res->enhist_disp_cfg[disp_num].ops |=
2732 MDP_PP_OPS_WRITE;
2733 }
2734 if (pp_sts.dither_sts & PP_STS_ENABLE) {
2735 flags |= PP_FLAGS_DIRTY_DITHER;
2736 if (!(mdss_pp_res->dither_disp_cfg[disp_num].flags
2737 & MDP_PP_OPS_DISABLE))
2738 mdss_pp_res->dither_disp_cfg[disp_num].flags |=
2739 MDP_PP_OPS_WRITE;
2740 }
2741 if (pp_sts.gamut_sts & PP_STS_ENABLE) {
2742 flags |= PP_FLAGS_DIRTY_GAMUT;
2743 if (!(mdss_pp_res->gamut_disp_cfg[disp_num].flags
2744 & MDP_PP_OPS_DISABLE))
2745 mdss_pp_res->gamut_disp_cfg[disp_num].flags |=
2746 MDP_PP_OPS_WRITE;
2747 }
2748 if (pp_sts.pgc_sts & PP_STS_ENABLE) {
2749 flags |= PP_FLAGS_DIRTY_PGC;
2750 if (!(mdss_pp_res->pgc_disp_cfg[disp_num].flags
2751 & MDP_PP_OPS_DISABLE))
2752 mdss_pp_res->pgc_disp_cfg[disp_num].flags |=
2753 MDP_PP_OPS_WRITE;
2754 }
2755
2756 mdss_pp_res->pp_disp_flags[disp_num] |= flags;
2757 mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_RESUME_COMMIT;
2758
2759 ret = mdss_mdp_get_ad(mfd, &ad);
2760 if (ret == -ENODEV || ret == -EPERM) {
2761 pr_debug("AD not supported on device, disp num %d\n",
2762 mfd->index);
2763 return 0;
2764 } else if (ret || !ad) {
2765 pr_err("Failed to get ad info: ret = %d, ad = 0x%pK\n",
2766 ret, ad);
2767 return ret;
2768 }
2769
2770 mutex_lock(&ad->lock);
2771 if (mfd->ipc_resume) {
2772 mfd->ipc_resume = false;
2773 if (PP_AD_STATE_RUN & ad->state) {
2774 ad->ipc_frame_count = 0;
2775 ad->state |= PP_AD_STATE_IPC_RESUME;
2776 ad->cfg.mode |= MDSS_AD_MODE_IPC_BIT;
2777 pr_debug("switch mode to %d, last_ad_data = %d\n",
2778 ad->cfg.mode, ad->last_ad_data);
2779 }
2780 }
2781
2782 if (PP_AD_STATE_CFG & ad->state)
2783 ad->sts |= PP_AD_STS_DIRTY_CFG;
2784 if (PP_AD_STATE_INIT & ad->state)
2785 ad->sts |= PP_AD_STS_DIRTY_INIT;
2786 if ((PP_AD_STATE_DATA & ad->state) &&
2787 (ad->sts & PP_STS_ENABLE))
2788 ad->sts |= PP_AD_STS_DIRTY_DATA;
2789
2790 if (PP_AD_STATE_RUN & ad->state)
2791 ad->state &= ~PP_AD_STATE_VSYNC;
2792 mutex_unlock(&ad->lock);
2793
2794 return 0;
2795}
2796
2797static int mdss_mdp_pp_dt_parse(struct device *dev)
2798{
2799 int ret = -EINVAL;
2800 struct device_node *node;
2801 struct mdss_data_type *mdata;
2802 u32 prop_val;
2803
2804 mdata = mdss_mdp_get_mdata();
2805 if (dev && mdata) {
2806 /* initialize offsets to U32_MAX */
2807 memset(&mdata->pp_block_off, U8_MAX,
2808 sizeof(mdata->pp_block_off));
2809 node = of_get_child_by_name(dev->of_node,
2810 "qcom,mdss-pp-offsets");
2811 if (node) {
2812 ret = of_property_read_u32(node,
2813 "qcom,mdss-sspp-mdss-igc-lut-off",
2814 &prop_val);
2815 if (ret) {
2816 pr_err("read property %s failed ret %d\n",
2817 "qcom,mdss-sspp-mdss-igc-lut-off", ret);
2818 goto bail_out;
2819 } else {
2820 mdata->pp_block_off.sspp_igc_lut_off =
2821 prop_val;
2822 }
2823
2824 ret = of_property_read_u32(node,
2825 "qcom,mdss-sspp-vig-pcc-off",
2826 &prop_val);
2827 if (ret) {
2828 pr_err("read property %s failed ret %d\n",
2829 "qcom,mdss-sspp-vig-pcc-off", ret);
2830 goto bail_out;
2831 } else {
2832 mdata->pp_block_off.vig_pcc_off = prop_val;
2833 }
2834
2835 ret = of_property_read_u32(node,
2836 "qcom,mdss-sspp-rgb-pcc-off",
2837 &prop_val);
2838 if (ret) {
2839 pr_err("read property %s failed ret %d\n",
2840 "qcom,mdss-sspp-rgb-pcc-off", ret);
2841 goto bail_out;
2842 } else {
2843 mdata->pp_block_off.rgb_pcc_off = prop_val;
2844 }
2845
2846 ret = of_property_read_u32(node,
2847 "qcom,mdss-sspp-dma-pcc-off",
2848 &prop_val);
2849 if (ret) {
2850 pr_err("read property %s failed ret %d\n",
2851 "qcom,mdss-sspp-dma-pcc-off", ret);
2852 goto bail_out;
2853 } else {
2854 mdata->pp_block_off.dma_pcc_off = prop_val;
2855 }
2856
2857 ret = of_property_read_u32(node,
2858 "qcom,mdss-lm-pgc-off",
2859 &prop_val);
2860
2861 if (ret) {
2862 pr_err("read property %s failed ret %d\n",
2863 "qcom,mdss-lm-pgc-off", ret);
2864 goto bail_out;
2865 } else {
2866 mdata->pp_block_off.lm_pgc_off = prop_val;
2867 }
2868
2869 ret = of_property_read_u32(node,
2870 "qcom,mdss-dspp-gamut-off",
2871 &prop_val);
2872 if (ret) {
2873 pr_debug("Could not read/find %s prop ret %d\n",
2874 "qcom,mdss-dspp-gamut-off", ret);
2875 mdata->pp_block_off.dspp_gamut_off = U32_MAX;
2876 } else {
2877 mdata->pp_block_off.dspp_gamut_off = prop_val;
2878 }
2879
2880 ret = of_property_read_u32(node,
2881 "qcom,mdss-dspp-pcc-off",
2882 &prop_val);
2883 if (ret) {
2884 pr_err("read property %s failed ret %d\n",
2885 "qcom,mdss-dspp-pcc-off", ret);
2886 goto bail_out;
2887 } else {
2888 mdata->pp_block_off.dspp_pcc_off = prop_val;
2889 }
2890
2891 ret = of_property_read_u32(node,
2892 "qcom,mdss-dspp-pgc-off",
2893 &prop_val);
2894 if (ret) {
2895 pr_err("read property %s failed ret %d\n",
2896 "qcom,mdss-dspp-pgc-off", ret);
2897 goto bail_out;
2898 } else {
2899 mdata->pp_block_off.dspp_pgc_off = prop_val;
2900 }
2901 } else {
2902 pr_debug("offsets are not supported\n");
2903 ret = 0;
2904 }
2905 } else {
2906 pr_err("invalid dev %pK mdata %pK\n", dev, mdata);
2907 ret = -EINVAL;
2908 }
2909bail_out:
2910 return ret;
2911}
2912
2913int mdss_mdp_pp_init(struct device *dev)
2914{
2915 int i, ret = 0;
2916 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
2917 struct mdss_mdp_pipe *vig;
2918 struct pp_hist_col_info *hist = NULL;
2919 u32 ctl_off = 0;
2920
2921 if (!mdata)
2922 return -EPERM;
2923
2924
2925 mdata->pp_reg_bus_clt = mdss_reg_bus_vote_client_create("pp\0");
2926 if (IS_ERR(mdata->pp_reg_bus_clt))
2927 pr_err("bus client register failed\n");
2928
2929 mutex_lock(&mdss_pp_mutex);
2930 if (!mdss_pp_res) {
2931 mdss_pp_res = devm_kzalloc(dev, sizeof(*mdss_pp_res),
2932 GFP_KERNEL);
2933 if (mdss_pp_res == NULL) {
2934 ret = -ENOMEM;
2935 } else {
2936 if (mdss_mdp_pp_dt_parse(dev))
2937 pr_info("No PP info in device tree\n");
2938
2939 ret = pp_get_driver_ops(&pp_driver_ops);
2940 if (ret) {
2941 pr_err("pp_get_driver_ops failed, ret=%d\n",
2942 ret);
2943 goto pp_exit;
2944 }
2945 pp_ops = pp_driver_ops.pp_ops;
2946 hist = devm_kzalloc(dev,
2947 sizeof(struct pp_hist_col_info) *
2948 mdata->ndspp,
2949 GFP_KERNEL);
2950 if (hist == NULL) {
2951 pr_err("dspp histogram allocation failed!\n");
2952 ret = -ENOMEM;
2953 goto pp_exit;
2954 }
2955 for (i = 0; i < mdata->ndspp; i++) {
2956 mutex_init(&hist[i].hist_mutex);
2957 spin_lock_init(&hist[i].hist_lock);
2958 hist[i].intr_shift = (i * 4) + 12;
2959 if (pp_driver_ops.get_hist_offset) {
2960 ret = pp_driver_ops.get_hist_offset(
2961 DSPP, &ctl_off);
2962 if (ret) {
2963 pr_err("get_hist_offset ret %d\n",
2964 ret);
2965 goto hist_exit;
2966 }
2967 hist[i].base =
2968 i < mdata->ndspp ?
2969 mdss_mdp_get_dspp_addr_off(i) +
2970 ctl_off : NULL;
2971 } else {
2972 hist[i].base = i < mdata->ndspp ?
2973 mdss_mdp_get_dspp_addr_off(i) +
2974 MDSS_MDP_REG_DSPP_HIST_CTL_BASE
2975 : NULL;
2976 }
2977 }
2978 if (mdata->ndspp == 4)
2979 hist[3].intr_shift = 22;
2980
2981 mdss_pp_res->dspp_hist = hist;
2982 }
2983 }
2984 if (mdata && mdata->vig_pipes) {
2985 vig = mdata->vig_pipes;
2986 for (i = 0; i < mdata->nvig_pipes; i++) {
2987 mutex_init(&vig[i].pp_res.hist.hist_mutex);
2988 spin_lock_init(&vig[i].pp_res.hist.hist_lock);
2989 vig[i].pp_res.hist.intr_shift = (vig[i].num * 4);
2990 if (i == 3)
2991 vig[i].pp_res.hist.intr_shift = 10;
2992 if (pp_driver_ops.get_hist_offset) {
2993 ret = pp_driver_ops.get_hist_offset(
2994 SSPP_VIG, &ctl_off);
2995 if (ret) {
2996 pr_err("get_hist_offset ret %d\n",
2997 ret);
2998 goto hist_exit;
2999 }
3000 vig[i].pp_res.hist.base = vig[i].base +
3001 ctl_off;
3002 } else {
3003 vig[i].pp_res.hist.base = vig[i].base +
3004 MDSS_MDP_REG_VIG_HIST_CTL_BASE;
3005 }
3006 }
3007 }
3008 mutex_unlock(&mdss_pp_mutex);
3009 return ret;
3010hist_exit:
3011 devm_kfree(dev, hist);
3012pp_exit:
3013 devm_kfree(dev, mdss_pp_res);
3014 mutex_unlock(&mdss_pp_mutex);
3015 return ret;
3016}
3017
3018void mdss_mdp_pp_term(struct device *dev)
3019{
3020 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
3021
3022 if (mdss_pp_res) {
3023 mutex_lock(&mdss_pp_mutex);
3024 devm_kfree(dev, mdss_pp_res->dspp_hist);
3025 devm_kfree(dev, mdss_pp_res);
3026 mdss_pp_res = NULL;
3027 mutex_unlock(&mdss_pp_mutex);
3028 }
3029
3030 mdss_reg_bus_vote_client_destroy(mdata->pp_reg_bus_clt);
3031 mdata->pp_reg_bus_clt = NULL;
3032}
3033
3034int mdss_mdp_pp_overlay_init(struct msm_fb_data_type *mfd)
3035{
3036 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
3037
3038 if (!mfd || !mdata) {
3039 pr_err("Invalid mfd %pK mdata %pK\n", mfd, mdata);
3040 return -EPERM;
3041 }
3042 if (mfd->index >= (MDP_BLOCK_MAX - MDP_LOGICAL_BLOCK_DISP_0))
3043 return 0;
3044
3045 if (mdata->nad_cfgs)
3046 mfd->mdp.ad_calc_bl = pp_ad_calc_bl;
3047 mfd->mdp.pp_release_fnc = pp_mfd_release_all;
3048 return 0;
3049}
3050
3051int mdss_mdp_pp_default_overlay_config(struct msm_fb_data_type *mfd,
3052 struct mdss_panel_data *pdata,
3053 bool enable)
3054{
3055 int ret = 0;
3056
3057 if (!mfd || !pdata) {
3058 pr_err("Invalid parameters mfd %pK pdata %pK\n", mfd, pdata);
3059 return -EINVAL;
3060 }
3061
3062 ret = mdss_mdp_panel_default_dither_config(mfd, pdata->panel_info.bpp,
3063 enable);
3064 if (ret)
3065 pr_err("Unable to configure default dither on fb%d ret %d\n",
3066 mfd->index, ret);
3067
3068 if (pdata->panel_info.type == DTV_PANEL) {
3069 ret = mdss_mdp_limited_lut_igc_config(mfd, enable);
3070 if (ret)
3071 pr_err("Unable to configure DTV panel default IGC ret %d\n",
3072 ret);
3073 }
3074
3075 return ret;
3076}
3077
3078static bool pp_ad_bl_threshold_check(int al_thresh, int base, int prev_bl,
3079 int curr_bl)
3080{
3081 int bl_thresh = 0, diff = 0;
3082 bool ret = false;
3083
3084 pr_debug("al_thresh = %d, base = %d\n", al_thresh, base);
3085 if (base <= 0) {
3086 pr_debug("Invalid base for threshold calculation %d\n", base);
3087 return ret;
3088 }
3089 bl_thresh = (curr_bl * al_thresh) / (base * 4);
3090 diff = (curr_bl > prev_bl) ? (curr_bl - prev_bl) : (prev_bl - curr_bl);
3091 ret = (diff > bl_thresh) ? true : false;
3092 pr_debug("prev_bl =%d, curr_bl = %d, bl_thresh = %d, diff = %d, ret = %d\n",
3093 prev_bl, curr_bl, bl_thresh, diff, ret);
3094
3095 return ret;
3096}
3097
3098static int pp_ad_calc_bl(struct msm_fb_data_type *mfd, int bl_in, int *bl_out,
3099 bool *bl_out_notify)
3100{
3101 int ret = -1;
3102 int temp = bl_in;
3103 u32 ad_bl_out = 0;
3104 struct mdss_ad_info *ad;
3105
3106 ret = mdss_mdp_get_ad(mfd, &ad);
3107 if (ret == -ENODEV || ret == -EPERM) {
3108 pr_debug("AD not supported on device, disp num %d\n",
3109 mfd->index);
3110 return 0;
3111 } else if (ret || !ad) {
3112 pr_err("Failed to get ad info: ret = %d, ad = 0x%pK.\n",
3113 ret, ad);
3114 return ret;
3115 }
3116
3117 /* Don't update BL = 0 to AD */
3118 if (bl_in == 0)
3119 return 0;
3120 mutex_lock(&ad->lock);
3121 if (!mfd->ad_bl_level)
3122 mfd->ad_bl_level = bl_in;
3123 if (!(ad->sts & PP_STS_ENABLE)) {
3124 pr_debug("AD is not enabled.\n");
3125 mutex_unlock(&ad->lock);
3126 return -EPERM;
3127 }
3128
3129 if (!ad->bl_mfd || !ad->bl_mfd->panel_info ||
3130 !ad->bl_att_lut) {
3131 pr_err("Invalid ad info: bl_mfd = 0x%pK, ad->bl_mfd->panel_info = 0x%pK, bl_att_lut = 0x%pK\n",
3132 ad->bl_mfd,
3133 (!ad->bl_mfd) ? NULL : ad->bl_mfd->panel_info,
3134 ad->bl_att_lut);
3135 mutex_unlock(&ad->lock);
3136 return -EINVAL;
3137 }
3138
3139 ret = pp_ad_linearize_bl(ad, bl_in, &temp,
3140 MDP_PP_AD_BL_LINEAR);
3141 if (ret) {
3142 pr_err("Failed to linearize BL: %d\n", ret);
3143 mutex_unlock(&ad->lock);
3144 return ret;
3145 }
3146
3147 if (ad->init.alpha > 0) {
3148 ret = pp_ad_attenuate_bl(ad, temp, &temp);
3149 if (ret) {
3150 pr_err("Failed to attenuate BL: %d\n", ret);
3151 mutex_unlock(&ad->lock);
3152 return ret;
3153 }
3154 ad_bl_out = temp;
3155
3156 ret = pp_ad_linearize_bl(ad, temp, &temp,
3157 MDP_PP_AD_BL_LINEAR_INV);
3158 if (ret) {
3159 pr_err("Failed to inverse linearize BL: %d\n", ret);
3160 mutex_unlock(&ad->lock);
3161 return ret;
3162 }
3163 *bl_out = temp;
3164 } else {
3165 ad_bl_out = temp;
3166 }
3167
3168 if (pp_ad_bl_threshold_check(ad->init.al_thresh, ad->init.alpha_base,
3169 ad->last_bl, ad_bl_out)) {
3170 mfd->ad_bl_level = ad_bl_out;
3171 pr_debug("backlight send to AD block: %d\n", mfd->ad_bl_level);
3172 *bl_out_notify = true;
3173 pp_ad_invalidate_input(mfd);
3174 }
3175
3176 mutex_unlock(&ad->lock);
3177 return 0;
3178}
3179
3180static int pp_get_dspp_num(u32 disp_num, u32 *dspp_num)
3181{
3182 int i;
3183 u32 mixer_cnt;
3184 u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
3185 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
3186
3187 mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
3188
3189 if (!mixer_cnt || !mdata)
3190 return -EPERM;
3191
3192 /* only read the first mixer */
3193 for (i = 0; i < mixer_cnt; i++) {
3194 if (mixer_id[i] < mdata->nmixers_intf)
3195 break;
3196 }
3197 if (i >= mixer_cnt || mixer_id[i] >= mdata->ndspp)
3198 return -EPERM;
3199 *dspp_num = mixer_id[i];
3200 return 0;
3201}
3202
3203int mdss_mdp_pa_config(struct msm_fb_data_type *mfd,
3204 struct mdp_pa_cfg_data *config,
3205 u32 *copyback)
3206{
3207 int ret = 0;
3208 u32 disp_num, dspp_num = 0;
3209 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
3210 char __iomem *pa_addr;
3211
3212 if (mdata->mdp_rev >= MDSS_MDP_HW_REV_103)
3213 return -EINVAL;
3214
3215 ret = pp_validate_dspp_mfd_block(mfd, config->block);
3216 if (ret) {
3217 pr_err("Invalid block %d mfd index %d, ret %d\n",
3218 config->block,
3219 (mfd ? mfd->index : -1), ret);
3220 return ret;
3221 }
3222
3223 mutex_lock(&mdss_pp_mutex);
3224 disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
3225
3226 if (config->pa_data.flags & MDP_PP_OPS_READ) {
3227 ret = pp_get_dspp_num(disp_num, &dspp_num);
3228 if (ret) {
3229 pr_err("no dspp connects to disp %d\n",
3230 disp_num);
3231 goto pa_config_exit;
3232 }
3233 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
3234 pa_addr = mdss_mdp_get_dspp_addr_off(dspp_num) +
3235 MDSS_MDP_REG_DSPP_PA_BASE;
3236 config->pa_data.hue_adj = readl_relaxed(pa_addr);
3237 pa_addr += 4;
3238 config->pa_data.sat_adj = readl_relaxed(pa_addr);
3239 pa_addr += 4;
3240 config->pa_data.val_adj = readl_relaxed(pa_addr);
3241 pa_addr += 4;
3242 config->pa_data.cont_adj = readl_relaxed(pa_addr);
3243 *copyback = 1;
3244 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
3245 } else {
3246 mdss_pp_res->pa_disp_cfg[disp_num] = config->pa_data;
3247 mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_PA;
3248 }
3249
3250pa_config_exit:
3251 mutex_unlock(&mdss_pp_mutex);
3252 return ret;
3253}
3254
3255int mdss_mdp_pa_v2_config(struct msm_fb_data_type *mfd,
3256 struct mdp_pa_v2_cfg_data *config,
3257 u32 *copyback)
3258{
3259 int ret = 0;
3260 u32 disp_num, dspp_num = 0;
3261 char __iomem *pa_addr;
3262 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
3263 struct mdp_pa_v2_cfg_data *pa_v2_cache = NULL;
3264 struct mdp_pp_cache_res res_cache;
3265 uint32_t flags = 0;
3266
3267 if (mdata->mdp_rev < MDSS_MDP_HW_REV_103)
3268 return -EINVAL;
3269
3270 ret = pp_validate_dspp_mfd_block(mfd, config->block);
3271 if (ret) {
3272 pr_err("Invalid block %d mfd index %d, ret %d\n",
3273 config->block,
3274 (mfd ? mfd->index : -1), ret);
3275 return ret;
3276 }
3277
3278 if (pp_ops[PA].pp_set_config)
3279 flags = config->flags;
3280 else
3281 flags = config->pa_v2_data.flags;
3282
3283 if ((flags & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
3284 pr_warn("Can't set both split bits\n");
3285 return -EINVAL;
3286 }
3287
3288 mutex_lock(&mdss_pp_mutex);
3289 disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
3290
3291 if (flags & MDP_PP_OPS_READ) {
3292 ret = pp_get_dspp_num(disp_num, &dspp_num);
3293 if (ret) {
3294 pr_err("no dspp connects to disp %d\n",
3295 disp_num);
3296 goto pa_config_exit;
3297 }
3298 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
3299 pa_addr = mdss_mdp_get_dspp_addr_off(dspp_num);
3300 if (IS_ERR(pa_addr)) {
3301 ret = PTR_ERR(pa_addr);
3302 goto pa_clk_off;
3303 }
3304 if (pp_ops[PA].pp_get_config) {
3305 ret = pp_ops[PA].pp_get_config(pa_addr, config,
3306 DSPP, disp_num);
3307 if (ret)
3308 pr_err("PA get config failed %d\n", ret);
3309 } else {
3310 pa_addr += MDSS_MDP_REG_DSPP_PA_BASE;
3311 ret = pp_read_pa_v2_regs(pa_addr,
3312 &config->pa_v2_data,
3313 disp_num);
3314 if (ret)
3315 goto pa_config_exit;
3316 *copyback = 1;
3317 }
3318pa_clk_off:
3319 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
3320 } else {
3321 if (pp_ops[PA].pp_set_config) {
3322 pr_debug("version of PA is %d\n", config->version);
3323 res_cache.block = DSPP;
3324 res_cache.mdss_pp_res = mdss_pp_res;
3325 res_cache.pipe_res = NULL;
3326 ret = pp_pa_cache_params(config, &res_cache);
3327 if (ret) {
3328 pr_err("PA config failed version %d ret %d\n",
3329 config->version, ret);
3330 ret = -EFAULT;
3331 goto pa_config_exit;
3332 }
3333 } else {
3334 if (flags & MDP_PP_PA_SIX_ZONE_ENABLE) {
3335 ret = pp_copy_pa_six_zone_lut(config, disp_num);
3336 if (ret) {
3337 pr_err("PA copy six zone lut failed ret %d\n",
3338 ret);
3339 goto pa_config_exit;
3340 }
3341 }
3342 pa_v2_cache = &mdss_pp_res->pa_v2_disp_cfg[disp_num];
3343 *pa_v2_cache = *config;
3344 pa_v2_cache->pa_v2_data.six_zone_curve_p0 =
3345 mdss_pp_res->six_zone_lut_curve_p0[disp_num];
3346 pa_v2_cache->pa_v2_data.six_zone_curve_p1 =
3347 mdss_pp_res->six_zone_lut_curve_p1[disp_num];
3348 }
3349 mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_PA;
3350 }
3351
3352pa_config_exit:
3353 mutex_unlock(&mdss_pp_mutex);
3354 return ret;
3355}
3356
3357
3358static int pp_read_pa_v2_regs(char __iomem *addr,
3359 struct mdp_pa_v2_data *pa_v2_config,
3360 u32 disp_num)
3361{
3362 int i;
3363 u32 data;
3364
3365 if (pa_v2_config->flags & MDP_PP_PA_HUE_ENABLE)
3366 pa_v2_config->global_hue_adj = readl_relaxed(addr);
3367 addr += 4;
3368 if (pa_v2_config->flags & MDP_PP_PA_SAT_ENABLE)
3369 pa_v2_config->global_sat_adj = readl_relaxed(addr);
3370 addr += 4;
3371 if (pa_v2_config->flags & MDP_PP_PA_VAL_ENABLE)
3372 pa_v2_config->global_val_adj = readl_relaxed(addr);
3373 addr += 4;
3374 if (pa_v2_config->flags & MDP_PP_PA_CONT_ENABLE)
3375 pa_v2_config->global_cont_adj = readl_relaxed(addr);
3376 addr += 4;
3377
3378 /* Six zone LUT and thresh data */
3379 if (pa_v2_config->flags & MDP_PP_PA_SIX_ZONE_ENABLE) {
3380 if (pa_v2_config->six_zone_len != MDP_SIX_ZONE_LUT_SIZE)
3381 return -EINVAL;
3382
3383 data = (3 << 25);
3384 writel_relaxed(data, addr);
3385
3386 for (i = 0; i < MDP_SIX_ZONE_LUT_SIZE; i++) {
3387 addr += 4;
3388 mdss_pp_res->six_zone_lut_curve_p1[disp_num][i] =
3389 readl_relaxed(addr);
3390 addr -= 4;
3391 mdss_pp_res->six_zone_lut_curve_p0[disp_num][i] =
3392 readl_relaxed(addr) & 0xFFF;
3393 }
3394
3395 if (copy_to_user(pa_v2_config->six_zone_curve_p0,
3396 &mdss_pp_res->six_zone_lut_curve_p0[disp_num][0],
3397 pa_v2_config->six_zone_len * sizeof(u32))) {
3398 return -EFAULT;
3399 }
3400
3401 if (copy_to_user(pa_v2_config->six_zone_curve_p1,
3402 &mdss_pp_res->six_zone_lut_curve_p1[disp_num][0],
3403 pa_v2_config->six_zone_len * sizeof(u32))) {
3404 return -EFAULT;
3405 }
3406
3407 addr += 8;
3408 pa_v2_config->six_zone_thresh = readl_relaxed(addr);
3409 addr += 4;
3410 } else {
3411 addr += 12;
3412 }
3413
3414 /* Skin memory color config registers */
3415 if (pa_v2_config->flags & MDP_PP_PA_SKIN_ENABLE)
3416 pp_read_pa_mem_col_regs(addr, &pa_v2_config->skin_cfg);
3417
3418 addr += 0x14;
3419 /* Sky memory color config registers */
3420 if (pa_v2_config->flags & MDP_PP_PA_SKY_ENABLE)
3421 pp_read_pa_mem_col_regs(addr, &pa_v2_config->sky_cfg);
3422
3423 addr += 0x14;
3424 /* Foliage memory color config registers */
3425 if (pa_v2_config->flags & MDP_PP_PA_FOL_ENABLE)
3426 pp_read_pa_mem_col_regs(addr, &pa_v2_config->fol_cfg);
3427
3428 return 0;
3429}
3430
3431static void pp_read_pa_mem_col_regs(char __iomem *addr,
3432 struct mdp_pa_mem_col_cfg *mem_col_cfg)
3433{
3434 mem_col_cfg->color_adjust_p0 = readl_relaxed(addr);
3435 addr += 4;
3436 mem_col_cfg->color_adjust_p1 = readl_relaxed(addr);
3437 addr += 4;
3438 mem_col_cfg->hue_region = readl_relaxed(addr);
3439 addr += 4;
3440 mem_col_cfg->sat_region = readl_relaxed(addr);
3441 addr += 4;
3442 mem_col_cfg->val_region = readl_relaxed(addr);
3443}
3444
3445static int pp_copy_pa_six_zone_lut(struct mdp_pa_v2_cfg_data *pa_v2_config,
3446 u32 disp_num)
3447{
3448 if (pa_v2_config->pa_v2_data.six_zone_len != MDP_SIX_ZONE_LUT_SIZE)
3449 return -EINVAL;
3450
3451 if (copy_from_user(&mdss_pp_res->six_zone_lut_curve_p0[disp_num][0],
3452 pa_v2_config->pa_v2_data.six_zone_curve_p0,
3453 pa_v2_config->pa_v2_data.six_zone_len * sizeof(u32))) {
3454 return -EFAULT;
3455 }
3456 if (copy_from_user(&mdss_pp_res->six_zone_lut_curve_p1[disp_num][0],
3457 pa_v2_config->pa_v2_data.six_zone_curve_p1,
3458 pa_v2_config->pa_v2_data.six_zone_len * sizeof(u32))) {
3459 return -EFAULT;
3460 }
3461
3462 return 0;
3463}
3464
3465static void pp_read_pcc_regs(char __iomem *addr,
3466 struct mdp_pcc_cfg_data *cfg_ptr)
3467{
3468 cfg_ptr->r.c = readl_relaxed(addr);
3469 cfg_ptr->g.c = readl_relaxed(addr + 4);
3470 cfg_ptr->b.c = readl_relaxed(addr + 8);
3471 addr += 0x10;
3472
3473 cfg_ptr->r.r = readl_relaxed(addr);
3474 cfg_ptr->g.r = readl_relaxed(addr + 4);
3475 cfg_ptr->b.r = readl_relaxed(addr + 8);
3476 addr += 0x10;
3477
3478 cfg_ptr->r.g = readl_relaxed(addr);
3479 cfg_ptr->g.g = readl_relaxed(addr + 4);
3480 cfg_ptr->b.g = readl_relaxed(addr + 8);
3481 addr += 0x10;
3482
3483 cfg_ptr->r.b = readl_relaxed(addr);
3484 cfg_ptr->g.b = readl_relaxed(addr + 4);
3485 cfg_ptr->b.b = readl_relaxed(addr + 8);
3486 addr += 0x10;
3487
3488 cfg_ptr->r.rr = readl_relaxed(addr);
3489 cfg_ptr->g.rr = readl_relaxed(addr + 4);
3490 cfg_ptr->b.rr = readl_relaxed(addr + 8);
3491 addr += 0x10;
3492
3493 cfg_ptr->r.rg = readl_relaxed(addr);
3494 cfg_ptr->g.rg = readl_relaxed(addr + 4);
3495 cfg_ptr->b.rg = readl_relaxed(addr + 8);
3496 addr += 0x10;
3497
3498 cfg_ptr->r.rb = readl_relaxed(addr);
3499 cfg_ptr->g.rb = readl_relaxed(addr + 4);
3500 cfg_ptr->b.rb = readl_relaxed(addr + 8);
3501 addr += 0x10;
3502
3503 cfg_ptr->r.gg = readl_relaxed(addr);
3504 cfg_ptr->g.gg = readl_relaxed(addr + 4);
3505 cfg_ptr->b.gg = readl_relaxed(addr + 8);
3506 addr += 0x10;
3507
3508 cfg_ptr->r.gb = readl_relaxed(addr);
3509 cfg_ptr->g.gb = readl_relaxed(addr + 4);
3510 cfg_ptr->b.gb = readl_relaxed(addr + 8);
3511 addr += 0x10;
3512
3513 cfg_ptr->r.bb = readl_relaxed(addr);
3514 cfg_ptr->g.bb = readl_relaxed(addr + 4);
3515 cfg_ptr->b.bb = readl_relaxed(addr + 8);
3516 addr += 0x10;
3517
3518 cfg_ptr->r.rgb_0 = readl_relaxed(addr);
3519 cfg_ptr->g.rgb_0 = readl_relaxed(addr + 4);
3520 cfg_ptr->b.rgb_0 = readl_relaxed(addr + 8);
3521 addr += 0x10;
3522
3523 cfg_ptr->r.rgb_1 = readl_relaxed(addr);
3524 cfg_ptr->g.rgb_1 = readl_relaxed(addr + 4);
3525 cfg_ptr->b.rgb_1 = readl_relaxed(addr + 8);
3526}
3527
3528static void pp_update_pcc_regs(char __iomem *addr,
3529 struct mdp_pcc_cfg_data *cfg_ptr)
3530{
3531 writel_relaxed(cfg_ptr->r.c, addr);
3532 writel_relaxed(cfg_ptr->g.c, addr + 4);
3533 writel_relaxed(cfg_ptr->b.c, addr + 8);
3534 addr += 0x10;
3535
3536 writel_relaxed(cfg_ptr->r.r, addr);
3537 writel_relaxed(cfg_ptr->g.r, addr + 4);
3538 writel_relaxed(cfg_ptr->b.r, addr + 8);
3539 addr += 0x10;
3540
3541 writel_relaxed(cfg_ptr->r.g, addr);
3542 writel_relaxed(cfg_ptr->g.g, addr + 4);
3543 writel_relaxed(cfg_ptr->b.g, addr + 8);
3544 addr += 0x10;
3545
3546 writel_relaxed(cfg_ptr->r.b, addr);
3547 writel_relaxed(cfg_ptr->g.b, addr + 4);
3548 writel_relaxed(cfg_ptr->b.b, addr + 8);
3549 addr += 0x10;
3550
3551 writel_relaxed(cfg_ptr->r.rr, addr);
3552 writel_relaxed(cfg_ptr->g.rr, addr + 4);
3553 writel_relaxed(cfg_ptr->b.rr, addr + 8);
3554 addr += 0x10;
3555
3556 writel_relaxed(cfg_ptr->r.rg, addr);
3557 writel_relaxed(cfg_ptr->g.rg, addr + 4);
3558 writel_relaxed(cfg_ptr->b.rg, addr + 8);
3559 addr += 0x10;
3560
3561 writel_relaxed(cfg_ptr->r.rb, addr);
3562 writel_relaxed(cfg_ptr->g.rb, addr + 4);
3563 writel_relaxed(cfg_ptr->b.rb, addr + 8);
3564 addr += 0x10;
3565
3566 writel_relaxed(cfg_ptr->r.gg, addr);
3567 writel_relaxed(cfg_ptr->g.gg, addr + 4);
3568 writel_relaxed(cfg_ptr->b.gg, addr + 8);
3569 addr += 0x10;
3570
3571 writel_relaxed(cfg_ptr->r.gb, addr);
3572 writel_relaxed(cfg_ptr->g.gb, addr + 4);
3573 writel_relaxed(cfg_ptr->b.gb, addr + 8);
3574 addr += 0x10;
3575
3576 writel_relaxed(cfg_ptr->r.bb, addr);
3577 writel_relaxed(cfg_ptr->g.bb, addr + 4);
3578 writel_relaxed(cfg_ptr->b.bb, addr + 8);
3579 addr += 0x10;
3580
3581 writel_relaxed(cfg_ptr->r.rgb_0, addr);
3582 writel_relaxed(cfg_ptr->g.rgb_0, addr + 4);
3583 writel_relaxed(cfg_ptr->b.rgb_0, addr + 8);
3584 addr += 0x10;
3585
3586 writel_relaxed(cfg_ptr->r.rgb_1, addr);
3587 writel_relaxed(cfg_ptr->g.rgb_1, addr + 4);
3588 writel_relaxed(cfg_ptr->b.rgb_1, addr + 8);
3589}
3590
3591int mdss_mdp_pcc_config(struct msm_fb_data_type *mfd,
3592 struct mdp_pcc_cfg_data *config,
3593 u32 *copyback)
3594{
3595 int ret = 0;
3596 u32 disp_num, dspp_num = 0;
3597 char __iomem *addr;
3598 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
3599 struct mdp_pp_cache_res res_cache;
3600
3601 ret = pp_validate_dspp_mfd_block(mfd, config->block);
3602 if (ret) {
3603 pr_err("Invalid block %d mfd index %d, ret %d\n",
3604 config->block,
3605 (mfd ? mfd->index : -1), ret);
3606 return ret;
3607 }
3608
3609 if ((config->ops & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
3610 pr_warn("Can't set both split bits\n");
3611 return -EINVAL;
3612 }
3613
3614 mutex_lock(&mdss_pp_mutex);
3615 disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
3616
3617 if (config->ops & MDP_PP_OPS_READ) {
3618 ret = pp_get_dspp_num(disp_num, &dspp_num);
3619 if (ret) {
3620 pr_err("%s, no dspp connects to disp %d\n",
3621 __func__, disp_num);
3622 goto pcc_config_exit;
3623 }
3624
3625 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
3626 if (pp_ops[PCC].pp_get_config) {
3627 addr = mdss_mdp_get_dspp_addr_off(disp_num);
3628 if (IS_ERR_OR_NULL(addr)) {
3629 pr_err("invalid dspp base_addr %pK\n",
3630 addr);
3631 ret = -EINVAL;
3632 goto pcc_clk_off;
3633 }
3634 if (mdata->pp_block_off.dspp_pcc_off == U32_MAX) {
3635 pr_err("invalid pcc params off %d\n",
3636 mdata->pp_block_off.dspp_pcc_off);
3637 ret = -EINVAL;
3638 goto pcc_clk_off;
3639 }
3640 addr += mdata->pp_block_off.dspp_pcc_off;
3641 ret = pp_ops[PCC].pp_get_config(addr, config,
3642 DSPP, disp_num);
3643 if (ret)
3644 pr_err("pcc get config failed %d\n", ret);
3645 goto pcc_clk_off;
3646 }
3647
3648 addr = mdss_mdp_get_dspp_addr_off(dspp_num) +
3649 MDSS_MDP_REG_DSPP_PCC_BASE;
3650 pp_read_pcc_regs(addr, config);
3651 *copyback = 1;
3652pcc_clk_off:
3653 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
3654 } else {
3655 if (pp_ops[PCC].pp_set_config) {
3656 pr_debug("version of pcc is %d\n", config->version);
3657 res_cache.block = DSPP;
3658 res_cache.mdss_pp_res = mdss_pp_res;
3659 res_cache.pipe_res = NULL;
3660 ret = pp_pcc_cache_params(config, &res_cache);
3661 if (ret) {
3662 pr_err("pcc config failed version %d ret %d\n",
3663 config->version, ret);
3664 ret = -EFAULT;
3665 goto pcc_config_exit;
3666 } else
3667 goto pcc_set_dirty;
3668 }
3669 mdss_pp_res->pcc_disp_cfg[disp_num] = *config;
3670pcc_set_dirty:
3671 mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_PCC;
3672 }
3673
3674pcc_config_exit:
3675 mutex_unlock(&mdss_pp_mutex);
3676 return ret;
3677}
3678
3679static void pp_read_igc_lut_cached(struct mdp_igc_lut_data *cfg)
3680{
3681 int i;
3682 u32 disp_num;
3683
3684 disp_num = cfg->block - MDP_LOGICAL_BLOCK_DISP_0;
3685 for (i = 0; i < IGC_LUT_ENTRIES; i++) {
3686 cfg->c0_c1_data[i] =
3687 mdss_pp_res->igc_disp_cfg[disp_num].c0_c1_data[i];
3688 cfg->c2_data[i] =
3689 mdss_pp_res->igc_disp_cfg[disp_num].c2_data[i];
3690 }
3691}
3692
3693static void pp_read_igc_lut(struct mdp_igc_lut_data *cfg,
3694 char __iomem *addr, u32 blk_idx, int32_t total_idx)
3695{
3696 int i;
3697 u32 data;
3698 int32_t mask = 0, idx = total_idx;
3699
3700 while (idx > 0) {
3701 mask = (mask << 1) + 1;
3702 idx--;
3703 }
3704 /* INDEX_UPDATE & VALUE_UPDATEN */
3705 data = (3 << 24) | (((~(1 << blk_idx)) & mask) << 28);
3706 writel_relaxed(data, addr);
3707
3708 for (i = 0; i < cfg->len; i++)
3709 cfg->c0_c1_data[i] = readl_relaxed(addr) & 0xFFF;
3710
3711 addr += 0x4;
3712 writel_relaxed(data, addr);
3713 for (i = 0; i < cfg->len; i++)
3714 cfg->c0_c1_data[i] |= (readl_relaxed(addr) & 0xFFF) << 16;
3715
3716 addr += 0x4;
3717 writel_relaxed(data, addr);
3718 for (i = 0; i < cfg->len; i++)
3719 cfg->c2_data[i] = readl_relaxed(addr) & 0xFFF;
3720}
3721
3722static void pp_update_igc_lut(struct mdp_igc_lut_data *cfg,
3723 char __iomem *addr, u32 blk_idx,
3724 u32 total_idx)
3725{
3726 int i;
3727 u32 data;
3728 int32_t mask = 0, idx = total_idx;
3729
3730 while (idx > 0) {
3731 mask = (mask << 1) + 1;
3732 idx--;
3733 }
3734
3735 /* INDEX_UPDATE */
3736 data = (1 << 25) | (((~(1 << blk_idx)) & mask) << 28);
3737 writel_relaxed((cfg->c0_c1_data[0] & 0xFFF) | data, addr);
3738
3739 /* disable index update */
3740 data &= ~(1 << 25);
3741 for (i = 1; i < cfg->len; i++)
3742 writel_relaxed((cfg->c0_c1_data[i] & 0xFFF) | data, addr);
3743
3744 addr += 0x4;
3745 data |= (1 << 25);
3746 writel_relaxed(((cfg->c0_c1_data[0] >> 16) & 0xFFF) | data, addr);
3747 data &= ~(1 << 25);
3748 for (i = 1; i < cfg->len; i++)
3749 writel_relaxed(((cfg->c0_c1_data[i] >> 16) & 0xFFF) | data,
3750 addr);
3751
3752 addr += 0x4;
3753 data |= (1 << 25);
3754 writel_relaxed((cfg->c2_data[0] & 0xFFF) | data, addr);
3755 data &= ~(1 << 25);
3756 for (i = 1; i < cfg->len; i++)
3757 writel_relaxed((cfg->c2_data[i] & 0xFFF) | data, addr);
3758}
3759
3760static int mdss_mdp_limited_lut_igc_config(struct msm_fb_data_type *mfd,
3761 bool enable)
3762{
3763 int ret = 0;
3764 u32 copyback = 0;
3765 u32 copy_from_kernel = 1;
3766 struct mdp_igc_lut_data config;
3767 struct mdp_pp_feature_version igc_version = {
3768 .pp_feature = IGC,
3769 };
3770 struct mdp_igc_lut_data_v1_7 igc_data;
3771
3772 if (!mfd)
3773 return -EINVAL;
3774
3775 if (!mdss_mdp_mfd_valid_dspp(mfd)) {
3776 pr_debug("IGC not supported on display num %d hw configuration\n",
3777 mfd->index);
3778 return 0;
3779 }
3780
3781 ret = mdss_mdp_pp_get_version(&igc_version);
3782 if (ret)
3783 pr_err("failed to get default IGC version, ret %d\n", ret);
3784
3785 config.version = igc_version.version_info;
3786 if (enable)
3787 config.ops = MDP_PP_OPS_WRITE | MDP_PP_OPS_ENABLE;
3788 else
3789 config.ops = MDP_PP_OPS_DISABLE;
3790 config.block = (mfd->index) + MDP_LOGICAL_BLOCK_DISP_0;
3791 switch (config.version) {
3792 case mdp_igc_v1_7:
3793 config.cfg_payload = &igc_data;
3794 igc_data.table_fmt = mdp_igc_custom;
3795 igc_data.len = IGC_LUT_ENTRIES;
3796 igc_data.c0_c1_data = igc_limited;
3797 igc_data.c2_data = igc_limited;
3798 break;
3799 case mdp_pp_legacy:
3800 default:
3801 config.cfg_payload = NULL;
3802 config.len = IGC_LUT_ENTRIES;
3803 config.c0_c1_data = igc_limited;
3804 config.c2_data = igc_limited;
3805 break;
3806 }
3807
3808 ret = mdss_mdp_igc_lut_config(mfd, &config, &copyback,
3809 copy_from_kernel);
3810 return ret;
3811}
3812
3813int mdss_mdp_igc_lut_config(struct msm_fb_data_type *mfd,
3814 struct mdp_igc_lut_data *config,
3815 u32 *copyback, u32 copy_from_kernel)
3816{
3817 int ret = 0;
3818 u32 tbl_idx, disp_num, dspp_num = 0;
3819 struct mdp_igc_lut_data local_cfg;
3820 char __iomem *igc_addr;
3821 struct mdp_pp_cache_res res_cache;
3822 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
3823
3824 ret = pp_validate_dspp_mfd_block(mfd, config->block);
3825 if (ret) {
3826 pr_err("Invalid block %d mfd index %d, ret %d\n",
3827 config->block,
3828 (mfd ? mfd->index : -1), ret);
3829 return ret;
3830 }
3831
3832 if ((config->ops & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
3833 pr_warn("Can't set both split bits\n");
3834 return -EINVAL;
3835 }
3836
3837 mutex_lock(&mdss_pp_mutex);
3838 disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
3839
3840 if (config->ops & MDP_PP_OPS_READ) {
3841 if (config->len != IGC_LUT_ENTRIES) {
3842 pr_err("invalid len for IGC table for read %d\n",
3843 config->len);
3844 return -EINVAL;
3845 }
3846 ret = pp_get_dspp_num(disp_num, &dspp_num);
3847 if (ret) {
3848 pr_err("%s, no dspp connects to disp %d\n",
3849 __func__, disp_num);
3850 goto igc_config_exit;
3851 }
3852 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
3853 if (config->ops & MDP_PP_IGC_FLAG_ROM0)
3854 tbl_idx = 1;
3855 else if (config->ops & MDP_PP_IGC_FLAG_ROM1)
3856 tbl_idx = 2;
3857 else
3858 tbl_idx = 0;
3859 igc_addr = mdata->mdp_base + MDSS_MDP_REG_IGC_DSPP_BASE +
3860 (0x10 * tbl_idx);
3861 local_cfg = *config;
3862 local_cfg.c0_c1_data =
3863 &mdss_pp_res->igc_lut_c0c1[disp_num][0];
3864 local_cfg.c2_data =
3865 &mdss_pp_res->igc_lut_c2[disp_num][0];
3866 if (mdata->has_no_lut_read)
3867 pp_read_igc_lut_cached(&local_cfg);
3868 else {
3869 if (pp_ops[IGC].pp_get_config) {
3870 config->block = dspp_num;
3871 pp_ops[IGC].pp_get_config(igc_addr, config,
3872 DSPP, disp_num);
3873 goto clock_off;
3874 } else {
3875 pp_read_igc_lut(&local_cfg, igc_addr,
3876 dspp_num, mdata->ndspp);
3877 }
3878 }
3879 if (copy_to_user(config->c0_c1_data, local_cfg.c0_c1_data,
3880 config->len * sizeof(u32))) {
3881 ret = -EFAULT;
3882 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
3883 goto igc_config_exit;
3884 }
3885 if (copy_to_user(config->c2_data, local_cfg.c2_data,
3886 config->len * sizeof(u32))) {
3887 ret = -EFAULT;
3888 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
3889 goto igc_config_exit;
3890 }
3891 *copyback = 1;
3892clock_off:
3893 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
3894 } else {
3895 if (pp_ops[IGC].pp_set_config) {
3896 res_cache.block = DSPP;
3897 res_cache.mdss_pp_res = mdss_pp_res;
3898 res_cache.pipe_res = NULL;
3899 ret = pp_igc_lut_cache_params(config,
3900 &res_cache, copy_from_kernel);
3901 if (ret) {
3902 pr_err("igc caching failed ret %d", ret);
3903 goto igc_config_exit;
3904 } else
3905 goto igc_set_dirty;
3906 }
3907 if (config->len != IGC_LUT_ENTRIES) {
3908 pr_err("invalid len for IGC table for write %d\n",
3909 config->len);
3910 return -EINVAL;
3911 }
3912 if (copy_from_kernel) {
3913 memcpy(&mdss_pp_res->igc_lut_c0c1[disp_num][0],
3914 config->c0_c1_data, config->len * sizeof(u32));
3915 memcpy(&mdss_pp_res->igc_lut_c2[disp_num][0],
3916 config->c2_data, config->len * sizeof(u32));
3917 } else {
3918 if (copy_from_user(
3919 &mdss_pp_res->igc_lut_c0c1[disp_num][0],
3920 config->c0_c1_data,
3921 config->len * sizeof(u32))) {
3922 ret = -EFAULT;
3923 goto igc_config_exit;
3924 }
3925 if (copy_from_user(
3926 &mdss_pp_res->igc_lut_c2[disp_num][0],
3927 config->c2_data, config->len * sizeof(u32))) {
3928 ret = -EFAULT;
3929 goto igc_config_exit;
3930 }
3931 }
3932 mdss_pp_res->igc_disp_cfg[disp_num] = *config;
3933 mdss_pp_res->igc_disp_cfg[disp_num].c0_c1_data =
3934 &mdss_pp_res->igc_lut_c0c1[disp_num][0];
3935 mdss_pp_res->igc_disp_cfg[disp_num].c2_data =
3936 &mdss_pp_res->igc_lut_c2[disp_num][0];
3937igc_set_dirty:
3938 mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_IGC;
3939 }
3940
3941igc_config_exit:
3942 mutex_unlock(&mdss_pp_mutex);
3943 return ret;
3944}
3945static void pp_update_gc_one_lut(char __iomem *addr,
3946 struct mdp_ar_gc_lut_data *lut_data,
3947 uint8_t num_stages)
3948{
3949 int i, start_idx, idx;
3950
3951 start_idx = ((readl_relaxed(addr) >> 16) & 0xF) + 1;
3952 for (i = start_idx; i < GC_LUT_SEGMENTS; i++) {
3953 idx = min((uint8_t)i, (uint8_t)(num_stages-1));
3954 writel_relaxed(lut_data[idx].x_start, addr);
3955 }
3956 for (i = 0; i < start_idx; i++) {
3957 idx = min((uint8_t)i, (uint8_t)(num_stages-1));
3958 writel_relaxed(lut_data[idx].x_start, addr);
3959 }
3960 addr += 4;
3961 start_idx = ((readl_relaxed(addr) >> 16) & 0xF) + 1;
3962 for (i = start_idx; i < GC_LUT_SEGMENTS; i++) {
3963 idx = min((uint8_t)i, (uint8_t)(num_stages-1));
3964 writel_relaxed(lut_data[idx].slope, addr);
3965 }
3966 for (i = 0; i < start_idx; i++) {
3967 idx = min((uint8_t)i, (uint8_t)(num_stages-1));
3968 writel_relaxed(lut_data[idx].slope, addr);
3969 }
3970 addr += 4;
3971 start_idx = ((readl_relaxed(addr) >> 16) & 0xF) + 1;
3972 for (i = start_idx; i < GC_LUT_SEGMENTS; i++) {
3973 idx = min((uint8_t)i, (uint8_t)(num_stages-1));
3974 writel_relaxed(lut_data[idx].offset, addr);
3975 }
3976 for (i = 0; i < start_idx; i++) {
3977 idx = min((uint8_t)i, (uint8_t)(num_stages-1));
3978 writel_relaxed(lut_data[idx].offset, addr);
3979 }
3980}
3981static void pp_update_argc_lut(char __iomem *addr,
3982 struct mdp_pgc_lut_data *config)
3983{
3984 pp_update_gc_one_lut(addr, config->r_data, config->num_r_stages);
3985 addr += 0x10;
3986 pp_update_gc_one_lut(addr, config->g_data, config->num_g_stages);
3987 addr += 0x10;
3988 pp_update_gc_one_lut(addr, config->b_data, config->num_b_stages);
3989}
3990static void pp_read_gc_one_lut(char __iomem *addr,
3991 struct mdp_ar_gc_lut_data *gc_data)
3992{
3993 int i, start_idx, data;
3994
3995 data = readl_relaxed(addr);
3996 start_idx = (data >> 16) & 0xF;
3997 gc_data[start_idx].x_start = data & 0xFFF;
3998
3999 for (i = start_idx + 1; i < GC_LUT_SEGMENTS; i++) {
4000 data = readl_relaxed(addr);
4001 gc_data[i].x_start = data & 0xFFF;
4002 }
4003 for (i = 0; i < start_idx; i++) {
4004 data = readl_relaxed(addr);
4005 gc_data[i].x_start = data & 0xFFF;
4006 }
4007
4008 addr += 4;
4009 data = readl_relaxed(addr);
4010 start_idx = (data >> 16) & 0xF;
4011 gc_data[start_idx].slope = data & 0x7FFF;
4012 for (i = start_idx + 1; i < GC_LUT_SEGMENTS; i++) {
4013 data = readl_relaxed(addr);
4014 gc_data[i].slope = data & 0x7FFF;
4015 }
4016 for (i = 0; i < start_idx; i++) {
4017 data = readl_relaxed(addr);
4018 gc_data[i].slope = data & 0x7FFF;
4019 }
4020 addr += 4;
4021 data = readl_relaxed(addr);
4022 start_idx = (data >> 16) & 0xF;
4023 gc_data[start_idx].offset = data & 0x7FFF;
4024 for (i = start_idx + 1; i < GC_LUT_SEGMENTS; i++) {
4025 data = readl_relaxed(addr);
4026 gc_data[i].offset = data & 0x7FFF;
4027 }
4028 for (i = 0; i < start_idx; i++) {
4029 data = readl_relaxed(addr);
4030 gc_data[i].offset = data & 0x7FFF;
4031 }
4032}
4033
4034static int pp_read_argc_lut(struct mdp_pgc_lut_data *config, char __iomem *addr)
4035{
4036 int ret = 0;
4037
4038 pp_read_gc_one_lut(addr, config->r_data);
4039 addr += 0x10;
4040 pp_read_gc_one_lut(addr, config->g_data);
4041 addr += 0x10;
4042 pp_read_gc_one_lut(addr, config->b_data);
4043 return ret;
4044}
4045
4046static int pp_read_argc_lut_cached(struct mdp_pgc_lut_data *config)
4047{
4048 int i;
4049 u32 disp_num;
4050 struct mdp_pgc_lut_data *pgc_ptr;
4051
4052 disp_num = PP_BLOCK(config->block) - MDP_LOGICAL_BLOCK_DISP_0;
4053 switch (PP_LOCAT(config->block)) {
4054 case MDSS_PP_LM_CFG:
4055 pgc_ptr = &mdss_pp_res->argc_disp_cfg[disp_num];
4056 break;
4057 case MDSS_PP_DSPP_CFG:
4058 pgc_ptr = &mdss_pp_res->pgc_disp_cfg[disp_num];
4059 break;
4060 default:
4061 return -EINVAL;
4062 }
4063
4064 for (i = 0; i < GC_LUT_SEGMENTS; i++) {
4065 config->r_data[i].x_start = pgc_ptr->r_data[i].x_start;
4066 config->r_data[i].slope = pgc_ptr->r_data[i].slope;
4067 config->r_data[i].offset = pgc_ptr->r_data[i].offset;
4068
4069 config->g_data[i].x_start = pgc_ptr->g_data[i].x_start;
4070 config->g_data[i].slope = pgc_ptr->g_data[i].slope;
4071 config->g_data[i].offset = pgc_ptr->g_data[i].offset;
4072
4073 config->b_data[i].x_start = pgc_ptr->b_data[i].x_start;
4074 config->b_data[i].slope = pgc_ptr->b_data[i].slope;
4075 config->b_data[i].offset = pgc_ptr->b_data[i].offset;
4076 }
4077
4078 return 0;
4079}
4080
4081/* Note: Assumes that its inputs have been checked by calling function */
4082static void pp_update_hist_lut(char __iomem *addr,
4083 struct mdp_hist_lut_data *cfg)
4084{
4085 int i;
4086
4087 for (i = 0; i < ENHIST_LUT_ENTRIES; i++)
4088 writel_relaxed(cfg->data[i], addr);
4089 /* swap */
4090 if (PP_LOCAT(cfg->block) == MDSS_PP_DSPP_CFG)
4091 writel_relaxed(1, addr + 4);
4092 else
4093 writel_relaxed(1, addr + 16);
4094}
4095
4096int mdss_mdp_argc_config(struct msm_fb_data_type *mfd,
4097 struct mdp_pgc_lut_data *config,
4098 u32 *copyback)
4099{
4100 int ret = 0;
4101 u32 disp_num, num = 0, is_lm = 0;
4102 struct mdp_pgc_lut_data local_cfg;
4103 struct mdp_pgc_lut_data *pgc_ptr;
4104 u32 tbl_size, r_size, g_size, b_size;
4105 char __iomem *argc_addr = 0;
4106 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
4107 struct mdss_mdp_ctl *ctl = NULL;
4108 u32 dirty_flag = 0;
4109
4110 if ((PP_BLOCK(config->block) < MDP_LOGICAL_BLOCK_DISP_0) ||
4111 (PP_BLOCK(config->block) >= MDP_BLOCK_MAX)) {
4112 pr_err("invalid block value %d\n", PP_BLOCK(config->block));
4113 return -EINVAL;
4114 }
4115
4116 if ((config->flags & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
4117 pr_warn("Can't set both split bits\n");
4118 return -EINVAL;
4119 }
4120
4121 if ((PP_BLOCK(config->block) - MDP_LOGICAL_BLOCK_DISP_0) !=
4122 mfd->index) {
4123 pr_err("PP block %d does not match corresponding mfd index %d\n",
4124 config->block, mfd->index);
4125 return -EINVAL;
4126 }
4127
4128 disp_num = PP_BLOCK(config->block) - MDP_LOGICAL_BLOCK_DISP_0;
4129 ctl = mfd_to_ctl(mfd);
4130 num = (ctl && ctl->mixer_left) ? ctl->mixer_left->num : -1;
4131 if (num < 0) {
4132 pr_err("invalid mfd index %d config\n",
4133 mfd->index);
4134 return -EPERM;
4135 }
4136 switch (PP_LOCAT(config->block)) {
4137 case MDSS_PP_LM_CFG:
4138 /*
4139 * LM GC LUT should be disabled before being rewritten. Skip
4140 * GC LUT config if it is already enabled.
4141 */
4142 if ((mdss_pp_res->pp_disp_sts[disp_num].argc_sts &
4143 PP_STS_ENABLE) &&
4144 !(config->flags & MDP_PP_OPS_DISABLE)) {
4145 pr_err("LM GC already enabled disp %d, skipping config\n",
4146 mfd->index);
4147 return -EPERM;
4148 }
4149 argc_addr = mdss_mdp_get_mixer_addr_off(num) +
4150 MDSS_MDP_REG_LM_GC_LUT_BASE;
4151 pgc_ptr = &mdss_pp_res->argc_disp_cfg[disp_num];
4152 dirty_flag = PP_FLAGS_DIRTY_ARGC;
4153 break;
4154 case MDSS_PP_DSPP_CFG:
4155 if (!mdss_mdp_mfd_valid_dspp(mfd)) {
4156 pr_err("invalid mfd index %d for dspp config\n",
4157 mfd->index);
4158 return -EPERM;
4159 }
4160 argc_addr = mdss_mdp_get_dspp_addr_off(num) +
4161 MDSS_MDP_REG_DSPP_GC_BASE;
4162 pgc_ptr = &mdss_pp_res->pgc_disp_cfg[disp_num];
4163 dirty_flag = PP_FLAGS_DIRTY_PGC;
4164 break;
4165 default:
4166 goto argc_config_exit;
4167 }
4168
4169 mutex_lock(&mdss_pp_mutex);
4170
4171 tbl_size = GC_LUT_SEGMENTS * sizeof(struct mdp_ar_gc_lut_data);
4172 if (config->flags & MDP_PP_OPS_READ) {
4173 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
4174 if (pp_ops[GC].pp_get_config) {
4175 char __iomem *temp_addr = NULL;
4176 u32 off = 0;
4177
4178 is_lm = (PP_LOCAT(config->block) == MDSS_PP_LM_CFG);
4179 off = (is_lm) ? mdata->pp_block_off.lm_pgc_off :
4180 mdata->pp_block_off.dspp_pgc_off;
4181 if (off == U32_MAX) {
4182 pr_err("invalid offset for loc %d off %d\n",
4183 PP_LOCAT(config->block), U32_MAX);
4184 ret = -EINVAL;
4185 goto clock_off;
4186 }
4187 temp_addr = (is_lm) ?
4188 mdss_mdp_get_mixer_addr_off(num) :
4189 mdss_mdp_get_dspp_addr_off(num);
4190 if (IS_ERR_OR_NULL(temp_addr)) {
4191 pr_err("invalid addr is_lm %d\n", is_lm);
4192 ret = -EINVAL;
4193 goto clock_off;
4194 }
4195 temp_addr += off;
4196 ret = pp_ops[GC].pp_get_config(temp_addr, config,
4197 ((is_lm) ? LM : DSPP), disp_num);
4198 if (ret)
4199 pr_err("gc get config failed %d\n", ret);
4200 goto clock_off;
4201 }
4202 local_cfg = *config;
4203 local_cfg.r_data =
4204 &mdss_pp_res->gc_lut_r[disp_num][0];
4205 local_cfg.g_data =
4206 &mdss_pp_res->gc_lut_g[disp_num][0];
4207 local_cfg.b_data =
4208 &mdss_pp_res->gc_lut_b[disp_num][0];
4209 if (mdata->has_no_lut_read)
4210 pp_read_argc_lut_cached(&local_cfg);
4211 else
4212 pp_read_argc_lut(&local_cfg, argc_addr);
4213 if (copy_to_user(config->r_data,
4214 &mdss_pp_res->gc_lut_r[disp_num][0], tbl_size)) {
4215 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
4216 ret = -EFAULT;
4217 goto argc_config_exit;
4218 }
4219 if (copy_to_user(config->g_data,
4220 &mdss_pp_res->gc_lut_g[disp_num][0], tbl_size)) {
4221 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
4222 ret = -EFAULT;
4223 goto argc_config_exit;
4224 }
4225 if (copy_to_user(config->b_data,
4226 &mdss_pp_res->gc_lut_b[disp_num][0], tbl_size)) {
4227 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
4228 ret = -EFAULT;
4229 goto argc_config_exit;
4230 }
4231 *copyback = 1;
4232clock_off:
4233 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
4234 } else {
4235 if (pp_ops[GC].pp_set_config) {
4236 pr_debug("version of gc is %d\n", config->version);
4237 is_lm = (PP_LOCAT(config->block) == MDSS_PP_LM_CFG);
4238 ret = pp_pgc_lut_cache_params(config, mdss_pp_res,
4239 ((is_lm) ? LM : DSPP));
4240 if (ret) {
4241 pr_err("pgc cache params failed, ret %d\n",
4242 ret);
4243 goto argc_config_exit;
4244 }
4245 } else {
4246 r_size = config->num_r_stages *
4247 sizeof(struct mdp_ar_gc_lut_data);
4248 g_size = config->num_g_stages *
4249 sizeof(struct mdp_ar_gc_lut_data);
4250 b_size = config->num_b_stages *
4251 sizeof(struct mdp_ar_gc_lut_data);
4252 if (r_size > tbl_size ||
4253 g_size > tbl_size ||
4254 b_size > tbl_size ||
4255 r_size == 0 ||
4256 g_size == 0 ||
4257 b_size == 0) {
4258 ret = -EINVAL;
4259 pr_warn("%s, number of rgb stages invalid\n",
4260 __func__);
4261 goto argc_config_exit;
4262 }
4263 if (copy_from_user(&mdss_pp_res->gc_lut_r[disp_num][0],
4264 config->r_data, r_size)) {
4265 ret = -EFAULT;
4266 goto argc_config_exit;
4267 }
4268 if (copy_from_user(&mdss_pp_res->gc_lut_g[disp_num][0],
4269 config->g_data, g_size)) {
4270 ret = -EFAULT;
4271 goto argc_config_exit;
4272 }
4273 if (copy_from_user(&mdss_pp_res->gc_lut_b[disp_num][0],
4274 config->b_data, b_size)) {
4275 ret = -EFAULT;
4276 goto argc_config_exit;
4277 }
4278
4279 *pgc_ptr = *config;
4280 pgc_ptr->r_data =
4281 &mdss_pp_res->gc_lut_r[disp_num][0];
4282 pgc_ptr->g_data =
4283 &mdss_pp_res->gc_lut_g[disp_num][0];
4284 pgc_ptr->b_data =
4285 &mdss_pp_res->gc_lut_b[disp_num][0];
4286 }
4287 mdss_pp_res->pp_disp_flags[disp_num] |= dirty_flag;
4288 }
4289argc_config_exit:
4290 mutex_unlock(&mdss_pp_mutex);
4291 return ret;
4292}
4293int mdss_mdp_hist_lut_config(struct msm_fb_data_type *mfd,
4294 struct mdp_hist_lut_data *config,
4295 u32 *copyback)
4296{
4297 int i, ret = 0;
4298 u32 disp_num, dspp_num = 0;
4299 char __iomem *hist_addr = NULL, *base_addr = NULL;
4300 struct mdp_pp_cache_res res_cache;
4301
4302 ret = pp_validate_dspp_mfd_block(mfd, PP_BLOCK(config->block));
4303 if (ret) {
4304 pr_err("Invalid block %d mfd index %d, ret %d\n",
4305 PP_BLOCK(config->block),
4306 (mfd ? mfd->index : -1), ret);
4307 return ret;
4308 }
4309
4310 mutex_lock(&mdss_pp_mutex);
4311 disp_num = PP_BLOCK(config->block) - MDP_LOGICAL_BLOCK_DISP_0;
4312
4313 if (config->ops & MDP_PP_OPS_READ) {
4314 ret = pp_get_dspp_num(disp_num, &dspp_num);
4315 if (ret) {
4316 pr_err("%s, no dspp connects to disp %d\n",
4317 __func__, disp_num);
4318 goto enhist_config_exit;
4319 }
4320 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
4321 base_addr = mdss_mdp_get_dspp_addr_off(dspp_num);
4322 if (IS_ERR_OR_NULL(base_addr)) {
4323 pr_err("invalid base addr %pK\n",
4324 base_addr);
4325 ret = -EINVAL;
4326 goto hist_lut_clk_off;
4327 }
4328 hist_addr = base_addr + MDSS_MDP_REG_DSPP_HIST_LUT_BASE;
4329 if (pp_ops[HIST_LUT].pp_get_config) {
4330 ret = pp_ops[HIST_LUT].pp_get_config(base_addr, config,
4331 DSPP, disp_num);
4332 if (ret)
4333 pr_err("hist_lut get config failed %d\n", ret);
4334 goto hist_lut_clk_off;
4335 }
4336
4337 for (i = 0; i < ENHIST_LUT_ENTRIES; i++)
4338 mdss_pp_res->enhist_lut[disp_num][i] =
4339 readl_relaxed(hist_addr);
4340 if (copy_to_user(config->data,
4341 &mdss_pp_res->enhist_lut[disp_num][0],
4342 ENHIST_LUT_ENTRIES * sizeof(u32))) {
4343 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
4344 ret = -EFAULT;
4345 goto enhist_config_exit;
4346 }
4347 *copyback = 1;
4348hist_lut_clk_off:
4349 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
4350 } else {
4351 if (pp_ops[HIST_LUT].pp_set_config) {
4352 res_cache.block = DSPP;
4353 res_cache.mdss_pp_res = mdss_pp_res;
4354 res_cache.pipe_res = NULL;
4355 ret = pp_hist_lut_cache_params(config, &res_cache);
4356 if (ret) {
4357 pr_err("hist_lut config failed version %d ret %d\n",
4358 config->version, ret);
4359 ret = -EFAULT;
4360 goto enhist_config_exit;
4361 } else {
4362 goto enhist_set_dirty;
4363 }
4364 }
4365 if (copy_from_user(&mdss_pp_res->enhist_lut[disp_num][0],
4366 config->data, ENHIST_LUT_ENTRIES * sizeof(u32))) {
4367 ret = -EFAULT;
4368 goto enhist_config_exit;
4369 }
4370 mdss_pp_res->enhist_disp_cfg[disp_num] = *config;
4371 mdss_pp_res->enhist_disp_cfg[disp_num].data =
4372 &mdss_pp_res->enhist_lut[disp_num][0];
4373enhist_set_dirty:
4374 mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_ENHIST;
4375 }
4376enhist_config_exit:
4377 mutex_unlock(&mdss_pp_mutex);
4378 return ret;
4379}
4380
4381static int mdss_mdp_panel_default_dither_config(struct msm_fb_data_type *mfd,
4382 u32 panel_bpp, bool enable)
4383{
4384 int ret = 0;
4385 struct mdp_dither_cfg_data dither;
4386 struct mdp_pp_feature_version dither_version = {
4387 .pp_feature = DITHER,
4388 };
4389 struct mdp_dither_data_v1_7 dither_data;
4390
4391 if (!mdss_mdp_mfd_valid_dspp(mfd)) {
4392 pr_debug("dither config not supported on display num %d\n",
4393 mfd->index);
4394 return 0;
4395 }
4396
4397 dither.block = mfd->index + MDP_LOGICAL_BLOCK_DISP_0;
4398 dither.flags = MDP_PP_OPS_DISABLE;
4399
4400 ret = mdss_mdp_pp_get_version(&dither_version);
4401 if (ret) {
4402 pr_err("failed to get default dither version, ret %d\n",
4403 ret);
4404 return ret;
4405 }
4406 dither.version = dither_version.version_info;
4407 dither.cfg_payload = NULL;
4408
4409 if (enable) {
4410 switch (panel_bpp) {
4411 case 24:
4412 dither.flags = MDP_PP_OPS_ENABLE | MDP_PP_OPS_WRITE;
4413 switch (dither.version) {
4414 case mdp_dither_v1_7:
4415 dither_data.g_y_depth = 8;
4416 dither_data.r_cr_depth = 8;
4417 dither_data.b_cb_depth = 8;
4418 /*
4419 * Use default dither table by setting len to 0
4420 */
4421 dither_data.len = 0;
4422 dither.cfg_payload = &dither_data;
4423 break;
4424 case mdp_pp_legacy:
4425 default:
4426 dither.g_y_depth = 8;
4427 dither.r_cr_depth = 8;
4428 dither.b_cb_depth = 8;
4429 dither.cfg_payload = NULL;
4430 break;
4431 }
4432 break;
4433 case 18:
4434 dither.flags = MDP_PP_OPS_ENABLE | MDP_PP_OPS_WRITE;
4435 switch (dither.version) {
4436 case mdp_dither_v1_7:
4437 dither_data.g_y_depth = 6;
4438 dither_data.r_cr_depth = 6;
4439 dither_data.b_cb_depth = 6;
4440 /*
4441 * Use default dither table by setting len to 0
4442 */
4443 dither_data.len = 0;
4444 dither.cfg_payload = &dither_data;
4445 break;
4446 case mdp_pp_legacy:
4447 default:
4448 dither.g_y_depth = 6;
4449 dither.r_cr_depth = 6;
4450 dither.b_cb_depth = 6;
4451 dither.cfg_payload = NULL;
4452 break;
4453 }
4454 break;
4455 default:
4456 dither.cfg_payload = NULL;
4457 break;
4458 }
4459 }
4460 ret = mdss_mdp_dither_config(mfd, &dither, NULL, true);
4461 if (ret)
4462 pr_err("dither config failed, ret %d\n", ret);
4463
4464 return ret;
4465}
4466
4467int mdss_mdp_dither_config(struct msm_fb_data_type *mfd,
4468 struct mdp_dither_cfg_data *config,
4469 u32 *copyback,
4470 int copy_from_kernel)
4471{
4472 u32 disp_num;
4473 int ret = 0;
4474
4475 ret = pp_validate_dspp_mfd_block(mfd, config->block);
4476 if (ret) {
4477 pr_err("Invalid block %d mfd index %d, ret %d\n",
4478 config->block,
4479 (mfd ? mfd->index : -1), ret);
4480 return ret;
4481 }
4482
4483 if (config->flags & MDP_PP_OPS_READ) {
4484 pr_err("Dither read is not supported\n");
4485 return -EOPNOTSUPP;
4486 }
4487
4488 if ((config->flags & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
4489 pr_warn("Can't set both split bits\n");
4490 return -EINVAL;
4491 }
4492
4493 mutex_lock(&mdss_pp_mutex);
4494 disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
4495 if (pp_ops[DITHER].pp_set_config) {
4496 pr_debug("version of dither is %d\n", config->version);
4497 ret = pp_dither_cache_params(config, mdss_pp_res,
4498 copy_from_kernel);
4499 if (ret) {
4500 pr_err("dither config failed version %d ret %d\n",
4501 config->version, ret);
4502 goto dither_config_exit;
4503 } else {
4504 goto dither_set_dirty;
4505 }
4506 }
4507
4508 mdss_pp_res->dither_disp_cfg[disp_num] = *config;
4509dither_set_dirty:
4510 mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_DITHER;
4511dither_config_exit:
4512 mutex_unlock(&mdss_pp_mutex);
4513 return ret;
4514}
4515
4516static int pp_gm_has_invalid_lut_size(struct mdp_gamut_cfg_data *config)
4517{
4518 if (config->tbl_size[0] != GAMUT_T0_SIZE)
4519 return -EINVAL;
4520 if (config->tbl_size[1] != GAMUT_T1_SIZE)
4521 return -EINVAL;
4522 if (config->tbl_size[2] != GAMUT_T2_SIZE)
4523 return -EINVAL;
4524 if (config->tbl_size[3] != GAMUT_T3_SIZE)
4525 return -EINVAL;
4526 if (config->tbl_size[4] != GAMUT_T4_SIZE)
4527 return -EINVAL;
4528 if (config->tbl_size[5] != GAMUT_T5_SIZE)
4529 return -EINVAL;
4530 if (config->tbl_size[6] != GAMUT_T6_SIZE)
4531 return -EINVAL;
4532 if (config->tbl_size[7] != GAMUT_T7_SIZE)
4533 return -EINVAL;
4534 return 0;
4535}
4536
4537
4538int mdss_mdp_gamut_config(struct msm_fb_data_type *mfd,
4539 struct mdp_gamut_cfg_data *config,
4540 u32 *copyback)
4541{
4542 int i, j, ret = 0;
4543 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
4544 u32 disp_num, dspp_num = 0;
4545 uint16_t *tbl_off;
4546 struct mdp_gamut_cfg_data local_cfg;
4547 uint16_t *r_tbl[MDP_GAMUT_TABLE_NUM];
4548 uint16_t *g_tbl[MDP_GAMUT_TABLE_NUM];
4549 uint16_t *b_tbl[MDP_GAMUT_TABLE_NUM];
4550 char __iomem *addr;
4551 u32 data = (3 << 20);
4552
4553 ret = pp_validate_dspp_mfd_block(mfd, config->block);
4554 if (ret) {
4555 pr_err("Invalid block %d mfd index %d, ret %d\n",
4556 config->block,
4557 (mfd ? mfd->index : -1), ret);
4558 return ret;
4559 }
4560
4561 if ((config->flags & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
4562 pr_warn("Can't set both split bits\n");
4563 return -EINVAL;
4564 }
4565
4566 mutex_lock(&mdss_pp_mutex);
4567 disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
4568
4569 if (config->flags & MDP_PP_OPS_READ) {
4570 ret = pp_get_dspp_num(disp_num, &dspp_num);
4571 if (ret) {
4572 pr_err("%s, no dspp connects to disp %d\n",
4573 __func__, disp_num);
4574 goto gamut_config_exit;
4575 }
4576 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
4577 if (pp_ops[GAMUT].pp_get_config) {
4578 addr = mdss_mdp_get_dspp_addr_off(disp_num);
4579 if (IS_ERR_OR_NULL(addr)) {
4580 pr_err("invalid dspp base addr %pK\n",
4581 addr);
4582 ret = -EINVAL;
4583 goto gamut_clk_off;
4584 }
4585 if (mdata->pp_block_off.dspp_gamut_off == U32_MAX) {
4586 pr_err("invalid gamut parmas off %d\n",
4587 mdata->pp_block_off.dspp_gamut_off);
4588 ret = -EINVAL;
4589 goto gamut_clk_off;
4590 }
4591 addr += mdata->pp_block_off.dspp_gamut_off;
4592 ret = pp_ops[GAMUT].pp_get_config(addr, config, DSPP,
4593 disp_num);
4594 if (ret)
4595 pr_err("gamut get config failed %d\n", ret);
4596 goto gamut_clk_off;
4597 }
4598 if (pp_gm_has_invalid_lut_size(config)) {
4599 pr_err("invalid lut size for gamut\n");
4600 ret = -EINVAL;
4601 goto gamut_clk_off;
4602 }
4603 addr = mdss_mdp_get_dspp_addr_off(dspp_num) +
4604 MDSS_MDP_REG_DSPP_GAMUT_BASE;
4605 for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
4606 r_tbl[i] = kzalloc(
4607 sizeof(uint16_t) * config->tbl_size[i],
4608 GFP_KERNEL);
4609 if (!r_tbl[i]) {
4610 pr_err("%s: alloc failed\n", __func__);
4611 ret = -ENOMEM;
4612 goto gamut_clk_off;
4613 }
4614 /* Reset gamut LUT index to 0 */
4615 writel_relaxed(data, addr);
4616 for (j = 0; j < config->tbl_size[i]; j++)
4617 r_tbl[i][j] = readl_relaxed(addr) & 0x1FFF;
4618 addr += 4;
4619 ret = copy_to_user(config->r_tbl[i], r_tbl[i],
4620 sizeof(uint16_t) * config->tbl_size[i]);
4621 kfree(r_tbl[i]);
4622 if (ret) {
4623 pr_err("%s: copy tbl to usr failed\n",
4624 __func__);
4625 ret = -EFAULT;
4626 goto gamut_clk_off;
4627 }
4628 }
4629 for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
4630 g_tbl[i] = kzalloc(
4631 sizeof(uint16_t) * config->tbl_size[i],
4632 GFP_KERNEL);
4633 if (!g_tbl[i]) {
4634 pr_err("%s: alloc failed\n", __func__);
4635 ret = -ENOMEM;
4636 goto gamut_clk_off;
4637 }
4638 /* Reset gamut LUT index to 0 */
4639 writel_relaxed(data, addr);
4640 for (j = 0; j < config->tbl_size[i]; j++)
4641 g_tbl[i][j] = readl_relaxed(addr) & 0x1FFF;
4642 addr += 4;
4643 ret = copy_to_user(config->g_tbl[i], g_tbl[i],
4644 sizeof(uint16_t) * config->tbl_size[i]);
4645 kfree(g_tbl[i]);
4646 if (ret) {
4647 pr_err("%s: copy tbl to usr failed\n",
4648 __func__);
4649 ret = -EFAULT;
4650 goto gamut_clk_off;
4651 }
4652 }
4653 for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
4654 b_tbl[i] = kzalloc(
4655 sizeof(uint16_t) * config->tbl_size[i],
4656 GFP_KERNEL);
4657 if (!b_tbl[i]) {
4658 pr_err("%s: alloc failed\n", __func__);
4659 ret = -ENOMEM;
4660 goto gamut_clk_off;
4661 }
4662 /* Reset gamut LUT index to 0 */
4663 writel_relaxed(data, addr);
4664 for (j = 0; j < config->tbl_size[i]; j++)
4665 b_tbl[i][j] = readl_relaxed(addr) & 0x1FFF;
4666 addr += 4;
4667 ret = copy_to_user(config->b_tbl[i], b_tbl[i],
4668 sizeof(uint16_t) * config->tbl_size[i]);
4669 kfree(b_tbl[i]);
4670 if (ret) {
4671 pr_err("%s: copy tbl to usr failed\n",
4672 __func__);
4673 ret = -EFAULT;
4674 goto gamut_clk_off;
4675 }
4676 }
4677 *copyback = 1;
4678gamut_clk_off:
4679 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
4680 } else {
4681 if (pp_ops[GAMUT].pp_set_config) {
4682 pr_debug("version of gamut is %d\n", config->version);
4683 ret = pp_gamut_cache_params(config, mdss_pp_res);
4684 if (ret) {
4685 pr_err("gamut config failed version %d ret %d\n",
4686 config->version, ret);
4687 ret = -EFAULT;
4688 goto gamut_config_exit;
4689 } else {
4690 goto gamut_set_dirty;
4691 }
4692 }
4693 if (pp_gm_has_invalid_lut_size(config)) {
4694 pr_err("invalid lut size for gamut\n");
4695 ret = -EINVAL;
4696 goto gamut_config_exit;
4697 }
4698 local_cfg = *config;
4699 tbl_off = mdss_pp_res->gamut_tbl[disp_num];
4700 for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
4701 local_cfg.r_tbl[i] = tbl_off;
4702 if (copy_from_user(tbl_off, config->r_tbl[i],
4703 config->tbl_size[i] * sizeof(uint16_t))) {
4704 ret = -EFAULT;
4705 goto gamut_config_exit;
4706 }
4707 tbl_off += local_cfg.tbl_size[i];
4708 }
4709 for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
4710 local_cfg.g_tbl[i] = tbl_off;
4711 if (copy_from_user(tbl_off, config->g_tbl[i],
4712 config->tbl_size[i] * sizeof(uint16_t))) {
4713 ret = -EFAULT;
4714 goto gamut_config_exit;
4715 }
4716 tbl_off += local_cfg.tbl_size[i];
4717 }
4718 for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
4719 local_cfg.b_tbl[i] = tbl_off;
4720 if (copy_from_user(tbl_off, config->b_tbl[i],
4721 config->tbl_size[i] * sizeof(uint16_t))) {
4722 ret = -EFAULT;
4723 goto gamut_config_exit;
4724 }
4725 tbl_off += local_cfg.tbl_size[i];
4726 }
4727 mdss_pp_res->gamut_disp_cfg[disp_num] = local_cfg;
4728gamut_set_dirty:
4729 mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_GAMUT;
4730 }
4731gamut_config_exit:
4732 mutex_unlock(&mdss_pp_mutex);
4733 return ret;
4734}
4735
4736static u32 pp_hist_read(char __iomem *v_addr,
4737 struct pp_hist_col_info *hist_info)
4738{
4739 int i, i_start;
4740 u32 sum = 0;
4741 u32 data;
4742
4743 data = readl_relaxed(v_addr);
4744 i_start = data >> 24;
4745 hist_info->data[i_start] = data & 0xFFFFFF;
4746 sum += hist_info->data[i_start];
4747 for (i = i_start + 1; i < HIST_V_SIZE; i++) {
4748 hist_info->data[i] = readl_relaxed(v_addr) & 0xFFFFFF;
4749 sum += hist_info->data[i];
4750 }
4751 for (i = 0; i < i_start; i++) {
4752 hist_info->data[i] = readl_relaxed(v_addr) & 0xFFFFFF;
4753 sum += hist_info->data[i];
4754 }
4755 hist_info->hist_cnt_read++;
4756 return sum;
4757}
4758
4759/* Assumes that relevant clocks are enabled */
4760static int pp_hist_enable(struct pp_hist_col_info *hist_info,
4761 struct mdp_histogram_start_req *req,
4762 struct mdss_mdp_ctl *ctl)
4763{
4764 unsigned long flag;
4765 int ret = 0;
4766
4767 mutex_lock(&hist_info->hist_mutex);
4768 /* check if it is idle */
4769 spin_lock_irqsave(&hist_info->hist_lock, flag);
4770 if (hist_info->col_en) {
4771 spin_unlock_irqrestore(&hist_info->hist_lock, flag);
4772 pr_err("%s Hist collection has already been enabled %pK\n",
4773 __func__, hist_info->base);
4774 ret = -EBUSY;
4775 goto exit;
4776 }
4777 hist_info->col_state = HIST_IDLE;
4778 hist_info->col_en = true;
4779 hist_info->frame_cnt = req->frame_cnt;
4780 hist_info->hist_cnt_read = 0;
4781 hist_info->hist_cnt_sent = 0;
4782 hist_info->hist_cnt_time = 0;
4783 if (ctl && ctl->mfd) {
4784 hist_info->ctl = ctl;
4785 hist_info->disp_num =
4786 ctl->mfd->index + MDP_LOGICAL_BLOCK_DISP_0;
4787 }
4788 /* if hist v2, make sure HW is unlocked */
4789 writel_relaxed(0, hist_info->base);
4790 spin_unlock_irqrestore(&hist_info->hist_lock, flag);
4791exit:
4792 mutex_unlock(&hist_info->hist_mutex);
4793 return ret;
4794}
4795
4796#define MDSS_MAX_HIST_BIN_SIZE 16777215
4797int mdss_mdp_hist_start(struct mdp_histogram_start_req *req)
4798{
4799 struct pp_hist_col_info *hist_info;
4800 int i, ret = 0;
4801 u32 disp_num, dspp_num = 0;
4802 u32 mixer_cnt, mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
4803 u32 frame_size, intr_mask = 0;
4804 struct mdss_mdp_pipe *pipe;
4805 struct mdss_mdp_ctl *ctl;
4806 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
4807 bool sspp_hist_supp = false;
4808
4809 if (!mdss_is_ready())
4810 return -EPROBE_DEFER;
4811
4812 if (mdata->mdp_rev < MDSS_MDP_HW_REV_103) {
4813 pr_err("Unsupported mdp rev %d\n", mdata->mdp_rev);
4814 return -EOPNOTSUPP;
4815 }
4816
4817 if (pp_driver_ops.is_sspp_hist_supp)
4818 sspp_hist_supp = pp_driver_ops.is_sspp_hist_supp();
4819
4820 if (!sspp_hist_supp &&
4821 (PP_LOCAT(req->block) == MDSS_PP_SSPP_CFG)) {
4822 pr_warn("No histogram on SSPP\n");
4823 ret = -EINVAL;
4824 goto hist_exit;
4825 }
4826
4827 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
4828
4829 if (PP_LOCAT(req->block) == MDSS_PP_SSPP_CFG) {
4830 i = MDSS_PP_ARG_MASK & req->block;
4831 if (!i) {
4832 ret = -EINVAL;
4833 pr_warn("Must pass pipe arguments, %d\n", i);
4834 goto hist_stop_clk;
4835 }
4836
4837 for (i = 0; i < MDSS_PP_ARG_NUM; i++) {
4838 if (!PP_ARG(i, req->block))
4839 continue;
4840 pipe = __get_hist_pipe(i);
4841 if (IS_ERR_OR_NULL(pipe))
4842 continue;
4843 hist_info = &pipe->pp_res.hist;
4844 ret = pp_hist_enable(hist_info, req, NULL);
4845 intr_mask = 1 << hist_info->intr_shift;
4846 mdss_mdp_hist_intr_req(&mdata->hist_intr, intr_mask,
4847 true);
4848 mdss_mdp_pipe_unmap(pipe);
4849 }
4850 } else if (PP_LOCAT(req->block) == MDSS_PP_DSPP_CFG) {
4851 if ((PP_BLOCK(req->block) < MDP_LOGICAL_BLOCK_DISP_0) ||
4852 (PP_BLOCK(req->block) >= MDP_BLOCK_MAX))
4853 goto hist_stop_clk;
4854
4855 disp_num = PP_BLOCK(req->block) - MDP_LOGICAL_BLOCK_DISP_0;
4856 mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
4857
4858 if (!mixer_cnt) {
4859 pr_err("%s, no dspp connects to disp %d\n",
4860 __func__, disp_num);
4861 ret = -EPERM;
4862 goto hist_stop_clk;
4863 }
4864 if (mixer_cnt > mdata->nmixers_intf) {
4865 pr_err("%s, Too many dspp connects to disp %d\n",
4866 __func__, mixer_cnt);
4867 ret = -EPERM;
4868 goto hist_stop_clk;
4869 }
4870
4871 ctl = mdata->mixer_intf[mixer_id[0]].ctl;
4872 frame_size = (ctl->width * ctl->height);
4873
4874 if (!frame_size ||
4875 ((MDSS_MAX_HIST_BIN_SIZE / frame_size) <
4876 req->frame_cnt)) {
4877 pr_err("%s, too many frames for given display size, %d\n",
4878 __func__, req->frame_cnt);
4879 ret = -EINVAL;
4880 goto hist_stop_clk;
4881 }
4882
4883 for (i = 0; i < mixer_cnt; i++) {
4884 dspp_num = mixer_id[i];
4885 if (dspp_num >= mdata->ndspp) {
4886 ret = -EINVAL;
4887 pr_warn("Invalid dspp num %d\n", dspp_num);
4888 goto hist_stop_clk;
4889 }
4890 hist_info = &mdss_pp_res->dspp_hist[dspp_num];
4891 ret = pp_hist_enable(hist_info, req, ctl);
4892 if (ret) {
4893 pr_err("failed to enable histogram dspp_num %d ret %d\n",
4894 dspp_num, ret);
4895 goto hist_stop_clk;
4896 }
4897 intr_mask |= 1 << hist_info->intr_shift;
4898 mdss_pp_res->pp_disp_flags[disp_num] |=
4899 PP_FLAGS_DIRTY_HIST_COL;
4900 }
4901 mdss_mdp_hist_intr_req(&mdata->hist_intr, intr_mask,
4902 true);
4903 }
4904hist_stop_clk:
4905 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
4906hist_exit:
4907 return ret;
4908}
4909
4910static int pp_hist_disable(struct pp_hist_col_info *hist_info)
4911{
4912 int ret = 0;
4913 unsigned long flag;
4914 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
4915 u32 intr_mask = 1;
4916
4917 mutex_lock(&hist_info->hist_mutex);
4918 spin_lock_irqsave(&hist_info->hist_lock, flag);
4919 if (hist_info->col_en == false) {
4920 spin_unlock_irqrestore(&hist_info->hist_lock, flag);
4921 pr_debug("Histogram already disabled (%pK)\n", hist_info->base);
4922 ret = -EINVAL;
4923 goto exit;
4924 }
4925 hist_info->col_en = false;
4926 hist_info->col_state = HIST_UNKNOWN;
4927 hist_info->disp_num = 0;
4928 hist_info->ctl = NULL;
4929 /* make sure HW is unlocked */
4930 writel_relaxed(0, hist_info->base);
4931 spin_unlock_irqrestore(&hist_info->hist_lock, flag);
4932 mdss_mdp_hist_intr_req(&mdata->hist_intr,
4933 intr_mask << hist_info->intr_shift, false);
4934 ret = 0;
4935exit:
4936 mutex_unlock(&hist_info->hist_mutex);
4937 return ret;
4938}
4939
4940int mdss_mdp_hist_stop(u32 block)
4941{
4942 int i, ret = 0;
4943 u32 disp_num;
4944 struct pp_hist_col_info *hist_info;
4945 struct mdss_mdp_pipe *pipe;
4946 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
4947
4948 if (!mdata)
4949 return -EPERM;
4950
4951 if (mdata->mdp_rev < MDSS_MDP_HW_REV_103) {
4952 pr_err("Unsupported mdp rev %d\n", mdata->mdp_rev);
4953 return -EOPNOTSUPP;
4954 }
4955
4956 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
4957 if (PP_LOCAT(block) == MDSS_PP_SSPP_CFG) {
4958 i = MDSS_PP_ARG_MASK & block;
4959 if (!i) {
4960 pr_warn("Must pass pipe arguments, %d\n", i);
4961 goto hist_stop_clk;
4962 }
4963
4964 for (i = 0; i < MDSS_PP_ARG_NUM; i++) {
4965 if (!PP_ARG(i, block))
4966 continue;
4967 pipe = __get_hist_pipe(i);
4968 if (IS_ERR_OR_NULL(pipe)) {
4969 pr_warn("Invalid Hist pipe (%d)\n", i);
4970 continue;
4971 }
4972 hist_info = &pipe->pp_res.hist;
4973 ret = pp_hist_disable(hist_info);
4974 mdss_mdp_pipe_unmap(pipe);
4975 if (ret)
4976 goto hist_stop_clk;
4977 }
4978 } else if (PP_LOCAT(block) == MDSS_PP_DSPP_CFG) {
4979 if ((PP_BLOCK(block) < MDP_LOGICAL_BLOCK_DISP_0) ||
4980 (PP_BLOCK(block) >= MDP_BLOCK_MAX))
4981 goto hist_stop_clk;
4982
4983 disp_num = PP_BLOCK(block);
4984 for (i = 0; i < mdata->ndspp; i++) {
4985 hist_info = &mdss_pp_res->dspp_hist[i];
4986 if (disp_num != hist_info->disp_num)
4987 continue;
4988 ret = pp_hist_disable(hist_info);
4989 if (ret)
4990 goto hist_stop_clk;
4991 mdss_pp_res->pp_disp_flags[i] |=
4992 PP_FLAGS_DIRTY_HIST_COL;
4993 }
4994 }
4995hist_stop_clk:
4996 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
4997 return ret;
4998}
4999
5000/**
5001 * mdss_mdp_hist_intr_req() - Request changes the histogram interrupts
5002 * @intr: structure containting state of interrupt register
5003 * @bits: the bits on interrupt register that should be changed
5004 * @en: true if bits should be set, false if bits should be cleared
5005 *
5006 * Adds or removes the bits from the interrupt request.
5007 *
5008 * Does not store reference count for each bit. I.e. a bit with multiple
5009 * enable requests can be disabled with a single disable request.
5010 *
5011 * Return: 0 if uneventful, errno on invalid input
5012 */
5013int mdss_mdp_hist_intr_req(struct mdss_intr *intr, u32 bits, bool en)
5014{
5015 unsigned long flag;
5016 int ret = 0;
5017
5018 if (!intr) {
5019 pr_err("NULL addr passed, %pK\n", intr);
5020 return -EINVAL;
5021 }
5022
5023 spin_lock_irqsave(&intr->lock, flag);
5024 if (en)
5025 intr->req |= bits;
5026 else
5027 intr->req &= ~bits;
5028 spin_unlock_irqrestore(&intr->lock, flag);
5029
5030 mdss_mdp_hist_intr_setup(intr, MDSS_IRQ_REQ);
5031
5032 return ret;
5033}
5034
5035
5036#define MDSS_INTR_STATE_ACTIVE 1
5037#define MDSS_INTR_STATE_NULL 0
5038#define MDSS_INTR_STATE_SUSPEND -1
5039
5040/**
5041 * mdss_mdp_hist_intr_setup() - Manage intr and clk depending on requests.
5042 * @intr: structure containting state of intr reg
5043 * @state: MDSS_IRQ_SUSPEND if suspend is needed,
5044 * MDSS_IRQ_RESUME if resume is needed,
5045 * MDSS_IRQ_REQ if neither (i.e. requesting an interrupt)
5046 *
5047 * This function acts as a gatekeeper for the interrupt, making sure that the
5048 * MDP clocks are enabled while the interrupts are enabled to prevent
5049 * unclocked accesses.
5050 *
5051 * To reduce code repetition, 4 state transitions have been encoded here. Each
5052 * transition updates the interrupt's state structure (mdss_intr) to reflect
5053 * the which bits have been requested (intr->req), are currently enabled
5054 * (intr->curr), as well as defines which interrupt bits need to be enabled or
5055 * disabled ('en' and 'dis' respectively). The 4th state is not explicity
5056 * coded in the if/else chain, but is for MDSS_IRQ_REQ's when the interrupt
5057 * is in suspend, in which case, the only change required (intr->req being
5058 * updated) has already occurred in the calling function.
5059 *
5060 * To control the clock, which can't be requested while holding the spinlock,
5061 * the initial state is compared with the exit state to detect when the
5062 * interrupt needs a clock.
5063 *
5064 * The clock requests surrounding the majority of this function serve to
5065 * enable the register writes to change the interrupt register, as well as to
5066 * prevent a race condition that could keep the clocks on (due to mdp_clk_cnt
5067 * never being decremented below 0) when a enable/disable occurs but the
5068 * disable requests the clocks disabled before the enable is able to request
5069 * the clocks enabled.
5070 *
5071 * Return: 0 if uneventful, errno on repeated action or invalid input
5072 */
5073int mdss_mdp_hist_intr_setup(struct mdss_intr *intr, int type)
5074{
5075 unsigned long flag;
5076 int ret = 0, req_clk = 0;
5077 u32 en = 0, dis = 0;
5078 u32 diff, init_curr;
5079 int init_state;
5080
5081 if (!intr) {
5082 WARN(1, "NULL intr pointer\n");
5083 return -EINVAL;
5084 }
5085
5086 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
5087 spin_lock_irqsave(&intr->lock, flag);
5088
5089 init_state = intr->state;
5090 init_curr = intr->curr;
5091
5092 if (type == MDSS_IRQ_RESUME) {
5093 /* resume intrs */
5094 if (intr->state == MDSS_INTR_STATE_ACTIVE) {
5095 ret = -EPERM;
5096 goto exit;
5097 }
5098 en = intr->req;
5099 dis = 0;
5100 intr->curr = intr->req;
5101 intr->state = intr->curr ?
5102 MDSS_INTR_STATE_ACTIVE : MDSS_INTR_STATE_NULL;
5103 } else if (type == MDSS_IRQ_SUSPEND) {
5104 /* suspend intrs */
5105 if (intr->state == MDSS_INTR_STATE_SUSPEND) {
5106 ret = -EPERM;
5107 goto exit;
5108 }
5109 en = 0;
5110 dis = intr->curr;
5111 intr->curr = 0;
5112 intr->state = MDSS_INTR_STATE_SUSPEND;
5113 } else if (intr->state != MDSS_IRQ_SUSPEND &&
5114 type == MDSS_IRQ_REQ) {
5115 /* Not resuming/suspending or in suspend state */
5116 diff = intr->req ^ intr->curr;
5117 en = diff & ~intr->curr;
5118 dis = diff & ~intr->req;
5119 intr->curr = intr->req;
5120 intr->state = intr->curr ?
5121 MDSS_INTR_STATE_ACTIVE : MDSS_INTR_STATE_NULL;
5122 }
5123
5124 if (en)
5125 mdss_mdp_hist_irq_enable(en);
5126 if (dis)
5127 mdss_mdp_hist_irq_disable(dis);
5128
5129 if ((init_state != MDSS_INTR_STATE_ACTIVE) &&
5130 (intr->state == MDSS_INTR_STATE_ACTIVE))
5131 req_clk = 1;
5132 else if ((init_state == MDSS_INTR_STATE_ACTIVE) &&
5133 (intr->state != MDSS_INTR_STATE_ACTIVE))
5134 req_clk = -1;
5135
5136exit:
5137 spin_unlock_irqrestore(&intr->lock, flag);
5138 if (req_clk < 0)
5139 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
5140 else if (req_clk > 0)
5141 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
5142
5143 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
5144 return ret;
5145}
5146
5147static int pp_hist_collect(struct mdp_histogram_data *hist,
5148 struct pp_hist_col_info *hist_info,
5149 char __iomem *ctl_base, u32 expect_sum,
5150 u32 block)
5151{
5152 int ret = 0;
5153 u32 sum;
5154 char __iomem *v_base = NULL;
5155 unsigned long flag;
5156 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
5157
5158 if (!mdata)
5159 return -EPERM;
5160
5161 mutex_lock(&hist_info->hist_mutex);
5162 spin_lock_irqsave(&hist_info->hist_lock, flag);
5163 if ((hist_info->col_en == 0) ||
5164 (hist_info->col_state != HIST_READY)) {
5165 pr_err("invalid params for histogram hist_info->col_en %d hist_info->col_state %d",
5166 hist_info->col_en, hist_info->col_state);
5167 ret = -ENODATA;
5168 spin_unlock_irqrestore(&hist_info->hist_lock, flag);
5169 goto hist_collect_exit;
5170 }
5171 spin_unlock_irqrestore(&hist_info->hist_lock, flag);
5172 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
5173 if (pp_ops[HIST].pp_get_config) {
5174 sum = pp_ops[HIST].pp_get_config(ctl_base, hist_info,
5175 block, 0);
5176 } else {
5177 if (block == DSPP)
5178 v_base = ctl_base +
5179 MDSS_MDP_REG_DSPP_HIST_DATA_BASE;
5180 else if (block == SSPP_VIG)
5181 v_base = ctl_base +
5182 MDSS_MDP_REG_VIG_HIST_CTL_BASE;
5183 sum = pp_hist_read(v_base, hist_info);
5184 }
5185 writel_relaxed(0, hist_info->base);
5186 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
5187 if (sum < 0) {
5188 pr_err("failed to get the hist data, sum = %d\n", sum);
5189 ret = sum;
5190 } else if (expect_sum && sum != expect_sum) {
5191 pr_err("hist error: bin sum incorrect! (%d/%d)\n",
5192 sum, expect_sum);
5193 ret = -EINVAL;
5194 }
5195hist_collect_exit:
5196 mutex_unlock(&hist_info->hist_mutex);
5197 return ret;
5198}
5199
5200int mdss_mdp_hist_collect(struct mdp_histogram_data *hist)
5201{
5202 int i, j, off, ret = 0, temp_ret = 0;
5203 struct pp_hist_col_info *hist_info;
5204 struct pp_hist_col_info *hists[MDSS_MDP_INTF_MAX_LAYERMIXER];
5205 u32 dspp_num, disp_num;
5206 char __iomem *ctl_base;
5207 u32 hist_cnt, mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
5208 u32 *hist_concat = NULL;
5209 u32 *hist_data_addr;
5210 u32 pipe_cnt = 0;
5211 u32 pipe_num = MDSS_MDP_SSPP_VIG0;
5212 u32 exp_sum = 0;
5213 struct mdss_mdp_pipe *pipe;
5214 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
5215 unsigned long flag;
5216
5217 if (mdata->mdp_rev < MDSS_MDP_HW_REV_103) {
5218 pr_err("Unsupported mdp rev %d\n", mdata->mdp_rev);
5219 return -EOPNOTSUPP;
5220 }
5221
5222 if (PP_LOCAT(hist->block) == MDSS_PP_DSPP_CFG) {
5223 if ((PP_BLOCK(hist->block) < MDP_LOGICAL_BLOCK_DISP_0) ||
5224 (PP_BLOCK(hist->block) >= MDP_BLOCK_MAX))
5225 return -EINVAL;
5226
5227 disp_num = PP_BLOCK(hist->block) - MDP_LOGICAL_BLOCK_DISP_0;
5228 hist_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
5229
5230 if (!hist_cnt) {
5231 pr_err("%s, no dspp connects to disp %d\n",
5232 __func__, disp_num);
5233 ret = -EPERM;
5234 goto hist_collect_exit;
5235 }
5236 if (hist_cnt > mdata->nmixers_intf) {
5237 pr_err("%s, Too many dspp connects to disp %d\n",
5238 __func__, hist_cnt);
5239 ret = -EPERM;
5240 goto hist_collect_exit;
5241 }
5242
5243 for (i = 0; i < hist_cnt; i++) {
5244 dspp_num = mixer_id[i];
5245 if (dspp_num >= mdata->ndspp) {
5246 ret = -EINVAL;
5247 pr_warn("Invalid dspp num %d\n", dspp_num);
5248 goto hist_collect_exit;
5249 }
5250 hists[i] = &mdss_pp_res->dspp_hist[dspp_num];
5251 }
5252 for (i = 0; i < hist_cnt; i++) {
5253 dspp_num = mixer_id[i];
5254 ctl_base = mdss_mdp_get_dspp_addr_off(dspp_num);
5255 exp_sum = (mdata->mixer_intf[dspp_num].width *
5256 mdata->mixer_intf[dspp_num].height);
5257 if (ret)
5258 temp_ret = ret;
5259 ret = pp_hist_collect(hist, hists[i], ctl_base,
5260 exp_sum, DSPP);
5261 if (ret)
5262 pr_err("hist error: dspp[%d] collect %d\n",
5263 dspp_num, ret);
5264 }
5265 /* state of dspp histogram blocks attached to logical display
5266 * should be changed atomically to idle. This will ensure that
5267 * histogram interrupt will see consistent states for all dspp's
5268 * attached to logical display.
5269 */
5270 for (i = 0; i < hist_cnt; i++) {
5271 if (!i)
5272 spin_lock_irqsave(&hists[i]->hist_lock, flag);
5273 else
5274 spin_lock(&hists[i]->hist_lock);
5275 }
5276 for (i = 0; i < hist_cnt; i++)
5277 hists[i]->col_state = HIST_IDLE;
5278 for (i = hist_cnt - 1; i >= 0; i--) {
5279 if (!i)
5280 spin_unlock_irqrestore(&hists[i]->hist_lock,
5281 flag);
5282 else
5283 spin_unlock(&hists[i]->hist_lock);
5284 }
5285 if (ret || temp_ret) {
5286 ret = ret ? ret : temp_ret;
5287 goto hist_collect_exit;
5288 }
5289
5290 if (hist->bin_cnt != HIST_V_SIZE) {
5291 pr_err("User not expecting size %d output\n",
5292 HIST_V_SIZE);
5293 ret = -EINVAL;
5294 goto hist_collect_exit;
5295 }
5296 if (hist_cnt > 1) {
5297 for (i = 1; i < hist_cnt; i++) {
5298 mutex_lock(&hists[i]->hist_mutex);
5299 for (j = 0; j < HIST_V_SIZE; j++)
5300 hists[0]->data[j] += hists[i]->data[j];
5301 mutex_unlock(&hists[i]->hist_mutex);
5302 }
5303 }
5304 hist_data_addr = hists[0]->data;
5305
5306 for (i = 0; i < hist_cnt; i++)
5307 hists[i]->hist_cnt_sent++;
5308
5309 } else if (PP_LOCAT(hist->block) == MDSS_PP_SSPP_CFG) {
5310
5311 hist_cnt = MDSS_PP_ARG_MASK & hist->block;
5312 if (!hist_cnt) {
5313 pr_warn("Must pass pipe arguments, %d\n", hist_cnt);
5314 goto hist_collect_exit;
5315 }
5316
5317 /* Find the first pipe requested */
5318 for (i = 0; i < MDSS_PP_ARG_NUM; i++) {
5319 if (PP_ARG(i, hist_cnt)) {
5320 pipe_num = i;
5321 break;
5322 }
5323 }
5324
5325 pipe = __get_hist_pipe(pipe_num);
5326 if (IS_ERR_OR_NULL(pipe)) {
5327 pr_warn("Invalid starting hist pipe, %d\n", pipe_num);
5328 ret = -ENODEV;
5329 goto hist_collect_exit;
5330 }
5331 hist_info = &pipe->pp_res.hist;
5332 mdss_mdp_pipe_unmap(pipe);
5333 for (i = pipe_num; i < MDSS_PP_ARG_NUM; i++) {
5334 if (!PP_ARG(i, hist->block))
5335 continue;
5336 pipe_cnt++;
5337 pipe = __get_hist_pipe(i);
5338 if (IS_ERR_OR_NULL(pipe)) {
5339 pr_warn("Invalid Hist pipe (%d)\n", i);
5340 continue;
5341 }
5342 hist_info = &pipe->pp_res.hist;
5343 mdss_mdp_pipe_unmap(pipe);
5344 }
5345 for (i = pipe_num; i < MDSS_PP_ARG_NUM; i++) {
5346 if (!PP_ARG(i, hist->block))
5347 continue;
5348 pipe_cnt++;
5349 pipe = __get_hist_pipe(i);
5350 if (IS_ERR_OR_NULL(pipe)) {
5351 pr_warn("Invalid Hist pipe (%d)\n", i);
5352 continue;
5353 }
5354 hist_info = &pipe->pp_res.hist;
5355 ctl_base = pipe->base;
5356 if (ret)
5357 temp_ret = ret;
5358 ret = pp_hist_collect(hist, hist_info, ctl_base,
5359 exp_sum, SSPP_VIG);
5360 if (ret)
5361 pr_debug("hist error: pipe[%d] collect: %d\n",
5362 pipe->num, ret);
5363
5364 mdss_mdp_pipe_unmap(pipe);
5365 }
5366 for (i = pipe_num; i < MDSS_PP_ARG_NUM; i++) {
5367 if (!PP_ARG(i, hist->block))
5368 continue;
5369 pipe_cnt++;
5370 pipe = __get_hist_pipe(i);
5371 if (IS_ERR_OR_NULL(pipe)) {
5372 pr_warn("Invalid Hist pipe (%d)\n", i);
5373 continue;
5374 }
5375 hist_info = &pipe->pp_res.hist;
5376 mdss_mdp_pipe_unmap(pipe);
5377 }
5378 if (ret || temp_ret) {
5379 ret = ret ? ret : temp_ret;
5380 goto hist_collect_exit;
5381 }
5382
5383 if (pipe_cnt != 0 &&
5384 (hist->bin_cnt != (HIST_V_SIZE * pipe_cnt))) {
5385 pr_err("User not expecting size %d output\n",
5386 pipe_cnt * HIST_V_SIZE);
5387 ret = -EINVAL;
5388 goto hist_collect_exit;
5389 }
5390 if (pipe_cnt > 1) {
5391 hist_concat = kzalloc(HIST_V_SIZE * pipe_cnt *
5392 sizeof(u32), GFP_KERNEL);
5393 if (!hist_concat) {
5394 ret = -ENOMEM;
5395 goto hist_collect_exit;
5396 }
5397
5398 for (i = pipe_num; i < MDSS_PP_ARG_NUM; i++) {
5399 if (!PP_ARG(i, hist->block))
5400 continue;
5401 pipe = __get_hist_pipe(i);
5402 if (IS_ERR_OR_NULL(pipe)) {
5403 pr_warn("Invalid Hist pipe (%d)\n", i);
5404 continue;
5405 }
5406 hist_info = &pipe->pp_res.hist;
5407 off = HIST_V_SIZE * i;
5408 mutex_lock(&hist_info->hist_mutex);
5409 for (j = off; j < off + HIST_V_SIZE; j++)
5410 hist_concat[j] =
5411 hist_info->data[j - off];
5412 hist_info->hist_cnt_sent++;
5413 mutex_unlock(&hist_info->hist_mutex);
5414 mdss_mdp_pipe_unmap(pipe);
5415 }
5416
5417 hist_data_addr = hist_concat;
5418 } else {
5419 hist_data_addr = hist_info->data;
5420 }
5421 } else {
5422 pr_info("No Histogram at location %d\n", PP_LOCAT(hist->block));
5423 goto hist_collect_exit;
5424 }
5425 ret = copy_to_user(hist->c0, hist_data_addr, sizeof(u32) *
5426 hist->bin_cnt);
5427hist_collect_exit:
5428 kfree(hist_concat);
5429
5430 return ret;
5431}
5432
5433static inline struct pp_hist_col_info *get_hist_info_from_isr(u32 *isr)
5434{
5435 u32 blk_idx;
5436 struct pp_hist_col_info *hist_info = NULL;
5437 struct mdss_mdp_pipe *pipe;
5438 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
5439
5440 if (*isr & HIST_INTR_DSPP_MASK) {
5441 if (*isr & (MDSS_MDP_HIST_INTR_DSPP_0_DONE |
5442 MDSS_MDP_HIST_INTR_DSPP_0_RESET_DONE)) {
5443 blk_idx = 0;
5444 *isr &= ~(MDSS_MDP_HIST_INTR_DSPP_0_DONE |
5445 MDSS_MDP_HIST_INTR_DSPP_0_RESET_DONE);
5446 } else if (*isr & (MDSS_MDP_HIST_INTR_DSPP_1_DONE |
5447 MDSS_MDP_HIST_INTR_DSPP_1_RESET_DONE)) {
5448 blk_idx = 1;
5449 *isr &= ~(MDSS_MDP_HIST_INTR_DSPP_1_DONE |
5450 MDSS_MDP_HIST_INTR_DSPP_1_RESET_DONE);
5451 } else if (*isr & (MDSS_MDP_HIST_INTR_DSPP_2_DONE |
5452 MDSS_MDP_HIST_INTR_DSPP_2_RESET_DONE)) {
5453 blk_idx = 2;
5454 *isr &= ~(MDSS_MDP_HIST_INTR_DSPP_2_DONE |
5455 MDSS_MDP_HIST_INTR_DSPP_2_RESET_DONE);
5456 } else {
5457 blk_idx = 3;
5458 *isr &= ~(MDSS_MDP_HIST_INTR_DSPP_3_DONE |
5459 MDSS_MDP_HIST_INTR_DSPP_3_RESET_DONE);
5460 }
5461 hist_info = &mdss_pp_res->dspp_hist[blk_idx];
5462 } else {
5463 if (*isr & (MDSS_MDP_HIST_INTR_VIG_0_DONE |
5464 MDSS_MDP_HIST_INTR_VIG_0_RESET_DONE)) {
5465 blk_idx = MDSS_MDP_SSPP_VIG0;
5466 *isr &= ~(MDSS_MDP_HIST_INTR_VIG_0_DONE |
5467 MDSS_MDP_HIST_INTR_VIG_0_RESET_DONE);
5468 } else if (*isr & (MDSS_MDP_HIST_INTR_VIG_1_DONE |
5469 MDSS_MDP_HIST_INTR_VIG_1_RESET_DONE)) {
5470 blk_idx = MDSS_MDP_SSPP_VIG1;
5471 *isr &= ~(MDSS_MDP_HIST_INTR_VIG_1_DONE |
5472 MDSS_MDP_HIST_INTR_VIG_1_RESET_DONE);
5473 } else if (*isr & (MDSS_MDP_HIST_INTR_VIG_2_DONE |
5474 MDSS_MDP_HIST_INTR_VIG_2_RESET_DONE)) {
5475 blk_idx = MDSS_MDP_SSPP_VIG2;
5476 *isr &= ~(MDSS_MDP_HIST_INTR_VIG_2_DONE |
5477 MDSS_MDP_HIST_INTR_VIG_2_RESET_DONE);
5478 } else {
5479 blk_idx = MDSS_MDP_SSPP_VIG3;
5480 *isr &= ~(MDSS_MDP_HIST_INTR_VIG_3_DONE |
5481 MDSS_MDP_HIST_INTR_VIG_3_RESET_DONE);
5482 }
5483 pipe = mdss_mdp_pipe_search(mdata, BIT(blk_idx),
5484 MDSS_MDP_PIPE_RECT0);
5485 if (IS_ERR_OR_NULL(pipe)) {
5486 pr_debug("pipe DNE, %d\n", blk_idx);
5487 return NULL;
5488 }
5489 hist_info = &pipe->pp_res.hist;
5490 }
5491
5492 return hist_info;
5493}
5494
5495/**
5496 * mdss_mdp_hist_intr_done - Handle histogram interrupts.
5497 * @isr: incoming histogram interrupts as bit mask
5498 *
5499 * This function takes the histogram interrupts received by the
5500 * MDP interrupt handler, and handles each of the interrupts by
5501 * progressing the histogram state if necessary and then clearing
5502 * the interrupt.
5503 */
5504void mdss_mdp_hist_intr_done(u32 isr)
5505{
5506 u32 isr_blk, is_hist_done, isr_tmp;
5507 struct pp_hist_col_info *hist_info = NULL;
5508 u32 isr_mask = HIST_V2_INTR_BIT_MASK;
5509 u32 intr_mask = 1, disp_num = 0;
5510
5511 if (pp_driver_ops.get_hist_isr_info)
5512 pp_driver_ops.get_hist_isr_info(&isr_mask);
5513
5514 isr &= isr_mask;
5515 while (isr != 0) {
5516 isr_tmp = isr;
5517 hist_info = get_hist_info_from_isr(&isr);
5518 if (hist_info == NULL) {
5519 pr_err("hist interrupt gave incorrect blk_idx\n");
5520 continue;
5521 }
5522 isr_blk = (isr_tmp >> hist_info->intr_shift) & 0x3;
5523 is_hist_done = isr_blk & 0x1;
5524 spin_lock(&hist_info->hist_lock);
5525 if (hist_info && is_hist_done && hist_info->col_en &&
5526 hist_info->col_state == HIST_IDLE) {
5527 hist_info->col_state = HIST_READY;
5528 disp_num = hist_info->disp_num;
5529 /* Clear the interrupt until next commit */
5530 mdss_mdp_hist_irq_clear_mask(intr_mask <<
5531 hist_info->intr_shift);
5532 writel_relaxed(1, hist_info->base);
5533 spin_unlock(&hist_info->hist_lock);
5534 mdss_mdp_hist_intr_notify(disp_num);
5535 } else {
5536 spin_unlock(&hist_info->hist_lock);
5537 }
5538 };
5539}
5540
5541static struct msm_fb_data_type *mdss_get_mfd_from_index(int index)
5542{
5543 struct msm_fb_data_type *out = NULL;
5544 struct mdss_mdp_ctl *ctl;
5545 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
5546 int i;
5547
5548 for (i = 0; i < mdata->nctl; i++) {
5549 ctl = mdata->ctl_off + i;
5550 if ((mdss_mdp_ctl_is_power_on(ctl)) && (ctl->mfd)
5551 && (ctl->mfd->index == index))
5552 out = ctl->mfd;
5553 }
5554 return out;
5555}
5556
5557static int pp_num_to_side(struct mdss_mdp_ctl *ctl, u32 num)
5558{
5559 u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
5560 u32 mixer_num;
5561
5562 if (!ctl || !ctl->mfd)
5563 return -EINVAL;
5564 mixer_num = mdss_mdp_get_ctl_mixers(ctl->mfd->index, mixer_id);
5565 if (mixer_num < 2)
5566 return MDSS_SIDE_NONE;
5567 else if (mixer_id[1] == num)
5568 return MDSS_SIDE_RIGHT;
5569 else if (mixer_id[0] == num)
5570 return MDSS_SIDE_LEFT;
5571
5572 pr_err("invalid, not on any side\n");
5573 return -EINVAL;
5574}
5575
5576static int mdss_mdp_get_ad(struct msm_fb_data_type *mfd,
5577 struct mdss_ad_info **ret_ad)
5578{
5579 int ret = 0;
5580 struct mdss_data_type *mdata;
5581 struct mdss_mdp_ctl *ctl = NULL;
5582
5583 *ret_ad = NULL;
5584 if (!mfd) {
5585 pr_err("invalid parameter mfd %pK\n", mfd);
5586 return -EINVAL;
5587 }
5588 mdata = mfd_to_mdata(mfd);
5589
5590 if (mdata->nad_cfgs == 0) {
5591 pr_debug("Assertive Display not supported by device\n");
5592 return -ENODEV;
5593 }
5594
5595 if (!mdss_mdp_mfd_valid_ad(mfd)) {
5596 pr_debug("AD not supported on display num %d hw config\n",
5597 mfd->index);
5598 return -EPERM;
5599 }
5600
5601 if (mfd->panel_info->type == DTV_PANEL) {
5602 pr_debug("AD not supported on external display\n");
5603 return -EPERM;
5604 }
5605
5606 ctl = mfd_to_ctl(mfd);
5607 if ((ctl) && (ctl->mixer_left))
5608 *ret_ad = &mdata->ad_cfgs[ctl->mixer_left->num];
5609 else
5610 ret = -EPERM;
5611
5612 return ret;
5613}
5614
5615/* must call this function from within ad->lock */
5616static int pp_ad_invalidate_input(struct msm_fb_data_type *mfd)
5617{
5618 int ret;
5619 struct mdss_ad_info *ad;
5620
5621 if (!mfd) {
5622 pr_err("Invalid mfd\n");
5623 return -EINVAL;
5624 }
5625
5626 ret = mdss_mdp_get_ad(mfd, &ad);
5627 if (ret == -ENODEV || ret == -EPERM) {
5628 pr_debug("AD not supported on device, disp num %d\n",
5629 mfd->index);
5630 return 0;
5631 } else if (ret || !ad) {
5632 pr_err("Failed to get ad info: ret = %d, ad = 0x%pK\n",
5633 ret, ad);
5634 return ret;
5635 }
5636 pr_debug("AD backlight level changed (%d), trigger update to AD\n",
5637 mfd->ad_bl_level);
5638 if (ad->cfg.mode == MDSS_AD_MODE_AUTO_BL) {
5639 pr_err("AD auto backlight no longer supported.\n");
5640 return -EINVAL;
5641 }
5642
5643 if (ad->state & PP_AD_STATE_RUN) {
5644 ad->calc_itr = ad->cfg.stab_itr;
5645 ad->sts |= PP_AD_STS_DIRTY_VSYNC;
5646 ad->sts |= PP_AD_STS_DIRTY_DATA;
5647 }
5648
5649 return 0;
5650}
5651
5652int mdss_mdp_ad_config(struct msm_fb_data_type *mfd,
5653 struct mdss_ad_init_cfg *init_cfg)
5654{
5655 struct mdss_ad_info *ad;
5656 struct msm_fb_data_type *bl_mfd;
5657 int lin_ret = -1, inv_ret = -1, att_ret = -1, ret = 0;
5658 u32 last_ops;
5659 struct mdss_overlay_private *mdp5_data;
5660
5661 ret = mdss_mdp_get_ad(mfd, &ad);
5662 if (ret == -ENODEV || ret == -EPERM) {
5663 pr_err("AD not supported on device, disp num %d\n",
5664 mfd->index);
5665 return ret;
5666 } else if (ret || !ad) {
5667 pr_err("Failed to get ad info: ret = %d, ad = 0x%pK\n",
5668 ret, ad);
5669 return ret;
5670 }
5671 if (mfd->panel_info->type == WRITEBACK_PANEL) {
5672 bl_mfd = mdss_get_mfd_from_index(0);
5673 if (!bl_mfd)
5674 return ret;
5675 } else {
5676 bl_mfd = mfd;
5677 }
5678
5679 if ((init_cfg->ops & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
5680 pr_warn("Can't set both split bits\n");
5681 return -EINVAL;
5682 }
5683
5684 mutex_lock(&ad->lock);
5685 if (init_cfg->ops & MDP_PP_AD_INIT) {
5686 memcpy(&ad->init, &init_cfg->params.init,
5687 sizeof(struct mdss_ad_init));
5688 if (init_cfg->params.init.bl_lin_len == AD_BL_LIN_LEN) {
5689 lin_ret = copy_from_user(&ad->bl_lin,
5690 init_cfg->params.init.bl_lin,
5691 init_cfg->params.init.bl_lin_len *
5692 sizeof(uint32_t));
5693 inv_ret = copy_from_user(&ad->bl_lin_inv,
5694 init_cfg->params.init.bl_lin_inv,
5695 init_cfg->params.init.bl_lin_len *
5696 sizeof(uint32_t));
5697 if (lin_ret || inv_ret)
5698 ret = -ENOMEM;
5699 } else {
5700 ret = -EINVAL;
5701 }
5702 if (ret) {
5703 ad->state &= ~PP_AD_STATE_BL_LIN;
5704 goto ad_config_exit;
5705 } else
5706 ad->state |= PP_AD_STATE_BL_LIN;
5707
5708 if ((init_cfg->params.init.bl_att_len == AD_BL_ATT_LUT_LEN) &&
5709 (init_cfg->params.init.bl_att_lut)) {
5710 att_ret = copy_from_user(&ad->bl_att_lut,
5711 init_cfg->params.init.bl_att_lut,
5712 init_cfg->params.init.bl_att_len *
5713 sizeof(uint32_t));
5714 if (att_ret)
5715 ret = -ENOMEM;
5716 } else {
5717 ret = -EINVAL;
5718 }
5719 if (ret) {
5720 ad->state &= ~PP_AD_STATE_BL_LIN;
5721 goto ad_config_exit;
5722 } else
5723 ad->state |= PP_AD_STATE_BL_LIN;
5724
5725 ad->sts |= PP_AD_STS_DIRTY_INIT;
5726 } else if (init_cfg->ops & MDP_PP_AD_CFG) {
5727 memcpy(&ad->cfg, &init_cfg->params.cfg,
5728 sizeof(struct mdss_ad_cfg));
5729 if (ad->state & PP_AD_STATE_IPC_RESUME)
5730 ad->cfg.mode |= MDSS_AD_MODE_IPC_BIT;
5731 ad->cfg.backlight_scale = MDSS_MDP_AD_BL_SCALE;
5732 ad->sts |= PP_AD_STS_DIRTY_CFG;
5733 mdp5_data = mfd_to_mdp5_data(mfd);
5734 if (mdp5_data)
5735 mdp5_data->ad_events = 0;
5736 }
5737
5738 last_ops = ad->ops & MDSS_PP_SPLIT_MASK;
5739 ad->ops = init_cfg->ops & MDSS_PP_SPLIT_MASK;
5740 /*
5741 * if there is a change in the split mode config, the init values
5742 * need to be re-written to hardware (if they have already been
5743 * written or if there is data pending to be written). Check for
5744 * pending data (DIRTY_INIT) is not checked here since it will not
5745 * affect the outcome of this conditional (i.e. if init hasn't
5746 * already been written (*_STATE_INIT is set), this conditional will
5747 * only evaluate to true (and set the DIRTY bit) if the DIRTY bit has
5748 * already been set).
5749 */
5750 if ((last_ops ^ ad->ops) && (ad->state & PP_AD_STATE_INIT))
5751 ad->sts |= PP_AD_STS_DIRTY_INIT;
5752
5753
5754 if (!ret && (init_cfg->ops & MDP_PP_OPS_DISABLE)) {
5755 ad->sts &= ~PP_STS_ENABLE;
5756 mutex_unlock(&ad->lock);
5757 cancel_work_sync(&ad->calc_work);
5758 mutex_lock(&ad->lock);
5759 ad->mfd = NULL;
5760 ad->bl_mfd = NULL;
5761 } else if (!ret && (init_cfg->ops & MDP_PP_OPS_ENABLE)) {
5762 ad->sts |= PP_STS_ENABLE;
5763 ad->mfd = mfd;
5764 ad->bl_mfd = bl_mfd;
5765 }
5766ad_config_exit:
5767 mutex_unlock(&ad->lock);
5768 return ret;
5769}
5770
5771int mdss_mdp_ad_input(struct msm_fb_data_type *mfd,
5772 struct mdss_ad_input *input, int wait) {
5773 int ret = 0;
5774 struct mdss_ad_info *ad;
5775 u32 bl;
5776 struct mdss_overlay_private *mdp5_data;
5777
5778 ret = mdss_mdp_get_ad(mfd, &ad);
5779 if (ret == -ENODEV || ret == -EPERM) {
5780 pr_err("AD not supported on device, disp num %d\n",
5781 mfd->index);
5782 return ret;
5783 } else if (ret || !ad) {
5784 pr_err("Failed to get ad info: ret = %d, ad = 0x%pK\n",
5785 ret, ad);
5786 return ret;
5787 }
5788
5789 mutex_lock(&ad->lock);
5790 if ((!PP_AD_STATE_IS_INITCFG(ad->state) &&
5791 !PP_AD_STS_IS_DIRTY(ad->sts)) &&
5792 (input->mode != MDSS_AD_MODE_CALIB)) {
5793 pr_warn("AD not initialized or configured.\n");
5794 ret = -EPERM;
5795 goto error;
5796 }
5797 switch (input->mode) {
5798 case MDSS_AD_MODE_AUTO_BL:
5799 case MDSS_AD_MODE_AUTO_STR:
5800 if (!MDSS_AD_MODE_DATA_MATCH(ad->cfg.mode,
5801 MDSS_AD_INPUT_AMBIENT)) {
5802 pr_err("Invalid mode %x\n", ad->cfg.mode);
5803 ret = -EINVAL;
5804 goto error;
5805 }
5806 if (input->in.amb_light > MDSS_MDP_MAX_AD_AL) {
5807 pr_warn("invalid input ambient light\n");
5808 ret = -EINVAL;
5809 goto error;
5810 }
5811 ad->ad_data_mode = MDSS_AD_INPUT_AMBIENT;
5812 pr_debug("ambient = %d\n", input->in.amb_light);
5813 ad->ad_data = input->in.amb_light;
5814 ad->calc_itr = ad->cfg.stab_itr;
5815 ad->sts |= PP_AD_STS_DIRTY_VSYNC;
5816 ad->sts |= PP_AD_STS_DIRTY_DATA;
5817 mdp5_data = mfd_to_mdp5_data(mfd);
5818 if (mdp5_data)
5819 mdp5_data->ad_events = 0;
5820 break;
5821 case MDSS_AD_MODE_TARG_STR:
5822 case MDSS_AD_MODE_MAN_STR:
5823 if (!MDSS_AD_MODE_DATA_MATCH(ad->cfg.mode,
5824 MDSS_AD_INPUT_STRENGTH)) {
5825 pr_err("Invalid mode %x\n", ad->cfg.mode);
5826 ret = -EINVAL;
5827 goto error;
5828 }
5829 if (input->in.strength > MDSS_MDP_MAX_AD_STR) {
5830 pr_warn("invalid input strength\n");
5831 ret = -EINVAL;
5832 goto error;
5833 }
5834 ad->ad_data_mode = MDSS_AD_INPUT_STRENGTH;
5835 pr_debug("strength = %d\n", input->in.strength);
5836 ad->ad_data = input->in.strength;
5837 ad->calc_itr = ad->cfg.stab_itr;
5838 ad->sts |= PP_AD_STS_DIRTY_VSYNC;
5839 ad->sts |= PP_AD_STS_DIRTY_DATA;
5840 break;
5841 case MDSS_AD_MODE_CALIB:
5842 wait = 0;
5843 if (mfd->calib_mode) {
5844 bl = input->in.calib_bl;
5845 if (bl >= AD_BL_LIN_LEN) {
5846 pr_warn("calib_bl 255 max!\n");
5847 break;
5848 }
5849 mutex_unlock(&ad->lock);
5850 mutex_lock(&mfd->bl_lock);
5851 MDSS_BRIGHT_TO_BL(bl, bl, mfd->panel_info->bl_max,
5852 mfd->panel_info->brightness_max);
5853 mdss_fb_set_backlight(mfd, bl);
5854 mutex_unlock(&mfd->bl_lock);
5855 mutex_lock(&ad->lock);
5856 mfd->calib_mode_bl = bl;
5857 } else {
5858 pr_warn("should be in calib mode\n");
5859 }
5860 break;
5861 default:
5862 pr_warn("invalid default %d\n", input->mode);
5863 ret = -EINVAL;
5864 goto error;
5865 }
5866error:
5867 mutex_unlock(&ad->lock);
5868 return ret;
5869}
5870
5871static void pp_ad_input_write(struct mdss_mdp_ad *ad_hw,
5872 struct mdss_ad_info *ad)
5873{
5874 char __iomem *base;
5875
5876 base = ad_hw->base;
5877 switch (ad->cfg.mode) {
5878 case MDSS_AD_MODE_AUTO_BL:
5879 writel_relaxed(ad->ad_data, base + MDSS_MDP_REG_AD_AL);
5880 break;
5881 case MDSS_AD_MODE_AUTO_STR:
5882 pr_debug("bl_data = %d, ad_data = %d\n", ad->bl_data,
5883 ad->ad_data);
5884 ad->last_ad_data = ad->ad_data;
5885 ad->last_ad_data_valid = true;
5886 writel_relaxed(ad->bl_data, base + MDSS_MDP_REG_AD_BL);
5887 writel_relaxed(ad->ad_data, base + MDSS_MDP_REG_AD_AL);
5888 break;
5889 case MDSS_AD_MODE_TARG_STR:
5890 writel_relaxed(ad->bl_data, base + MDSS_MDP_REG_AD_BL);
5891 writel_relaxed(ad->ad_data, base + MDSS_MDP_REG_AD_TARG_STR);
5892 break;
5893 case MDSS_AD_MODE_MAN_STR:
5894 writel_relaxed(ad->bl_data, base + MDSS_MDP_REG_AD_BL);
5895 writel_relaxed(ad->ad_data, base + MDSS_MDP_REG_AD_STR_MAN);
5896 break;
5897 case MDSS_AD_MODE_MAN_IPC:
5898 if (!ad->last_ad_data_valid) {
5899 ad->last_ad_data = ad->ad_data;
5900 ad->last_ad_data_valid = true;
5901 }
5902 pr_debug("bl_data = %d, last_ad_data = %d, last_str = %d\n",
5903 ad->bl_data, ad->last_ad_data, ad->last_str);
5904 writel_relaxed(ad->bl_data, base + MDSS_MDP_REG_AD_BL);
5905 writel_relaxed(ad->last_ad_data, base + MDSS_MDP_REG_AD_AL);
5906 writel_relaxed(ad->last_str, base + MDSS_MDP_REG_AD_STR_MAN);
5907 break;
5908 default:
5909 pr_warn("Invalid mode! %d\n", ad->cfg.mode);
5910 break;
5911 }
5912}
5913
5914#define MDSS_AD_MERGED_WIDTH 4
5915static void pp_ad_init_write(struct mdss_mdp_ad *ad_hw, struct mdss_ad_info *ad,
5916 struct mdss_mdp_ctl *ctl)
5917{
5918 struct mdss_data_type *mdata = ctl->mdata;
5919 u32 temp, cfg_buf_mode;
5920 u32 frame_start, frame_end, procs_start, procs_end, tile_ctrl;
5921 u32 num;
5922 int side;
5923 char __iomem *base;
5924 bool is_calc, is_dual_pipe, split_mode;
5925 u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
5926 u32 mixer_num;
5927
5928 mixer_num = mdss_mdp_get_ctl_mixers(ctl->mfd->index, mixer_id);
5929 if (mixer_num > 1)
5930 is_dual_pipe = true;
5931 else
5932 is_dual_pipe = false;
5933
5934 base = ad_hw->base;
5935 is_calc = ad->calc_hw_num == ad_hw->num;
5936 split_mode = !!(ad->ops & MDSS_PP_SPLIT_MASK);
5937
5938 writel_relaxed(ad->init.i_control[0] & 0x1F,
5939 base + MDSS_MDP_REG_AD_CON_CTRL_0);
5940 writel_relaxed(ad->init.i_control[1] << 8,
5941 base + MDSS_MDP_REG_AD_CON_CTRL_1);
5942
5943 temp = ad->init.white_lvl << 16;
5944 temp |= ad->init.black_lvl & 0xFFFF;
5945 writel_relaxed(temp, base + MDSS_MDP_REG_AD_BW_LVL);
5946
5947 writel_relaxed(ad->init.var, base + MDSS_MDP_REG_AD_VAR);
5948
5949 writel_relaxed(ad->init.limit_ampl, base + MDSS_MDP_REG_AD_AMP_LIM);
5950
5951 writel_relaxed(ad->init.i_dither, base + MDSS_MDP_REG_AD_DITH);
5952
5953 temp = ad->init.slope_max << 8;
5954 temp |= ad->init.slope_min & 0xFF;
5955 writel_relaxed(temp, base + MDSS_MDP_REG_AD_SLOPE);
5956
5957 writel_relaxed(ad->init.dither_ctl, base + MDSS_MDP_REG_AD_DITH_CTRL);
5958
5959 writel_relaxed(ad->init.format, base + MDSS_MDP_REG_AD_CTRL_0);
5960 writel_relaxed(ad->init.auto_size, base + MDSS_MDP_REG_AD_CTRL_1);
5961
5962 if (split_mode)
5963 temp = mdata->mixer_intf[ad_hw->num].width << 16;
5964 else
5965 temp = ad->init.frame_w << 16;
5966 temp |= ad->init.frame_h & 0xFFFF;
5967 writel_relaxed(temp, base + MDSS_MDP_REG_AD_FRAME_SIZE);
5968
5969 temp = ad->init.logo_v << 8;
5970 temp |= ad->init.logo_h & 0xFF;
5971 writel_relaxed(temp, base + MDSS_MDP_REG_AD_LOGO_POS);
5972
5973 pp_ad_cfg_lut(base + MDSS_MDP_REG_AD_LUT_FI, ad->init.asym_lut);
5974 pp_ad_cfg_lut(base + MDSS_MDP_REG_AD_LUT_CC, ad->init.color_corr_lut);
5975
5976 if (mdata->mdp_rev >= MDSS_MDP_HW_REV_103) {
5977 if (is_dual_pipe && !split_mode) {
5978 num = ad_hw->num;
5979 side = pp_num_to_side(ctl, num);
5980 tile_ctrl = 0x5;
5981 if ((ad->calc_hw_num + 1) == num)
5982 tile_ctrl |= 0x10;
5983
5984 if (side <= MDSS_SIDE_NONE) {
5985 WARN(1, "error finding sides, %d\n", side);
5986 frame_start = 0;
5987 procs_start = frame_start;
5988 frame_end = 0;
5989 procs_end = frame_end;
5990 } else if (side == MDSS_SIDE_LEFT) {
5991 frame_start = 0;
5992 procs_start = 0;
5993 frame_end = mdata->mixer_intf[num].width +
5994 MDSS_AD_MERGED_WIDTH;
5995 procs_end = mdata->mixer_intf[num].width;
5996 } else {
5997 procs_start = ad->init.frame_w -
5998 (mdata->mixer_intf[num].width);
5999 procs_end = ad->init.frame_w;
6000 frame_start = procs_start -
6001 MDSS_AD_MERGED_WIDTH;
6002 frame_end = procs_end;
6003 }
6004 procs_end -= 1;
6005 frame_end -= 1;
6006 cfg_buf_mode = 0x3;
6007 } else {
6008 frame_start = 0x0;
6009 frame_end = 0xFFFF;
6010 procs_start = 0x0;
6011 procs_end = 0xFFFF;
6012 tile_ctrl = 0x0;
6013 cfg_buf_mode = 0x2;
6014 }
6015
6016 writel_relaxed(frame_start, base + MDSS_MDP_REG_AD_FRAME_START);
6017 writel_relaxed(frame_end, base + MDSS_MDP_REG_AD_FRAME_END);
6018 writel_relaxed(procs_start, base + MDSS_MDP_REG_AD_PROCS_START);
6019 writel_relaxed(procs_end, base + MDSS_MDP_REG_AD_PROCS_END);
6020 writel_relaxed(tile_ctrl, base + MDSS_MDP_REG_AD_TILE_CTRL);
6021 writel_relaxed(cfg_buf_mode, base + MDSS_MDP_REG_AD_CFG_BUF);
6022 }
6023}
6024
6025#define MDSS_PP_AD_DEF_CALIB 0x6E
6026static void pp_ad_cfg_write(struct mdss_mdp_ad *ad_hw, struct mdss_ad_info *ad)
6027{
6028 char __iomem *base;
6029 u32 temp, temp_calib = MDSS_PP_AD_DEF_CALIB;
6030
6031 base = ad_hw->base;
6032 switch (ad->cfg.mode) {
6033 case MDSS_AD_MODE_AUTO_BL:
6034 temp = ad->cfg.backlight_max << 16;
6035 temp |= ad->cfg.backlight_min & 0xFFFF;
6036 writel_relaxed(temp, base + MDSS_MDP_REG_AD_BL_MINMAX);
6037 writel_relaxed(ad->cfg.amb_light_min,
6038 base + MDSS_MDP_REG_AD_AL_MIN);
6039 temp = ad->cfg.filter[1] << 16;
6040 temp |= ad->cfg.filter[0] & 0xFFFF;
6041 writel_relaxed(temp, base + MDSS_MDP_REG_AD_AL_FILT);
6042 /* fall-through */
6043 case MDSS_AD_MODE_AUTO_STR:
6044 memcpy(ad->last_calib, ad->cfg.calib, sizeof(ad->last_calib));
6045 ad->last_calib_valid = true;
6046 pp_ad_cfg_lut(base + MDSS_MDP_REG_AD_LUT_AL,
6047 ad->cfg.al_calib_lut);
6048 writel_relaxed(ad->cfg.strength_limit,
6049 base + MDSS_MDP_REG_AD_STR_LIM);
6050 temp = ad->cfg.calib[3] << 16;
6051 temp |= ad->cfg.calib[2] & 0xFFFF;
6052 writel_relaxed(temp, base + MDSS_MDP_REG_AD_CALIB_CD);
6053 writel_relaxed(ad->cfg.t_filter_recursion,
6054 base + MDSS_MDP_REG_AD_TFILT_CTRL);
6055 temp_calib = ad->cfg.calib[0] & 0xFFFF;
6056 /* fall-through */
6057 case MDSS_AD_MODE_TARG_STR:
6058 temp = ad->cfg.calib[1] << 16;
6059 temp |= temp_calib;
6060 writel_relaxed(temp, base + MDSS_MDP_REG_AD_CALIB_AB);
6061 /* fall-through */
6062 case MDSS_AD_MODE_MAN_STR:
6063 writel_relaxed(ad->cfg.backlight_scale,
6064 base + MDSS_MDP_REG_AD_BL_MAX);
6065 writel_relaxed(ad->cfg.mode | MDSS_AD_AUTO_TRIGGER,
6066 base + MDSS_MDP_REG_AD_MODE_SEL);
6067 pr_debug("stab_itr = %d\n", ad->cfg.stab_itr);
6068 break;
6069 case MDSS_AD_MODE_MAN_IPC:
6070 if (!ad->last_calib_valid) {
6071 memcpy(ad->last_calib, ad->cfg.calib,
6072 sizeof(ad->last_calib));
6073 ad->last_calib_valid = true;
6074 }
6075 writel_relaxed(MDSS_AD_T_FILTER_CTRL_0,
6076 base + MDSS_MDP_REG_AD_TFILT_CTRL);
6077 pp_ad_cfg_lut(base + MDSS_MDP_REG_AD_LUT_AL,
6078 ad->cfg.al_calib_lut);
6079 writel_relaxed(ad->cfg.strength_limit,
6080 base + MDSS_MDP_REG_AD_STR_LIM);
6081 temp = ad->last_calib[3] << 16;
6082 temp |= ad->last_calib[2] & 0xFFFF;
6083 writel_relaxed(temp, base + MDSS_MDP_REG_AD_CALIB_CD);
6084 temp_calib = ad->last_calib[0] & 0xFFFF;
6085 temp = ad->last_calib[1] << 16;
6086 temp |= temp_calib;
6087 writel_relaxed(temp, base + MDSS_MDP_REG_AD_CALIB_AB);
6088 writel_relaxed(ad->cfg.backlight_scale,
6089 base + MDSS_MDP_REG_AD_BL_MAX);
6090 writel_relaxed(ad->cfg.mode | MDSS_AD_AUTO_TRIGGER,
6091 base + MDSS_MDP_REG_AD_MODE_SEL);
6092 pr_debug("stab_itr = %d\n", ad->cfg.stab_itr);
6093 break;
6094 default:
6095 break;
6096 }
6097}
6098
6099static void pp_ad_vsync_handler(struct mdss_mdp_ctl *ctl, ktime_t t)
6100{
6101 struct mdss_data_type *mdata = ctl->mdata;
6102 struct mdss_ad_info *ad;
6103
6104 if (ctl->mixer_left && ctl->mixer_left->num < mdata->nad_cfgs) {
6105 ad = &mdata->ad_cfgs[ctl->mixer_left->num];
6106 queue_work(mdata->ad_calc_wq, &ad->calc_work);
6107 }
6108}
6109
6110#define MDSS_PP_AD_BYPASS_DEF 0x101
6111static void pp_ad_bypass_config(struct mdss_ad_info *ad,
6112 struct mdss_mdp_ctl *ctl, u32 num, u32 *opmode)
6113{
6114 int side = pp_num_to_side(ctl, num);
6115
6116 if (pp_sts_is_enabled(ad->reg_sts | (ad->ops & MDSS_PP_SPLIT_MASK),
6117 side)) {
6118 *opmode = 0;
6119 } else {
6120 *opmode = MDSS_PP_AD_BYPASS_DEF;
6121 }
6122}
6123
6124static int pp_ad_setup_hw_nums(struct msm_fb_data_type *mfd,
6125 struct mdss_ad_info *ad)
6126{
6127 u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
6128 u32 mixer_num;
6129
6130 mixer_num = mdss_mdp_get_ctl_mixers(mfd->index, mixer_id);
6131 if (!mixer_num)
6132 return -EINVAL;
6133
6134 /* default to left mixer */
6135 ad->calc_hw_num = mixer_id[0];
6136 if ((mixer_num > 1) && (ad->ops & MDSS_PP_SPLIT_RIGHT_ONLY))
6137 ad->calc_hw_num = mixer_id[1];
6138 return 0;
6139}
6140
6141static int mdss_mdp_ad_ipc_reset(struct msm_fb_data_type *mfd)
6142{
6143 int ret = 0;
6144 struct mdss_ad_info *ad;
6145
6146 if (!mfd) {
6147 pr_err("mfd = 0x%pK\n", mfd);
6148 return -EINVAL;
6149 }
6150
6151 ret = mdss_mdp_get_ad(mfd, &ad);
6152 if (ret == -ENODEV || ret == -EPERM) {
6153 pr_debug("AD not supported on device, disp num %d\n",
6154 mfd->index);
6155 return 0;
6156 } else if (ret || !ad) {
6157 pr_err("Failed to get ad info: ret = %d, ad = 0x%pK\n",
6158 ret, ad);
6159 return ret;
6160 }
6161
6162 mutex_lock(&ad->lock);
6163 if (ad->state & PP_AD_STATE_RUN && ad->state & PP_AD_STATE_IPC_RESET)
6164 ad->state &= ~PP_AD_STATE_IPC_RESET;
6165 mutex_unlock(&ad->lock);
6166
6167 return 0;
6168}
6169
6170static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd)
6171{
6172 int ret = 0;
6173 struct mdss_ad_info *ad;
6174 struct mdss_mdp_ctl *ctl, *sctl;
6175 struct msm_fb_data_type *bl_mfd;
6176 struct mdss_data_type *mdata;
6177 u32 bypass = MDSS_PP_AD_BYPASS_DEF, bl;
6178 u32 width;
6179
6180 if (!mfd) {
6181 pr_err("mfd = 0x%pK\n", mfd);
6182 return -EINVAL;
6183 }
6184
6185 ctl = mfd_to_ctl(mfd);
6186 if (!ctl) {
6187 pr_err("ctl = 0x%pK\n", ctl);
6188 return -EINVAL;
6189 }
6190 sctl = mdss_mdp_get_split_ctl(ctl);
6191
6192 ret = mdss_mdp_get_ad(mfd, &ad);
6193 if (ret == -ENODEV || ret == -EPERM) {
6194 pr_debug("AD not supported on device, disp num %d\n",
6195 mfd->index);
6196 return 0;
6197 } else if (ret || !ad) {
6198 pr_err("Failed to get ad info: ret = %d, ad = 0x%pK\n",
6199 ret, ad);
6200 return ret;
6201 }
6202 if (mfd->panel_info->type == WRITEBACK_PANEL) {
6203 bl_mfd = mdss_get_mfd_from_index(0);
6204 if (!bl_mfd) {
6205 ret = -EINVAL;
6206 pr_warn("failed to get primary FB bl handle, err = %d\n",
6207 ret);
6208 goto exit;
6209 }
6210 } else {
6211 bl_mfd = mfd;
6212 }
6213
6214 mdata = mdss_mdp_get_mdata();
6215
6216 mutex_lock(&ad->lock);
6217 if (ad->state & PP_AD_STATE_RUN && ad->state & PP_AD_STATE_IPC_RESUME) {
6218 if (ad->ipc_frame_count == MDSS_AD_IPC_FRAME_COUNT) {
6219 ad->state &= ~PP_AD_STATE_IPC_RESUME;
6220 ad->state |= PP_AD_STATE_IPC_RESET;
6221 ad->cfg.mode &= ~MDSS_AD_MODE_IPC_BIT;
6222 if (ad->last_ad_data != ad->ad_data)
6223 ad->sts |= PP_AD_STS_DIRTY_DATA;
6224 if (memcmp(ad->last_calib, ad->cfg.calib,
6225 sizeof(ad->last_calib)))
6226 ad->sts |= PP_AD_STS_DIRTY_CFG;
6227 pr_debug("switch mode to %d, last_ad_data = %d\n",
6228 ad->cfg.mode, ad->last_ad_data);
6229 } else {
6230 ad->ipc_frame_count++;
6231 }
6232 }
6233
6234 if (ad->sts != last_sts || ad->state != last_state) {
6235 last_sts = ad->sts;
6236 last_state = ad->state;
6237 pr_debug("beginning: ad->sts = 0x%08x, state = 0x%08x\n",
6238 ad->sts, ad->state);
6239 }
6240
6241 if (ad->sts & PP_AD_STS_DIRTY_DATA) {
6242 ad->sts &= ~PP_AD_STS_DIRTY_DATA;
6243 ad->state |= PP_AD_STATE_DATA;
6244 pr_debug("dirty data, last_bl = %d\n", ad->last_bl);
6245 if (!bl_mfd->ad_bl_level)
6246 bl_mfd->ad_bl_level = bl_mfd->bl_level;
6247 bl = bl_mfd->ad_bl_level;
6248
6249 if (ad->last_bl != bl) {
6250 ad->last_bl = bl;
6251 linear_map(bl, &ad->bl_data,
6252 bl_mfd->panel_info->bl_max,
6253 MDSS_MDP_AD_BL_SCALE);
6254 }
6255 if (!(ad->state & PP_AD_STATE_IPC_RESUME)) {
6256 ad->calc_itr = ad->cfg.stab_itr;
6257 ad->sts |= PP_AD_STS_DIRTY_VSYNC;
6258 }
6259 ad->reg_sts |= PP_AD_STS_DIRTY_DATA;
6260 }
6261
6262 if (ad->sts & PP_AD_STS_DIRTY_CFG) {
6263 ad->sts &= ~PP_AD_STS_DIRTY_CFG;
6264 ad->state |= PP_AD_STATE_CFG;
6265
6266 ad->reg_sts |= PP_AD_STS_DIRTY_CFG;
6267 }
6268 if (ad->sts & PP_AD_STS_DIRTY_INIT) {
6269 ad->sts &= ~PP_AD_STS_DIRTY_INIT;
6270 if (pp_ad_setup_hw_nums(mfd, ad)) {
6271 pr_warn("failed to setup ad master\n");
6272 ad->calc_hw_num = PP_AD_BAD_HW_NUM;
6273 } else {
6274 ad->state |= PP_AD_STATE_INIT;
6275 ad->reg_sts |= PP_AD_STS_DIRTY_INIT;
6276 }
6277 }
6278
6279 width = ctl->width;
6280 if (sctl)
6281 width += sctl->width;
6282
6283 /* update ad screen size if it has changed since last configuration */
6284 if ((ad->init.frame_w != width) ||
6285 (ad->init.frame_h != ctl->height)) {
6286 pr_debug("changing from %dx%d to %dx%d\n", ad->init.frame_w,
6287 ad->init.frame_h,
6288 width,
6289 ctl->height);
6290 ad->init.frame_w = width;
6291 ad->init.frame_h = ctl->height;
6292 ad->reg_sts |= PP_AD_STS_DIRTY_INIT;
6293 }
6294
6295 if ((ad->sts & PP_STS_ENABLE) && PP_AD_STATE_IS_READY(ad->state)) {
6296 bypass = 0;
6297 ad->reg_sts |= PP_AD_STS_DIRTY_ENABLE;
6298 ad->state |= PP_AD_STATE_RUN;
6299 if (bl_mfd != mfd)
6300 bl_mfd->ext_ad_ctrl = mfd->index;
6301 bl_mfd->ext_bl_ctrl = ad->cfg.bl_ctrl_mode;
6302 } else {
6303 if (ad->state & PP_AD_STATE_RUN) {
6304 ad->reg_sts = PP_AD_STS_DIRTY_ENABLE;
6305 /* Clear state and regs when going to off state*/
6306 ad->sts = 0;
6307 ad->sts |= PP_AD_STS_DIRTY_VSYNC;
6308 ad->state &= ~PP_AD_STATE_INIT;
6309 ad->state &= ~PP_AD_STATE_CFG;
6310 ad->state &= ~PP_AD_STATE_DATA;
6311 ad->state &= ~PP_AD_STATE_BL_LIN;
6312 ad->state &= ~PP_AD_STATE_IPC_RESUME;
6313 ad->state &= ~PP_AD_STATE_IPC_RESET;
6314 ad->ad_data = 0;
6315 ad->ad_data_mode = 0;
6316 ad->last_bl = 0;
6317 ad->last_ad_data = 0;
6318 ad->last_calib_valid = false;
6319 ad->last_ad_data_valid = false;
6320 ad->ipc_frame_count = 0;
6321 ad->calc_itr = 0;
6322 ad->calc_hw_num = PP_AD_BAD_HW_NUM;
6323 memset(&ad->last_calib, 0, sizeof(ad->last_calib));
6324 memset(&ad->bl_lin, 0, sizeof(uint32_t) *
6325 AD_BL_LIN_LEN);
6326 memset(&ad->bl_lin_inv, 0, sizeof(uint32_t) *
6327 AD_BL_LIN_LEN);
6328 memset(&ad->bl_att_lut, 0, sizeof(uint32_t) *
6329 AD_BL_ATT_LUT_LEN);
6330 memset(&ad->init, 0, sizeof(struct mdss_ad_init));
6331 memset(&ad->cfg, 0, sizeof(struct mdss_ad_cfg));
6332 bl_mfd->ext_bl_ctrl = 0;
6333 bl_mfd->ext_ad_ctrl = -1;
6334 bl_mfd->ad_bl_level = 0;
6335 }
6336 ad->state &= ~PP_AD_STATE_RUN;
6337 }
6338 if (!bypass)
6339 ad->reg_sts |= PP_STS_ENABLE;
6340 else
6341 ad->reg_sts &= ~PP_STS_ENABLE;
6342
6343 if (PP_AD_STS_DIRTY_VSYNC & ad->sts) {
6344 pr_debug("dirty vsync, calc_itr = %d\n", ad->calc_itr);
6345 ad->sts &= ~PP_AD_STS_DIRTY_VSYNC;
6346 if (!(PP_AD_STATE_VSYNC & ad->state) && ad->calc_itr &&
6347 (ad->state & PP_AD_STATE_RUN)) {
6348 ctl->ops.add_vsync_handler(ctl, &ad->handle);
6349 ad->state |= PP_AD_STATE_VSYNC;
6350 } else if ((PP_AD_STATE_VSYNC & ad->state) &&
6351 (!ad->calc_itr || !(PP_AD_STATE_RUN & ad->state))) {
6352 ctl->ops.remove_vsync_handler(ctl, &ad->handle);
6353 ad->state &= ~PP_AD_STATE_VSYNC;
6354 }
6355 }
6356
6357 if (ad->sts != last_sts || ad->state != last_state) {
6358 last_sts = ad->sts;
6359 last_state = ad->state;
6360 pr_debug("end: ad->sts = 0x%08x, state = 0x%08x\n", ad->sts,
6361 ad->state);
6362 }
6363 mutex_unlock(&ad->lock);
6364exit:
6365 return ret;
6366}
6367
6368#define MDSS_PP_AD_SLEEP 10
6369static void pp_ad_calc_worker(struct work_struct *work)
6370{
6371 struct mdss_ad_info *ad;
6372 struct mdss_mdp_ctl *ctl;
6373 struct mdss_overlay_private *mdp5_data;
6374 struct mdss_data_type *mdata;
6375 char __iomem *base;
6376
6377 ad = container_of(work, struct mdss_ad_info, calc_work);
6378
6379 mutex_lock(&ad->lock);
6380 if (!ad->mfd || !(ad->sts & PP_STS_ENABLE)) {
6381 mutex_unlock(&ad->lock);
6382 return;
6383 }
6384 mdp5_data = mfd_to_mdp5_data(ad->mfd);
6385 if (!mdp5_data) {
6386 pr_err("mdp5_data = 0x%pK\n", mdp5_data);
6387 mutex_unlock(&ad->lock);
6388 return;
6389 }
6390
6391 ctl = mfd_to_ctl(ad->mfd);
6392 mdata = mfd_to_mdata(ad->mfd);
6393 if (!ctl || !mdata || ad->calc_hw_num >= mdata->nad_cfgs) {
6394 pr_err("ctl = 0x%pK, mdata = 0x%pK, ad->calc_hw_num = %d, mdata->nad_cfg = %d\n",
6395 ctl, mdata, ad->calc_hw_num,
6396 (!mdata ? 0 : mdata->nad_cfgs));
6397 mutex_unlock(&ad->lock);
6398 return;
6399 }
6400
6401 base = mdata->ad_off[ad->calc_hw_num].base;
6402
6403 if ((ad->cfg.mode == MDSS_AD_MODE_AUTO_STR) && (ad->last_bl == 0)) {
6404 mutex_unlock(&ad->lock);
6405 return;
6406 }
6407 if ((PP_AD_STATE_RUN & ad->state) && ad->calc_itr > 0)
6408 ad->calc_itr--;
6409
6410 mdp5_data->ad_events++;
6411 sysfs_notify_dirent(mdp5_data->ad_event_sd);
6412 if (!ad->calc_itr) {
6413 ad->state &= ~PP_AD_STATE_VSYNC;
6414 ctl->ops.remove_vsync_handler(ctl, &ad->handle);
6415 }
6416 mutex_unlock(&ad->lock);
6417
6418 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
6419 ad->last_str = 0xFF & readl_relaxed(base + MDSS_MDP_REG_AD_STR_OUT);
6420 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
6421 pr_debug("itr number %d str %d\n", ad->calc_itr, ad->last_str);
6422}
6423
6424#define PP_AD_LUT_LEN 33
6425static void pp_ad_cfg_lut(char __iomem *addr, u32 *data)
6426{
6427 int i;
6428 u32 temp;
6429
6430 for (i = 0; i < PP_AD_LUT_LEN - 1; i += 2) {
6431 temp = data[i+1] << 16;
6432 temp |= (data[i] & 0xFFFF);
6433 writel_relaxed(temp, addr + (i*2));
6434 }
6435 writel_relaxed(data[PP_AD_LUT_LEN - 1] << 16,
6436 addr + ((PP_AD_LUT_LEN - 1) * 2));
6437}
6438
6439/* must call this function from within ad->lock */
6440static int pp_ad_attenuate_bl(struct mdss_ad_info *ad, u32 bl, u32 *bl_out)
6441{
6442 u32 shift = 0, ratio_temp = 0;
6443 u32 n, lut_interval, bl_att;
6444
6445 if (bl < 0 || ad->init.alpha < 0) {
6446 pr_err("Invalid input: backlight = %d, alpha = %d\n", bl,
6447 ad->init.alpha);
6448 return -EINVAL;
6449 }
6450
6451 if (ad->init.alpha == 0) {
6452 pr_debug("alpha = %d, hence no attenuation needed\n",
6453 ad->init.alpha);
6454 return 0;
6455 }
6456 pr_debug("bl_in = %d\n", bl);
6457 /* map panel backlight range to AD backlight range */
6458 linear_map(bl, &bl, ad->bl_mfd->panel_info->bl_max,
6459 MDSS_MDP_AD_BL_SCALE);
6460
6461 pr_debug("Before attenuation = %d\n", bl);
6462 ratio_temp = MDSS_MDP_AD_BL_SCALE / (AD_BL_ATT_LUT_LEN - 1);
6463 while (ratio_temp > 0) {
6464 ratio_temp = ratio_temp >> 1;
6465 shift++;
6466 }
6467 n = bl >> shift;
6468 if (n >= (AD_BL_ATT_LUT_LEN - 1)) {
6469 pr_err("Invalid index for BL attenuation: %d.\n", n);
6470 return -EINVAL;
6471 }
6472 lut_interval = (MDSS_MDP_AD_BL_SCALE + 1) / (AD_BL_ATT_LUT_LEN - 1);
6473 bl_att = ((ad->bl_att_lut[n + 1] - ad->bl_att_lut[n]) *
6474 (bl - lut_interval * n) + (ad->bl_att_lut[n] * lut_interval)) /
6475 lut_interval;
6476 pr_debug("n = %u, bl_att_lut[%u] = %u, bl_att_lut[%u] = %u, bl_att = %u\n",
6477 n, n, ad->bl_att_lut[n], n + 1, ad->bl_att_lut[n + 1], bl_att);
6478 *bl_out = (ad->init.alpha * bl_att +
6479 (ad->init.alpha_base - ad->init.alpha) * bl) /
6480 ad->init.alpha_base;
6481
6482 pr_debug("After attenuation = %d\n", *bl_out);
6483 /* map AD backlight range back to panel backlight range */
6484 linear_map(*bl_out, bl_out, MDSS_MDP_AD_BL_SCALE,
6485 ad->bl_mfd->panel_info->bl_max);
6486
6487 pr_debug("bl_out = %d\n", *bl_out);
6488 return 0;
6489}
6490
6491/* must call this function from within ad->lock */
6492static int pp_ad_linearize_bl(struct mdss_ad_info *ad, u32 bl, u32 *bl_out,
6493 int inv)
6494{
6495
6496 u32 n, bl_lut_max_index = AD_BL_LIN_LEN - 1;
6497 uint32_t *bl_lut = NULL;
6498 int ret = -EINVAL;
6499
6500 if (bl < 0 || bl > ad->bl_mfd->panel_info->bl_max) {
6501 pr_err("Invalid backlight input: bl = %d, bl_max = %d\n", bl,
6502 ad->bl_mfd->panel_info->bl_max);
6503 return -EINVAL;
6504 }
6505
6506 pr_debug("bl_in = %d, inv = %d\n", bl, inv);
6507 if (inv == MDP_PP_AD_BL_LINEAR) {
6508 bl_lut = ad->bl_lin;
6509 } else if (inv == MDP_PP_AD_BL_LINEAR_INV) {
6510 bl_lut = ad->bl_lin_inv;
6511 } else {
6512 pr_err("invalid inv param: inv = %d\n", inv);
6513 return -EINVAL;
6514 }
6515
6516 /* map panel backlight range to AD backlight range */
6517 linear_map(bl, &bl, ad->bl_mfd->panel_info->bl_max,
6518 MDSS_MDP_AD_BL_SCALE);
6519
6520 pr_debug("Before linearization = %d\n", bl);
6521 n = bl * bl_lut_max_index / MDSS_MDP_AD_BL_SCALE;
6522 pr_debug("n = %u\n", n);
6523 if (n > bl_lut_max_index) {
6524 pr_err("Invalid index for BL linearization: %d.\n", n);
6525 return ret;
6526 } else if (n == bl_lut_max_index) {
6527 *bl_out = bl_lut[n];
6528 } else if (bl == n * MDSS_MDP_AD_BL_SCALE / bl_lut_max_index) {
6529 *bl_out = bl_lut[n];
6530 } else if (bl == (n + 1) * MDSS_MDP_AD_BL_SCALE / bl_lut_max_index) {
6531 *bl_out = bl_lut[n + 1];
6532 } else {
6533 /* linear piece-wise interpolation */
6534 *bl_out = ((bl_lut[n + 1] - bl_lut[n]) *
6535 (bl - n * MDSS_MDP_AD_BL_SCALE /
6536 bl_lut_max_index) + bl_lut[n] *
6537 MDSS_MDP_AD_BL_SCALE / bl_lut_max_index) *
6538 bl_lut_max_index / MDSS_MDP_AD_BL_SCALE;
6539 }
6540 pr_debug("After linearization = %d\n", *bl_out);
6541
6542 /* map AD backlight range back to panel backlight range */
6543 linear_map(*bl_out, bl_out, MDSS_MDP_AD_BL_SCALE,
6544 ad->bl_mfd->panel_info->bl_max);
6545
6546 pr_debug("bl_out = %d\n", *bl_out);
6547 return 0;
6548}
6549
6550int mdss_mdp_ad_addr_setup(struct mdss_data_type *mdata, u32 *ad_offsets)
6551{
6552 u32 i;
6553 int rc = 0;
6554
6555 mdata->ad_off = devm_kzalloc(&mdata->pdev->dev,
6556 sizeof(struct mdss_mdp_ad) * mdata->nad_cfgs,
6557 GFP_KERNEL);
6558
6559 if (!mdata->ad_off) {
6560 pr_err("unable to setup assertive display hw:devm_kzalloc fail\n");
6561 return -ENOMEM;
6562 }
6563
6564 mdata->ad_cfgs = devm_kzalloc(&mdata->pdev->dev,
6565 sizeof(struct mdss_ad_info) * mdata->nad_cfgs,
6566 GFP_KERNEL);
6567
6568 if (!mdata->ad_cfgs) {
6569 pr_err("unable to setup assertive display:devm_kzalloc fail\n");
6570 devm_kfree(&mdata->pdev->dev, mdata->ad_off);
6571 return -ENOMEM;
6572 }
6573
6574 mdata->ad_calc_wq = create_singlethread_workqueue("ad_calc_wq");
6575 for (i = 0; i < mdata->nad_cfgs; i++) {
6576 mdata->ad_off[i].base = mdata->mdss_io.base + ad_offsets[i];
6577 mdata->ad_off[i].num = i;
6578 mdata->ad_cfgs[i].num = i;
6579 mdata->ad_cfgs[i].ops = 0;
6580 mdata->ad_cfgs[i].reg_sts = 0;
6581 mdata->ad_cfgs[i].calc_itr = 0;
6582 mdata->ad_cfgs[i].last_str = 0xFFFFFFFF;
6583 mdata->ad_cfgs[i].last_bl = 0;
6584 mdata->ad_cfgs[i].last_ad_data = 0;
6585 memset(mdata->ad_cfgs[i].last_calib, 0,
6586 sizeof(mdata->ad_cfgs[i].last_calib));
6587 mdata->ad_cfgs[i].last_calib_valid = false;
6588 mdata->ad_cfgs[i].last_ad_data_valid = false;
6589 mutex_init(&mdata->ad_cfgs[i].lock);
6590 mdata->ad_cfgs[i].handle.vsync_handler = pp_ad_vsync_handler;
6591 mdata->ad_cfgs[i].handle.cmd_post_flush = true;
6592 INIT_WORK(&mdata->ad_cfgs[i].calc_work, pp_ad_calc_worker);
6593 }
6594 return rc;
6595}
6596
6597static int is_valid_calib_ctrl_addr(char __iomem *ptr)
6598{
6599 char __iomem *base;
6600 int ret = 0, counter = 0;
6601 int stage = 0;
6602 struct mdss_mdp_ctl *ctl;
6603
6604 /* Controller */
6605 for (counter = 0; counter < mdss_res->nctl; counter++) {
6606 ctl = mdss_res->ctl_off + counter;
6607 base = ctl->base;
6608
6609 if (ptr == base + MDSS_MDP_REG_CTL_TOP) {
6610 ret = MDP_PP_OPS_READ;
6611 break;
6612 } else if (ptr == base + MDSS_MDP_REG_CTL_FLUSH) {
6613 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6614 break;
6615 }
6616
6617 for (stage = 0; stage < (mdss_res->nmixers_intf +
6618 mdss_res->nmixers_wb); stage++)
6619 if (ptr == base + MDSS_MDP_REG_CTL_LAYER(stage)) {
6620 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6621 goto End;
6622 }
6623 }
6624
6625End:
6626 return ret;
6627}
6628
6629static int is_valid_calib_dspp_addr(char __iomem *ptr)
6630{
6631 char __iomem *base;
6632 int ret = 0, counter = 0;
6633 struct mdss_mdp_mixer *mixer;
6634
6635 for (counter = 0; counter < mdss_res->nmixers_intf; counter++) {
6636 mixer = mdss_res->mixer_intf + counter;
6637 base = mixer->dspp_base;
6638
6639 if (ptr == base) {
6640 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6641 break;
6642 /* PA range */
6643 } else if ((ptr >= base + MDSS_MDP_REG_DSPP_PA_BASE) &&
6644 (ptr <= base + MDSS_MDP_REG_DSPP_PA_BASE +
6645 MDSS_MDP_PA_SIZE)) {
6646 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6647 break;
6648 /* PCC range */
6649 } else if ((ptr >= base + MDSS_MDP_REG_DSPP_PCC_BASE) &&
6650 (ptr <= base + MDSS_MDP_REG_DSPP_PCC_BASE +
6651 MDSS_MDP_PCC_SIZE)) {
6652 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6653 break;
6654 /* Gamut range */
6655 } else if ((ptr >= base + MDSS_MDP_REG_DSPP_GAMUT_BASE) &&
6656 (ptr <= base + MDSS_MDP_REG_DSPP_GAMUT_BASE +
6657 MDSS_MDP_GAMUT_SIZE)) {
6658 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6659 break;
6660 /* GC range */
6661 } else if ((ptr >= base + MDSS_MDP_REG_DSPP_GC_BASE) &&
6662 (ptr <= base + MDSS_MDP_REG_DSPP_GC_BASE +
6663 MDSS_MDP_GC_SIZE)) {
6664 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6665 break;
6666 /* Dither enable/disable */
6667 } else if ((ptr == base + MDSS_MDP_REG_DSPP_DITHER_DEPTH)) {
6668 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6669 break;
6670 /* Six zone and mem color */
6671 } else if (mdss_res->mdp_rev >= MDSS_MDP_HW_REV_103 &&
6672 (ptr >= base + MDSS_MDP_REG_DSPP_SIX_ZONE_BASE) &&
6673 (ptr <= base + MDSS_MDP_REG_DSPP_SIX_ZONE_BASE +
6674 MDSS_MDP_SIX_ZONE_SIZE +
6675 MDSS_MDP_MEM_COL_SIZE)) {
6676 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6677 break;
6678 }
6679 }
6680
6681 return ret;
6682}
6683
6684static int is_valid_calib_vig_addr(char __iomem *ptr)
6685{
6686 char __iomem *base;
6687 int ret = 0, counter = 0;
6688 struct mdss_mdp_pipe *pipe;
6689
6690 for (counter = 0; counter < mdss_res->nvig_pipes; counter++) {
6691 pipe = mdss_res->vig_pipes + counter;
6692 base = pipe->base;
6693
6694 if (ptr == base + MDSS_MDP_REG_VIG_OP_MODE) {
6695 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6696 break;
6697 } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_FORMAT) {
6698 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6699 break;
6700 } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_CONSTANT_COLOR) {
6701 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6702 break;
6703 } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN) {
6704 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6705 break;
6706 } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_OP_MODE) {
6707 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6708 break;
6709 /* QSEED2 range */
6710 } else if ((ptr >= base + MDSS_MDP_REG_VIG_QSEED2_SHARP) &&
6711 (ptr <= base + MDSS_MDP_REG_VIG_QSEED2_SHARP +
6712 MDSS_MDP_VIG_QSEED2_SHARP_SIZE)) {
6713 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6714 break;
6715 /* PA range */
6716 } else if ((ptr >= base + MDSS_MDP_REG_VIG_PA_BASE) &&
6717 (ptr <= base + MDSS_MDP_REG_VIG_PA_BASE +
6718 MDSS_MDP_PA_SIZE)) {
6719 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6720 break;
6721 /* Mem color range */
6722 } else if (mdss_res->mdp_rev >= MDSS_MDP_HW_REV_103 &&
6723 (ptr >= base + MDSS_MDP_REG_VIG_MEM_COL_BASE) &&
6724 (ptr <= base + MDSS_MDP_REG_VIG_MEM_COL_BASE +
6725 MDSS_MDP_MEM_COL_SIZE)) {
6726 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6727 break;
6728 }
6729 }
6730
6731 return ret;
6732}
6733
6734static int is_valid_calib_rgb_addr(char __iomem *ptr)
6735{
6736 char __iomem *base;
6737 int ret = 0, counter = 0;
6738 struct mdss_mdp_pipe *pipe;
6739
6740 for (counter = 0; counter < mdss_res->nrgb_pipes; counter++) {
6741 pipe = mdss_res->rgb_pipes + counter;
6742 base = pipe->base;
6743
6744 if (ptr == base + MDSS_MDP_REG_SSPP_SRC_FORMAT) {
6745 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6746 break;
6747 } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_CONSTANT_COLOR) {
6748 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6749 break;
6750 } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN) {
6751 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6752 break;
6753 } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_OP_MODE) {
6754 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6755 break;
6756 }
6757 }
6758
6759 return ret;
6760}
6761
6762static int is_valid_calib_dma_addr(char __iomem *ptr)
6763{
6764 char __iomem *base;
6765 int ret = 0, counter = 0;
6766 struct mdss_mdp_pipe *pipe;
6767
6768 for (counter = 0; counter < mdss_res->ndma_pipes; counter++) {
6769 pipe = mdss_res->dma_pipes + counter;
6770 base = pipe->base;
6771
6772 if (ptr == base + MDSS_MDP_REG_SSPP_SRC_FORMAT) {
6773 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6774 break;
6775 } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_CONSTANT_COLOR) {
6776 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6777 break;
6778 } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN) {
6779 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6780 break;
6781 } else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_OP_MODE) {
6782 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6783 break;
6784 }
6785 }
6786
6787 return ret;
6788}
6789
6790static int is_valid_calib_mixer_addr(char __iomem *ptr)
6791{
6792 char __iomem *base;
6793 int ret = 0, counter = 0;
6794 int stage = 0;
6795 struct mdss_mdp_mixer *mixer;
6796
6797 for (counter = 0; counter < (mdss_res->nmixers_intf +
6798 mdss_res->nmixers_wb); counter++) {
6799 mixer = mdss_res->mixer_intf + counter;
6800 base = mixer->base;
6801
6802 if (ptr == base + MDSS_MDP_REG_LM_OP_MODE) {
6803 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6804 break;
6805 /* GC range */
6806 } else if ((ptr >= base + MDSS_MDP_REG_LM_GC_LUT_BASE) &&
6807 (ptr <= base + MDSS_MDP_REG_LM_GC_LUT_BASE +
6808 MDSS_MDP_GC_SIZE)) {
6809 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6810 break;
6811 }
6812
6813 for (stage = 0; stage < TOTAL_BLEND_STAGES; stage++)
6814 if (ptr == base + MDSS_MDP_REG_LM_BLEND_OFFSET(stage) +
6815 MDSS_MDP_REG_LM_BLEND_OP) {
6816 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6817 goto End;
6818 } else if (ptr == base +
6819 MDSS_MDP_REG_LM_BLEND_OFFSET(stage) +
6820 MDSS_MDP_REG_LM_BLEND_FG_ALPHA) {
6821 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6822 goto End;
6823 } else if (ptr == base +
6824 MDSS_MDP_REG_LM_BLEND_OFFSET(stage) +
6825 MDSS_MDP_REG_LM_BLEND_BG_ALPHA) {
6826 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6827 goto End;
6828 }
6829 }
6830
6831End:
6832 return ret;
6833}
6834
6835static int is_valid_calib_addr(void *addr, u32 operation)
6836{
6837 int ret = 0;
6838 char __iomem *ptr = addr;
6839 char __iomem *mixer_base = mdss_res->mixer_intf->base;
6840 char __iomem *ctl_base = mdss_res->ctl_off->base;
6841 char __iomem *dspp_base = mdss_res->mixer_intf->dspp_base;
6842
6843 if ((uintptr_t) addr % 4) {
6844 ret = 0;
6845 } else if (ptr == mdss_res->mdss_io.base + MDSS_REG_HW_VERSION) {
6846 ret = MDP_PP_OPS_READ;
6847 } else if (ptr == (mdss_res->mdp_base + MDSS_MDP_REG_HW_VERSION) ||
6848 ptr == (mdss_res->mdp_base + MDSS_MDP_REG_DISP_INTF_SEL)) {
6849 ret = MDP_PP_OPS_READ;
6850 /* IGC DSPP range */
6851 } else if (ptr >= (mdss_res->mdp_base + MDSS_MDP_REG_IGC_DSPP_BASE) &&
6852 ptr <= (mdss_res->mdp_base + MDSS_MDP_REG_IGC_DSPP_BASE +
6853 MDSS_MDP_IGC_DSPP_SIZE)) {
6854 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6855 /* IGC SSPP range */
6856 } else if (ptr >= (mdss_res->mdp_base + MDSS_MDP_REG_IGC_VIG_BASE) &&
6857 ptr <= (mdss_res->mdp_base + MDSS_MDP_REG_IGC_VIG_BASE +
6858 MDSS_MDP_IGC_SSPP_SIZE)) {
6859 ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
6860 } else {
6861 if (ptr >= dspp_base) {
6862 ret = is_valid_calib_dspp_addr(ptr);
6863 if (ret)
6864 goto valid_addr;
6865 }
6866 if (ptr >= ctl_base) {
6867 ret = is_valid_calib_ctrl_addr(ptr);
6868 if (ret)
6869 goto valid_addr;
6870 }
6871 if (mdss_res->vig_pipes &&
6872 ptr >= mdss_res->vig_pipes->base) {
6873 ret = is_valid_calib_vig_addr(ptr);
6874 if (ret)
6875 goto valid_addr;
6876 }
6877 if (mdss_res->rgb_pipes &&
6878 ptr >= mdss_res->rgb_pipes->base) {
6879 ret = is_valid_calib_rgb_addr(ptr);
6880 if (ret)
6881 goto valid_addr;
6882 }
6883 if (mdss_res->dma_pipes &&
6884 ptr >= mdss_res->dma_pipes->base) {
6885 ret = is_valid_calib_dma_addr(ptr);
6886 if (ret)
6887 goto valid_addr;
6888 }
6889 if (ptr >= mixer_base)
6890 ret = is_valid_calib_mixer_addr(ptr);
6891 }
6892
6893valid_addr:
6894 return ret & operation;
6895}
6896
6897int mdss_mdp_calib_config(struct mdp_calib_config_data *cfg, u32 *copyback)
6898{
6899 int ret = -1;
6900 void *ptr;
6901
6902 /* Calib addrs are always offsets from the MDSS base */
6903 ptr = (void *)((unsigned long) cfg->addr) +
6904 ((uintptr_t) mdss_res->mdss_io.base);
6905 if (is_valid_calib_addr(ptr, cfg->ops))
6906 ret = 0;
6907 else
6908 return ret;
6909
6910 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
6911
6912 if (cfg->ops & MDP_PP_OPS_READ) {
6913 cfg->data = readl_relaxed(ptr);
6914 *copyback = 1;
6915 ret = 0;
6916 } else if (cfg->ops & MDP_PP_OPS_WRITE) {
6917 writel_relaxed(cfg->data, ptr);
6918 ret = 0;
6919 }
6920 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
6921 return ret;
6922}
6923
6924int mdss_mdp_calib_mode(struct msm_fb_data_type *mfd,
6925 struct mdss_calib_cfg *cfg)
6926{
6927 if (!mdss_pp_res || !mfd)
6928 return -EINVAL;
6929 mutex_lock(&mdss_pp_mutex);
6930 mfd->calib_mode = cfg->calib_mask;
6931 mutex_lock(&mfd->bl_lock);
6932 mfd->calib_mode_bl = mfd->bl_level;
6933 mutex_unlock(&mfd->bl_lock);
6934 mutex_unlock(&mdss_pp_mutex);
6935 return 0;
6936}
6937
6938int mdss_mdp_calib_config_buffer(struct mdp_calib_config_buffer *cfg,
6939 u32 *copyback)
6940{
6941 int ret = -1, counter;
6942 uint32_t *buff = NULL, *buff_org = NULL;
6943 void *ptr;
6944 int i = 0;
6945
6946 if (!cfg) {
6947 pr_err("Invalid buffer pointer\n");
6948 return ret;
6949 }
6950
6951 if (cfg->size == 0 || cfg->size > PAGE_SIZE) {
6952 pr_err("Invalid buffer size %d\n", cfg->size);
6953 return ret;
6954 }
6955
6956 counter = cfg->size / (sizeof(uint32_t) * 2);
6957 buff_org = buff = kzalloc(cfg->size, GFP_KERNEL);
6958 if (buff == NULL) {
6959 pr_err("Config buffer allocation failed\n");
6960 return ret;
6961 }
6962
6963 if (copy_from_user(buff, cfg->buffer, cfg->size)) {
6964 kfree(buff);
6965 pr_err("config buffer copy failed\n");
6966 return ret;
6967 }
6968
6969 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
6970
6971 for (i = 0; i < counter; i++) {
6972 ptr = (void *) (((unsigned int) *buff) +
6973 mdss_res->mdss_io.base);
6974
6975 if (!is_valid_calib_addr(ptr, cfg->ops)) {
6976 ret = -1;
6977 pr_err("Address validation failed or access not permitted\n");
6978 break;
6979 }
6980
6981 buff++;
6982 if (cfg->ops & MDP_PP_OPS_READ)
6983 *buff = readl_relaxed(ptr);
6984 else if (cfg->ops & MDP_PP_OPS_WRITE)
6985 writel_relaxed(*buff, ptr);
6986 buff++;
6987 }
6988
6989 if (ret & MDP_PP_OPS_READ) {
6990 ret = copy_to_user(cfg->buffer, buff_org, cfg->size);
6991 *copyback = 1;
6992 }
6993
6994 mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
6995
6996 kfree(buff_org);
6997 return ret;
6998}
6999
7000static int sspp_cache_location(u32 pipe_type, enum pp_config_block *block)
7001{
7002 int ret = 0;
7003
7004 if (!block) {
7005 pr_err("invalid params %pK\n", block);
7006 return -EINVAL;
7007 }
7008 switch (pipe_type) {
7009 case MDSS_MDP_PIPE_TYPE_VIG:
7010 *block = SSPP_VIG;
7011 break;
7012 case MDSS_MDP_PIPE_TYPE_RGB:
7013 *block = SSPP_RGB;
7014 break;
7015 case MDSS_MDP_PIPE_TYPE_DMA:
7016 *block = SSPP_DMA;
7017 break;
7018 default:
7019 pr_err("invalid pipe type %d\n", pipe_type);
7020 ret = -EINVAL;
7021 break;
7022 }
7023 return ret;
7024}
7025
7026int mdss_mdp_pp_sspp_config(struct mdss_mdp_pipe *pipe)
7027{
7028 struct mdp_histogram_start_req hist;
7029 struct mdp_pp_cache_res cache_res;
7030 u32 len = 0;
7031 int ret = 0;
7032
7033 if (!pipe) {
7034 pr_err("invalid params, pipe %pK\n", pipe);
7035 return -EINVAL;
7036 }
7037
7038 cache_res.mdss_pp_res = NULL;
7039 cache_res.pipe_res = pipe;
7040 ret = sspp_cache_location(pipe->type, &cache_res.block);
7041 if (ret) {
7042 pr_err("invalid cache res block for igc ret %d\n",
7043 ret);
7044 goto exit_fail;
7045 }
7046 if ((pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_IGC_CFG)) {
7047 len = pipe->pp_cfg.igc_cfg.len;
7048 if (pp_ops[IGC].pp_set_config) {
7049 ret = pp_igc_lut_cache_params(&pipe->pp_cfg.igc_cfg,
7050 &cache_res, false);
7051 if (ret) {
7052 pr_err("failed to cache igc params ret %d\n",
7053 ret);
7054 goto exit_fail;
7055 }
7056 } else if (len == IGC_LUT_ENTRIES) {
7057 ret = copy_from_user(pipe->pp_res.igc_c0_c1,
7058 pipe->pp_cfg.igc_cfg.c0_c1_data,
7059 sizeof(uint32_t) * len);
7060 if (ret) {
7061 pr_err("failed to copy the igc c0_c1 data\n");
7062 ret = -EFAULT;
7063 goto exit_fail;
7064 }
7065 ret = copy_from_user(pipe->pp_res.igc_c2,
7066 pipe->pp_cfg.igc_cfg.c2_data,
7067 sizeof(uint32_t) * len);
7068 if (ret) {
7069 ret = -EFAULT;
7070 pr_err("failed to copy the igc c2 data\n");
7071 goto exit_fail;
7072 }
7073 pipe->pp_cfg.igc_cfg.c0_c1_data =
7074 pipe->pp_res.igc_c0_c1;
7075 pipe->pp_cfg.igc_cfg.c2_data = pipe->pp_res.igc_c2;
7076 } else
7077 pr_warn("invalid length of IGC len %d\n", len);
7078 }
7079 if (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_HIST_CFG) {
7080 if (pipe->pp_cfg.hist_cfg.ops & MDP_PP_OPS_ENABLE) {
7081 hist.block = pipe->pp_cfg.hist_cfg.block;
7082 hist.frame_cnt =
7083 pipe->pp_cfg.hist_cfg.frame_cnt;
7084 hist.bit_mask = pipe->pp_cfg.hist_cfg.bit_mask;
7085 hist.num_bins = pipe->pp_cfg.hist_cfg.num_bins;
7086 mdss_mdp_hist_start(&hist);
7087 } else if (pipe->pp_cfg.hist_cfg.ops &
7088 MDP_PP_OPS_DISABLE) {
7089 mdss_mdp_hist_stop(pipe->pp_cfg.hist_cfg.block);
7090 }
7091 }
7092 if (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_HIST_LUT_CFG) {
7093 if (!pp_ops[HIST_LUT].pp_set_config) {
7094 len = pipe->pp_cfg.hist_lut_cfg.len;
7095 if (len != ENHIST_LUT_ENTRIES) {
7096 ret = -EINVAL;
7097 pr_err("Invalid hist lut len: %d\n", len);
7098 goto exit_fail;
7099 }
7100 ret = copy_from_user(pipe->pp_res.hist_lut,
7101 pipe->pp_cfg.hist_lut_cfg.data,
7102 sizeof(uint32_t) * len);
7103 if (ret) {
7104 ret = -EFAULT;
7105 pr_err("failed to copy the hist lut\n");
7106 goto exit_fail;
7107 }
7108 pipe->pp_cfg.hist_lut_cfg.data = pipe->pp_res.hist_lut;
7109 } else {
7110 ret = pp_hist_lut_cache_params(
7111 &pipe->pp_cfg.hist_lut_cfg,
7112 &cache_res);
7113 if (ret) {
7114 pr_err("Failed to cache Hist LUT params on pipe %d, ret %d\n",
7115 pipe->num, ret);
7116 goto exit_fail;
7117 }
7118 }
7119 }
7120 if ((pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_PA_V2_CFG) &&
7121 (pp_ops[PA].pp_set_config)) {
7122 ret = pp_pa_cache_params(&pipe->pp_cfg.pa_v2_cfg_data,
7123 &cache_res);
7124 if (ret) {
7125 pr_err("Failed to cache PA params on pipe %d, ret %d\n",
7126 pipe->num, ret);
7127 goto exit_fail;
7128 }
7129 }
7130 if (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_PCC_CFG
7131 && pp_ops[PCC].pp_set_config) {
7132 ret = pp_pcc_cache_params(&pipe->pp_cfg.pcc_cfg_data,
7133 &cache_res);
7134 if (ret) {
7135 pr_err("failed to cache the pcc params ret %d\n", ret);
7136 goto exit_fail;
7137 }
7138 }
7139exit_fail:
7140 if (ret) {
7141 pr_err("VIG PP setup failed on pipe %d type %d ret %d\n",
7142 pipe->num, pipe->type, ret);
7143 pipe->pp_cfg.config_ops = 0;
7144 }
7145
7146 return ret;
7147}
7148
7149static int pp_update_pcc_pipe_setup(struct mdss_mdp_pipe *pipe, u32 location)
7150{
7151 int ret = 0;
7152 struct mdss_data_type *mdata = NULL;
7153 char __iomem *pipe_base = NULL;
7154
7155 if (!pipe) {
7156 pr_err("invalid param pipe %pK\n", pipe);
7157 return -EINVAL;
7158 }
7159
7160 mdata = mdss_mdp_get_mdata();
7161 pipe_base = pipe->base;
7162 switch (location) {
7163 case SSPP_VIG:
7164 if (mdata->pp_block_off.vig_pcc_off == U32_MAX) {
7165 pr_err("invalid offset for vig pcc %d\n",
7166 U32_MAX);
7167 ret = -EINVAL;
7168 goto exit_sspp_setup;
7169 }
7170 pipe_base += mdata->pp_block_off.vig_pcc_off;
7171 break;
7172 case SSPP_RGB:
7173 if (mdata->pp_block_off.rgb_pcc_off == U32_MAX) {
7174 pr_err("invalid offset for rgb pcc %d\n",
7175 U32_MAX);
7176 ret = -EINVAL;
7177 goto exit_sspp_setup;
7178 }
7179 pipe_base += mdata->pp_block_off.rgb_pcc_off;
7180 break;
7181 case SSPP_DMA:
7182 if (mdata->pp_block_off.dma_pcc_off == U32_MAX) {
7183 pr_err("invalid offset for dma pcc %d\n",
7184 U32_MAX);
7185 ret = -EINVAL;
7186 goto exit_sspp_setup;
7187 }
7188 pipe_base += mdata->pp_block_off.dma_pcc_off;
7189 break;
7190 default:
7191 pr_err("invalid location for PCC %d\n",
7192 location);
7193 ret = -EINVAL;
7194 goto exit_sspp_setup;
7195 }
7196 pp_ops[PCC].pp_set_config(pipe_base, &pipe->pp_res.pp_sts,
7197 &pipe->pp_cfg.pcc_cfg_data, location);
7198exit_sspp_setup:
7199 return ret;
7200}
7201
7202int mdss_mdp_pp_get_version(struct mdp_pp_feature_version *version)
7203{
7204 int ret = 0;
7205 u32 ver_info = mdp_pp_legacy;
7206
7207 if (!version) {
7208 pr_err("invalid param version %pK\n", version);
7209 ret = -EINVAL;
7210 goto exit_version;
7211 }
7212 if (version->pp_feature >= PP_FEATURE_MAX) {
7213 pr_err("invalid feature passed %d\n", version->pp_feature);
7214 ret = -EINVAL;
7215 goto exit_version;
7216 }
7217 if (pp_ops[version->pp_feature].pp_get_version)
7218 ret = pp_ops[version->pp_feature].pp_get_version(&ver_info);
7219 if (ret)
7220 pr_err("failed to query version for feature %d ret %d\n",
7221 version->pp_feature, ret);
7222 else
7223 version->version_info = ver_info;
7224exit_version:
7225 return ret;
7226}
7227
7228static void mdss_mdp_hist_irq_set_mask(u32 irq)
7229{
7230 u32 mask;
7231 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
7232
7233 spin_lock(&mdata->hist_intr.lock);
7234 mask = readl_relaxed(mdata->mdp_base + MDSS_MDP_REG_HIST_INTR_EN);
7235 mask |= irq;
7236 pr_debug("interrupt mask being set %x irq updated %x\n", mask, irq);
7237 writel_relaxed(mask, mdata->mdp_base + MDSS_MDP_REG_HIST_INTR_EN);
7238 spin_unlock(&mdata->hist_intr.lock);
7239}
7240
7241static void mdss_mdp_hist_irq_clear_mask(u32 irq)
7242{
7243 u32 mask;
7244 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
7245
7246 spin_lock(&mdata->hist_intr.lock);
7247 mask = readl_relaxed(mdata->mdp_base + MDSS_MDP_REG_HIST_INTR_EN);
7248 mask = mask & ~irq;
7249 pr_debug("interrupt mask being cleared %x irq cleared %x\n", mask, irq);
7250 writel_relaxed(mask, mdata->mdp_base + MDSS_MDP_REG_HIST_INTR_EN);
7251 spin_unlock(&mdata->hist_intr.lock);
7252}
7253
7254static void mdss_mdp_hist_intr_notify(u32 disp)
7255{
7256 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
7257 struct pp_hist_col_info *hist_info = NULL;
7258 int i = 0, disp_count = 0, hist_count = 0;
7259 struct mdss_mdp_ctl *ctl = NULL;
7260 struct mdss_overlay_private *mdp5_data = NULL;
7261
7262 for (i = 0; i < mdata->ndspp; i++) {
7263 hist_info = &mdss_pp_res->dspp_hist[i];
7264 spin_lock(&hist_info->hist_lock);
7265 if (hist_info->disp_num == disp) {
7266 disp_count++;
7267 ctl = hist_info->ctl;
7268 if (hist_info->col_state == HIST_READY)
7269 hist_count++;
7270 }
7271 spin_unlock(&hist_info->hist_lock);
7272 }
7273 if (disp_count != hist_count || !ctl)
7274 return;
7275 mdp5_data = mfd_to_mdp5_data(ctl->mfd);
7276 if (!mdp5_data) {
7277 pr_err("mdp5_data is NULL\n");
7278 return;
7279 }
7280 mdp5_data->hist_events++;
7281 sysfs_notify_dirent(mdp5_data->hist_event_sd);
7282}
7283
7284int mdss_mdp_copy_layer_pp_info(struct mdp_input_layer *layer)
7285{
7286 struct mdp_overlay_pp_params *pp_info = NULL;
7287 int ret = 0;
7288 uint32_t ops;
7289
7290 if (!layer) {
7291 pr_err("invalid layer pointer passed %pK\n", layer);
7292 return -EFAULT;
7293 }
7294
7295 pp_info = kmalloc(sizeof(struct mdp_overlay_pp_params),
7296 GFP_KERNEL);
7297 if (!pp_info)
7298 return -ENOMEM;
7299
7300 ret = copy_from_user(pp_info, layer->pp_info,
7301 sizeof(struct mdp_overlay_pp_params));
7302 if (ret) {
7303 pr_err("layer list copy from user failed, pp_info = %pK\n",
7304 layer->pp_info);
7305 ret = -EFAULT;
7306 goto exit_pp_info;
7307 }
7308
7309 ops = pp_info->config_ops;
7310 if (ops & MDP_OVERLAY_PP_IGC_CFG) {
7311 ret = pp_copy_layer_igc_payload(pp_info);
7312 if (ret) {
7313 pr_err("Failed to copy IGC payload, ret = %d\n", ret);
7314 goto exit_pp_info;
7315 }
7316 } else {
7317 pp_info->igc_cfg.cfg_payload = NULL;
7318 }
7319 if (ops & MDP_OVERLAY_PP_HIST_LUT_CFG) {
7320 ret = pp_copy_layer_hist_lut_payload(pp_info);
7321 if (ret) {
7322 pr_err("Failed to copy Hist LUT payload, ret = %d\n",
7323 ret);
7324 goto exit_igc;
7325 }
7326 } else {
7327 pp_info->hist_lut_cfg.cfg_payload = NULL;
7328 }
7329 if (ops & MDP_OVERLAY_PP_PA_V2_CFG) {
7330 ret = pp_copy_layer_pa_payload(pp_info);
7331 if (ret) {
7332 pr_err("Failed to copy PA payload, ret = %d\n", ret);
7333 goto exit_hist_lut;
7334 }
7335 } else {
7336 pp_info->pa_v2_cfg_data.cfg_payload = NULL;
7337 }
7338 if (ops & MDP_OVERLAY_PP_PCC_CFG) {
7339 ret = pp_copy_layer_pcc_payload(pp_info);
7340 if (ret) {
7341 pr_err("Failed to copy PCC payload, ret = %d\n", ret);
7342 goto exit_pa;
7343 }
7344 } else {
7345 pp_info->pcc_cfg_data.cfg_payload = NULL;
7346 }
7347
7348 layer->pp_info = pp_info;
7349
7350 return ret;
7351
7352exit_pa:
7353 kfree(pp_info->pa_v2_cfg_data.cfg_payload);
7354exit_hist_lut:
7355 kfree(pp_info->hist_lut_cfg.cfg_payload);
7356exit_igc:
7357 kfree(pp_info->igc_cfg.cfg_payload);
7358exit_pp_info:
7359 kfree(pp_info);
7360 return ret;
7361}
7362
7363void mdss_mdp_free_layer_pp_info(struct mdp_input_layer *layer)
7364{
7365 struct mdp_overlay_pp_params *pp_info = (layer) ?
7366 (struct mdp_overlay_pp_params *) layer->pp_info : NULL;
7367
7368 if (!pp_info)
7369 return;
7370
7371 kfree(pp_info->igc_cfg.cfg_payload);
7372 kfree(pp_info->hist_lut_cfg.cfg_payload);
7373 kfree(pp_info->pa_v2_cfg_data.cfg_payload);
7374 kfree(pp_info->pcc_cfg_data.cfg_payload);
7375 kfree(pp_info);
7376 layer->pp_info = NULL;
7377}
7378
7379int mdss_mdp_mfd_valid_dspp(struct msm_fb_data_type *mfd)
7380{
7381 struct mdss_mdp_ctl *ctl = NULL;
7382 int valid_dspp = false;
7383 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
7384
7385 ctl = mfd_to_ctl(mfd);
7386 valid_dspp = (ctl) && (ctl->mixer_left) &&
7387 (ctl->mixer_left->num < mdata->ndspp);
7388 if ((ctl) && (ctl->mixer_right))
7389 valid_dspp &= (ctl->mixer_right->num < mdata->ndspp);
7390 return valid_dspp;
7391}
7392
7393static int mdss_mdp_mfd_valid_ad(struct msm_fb_data_type *mfd)
7394{
7395 struct mdss_mdp_ctl *ctl = NULL;
7396 int valid_ad = false;
7397 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
7398
7399 ctl = mfd_to_ctl(mfd);
7400 valid_ad = (ctl) && (ctl->mixer_left) &&
7401 (ctl->mixer_left->num < mdata->nad_cfgs);
7402 if ((ctl) && (ctl->mixer_right))
7403 valid_ad &= (ctl->mixer_right->num < mdata->nad_cfgs);
7404 return valid_ad;
7405}
7406
7407static int pp_mfd_release_all(struct msm_fb_data_type *mfd)
7408{
7409 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
7410 int ret = 0;
7411
7412 if (!mfd || !mdata) {
7413 pr_err("Invalid mfd %pK mdata %pK\n", mfd, mdata);
7414 return -EPERM;
7415 }
7416
7417 if (mfd->index >= (MDP_BLOCK_MAX - MDP_LOGICAL_BLOCK_DISP_0))
7418 return ret;
7419
7420 if (mdata->nad_cfgs) {
7421 ret = pp_mfd_ad_release_all(mfd);
7422 if (ret)
7423 pr_err("ad release all failed on disp %d, ret %d\n",
7424 mfd->index, ret);
7425 }
7426
7427 if (mdss_mdp_mfd_valid_dspp(mfd))
7428 mdss_mdp_hist_stop(mfd->index + MDP_LOGICAL_BLOCK_DISP_0);
7429 memset(&mdss_pp_res->pp_disp_sts[mfd->index], 0,
7430 sizeof(mdss_pp_res->pp_disp_sts[mfd->index]));
7431 mfd->bl_scale = 1024;
7432
7433 return ret;
7434}
7435
7436static int pp_mfd_ad_release_all(struct msm_fb_data_type *mfd)
7437{
7438 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
7439 struct mdss_mdp_ctl *ctl = NULL;
7440 struct mdss_ad_info *ad = NULL;
7441 int ret = 0;
7442
7443 if (!mdata || !mfd) {
7444 pr_err("invalid params mdata %pK mfd %pK\n", mdata, mfd);
7445 return -EINVAL;
7446 }
7447 if (!mdata->ad_calc_wq)
7448 return 0;
7449
7450 ret = mdss_mdp_get_ad(mfd, &ad);
7451 if (ret == -ENODEV || ret == -EPERM) {
7452 pr_debug("AD not supported on device, disp num %d\n",
7453 mfd->index);
7454 return 0;
7455 } else if (ret) {
7456 pr_err("failed to get ad_info ret %d\n", ret);
7457 return ret;
7458 }
7459 if (!ad->mfd)
7460 return 0;
7461
7462 mutex_lock(&ad->lock);
7463 ad->sts &= ~PP_STS_ENABLE;
7464 ad->mfd = NULL;
7465 ad->bl_mfd = NULL;
7466 ad->state = 0;
7467 mutex_unlock(&ad->lock);
7468 cancel_work_sync(&ad->calc_work);
7469
7470 ctl = mfd_to_ctl(mfd);
7471 if (ctl && ctl->ops.remove_vsync_handler)
7472 ctl->ops.remove_vsync_handler(ctl, &ad->handle);
7473
7474 return ret;
7475}
7476
7477static inline int pp_validate_dspp_mfd_block(struct msm_fb_data_type *mfd,
7478 int block)
7479{
7480 if (!mfd)
7481 return -EINVAL;
7482
7483 if (!mdss_mdp_mfd_valid_dspp(mfd)) {
7484 pr_err("invalid display num %d for PP config\n", mfd->index);
7485 return -EPERM;
7486 }
7487
7488 if ((block < MDP_LOGICAL_BLOCK_DISP_0) ||
7489 (block >= MDP_BLOCK_MAX)) {
7490 pr_err("invalid block %d\n", block);
7491 return -EINVAL;
7492 }
7493
7494 if ((block - MDP_LOGICAL_BLOCK_DISP_0) != mfd->index) {
7495 pr_err("PP block %d does not match corresponding mfd index %d\n",
7496 block, mfd->index);
7497 return -EINVAL;
7498 }
7499
7500 return 0;
7501}
7502
7503static int pp_get_driver_ops(struct mdp_pp_driver_ops *ops)
7504{
7505 struct mdss_data_type *mdata = mdss_mdp_get_mdata();
7506 int ret = 0;
7507 void *pp_cfg = NULL;
7508
7509 switch (mdata->mdp_rev) {
7510 case MDSS_MDP_HW_REV_107:
7511 case MDSS_MDP_HW_REV_107_1:
7512 case MDSS_MDP_HW_REV_107_2:
7513 case MDSS_MDP_HW_REV_114:
7514 case MDSS_MDP_HW_REV_115:
7515 case MDSS_MDP_HW_REV_116:
7516 pp_cfg = pp_get_driver_ops_v1_7(ops);
7517 if (IS_ERR_OR_NULL(pp_cfg))
7518 ret = -EINVAL;
7519 else
7520 mdss_pp_res->pp_data_v1_7 = pp_cfg;
7521 break;
7522 case MDSS_MDP_HW_REV_300:
7523 case MDSS_MDP_HW_REV_301:
7524 pp_cfg = pp_get_driver_ops_v3(ops);
7525 if (IS_ERR_OR_NULL(pp_cfg)) {
7526 ret = -EINVAL;
7527 } else {
7528 mdss_pp_res->pp_data_v1_7 = pp_cfg;
7529 /* Currently all caching data is used from v17 for V3
7530 * hence setting the pointer to NULL. Will be used if we
7531 * have to add any caching specific to V3.
7532 */
7533 mdss_pp_res->pp_data_v3 = NULL;
7534 }
7535 break;
7536 default:
7537 memset(ops, 0, sizeof(struct mdp_pp_driver_ops));
7538 break;
7539 }
7540 return ret;
7541}
7542
7543static int pp_ppb_setup(struct mdss_mdp_mixer *mixer)
7544{
7545 struct pp_sts_type *pp_sts;
7546 struct mdss_mdp_ctl *ctl;
7547 char __iomem *addr;
7548 u32 flags, disp_num;
7549 int ret = 0;
7550
7551 if (!mixer || !mixer->ctl || !mixer->ctl->mfd) {
7552 pr_err("invalid parameters, mixer %pK ctl %pK mfd %pK\n",
7553 mixer, (mixer ? mixer->ctl : NULL),
7554 (mixer ? (mixer->ctl ? mixer->ctl->mfd : NULL) : NULL));
7555 return -EINVAL;
7556 }
7557 ctl = mixer->ctl;
7558 disp_num = ctl->mfd->index;
7559
7560 if (disp_num < MDSS_BLOCK_DISP_NUM)
7561 flags = mdss_pp_res->pp_disp_flags[disp_num];
7562 else
7563 flags = 0;
7564 if ((flags & PP_FLAGS_DIRTY_DITHER)) {
7565 if (pp_ops[DITHER].pp_set_config) {
7566 pp_sts = &mdss_pp_res->pp_disp_sts[disp_num];
7567 addr = mixer->pingpong_base;
7568 /* if dither is supported in PPB function will
7569 * return 0. Failure will indicate that there
7570 * is no DITHER in PPB. In case of error skip the
7571 * programming of CTL flush bits for dither flush.
7572 */
7573 ret = pp_ops[DITHER].pp_set_config(addr, pp_sts,
7574 &mdss_pp_res->dither_disp_cfg[disp_num], PPB);
7575 if (!ret) {
7576 switch (mixer->num) {
7577 case MDSS_MDP_INTF_LAYERMIXER0:
7578 case MDSS_MDP_INTF_LAYERMIXER1:
7579 case MDSS_MDP_INTF_LAYERMIXER2:
7580 ctl->flush_bits |= BIT(13) <<
7581 mixer->num;
7582 break;
7583 case MDSS_MDP_INTF_LAYERMIXER3:
7584 ctl->flush_bits |= BIT(21);
7585 break;
7586 }
7587 }
7588 ret = 0;
7589 }
7590 }
7591 return ret;
7592}