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