1132718Skan/*	$NetBSD: amdgpu_dce_opp.c,v 1.2 2021/12/18 23:45:02 riastradh Exp $	*/
272562Sobrien
3169689Skan/*
4169689Skan * Copyright 2012-15 Advanced Micro Devices, Inc.
550397Sobrien *
6132718Skan * Permission is hereby granted, free of charge, to any person obtaining a
750397Sobrien * copy of this software and associated documentation files (the "Software"),
850397Sobrien * to deal in the Software without restriction, including without limitation
9132718Skan * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1050397Sobrien * and/or sell copies of the Software, and to permit persons to whom the
11132718Skan * Software is furnished to do so, subject to the following conditions:
1250397Sobrien *
1350397Sobrien * The above copyright notice and this permission notice shall be included in
1450397Sobrien * all copies or substantial portions of the Software.
1550397Sobrien *
16132718Skan * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1750397Sobrien * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1850397Sobrien * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1950397Sobrien * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
2050397Sobrien * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2150397Sobrien * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22132718Skan * OTHER DEALINGS IN THE SOFTWARE.
23169689Skan *
24169689Skan * Authors: AMD
2550397Sobrien *
2650397Sobrien */
2750397Sobrien
28132718Skan#include <sys/cdefs.h>
29132718Skan__KERNEL_RCSID(0, "$NetBSD: amdgpu_dce_opp.c,v 1.2 2021/12/18 23:45:02 riastradh Exp $");
3050397Sobrien
3150397Sobrien#include <linux/slab.h>
3250397Sobrien
3350397Sobrien#include "dm_services.h"
3450397Sobrien#include "basics/conversion.h"
3550397Sobrien
36169689Skan#include "dce_opp.h"
3750397Sobrien
3850397Sobrien#include "reg_helper.h"
3950397Sobrien
4050397Sobrien#define REG(reg)\
4190075Sobrien	(opp110->regs->reg)
4250397Sobrien
4390075Sobrien#undef FN
4450397Sobrien#define FN(reg_name, field_name) \
4550397Sobrien	opp110->opp_shift->field_name, opp110->opp_mask->field_name
4690075Sobrien
4790075Sobrien#define CTX \
4890075Sobrien	opp110->base.ctx
4990075Sobrien
5090075Sobrienenum {
51132718Skan	MAX_PWL_ENTRY = 128,
52169689Skan	MAX_REGIONS_NUMBER = 16
53169689Skan};
5450397Sobrien
55169689Skanenum {
56169689Skan	MAX_LUT_ENTRY = 256,
57169689Skan	MAX_NUMBER_OF_ENTRIES = 256
58169689Skan};
59169689Skan
60169689Skan
61169689Skanenum {
62169689Skan	OUTPUT_CSC_MATRIX_SIZE = 12
63169689Skan};
64169689Skan
65169689Skan
66169689Skan
67169689Skan
68169689Skan
69169689Skan
70169689Skan
71169689Skan
72169689Skan
73169689Skan
74169689Skan
75169689Skan
76169689Skan
77169689Skan
78169689Skan
7950397Sobrien
80169689Skan
81169689Skan
82169689Skan
83169689Skan
84169689Skan
85169689Skan
86169689Skan/*
87169689Skan *****************************************************************************
88169689Skan *  Function: regamma_config_regions_and_segments
89169689Skan *
90169689Skan *     build regamma curve by using predefined hw points
91169689Skan *     uses interface parameters ,like EDID coeff.
92169689Skan *
93169689Skan * @param   : parameters   interface parameters
94169689Skan *  @return void
95169689Skan *
96169689Skan *  @note
97169689Skan *
98169689Skan *  @see
99169689Skan *
100169689Skan *****************************************************************************
101169689Skan */
102169689Skan
10350397Sobrien
104169689Skan
105169689Skan/**
106169689Skan *	set_truncation
107169689Skan *	1) set truncation depth: 0 for 18 bpp or 1 for 24 bpp
108169689Skan *	2) enable truncation
109169689Skan *	3) HW remove 12bit FMT support for DCE11 power saving reason.
110169689Skan */
111169689Skanstatic void set_truncation(
112169689Skan		struct dce110_opp *opp110,
113169689Skan		const struct bit_depth_reduction_params *params)
114169689Skan{
115169689Skan	/*Disable truncation*/
116169689Skan	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
117169689Skan			FMT_TRUNCATE_EN, 0,
118169689Skan			FMT_TRUNCATE_DEPTH, 0,
119169689Skan			FMT_TRUNCATE_MODE, 0);
120169689Skan
121169689Skan
122169689Skan	if (params->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
123169689Skan		/*  8bpc trunc on YCbCr422*/
124169689Skan		if (params->flags.TRUNCATE_DEPTH == 1)
125169689Skan			REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
126169689Skan					FMT_TRUNCATE_EN, 1,
127169689Skan					FMT_TRUNCATE_DEPTH, 1,
128169689Skan					FMT_TRUNCATE_MODE, 0);
129169689Skan		else if (params->flags.TRUNCATE_DEPTH == 2)
130169689Skan			/*  10bpc trunc on YCbCr422*/
131169689Skan			REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
132169689Skan					FMT_TRUNCATE_EN, 1,
133169689Skan					FMT_TRUNCATE_DEPTH, 2,
134169689Skan					FMT_TRUNCATE_MODE, 0);
135169689Skan		return;
136169689Skan	}
137169689Skan	/* on other format-to do */
138169689Skan	if (params->flags.TRUNCATE_ENABLED == 0)
139169689Skan		return;
140169689Skan	/*Set truncation depth and Enable truncation*/
141169689Skan	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
142169689Skan				FMT_TRUNCATE_EN, 1,
143169689Skan				FMT_TRUNCATE_DEPTH,
144169689Skan				params->flags.TRUNCATE_DEPTH,
145169689Skan				FMT_TRUNCATE_MODE,
146169689Skan				params->flags.TRUNCATE_MODE);
147169689Skan}
148169689Skan
149169689Skan
150169689Skan/**
151169689Skan *	set_spatial_dither
152169689Skan *	1) set spatial dithering mode: pattern of seed
153169689Skan *	2) set spatial dithering depth: 0 for 18bpp or 1 for 24bpp
154169689Skan *	3) set random seed
155169689Skan *	4) set random mode
156169689Skan *		lfsr is reset every frame or not reset
157169689Skan *		RGB dithering method
158169689Skan *		0: RGB data are all dithered with x^28+x^3+1
159169689Skan *		1: R data is dithered with x^28+x^3+1
160169689Skan *		G data is dithered with x^28+X^9+1
161169689Skan *		B data is dithered with x^28+x^13+1
162169689Skan *		enable high pass filter or not
163169689Skan *	5) enable spatical dithering
164169689Skan */
165169689Skanstatic void set_spatial_dither(
166169689Skan	struct dce110_opp *opp110,
167169689Skan	const struct bit_depth_reduction_params *params)
168169689Skan{
169169689Skan	/*Disable spatial (random) dithering*/
170169689Skan	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
171169689Skan		FMT_SPATIAL_DITHER_EN, 0,
172169689Skan		FMT_SPATIAL_DITHER_DEPTH, 0,
173169689Skan		FMT_SPATIAL_DITHER_MODE, 0);
174169689Skan
175169689Skan	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
176169689Skan		FMT_HIGHPASS_RANDOM_ENABLE, 0,
177169689Skan		FMT_FRAME_RANDOM_ENABLE, 0,
178169689Skan		FMT_RGB_RANDOM_ENABLE, 0);
179169689Skan
180169689Skan	REG_UPDATE(FMT_BIT_DEPTH_CONTROL,
181169689Skan		FMT_TEMPORAL_DITHER_EN, 0);
182169689Skan
183169689Skan	/* no 10bpc on DCE11*/
184169689Skan	if (params->flags.SPATIAL_DITHER_ENABLED == 0 ||
185169689Skan		params->flags.SPATIAL_DITHER_DEPTH == 2)
186169689Skan		return;
187169689Skan
188169689Skan	/* only use FRAME_COUNTER_MAX if frameRandom == 1*/
189169689Skan
190169689Skan	if (opp110->opp_mask->FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX &&
191169689Skan			opp110->opp_mask->FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP) {
192169689Skan		if (params->flags.FRAME_RANDOM == 1) {
193169689Skan			if (params->flags.SPATIAL_DITHER_DEPTH == 0 ||
194169689Skan			params->flags.SPATIAL_DITHER_DEPTH == 1) {
195169689Skan				REG_UPDATE_2(FMT_CONTROL,
196169689Skan					FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 15,
197169689Skan					FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 2);
198169689Skan			} else if (params->flags.SPATIAL_DITHER_DEPTH == 2) {
199169689Skan				REG_UPDATE_2(FMT_CONTROL,
200169689Skan					FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 3,
201169689Skan					FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 1);
202169689Skan			} else
203169689Skan				return;
204169689Skan		} else {
205169689Skan			REG_UPDATE_2(FMT_CONTROL,
206169689Skan					FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 0,
207169689Skan					FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 0);
208169689Skan		}
209169689Skan	}
210169689Skan	/* Set seed for random values for
211169689Skan	 * spatial dithering for R,G,B channels
212169689Skan	 */
213169689Skan	REG_UPDATE(FMT_DITHER_RAND_R_SEED,
214169689Skan			FMT_RAND_R_SEED, params->r_seed_value);
215169689Skan
216169689Skan	REG_UPDATE(FMT_DITHER_RAND_G_SEED,
217169689Skan			FMT_RAND_G_SEED, params->g_seed_value);
218169689Skan
219169689Skan	REG_UPDATE(FMT_DITHER_RAND_B_SEED,
220169689Skan			FMT_RAND_B_SEED, params->b_seed_value);
221169689Skan
222169689Skan	/* FMT_OFFSET_R_Cr  31:16 0x0 Setting the zero
223169689Skan	 * offset for the R/Cr channel, lower 4LSB
224169689Skan	 * is forced to zeros. Typically set to 0
225169689Skan	 * RGB and 0x80000 YCbCr.
226169689Skan	 */
227169689Skan	/* FMT_OFFSET_G_Y   31:16 0x0 Setting the zero
228169689Skan	 * offset for the G/Y  channel, lower 4LSB is
229169689Skan	 * forced to zeros. Typically set to 0 RGB
230169689Skan	 * and 0x80000 YCbCr.
231169689Skan	 */
232169689Skan	/* FMT_OFFSET_B_Cb  31:16 0x0 Setting the zero
233169689Skan	 * offset for the B/Cb channel, lower 4LSB is
234169689Skan	 * forced to zeros. Typically set to 0 RGB and
235169689Skan	 * 0x80000 YCbCr.
236169689Skan	 */
23750397Sobrien
23850397Sobrien	/* Disable High pass filter
23950397Sobrien	 * Reset only at startup
240169689Skan	 * Set RGB data dithered with x^28+x^3+1
241169689Skan	 */
242169689Skan	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
24350397Sobrien		FMT_HIGHPASS_RANDOM_ENABLE, params->flags.HIGHPASS_RANDOM,
24450397Sobrien		FMT_FRAME_RANDOM_ENABLE, params->flags.FRAME_RANDOM,
245132718Skan		FMT_RGB_RANDOM_ENABLE, params->flags.RGB_RANDOM);
246132718Skan
24750397Sobrien	/* Set spatial dithering bit depth
24896263Sobrien	 * Set spatial dithering mode
24996263Sobrien	 * (default is Seed patterrn AAAA...)
25090075Sobrien	 * Enable spatial dithering
25190075Sobrien	 */
252169689Skan	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
253169689Skan		FMT_SPATIAL_DITHER_DEPTH, params->flags.SPATIAL_DITHER_DEPTH,
254169689Skan		FMT_SPATIAL_DITHER_MODE, params->flags.SPATIAL_DITHER_MODE,
255169689Skan		FMT_SPATIAL_DITHER_EN, 1);
256169689Skan}
257169689Skan
25850397Sobrien/**
25950397Sobrien *	SetTemporalDither (Frame Modulation)
260169689Skan *	1) set temporal dither depth
26150397Sobrien *	2) select pattern: from hard-coded pattern or programmable pattern
26296263Sobrien *	3) select optimized strips for BGR or RGB LCD sub-pixel
26396263Sobrien *	4) set s matrix
26496263Sobrien *	5) set t matrix
26596263Sobrien *	6) set grey level for 0.25, 0.5, 0.75
26650397Sobrien *	7) enable temporal dithering
26750397Sobrien */
26850397Sobrien
26950397Sobrienstatic void set_temporal_dither(
27050397Sobrien	struct dce110_opp *opp110,
27150397Sobrien	const struct bit_depth_reduction_params *params)
27250397Sobrien{
27350397Sobrien	/*Disable temporal (frame modulation) dithering first*/
27450397Sobrien	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
27550397Sobrien		FMT_TEMPORAL_DITHER_EN, 0,
27650397Sobrien		FMT_TEMPORAL_DITHER_RESET, 0,
27750397Sobrien		FMT_TEMPORAL_DITHER_OFFSET, 0);
27850397Sobrien
27950397Sobrien	REG_UPDATE_2(FMT_BIT_DEPTH_CONTROL,
28050397Sobrien		FMT_TEMPORAL_DITHER_DEPTH, 0,
28190075Sobrien		FMT_TEMPORAL_LEVEL, 0);
28290075Sobrien
28390075Sobrien	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
28490075Sobrien		FMT_25FRC_SEL, 0,
28590075Sobrien		FMT_50FRC_SEL, 0,
28690075Sobrien		FMT_75FRC_SEL, 0);
28790075Sobrien
28890075Sobrien	/* no 10bpc dither on DCE11*/
28990075Sobrien	if (params->flags.FRAME_MODULATION_ENABLED == 0 ||
29090075Sobrien		params->flags.FRAME_MODULATION_DEPTH == 2)
29190075Sobrien		return;
29290075Sobrien
29390075Sobrien	/* Set temporal dithering depth*/
29490075Sobrien	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
29590075Sobrien		FMT_TEMPORAL_DITHER_DEPTH, params->flags.FRAME_MODULATION_DEPTH,
29690075Sobrien		FMT_TEMPORAL_DITHER_RESET, 0,
29790075Sobrien		FMT_TEMPORAL_DITHER_OFFSET, 0);
29890075Sobrien
299132718Skan	/*Select legacy pattern based on FRC and Temporal level*/
300132718Skan	if (REG(FMT_TEMPORAL_DITHER_PATTERN_CONTROL)) {
301132718Skan		REG_WRITE(FMT_TEMPORAL_DITHER_PATTERN_CONTROL, 0);
302132718Skan		/*Set s matrix*/
303169689Skan		REG_WRITE(FMT_TEMPORAL_DITHER_PROGRAMMABLE_PATTERN_S_MATRIX, 0);
304169689Skan		/*Set t matrix*/
305169689Skan		REG_WRITE(FMT_TEMPORAL_DITHER_PROGRAMMABLE_PATTERN_T_MATRIX, 0);
306169689Skan	}
307169689Skan
308169689Skan	/*Select patterns for 0.25, 0.5 and 0.75 grey level*/
309169689Skan	REG_UPDATE(FMT_BIT_DEPTH_CONTROL,
310169689Skan		FMT_TEMPORAL_LEVEL, params->flags.TEMPORAL_LEVEL);
311169689Skan
312132718Skan	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
313132718Skan		FMT_25FRC_SEL, params->flags.FRC25,
314169689Skan		FMT_50FRC_SEL, params->flags.FRC50,
315169689Skan		FMT_75FRC_SEL, params->flags.FRC75);
31650397Sobrien
317169689Skan	/*Enable bit reduction by temporal (frame modulation) dithering*/
318169689Skan	REG_UPDATE(FMT_BIT_DEPTH_CONTROL,
319169689Skan		FMT_TEMPORAL_DITHER_EN, 1);
320169689Skan}
321169689Skan
322132718Skan/**
32350397Sobrien *	Set Clamping
324169689Skan *	1) Set clamping format based on bpc - 0 for 6bpc (No clamping)
325169689Skan *		1 for 8 bpc
326169689Skan *		2 for 10 bpc
327169689Skan *		3 for 12 bpc
328132718Skan *		7 for programable
329132718Skan *	2) Enable clamp if Limited range requested
330132718Skan */
331132718Skanvoid dce110_opp_set_clamping(
33250397Sobrien	struct dce110_opp *opp110,
333132718Skan	const struct clamping_and_pixel_encoding_params *params)
334132718Skan{
33552284Sobrien	REG_SET_2(FMT_CLAMP_CNTL, 0,
336132718Skan		FMT_CLAMP_DATA_EN, 0,
337132718Skan		FMT_CLAMP_COLOR_FORMAT, 0);
338132718Skan
339169689Skan	switch (params->clamping_level) {
340132718Skan	case CLAMPING_FULL_RANGE:
341132718Skan		break;
342132718Skan	case CLAMPING_LIMITED_RANGE_8BPC:
343169689Skan		REG_SET_2(FMT_CLAMP_CNTL, 0,
344169689Skan			FMT_CLAMP_DATA_EN, 1,
345169689Skan			FMT_CLAMP_COLOR_FORMAT, 1);
346169689Skan		break;
347169689Skan	case CLAMPING_LIMITED_RANGE_10BPC:
348169689Skan		REG_SET_2(FMT_CLAMP_CNTL, 0,
34990075Sobrien			FMT_CLAMP_DATA_EN, 1,
350169689Skan			FMT_CLAMP_COLOR_FORMAT, 2);
35190075Sobrien		break;
35252284Sobrien	case CLAMPING_LIMITED_RANGE_12BPC:
353132718Skan		REG_SET_2(FMT_CLAMP_CNTL, 0,
354132718Skan			FMT_CLAMP_DATA_EN, 1,
355132718Skan			FMT_CLAMP_COLOR_FORMAT, 3);
356132718Skan		break;
35796263Sobrien	case CLAMPING_LIMITED_RANGE_PROGRAMMABLE:
358132718Skan		/*Set clamp control*/
359132718Skan		REG_SET_2(FMT_CLAMP_CNTL, 0,
360132718Skan			FMT_CLAMP_DATA_EN, 1,
361132718Skan			FMT_CLAMP_COLOR_FORMAT, 7);
362132718Skan
363117395Skan		/*set the defaults*/
364132718Skan		REG_SET_2(FMT_CLAMP_COMPONENT_R, 0,
365132718Skan			FMT_CLAMP_LOWER_R, 0x10,
366169689Skan			FMT_CLAMP_UPPER_R, 0xFEF);
367169689Skan
368169689Skan		REG_SET_2(FMT_CLAMP_COMPONENT_G, 0,
369169689Skan			FMT_CLAMP_LOWER_G, 0x10,
370169689Skan			FMT_CLAMP_UPPER_G, 0xFEF);
371169689Skan
372132718Skan		REG_SET_2(FMT_CLAMP_COMPONENT_B, 0,
373132718Skan			FMT_CLAMP_LOWER_B, 0x10,
374146895Skan			FMT_CLAMP_UPPER_B, 0xFEF);
375146895Skan		break;
376132718Skan	default:
377132718Skan		break;
378132718Skan	}
379132718Skan}
380132718Skan
381132718Skan/**
382132718Skan *	set_pixel_encoding
383169689Skan *
384169689Skan *	Set Pixel Encoding
385169689Skan *		0: RGB 4:4:4 or YCbCr 4:4:4 or YOnly
386169689Skan *		1: YCbCr 4:2:2
387169689Skan */
388169689Skanstatic void set_pixel_encoding(
389169689Skan	struct dce110_opp *opp110,
390169689Skan	const struct clamping_and_pixel_encoding_params *params)
391169689Skan{
392169689Skan	if (opp110->opp_mask->FMT_CBCR_BIT_REDUCTION_BYPASS)
393169689Skan		REG_UPDATE_3(FMT_CONTROL,
394169689Skan				FMT_PIXEL_ENCODING, 0,
395169689Skan				FMT_SUBSAMPLING_MODE, 0,
396169689Skan				FMT_CBCR_BIT_REDUCTION_BYPASS, 0);
397169689Skan	else
398169689Skan		REG_UPDATE_2(FMT_CONTROL,
399169689Skan				FMT_PIXEL_ENCODING, 0,
400169689Skan				FMT_SUBSAMPLING_MODE, 0);
401169689Skan
40250397Sobrien	if (params->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
40350397Sobrien		REG_UPDATE_2(FMT_CONTROL,
40450397Sobrien				FMT_PIXEL_ENCODING, 1,
40550397Sobrien				FMT_SUBSAMPLING_ORDER, 0);
40650397Sobrien	}
40750397Sobrien	if (params->pixel_encoding == PIXEL_ENCODING_YCBCR420) {
40890075Sobrien		REG_UPDATE_3(FMT_CONTROL,
40950397Sobrien				FMT_PIXEL_ENCODING, 2,
41050397Sobrien				FMT_SUBSAMPLING_MODE, 2,
41150397Sobrien				FMT_CBCR_BIT_REDUCTION_BYPASS, 1);
41250397Sobrien	}
41350397Sobrien
41450397Sobrien}
41550397Sobrien
41650397Sobrienvoid dce110_opp_program_bit_depth_reduction(
41750397Sobrien	struct output_pixel_processor *opp,
41850397Sobrien	const struct bit_depth_reduction_params *params)
41950397Sobrien{
42050397Sobrien	struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
421169689Skan
422169689Skan	set_truncation(opp110, params);
423169689Skan	set_spatial_dither(opp110, params);
424169689Skan	set_temporal_dither(opp110, params);
42590075Sobrien}
42650397Sobrien
42790075Sobrienvoid dce110_opp_program_clamping_and_pixel_encoding(
42890075Sobrien	struct output_pixel_processor *opp,
42990075Sobrien	const struct clamping_and_pixel_encoding_params *params)
43090075Sobrien{
43190075Sobrien	struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
43290075Sobrien
43390075Sobrien	dce110_opp_set_clamping(opp110, params);
43490075Sobrien	set_pixel_encoding(opp110, params);
43590075Sobrien}
43690075Sobrien
43790075Sobrienstatic void program_formatter_420_memory(struct output_pixel_processor *opp)
43890075Sobrien{
43990075Sobrien	struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
44090075Sobrien	uint32_t fmt_mem_cntl_value;
44190075Sobrien
44290075Sobrien	/* Program source select*/
44390075Sobrien	/* Use HW default source select for FMT_MEMORYx_CONTROL */
44490075Sobrien	/* Use that value for FMT_SRC_SELECT as well*/
44590075Sobrien	REG_GET(CONTROL,
44690075Sobrien			FMT420_MEM0_SOURCE_SEL, &fmt_mem_cntl_value);
44790075Sobrien
448169689Skan	REG_UPDATE(FMT_CONTROL,
44990075Sobrien			FMT_SRC_SELECT, fmt_mem_cntl_value);
450169689Skan
45190075Sobrien	/* Turn on the memory */
45290075Sobrien	REG_UPDATE(CONTROL,
45390075Sobrien			FMT420_MEM0_PWR_FORCE, 0);
45490075Sobrien}
45590075Sobrien
45690075Sobrienvoid dce110_opp_set_dyn_expansion(
45790075Sobrien	struct output_pixel_processor *opp,
458117395Skan	enum dc_color_space color_sp,
459117395Skan	enum dc_color_depth color_dpth,
46090075Sobrien	enum signal_type signal)
461132718Skan{
462132718Skan	struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
463117395Skan
464132718Skan	REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
465132718Skan			FMT_DYNAMIC_EXP_EN, 0,
466169689Skan			FMT_DYNAMIC_EXP_MODE, 0);
467169689Skan
468132718Skan	/*00 - 10-bit -> 12-bit dynamic expansion*/
469169689Skan	/*01 - 8-bit  -> 12-bit dynamic expansion*/
470169689Skan	if (signal == SIGNAL_TYPE_HDMI_TYPE_A ||
471169689Skan		signal == SIGNAL_TYPE_DISPLAY_PORT ||
472169689Skan		signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
473169689Skan		switch (color_dpth) {
474169689Skan		case COLOR_DEPTH_888:
475132718Skan			REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
476132718Skan				FMT_DYNAMIC_EXP_EN, 1,
477132718Skan				FMT_DYNAMIC_EXP_MODE, 1);
478169689Skan			break;
479132718Skan		case COLOR_DEPTH_101010:
480132718Skan			REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
481132718Skan				FMT_DYNAMIC_EXP_EN, 1,
482117395Skan				FMT_DYNAMIC_EXP_MODE, 0);
483117395Skan			break;
484117395Skan		case COLOR_DEPTH_121212:
485146895Skan			REG_UPDATE_2(
486117395Skan				FMT_DYNAMIC_EXP_CNTL,
487132718Skan				FMT_DYNAMIC_EXP_EN, 1,/*otherwise last two bits are zero*/
488132718Skan				FMT_DYNAMIC_EXP_MODE, 0);
489132718Skan			break;
490132718Skan		default:
491132718Skan			break;
492169689Skan		}
493169689Skan	}
494169689Skan}
495169689Skan
496169689Skanstatic void program_formatter_reset_dig_resync_fifo(struct output_pixel_processor *opp)
497169689Skan{
498169689Skan	struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
499169689Skan
500169689Skan	/* clear previous phase lock status*/
501169689Skan	REG_UPDATE(FMT_CONTROL,
502169689Skan			FMT_420_PIXEL_PHASE_LOCKED_CLEAR, 1);
503169689Skan
504169689Skan	/* poll until FMT_420_PIXEL_PHASE_LOCKED become 1*/
505169689Skan	REG_WAIT(FMT_CONTROL, FMT_420_PIXEL_PHASE_LOCKED, 1, 10, 10);
506169689Skan
507169689Skan}
508169689Skan
509169689Skanvoid dce110_opp_program_fmt(
510169689Skan	struct output_pixel_processor *opp,
511169689Skan	struct bit_depth_reduction_params *fmt_bit_depth,
512169689Skan	struct clamping_and_pixel_encoding_params *clamping)
513169689Skan{
514169689Skan	/* dithering is affected by <CrtcSourceSelect>, hence should be
515169689Skan	 * programmed afterwards */
516169689Skan
517169689Skan	if (clamping->pixel_encoding == PIXEL_ENCODING_YCBCR420)
518169689Skan		program_formatter_420_memory(opp);
519169689Skan
520169689Skan	dce110_opp_program_bit_depth_reduction(
521169689Skan		opp,
522169689Skan		fmt_bit_depth);
523169689Skan
524169689Skan	dce110_opp_program_clamping_and_pixel_encoding(
525169689Skan		opp,
526169689Skan		clamping);
527169689Skan
528169689Skan	if (clamping->pixel_encoding == PIXEL_ENCODING_YCBCR420)
529169689Skan		program_formatter_reset_dig_resync_fifo(opp);
530169689Skan
531169689Skan	return;
532169689Skan}
533169689Skan
534169689Skan
535169689Skan
536169689Skan
537169689Skan
538169689Skan/*****************************************/
539169689Skan/* Constructor, Destructor               */
540169689Skan/*****************************************/
541169689Skan
542169689Skanstatic const struct opp_funcs funcs = {
543169689Skan	.opp_set_dyn_expansion = dce110_opp_set_dyn_expansion,
544169689Skan	.opp_destroy = dce110_opp_destroy,
545169689Skan	.opp_program_fmt = dce110_opp_program_fmt,
546169689Skan	.opp_program_bit_depth_reduction = dce110_opp_program_bit_depth_reduction
547169689Skan};
548169689Skan
549169689Skanvoid dce110_opp_construct(struct dce110_opp *opp110,
550169689Skan	struct dc_context *ctx,
551169689Skan	uint32_t inst,
552169689Skan	const struct dce_opp_registers *regs,
553169689Skan	const struct dce_opp_shift *opp_shift,
554169689Skan	const struct dce_opp_mask *opp_mask)
555169689Skan{
556169689Skan	opp110->base.funcs = &funcs;
557169689Skan
558169689Skan	opp110->base.ctx = ctx;
559169689Skan
560169689Skan	opp110->base.inst = inst;
561169689Skan
562169689Skan	opp110->regs = regs;
56390075Sobrien	opp110->opp_shift = opp_shift;
564169689Skan	opp110->opp_mask = opp_mask;
565169689Skan}
566169689Skan
567169689Skanvoid dce110_opp_destroy(struct output_pixel_processor **opp)
568169689Skan{
569169689Skan	if (*opp)
570169689Skan		kfree(FROM_DCE11_OPP(*opp));
571169689Skan	*opp = NULL;
572169689Skan}
573169689Skan
574169689Skan