Home | History | Annotate | Line # | Download | only in dce
      1 /*	$NetBSD: amdgpu_dce_transform.c,v 1.2 2021/12/18 23:45:02 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright 2012-16 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_dce_transform.c,v 1.2 2021/12/18 23:45:02 riastradh Exp $");
     30 
     31 #include "dce_transform.h"
     32 #include "reg_helper.h"
     33 #include "opp.h"
     34 #include "basics/conversion.h"
     35 #include "dc.h"
     36 
     37 #define REG(reg) \
     38 	(xfm_dce->regs->reg)
     39 
     40 #undef FN
     41 #define FN(reg_name, field_name) \
     42 	xfm_dce->xfm_shift->field_name, xfm_dce->xfm_mask->field_name
     43 
     44 #define CTX \
     45 	xfm_dce->base.ctx
     46 #define DC_LOGGER \
     47 	xfm_dce->base.ctx->logger
     48 
     49 #define IDENTITY_RATIO(ratio) (dc_fixpt_u2d19(ratio) == (1 << 19))
     50 #define GAMUT_MATRIX_SIZE 12
     51 #define SCL_PHASES 16
     52 
     53 enum dcp_out_trunc_round_mode {
     54 	DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE,
     55 	DCP_OUT_TRUNC_ROUND_MODE_ROUND
     56 };
     57 
     58 enum dcp_out_trunc_round_depth {
     59 	DCP_OUT_TRUNC_ROUND_DEPTH_14BIT,
     60 	DCP_OUT_TRUNC_ROUND_DEPTH_13BIT,
     61 	DCP_OUT_TRUNC_ROUND_DEPTH_12BIT,
     62 	DCP_OUT_TRUNC_ROUND_DEPTH_11BIT,
     63 	DCP_OUT_TRUNC_ROUND_DEPTH_10BIT,
     64 	DCP_OUT_TRUNC_ROUND_DEPTH_9BIT,
     65 	DCP_OUT_TRUNC_ROUND_DEPTH_8BIT
     66 };
     67 
     68 /*  defines the various methods of bit reduction available for use */
     69 enum dcp_bit_depth_reduction_mode {
     70 	DCP_BIT_DEPTH_REDUCTION_MODE_DITHER,
     71 	DCP_BIT_DEPTH_REDUCTION_MODE_ROUND,
     72 	DCP_BIT_DEPTH_REDUCTION_MODE_TRUNCATE,
     73 	DCP_BIT_DEPTH_REDUCTION_MODE_DISABLED,
     74 	DCP_BIT_DEPTH_REDUCTION_MODE_INVALID
     75 };
     76 
     77 enum dcp_spatial_dither_mode {
     78 	DCP_SPATIAL_DITHER_MODE_AAAA,
     79 	DCP_SPATIAL_DITHER_MODE_A_AA_A,
     80 	DCP_SPATIAL_DITHER_MODE_AABBAABB,
     81 	DCP_SPATIAL_DITHER_MODE_AABBCCAABBCC,
     82 	DCP_SPATIAL_DITHER_MODE_INVALID
     83 };
     84 
     85 enum dcp_spatial_dither_depth {
     86 	DCP_SPATIAL_DITHER_DEPTH_30BPP,
     87 	DCP_SPATIAL_DITHER_DEPTH_24BPP
     88 };
     89 
     90 enum csc_color_mode {
     91 	/* 00 - BITS2:0 Bypass */
     92 	CSC_COLOR_MODE_GRAPHICS_BYPASS,
     93 	/* 01 - hard coded coefficient TV RGB */
     94 	CSC_COLOR_MODE_GRAPHICS_PREDEFINED,
     95 	/* 04 - programmable OUTPUT CSC coefficient */
     96 	CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC,
     97 };
     98 
     99 enum grph_color_adjust_option {
    100 	GRPH_COLOR_MATRIX_HW_DEFAULT = 1,
    101 	GRPH_COLOR_MATRIX_SW
    102 };
    103 
    104 static const struct out_csc_color_matrix global_color_matrix[] = {
    105 { COLOR_SPACE_SRGB,
    106 	{ 0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} },
    107 { COLOR_SPACE_SRGB_LIMITED,
    108 	{ 0x1B60, 0, 0, 0x200, 0, 0x1B60, 0, 0x200, 0, 0, 0x1B60, 0x200} },
    109 { COLOR_SPACE_YCBCR601,
    110 	{ 0xE00, 0xF447, 0xFDB9, 0x1000, 0x82F, 0x1012, 0x31F, 0x200, 0xFB47,
    111 		0xF6B9, 0xE00, 0x1000} },
    112 { COLOR_SPACE_YCBCR709, { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x5D2, 0x1394, 0x1FA,
    113 	0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} },
    114 /* TODO: correct values below */
    115 { COLOR_SPACE_YCBCR601_LIMITED, { 0xE00, 0xF447, 0xFDB9, 0x1000, 0x991,
    116 	0x12C9, 0x3A6, 0x200, 0xFB47, 0xF6B9, 0xE00, 0x1000} },
    117 { COLOR_SPACE_YCBCR709_LIMITED, { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x6CE, 0x16E3,
    118 	0x24F, 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} }
    119 };
    120 
    121 static bool setup_scaling_configuration(
    122 	struct dce_transform *xfm_dce,
    123 	const struct scaler_data *data)
    124 {
    125 	REG_SET(SCL_BYPASS_CONTROL, 0, SCL_BYPASS_MODE, 0);
    126 
    127 	if (data->taps.h_taps + data->taps.v_taps <= 2) {
    128 		/* Set bypass */
    129 		if (xfm_dce->xfm_mask->SCL_PSCL_EN != 0)
    130 			REG_UPDATE_2(SCL_MODE, SCL_MODE, 0, SCL_PSCL_EN, 0);
    131 		else
    132 			REG_UPDATE(SCL_MODE, SCL_MODE, 0);
    133 		return false;
    134 	}
    135 
    136 	REG_SET_2(SCL_TAP_CONTROL, 0,
    137 			SCL_H_NUM_OF_TAPS, data->taps.h_taps - 1,
    138 			SCL_V_NUM_OF_TAPS, data->taps.v_taps - 1);
    139 
    140 	if (data->format <= PIXEL_FORMAT_GRPH_END)
    141 		REG_UPDATE(SCL_MODE, SCL_MODE, 1);
    142 	else
    143 		REG_UPDATE(SCL_MODE, SCL_MODE, 2);
    144 
    145 	if (xfm_dce->xfm_mask->SCL_PSCL_EN != 0)
    146 		REG_UPDATE(SCL_MODE, SCL_PSCL_EN, 1);
    147 
    148 	/* 1 - Replace out of bound pixels with edge */
    149 	REG_SET(SCL_CONTROL, 0, SCL_BOUNDARY_MODE, 1);
    150 
    151 	return true;
    152 }
    153 
    154 static void program_overscan(
    155 		struct dce_transform *xfm_dce,
    156 		const struct scaler_data *data)
    157 {
    158 	int overscan_right = data->h_active
    159 			- data->recout.x - data->recout.width;
    160 	int overscan_bottom = data->v_active
    161 			- data->recout.y - data->recout.height;
    162 
    163 	if (xfm_dce->base.ctx->dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE) {
    164 		overscan_bottom += 2;
    165 		overscan_right += 2;
    166 	}
    167 
    168 	if (overscan_right < 0) {
    169 		BREAK_TO_DEBUGGER();
    170 		overscan_right = 0;
    171 	}
    172 	if (overscan_bottom < 0) {
    173 		BREAK_TO_DEBUGGER();
    174 		overscan_bottom = 0;
    175 	}
    176 
    177 	REG_SET_2(EXT_OVERSCAN_LEFT_RIGHT, 0,
    178 			EXT_OVERSCAN_LEFT, data->recout.x,
    179 			EXT_OVERSCAN_RIGHT, overscan_right);
    180 	REG_SET_2(EXT_OVERSCAN_TOP_BOTTOM, 0,
    181 			EXT_OVERSCAN_TOP, data->recout.y,
    182 			EXT_OVERSCAN_BOTTOM, overscan_bottom);
    183 }
    184 
    185 static void program_multi_taps_filter(
    186 	struct dce_transform *xfm_dce,
    187 	int taps,
    188 	const uint16_t *coeffs,
    189 	enum ram_filter_type filter_type)
    190 {
    191 	int phase, pair;
    192 	int array_idx = 0;
    193 	int taps_pairs = (taps + 1) / 2;
    194 	int phases_to_program = SCL_PHASES / 2 + 1;
    195 
    196 	uint32_t power_ctl = 0;
    197 
    198 	if (!coeffs)
    199 		return;
    200 
    201 	/*We need to disable power gating on coeff memory to do programming*/
    202 	if (REG(DCFE_MEM_PWR_CTRL)) {
    203 		power_ctl = REG_READ(DCFE_MEM_PWR_CTRL);
    204 		REG_SET(DCFE_MEM_PWR_CTRL, power_ctl, SCL_COEFF_MEM_PWR_DIS, 1);
    205 
    206 		REG_WAIT(DCFE_MEM_PWR_STATUS, SCL_COEFF_MEM_PWR_STATE, 0, 1, 10);
    207 	}
    208 	for (phase = 0; phase < phases_to_program; phase++) {
    209 		/*we always program N/2 + 1 phases, total phases N, but N/2-1 are just mirror
    210 		phase 0 is unique and phase N/2 is unique if N is even*/
    211 		for (pair = 0; pair < taps_pairs; pair++) {
    212 			uint16_t odd_coeff = 0;
    213 			uint16_t even_coeff = coeffs[array_idx];
    214 
    215 			REG_SET_3(SCL_COEF_RAM_SELECT, 0,
    216 					SCL_C_RAM_FILTER_TYPE, filter_type,
    217 					SCL_C_RAM_PHASE, phase,
    218 					SCL_C_RAM_TAP_PAIR_IDX, pair);
    219 
    220 			if (taps % 2 && pair == taps_pairs - 1)
    221 				array_idx++;
    222 			else {
    223 				odd_coeff = coeffs[array_idx + 1];
    224 				array_idx += 2;
    225 			}
    226 
    227 			REG_SET_4(SCL_COEF_RAM_TAP_DATA, 0,
    228 					SCL_C_RAM_EVEN_TAP_COEF_EN, 1,
    229 					SCL_C_RAM_EVEN_TAP_COEF, even_coeff,
    230 					SCL_C_RAM_ODD_TAP_COEF_EN, 1,
    231 					SCL_C_RAM_ODD_TAP_COEF, odd_coeff);
    232 		}
    233 	}
    234 
    235 	/*We need to restore power gating on coeff memory to initial state*/
    236 	if (REG(DCFE_MEM_PWR_CTRL))
    237 		REG_WRITE(DCFE_MEM_PWR_CTRL, power_ctl);
    238 }
    239 
    240 static void program_viewport(
    241 	struct dce_transform *xfm_dce,
    242 	const struct rect *view_port)
    243 {
    244 	REG_SET_2(VIEWPORT_START, 0,
    245 			VIEWPORT_X_START, view_port->x,
    246 			VIEWPORT_Y_START, view_port->y);
    247 
    248 	REG_SET_2(VIEWPORT_SIZE, 0,
    249 			VIEWPORT_HEIGHT, view_port->height,
    250 			VIEWPORT_WIDTH, view_port->width);
    251 
    252 	/* TODO: add stereo support */
    253 }
    254 
    255 static void calculate_inits(
    256 	struct dce_transform *xfm_dce,
    257 	const struct scaler_data *data,
    258 	struct scl_ratios_inits *inits)
    259 {
    260 	struct fixed31_32 h_init;
    261 	struct fixed31_32 v_init;
    262 
    263 	inits->h_int_scale_ratio =
    264 		dc_fixpt_u2d19(data->ratios.horz) << 5;
    265 	inits->v_int_scale_ratio =
    266 		dc_fixpt_u2d19(data->ratios.vert) << 5;
    267 
    268 	h_init =
    269 		dc_fixpt_div_int(
    270 			dc_fixpt_add(
    271 				data->ratios.horz,
    272 				dc_fixpt_from_int(data->taps.h_taps + 1)),
    273 				2);
    274 	inits->h_init.integer = dc_fixpt_floor(h_init);
    275 	inits->h_init.fraction = dc_fixpt_u0d19(h_init) << 5;
    276 
    277 	v_init =
    278 		dc_fixpt_div_int(
    279 			dc_fixpt_add(
    280 				data->ratios.vert,
    281 				dc_fixpt_from_int(data->taps.v_taps + 1)),
    282 				2);
    283 	inits->v_init.integer = dc_fixpt_floor(v_init);
    284 	inits->v_init.fraction = dc_fixpt_u0d19(v_init) << 5;
    285 }
    286 
    287 static void program_scl_ratios_inits(
    288 	struct dce_transform *xfm_dce,
    289 	struct scl_ratios_inits *inits)
    290 {
    291 
    292 	REG_SET(SCL_HORZ_FILTER_SCALE_RATIO, 0,
    293 			SCL_H_SCALE_RATIO, inits->h_int_scale_ratio);
    294 
    295 	REG_SET(SCL_VERT_FILTER_SCALE_RATIO, 0,
    296 			SCL_V_SCALE_RATIO, inits->v_int_scale_ratio);
    297 
    298 	REG_SET_2(SCL_HORZ_FILTER_INIT, 0,
    299 			SCL_H_INIT_INT, inits->h_init.integer,
    300 			SCL_H_INIT_FRAC, inits->h_init.fraction);
    301 
    302 	REG_SET_2(SCL_VERT_FILTER_INIT, 0,
    303 			SCL_V_INIT_INT, inits->v_init.integer,
    304 			SCL_V_INIT_FRAC, inits->v_init.fraction);
    305 
    306 	REG_WRITE(SCL_AUTOMATIC_MODE_CONTROL, 0);
    307 }
    308 
    309 static const uint16_t *get_filter_coeffs_16p(int taps, struct fixed31_32 ratio)
    310 {
    311 	if (taps == 4)
    312 		return get_filter_4tap_16p(ratio);
    313 	else if (taps == 3)
    314 		return get_filter_3tap_16p(ratio);
    315 	else if (taps == 2)
    316 		return get_filter_2tap_16p();
    317 	else if (taps == 1)
    318 		return NULL;
    319 	else {
    320 		/* should never happen, bug */
    321 		BREAK_TO_DEBUGGER();
    322 		return NULL;
    323 	}
    324 }
    325 
    326 static void dce_transform_set_scaler(
    327 	struct transform *xfm,
    328 	const struct scaler_data *data)
    329 {
    330 	struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
    331 	bool is_scaling_required;
    332 	bool filter_updated = false;
    333 	const uint16_t *coeffs_v, *coeffs_h;
    334 
    335 	/*Use all three pieces of memory always*/
    336 	REG_SET_2(LB_MEMORY_CTRL, 0,
    337 			LB_MEMORY_CONFIG, 0,
    338 			LB_MEMORY_SIZE, xfm_dce->lb_memory_size);
    339 
    340 	/* Clear SCL_F_SHARP_CONTROL value to 0 */
    341 	REG_WRITE(SCL_F_SHARP_CONTROL, 0);
    342 
    343 	/* 1. Program overscan */
    344 	program_overscan(xfm_dce, data);
    345 
    346 	/* 2. Program taps and configuration */
    347 	is_scaling_required = setup_scaling_configuration(xfm_dce, data);
    348 
    349 	if (is_scaling_required) {
    350 		/* 3. Calculate and program ratio, filter initialization */
    351 		struct scl_ratios_inits inits = { 0 };
    352 
    353 		calculate_inits(xfm_dce, data, &inits);
    354 
    355 		program_scl_ratios_inits(xfm_dce, &inits);
    356 
    357 		coeffs_v = get_filter_coeffs_16p(data->taps.v_taps, data->ratios.vert);
    358 		coeffs_h = get_filter_coeffs_16p(data->taps.h_taps, data->ratios.horz);
    359 
    360 		if (coeffs_v != xfm_dce->filter_v || coeffs_h != xfm_dce->filter_h) {
    361 			/* 4. Program vertical filters */
    362 			if (xfm_dce->filter_v == NULL)
    363 				REG_SET(SCL_VERT_FILTER_CONTROL, 0,
    364 						SCL_V_2TAP_HARDCODE_COEF_EN, 0);
    365 			program_multi_taps_filter(
    366 					xfm_dce,
    367 					data->taps.v_taps,
    368 					coeffs_v,
    369 					FILTER_TYPE_RGB_Y_VERTICAL);
    370 			program_multi_taps_filter(
    371 					xfm_dce,
    372 					data->taps.v_taps,
    373 					coeffs_v,
    374 					FILTER_TYPE_ALPHA_VERTICAL);
    375 
    376 			/* 5. Program horizontal filters */
    377 			if (xfm_dce->filter_h == NULL)
    378 				REG_SET(SCL_HORZ_FILTER_CONTROL, 0,
    379 						SCL_H_2TAP_HARDCODE_COEF_EN, 0);
    380 			program_multi_taps_filter(
    381 					xfm_dce,
    382 					data->taps.h_taps,
    383 					coeffs_h,
    384 					FILTER_TYPE_RGB_Y_HORIZONTAL);
    385 			program_multi_taps_filter(
    386 					xfm_dce,
    387 					data->taps.h_taps,
    388 					coeffs_h,
    389 					FILTER_TYPE_ALPHA_HORIZONTAL);
    390 
    391 			xfm_dce->filter_v = coeffs_v;
    392 			xfm_dce->filter_h = coeffs_h;
    393 			filter_updated = true;
    394 		}
    395 	}
    396 
    397 	/* 6. Program the viewport */
    398 	program_viewport(xfm_dce, &data->viewport);
    399 
    400 	/* 7. Set bit to flip to new coefficient memory */
    401 	if (filter_updated)
    402 		REG_UPDATE(SCL_UPDATE, SCL_COEF_UPDATE_COMPLETE, 1);
    403 
    404 	REG_UPDATE(LB_DATA_FORMAT, ALPHA_EN, data->lb_params.alpha_en);
    405 }
    406 
    407 /*****************************************************************************
    408  * set_clamp
    409  *
    410  * @param depth : bit depth to set the clamp to (should match denorm)
    411  *
    412  * @brief
    413  *     Programs clamp according to panel bit depth.
    414  *
    415  *******************************************************************************/
    416 static void set_clamp(
    417 	struct dce_transform *xfm_dce,
    418 	enum dc_color_depth depth)
    419 {
    420 	int clamp_max = 0;
    421 
    422 	/* At the clamp block the data will be MSB aligned, so we set the max
    423 	 * clamp accordingly.
    424 	 * For example, the max value for 6 bits MSB aligned (14 bit bus) would
    425 	 * be "11 1111 0000 0000" in binary, so 0x3F00.
    426 	 */
    427 	switch (depth) {
    428 	case COLOR_DEPTH_666:
    429 		/* 6bit MSB aligned on 14 bit bus '11 1111 0000 0000' */
    430 		clamp_max = 0x3F00;
    431 		break;
    432 	case COLOR_DEPTH_888:
    433 		/* 8bit MSB aligned on 14 bit bus '11 1111 1100 0000' */
    434 		clamp_max = 0x3FC0;
    435 		break;
    436 	case COLOR_DEPTH_101010:
    437 		/* 10bit MSB aligned on 14 bit bus '11 1111 1111 1100' */
    438 		clamp_max = 0x3FFC;
    439 		break;
    440 	case COLOR_DEPTH_121212:
    441 		/* 12bit MSB aligned on 14 bit bus '11 1111 1111 1111' */
    442 		clamp_max = 0x3FFF;
    443 		break;
    444 	default:
    445 		clamp_max = 0x3FC0;
    446 		BREAK_TO_DEBUGGER(); /* Invalid clamp bit depth */
    447 	}
    448 	REG_SET_2(OUT_CLAMP_CONTROL_B_CB, 0,
    449 			OUT_CLAMP_MIN_B_CB, 0,
    450 			OUT_CLAMP_MAX_B_CB, clamp_max);
    451 
    452 	REG_SET_2(OUT_CLAMP_CONTROL_G_Y, 0,
    453 			OUT_CLAMP_MIN_G_Y, 0,
    454 			OUT_CLAMP_MAX_G_Y, clamp_max);
    455 
    456 	REG_SET_2(OUT_CLAMP_CONTROL_R_CR, 0,
    457 			OUT_CLAMP_MIN_R_CR, 0,
    458 			OUT_CLAMP_MAX_R_CR, clamp_max);
    459 }
    460 
    461 /*******************************************************************************
    462  * set_round
    463  *
    464  * @brief
    465  *     Programs Round/Truncate
    466  *
    467  * @param [in] mode  :round or truncate
    468  * @param [in] depth :bit depth to round/truncate to
    469  OUT_ROUND_TRUNC_MODE 3:0 0xA Output data round or truncate mode
    470  POSSIBLE VALUES:
    471       00 - truncate to u0.12
    472       01 - truncate to u0.11
    473       02 - truncate to u0.10
    474       03 - truncate to u0.9
    475       04 - truncate to u0.8
    476       05 - reserved
    477       06 - truncate to u0.14
    478       07 - truncate to u0.13		set_reg_field_value(
    479 			value,
    480 			clamp_max,
    481 			OUT_CLAMP_CONTROL_R_CR,
    482 			OUT_CLAMP_MAX_R_CR);
    483       08 - round to u0.12
    484       09 - round to u0.11
    485       10 - round to u0.10
    486       11 - round to u0.9
    487       12 - round to u0.8
    488       13 - reserved
    489       14 - round to u0.14
    490       15 - round to u0.13
    491 
    492  ******************************************************************************/
    493 static void set_round(
    494 	struct dce_transform *xfm_dce,
    495 	enum dcp_out_trunc_round_mode mode,
    496 	enum dcp_out_trunc_round_depth depth)
    497 {
    498 	int depth_bits = 0;
    499 	int mode_bit = 0;
    500 
    501 	/*  set up bit depth */
    502 	switch (depth) {
    503 	case DCP_OUT_TRUNC_ROUND_DEPTH_14BIT:
    504 		depth_bits = 6;
    505 		break;
    506 	case DCP_OUT_TRUNC_ROUND_DEPTH_13BIT:
    507 		depth_bits = 7;
    508 		break;
    509 	case DCP_OUT_TRUNC_ROUND_DEPTH_12BIT:
    510 		depth_bits = 0;
    511 		break;
    512 	case DCP_OUT_TRUNC_ROUND_DEPTH_11BIT:
    513 		depth_bits = 1;
    514 		break;
    515 	case DCP_OUT_TRUNC_ROUND_DEPTH_10BIT:
    516 		depth_bits = 2;
    517 		break;
    518 	case DCP_OUT_TRUNC_ROUND_DEPTH_9BIT:
    519 		depth_bits = 3;
    520 		break;
    521 	case DCP_OUT_TRUNC_ROUND_DEPTH_8BIT:
    522 		depth_bits = 4;
    523 		break;
    524 	default:
    525 		depth_bits = 4;
    526 		BREAK_TO_DEBUGGER(); /* Invalid dcp_out_trunc_round_depth */
    527 	}
    528 
    529 	/*  set up round or truncate */
    530 	switch (mode) {
    531 	case DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE:
    532 		mode_bit = 0;
    533 		break;
    534 	case DCP_OUT_TRUNC_ROUND_MODE_ROUND:
    535 		mode_bit = 1;
    536 		break;
    537 	default:
    538 		BREAK_TO_DEBUGGER(); /* Invalid dcp_out_trunc_round_mode */
    539 	}
    540 
    541 	depth_bits |= mode_bit << 3;
    542 
    543 	REG_SET(OUT_ROUND_CONTROL, 0, OUT_ROUND_TRUNC_MODE, depth_bits);
    544 }
    545 
    546 /*****************************************************************************
    547  * set_dither
    548  *
    549  * @brief
    550  *     Programs Dither
    551  *
    552  * @param [in] dither_enable        : enable dither
    553  * @param [in] dither_mode           : dither mode to set
    554  * @param [in] dither_depth          : bit depth to dither to
    555  * @param [in] frame_random_enable    : enable frame random
    556  * @param [in] rgb_random_enable      : enable rgb random
    557  * @param [in] highpass_random_enable : enable highpass random
    558  *
    559  ******************************************************************************/
    560 
    561 static void set_dither(
    562 	struct dce_transform *xfm_dce,
    563 	bool dither_enable,
    564 	enum dcp_spatial_dither_mode dither_mode,
    565 	enum dcp_spatial_dither_depth dither_depth,
    566 	bool frame_random_enable,
    567 	bool rgb_random_enable,
    568 	bool highpass_random_enable)
    569 {
    570 	int dither_depth_bits = 0;
    571 	int dither_mode_bits = 0;
    572 
    573 	switch (dither_mode) {
    574 	case DCP_SPATIAL_DITHER_MODE_AAAA:
    575 		dither_mode_bits = 0;
    576 		break;
    577 	case DCP_SPATIAL_DITHER_MODE_A_AA_A:
    578 		dither_mode_bits = 1;
    579 		break;
    580 	case DCP_SPATIAL_DITHER_MODE_AABBAABB:
    581 		dither_mode_bits = 2;
    582 		break;
    583 	case DCP_SPATIAL_DITHER_MODE_AABBCCAABBCC:
    584 		dither_mode_bits = 3;
    585 		break;
    586 	default:
    587 		/* Invalid dcp_spatial_dither_mode */
    588 		BREAK_TO_DEBUGGER();
    589 	}
    590 
    591 	switch (dither_depth) {
    592 	case DCP_SPATIAL_DITHER_DEPTH_30BPP:
    593 		dither_depth_bits = 0;
    594 		break;
    595 	case DCP_SPATIAL_DITHER_DEPTH_24BPP:
    596 		dither_depth_bits = 1;
    597 		break;
    598 	default:
    599 		/* Invalid dcp_spatial_dither_depth */
    600 		BREAK_TO_DEBUGGER();
    601 	}
    602 
    603 	/*  write the register */
    604 	REG_SET_6(DCP_SPATIAL_DITHER_CNTL, 0,
    605 			DCP_SPATIAL_DITHER_EN, dither_enable,
    606 			DCP_SPATIAL_DITHER_MODE, dither_mode_bits,
    607 			DCP_SPATIAL_DITHER_DEPTH, dither_depth_bits,
    608 			DCP_FRAME_RANDOM_ENABLE, frame_random_enable,
    609 			DCP_RGB_RANDOM_ENABLE, rgb_random_enable,
    610 			DCP_HIGHPASS_RANDOM_ENABLE, highpass_random_enable);
    611 }
    612 
    613 /*****************************************************************************
    614  * dce_transform_bit_depth_reduction_program
    615  *
    616  * @brief
    617  *     Programs the DCP bit depth reduction registers (Clamp, Round/Truncate,
    618  *      Dither) for dce
    619  *
    620  * @param depth : bit depth to set the clamp to (should match denorm)
    621  *
    622  ******************************************************************************/
    623 static void program_bit_depth_reduction(
    624 	struct dce_transform *xfm_dce,
    625 	enum dc_color_depth depth,
    626 	const struct bit_depth_reduction_params *bit_depth_params)
    627 {
    628 	enum dcp_out_trunc_round_depth trunc_round_depth;
    629 	enum dcp_out_trunc_round_mode trunc_mode;
    630 	bool spatial_dither_enable;
    631 
    632 	ASSERT(depth < COLOR_DEPTH_121212); /* Invalid clamp bit depth */
    633 
    634 	spatial_dither_enable = bit_depth_params->flags.SPATIAL_DITHER_ENABLED;
    635 	/* Default to 12 bit truncation without rounding */
    636 	trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_12BIT;
    637 	trunc_mode = DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE;
    638 
    639 	if (bit_depth_params->flags.TRUNCATE_ENABLED) {
    640 		/* Don't enable dithering if truncation is enabled */
    641 		spatial_dither_enable = false;
    642 		trunc_mode = bit_depth_params->flags.TRUNCATE_MODE ?
    643 			     DCP_OUT_TRUNC_ROUND_MODE_ROUND :
    644 			     DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE;
    645 
    646 		if (bit_depth_params->flags.TRUNCATE_DEPTH == 0 ||
    647 		    bit_depth_params->flags.TRUNCATE_DEPTH == 1)
    648 			trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_8BIT;
    649 		else if (bit_depth_params->flags.TRUNCATE_DEPTH == 2)
    650 			trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_10BIT;
    651 		else {
    652 			/*
    653 			 * Invalid truncate/round depth. Setting here to 12bit
    654 			 * to prevent use-before-initialize errors.
    655 			 */
    656 			trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_12BIT;
    657 			BREAK_TO_DEBUGGER();
    658 		}
    659 	}
    660 
    661 	set_clamp(xfm_dce, depth);
    662 	set_round(xfm_dce, trunc_mode, trunc_round_depth);
    663 	set_dither(xfm_dce,
    664 		   spatial_dither_enable,
    665 		   DCP_SPATIAL_DITHER_MODE_A_AA_A,
    666 		   DCP_SPATIAL_DITHER_DEPTH_30BPP,
    667 		   bit_depth_params->flags.FRAME_RANDOM,
    668 		   bit_depth_params->flags.RGB_RANDOM,
    669 		   bit_depth_params->flags.HIGHPASS_RANDOM);
    670 }
    671 
    672 static int dce_transform_get_max_num_of_supported_lines(
    673 	struct dce_transform *xfm_dce,
    674 	enum lb_pixel_depth depth,
    675 	int pixel_width)
    676 {
    677 	int pixels_per_entries = 0;
    678 	int max_pixels_supports = 0;
    679 
    680 	ASSERT(pixel_width);
    681 
    682 	/* Find number of pixels that can fit into a single LB entry and
    683 	 * take floor of the value since we cannot store a single pixel
    684 	 * across multiple entries. */
    685 	switch (depth) {
    686 	case LB_PIXEL_DEPTH_18BPP:
    687 		pixels_per_entries = xfm_dce->lb_bits_per_entry / 18;
    688 		break;
    689 
    690 	case LB_PIXEL_DEPTH_24BPP:
    691 		pixels_per_entries = xfm_dce->lb_bits_per_entry / 24;
    692 		break;
    693 
    694 	case LB_PIXEL_DEPTH_30BPP:
    695 		pixels_per_entries = xfm_dce->lb_bits_per_entry / 30;
    696 		break;
    697 
    698 	case LB_PIXEL_DEPTH_36BPP:
    699 		pixels_per_entries = xfm_dce->lb_bits_per_entry / 36;
    700 		break;
    701 
    702 	default:
    703 		DC_LOG_WARNING("%s: Invalid LB pixel depth",
    704 			__func__);
    705 		BREAK_TO_DEBUGGER();
    706 		break;
    707 	}
    708 
    709 	ASSERT(pixels_per_entries);
    710 
    711 	max_pixels_supports =
    712 			pixels_per_entries *
    713 			xfm_dce->lb_memory_size;
    714 
    715 	return (max_pixels_supports / pixel_width);
    716 }
    717 
    718 static void set_denormalization(
    719 	struct dce_transform *xfm_dce,
    720 	enum dc_color_depth depth)
    721 {
    722 	int denorm_mode = 0;
    723 
    724 	switch (depth) {
    725 	case COLOR_DEPTH_666:
    726 		/* 63/64 for 6 bit output color depth */
    727 		denorm_mode = 1;
    728 		break;
    729 	case COLOR_DEPTH_888:
    730 		/* Unity for 8 bit output color depth
    731 		 * because prescale is disabled by default */
    732 		denorm_mode = 0;
    733 		break;
    734 	case COLOR_DEPTH_101010:
    735 		/* 1023/1024 for 10 bit output color depth */
    736 		denorm_mode = 3;
    737 		break;
    738 	case COLOR_DEPTH_121212:
    739 		/* 4095/4096 for 12 bit output color depth */
    740 		denorm_mode = 5;
    741 		break;
    742 	case COLOR_DEPTH_141414:
    743 	case COLOR_DEPTH_161616:
    744 	default:
    745 		/* not valid used case! */
    746 		break;
    747 	}
    748 
    749 	REG_SET(DENORM_CONTROL, 0, DENORM_MODE, denorm_mode);
    750 }
    751 
    752 static void dce_transform_set_pixel_storage_depth(
    753 	struct transform *xfm,
    754 	enum lb_pixel_depth depth,
    755 	const struct bit_depth_reduction_params *bit_depth_params)
    756 {
    757 	struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
    758 	int pixel_depth, expan_mode;
    759 	enum dc_color_depth color_depth;
    760 
    761 	switch (depth) {
    762 	case LB_PIXEL_DEPTH_18BPP:
    763 		color_depth = COLOR_DEPTH_666;
    764 		pixel_depth = 2;
    765 		expan_mode  = 1;
    766 		break;
    767 	case LB_PIXEL_DEPTH_24BPP:
    768 		color_depth = COLOR_DEPTH_888;
    769 		pixel_depth = 1;
    770 		expan_mode  = 1;
    771 		break;
    772 	case LB_PIXEL_DEPTH_30BPP:
    773 		color_depth = COLOR_DEPTH_101010;
    774 		pixel_depth = 0;
    775 		expan_mode  = 1;
    776 		break;
    777 	case LB_PIXEL_DEPTH_36BPP:
    778 		color_depth = COLOR_DEPTH_121212;
    779 		pixel_depth = 3;
    780 		expan_mode  = 0;
    781 		break;
    782 	default:
    783 		color_depth = COLOR_DEPTH_101010;
    784 		pixel_depth = 0;
    785 		expan_mode  = 1;
    786 		BREAK_TO_DEBUGGER();
    787 		break;
    788 	}
    789 
    790 	set_denormalization(xfm_dce, color_depth);
    791 	program_bit_depth_reduction(xfm_dce, color_depth, bit_depth_params);
    792 
    793 	REG_UPDATE_2(LB_DATA_FORMAT,
    794 			PIXEL_DEPTH, pixel_depth,
    795 			PIXEL_EXPAN_MODE, expan_mode);
    796 
    797 	if (!(xfm_dce->lb_pixel_depth_supported & depth)) {
    798 		/*we should use unsupported capabilities
    799 		 *  unless it is required by w/a*/
    800 		DC_LOG_WARNING("%s: Capability not supported",
    801 			__func__);
    802 	}
    803 }
    804 
    805 static void program_gamut_remap(
    806 	struct dce_transform *xfm_dce,
    807 	const uint16_t *reg_val)
    808 {
    809 	if (reg_val) {
    810 		REG_SET_2(GAMUT_REMAP_C11_C12, 0,
    811 				GAMUT_REMAP_C11, reg_val[0],
    812 				GAMUT_REMAP_C12, reg_val[1]);
    813 		REG_SET_2(GAMUT_REMAP_C13_C14, 0,
    814 				GAMUT_REMAP_C13, reg_val[2],
    815 				GAMUT_REMAP_C14, reg_val[3]);
    816 		REG_SET_2(GAMUT_REMAP_C21_C22, 0,
    817 				GAMUT_REMAP_C21, reg_val[4],
    818 				GAMUT_REMAP_C22, reg_val[5]);
    819 		REG_SET_2(GAMUT_REMAP_C23_C24, 0,
    820 				GAMUT_REMAP_C23, reg_val[6],
    821 				GAMUT_REMAP_C24, reg_val[7]);
    822 		REG_SET_2(GAMUT_REMAP_C31_C32, 0,
    823 				GAMUT_REMAP_C31, reg_val[8],
    824 				GAMUT_REMAP_C32, reg_val[9]);
    825 		REG_SET_2(GAMUT_REMAP_C33_C34, 0,
    826 				GAMUT_REMAP_C33, reg_val[10],
    827 				GAMUT_REMAP_C34, reg_val[11]);
    828 
    829 		REG_SET(GAMUT_REMAP_CONTROL, 0, GRPH_GAMUT_REMAP_MODE, 1);
    830 	} else
    831 		REG_SET(GAMUT_REMAP_CONTROL, 0, GRPH_GAMUT_REMAP_MODE, 0);
    832 
    833 }
    834 
    835 /**
    836  *****************************************************************************
    837  *  Function: dal_transform_wide_gamut_set_gamut_remap
    838  *
    839  *  @param [in] const struct xfm_grph_csc_adjustment *adjust
    840  *
    841  *  @return
    842  *     void
    843  *
    844  *  @note calculate and apply color temperature adjustment to in Rgb color space
    845  *
    846  *  @see
    847  *
    848  *****************************************************************************
    849  */
    850 static void dce_transform_set_gamut_remap(
    851 	struct transform *xfm,
    852 	const struct xfm_grph_csc_adjustment *adjust)
    853 {
    854 	struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
    855 	int i = 0;
    856 
    857 	if (adjust->gamut_adjust_type != GRAPHICS_GAMUT_ADJUST_TYPE_SW)
    858 		/* Bypass if type is bypass or hw */
    859 		program_gamut_remap(xfm_dce, NULL);
    860 	else {
    861 		struct fixed31_32 arr_matrix[GAMUT_MATRIX_SIZE];
    862 		uint16_t arr_reg_val[GAMUT_MATRIX_SIZE];
    863 
    864 		for (i = 0; i < GAMUT_MATRIX_SIZE; i++)
    865 			arr_matrix[i] = adjust->temperature_matrix[i];
    866 
    867 		convert_float_matrix(
    868 			arr_reg_val, arr_matrix, GAMUT_MATRIX_SIZE);
    869 
    870 		program_gamut_remap(xfm_dce, arr_reg_val);
    871 	}
    872 }
    873 
    874 static uint32_t decide_taps(struct fixed31_32 ratio, uint32_t in_taps, bool chroma)
    875 {
    876 	uint32_t taps;
    877 
    878 	if (IDENTITY_RATIO(ratio)) {
    879 		return 1;
    880 	} else if (in_taps != 0) {
    881 		taps = in_taps;
    882 	} else {
    883 		taps = 4;
    884 	}
    885 
    886 	if (chroma) {
    887 		taps /= 2;
    888 		if (taps < 2)
    889 			taps = 2;
    890 	}
    891 
    892 	return taps;
    893 }
    894 
    895 
    896 bool dce_transform_get_optimal_number_of_taps(
    897 	struct transform *xfm,
    898 	struct scaler_data *scl_data,
    899 	const struct scaling_taps *in_taps)
    900 {
    901 	struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
    902 	int pixel_width = scl_data->viewport.width;
    903 	int max_num_of_lines;
    904 
    905 	if (xfm_dce->prescaler_on &&
    906 			(scl_data->viewport.width > scl_data->recout.width))
    907 		pixel_width = scl_data->recout.width;
    908 
    909 	max_num_of_lines = dce_transform_get_max_num_of_supported_lines(
    910 		xfm_dce,
    911 		scl_data->lb_params.depth,
    912 		pixel_width);
    913 
    914 	/* Fail if in_taps are impossible */
    915 	if (in_taps->v_taps >= max_num_of_lines)
    916 		return false;
    917 
    918 	/*
    919 	 * Set taps according to this policy (in this order)
    920 	 * - Use 1 for no scaling
    921 	 * - Use input taps
    922 	 * - Use 4 and reduce as required by line buffer size
    923 	 * - Decide chroma taps if chroma is scaled
    924 	 *
    925 	 * Ignore input chroma taps. Decide based on non-chroma
    926 	 */
    927 	scl_data->taps.h_taps = decide_taps(scl_data->ratios.horz, in_taps->h_taps, false);
    928 	scl_data->taps.v_taps = decide_taps(scl_data->ratios.vert, in_taps->v_taps, false);
    929 	scl_data->taps.h_taps_c = decide_taps(scl_data->ratios.horz_c, in_taps->h_taps, true);
    930 	scl_data->taps.v_taps_c = decide_taps(scl_data->ratios.vert_c, in_taps->v_taps, true);
    931 
    932 	if (!IDENTITY_RATIO(scl_data->ratios.vert)) {
    933 		/* reduce v_taps if needed but ensure we have at least two */
    934 		if (in_taps->v_taps == 0
    935 				&& max_num_of_lines <= scl_data->taps.v_taps
    936 				&& scl_data->taps.v_taps > 1) {
    937 			scl_data->taps.v_taps = max_num_of_lines - 1;
    938 		}
    939 
    940 		if (scl_data->taps.v_taps <= 1)
    941 			return false;
    942 	}
    943 
    944 	if (!IDENTITY_RATIO(scl_data->ratios.vert_c)) {
    945 		/* reduce chroma v_taps if needed but ensure we have at least two */
    946 		if (max_num_of_lines <= scl_data->taps.v_taps_c && scl_data->taps.v_taps_c > 1) {
    947 			scl_data->taps.v_taps_c = max_num_of_lines - 1;
    948 		}
    949 
    950 		if (scl_data->taps.v_taps_c <= 1)
    951 			return false;
    952 	}
    953 
    954 	/* we've got valid taps */
    955 	return true;
    956 }
    957 
    958 static void dce_transform_reset(struct transform *xfm)
    959 {
    960 	struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
    961 
    962 	xfm_dce->filter_h = NULL;
    963 	xfm_dce->filter_v = NULL;
    964 }
    965 
    966 static void program_color_matrix(
    967 	struct dce_transform *xfm_dce,
    968 	const struct out_csc_color_matrix *tbl_entry,
    969 	enum grph_color_adjust_option options)
    970 {
    971 	{
    972 		REG_SET_2(OUTPUT_CSC_C11_C12, 0,
    973 			OUTPUT_CSC_C11, tbl_entry->regval[0],
    974 			OUTPUT_CSC_C12, tbl_entry->regval[1]);
    975 	}
    976 	{
    977 		REG_SET_2(OUTPUT_CSC_C13_C14, 0,
    978 			OUTPUT_CSC_C11, tbl_entry->regval[2],
    979 			OUTPUT_CSC_C12, tbl_entry->regval[3]);
    980 	}
    981 	{
    982 		REG_SET_2(OUTPUT_CSC_C21_C22, 0,
    983 			OUTPUT_CSC_C11, tbl_entry->regval[4],
    984 			OUTPUT_CSC_C12, tbl_entry->regval[5]);
    985 	}
    986 	{
    987 		REG_SET_2(OUTPUT_CSC_C23_C24, 0,
    988 			OUTPUT_CSC_C11, tbl_entry->regval[6],
    989 			OUTPUT_CSC_C12, tbl_entry->regval[7]);
    990 	}
    991 	{
    992 		REG_SET_2(OUTPUT_CSC_C31_C32, 0,
    993 			OUTPUT_CSC_C11, tbl_entry->regval[8],
    994 			OUTPUT_CSC_C12, tbl_entry->regval[9]);
    995 	}
    996 	{
    997 		REG_SET_2(OUTPUT_CSC_C33_C34, 0,
    998 			OUTPUT_CSC_C11, tbl_entry->regval[10],
    999 			OUTPUT_CSC_C12, tbl_entry->regval[11]);
   1000 	}
   1001 }
   1002 
   1003 static bool configure_graphics_mode(
   1004 	struct dce_transform *xfm_dce,
   1005 	enum csc_color_mode config,
   1006 	enum graphics_csc_adjust_type csc_adjust_type,
   1007 	enum dc_color_space color_space)
   1008 {
   1009 	REG_SET(OUTPUT_CSC_CONTROL, 0,
   1010 		OUTPUT_CSC_GRPH_MODE, 0);
   1011 
   1012 	if (csc_adjust_type == GRAPHICS_CSC_ADJUST_TYPE_SW) {
   1013 		if (config == CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC) {
   1014 			REG_SET(OUTPUT_CSC_CONTROL, 0,
   1015 				OUTPUT_CSC_GRPH_MODE, 4);
   1016 		} else {
   1017 
   1018 			switch (color_space) {
   1019 			case COLOR_SPACE_SRGB:
   1020 				/* by pass */
   1021 				REG_SET(OUTPUT_CSC_CONTROL, 0,
   1022 					OUTPUT_CSC_GRPH_MODE, 0);
   1023 				break;
   1024 			case COLOR_SPACE_SRGB_LIMITED:
   1025 				/* TV RGB */
   1026 				REG_SET(OUTPUT_CSC_CONTROL, 0,
   1027 					OUTPUT_CSC_GRPH_MODE, 1);
   1028 				break;
   1029 			case COLOR_SPACE_YCBCR601:
   1030 			case COLOR_SPACE_YCBCR601_LIMITED:
   1031 				/* YCbCr601 */
   1032 				REG_SET(OUTPUT_CSC_CONTROL, 0,
   1033 					OUTPUT_CSC_GRPH_MODE, 2);
   1034 				break;
   1035 			case COLOR_SPACE_YCBCR709:
   1036 			case COLOR_SPACE_YCBCR709_LIMITED:
   1037 				/* YCbCr709 */
   1038 				REG_SET(OUTPUT_CSC_CONTROL, 0,
   1039 					OUTPUT_CSC_GRPH_MODE, 3);
   1040 				break;
   1041 			default:
   1042 				return false;
   1043 			}
   1044 		}
   1045 	} else if (csc_adjust_type == GRAPHICS_CSC_ADJUST_TYPE_HW) {
   1046 		switch (color_space) {
   1047 		case COLOR_SPACE_SRGB:
   1048 			/* by pass */
   1049 			REG_SET(OUTPUT_CSC_CONTROL, 0,
   1050 				OUTPUT_CSC_GRPH_MODE, 0);
   1051 			break;
   1052 			break;
   1053 		case COLOR_SPACE_SRGB_LIMITED:
   1054 			/* TV RGB */
   1055 			REG_SET(OUTPUT_CSC_CONTROL, 0,
   1056 				OUTPUT_CSC_GRPH_MODE, 1);
   1057 			break;
   1058 		case COLOR_SPACE_YCBCR601:
   1059 		case COLOR_SPACE_YCBCR601_LIMITED:
   1060 			/* YCbCr601 */
   1061 			REG_SET(OUTPUT_CSC_CONTROL, 0,
   1062 				OUTPUT_CSC_GRPH_MODE, 2);
   1063 			break;
   1064 		case COLOR_SPACE_YCBCR709:
   1065 		case COLOR_SPACE_YCBCR709_LIMITED:
   1066 			 /* YCbCr709 */
   1067 			REG_SET(OUTPUT_CSC_CONTROL, 0,
   1068 				OUTPUT_CSC_GRPH_MODE, 3);
   1069 			break;
   1070 		default:
   1071 			return false;
   1072 		}
   1073 
   1074 	} else
   1075 		/* by pass */
   1076 		REG_SET(OUTPUT_CSC_CONTROL, 0,
   1077 			OUTPUT_CSC_GRPH_MODE, 0);
   1078 
   1079 	return true;
   1080 }
   1081 
   1082 void dce110_opp_set_csc_adjustment(
   1083 	struct transform *xfm,
   1084 	const struct out_csc_color_matrix *tbl_entry)
   1085 {
   1086 	struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
   1087 	enum csc_color_mode config =
   1088 			CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC;
   1089 
   1090 	program_color_matrix(
   1091 			xfm_dce, tbl_entry, GRPH_COLOR_MATRIX_SW);
   1092 
   1093 	/*  We did everything ,now program DxOUTPUT_CSC_CONTROL */
   1094 	configure_graphics_mode(xfm_dce, config, GRAPHICS_CSC_ADJUST_TYPE_SW,
   1095 			tbl_entry->color_space);
   1096 }
   1097 
   1098 void dce110_opp_set_csc_default(
   1099 	struct transform *xfm,
   1100 	const struct default_adjustment *default_adjust)
   1101 {
   1102 	struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
   1103 	enum csc_color_mode config =
   1104 			CSC_COLOR_MODE_GRAPHICS_PREDEFINED;
   1105 
   1106 	if (default_adjust->force_hw_default == false) {
   1107 		const struct out_csc_color_matrix *elm;
   1108 		/* currently parameter not in use */
   1109 		enum grph_color_adjust_option option =
   1110 			GRPH_COLOR_MATRIX_HW_DEFAULT;
   1111 		uint32_t i;
   1112 		/*
   1113 		 * HW default false we program locally defined matrix
   1114 		 * HW default true  we use predefined hw matrix and we
   1115 		 * do not need to program matrix
   1116 		 * OEM wants the HW default via runtime parameter.
   1117 		 */
   1118 		option = GRPH_COLOR_MATRIX_SW;
   1119 
   1120 		for (i = 0; i < ARRAY_SIZE(global_color_matrix); ++i) {
   1121 			elm = &global_color_matrix[i];
   1122 			if (elm->color_space != default_adjust->out_color_space)
   1123 				continue;
   1124 			/* program the matrix with default values from this
   1125 			 * file */
   1126 			program_color_matrix(xfm_dce, elm, option);
   1127 			config = CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC;
   1128 			break;
   1129 		}
   1130 	}
   1131 
   1132 	/* configure the what we programmed :
   1133 	 * 1. Default values from this file
   1134 	 * 2. Use hardware default from ROM_A and we do not need to program
   1135 	 * matrix */
   1136 
   1137 	configure_graphics_mode(xfm_dce, config,
   1138 		default_adjust->csc_adjust_type,
   1139 		default_adjust->out_color_space);
   1140 }
   1141 
   1142 static void program_pwl(struct dce_transform *xfm_dce,
   1143 			const struct pwl_params *params)
   1144 {
   1145 	int retval;
   1146 	uint8_t max_tries = 10;
   1147 	uint8_t counter = 0;
   1148 	uint32_t i = 0;
   1149 	const struct pwl_result_data *rgb = params->rgb_resulted;
   1150 
   1151 	/* Power on LUT memory */
   1152 	if (REG(DCFE_MEM_PWR_CTRL))
   1153 		REG_UPDATE(DCFE_MEM_PWR_CTRL,
   1154 			   DCP_REGAMMA_MEM_PWR_DIS, 1);
   1155 	else
   1156 		REG_UPDATE(DCFE_MEM_LIGHT_SLEEP_CNTL,
   1157 			   REGAMMA_LUT_LIGHT_SLEEP_DIS, 1);
   1158 
   1159 	while (counter < max_tries) {
   1160 		if (REG(DCFE_MEM_PWR_STATUS)) {
   1161 			REG_GET(DCFE_MEM_PWR_STATUS,
   1162 				DCP_REGAMMA_MEM_PWR_STATE,
   1163 				&retval);
   1164 
   1165 			if (retval == 0)
   1166 				break;
   1167 			++counter;
   1168 		} else {
   1169 			REG_GET(DCFE_MEM_LIGHT_SLEEP_CNTL,
   1170 				REGAMMA_LUT_MEM_PWR_STATE,
   1171 				&retval);
   1172 
   1173 			if (retval == 0)
   1174 				break;
   1175 			++counter;
   1176 		}
   1177 	}
   1178 
   1179 	if (counter == max_tries) {
   1180 		DC_LOG_WARNING("%s: regamma lut was not powered on "
   1181 				"in a timely manner,"
   1182 				" programming still proceeds\n",
   1183 				__func__);
   1184 	}
   1185 
   1186 	REG_UPDATE(REGAMMA_LUT_WRITE_EN_MASK,
   1187 		   REGAMMA_LUT_WRITE_EN_MASK, 7);
   1188 
   1189 	REG_WRITE(REGAMMA_LUT_INDEX, 0);
   1190 
   1191 	/* Program REGAMMA_LUT_DATA */
   1192 	while (i != params->hw_points_num) {
   1193 
   1194 		REG_WRITE(REGAMMA_LUT_DATA, rgb->red_reg);
   1195 		REG_WRITE(REGAMMA_LUT_DATA, rgb->green_reg);
   1196 		REG_WRITE(REGAMMA_LUT_DATA, rgb->blue_reg);
   1197 		REG_WRITE(REGAMMA_LUT_DATA, rgb->delta_red_reg);
   1198 		REG_WRITE(REGAMMA_LUT_DATA, rgb->delta_green_reg);
   1199 		REG_WRITE(REGAMMA_LUT_DATA, rgb->delta_blue_reg);
   1200 
   1201 		++rgb;
   1202 		++i;
   1203 	}
   1204 
   1205 	/*  we are done with DCP LUT memory; re-enable low power mode */
   1206 	if (REG(DCFE_MEM_PWR_CTRL))
   1207 		REG_UPDATE(DCFE_MEM_PWR_CTRL,
   1208 			   DCP_REGAMMA_MEM_PWR_DIS, 0);
   1209 	else
   1210 		REG_UPDATE(DCFE_MEM_LIGHT_SLEEP_CNTL,
   1211 			   REGAMMA_LUT_LIGHT_SLEEP_DIS, 0);
   1212 }
   1213 
   1214 static void regamma_config_regions_and_segments(struct dce_transform *xfm_dce,
   1215 						const struct pwl_params *params)
   1216 {
   1217 	const struct gamma_curve *curve;
   1218 
   1219 	REG_SET_2(REGAMMA_CNTLA_START_CNTL, 0,
   1220 		  REGAMMA_CNTLA_EXP_REGION_START, params->arr_points[0].custom_float_x,
   1221 		  REGAMMA_CNTLA_EXP_REGION_START_SEGMENT, 0);
   1222 
   1223 	REG_SET(REGAMMA_CNTLA_SLOPE_CNTL, 0,
   1224 		REGAMMA_CNTLA_EXP_REGION_LINEAR_SLOPE, params->arr_points[0].custom_float_slope);
   1225 
   1226 	REG_SET(REGAMMA_CNTLA_END_CNTL1, 0,
   1227 		REGAMMA_CNTLA_EXP_REGION_END, params->arr_points[1].custom_float_x);
   1228 
   1229 	REG_SET_2(REGAMMA_CNTLA_END_CNTL2, 0,
   1230 		  REGAMMA_CNTLA_EXP_REGION_END_BASE, params->arr_points[1].custom_float_y,
   1231 		  REGAMMA_CNTLA_EXP_REGION_END_SLOPE, params->arr_points[1].custom_float_slope);
   1232 
   1233 	curve = params->arr_curve_points;
   1234 
   1235 	REG_SET_4(REGAMMA_CNTLA_REGION_0_1, 0,
   1236 		  REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
   1237 		  REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
   1238 		  REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
   1239 		  REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
   1240 	curve += 2;
   1241 
   1242 	REG_SET_4(REGAMMA_CNTLA_REGION_2_3, 0,
   1243 		  REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
   1244 		  REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
   1245 		  REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
   1246 		  REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
   1247 	curve += 2;
   1248 
   1249 	REG_SET_4(REGAMMA_CNTLA_REGION_4_5, 0,
   1250 		  REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
   1251 		  REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
   1252 		  REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
   1253 		  REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
   1254 	curve += 2;
   1255 
   1256 	REG_SET_4(REGAMMA_CNTLA_REGION_6_7, 0,
   1257 		  REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
   1258 		  REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
   1259 		  REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
   1260 		  REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
   1261 	curve += 2;
   1262 
   1263 	REG_SET_4(REGAMMA_CNTLA_REGION_8_9, 0,
   1264 		  REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
   1265 		  REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
   1266 		  REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
   1267 		  REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
   1268 	curve += 2;
   1269 
   1270 	REG_SET_4(REGAMMA_CNTLA_REGION_10_11, 0,
   1271 		  REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
   1272 		  REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
   1273 		  REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
   1274 		  REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
   1275 	curve += 2;
   1276 
   1277 	REG_SET_4(REGAMMA_CNTLA_REGION_12_13, 0,
   1278 		  REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
   1279 		  REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
   1280 		  REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
   1281 		  REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
   1282 	curve += 2;
   1283 
   1284 	REG_SET_4(REGAMMA_CNTLA_REGION_14_15, 0,
   1285 		  REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
   1286 		  REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
   1287 		  REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
   1288 		  REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
   1289 }
   1290 
   1291 
   1292 
   1293 void dce110_opp_program_regamma_pwl(struct transform *xfm,
   1294 				    const struct pwl_params *params)
   1295 {
   1296 	struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
   1297 
   1298 	/* Setup regions */
   1299 	regamma_config_regions_and_segments(xfm_dce, params);
   1300 
   1301 	/* Program PWL */
   1302 	program_pwl(xfm_dce, params);
   1303 }
   1304 
   1305 void dce110_opp_power_on_regamma_lut(struct transform *xfm,
   1306 				     bool power_on)
   1307 {
   1308 	struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
   1309 
   1310 	if (REG(DCFE_MEM_PWR_CTRL))
   1311 		REG_UPDATE_2(DCFE_MEM_PWR_CTRL,
   1312 			     DCP_REGAMMA_MEM_PWR_DIS, power_on,
   1313 			     DCP_LUT_MEM_PWR_DIS, power_on);
   1314 	else
   1315 		REG_UPDATE_2(DCFE_MEM_LIGHT_SLEEP_CNTL,
   1316 			    REGAMMA_LUT_LIGHT_SLEEP_DIS, power_on,
   1317 			    DCP_LUT_LIGHT_SLEEP_DIS, power_on);
   1318 
   1319 }
   1320 
   1321 void dce110_opp_set_regamma_mode(struct transform *xfm,
   1322 				 enum opp_regamma mode)
   1323 {
   1324 	struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
   1325 
   1326 	REG_SET(REGAMMA_CONTROL, 0,
   1327 		GRPH_REGAMMA_MODE, mode);
   1328 }
   1329 
   1330 static const struct transform_funcs dce_transform_funcs = {
   1331 	.transform_reset = dce_transform_reset,
   1332 	.transform_set_scaler = dce_transform_set_scaler,
   1333 	.transform_set_gamut_remap = dce_transform_set_gamut_remap,
   1334 	.opp_set_csc_adjustment = dce110_opp_set_csc_adjustment,
   1335 	.opp_set_csc_default = dce110_opp_set_csc_default,
   1336 	.opp_power_on_regamma_lut = dce110_opp_power_on_regamma_lut,
   1337 	.opp_program_regamma_pwl = dce110_opp_program_regamma_pwl,
   1338 	.opp_set_regamma_mode = dce110_opp_set_regamma_mode,
   1339 	.transform_set_pixel_storage_depth = dce_transform_set_pixel_storage_depth,
   1340 	.transform_get_optimal_number_of_taps = dce_transform_get_optimal_number_of_taps
   1341 };
   1342 
   1343 /*****************************************/
   1344 /* Constructor, Destructor               */
   1345 /*****************************************/
   1346 
   1347 void dce_transform_construct(
   1348 	struct dce_transform *xfm_dce,
   1349 	struct dc_context *ctx,
   1350 	uint32_t inst,
   1351 	const struct dce_transform_registers *regs,
   1352 	const struct dce_transform_shift *xfm_shift,
   1353 	const struct dce_transform_mask *xfm_mask)
   1354 {
   1355 	xfm_dce->base.ctx = ctx;
   1356 
   1357 	xfm_dce->base.inst = inst;
   1358 	xfm_dce->base.funcs = &dce_transform_funcs;
   1359 
   1360 	xfm_dce->regs = regs;
   1361 	xfm_dce->xfm_shift = xfm_shift;
   1362 	xfm_dce->xfm_mask = xfm_mask;
   1363 
   1364 	xfm_dce->prescaler_on = true;
   1365 	xfm_dce->lb_pixel_depth_supported =
   1366 			LB_PIXEL_DEPTH_18BPP |
   1367 			LB_PIXEL_DEPTH_24BPP |
   1368 			LB_PIXEL_DEPTH_30BPP;
   1369 
   1370 	xfm_dce->lb_bits_per_entry = LB_BITS_PER_ENTRY;
   1371 	xfm_dce->lb_memory_size = LB_TOTAL_NUMBER_OF_ENTRIES; /*0x6B0*/
   1372 }
   1373