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 #include "basics/conversion.h"
28 
29 #include "dce_opp.h"
30 
31 #include "reg_helper.h"
32 
33 #define REG(reg)\
34 	(opp110->regs->reg)
35 
36 #undef FN
37 #define FN(reg_name, field_name) \
38 	opp110->opp_shift->field_name, opp110->opp_mask->field_name
39 
40 #define CTX \
41 	opp110->base.ctx
42 
43 enum {
44 	MAX_PWL_ENTRY = 128,
45 	MAX_REGIONS_NUMBER = 16
46 };
47 
48 enum {
49 	MAX_LUT_ENTRY = 256,
50 	MAX_NUMBER_OF_ENTRIES = 256
51 };
52 
53 
54 enum {
55 	OUTPUT_CSC_MATRIX_SIZE = 12
56 };
57 
58 static const struct out_csc_color_matrix global_color_matrix[] = {
59 { COLOR_SPACE_SRGB,
60 	{ 0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} },
61 { COLOR_SPACE_SRGB_LIMITED,
62 	{ 0x1B60, 0, 0, 0x200, 0, 0x1B60, 0, 0x200, 0, 0, 0x1B60, 0x200} },
63 { COLOR_SPACE_YCBCR601,
64 	{ 0xE00, 0xF447, 0xFDB9, 0x1000, 0x82F, 0x1012, 0x31F, 0x200, 0xFB47,
65 		0xF6B9, 0xE00, 0x1000} },
66 { COLOR_SPACE_YCBCR709, { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x5D2, 0x1394, 0x1FA,
67 	0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} },
68 /* TODO: correct values below */
69 { COLOR_SPACE_YCBCR601_LIMITED, { 0xE00, 0xF447, 0xFDB9, 0x1000, 0x991,
70 	0x12C9, 0x3A6, 0x200, 0xFB47, 0xF6B9, 0xE00, 0x1000} },
71 { COLOR_SPACE_YCBCR709_LIMITED, { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x6CE, 0x16E3,
72 	0x24F, 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} }
73 };
74 
75 enum csc_color_mode {
76 	/* 00 - BITS2:0 Bypass */
77 	CSC_COLOR_MODE_GRAPHICS_BYPASS,
78 	/* 01 - hard coded coefficient TV RGB */
79 	CSC_COLOR_MODE_GRAPHICS_PREDEFINED,
80 	/* 04 - programmable OUTPUT CSC coefficient */
81 	CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC,
82 };
83 
84 
85 
86 
87 
88 
89 
90 
91 
92 
93 
94 
95 
96 
97 
98 
99 
100 
101 /*
102  *****************************************************************************
103  *  Function: regamma_config_regions_and_segments
104  *
105  *     build regamma curve by using predefined hw points
106  *     uses interface parameters ,like EDID coeff.
107  *
108  * @param   : parameters   interface parameters
109  *  @return void
110  *
111  *  @note
112  *
113  *  @see
114  *
115  *****************************************************************************
116  */
117 static void regamma_config_regions_and_segments(
118 	struct dce110_opp *opp110,
119 	const struct pwl_params *params)
120 {
121 	const struct gamma_curve *curve;
122 
123 	{
124 		REG_SET_2(REGAMMA_CNTLA_START_CNTL, 0,
125 			REGAMMA_CNTLA_EXP_REGION_START, params->arr_points[0].custom_float_x,
126 			REGAMMA_CNTLA_EXP_REGION_START_SEGMENT, 0);
127 	}
128 	{
129 		REG_SET(REGAMMA_CNTLA_SLOPE_CNTL, 0,
130 			REGAMMA_CNTLA_EXP_REGION_LINEAR_SLOPE, params->arr_points[0].custom_float_slope);
131 
132 	}
133 	{
134 		REG_SET(REGAMMA_CNTLA_END_CNTL1, 0,
135 			REGAMMA_CNTLA_EXP_REGION_END, params->arr_points[1].custom_float_x);
136 	}
137 	{
138 		REG_SET_2(REGAMMA_CNTLA_END_CNTL2, 0,
139 			REGAMMA_CNTLA_EXP_REGION_END_BASE, params->arr_points[1].custom_float_y,
140 			REGAMMA_CNTLA_EXP_REGION_END_SLOPE, params->arr_points[2].custom_float_slope);
141 	}
142 
143 	curve = params->arr_curve_points;
144 
145 	{
146 		REG_SET_4(REGAMMA_CNTLA_REGION_0_1, 0,
147 			REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
148 			REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
149 			REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
150 			REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
151 	}
152 
153 	curve += 2;
154 
155 	{
156 		REG_SET_4(REGAMMA_CNTLA_REGION_2_3, 0,
157 			REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
158 			REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
159 			REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
160 			REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
161 
162 	}
163 
164 	curve += 2;
165 
166 	{
167 		REG_SET_4(REGAMMA_CNTLA_REGION_4_5, 0,
168 			REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
169 			REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
170 			REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
171 			REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
172 
173 	}
174 
175 	curve += 2;
176 
177 	{
178 		REG_SET_4(REGAMMA_CNTLA_REGION_6_7, 0,
179 			REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
180 			REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
181 			REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
182 			REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
183 
184 	}
185 
186 	curve += 2;
187 
188 	{
189 		REG_SET_4(REGAMMA_CNTLA_REGION_8_9, 0,
190 			REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
191 			REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
192 			REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
193 			REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
194 
195 	}
196 
197 	curve += 2;
198 
199 	{
200 		REG_SET_4(REGAMMA_CNTLA_REGION_10_11, 0,
201 			REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
202 			REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
203 			REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
204 			REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
205 
206 	}
207 
208 	curve += 2;
209 
210 	{
211 		REG_SET_4(REGAMMA_CNTLA_REGION_12_13, 0,
212 			REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
213 			REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
214 			REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
215 			REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
216 
217 	}
218 
219 	curve += 2;
220 
221 	{
222 		REG_SET_4(REGAMMA_CNTLA_REGION_14_15, 0,
223 			REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
224 			REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
225 			REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
226 			REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
227 	}
228 }
229 
230 static void program_pwl(
231 	struct dce110_opp *opp110,
232 	const struct pwl_params *params)
233 {
234 	uint32_t value;
235 	int retval;
236 
237 	{
238 		uint8_t max_tries = 10;
239 		uint8_t counter = 0;
240 
241 		/* Power on LUT memory */
242 		if (REG(DCFE_MEM_PWR_CTRL))
243 			REG_UPDATE(DCFE_MEM_PWR_CTRL,
244 				DCP_REGAMMA_MEM_PWR_DIS, 1);
245 		else
246 			REG_UPDATE(DCFE_MEM_LIGHT_SLEEP_CNTL,
247 				REGAMMA_LUT_LIGHT_SLEEP_DIS, 1);
248 
249 		while (counter < max_tries) {
250 			if (REG(DCFE_MEM_PWR_STATUS)) {
251 				value = REG_READ(DCFE_MEM_PWR_STATUS);
252 				REG_GET(DCFE_MEM_PWR_STATUS,
253 						DCP_REGAMMA_MEM_PWR_STATE,
254 						&retval);
255 
256 				if (retval == 0)
257 						break;
258 				++counter;
259 			} else {
260 				value = REG_READ(DCFE_MEM_LIGHT_SLEEP_CNTL);
261 				REG_GET(DCFE_MEM_LIGHT_SLEEP_CNTL,
262 						REGAMMA_LUT_MEM_PWR_STATE,
263 						&retval);
264 
265 				if (retval == 0)
266 						break;
267 				++counter;
268 			}
269 		}
270 
271 		if (counter == max_tries) {
272 			dm_logger_write(opp110->base.ctx->logger, LOG_WARNING,
273 				"%s: regamma lut was not powered on "
274 				"in a timely manner,"
275 				" programming still proceeds\n",
276 				__func__);
277 		}
278 	}
279 
280 	REG_UPDATE(REGAMMA_LUT_WRITE_EN_MASK,
281 			REGAMMA_LUT_WRITE_EN_MASK, 7);
282 
283 	REG_WRITE(REGAMMA_LUT_INDEX, 0);
284 
285 	/* Program REGAMMA_LUT_DATA */
286 	{
287 		uint32_t i = 0;
288 		const struct pwl_result_data *rgb = params->rgb_resulted;
289 
290 		while (i != params->hw_points_num) {
291 
292 			REG_WRITE(REGAMMA_LUT_DATA, rgb->red_reg);
293 			REG_WRITE(REGAMMA_LUT_DATA, rgb->green_reg);
294 			REG_WRITE(REGAMMA_LUT_DATA, rgb->blue_reg);
295 			REG_WRITE(REGAMMA_LUT_DATA, rgb->delta_red_reg);
296 			REG_WRITE(REGAMMA_LUT_DATA, rgb->delta_green_reg);
297 			REG_WRITE(REGAMMA_LUT_DATA, rgb->delta_blue_reg);
298 
299 			++rgb;
300 			++i;
301 		}
302 	}
303 
304 	/*  we are done with DCP LUT memory; re-enable low power mode */
305 	if (REG(DCFE_MEM_PWR_CTRL))
306 		REG_UPDATE(DCFE_MEM_PWR_CTRL,
307 			DCP_REGAMMA_MEM_PWR_DIS, 0);
308 	else
309 		REG_UPDATE(DCFE_MEM_LIGHT_SLEEP_CNTL,
310 			REGAMMA_LUT_LIGHT_SLEEP_DIS, 0);
311 }
312 
313 bool dce110_opp_program_regamma_pwl(
314 	struct output_pixel_processor *opp,
315 	const struct pwl_params *params)
316 {
317 	struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
318 
319 	/* Setup regions */
320 	regamma_config_regions_and_segments(opp110, params);
321 
322 	/* Program PWL */
323 	program_pwl(opp110, params);
324 
325 	return true;
326 }
327 
328 void dce110_opp_power_on_regamma_lut(
329 	struct output_pixel_processor *opp,
330 	bool power_on)
331 {
332 	struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
333 
334 	if (REG(DCFE_MEM_PWR_CTRL))
335 		REG_UPDATE_2(DCFE_MEM_PWR_CTRL,
336 			DCP_REGAMMA_MEM_PWR_DIS, power_on,
337 			DCP_LUT_MEM_PWR_DIS, power_on);
338 	else
339 		REG_UPDATE_2(DCFE_MEM_LIGHT_SLEEP_CNTL,
340 			REGAMMA_LUT_LIGHT_SLEEP_DIS, power_on,
341 			DCP_LUT_LIGHT_SLEEP_DIS, power_on);
342 
343 }
344 
345 void dce110_opp_set_regamma_mode(struct output_pixel_processor *opp,
346 		enum opp_regamma mode)
347 {
348 	struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
349 
350 	REG_SET(REGAMMA_CONTROL, 0,
351 			GRPH_REGAMMA_MODE, mode);
352 }
353 
354 /**
355  *	set_truncation
356  *	1) set truncation depth: 0 for 18 bpp or 1 for 24 bpp
357  *	2) enable truncation
358  *	3) HW remove 12bit FMT support for DCE11 power saving reason.
359  */
360 static void set_truncation(
361 		struct dce110_opp *opp110,
362 		const struct bit_depth_reduction_params *params)
363 {
364 	/*Disable truncation*/
365 	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
366 			FMT_TRUNCATE_EN, 0,
367 			FMT_TRUNCATE_DEPTH, 0,
368 			FMT_TRUNCATE_MODE, 0);
369 
370 
371 	if (params->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
372 		/*  8bpc trunc on YCbCr422*/
373 		if (params->flags.TRUNCATE_DEPTH == 1)
374 			REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
375 					FMT_TRUNCATE_EN, 1,
376 					FMT_TRUNCATE_DEPTH, 1,
377 					FMT_TRUNCATE_MODE, 0);
378 		else if (params->flags.TRUNCATE_DEPTH == 2)
379 			/*  10bpc trunc on YCbCr422*/
380 			REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
381 					FMT_TRUNCATE_EN, 1,
382 					FMT_TRUNCATE_DEPTH, 2,
383 					FMT_TRUNCATE_MODE, 0);
384 		return;
385 	}
386 	/* on other format-to do */
387 	if (params->flags.TRUNCATE_ENABLED == 0 ||
388 			params->flags.TRUNCATE_DEPTH == 2)
389 		return;
390 	/*Set truncation depth and Enable truncation*/
391 	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
392 				FMT_TRUNCATE_EN, 1,
393 				FMT_TRUNCATE_DEPTH,
394 				params->flags.TRUNCATE_MODE,
395 				FMT_TRUNCATE_MODE,
396 				params->flags.TRUNCATE_DEPTH);
397 }
398 
399 
400 /**
401  *	set_spatial_dither
402  *	1) set spatial dithering mode: pattern of seed
403  *	2) set spatical dithering depth: 0 for 18bpp or 1 for 24bpp
404  *	3) set random seed
405  *	4) set random mode
406  *		lfsr is reset every frame or not reset
407  *		RGB dithering method
408  *		0: RGB data are all dithered with x^28+x^3+1
409  *		1: R data is dithered with x^28+x^3+1
410  *		G data is dithered with x^28+X^9+1
411  *		B data is dithered with x^28+x^13+1
412  *		enable high pass filter or not
413  *	5) enable spatical dithering
414  */
415 static void set_spatial_dither(
416 	struct dce110_opp *opp110,
417 	const struct bit_depth_reduction_params *params)
418 {
419 	/*Disable spatial (random) dithering*/
420 	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
421 		FMT_SPATIAL_DITHER_EN, 0,
422 		FMT_SPATIAL_DITHER_DEPTH, 0,
423 		FMT_SPATIAL_DITHER_MODE, 0);
424 
425 	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
426 		FMT_HIGHPASS_RANDOM_ENABLE, 0,
427 		FMT_FRAME_RANDOM_ENABLE, 0,
428 		FMT_RGB_RANDOM_ENABLE, 0);
429 
430 	REG_UPDATE(FMT_BIT_DEPTH_CONTROL,
431 		FMT_TEMPORAL_DITHER_EN, 0);
432 
433 	/* no 10bpc on DCE11*/
434 	if (params->flags.SPATIAL_DITHER_ENABLED == 0 ||
435 		params->flags.SPATIAL_DITHER_DEPTH == 2)
436 		return;
437 
438 	/* only use FRAME_COUNTER_MAX if frameRandom == 1*/
439 
440 	if (opp110->opp_mask->FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX &&
441 			opp110->opp_mask->FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP) {
442 		if (params->flags.FRAME_RANDOM == 1) {
443 			if (params->flags.SPATIAL_DITHER_DEPTH == 0 ||
444 			params->flags.SPATIAL_DITHER_DEPTH == 1) {
445 				REG_UPDATE_2(FMT_CONTROL,
446 					FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 15,
447 					FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 2);
448 			} else if (params->flags.SPATIAL_DITHER_DEPTH == 2) {
449 				REG_UPDATE_2(FMT_CONTROL,
450 					FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 3,
451 					FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 1);
452 			} else
453 				return;
454 		} else {
455 			REG_UPDATE_2(FMT_CONTROL,
456 					FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 0,
457 					FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 0);
458 		}
459 	}
460 	/* Set seed for random values for
461 	 * spatial dithering for R,G,B channels
462 	 */
463 	REG_UPDATE(FMT_DITHER_RAND_R_SEED,
464 			FMT_RAND_R_SEED, params->r_seed_value);
465 
466 	REG_UPDATE(FMT_DITHER_RAND_G_SEED,
467 			FMT_RAND_G_SEED, params->g_seed_value);
468 
469 	REG_UPDATE(FMT_DITHER_RAND_B_SEED,
470 			FMT_RAND_B_SEED, params->b_seed_value);
471 
472 	/* FMT_OFFSET_R_Cr  31:16 0x0 Setting the zero
473 	 * offset for the R/Cr channel, lower 4LSB
474 	 * is forced to zeros. Typically set to 0
475 	 * RGB and 0x80000 YCbCr.
476 	 */
477 	/* FMT_OFFSET_G_Y   31:16 0x0 Setting the zero
478 	 * offset for the G/Y  channel, lower 4LSB is
479 	 * forced to zeros. Typically set to 0 RGB
480 	 * and 0x80000 YCbCr.
481 	 */
482 	/* FMT_OFFSET_B_Cb  31:16 0x0 Setting the zero
483 	 * offset for the B/Cb channel, lower 4LSB is
484 	 * forced to zeros. Typically set to 0 RGB and
485 	 * 0x80000 YCbCr.
486 	 */
487 
488 	/* Disable High pass filter
489 	 * Reset only at startup
490 	 * Set RGB data dithered with x^28+x^3+1
491 	 */
492 	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
493 		FMT_HIGHPASS_RANDOM_ENABLE, params->flags.HIGHPASS_RANDOM,
494 		FMT_FRAME_RANDOM_ENABLE, params->flags.FRAME_RANDOM,
495 		FMT_RGB_RANDOM_ENABLE, params->flags.RGB_RANDOM);
496 
497 	/* Set spatial dithering bit depth
498 	 * Set spatial dithering mode
499 	 * (default is Seed patterrn AAAA...)
500 	 * Enable spatial dithering
501 	 */
502 	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
503 		FMT_SPATIAL_DITHER_DEPTH, params->flags.SPATIAL_DITHER_DEPTH,
504 		FMT_SPATIAL_DITHER_MODE, params->flags.SPATIAL_DITHER_MODE,
505 		FMT_SPATIAL_DITHER_EN, 1);
506 }
507 
508 /**
509  *	SetTemporalDither (Frame Modulation)
510  *	1) set temporal dither depth
511  *	2) select pattern: from hard-coded pattern or programmable pattern
512  *	3) select optimized strips for BGR or RGB LCD sub-pixel
513  *	4) set s matrix
514  *	5) set t matrix
515  *	6) set grey level for 0.25, 0.5, 0.75
516  *	7) enable temporal dithering
517  */
518 
519 static void set_temporal_dither(
520 	struct dce110_opp *opp110,
521 	const struct bit_depth_reduction_params *params)
522 {
523 	/*Disable temporal (frame modulation) dithering first*/
524 	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
525 		FMT_TEMPORAL_DITHER_EN, 0,
526 		FMT_TEMPORAL_DITHER_RESET, 0,
527 		FMT_TEMPORAL_DITHER_OFFSET, 0);
528 
529 	REG_UPDATE_2(FMT_BIT_DEPTH_CONTROL,
530 		FMT_TEMPORAL_DITHER_DEPTH, 0,
531 		FMT_TEMPORAL_LEVEL, 0);
532 
533 	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
534 		FMT_25FRC_SEL, 0,
535 		FMT_50FRC_SEL, 0,
536 		FMT_75FRC_SEL, 0);
537 
538 	/* no 10bpc dither on DCE11*/
539 	if (params->flags.FRAME_MODULATION_ENABLED == 0 ||
540 		params->flags.FRAME_MODULATION_DEPTH == 2)
541 		return;
542 
543 	/* Set temporal dithering depth*/
544 	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
545 		FMT_TEMPORAL_DITHER_DEPTH, params->flags.FRAME_MODULATION_DEPTH,
546 		FMT_TEMPORAL_DITHER_RESET, 0,
547 		FMT_TEMPORAL_DITHER_OFFSET, 0);
548 
549 	/*Select legacy pattern based on FRC and Temporal level*/
550 	if (REG(FMT_TEMPORAL_DITHER_PATTERN_CONTROL)) {
551 		REG_WRITE(FMT_TEMPORAL_DITHER_PATTERN_CONTROL, 0);
552 		/*Set s matrix*/
553 		REG_WRITE(FMT_TEMPORAL_DITHER_PROGRAMMABLE_PATTERN_S_MATRIX, 0);
554 		/*Set t matrix*/
555 		REG_WRITE(FMT_TEMPORAL_DITHER_PROGRAMMABLE_PATTERN_T_MATRIX, 0);
556 	}
557 
558 	/*Select patterns for 0.25, 0.5 and 0.75 grey level*/
559 	REG_UPDATE(FMT_BIT_DEPTH_CONTROL,
560 		FMT_TEMPORAL_LEVEL, params->flags.TEMPORAL_LEVEL);
561 
562 	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
563 		FMT_25FRC_SEL, params->flags.FRC25,
564 		FMT_50FRC_SEL, params->flags.FRC50,
565 		FMT_75FRC_SEL, params->flags.FRC75);
566 
567 	/*Enable bit reduction by temporal (frame modulation) dithering*/
568 	REG_UPDATE(FMT_BIT_DEPTH_CONTROL,
569 		FMT_TEMPORAL_DITHER_EN, 1);
570 }
571 
572 /**
573  *	Set Clamping
574  *	1) Set clamping format based on bpc - 0 for 6bpc (No clamping)
575  *		1 for 8 bpc
576  *		2 for 10 bpc
577  *		3 for 12 bpc
578  *		7 for programable
579  *	2) Enable clamp if Limited range requested
580  */
581 void dce110_opp_set_clamping(
582 	struct dce110_opp *opp110,
583 	const struct clamping_and_pixel_encoding_params *params)
584 {
585 	REG_SET_2(FMT_CLAMP_CNTL, 0,
586 		FMT_CLAMP_DATA_EN, 0,
587 		FMT_CLAMP_COLOR_FORMAT, 0);
588 
589 	switch (params->clamping_level) {
590 	case CLAMPING_FULL_RANGE:
591 		break;
592 	case CLAMPING_LIMITED_RANGE_8BPC:
593 		REG_SET_2(FMT_CLAMP_CNTL, 0,
594 			FMT_CLAMP_DATA_EN, 1,
595 			FMT_CLAMP_COLOR_FORMAT, 1);
596 		break;
597 	case CLAMPING_LIMITED_RANGE_10BPC:
598 		REG_SET_2(FMT_CLAMP_CNTL, 0,
599 			FMT_CLAMP_DATA_EN, 1,
600 			FMT_CLAMP_COLOR_FORMAT, 2);
601 		break;
602 	case CLAMPING_LIMITED_RANGE_12BPC:
603 		REG_SET_2(FMT_CLAMP_CNTL, 0,
604 			FMT_CLAMP_DATA_EN, 1,
605 			FMT_CLAMP_COLOR_FORMAT, 3);
606 		break;
607 	case CLAMPING_LIMITED_RANGE_PROGRAMMABLE:
608 		/*Set clamp control*/
609 		REG_SET_2(FMT_CLAMP_CNTL, 0,
610 			FMT_CLAMP_DATA_EN, 1,
611 			FMT_CLAMP_COLOR_FORMAT, 7);
612 
613 		/*set the defaults*/
614 		REG_SET_2(FMT_CLAMP_COMPONENT_R, 0,
615 			FMT_CLAMP_LOWER_R, 0x10,
616 			FMT_CLAMP_UPPER_R, 0xFEF);
617 
618 		REG_SET_2(FMT_CLAMP_COMPONENT_G, 0,
619 			FMT_CLAMP_LOWER_G, 0x10,
620 			FMT_CLAMP_UPPER_G, 0xFEF);
621 
622 		REG_SET_2(FMT_CLAMP_COMPONENT_B, 0,
623 			FMT_CLAMP_LOWER_B, 0x10,
624 			FMT_CLAMP_UPPER_B, 0xFEF);
625 		break;
626 	default:
627 		break;
628 	}
629 }
630 
631 /**
632  *	set_pixel_encoding
633  *
634  *	Set Pixel Encoding
635  *		0: RGB 4:4:4 or YCbCr 4:4:4 or YOnly
636  *		1: YCbCr 4:2:2
637  */
638 static void set_pixel_encoding(
639 	struct dce110_opp *opp110,
640 	const struct clamping_and_pixel_encoding_params *params)
641 {
642 	if (opp110->opp_mask->FMT_CBCR_BIT_REDUCTION_BYPASS)
643 		REG_UPDATE_3(FMT_CONTROL,
644 				FMT_PIXEL_ENCODING, 0,
645 				FMT_SUBSAMPLING_MODE, 0,
646 				FMT_CBCR_BIT_REDUCTION_BYPASS, 0);
647 	else
648 		REG_UPDATE_2(FMT_CONTROL,
649 				FMT_PIXEL_ENCODING, 0,
650 				FMT_SUBSAMPLING_MODE, 0);
651 
652 	if (params->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
653 		REG_UPDATE_2(FMT_CONTROL,
654 				FMT_PIXEL_ENCODING, 1,
655 				FMT_SUBSAMPLING_ORDER, 0);
656 	}
657 	if (params->pixel_encoding == PIXEL_ENCODING_YCBCR420) {
658 		REG_UPDATE_3(FMT_CONTROL,
659 				FMT_PIXEL_ENCODING, 2,
660 				FMT_SUBSAMPLING_MODE, 2,
661 				FMT_CBCR_BIT_REDUCTION_BYPASS, 1);
662 	}
663 
664 }
665 
666 void dce110_opp_program_bit_depth_reduction(
667 	struct output_pixel_processor *opp,
668 	const struct bit_depth_reduction_params *params)
669 {
670 	struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
671 
672 	set_truncation(opp110, params);
673 	set_spatial_dither(opp110, params);
674 	set_temporal_dither(opp110, params);
675 }
676 
677 void dce110_opp_program_clamping_and_pixel_encoding(
678 	struct output_pixel_processor *opp,
679 	const struct clamping_and_pixel_encoding_params *params)
680 {
681 	struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
682 
683 	dce110_opp_set_clamping(opp110, params);
684 	set_pixel_encoding(opp110, params);
685 }
686 
687 static void program_formatter_420_memory(struct output_pixel_processor *opp)
688 {
689 	struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
690 	uint32_t fmt_mem_cntl_value;
691 
692 	/* Program source select*/
693 	/* Use HW default source select for FMT_MEMORYx_CONTROL */
694 	/* Use that value for FMT_SRC_SELECT as well*/
695 	REG_GET(CONTROL,
696 			FMT420_MEM0_SOURCE_SEL, &fmt_mem_cntl_value);
697 
698 	REG_UPDATE(FMT_CONTROL,
699 			FMT_SRC_SELECT, fmt_mem_cntl_value);
700 
701 	/* Turn on the memory */
702 	REG_UPDATE(CONTROL,
703 			FMT420_MEM0_PWR_FORCE, 0);
704 }
705 
706 void dce110_opp_set_dyn_expansion(
707 	struct output_pixel_processor *opp,
708 	enum dc_color_space color_sp,
709 	enum dc_color_depth color_dpth,
710 	enum signal_type signal)
711 {
712 	struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
713 
714 	REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
715 			FMT_DYNAMIC_EXP_EN, 0,
716 			FMT_DYNAMIC_EXP_MODE, 0);
717 
718 	/*00 - 10-bit -> 12-bit dynamic expansion*/
719 	/*01 - 8-bit  -> 12-bit dynamic expansion*/
720 	if (signal == SIGNAL_TYPE_HDMI_TYPE_A ||
721 		signal == SIGNAL_TYPE_DISPLAY_PORT ||
722 		signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
723 		switch (color_dpth) {
724 		case COLOR_DEPTH_888:
725 			REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
726 				FMT_DYNAMIC_EXP_EN, 1,
727 				FMT_DYNAMIC_EXP_MODE, 1);
728 			break;
729 		case COLOR_DEPTH_101010:
730 			REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
731 				FMT_DYNAMIC_EXP_EN, 1,
732 				FMT_DYNAMIC_EXP_MODE, 0);
733 			break;
734 		case COLOR_DEPTH_121212:
735 			REG_UPDATE_2(
736 				FMT_DYNAMIC_EXP_CNTL,
737 				FMT_DYNAMIC_EXP_EN, 1,/*otherwise last two bits are zero*/
738 				FMT_DYNAMIC_EXP_MODE, 0);
739 			break;
740 		default:
741 			break;
742 		}
743 	}
744 }
745 
746 static void program_formatter_reset_dig_resync_fifo(struct output_pixel_processor *opp)
747 {
748 	struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
749 
750 	/* clear previous phase lock status*/
751 	REG_UPDATE(FMT_CONTROL,
752 			FMT_420_PIXEL_PHASE_LOCKED_CLEAR, 1);
753 
754 	/* poll until FMT_420_PIXEL_PHASE_LOCKED become 1*/
755 	REG_WAIT(FMT_CONTROL, FMT_420_PIXEL_PHASE_LOCKED, 1, 10, 10);
756 
757 }
758 
759 void dce110_opp_program_fmt(
760 	struct output_pixel_processor *opp,
761 	struct bit_depth_reduction_params *fmt_bit_depth,
762 	struct clamping_and_pixel_encoding_params *clamping)
763 {
764 	/* dithering is affected by <CrtcSourceSelect>, hence should be
765 	 * programmed afterwards */
766 
767 	if (clamping->pixel_encoding == PIXEL_ENCODING_YCBCR420)
768 		program_formatter_420_memory(opp);
769 
770 	dce110_opp_program_bit_depth_reduction(
771 		opp,
772 		fmt_bit_depth);
773 
774 	dce110_opp_program_clamping_and_pixel_encoding(
775 		opp,
776 		clamping);
777 
778 	if (clamping->pixel_encoding == PIXEL_ENCODING_YCBCR420)
779 		program_formatter_reset_dig_resync_fifo(opp);
780 
781 	return;
782 }
783 
784 static void program_color_matrix(
785 	struct dce110_opp *opp110,
786 	const struct out_csc_color_matrix *tbl_entry,
787 	enum grph_color_adjust_option options)
788 {
789 	{
790 		REG_SET_2(OUTPUT_CSC_C11_C12, 0,
791 			OUTPUT_CSC_C11, tbl_entry->regval[0],
792 			OUTPUT_CSC_C12, tbl_entry->regval[1]);
793 	}
794 	{
795 		REG_SET_2(OUTPUT_CSC_C13_C14, 0,
796 			OUTPUT_CSC_C11, tbl_entry->regval[2],
797 			OUTPUT_CSC_C12, tbl_entry->regval[3]);
798 	}
799 	{
800 		REG_SET_2(OUTPUT_CSC_C21_C22, 0,
801 			OUTPUT_CSC_C11, tbl_entry->regval[4],
802 			OUTPUT_CSC_C12, tbl_entry->regval[5]);
803 	}
804 	{
805 		REG_SET_2(OUTPUT_CSC_C23_C24, 0,
806 			OUTPUT_CSC_C11, tbl_entry->regval[6],
807 			OUTPUT_CSC_C12, tbl_entry->regval[7]);
808 	}
809 	{
810 		REG_SET_2(OUTPUT_CSC_C31_C32, 0,
811 			OUTPUT_CSC_C11, tbl_entry->regval[8],
812 			OUTPUT_CSC_C12, tbl_entry->regval[9]);
813 	}
814 	{
815 		REG_SET_2(OUTPUT_CSC_C33_C34, 0,
816 			OUTPUT_CSC_C11, tbl_entry->regval[10],
817 			OUTPUT_CSC_C12, tbl_entry->regval[11]);
818 	}
819 }
820 
821 static bool configure_graphics_mode(
822 	struct dce110_opp *opp110,
823 	enum csc_color_mode config,
824 	enum graphics_csc_adjust_type csc_adjust_type,
825 	enum dc_color_space color_space)
826 {
827 	REG_SET(OUTPUT_CSC_CONTROL, 0,
828 		OUTPUT_CSC_GRPH_MODE, 0);
829 
830 	if (csc_adjust_type == GRAPHICS_CSC_ADJUST_TYPE_SW) {
831 		if (config == CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC) {
832 			REG_SET(OUTPUT_CSC_CONTROL, 0,
833 				OUTPUT_CSC_GRPH_MODE, 4);
834 		} else {
835 
836 			switch (color_space) {
837 			case COLOR_SPACE_SRGB:
838 				/* by pass */
839 				REG_SET(OUTPUT_CSC_CONTROL, 0,
840 					OUTPUT_CSC_GRPH_MODE, 0);
841 				break;
842 			case COLOR_SPACE_SRGB_LIMITED:
843 				/* TV RGB */
844 				REG_SET(OUTPUT_CSC_CONTROL, 0,
845 					OUTPUT_CSC_GRPH_MODE, 1);
846 				break;
847 			case COLOR_SPACE_YCBCR601:
848 			case COLOR_SPACE_YCBCR601_LIMITED:
849 				/* YCbCr601 */
850 				REG_SET(OUTPUT_CSC_CONTROL, 0,
851 					OUTPUT_CSC_GRPH_MODE, 2);
852 				break;
853 			case COLOR_SPACE_YCBCR709:
854 			case COLOR_SPACE_YCBCR709_LIMITED:
855 				/* YCbCr709 */
856 				REG_SET(OUTPUT_CSC_CONTROL, 0,
857 					OUTPUT_CSC_GRPH_MODE, 3);
858 				break;
859 			default:
860 				return false;
861 			}
862 		}
863 	} else if (csc_adjust_type == GRAPHICS_CSC_ADJUST_TYPE_HW) {
864 		switch (color_space) {
865 		case COLOR_SPACE_SRGB:
866 			/* by pass */
867 			REG_SET(OUTPUT_CSC_CONTROL, 0,
868 				OUTPUT_CSC_GRPH_MODE, 0);
869 			break;
870 			break;
871 		case COLOR_SPACE_SRGB_LIMITED:
872 			/* TV RGB */
873 			REG_SET(OUTPUT_CSC_CONTROL, 0,
874 				OUTPUT_CSC_GRPH_MODE, 1);
875 			break;
876 		case COLOR_SPACE_YCBCR601:
877 		case COLOR_SPACE_YCBCR601_LIMITED:
878 			/* YCbCr601 */
879 			REG_SET(OUTPUT_CSC_CONTROL, 0,
880 				OUTPUT_CSC_GRPH_MODE, 2);
881 			break;
882 		case COLOR_SPACE_YCBCR709:
883 		case COLOR_SPACE_YCBCR709_LIMITED:
884 			 /* YCbCr709 */
885 			REG_SET(OUTPUT_CSC_CONTROL, 0,
886 				OUTPUT_CSC_GRPH_MODE, 3);
887 			break;
888 		default:
889 			return false;
890 		}
891 
892 	} else
893 		/* by pass */
894 		REG_SET(OUTPUT_CSC_CONTROL, 0,
895 			OUTPUT_CSC_GRPH_MODE, 0);
896 
897 	return true;
898 }
899 
900 void dce110_opp_set_csc_adjustment(
901 	struct output_pixel_processor *opp,
902 	const struct out_csc_color_matrix *tbl_entry)
903 {
904 	struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
905 	enum csc_color_mode config =
906 			CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC;
907 
908 	program_color_matrix(
909 			opp110, tbl_entry, GRAPHICS_CSC_ADJUST_TYPE_SW);
910 
911 	/*  We did everything ,now program DxOUTPUT_CSC_CONTROL */
912 	configure_graphics_mode(opp110, config, GRAPHICS_CSC_ADJUST_TYPE_SW,
913 			tbl_entry->color_space);
914 }
915 
916 void dce110_opp_set_csc_default(
917 	struct output_pixel_processor *opp,
918 	const struct default_adjustment *default_adjust)
919 {
920 	struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
921 	enum csc_color_mode config =
922 			CSC_COLOR_MODE_GRAPHICS_PREDEFINED;
923 
924 	if (default_adjust->force_hw_default == false) {
925 		const struct out_csc_color_matrix *elm;
926 		/* currently parameter not in use */
927 		enum grph_color_adjust_option option =
928 			GRPH_COLOR_MATRIX_HW_DEFAULT;
929 		uint32_t i;
930 		/*
931 		 * HW default false we program locally defined matrix
932 		 * HW default true  we use predefined hw matrix and we
933 		 * do not need to program matrix
934 		 * OEM wants the HW default via runtime parameter.
935 		 */
936 		option = GRPH_COLOR_MATRIX_SW;
937 
938 		for (i = 0; i < ARRAY_SIZE(global_color_matrix); ++i) {
939 			elm = &global_color_matrix[i];
940 			if (elm->color_space != default_adjust->out_color_space)
941 				continue;
942 			/* program the matrix with default values from this
943 			 * file */
944 			program_color_matrix(opp110, elm, option);
945 			config = CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC;
946 			break;
947 		}
948 	}
949 
950 	/* configure the what we programmed :
951 	 * 1. Default values from this file
952 	 * 2. Use hardware default from ROM_A and we do not need to program
953 	 * matrix */
954 
955 	configure_graphics_mode(opp110, config,
956 		default_adjust->csc_adjust_type,
957 		default_adjust->out_color_space);
958 }
959 
960 
961 /*****************************************/
962 /* Constructor, Destructor               */
963 /*****************************************/
964 
965 static const struct opp_funcs funcs = {
966 	.opp_power_on_regamma_lut = dce110_opp_power_on_regamma_lut,
967 	.opp_set_csc_adjustment = dce110_opp_set_csc_adjustment,
968 	.opp_set_csc_default = dce110_opp_set_csc_default,
969 	.opp_set_dyn_expansion = dce110_opp_set_dyn_expansion,
970 	.opp_program_regamma_pwl = dce110_opp_program_regamma_pwl,
971 	.opp_set_regamma_mode = dce110_opp_set_regamma_mode,
972 	.opp_destroy = dce110_opp_destroy,
973 	.opp_program_fmt = dce110_opp_program_fmt,
974 	.opp_program_bit_depth_reduction = dce110_opp_program_bit_depth_reduction
975 };
976 
977 bool dce110_opp_construct(struct dce110_opp *opp110,
978 	struct dc_context *ctx,
979 	uint32_t inst,
980 	const struct dce_opp_registers *regs,
981 	const struct dce_opp_shift *opp_shift,
982 	const struct dce_opp_mask *opp_mask)
983 {
984 	opp110->base.funcs = &funcs;
985 
986 	opp110->base.ctx = ctx;
987 
988 	opp110->base.inst = inst;
989 
990 	opp110->regs = regs;
991 	opp110->opp_shift = opp_shift;
992 	opp110->opp_mask = opp_mask;
993 
994 	return true;
995 }
996 
997 void dce110_opp_destroy(struct output_pixel_processor **opp)
998 {
999 	if (*opp)
1000 		dm_free(FROM_DCE11_OPP(*opp));
1001 	*opp = NULL;
1002 }
1003 
1004