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 }
558