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, true, false, true);
506
507	/* Program PWL */
508	program_pwl(xfm_dce, params);
509
510	/* program regamma config */
511	configure_regamma_mode(xfm_dce, 1);
512
513	/* Power return to auto back */
514	power_on_lut(xfm, false, false, 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