Linux Audio

Check our new training course

Yocto / OpenEmbedded training

Mar 24-27, 2025, special US time zones
Register
Loading...
v6.9.4
  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 "core_types.h"
 
 27#include "dm_services.h"
 28#include "dcn10_opp.h"
 29#include "reg_helper.h"
 30
 31#define REG(reg) \
 32	(oppn10->regs->reg)
 33
 34#undef FN
 35#define FN(reg_name, field_name) \
 36	oppn10->opp_shift->field_name, oppn10->opp_mask->field_name
 37
 38#define CTX \
 39	oppn10->base.ctx
 40
 
 
 
 41/**
 42 * opp1_set_truncation():
 43 *	1) set truncation depth: 0 for 18 bpp or 1 for 24 bpp
 44 *	2) enable truncation
 45 *	3) HW remove 12bit FMT support for DCE11 power saving reason.
 46 *
 47 * @oppn10: output_pixel_processor struct instance for dcn10.
 48 * @params: pointer to bit_depth_reduction_params.
 49 */
 50static void opp1_set_truncation(
 51		struct dcn10_opp *oppn10,
 52		const struct bit_depth_reduction_params *params)
 53{
 54	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
 55		FMT_TRUNCATE_EN, params->flags.TRUNCATE_ENABLED,
 56		FMT_TRUNCATE_DEPTH, params->flags.TRUNCATE_DEPTH,
 57		FMT_TRUNCATE_MODE, params->flags.TRUNCATE_MODE);
 58}
 59
 60static void opp1_set_spatial_dither(
 61	struct dcn10_opp *oppn10,
 62	const struct bit_depth_reduction_params *params)
 63{
 64	/*Disable spatial (random) dithering*/
 65	REG_UPDATE_7(FMT_BIT_DEPTH_CONTROL,
 66			FMT_SPATIAL_DITHER_EN, 0,
 67			FMT_SPATIAL_DITHER_MODE, 0,
 68			FMT_SPATIAL_DITHER_DEPTH, 0,
 69			FMT_TEMPORAL_DITHER_EN, 0,
 70			FMT_HIGHPASS_RANDOM_ENABLE, 0,
 71			FMT_FRAME_RANDOM_ENABLE, 0,
 72			FMT_RGB_RANDOM_ENABLE, 0);
 73
 74
 75	/* only use FRAME_COUNTER_MAX if frameRandom == 1*/
 76	if (params->flags.FRAME_RANDOM == 1) {
 77		if (params->flags.SPATIAL_DITHER_DEPTH == 0 || params->flags.SPATIAL_DITHER_DEPTH == 1) {
 78			REG_UPDATE_2(FMT_CONTROL,
 79					FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 15,
 80					FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 2);
 81		} else if (params->flags.SPATIAL_DITHER_DEPTH == 2) {
 82			REG_UPDATE_2(FMT_CONTROL,
 83					FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 3,
 84					FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 1);
 85		} else {
 86			return;
 87		}
 88	} else {
 89		REG_UPDATE_2(FMT_CONTROL,
 90				FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 0,
 91				FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 0);
 92	}
 93
 94	/*Set seed for random values for
 95	 * spatial dithering for R,G,B channels*/
 96
 97	REG_SET(FMT_DITHER_RAND_R_SEED, 0,
 98			FMT_RAND_R_SEED, params->r_seed_value);
 99
100	REG_SET(FMT_DITHER_RAND_G_SEED, 0,
101			FMT_RAND_G_SEED, params->g_seed_value);
102
103	REG_SET(FMT_DITHER_RAND_B_SEED, 0,
104			FMT_RAND_B_SEED, params->b_seed_value);
105
106	/* FMT_OFFSET_R_Cr  31:16 0x0 Setting the zero
107	 * offset for the R/Cr channel, lower 4LSB
108	 * is forced to zeros. Typically set to 0
109	 * RGB and 0x80000 YCbCr.
110	 */
111	/* FMT_OFFSET_G_Y   31:16 0x0 Setting the zero
112	 * offset for the G/Y  channel, lower 4LSB is
113	 * forced to zeros. Typically set to 0 RGB
114	 * and 0x80000 YCbCr.
115	 */
116	/* FMT_OFFSET_B_Cb  31:16 0x0 Setting the zero
117	 * offset for the B/Cb channel, lower 4LSB is
118	 * forced to zeros. Typically set to 0 RGB and
119	 * 0x80000 YCbCr.
120	 */
121
122	REG_UPDATE_6(FMT_BIT_DEPTH_CONTROL,
123			/*Enable spatial dithering*/
124			FMT_SPATIAL_DITHER_EN, params->flags.SPATIAL_DITHER_ENABLED,
125			/* Set spatial dithering mode
126			 * (default is Seed patterrn AAAA...)
127			 */
128			FMT_SPATIAL_DITHER_MODE, params->flags.SPATIAL_DITHER_MODE,
129			/*Set spatial dithering bit depth*/
130			FMT_SPATIAL_DITHER_DEPTH, params->flags.SPATIAL_DITHER_DEPTH,
131			/*Disable High pass filter*/
132			FMT_HIGHPASS_RANDOM_ENABLE, params->flags.HIGHPASS_RANDOM,
133			/*Reset only at startup*/
134			FMT_FRAME_RANDOM_ENABLE, params->flags.FRAME_RANDOM,
135			/*Set RGB data dithered with x^28+x^3+1*/
136			FMT_RGB_RANDOM_ENABLE, params->flags.RGB_RANDOM);
137}
138
139void opp1_program_bit_depth_reduction(
140	struct output_pixel_processor *opp,
141	const struct bit_depth_reduction_params *params)
142{
143	struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
144
145	opp1_set_truncation(oppn10, params);
146	opp1_set_spatial_dither(oppn10, params);
147	/* TODO
148	 * set_temporal_dither(oppn10, params);
149	 */
150}
151
152/**
153 * opp1_set_pixel_encoding():
 
 
154 *		0: RGB 4:4:4 or YCbCr 4:4:4 or YOnly
155 *		1: YCbCr 4:2:2
156 *
157 * @oppn10: output_pixel_processor struct instance for dcn10.
158 * @params: pointer to clamping_and_pixel_encoding_params.
159 */
160static void opp1_set_pixel_encoding(
161	struct dcn10_opp *oppn10,
162	const struct clamping_and_pixel_encoding_params *params)
163{
164	bool force_chroma_subsampling_1tap =
165			oppn10->base.ctx->dc->debug.force_chroma_subsampling_1tap;
166
167	switch (params->pixel_encoding)	{
168
169	case PIXEL_ENCODING_RGB:
170	case PIXEL_ENCODING_YCBCR444:
171		REG_UPDATE(FMT_CONTROL, FMT_PIXEL_ENCODING, 0);
172		break;
173	case PIXEL_ENCODING_YCBCR422:
174		REG_UPDATE_3(FMT_CONTROL,
175				FMT_PIXEL_ENCODING, 1,
176				FMT_SUBSAMPLING_MODE, 2,
177				FMT_CBCR_BIT_REDUCTION_BYPASS, 0);
178		break;
179	case PIXEL_ENCODING_YCBCR420:
180		REG_UPDATE(FMT_CONTROL, FMT_PIXEL_ENCODING, 2);
181		break;
182	default:
183		break;
184	}
185
186	if (force_chroma_subsampling_1tap)
187		REG_UPDATE(FMT_CONTROL,	FMT_SUBSAMPLING_MODE, 0);
188}
189
190/**
191 * opp1_set_clamping():
192 *	1) Set clamping format based on bpc - 0 for 6bpc (No clamping)
193 *		1 for 8 bpc
194 *		2 for 10 bpc
195 *		3 for 12 bpc
196 *		7 for programable
197 *	2) Enable clamp if Limited range requested
198 *
199 * @oppn10: output_pixel_processor struct instance for dcn10.
200 * @params: pointer to clamping_and_pixel_encoding_params.
201 */
202static void opp1_set_clamping(
203	struct dcn10_opp *oppn10,
204	const struct clamping_and_pixel_encoding_params *params)
205{
206	REG_UPDATE_2(FMT_CLAMP_CNTL,
207			FMT_CLAMP_DATA_EN, 0,
208			FMT_CLAMP_COLOR_FORMAT, 0);
209
210	switch (params->clamping_level) {
211	case CLAMPING_FULL_RANGE:
212		REG_UPDATE_2(FMT_CLAMP_CNTL,
213				FMT_CLAMP_DATA_EN, 1,
214				FMT_CLAMP_COLOR_FORMAT, 0);
215		break;
216	case CLAMPING_LIMITED_RANGE_8BPC:
217		REG_UPDATE_2(FMT_CLAMP_CNTL,
218				FMT_CLAMP_DATA_EN, 1,
219				FMT_CLAMP_COLOR_FORMAT, 1);
220		break;
221	case CLAMPING_LIMITED_RANGE_10BPC:
222		REG_UPDATE_2(FMT_CLAMP_CNTL,
223				FMT_CLAMP_DATA_EN, 1,
224				FMT_CLAMP_COLOR_FORMAT, 2);
225
226		break;
227	case CLAMPING_LIMITED_RANGE_12BPC:
228		REG_UPDATE_2(FMT_CLAMP_CNTL,
229				FMT_CLAMP_DATA_EN, 1,
230				FMT_CLAMP_COLOR_FORMAT, 3);
231		break;
232	case CLAMPING_LIMITED_RANGE_PROGRAMMABLE:
233		/* TODO */
234	default:
235		break;
236	}
237
238}
239
240void opp1_set_dyn_expansion(
241	struct output_pixel_processor *opp,
242	enum dc_color_space color_sp,
243	enum dc_color_depth color_dpth,
244	enum signal_type signal)
245{
246	struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
247
248	REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
249			FMT_DYNAMIC_EXP_EN, 0,
250			FMT_DYNAMIC_EXP_MODE, 0);
251
252	if (opp->dyn_expansion == DYN_EXPANSION_DISABLE)
253		return;
254
255	/*00 - 10-bit -> 12-bit dynamic expansion*/
256	/*01 - 8-bit  -> 12-bit dynamic expansion*/
257	if (signal == SIGNAL_TYPE_HDMI_TYPE_A ||
258		signal == SIGNAL_TYPE_DISPLAY_PORT ||
259		signal == SIGNAL_TYPE_DISPLAY_PORT_MST ||
260		signal == SIGNAL_TYPE_VIRTUAL) {
261		switch (color_dpth) {
262		case COLOR_DEPTH_888:
263			REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
264				FMT_DYNAMIC_EXP_EN, 1,
265				FMT_DYNAMIC_EXP_MODE, 1);
266			break;
267		case COLOR_DEPTH_101010:
268			REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
269				FMT_DYNAMIC_EXP_EN, 1,
270				FMT_DYNAMIC_EXP_MODE, 0);
271			break;
272		case COLOR_DEPTH_121212:
273			REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
274				FMT_DYNAMIC_EXP_EN, 1,/*otherwise last two bits are zero*/
275				FMT_DYNAMIC_EXP_MODE, 0);
276			break;
277		default:
278			break;
279		}
280	}
281}
282
283static void opp1_program_clamping_and_pixel_encoding(
284	struct output_pixel_processor *opp,
285	const struct clamping_and_pixel_encoding_params *params)
286{
287	struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
288
289	opp1_set_clamping(oppn10, params);
290	opp1_set_pixel_encoding(oppn10, params);
291}
292
293void opp1_program_fmt(
294	struct output_pixel_processor *opp,
295	struct bit_depth_reduction_params *fmt_bit_depth,
296	struct clamping_and_pixel_encoding_params *clamping)
297{
298	struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
299
300	if (clamping->pixel_encoding == PIXEL_ENCODING_YCBCR420)
301		REG_UPDATE(FMT_MAP420_MEMORY_CONTROL, FMT_MAP420MEM_PWR_FORCE, 0);
302
303	/* dithering is affected by <CrtcSourceSelect>, hence should be
304	 * programmed afterwards */
305	opp1_program_bit_depth_reduction(
306		opp,
307		fmt_bit_depth);
308
309	opp1_program_clamping_and_pixel_encoding(
310		opp,
311		clamping);
312
313	return;
314}
315
316void opp1_program_stereo(
317	struct output_pixel_processor *opp,
318	bool enable,
319	const struct dc_crtc_timing *timing)
320{
321	struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
322
323	uint32_t active_width = timing->h_addressable - timing->h_border_right - timing->h_border_right;
324	uint32_t space1_size = timing->v_total - timing->v_addressable;
325	/* TODO: confirm computation of space2_size */
326	uint32_t space2_size = timing->v_total - timing->v_addressable;
327
328	if (!enable) {
329		active_width = 0;
330		space1_size = 0;
331		space2_size = 0;
332	}
333
334	/* TODO: for which cases should FMT_STEREOSYNC_OVERRIDE be set? */
335	REG_UPDATE(FMT_CONTROL, FMT_STEREOSYNC_OVERRIDE, 0);
336
337	REG_UPDATE(OPPBUF_CONTROL, OPPBUF_ACTIVE_WIDTH, active_width);
338
339	/* Program OPPBUF_3D_VACT_SPACE1_SIZE and OPPBUF_VACT_SPACE2_SIZE registers
340	 * In 3D progressive frames, Vactive space happens only in between the 2 frames,
341	 * so only need to program OPPBUF_3D_VACT_SPACE1_SIZE
342	 * In 3D alternative frames, left and right frames, top and bottom field.
343	 */
344	if (timing->timing_3d_format == TIMING_3D_FORMAT_FRAME_ALTERNATE)
345		REG_UPDATE(OPPBUF_3D_PARAMETERS_0, OPPBUF_3D_VACT_SPACE2_SIZE, space2_size);
346	else
347		REG_UPDATE(OPPBUF_3D_PARAMETERS_0, OPPBUF_3D_VACT_SPACE1_SIZE, space1_size);
348
349	/* TODO: Is programming of OPPBUF_DUMMY_DATA_R/G/B needed? */
350	/*
351	REG_UPDATE(OPPBUF_3D_PARAMETERS_0,
352			OPPBUF_DUMMY_DATA_R, data_r);
353	REG_UPDATE(OPPBUF_3D_PARAMETERS_1,
354			OPPBUF_DUMMY_DATA_G, data_g);
355	REG_UPDATE(OPPBUF_3D_PARAMETERS_1,
356			OPPBUF_DUMMY_DATA_B, _data_b);
357	*/
358}
359
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
360void opp1_pipe_clock_control(struct output_pixel_processor *opp, bool enable)
361{
362	struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
363	uint32_t regval = enable ? 1 : 0;
364
365	REG_UPDATE(OPP_PIPE_CONTROL, OPP_PIPE_CLOCK_EN, regval);
366}
367
368/*****************************************/
369/* Constructor, Destructor               */
370/*****************************************/
371
372void opp1_destroy(struct output_pixel_processor **opp)
373{
374	kfree(TO_DCN10_OPP(*opp));
375	*opp = NULL;
376}
377
378static const struct opp_funcs dcn10_opp_funcs = {
379		.opp_set_dyn_expansion = opp1_set_dyn_expansion,
380		.opp_program_fmt = opp1_program_fmt,
381		.opp_program_bit_depth_reduction = opp1_program_bit_depth_reduction,
382		.opp_program_stereo = opp1_program_stereo,
383		.opp_pipe_clock_control = opp1_pipe_clock_control,
384		.opp_set_disp_pattern_generator = NULL,
385		.opp_program_dpg_dimensions = NULL,
386		.dpg_is_blanked = NULL,
387		.dpg_is_pending = NULL,
388		.opp_destroy = opp1_destroy
389};
390
391void dcn10_opp_construct(struct dcn10_opp *oppn10,
392	struct dc_context *ctx,
393	uint32_t inst,
394	const struct dcn10_opp_registers *regs,
395	const struct dcn10_opp_shift *opp_shift,
396	const struct dcn10_opp_mask *opp_mask)
397{
398
399	oppn10->base.ctx = ctx;
400	oppn10->base.inst = inst;
401	oppn10->base.funcs = &dcn10_opp_funcs;
402
403	oppn10->regs = regs;
404	oppn10->opp_shift = opp_shift;
405	oppn10->opp_mask = opp_mask;
406}
v5.14.15
  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/slab.h>
 27
 28#include "dm_services.h"
 29#include "dcn10_opp.h"
 30#include "reg_helper.h"
 31
 32#define REG(reg) \
 33	(oppn10->regs->reg)
 34
 35#undef FN
 36#define FN(reg_name, field_name) \
 37	oppn10->opp_shift->field_name, oppn10->opp_mask->field_name
 38
 39#define CTX \
 40	oppn10->base.ctx
 41
 42
 43/************* FORMATTER ************/
 44
 45/**
 46 *	set_truncation
 47 *	1) set truncation depth: 0 for 18 bpp or 1 for 24 bpp
 48 *	2) enable truncation
 49 *	3) HW remove 12bit FMT support for DCE11 power saving reason.
 
 
 
 50 */
 51static void opp1_set_truncation(
 52		struct dcn10_opp *oppn10,
 53		const struct bit_depth_reduction_params *params)
 54{
 55	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
 56		FMT_TRUNCATE_EN, params->flags.TRUNCATE_ENABLED,
 57		FMT_TRUNCATE_DEPTH, params->flags.TRUNCATE_DEPTH,
 58		FMT_TRUNCATE_MODE, params->flags.TRUNCATE_MODE);
 59}
 60
 61static void opp1_set_spatial_dither(
 62	struct dcn10_opp *oppn10,
 63	const struct bit_depth_reduction_params *params)
 64{
 65	/*Disable spatial (random) dithering*/
 66	REG_UPDATE_7(FMT_BIT_DEPTH_CONTROL,
 67			FMT_SPATIAL_DITHER_EN, 0,
 68			FMT_SPATIAL_DITHER_MODE, 0,
 69			FMT_SPATIAL_DITHER_DEPTH, 0,
 70			FMT_TEMPORAL_DITHER_EN, 0,
 71			FMT_HIGHPASS_RANDOM_ENABLE, 0,
 72			FMT_FRAME_RANDOM_ENABLE, 0,
 73			FMT_RGB_RANDOM_ENABLE, 0);
 74
 75
 76	/* only use FRAME_COUNTER_MAX if frameRandom == 1*/
 77	if (params->flags.FRAME_RANDOM == 1) {
 78		if (params->flags.SPATIAL_DITHER_DEPTH == 0 || params->flags.SPATIAL_DITHER_DEPTH == 1) {
 79			REG_UPDATE_2(FMT_CONTROL,
 80					FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 15,
 81					FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 2);
 82		} else if (params->flags.SPATIAL_DITHER_DEPTH == 2) {
 83			REG_UPDATE_2(FMT_CONTROL,
 84					FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 3,
 85					FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 1);
 86		} else {
 87			return;
 88		}
 89	} else {
 90		REG_UPDATE_2(FMT_CONTROL,
 91				FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 0,
 92				FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 0);
 93	}
 94
 95	/*Set seed for random values for
 96	 * spatial dithering for R,G,B channels*/
 97
 98	REG_SET(FMT_DITHER_RAND_R_SEED, 0,
 99			FMT_RAND_R_SEED, params->r_seed_value);
100
101	REG_SET(FMT_DITHER_RAND_G_SEED, 0,
102			FMT_RAND_G_SEED, params->g_seed_value);
103
104	REG_SET(FMT_DITHER_RAND_B_SEED, 0,
105			FMT_RAND_B_SEED, params->b_seed_value);
106
107	/* FMT_OFFSET_R_Cr  31:16 0x0 Setting the zero
108	 * offset for the R/Cr channel, lower 4LSB
109	 * is forced to zeros. Typically set to 0
110	 * RGB and 0x80000 YCbCr.
111	 */
112	/* FMT_OFFSET_G_Y   31:16 0x0 Setting the zero
113	 * offset for the G/Y  channel, lower 4LSB is
114	 * forced to zeros. Typically set to 0 RGB
115	 * and 0x80000 YCbCr.
116	 */
117	/* FMT_OFFSET_B_Cb  31:16 0x0 Setting the zero
118	 * offset for the B/Cb channel, lower 4LSB is
119	 * forced to zeros. Typically set to 0 RGB and
120	 * 0x80000 YCbCr.
121	 */
122
123	REG_UPDATE_6(FMT_BIT_DEPTH_CONTROL,
124			/*Enable spatial dithering*/
125			FMT_SPATIAL_DITHER_EN, params->flags.SPATIAL_DITHER_ENABLED,
126			/* Set spatial dithering mode
127			 * (default is Seed patterrn AAAA...)
128			 */
129			FMT_SPATIAL_DITHER_MODE, params->flags.SPATIAL_DITHER_MODE,
130			/*Set spatial dithering bit depth*/
131			FMT_SPATIAL_DITHER_DEPTH, params->flags.SPATIAL_DITHER_DEPTH,
132			/*Disable High pass filter*/
133			FMT_HIGHPASS_RANDOM_ENABLE, params->flags.HIGHPASS_RANDOM,
134			/*Reset only at startup*/
135			FMT_FRAME_RANDOM_ENABLE, params->flags.FRAME_RANDOM,
136			/*Set RGB data dithered with x^28+x^3+1*/
137			FMT_RGB_RANDOM_ENABLE, params->flags.RGB_RANDOM);
138}
139
140void opp1_program_bit_depth_reduction(
141	struct output_pixel_processor *opp,
142	const struct bit_depth_reduction_params *params)
143{
144	struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
145
146	opp1_set_truncation(oppn10, params);
147	opp1_set_spatial_dither(oppn10, params);
148	/* TODO
149	 * set_temporal_dither(oppn10, params);
150	 */
151}
152
153/**
154 *	set_pixel_encoding
155 *
156 *	Set Pixel Encoding
157 *		0: RGB 4:4:4 or YCbCr 4:4:4 or YOnly
158 *		1: YCbCr 4:2:2
 
 
 
159 */
160static void opp1_set_pixel_encoding(
161	struct dcn10_opp *oppn10,
162	const struct clamping_and_pixel_encoding_params *params)
163{
 
 
 
164	switch (params->pixel_encoding)	{
165
166	case PIXEL_ENCODING_RGB:
167	case PIXEL_ENCODING_YCBCR444:
168		REG_UPDATE(FMT_CONTROL, FMT_PIXEL_ENCODING, 0);
169		break;
170	case PIXEL_ENCODING_YCBCR422:
171		REG_UPDATE_3(FMT_CONTROL,
172				FMT_PIXEL_ENCODING, 1,
173				FMT_SUBSAMPLING_MODE, 2,
174				FMT_CBCR_BIT_REDUCTION_BYPASS, 0);
175		break;
176	case PIXEL_ENCODING_YCBCR420:
177		REG_UPDATE(FMT_CONTROL, FMT_PIXEL_ENCODING, 2);
178		break;
179	default:
180		break;
181	}
 
 
 
182}
183
184/**
185 *	Set Clamping
186 *	1) Set clamping format based on bpc - 0 for 6bpc (No clamping)
187 *		1 for 8 bpc
188 *		2 for 10 bpc
189 *		3 for 12 bpc
190 *		7 for programable
191 *	2) Enable clamp if Limited range requested
 
 
 
192 */
193static void opp1_set_clamping(
194	struct dcn10_opp *oppn10,
195	const struct clamping_and_pixel_encoding_params *params)
196{
197	REG_UPDATE_2(FMT_CLAMP_CNTL,
198			FMT_CLAMP_DATA_EN, 0,
199			FMT_CLAMP_COLOR_FORMAT, 0);
200
201	switch (params->clamping_level) {
202	case CLAMPING_FULL_RANGE:
203		REG_UPDATE_2(FMT_CLAMP_CNTL,
204				FMT_CLAMP_DATA_EN, 1,
205				FMT_CLAMP_COLOR_FORMAT, 0);
206		break;
207	case CLAMPING_LIMITED_RANGE_8BPC:
208		REG_UPDATE_2(FMT_CLAMP_CNTL,
209				FMT_CLAMP_DATA_EN, 1,
210				FMT_CLAMP_COLOR_FORMAT, 1);
211		break;
212	case CLAMPING_LIMITED_RANGE_10BPC:
213		REG_UPDATE_2(FMT_CLAMP_CNTL,
214				FMT_CLAMP_DATA_EN, 1,
215				FMT_CLAMP_COLOR_FORMAT, 2);
216
217		break;
218	case CLAMPING_LIMITED_RANGE_12BPC:
219		REG_UPDATE_2(FMT_CLAMP_CNTL,
220				FMT_CLAMP_DATA_EN, 1,
221				FMT_CLAMP_COLOR_FORMAT, 3);
222		break;
223	case CLAMPING_LIMITED_RANGE_PROGRAMMABLE:
224		/* TODO */
225	default:
226		break;
227	}
228
229}
230
231void opp1_set_dyn_expansion(
232	struct output_pixel_processor *opp,
233	enum dc_color_space color_sp,
234	enum dc_color_depth color_dpth,
235	enum signal_type signal)
236{
237	struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
238
239	REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
240			FMT_DYNAMIC_EXP_EN, 0,
241			FMT_DYNAMIC_EXP_MODE, 0);
242
243	if (opp->dyn_expansion == DYN_EXPANSION_DISABLE)
244		return;
245
246	/*00 - 10-bit -> 12-bit dynamic expansion*/
247	/*01 - 8-bit  -> 12-bit dynamic expansion*/
248	if (signal == SIGNAL_TYPE_HDMI_TYPE_A ||
249		signal == SIGNAL_TYPE_DISPLAY_PORT ||
250		signal == SIGNAL_TYPE_DISPLAY_PORT_MST ||
251		signal == SIGNAL_TYPE_VIRTUAL) {
252		switch (color_dpth) {
253		case COLOR_DEPTH_888:
254			REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
255				FMT_DYNAMIC_EXP_EN, 1,
256				FMT_DYNAMIC_EXP_MODE, 1);
257			break;
258		case COLOR_DEPTH_101010:
259			REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
260				FMT_DYNAMIC_EXP_EN, 1,
261				FMT_DYNAMIC_EXP_MODE, 0);
262			break;
263		case COLOR_DEPTH_121212:
264			REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
265				FMT_DYNAMIC_EXP_EN, 1,/*otherwise last two bits are zero*/
266				FMT_DYNAMIC_EXP_MODE, 0);
267			break;
268		default:
269			break;
270		}
271	}
272}
273
274static void opp1_program_clamping_and_pixel_encoding(
275	struct output_pixel_processor *opp,
276	const struct clamping_and_pixel_encoding_params *params)
277{
278	struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
279
280	opp1_set_clamping(oppn10, params);
281	opp1_set_pixel_encoding(oppn10, params);
282}
283
284void opp1_program_fmt(
285	struct output_pixel_processor *opp,
286	struct bit_depth_reduction_params *fmt_bit_depth,
287	struct clamping_and_pixel_encoding_params *clamping)
288{
289	struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
290
291	if (clamping->pixel_encoding == PIXEL_ENCODING_YCBCR420)
292		REG_UPDATE(FMT_MAP420_MEMORY_CONTROL, FMT_MAP420MEM_PWR_FORCE, 0);
293
294	/* dithering is affected by <CrtcSourceSelect>, hence should be
295	 * programmed afterwards */
296	opp1_program_bit_depth_reduction(
297		opp,
298		fmt_bit_depth);
299
300	opp1_program_clamping_and_pixel_encoding(
301		opp,
302		clamping);
303
304	return;
305}
306
307void opp1_program_stereo(
308	struct output_pixel_processor *opp,
309	bool enable,
310	const struct dc_crtc_timing *timing)
311{
312	struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
313
314	uint32_t active_width = timing->h_addressable - timing->h_border_right - timing->h_border_right;
315	uint32_t space1_size = timing->v_total - timing->v_addressable;
316	/* TODO: confirm computation of space2_size */
317	uint32_t space2_size = timing->v_total - timing->v_addressable;
318
319	if (!enable) {
320		active_width = 0;
321		space1_size = 0;
322		space2_size = 0;
323	}
324
325	/* TODO: for which cases should FMT_STEREOSYNC_OVERRIDE be set? */
326	REG_UPDATE(FMT_CONTROL, FMT_STEREOSYNC_OVERRIDE, 0);
327
328	REG_UPDATE(OPPBUF_CONTROL, OPPBUF_ACTIVE_WIDTH, active_width);
329
330	/* Program OPPBUF_3D_VACT_SPACE1_SIZE and OPPBUF_VACT_SPACE2_SIZE registers
331	 * In 3D progressive frames, Vactive space happens only in between the 2 frames,
332	 * so only need to program OPPBUF_3D_VACT_SPACE1_SIZE
333	 * In 3D alternative frames, left and right frames, top and bottom field.
334	 */
335	if (timing->timing_3d_format == TIMING_3D_FORMAT_FRAME_ALTERNATE)
336		REG_UPDATE(OPPBUF_3D_PARAMETERS_0, OPPBUF_3D_VACT_SPACE2_SIZE, space2_size);
337	else
338		REG_UPDATE(OPPBUF_3D_PARAMETERS_0, OPPBUF_3D_VACT_SPACE1_SIZE, space1_size);
339
340	/* TODO: Is programming of OPPBUF_DUMMY_DATA_R/G/B needed? */
341	/*
342	REG_UPDATE(OPPBUF_3D_PARAMETERS_0,
343			OPPBUF_DUMMY_DATA_R, data_r);
344	REG_UPDATE(OPPBUF_3D_PARAMETERS_1,
345			OPPBUF_DUMMY_DATA_G, data_g);
346	REG_UPDATE(OPPBUF_3D_PARAMETERS_1,
347			OPPBUF_DUMMY_DATA_B, _data_b);
348	*/
349}
350
351void opp1_program_oppbuf(
352	struct output_pixel_processor *opp,
353	struct oppbuf_params *oppbuf)
354{
355	struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
356
357	/* Program the oppbuf active width to be the frame width from mpc */
358	REG_UPDATE(OPPBUF_CONTROL, OPPBUF_ACTIVE_WIDTH, oppbuf->active_width);
359
360	/* Specifies the number of segments in multi-segment mode (DP-MSO operation)
361	 * description  "In 1/2/4 segment mode, specifies the horizontal active width in pixels of the display panel.
362	 * In 4 segment split left/right mode, specifies the horizontal 1/2 active width in pixels of the display panel.
363	 * Used to determine segment boundaries in multi-segment mode. Used to determine the width of the vertical active space in 3D frame packed modes.
364	 * OPPBUF_ACTIVE_WIDTH must be integer divisible by the total number of segments."
365	 */
366	REG_UPDATE(OPPBUF_CONTROL, OPPBUF_DISPLAY_SEGMENTATION, oppbuf->mso_segmentation);
367
368	/* description  "Specifies the number of overlap pixels (1-8 overlapping pixels supported), used in multi-segment mode (DP-MSO operation)" */
369	REG_UPDATE(OPPBUF_CONTROL, OPPBUF_OVERLAP_PIXEL_NUM, oppbuf->mso_overlap_pixel_num);
370
371	/* description  "Specifies the number of times a pixel is replicated (0-15 pixel replications supported).
372	 * A value of 0 disables replication. The total number of times a pixel is output is OPPBUF_PIXEL_REPETITION + 1."
373	 */
374	REG_UPDATE(OPPBUF_CONTROL, OPPBUF_PIXEL_REPETITION, oppbuf->pixel_repetition);
375
376	/* Controls the number of padded pixels at the end of a segment */
377	if (REG(OPPBUF_CONTROL1))
378		REG_UPDATE(OPPBUF_CONTROL1, OPPBUF_NUM_SEGMENT_PADDED_PIXELS, oppbuf->num_segment_padded_pixels);
379}
380
381void opp1_pipe_clock_control(struct output_pixel_processor *opp, bool enable)
382{
383	struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
384	uint32_t regval = enable ? 1 : 0;
385
386	REG_UPDATE(OPP_PIPE_CONTROL, OPP_PIPE_CLOCK_EN, regval);
387}
388
389/*****************************************/
390/* Constructor, Destructor               */
391/*****************************************/
392
393void opp1_destroy(struct output_pixel_processor **opp)
394{
395	kfree(TO_DCN10_OPP(*opp));
396	*opp = NULL;
397}
398
399static const struct opp_funcs dcn10_opp_funcs = {
400		.opp_set_dyn_expansion = opp1_set_dyn_expansion,
401		.opp_program_fmt = opp1_program_fmt,
402		.opp_program_bit_depth_reduction = opp1_program_bit_depth_reduction,
403		.opp_program_stereo = opp1_program_stereo,
404		.opp_pipe_clock_control = opp1_pipe_clock_control,
405		.opp_set_disp_pattern_generator = NULL,
406		.opp_program_dpg_dimensions = NULL,
407		.dpg_is_blanked = NULL,
 
408		.opp_destroy = opp1_destroy
409};
410
411void dcn10_opp_construct(struct dcn10_opp *oppn10,
412	struct dc_context *ctx,
413	uint32_t inst,
414	const struct dcn10_opp_registers *regs,
415	const struct dcn10_opp_shift *opp_shift,
416	const struct dcn10_opp_mask *opp_mask)
417{
418
419	oppn10->base.ctx = ctx;
420	oppn10->base.inst = inst;
421	oppn10->base.funcs = &dcn10_opp_funcs;
422
423	oppn10->regs = regs;
424	oppn10->opp_shift = opp_shift;
425	oppn10->opp_mask = opp_mask;
426}