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