File Index
Files and directories
Sign in
FILE

dcn10_opp.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/amd/display/dc/opp/dcn10/dcn10_opp.c C
  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_3(FMT_CONTROL,
172				FMT_PIXEL_ENCODING, 0,
173				FMT_SUBSAMPLING_MODE, 0,
174				FMT_CBCR_BIT_REDUCTION_BYPASS, 0);
175		REG_UPDATE(FMT_CONTROL, FMT_PIXEL_ENCODING, 0);
176		break;
177	case PIXEL_ENCODING_YCBCR422:
178		REG_UPDATE_3(FMT_CONTROL,
179				FMT_PIXEL_ENCODING, 1,
180				FMT_SUBSAMPLING_MODE, 2,
181				FMT_CBCR_BIT_REDUCTION_BYPASS, 0);
182		break;
183	case PIXEL_ENCODING_YCBCR420:
184		REG_UPDATE_3(FMT_CONTROL,
185				FMT_PIXEL_ENCODING, 2,
186				FMT_SUBSAMPLING_MODE, 2,
187				FMT_CBCR_BIT_REDUCTION_BYPASS, 1);
188		break;
189	default:
190		break;
191	}
192
193	if (force_chroma_subsampling_1tap)
194		REG_UPDATE(FMT_CONTROL,	FMT_SUBSAMPLING_MODE, 0);
195}
196
197/**
198 * opp1_set_clamping():
199 *	1) Set clamping format based on bpc - 0 for 6bpc (No clamping)
200 *		1 for 8 bpc
201 *		2 for 10 bpc
202 *		3 for 12 bpc
203 *		7 for programable
204 *	2) Enable clamp if Limited range requested
205 *
206 * @oppn10: output_pixel_processor struct instance for dcn10.
207 * @params: pointer to clamping_and_pixel_encoding_params.
208 */
209static void opp1_set_clamping(
210	struct dcn10_opp *oppn10,
211	const struct clamping_and_pixel_encoding_params *params)
212{
213	REG_UPDATE_2(FMT_CLAMP_CNTL,
214			FMT_CLAMP_DATA_EN, 0,
215			FMT_CLAMP_COLOR_FORMAT, 0);
216
217	switch (params->clamping_level) {
218	case CLAMPING_FULL_RANGE:
219		REG_UPDATE_2(FMT_CLAMP_CNTL,
220				FMT_CLAMP_DATA_EN, 1,
221				FMT_CLAMP_COLOR_FORMAT, 0);
222		break;
223	case CLAMPING_LIMITED_RANGE_8BPC:
224		REG_UPDATE_2(FMT_CLAMP_CNTL,
225				FMT_CLAMP_DATA_EN, 1,
226				FMT_CLAMP_COLOR_FORMAT, 1);
227		break;
228	case CLAMPING_LIMITED_RANGE_10BPC:
229		REG_UPDATE_2(FMT_CLAMP_CNTL,
230				FMT_CLAMP_DATA_EN, 1,
231				FMT_CLAMP_COLOR_FORMAT, 2);
232
233		break;
234	case CLAMPING_LIMITED_RANGE_12BPC:
235		REG_UPDATE_2(FMT_CLAMP_CNTL,
236				FMT_CLAMP_DATA_EN, 1,
237				FMT_CLAMP_COLOR_FORMAT, 3);
238		break;
239	case CLAMPING_LIMITED_RANGE_PROGRAMMABLE:
240		/* TODO */
241	default:
242		break;
243	}
244
245}
246
247void opp1_set_dyn_expansion(
248	struct output_pixel_processor *opp,
249	enum dc_color_space color_sp,
250	enum dc_color_depth color_dpth,
251	enum signal_type signal)
252{
253	struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
254
255	REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
256			FMT_DYNAMIC_EXP_EN, 0,
257			FMT_DYNAMIC_EXP_MODE, 0);
258
259	if (opp->dyn_expansion == DYN_EXPANSION_DISABLE)
260		return;
261
262	/*00 - 10-bit -> 12-bit dynamic expansion*/
263	/*01 - 8-bit  -> 12-bit dynamic expansion*/
264	if (signal == SIGNAL_TYPE_HDMI_TYPE_A ||
265		signal == SIGNAL_TYPE_DISPLAY_PORT ||
266		signal == SIGNAL_TYPE_DISPLAY_PORT_MST ||
267		signal == SIGNAL_TYPE_VIRTUAL) {
268		switch (color_dpth) {
269		case COLOR_DEPTH_888:
270			REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
271				FMT_DYNAMIC_EXP_EN, 1,
272				FMT_DYNAMIC_EXP_MODE, 1);
273			break;
274		case COLOR_DEPTH_101010:
275			REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
276				FMT_DYNAMIC_EXP_EN, 1,
277				FMT_DYNAMIC_EXP_MODE, 0);
278			break;
279		case COLOR_DEPTH_121212:
280			REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
281				FMT_DYNAMIC_EXP_EN, 1,/*otherwise last two bits are zero*/
282				FMT_DYNAMIC_EXP_MODE, 0);
283			break;
284		default:
285			break;
286		}
287	}
288}
289
290static void opp1_program_clamping_and_pixel_encoding(
291	struct output_pixel_processor *opp,
292	const struct clamping_and_pixel_encoding_params *params)
293{
294	struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
295
296	opp1_set_clamping(oppn10, params);
297	opp1_set_pixel_encoding(oppn10, params);
298}
299
300void opp1_program_fmt(
301	struct output_pixel_processor *opp,
302	struct bit_depth_reduction_params *fmt_bit_depth,
303	struct clamping_and_pixel_encoding_params *clamping)
304{
305	struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
306
307	if (clamping->pixel_encoding == PIXEL_ENCODING_YCBCR420)
308		REG_UPDATE(FMT_MAP420_MEMORY_CONTROL, FMT_MAP420MEM_PWR_FORCE, 0);
309
310	/* dithering is affected by <CrtcSourceSelect>, hence should be
311	 * programmed afterwards */
312	opp1_program_bit_depth_reduction(
313		opp,
314		fmt_bit_depth);
315
316	opp1_program_clamping_and_pixel_encoding(
317		opp,
318		clamping);
319
320	return;
321}
322
323void opp1_program_stereo(
324	struct output_pixel_processor *opp,
325	bool enable,
326	const struct dc_crtc_timing *timing)
327{
328	struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
329
330	uint32_t active_width = timing->h_addressable - timing->h_border_right - timing->h_border_right;
331	uint32_t space1_size = timing->v_total - timing->v_addressable;
332	/* TODO: confirm computation of space2_size */
333	uint32_t space2_size = timing->v_total - timing->v_addressable;
334
335	if (!enable) {
336		active_width = 0;
337		space1_size = 0;
338		space2_size = 0;
339	}
340
341	/* TODO: for which cases should FMT_STEREOSYNC_OVERRIDE be set? */
342	REG_UPDATE(FMT_CONTROL, FMT_STEREOSYNC_OVERRIDE, 0);
343
344	REG_UPDATE(OPPBUF_CONTROL, OPPBUF_ACTIVE_WIDTH, active_width);
345
346	/* Program OPPBUF_3D_VACT_SPACE1_SIZE and OPPBUF_VACT_SPACE2_SIZE registers
347	 * In 3D progressive frames, Vactive space happens only in between the 2 frames,
348	 * so only need to program OPPBUF_3D_VACT_SPACE1_SIZE
349	 * In 3D alternative frames, left and right frames, top and bottom field.
350	 */
351	if (timing->timing_3d_format == TIMING_3D_FORMAT_FRAME_ALTERNATE)
352		REG_UPDATE(OPPBUF_3D_PARAMETERS_0, OPPBUF_3D_VACT_SPACE2_SIZE, space2_size);
353	else
354		REG_UPDATE(OPPBUF_3D_PARAMETERS_0, OPPBUF_3D_VACT_SPACE1_SIZE, space1_size);
355
356	/* TODO: Is programming of OPPBUF_DUMMY_DATA_R/G/B needed? */
357	/*
358	REG_UPDATE(OPPBUF_3D_PARAMETERS_0,
359			OPPBUF_DUMMY_DATA_R, data_r);
360	REG_UPDATE(OPPBUF_3D_PARAMETERS_1,
361			OPPBUF_DUMMY_DATA_G, data_g);
362	REG_UPDATE(OPPBUF_3D_PARAMETERS_1,
363			OPPBUF_DUMMY_DATA_B, _data_b);
364	*/
365}
366
367void opp1_pipe_clock_control(struct output_pixel_processor *opp, bool enable)
368{
369	struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
370	uint32_t regval = enable ? 1 : 0;
371
372	REG_UPDATE(OPP_PIPE_CONTROL, OPP_PIPE_CLOCK_EN, regval);
373}
374
375
376void opp1_read_reg_state(struct output_pixel_processor *opp, struct dcn_opp_reg_state *opp_reg_state)
377{
378	struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
379
380	opp_reg_state->fmt_control = REG_READ(FMT_CONTROL);
381	opp_reg_state->opp_pipe_control = REG_READ(OPP_PIPE_CONTROL);
382	opp_reg_state->opp_pipe_crc_control = REG_READ(OPP_PIPE_CRC_CONTROL);
383	opp_reg_state->oppbuf_control = REG_READ(OPPBUF_CONTROL);
384}
385
386/*****************************************/
387/* Constructor, Destructor               */
388/*****************************************/
389
390void opp1_destroy(struct output_pixel_processor **opp)
391{
392	kfree(TO_DCN10_OPP(*opp));
393	*opp = NULL;
394}
395
396static const struct opp_funcs dcn10_opp_funcs = {
397		.opp_set_dyn_expansion = opp1_set_dyn_expansion,
398		.opp_program_fmt = opp1_program_fmt,
399		.opp_program_bit_depth_reduction = opp1_program_bit_depth_reduction,
400		.opp_program_stereo = opp1_program_stereo,
401		.opp_pipe_clock_control = opp1_pipe_clock_control,
402		.opp_set_disp_pattern_generator = NULL,
403		.opp_program_dpg_dimensions = NULL,
404		.dpg_is_blanked = NULL,
405		.dpg_is_pending = NULL,
406		.opp_destroy = opp1_destroy,
407		.opp_read_reg_state = opp1_read_reg_state
408};
409
410void dcn10_opp_construct(struct dcn10_opp *oppn10,
411	struct dc_context *ctx,
412	uint32_t inst,
413	const struct dcn10_opp_registers *regs,
414	const struct dcn10_opp_shift *opp_shift,
415	const struct dcn10_opp_mask *opp_mask)
416{
417
418	oppn10->base.ctx = ctx;
419	oppn10->base.inst = inst;
420	oppn10->base.funcs = &dcn10_opp_funcs;
421
422	oppn10->regs = regs;
423	oppn10->opp_shift = opp_shift;
424	oppn10->opp_mask = opp_mask;
425}
~/ Read-only file preview.