1/*
2 * Copyright 2012-15 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: AMD
23 *
24 */
25
26#include "dm_services.h"
27
28/* include DCE11 register header files */
29#include "dce/dce_11_0_d.h"
30#include "dce/dce_11_0_sh_mask.h"
31
32#include "dce110_transform_v.h"
33
34static void power_on_lut(struct transform *xfm,
35 bool power_on, bool inputgamma, bool regamma)
36{
37 uint32_t value = dm_read_reg(xfm->ctx, mmDCFEV_MEM_PWR_CTRL);
38 int i;
39
40 if (power_on) {
41 if (inputgamma)
42 set_reg_field_value(
43 value,
44 1,
45 DCFEV_MEM_PWR_CTRL,
46 COL_MAN_INPUT_GAMMA_MEM_PWR_DIS);
47 if (regamma)
48 set_reg_field_value(
49 value,
50 1,
51 DCFEV_MEM_PWR_CTRL,
52 COL_MAN_GAMMA_CORR_MEM_PWR_DIS);
53 } else {
54 if (inputgamma)
55 set_reg_field_value(
56 value,
57 0,
58 DCFEV_MEM_PWR_CTRL,
59 COL_MAN_INPUT_GAMMA_MEM_PWR_DIS);
60 if (regamma)
61 set_reg_field_value(
62 value,
63 0,
64 DCFEV_MEM_PWR_CTRL,
65 COL_MAN_GAMMA_CORR_MEM_PWR_DIS);
66 }
67
68 dm_write_reg(xfm->ctx, mmDCFEV_MEM_PWR_CTRL, value);
69
70 for (i = 0; i < 3; i++) {
71 value = dm_read_reg(xfm->ctx, mmDCFEV_MEM_PWR_CTRL);
72 if (get_reg_field_value(value,
73 DCFEV_MEM_PWR_CTRL,
74 COL_MAN_INPUT_GAMMA_MEM_PWR_DIS) &&
75 get_reg_field_value(value,
76 DCFEV_MEM_PWR_CTRL,
77 COL_MAN_GAMMA_CORR_MEM_PWR_DIS))
78 break;
79
80 udelay(2);
81 }
82}
83
84static void set_bypass_input_gamma(struct dce_transform *xfm_dce)
85{
86 uint32_t value;
87
88 value = dm_read_reg(xfm_dce->base.ctx,
89 mmCOL_MAN_INPUT_GAMMA_CONTROL1);
90
91 set_reg_field_value(
92 value,
93 0,
94 COL_MAN_INPUT_GAMMA_CONTROL1,
95 INPUT_GAMMA_MODE);
96
97 dm_write_reg(xfm_dce->base.ctx,
98 mmCOL_MAN_INPUT_GAMMA_CONTROL1, value);
99}
100
101static void configure_regamma_mode(struct dce_transform *xfm_dce, uint32_t mode)
102{
103 uint32_t value = 0;
104
105 set_reg_field_value(
106 value,
107 mode,
108 GAMMA_CORR_CONTROL,
109 GAMMA_CORR_MODE);
110
111 dm_write_reg(xfm_dce->base.ctx, mmGAMMA_CORR_CONTROL, 0);
112}
113
114/*
115 *****************************************************************************
116 * Function: regamma_config_regions_and_segments
117 *
118 * build regamma curve by using predefined hw points
119 * uses interface parameters ,like EDID coeff.
120 *
121 * @param : parameters interface parameters
122 * @return void
123 *
124 * @note
125 *
126 * @see
127 *
128 *****************************************************************************
129 */
130static void regamma_config_regions_and_segments(
131 struct dce_transform *xfm_dce, const struct pwl_params *params)
132{
133 const struct gamma_curve *curve;
134 uint32_t value = 0;
135
136 {
137 set_reg_field_value(
138 value,
139 params->arr_points[0].custom_float_x,
140 GAMMA_CORR_CNTLA_START_CNTL,
141 GAMMA_CORR_CNTLA_EXP_REGION_START);
142
143 set_reg_field_value(
144 value,
145 0,
146 GAMMA_CORR_CNTLA_START_CNTL,
147 GAMMA_CORR_CNTLA_EXP_REGION_START_SEGMENT);
148
149 dm_write_reg(xfm_dce->base.ctx, mmGAMMA_CORR_CNTLA_START_CNTL,
150 value);
151 }
152 {
153 value = 0;
154 set_reg_field_value(
155 value,
156 params->arr_points[0].custom_float_slope,
157 GAMMA_CORR_CNTLA_SLOPE_CNTL,
158 GAMMA_CORR_CNTLA_EXP_REGION_LINEAR_SLOPE);
159
160 dm_write_reg(xfm_dce->base.ctx,
161 mmGAMMA_CORR_CNTLA_SLOPE_CNTL, value);
162 }
163 {
164 value = 0;
165 set_reg_field_value(
166 value,
167 params->arr_points[1].custom_float_x,
168 GAMMA_CORR_CNTLA_END_CNTL1,
169 GAMMA_CORR_CNTLA_EXP_REGION_END);
170
171 dm_write_reg(xfm_dce->base.ctx,
172 mmGAMMA_CORR_CNTLA_END_CNTL1, value);
173 }
174 {
175 value = 0;
176 set_reg_field_value(
177 value,
178 params->arr_points[1].custom_float_slope,
179 GAMMA_CORR_CNTLA_END_CNTL2,
180 GAMMA_CORR_CNTLA_EXP_REGION_END_BASE);
181
182 set_reg_field_value(
183 value,
184 params->arr_points[1].custom_float_y,
185 GAMMA_CORR_CNTLA_END_CNTL2,
186 GAMMA_CORR_CNTLA_EXP_REGION_END_SLOPE);
187
188 dm_write_reg(xfm_dce->base.ctx,
189 mmGAMMA_CORR_CNTLA_END_CNTL2, value);
190 }
191
192 curve = params->arr_curve_points;
193
194 {
195 value = 0;
196 set_reg_field_value(
197 value,
198 curve[0].offset,
199 GAMMA_CORR_CNTLA_REGION_0_1,
200 GAMMA_CORR_CNTLA_EXP_REGION0_LUT_OFFSET);
201
202 set_reg_field_value(
203 value,
204 curve[0].segments_num,
205 GAMMA_CORR_CNTLA_REGION_0_1,
206 GAMMA_CORR_CNTLA_EXP_REGION0_NUM_SEGMENTS);
207
208 set_reg_field_value(
209 value,
210 curve[1].offset,
211 GAMMA_CORR_CNTLA_REGION_0_1,
212 GAMMA_CORR_CNTLA_EXP_REGION1_LUT_OFFSET);
213
214 set_reg_field_value(
215 value,
216 curve[1].segments_num,
217 GAMMA_CORR_CNTLA_REGION_0_1,
218 GAMMA_CORR_CNTLA_EXP_REGION1_NUM_SEGMENTS);
219
220 dm_write_reg(
221 xfm_dce->base.ctx,
222 mmGAMMA_CORR_CNTLA_REGION_0_1,
223 value);
224 }
225
226 curve += 2;
227 {
228 value = 0;
229 set_reg_field_value(
230 value,
231 curve[0].offset,
232 GAMMA_CORR_CNTLA_REGION_2_3,
233 GAMMA_CORR_CNTLA_EXP_REGION2_LUT_OFFSET);
234
235 set_reg_field_value(
236 value,
237 curve[0].segments_num,
238 GAMMA_CORR_CNTLA_REGION_2_3,
239 GAMMA_CORR_CNTLA_EXP_REGION2_NUM_SEGMENTS);
240
241 set_reg_field_value(
242 value,
243 curve[1].offset,
244 GAMMA_CORR_CNTLA_REGION_2_3,
245 GAMMA_CORR_CNTLA_EXP_REGION3_LUT_OFFSET);
246
247 set_reg_field_value(
248 value,
249 curve[1].segments_num,
250 GAMMA_CORR_CNTLA_REGION_2_3,
251 GAMMA_CORR_CNTLA_EXP_REGION3_NUM_SEGMENTS);
252
253 dm_write_reg(xfm_dce->base.ctx,
254 mmGAMMA_CORR_CNTLA_REGION_2_3,
255 value);
256 }
257
258 curve += 2;
259 {
260 value = 0;
261 set_reg_field_value(
262 value,
263 curve[0].offset,
264 GAMMA_CORR_CNTLA_REGION_4_5,
265 GAMMA_CORR_CNTLA_EXP_REGION4_LUT_OFFSET);
266
267 set_reg_field_value(
268 value,
269 curve[0].segments_num,
270 GAMMA_CORR_CNTLA_REGION_4_5,
271 GAMMA_CORR_CNTLA_EXP_REGION4_NUM_SEGMENTS);
272
273 set_reg_field_value(
274 value,
275 curve[1].offset,
276 GAMMA_CORR_CNTLA_REGION_4_5,
277 GAMMA_CORR_CNTLA_EXP_REGION5_LUT_OFFSET);
278
279 set_reg_field_value(
280 value,
281 curve[1].segments_num,
282 GAMMA_CORR_CNTLA_REGION_4_5,
283 GAMMA_CORR_CNTLA_EXP_REGION5_NUM_SEGMENTS);
284
285 dm_write_reg(xfm_dce->base.ctx,
286 mmGAMMA_CORR_CNTLA_REGION_4_5,
287 value);
288 }
289
290 curve += 2;
291 {
292 value = 0;
293 set_reg_field_value(
294 value,
295 curve[0].offset,
296 GAMMA_CORR_CNTLA_REGION_6_7,
297 GAMMA_CORR_CNTLA_EXP_REGION6_LUT_OFFSET);
298
299 set_reg_field_value(
300 value,
301 curve[0].segments_num,
302 GAMMA_CORR_CNTLA_REGION_6_7,
303 GAMMA_CORR_CNTLA_EXP_REGION6_NUM_SEGMENTS);
304
305 set_reg_field_value(
306 value,
307 curve[1].offset,
308 GAMMA_CORR_CNTLA_REGION_6_7,
309 GAMMA_CORR_CNTLA_EXP_REGION7_LUT_OFFSET);
310
311 set_reg_field_value(
312 value,
313 curve[1].segments_num,
314 GAMMA_CORR_CNTLA_REGION_6_7,
315 GAMMA_CORR_CNTLA_EXP_REGION7_NUM_SEGMENTS);
316
317 dm_write_reg(xfm_dce->base.ctx,
318 mmGAMMA_CORR_CNTLA_REGION_6_7,
319 value);
320 }
321
322 curve += 2;
323 {
324 value = 0;
325 set_reg_field_value(
326 value,
327 curve[0].offset,
328 GAMMA_CORR_CNTLA_REGION_8_9,
329 GAMMA_CORR_CNTLA_EXP_REGION8_LUT_OFFSET);
330
331 set_reg_field_value(
332 value,
333 curve[0].segments_num,
334 GAMMA_CORR_CNTLA_REGION_8_9,
335 GAMMA_CORR_CNTLA_EXP_REGION8_NUM_SEGMENTS);
336
337 set_reg_field_value(
338 value,
339 curve[1].offset,
340 GAMMA_CORR_CNTLA_REGION_8_9,
341 GAMMA_CORR_CNTLA_EXP_REGION9_LUT_OFFSET);
342
343 set_reg_field_value(
344 value,
345 curve[1].segments_num,
346 GAMMA_CORR_CNTLA_REGION_8_9,
347 GAMMA_CORR_CNTLA_EXP_REGION9_NUM_SEGMENTS);
348
349 dm_write_reg(xfm_dce->base.ctx,
350 mmGAMMA_CORR_CNTLA_REGION_8_9,
351 value);
352 }
353
354 curve += 2;
355 {
356 value = 0;
357 set_reg_field_value(
358 value,
359 curve[0].offset,
360 GAMMA_CORR_CNTLA_REGION_10_11,
361 GAMMA_CORR_CNTLA_EXP_REGION10_LUT_OFFSET);
362
363 set_reg_field_value(
364 value,
365 curve[0].segments_num,
366 GAMMA_CORR_CNTLA_REGION_10_11,
367 GAMMA_CORR_CNTLA_EXP_REGION10_NUM_SEGMENTS);
368
369 set_reg_field_value(
370 value,
371 curve[1].offset,
372 GAMMA_CORR_CNTLA_REGION_10_11,
373 GAMMA_CORR_CNTLA_EXP_REGION11_LUT_OFFSET);
374
375 set_reg_field_value(
376 value,
377 curve[1].segments_num,
378 GAMMA_CORR_CNTLA_REGION_10_11,
379 GAMMA_CORR_CNTLA_EXP_REGION11_NUM_SEGMENTS);
380
381 dm_write_reg(xfm_dce->base.ctx,
382 mmGAMMA_CORR_CNTLA_REGION_10_11,
383 value);
384 }
385
386 curve += 2;
387 {
388 value = 0;
389 set_reg_field_value(
390 value,
391 curve[0].offset,
392 GAMMA_CORR_CNTLA_REGION_12_13,
393 GAMMA_CORR_CNTLA_EXP_REGION12_LUT_OFFSET);
394
395 set_reg_field_value(
396 value,
397 curve[0].segments_num,
398 GAMMA_CORR_CNTLA_REGION_12_13,
399 GAMMA_CORR_CNTLA_EXP_REGION12_NUM_SEGMENTS);
400
401 set_reg_field_value(
402 value,
403 curve[1].offset,
404 GAMMA_CORR_CNTLA_REGION_12_13,
405 GAMMA_CORR_CNTLA_EXP_REGION13_LUT_OFFSET);
406
407 set_reg_field_value(
408 value,
409 curve[1].segments_num,
410 GAMMA_CORR_CNTLA_REGION_12_13,
411 GAMMA_CORR_CNTLA_EXP_REGION13_NUM_SEGMENTS);
412
413 dm_write_reg(xfm_dce->base.ctx,
414 mmGAMMA_CORR_CNTLA_REGION_12_13,
415 value);
416 }
417
418 curve += 2;
419 {
420 value = 0;
421 set_reg_field_value(
422 value,
423 curve[0].offset,
424 GAMMA_CORR_CNTLA_REGION_14_15,
425 GAMMA_CORR_CNTLA_EXP_REGION14_LUT_OFFSET);
426
427 set_reg_field_value(
428 value,
429 curve[0].segments_num,
430 GAMMA_CORR_CNTLA_REGION_14_15,
431 GAMMA_CORR_CNTLA_EXP_REGION14_NUM_SEGMENTS);
432
433 set_reg_field_value(
434 value,
435 curve[1].offset,
436 GAMMA_CORR_CNTLA_REGION_14_15,
437 GAMMA_CORR_CNTLA_EXP_REGION15_LUT_OFFSET);
438
439 set_reg_field_value(
440 value,
441 curve[1].segments_num,
442 GAMMA_CORR_CNTLA_REGION_14_15,
443 GAMMA_CORR_CNTLA_EXP_REGION15_NUM_SEGMENTS);
444
445 dm_write_reg(xfm_dce->base.ctx,
446 mmGAMMA_CORR_CNTLA_REGION_14_15,
447 value);
448 }
449}
450
451static void program_pwl(struct dce_transform *xfm_dce,
452 const struct pwl_params *params)
453{
454 uint32_t value = 0;
455
456 set_reg_field_value(
457 value,
458 7,
459 GAMMA_CORR_LUT_WRITE_EN_MASK,
460 GAMMA_CORR_LUT_WRITE_EN_MASK);
461
462 dm_write_reg(xfm_dce->base.ctx,
463 mmGAMMA_CORR_LUT_WRITE_EN_MASK, value);
464
465 dm_write_reg(xfm_dce->base.ctx,
466 mmGAMMA_CORR_LUT_INDEX, 0);
467
468 /* Program REGAMMA_LUT_DATA */
469 {
470 const uint32_t addr = mmGAMMA_CORR_LUT_DATA;
471 uint32_t i = 0;
472 const struct pwl_result_data *rgb =
473 params->rgb_resulted;
474
475 while (i != params->hw_points_num) {
476 dm_write_reg(xfm_dce->base.ctx, addr, rgb->red_reg);
477 dm_write_reg(xfm_dce->base.ctx, addr, rgb->green_reg);
478 dm_write_reg(xfm_dce->base.ctx, addr, rgb->blue_reg);
479
480 dm_write_reg(xfm_dce->base.ctx, addr,
481 rgb->delta_red_reg);
482 dm_write_reg(xfm_dce->base.ctx, addr,
483 rgb->delta_green_reg);
484 dm_write_reg(xfm_dce->base.ctx, addr,
485 rgb->delta_blue_reg);
486
487 ++rgb;
488 ++i;
489 }
490 }
491}
492
493void dce110_opp_program_regamma_pwl_v(
494 struct transform *xfm,
495 const struct pwl_params *params)
496{
497 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
498
499 /* Setup regions */
500 regamma_config_regions_and_segments(xfm_dce, params);
501
502 set_bypass_input_gamma(xfm_dce);
503
504 /* Power on gamma LUT memory */
505 power_on_lut(xfm, power_on: true, inputgamma: false, regamma: true);
506
507 /* Program PWL */
508 program_pwl(xfm_dce, params);
509
510 /* program regamma config */
511 configure_regamma_mode(xfm_dce, mode: 1);
512
513 /* Power return to auto back */
514 power_on_lut(xfm, power_on: false, inputgamma: false, regamma: true);
515}
516
517void dce110_opp_power_on_regamma_lut_v(
518 struct transform *xfm,
519 bool power_on)
520{
521 uint32_t value = dm_read_reg(xfm->ctx, mmDCFEV_MEM_PWR_CTRL);
522
523 set_reg_field_value(
524 value,
525 0,
526 DCFEV_MEM_PWR_CTRL,
527 COL_MAN_GAMMA_CORR_MEM_PWR_FORCE);
528
529 set_reg_field_value(
530 value,
531 power_on,
532 DCFEV_MEM_PWR_CTRL,
533 COL_MAN_GAMMA_CORR_MEM_PWR_DIS);
534
535 set_reg_field_value(
536 value,
537 0,
538 DCFEV_MEM_PWR_CTRL,
539 COL_MAN_INPUT_GAMMA_MEM_PWR_FORCE);
540
541 set_reg_field_value(
542 value,
543 power_on,
544 DCFEV_MEM_PWR_CTRL,
545 COL_MAN_INPUT_GAMMA_MEM_PWR_DIS);
546
547 dm_write_reg(xfm->ctx, mmDCFEV_MEM_PWR_CTRL, value);
548}
549
550void dce110_opp_set_regamma_mode_v(
551 struct transform *xfm,
552 enum opp_regamma mode)
553{
554 // TODO: need to implement the function
555}
556

source code of linux/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_regamma_v.c