cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dcn20_mpc.c (18106B)


      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 "dcn20_mpc.h"
     27
     28#include "reg_helper.h"
     29#include "dc.h"
     30#include "mem_input.h"
     31#include "dcn10/dcn10_cm_common.h"
     32
     33#define REG(reg)\
     34	mpc20->mpc_regs->reg
     35
     36#define IND_REG(index) \
     37	(index)
     38
     39#define CTX \
     40	mpc20->base.ctx
     41
     42#undef FN
     43#define FN(reg_name, field_name) \
     44	mpc20->mpc_shift->field_name, mpc20->mpc_mask->field_name
     45
     46#define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0]))
     47
     48void mpc2_update_blending(
     49	struct mpc *mpc,
     50	struct mpcc_blnd_cfg *blnd_cfg,
     51	int mpcc_id)
     52{
     53	struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc);
     54
     55	struct mpcc *mpcc = mpc1_get_mpcc(mpc, mpcc_id);
     56
     57	REG_UPDATE_7(MPCC_CONTROL[mpcc_id],
     58			MPCC_ALPHA_BLND_MODE,		blnd_cfg->alpha_mode,
     59			MPCC_ALPHA_MULTIPLIED_MODE,	blnd_cfg->pre_multiplied_alpha,
     60			MPCC_BLND_ACTIVE_OVERLAP_ONLY,	blnd_cfg->overlap_only,
     61			MPCC_GLOBAL_ALPHA,		blnd_cfg->global_alpha,
     62			MPCC_GLOBAL_GAIN,		blnd_cfg->global_gain,
     63			MPCC_BG_BPC,			blnd_cfg->background_color_bpc,
     64			MPCC_BOT_GAIN_MODE,		blnd_cfg->bottom_gain_mode);
     65
     66	REG_SET(MPCC_TOP_GAIN[mpcc_id], 0, MPCC_TOP_GAIN, blnd_cfg->top_gain);
     67	REG_SET(MPCC_BOT_GAIN_INSIDE[mpcc_id], 0, MPCC_BOT_GAIN_INSIDE, blnd_cfg->bottom_inside_gain);
     68	REG_SET(MPCC_BOT_GAIN_OUTSIDE[mpcc_id], 0, MPCC_BOT_GAIN_OUTSIDE, blnd_cfg->bottom_outside_gain);
     69
     70	mpcc->blnd_cfg = *blnd_cfg;
     71}
     72
     73void mpc2_set_denorm(
     74		struct mpc *mpc,
     75		int opp_id,
     76		enum dc_color_depth output_depth)
     77{
     78	struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc);
     79	int denorm_mode = 0;
     80
     81	switch (output_depth) {
     82	case COLOR_DEPTH_666:
     83		denorm_mode = 1;
     84		break;
     85	case COLOR_DEPTH_888:
     86		denorm_mode = 2;
     87		break;
     88	case COLOR_DEPTH_999:
     89		denorm_mode = 3;
     90		break;
     91	case COLOR_DEPTH_101010:
     92		denorm_mode = 4;
     93		break;
     94	case COLOR_DEPTH_111111:
     95		denorm_mode = 5;
     96		break;
     97	case COLOR_DEPTH_121212:
     98		denorm_mode = 6;
     99		break;
    100	case COLOR_DEPTH_141414:
    101	case COLOR_DEPTH_161616:
    102	default:
    103		/* not valid used case! */
    104		break;
    105	}
    106
    107	REG_UPDATE(DENORM_CONTROL[opp_id],
    108			MPC_OUT_DENORM_MODE, denorm_mode);
    109}
    110
    111void mpc2_set_denorm_clamp(
    112		struct mpc *mpc,
    113		int opp_id,
    114		struct mpc_denorm_clamp denorm_clamp)
    115{
    116	struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc);
    117
    118	REG_UPDATE_2(DENORM_CONTROL[opp_id],
    119			MPC_OUT_DENORM_CLAMP_MAX_R_CR, denorm_clamp.clamp_max_r_cr,
    120			MPC_OUT_DENORM_CLAMP_MIN_R_CR, denorm_clamp.clamp_min_r_cr);
    121	REG_UPDATE_2(DENORM_CLAMP_G_Y[opp_id],
    122			MPC_OUT_DENORM_CLAMP_MAX_G_Y, denorm_clamp.clamp_max_g_y,
    123			MPC_OUT_DENORM_CLAMP_MIN_G_Y, denorm_clamp.clamp_min_g_y);
    124	REG_UPDATE_2(DENORM_CLAMP_B_CB[opp_id],
    125			MPC_OUT_DENORM_CLAMP_MAX_B_CB, denorm_clamp.clamp_max_b_cb,
    126			MPC_OUT_DENORM_CLAMP_MIN_B_CB, denorm_clamp.clamp_min_b_cb);
    127}
    128
    129
    130
    131void mpc2_set_output_csc(
    132		struct mpc *mpc,
    133		int opp_id,
    134		const uint16_t *regval,
    135		enum mpc_output_csc_mode ocsc_mode)
    136{
    137	uint32_t cur_mode;
    138	struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc);
    139	struct color_matrices_reg ocsc_regs;
    140
    141	if (ocsc_mode == MPC_OUTPUT_CSC_DISABLE) {
    142		REG_SET(CSC_MODE[opp_id], 0, MPC_OCSC_MODE, ocsc_mode);
    143		return;
    144	}
    145
    146	if (regval == NULL) {
    147		BREAK_TO_DEBUGGER();
    148		return;
    149	}
    150
    151	/* determine which CSC coefficients (A or B) we are using
    152	 * currently.  select the alternate set to double buffer
    153	 * the CSC update so CSC is updated on frame boundary
    154	 */
    155	IX_REG_GET(MPC_OCSC_TEST_DEBUG_INDEX, MPC_OCSC_TEST_DEBUG_DATA,
    156						MPC_OCSC_TEST_DEBUG_DATA_STATUS_IDX,
    157						MPC_OCSC_TEST_DEBUG_DATA_OCSC_MODE, &cur_mode);
    158
    159	if (cur_mode != MPC_OUTPUT_CSC_COEF_A)
    160		ocsc_mode = MPC_OUTPUT_CSC_COEF_A;
    161	else
    162		ocsc_mode = MPC_OUTPUT_CSC_COEF_B;
    163
    164	ocsc_regs.shifts.csc_c11 = mpc20->mpc_shift->MPC_OCSC_C11_A;
    165	ocsc_regs.masks.csc_c11  = mpc20->mpc_mask->MPC_OCSC_C11_A;
    166	ocsc_regs.shifts.csc_c12 = mpc20->mpc_shift->MPC_OCSC_C12_A;
    167	ocsc_regs.masks.csc_c12 = mpc20->mpc_mask->MPC_OCSC_C12_A;
    168
    169	if (ocsc_mode == MPC_OUTPUT_CSC_COEF_A) {
    170		ocsc_regs.csc_c11_c12 = REG(CSC_C11_C12_A[opp_id]);
    171		ocsc_regs.csc_c33_c34 = REG(CSC_C33_C34_A[opp_id]);
    172	} else {
    173		ocsc_regs.csc_c11_c12 = REG(CSC_C11_C12_B[opp_id]);
    174		ocsc_regs.csc_c33_c34 = REG(CSC_C33_C34_B[opp_id]);
    175	}
    176
    177	cm_helper_program_color_matrices(
    178			mpc20->base.ctx,
    179			regval,
    180			&ocsc_regs);
    181
    182	REG_SET(CSC_MODE[opp_id], 0, MPC_OCSC_MODE, ocsc_mode);
    183}
    184
    185void mpc2_set_ocsc_default(
    186		struct mpc *mpc,
    187		int opp_id,
    188		enum dc_color_space color_space,
    189		enum mpc_output_csc_mode ocsc_mode)
    190{
    191	uint32_t cur_mode;
    192	struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc);
    193	uint32_t arr_size;
    194	struct color_matrices_reg ocsc_regs;
    195	const uint16_t *regval = NULL;
    196
    197	if (ocsc_mode == MPC_OUTPUT_CSC_DISABLE) {
    198		REG_SET(CSC_MODE[opp_id], 0, MPC_OCSC_MODE, ocsc_mode);
    199		return;
    200	}
    201
    202	regval = find_color_matrix(color_space, &arr_size);
    203
    204	if (regval == NULL) {
    205		BREAK_TO_DEBUGGER();
    206		return;
    207	}
    208
    209	/* determine which CSC coefficients (A or B) we are using
    210	 * currently.  select the alternate set to double buffer
    211	 * the CSC update so CSC is updated on frame boundary
    212	 */
    213	IX_REG_GET(MPC_OCSC_TEST_DEBUG_INDEX, MPC_OCSC_TEST_DEBUG_DATA,
    214						MPC_OCSC_TEST_DEBUG_DATA_STATUS_IDX,
    215						MPC_OCSC_TEST_DEBUG_DATA_OCSC_MODE, &cur_mode);
    216
    217	if (cur_mode != MPC_OUTPUT_CSC_COEF_A)
    218		ocsc_mode = MPC_OUTPUT_CSC_COEF_A;
    219	else
    220		ocsc_mode = MPC_OUTPUT_CSC_COEF_B;
    221
    222	ocsc_regs.shifts.csc_c11 = mpc20->mpc_shift->MPC_OCSC_C11_A;
    223	ocsc_regs.masks.csc_c11  = mpc20->mpc_mask->MPC_OCSC_C11_A;
    224	ocsc_regs.shifts.csc_c12 = mpc20->mpc_shift->MPC_OCSC_C12_A;
    225	ocsc_regs.masks.csc_c12 = mpc20->mpc_mask->MPC_OCSC_C12_A;
    226
    227
    228	if (ocsc_mode == MPC_OUTPUT_CSC_COEF_A) {
    229		ocsc_regs.csc_c11_c12 = REG(CSC_C11_C12_A[opp_id]);
    230		ocsc_regs.csc_c33_c34 = REG(CSC_C33_C34_A[opp_id]);
    231	} else {
    232		ocsc_regs.csc_c11_c12 = REG(CSC_C11_C12_B[opp_id]);
    233		ocsc_regs.csc_c33_c34 = REG(CSC_C33_C34_B[opp_id]);
    234	}
    235
    236	cm_helper_program_color_matrices(
    237			mpc20->base.ctx,
    238			regval,
    239			&ocsc_regs);
    240
    241	REG_SET(CSC_MODE[opp_id], 0, MPC_OCSC_MODE, ocsc_mode);
    242}
    243
    244static void mpc2_ogam_get_reg_field(
    245		struct mpc *mpc,
    246		struct xfer_func_reg *reg)
    247{
    248	struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc);
    249
    250	reg->shifts.exp_region0_lut_offset = mpc20->mpc_shift->MPCC_OGAM_RAMA_EXP_REGION0_LUT_OFFSET;
    251	reg->masks.exp_region0_lut_offset = mpc20->mpc_mask->MPCC_OGAM_RAMA_EXP_REGION0_LUT_OFFSET;
    252	reg->shifts.exp_region0_num_segments = mpc20->mpc_shift->MPCC_OGAM_RAMA_EXP_REGION0_NUM_SEGMENTS;
    253	reg->masks.exp_region0_num_segments = mpc20->mpc_mask->MPCC_OGAM_RAMA_EXP_REGION0_NUM_SEGMENTS;
    254	reg->shifts.exp_region1_lut_offset = mpc20->mpc_shift->MPCC_OGAM_RAMA_EXP_REGION1_LUT_OFFSET;
    255	reg->masks.exp_region1_lut_offset = mpc20->mpc_mask->MPCC_OGAM_RAMA_EXP_REGION1_LUT_OFFSET;
    256	reg->shifts.exp_region1_num_segments = mpc20->mpc_shift->MPCC_OGAM_RAMA_EXP_REGION1_NUM_SEGMENTS;
    257	reg->masks.exp_region1_num_segments = mpc20->mpc_mask->MPCC_OGAM_RAMA_EXP_REGION1_NUM_SEGMENTS;
    258	reg->shifts.field_region_end = mpc20->mpc_shift->MPCC_OGAM_RAMA_EXP_REGION_END_B;
    259	reg->masks.field_region_end = mpc20->mpc_mask->MPCC_OGAM_RAMA_EXP_REGION_END_B;
    260	reg->shifts.field_region_end_slope = mpc20->mpc_shift->MPCC_OGAM_RAMA_EXP_REGION_END_SLOPE_B;
    261	reg->masks.field_region_end_slope = mpc20->mpc_mask->MPCC_OGAM_RAMA_EXP_REGION_END_SLOPE_B;
    262	reg->shifts.field_region_end_base = mpc20->mpc_shift->MPCC_OGAM_RAMA_EXP_REGION_END_BASE_B;
    263	reg->masks.field_region_end_base = mpc20->mpc_mask->MPCC_OGAM_RAMA_EXP_REGION_END_BASE_B;
    264	reg->shifts.field_region_linear_slope = mpc20->mpc_shift->MPCC_OGAM_RAMA_EXP_REGION_LINEAR_SLOPE_B;
    265	reg->masks.field_region_linear_slope = mpc20->mpc_mask->MPCC_OGAM_RAMA_EXP_REGION_LINEAR_SLOPE_B;
    266	reg->shifts.exp_region_start = mpc20->mpc_shift->MPCC_OGAM_RAMA_EXP_REGION_START_B;
    267	reg->masks.exp_region_start = mpc20->mpc_mask->MPCC_OGAM_RAMA_EXP_REGION_START_B;
    268	reg->shifts.exp_resion_start_segment = mpc20->mpc_shift->MPCC_OGAM_RAMA_EXP_REGION_START_SEGMENT_B;
    269	reg->masks.exp_resion_start_segment = mpc20->mpc_mask->MPCC_OGAM_RAMA_EXP_REGION_START_SEGMENT_B;
    270}
    271
    272void mpc20_power_on_ogam_lut(
    273		struct mpc *mpc, int mpcc_id,
    274		bool power_on)
    275{
    276	struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc);
    277
    278	REG_SET(MPCC_MEM_PWR_CTRL[mpcc_id], 0,
    279			MPCC_OGAM_MEM_PWR_DIS, power_on == true ? 1:0);
    280
    281}
    282
    283static void mpc20_configure_ogam_lut(
    284		struct mpc *mpc, int mpcc_id,
    285		bool is_ram_a)
    286{
    287	struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc);
    288
    289	REG_UPDATE_2(MPCC_OGAM_LUT_RAM_CONTROL[mpcc_id],
    290			MPCC_OGAM_LUT_WRITE_EN_MASK, 7,
    291			MPCC_OGAM_LUT_RAM_SEL, is_ram_a == true ? 0:1);
    292
    293	REG_SET(MPCC_OGAM_LUT_INDEX[mpcc_id], 0, MPCC_OGAM_LUT_INDEX, 0);
    294}
    295
    296static enum dc_lut_mode mpc20_get_ogam_current(struct mpc *mpc, int mpcc_id)
    297{
    298	enum dc_lut_mode mode;
    299	uint32_t state_mode;
    300	struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc);
    301
    302	REG_GET(MPCC_OGAM_LUT_RAM_CONTROL[mpcc_id],
    303			MPCC_OGAM_CONFIG_STATUS, &state_mode);
    304
    305		switch (state_mode) {
    306		case 0:
    307			mode = LUT_BYPASS;
    308			break;
    309		case 1:
    310			mode = LUT_RAM_A;
    311			break;
    312		case 2:
    313			mode = LUT_RAM_B;
    314			break;
    315		default:
    316			mode = LUT_BYPASS;
    317			break;
    318		}
    319		return mode;
    320}
    321
    322static void mpc2_program_lutb(struct mpc *mpc, int mpcc_id,
    323			const struct pwl_params *params)
    324{
    325	struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc);
    326	struct xfer_func_reg gam_regs;
    327
    328	mpc2_ogam_get_reg_field(mpc, &gam_regs);
    329
    330	gam_regs.start_cntl_b = REG(MPCC_OGAM_RAMB_START_CNTL_B[mpcc_id]);
    331	gam_regs.start_cntl_g = REG(MPCC_OGAM_RAMB_START_CNTL_G[mpcc_id]);
    332	gam_regs.start_cntl_r = REG(MPCC_OGAM_RAMB_START_CNTL_R[mpcc_id]);
    333	gam_regs.start_slope_cntl_b = REG(MPCC_OGAM_RAMB_SLOPE_CNTL_B[mpcc_id]);
    334	gam_regs.start_slope_cntl_g = REG(MPCC_OGAM_RAMB_SLOPE_CNTL_G[mpcc_id]);
    335	gam_regs.start_slope_cntl_r = REG(MPCC_OGAM_RAMB_SLOPE_CNTL_R[mpcc_id]);
    336	gam_regs.start_end_cntl1_b = REG(MPCC_OGAM_RAMB_END_CNTL1_B[mpcc_id]);
    337	gam_regs.start_end_cntl2_b = REG(MPCC_OGAM_RAMB_END_CNTL2_B[mpcc_id]);
    338	gam_regs.start_end_cntl1_g = REG(MPCC_OGAM_RAMB_END_CNTL1_G[mpcc_id]);
    339	gam_regs.start_end_cntl2_g = REG(MPCC_OGAM_RAMB_END_CNTL2_G[mpcc_id]);
    340	gam_regs.start_end_cntl1_r = REG(MPCC_OGAM_RAMB_END_CNTL1_R[mpcc_id]);
    341	gam_regs.start_end_cntl2_r = REG(MPCC_OGAM_RAMB_END_CNTL2_R[mpcc_id]);
    342	gam_regs.region_start = REG(MPCC_OGAM_RAMB_REGION_0_1[mpcc_id]);
    343	gam_regs.region_end = REG(MPCC_OGAM_RAMB_REGION_32_33[mpcc_id]);
    344
    345	cm_helper_program_xfer_func(mpc20->base.ctx, params, &gam_regs);
    346
    347}
    348
    349static void mpc2_program_luta(struct mpc *mpc, int mpcc_id,
    350		const struct pwl_params *params)
    351{
    352	struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc);
    353	struct xfer_func_reg gam_regs;
    354
    355	mpc2_ogam_get_reg_field(mpc, &gam_regs);
    356
    357	gam_regs.start_cntl_b = REG(MPCC_OGAM_RAMA_START_CNTL_B[mpcc_id]);
    358	gam_regs.start_cntl_g = REG(MPCC_OGAM_RAMA_START_CNTL_G[mpcc_id]);
    359	gam_regs.start_cntl_r = REG(MPCC_OGAM_RAMA_START_CNTL_R[mpcc_id]);
    360	gam_regs.start_slope_cntl_b = REG(MPCC_OGAM_RAMA_SLOPE_CNTL_B[mpcc_id]);
    361	gam_regs.start_slope_cntl_g = REG(MPCC_OGAM_RAMA_SLOPE_CNTL_G[mpcc_id]);
    362	gam_regs.start_slope_cntl_r = REG(MPCC_OGAM_RAMA_SLOPE_CNTL_R[mpcc_id]);
    363	gam_regs.start_end_cntl1_b = REG(MPCC_OGAM_RAMA_END_CNTL1_B[mpcc_id]);
    364	gam_regs.start_end_cntl2_b = REG(MPCC_OGAM_RAMA_END_CNTL2_B[mpcc_id]);
    365	gam_regs.start_end_cntl1_g = REG(MPCC_OGAM_RAMA_END_CNTL1_G[mpcc_id]);
    366	gam_regs.start_end_cntl2_g = REG(MPCC_OGAM_RAMA_END_CNTL2_G[mpcc_id]);
    367	gam_regs.start_end_cntl1_r = REG(MPCC_OGAM_RAMA_END_CNTL1_R[mpcc_id]);
    368	gam_regs.start_end_cntl2_r = REG(MPCC_OGAM_RAMA_END_CNTL2_R[mpcc_id]);
    369	gam_regs.region_start = REG(MPCC_OGAM_RAMA_REGION_0_1[mpcc_id]);
    370	gam_regs.region_end = REG(MPCC_OGAM_RAMA_REGION_32_33[mpcc_id]);
    371
    372	cm_helper_program_xfer_func(mpc20->base.ctx, params, &gam_regs);
    373
    374}
    375
    376static void mpc20_program_ogam_pwl(
    377		struct mpc *mpc, int mpcc_id,
    378		const struct pwl_result_data *rgb,
    379		uint32_t num)
    380{
    381	uint32_t i;
    382	struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc);
    383
    384	PERF_TRACE();
    385	REG_SEQ_START();
    386
    387	for (i = 0 ; i < num; i++) {
    388		REG_SET(MPCC_OGAM_LUT_DATA[mpcc_id], 0, MPCC_OGAM_LUT_DATA, rgb[i].red_reg);
    389		REG_SET(MPCC_OGAM_LUT_DATA[mpcc_id], 0, MPCC_OGAM_LUT_DATA, rgb[i].green_reg);
    390		REG_SET(MPCC_OGAM_LUT_DATA[mpcc_id], 0, MPCC_OGAM_LUT_DATA, rgb[i].blue_reg);
    391
    392		REG_SET(MPCC_OGAM_LUT_DATA[mpcc_id], 0,
    393				MPCC_OGAM_LUT_DATA, rgb[i].delta_red_reg);
    394		REG_SET(MPCC_OGAM_LUT_DATA[mpcc_id], 0,
    395				MPCC_OGAM_LUT_DATA, rgb[i].delta_green_reg);
    396		REG_SET(MPCC_OGAM_LUT_DATA[mpcc_id], 0,
    397				MPCC_OGAM_LUT_DATA, rgb[i].delta_blue_reg);
    398
    399	}
    400
    401}
    402
    403static void apply_DEDCN20_305_wa(struct mpc *mpc, int mpcc_id,
    404				 enum dc_lut_mode current_mode,
    405				 enum dc_lut_mode next_mode)
    406{
    407	struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc);
    408
    409	if (mpc->ctx->dc->debug.cm_in_bypass) {
    410		REG_SET(MPCC_OGAM_MODE[mpcc_id], 0, MPCC_OGAM_MODE, 0);
    411		return;
    412	}
    413
    414	if (mpc->ctx->dc->work_arounds.dedcn20_305_wa == false) {
    415		/*hw fixed in new review*/
    416		return;
    417	}
    418	if (current_mode == LUT_BYPASS)
    419		/*this will only work if OTG is locked.
    420		 *if we were to support OTG unlock case,
    421		 *the workaround will be more complex
    422		 */
    423		REG_SET(MPCC_OGAM_MODE[mpcc_id], 0, MPCC_OGAM_MODE,
    424			next_mode == LUT_RAM_A ? 1:2);
    425}
    426
    427void mpc2_set_output_gamma(
    428		struct mpc *mpc,
    429		int mpcc_id,
    430		const struct pwl_params *params)
    431{
    432	enum dc_lut_mode current_mode;
    433	enum dc_lut_mode next_mode;
    434	struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc);
    435
    436	if (mpc->ctx->dc->debug.cm_in_bypass) {
    437		REG_SET(MPCC_OGAM_MODE[mpcc_id], 0, MPCC_OGAM_MODE, 0);
    438		return;
    439	}
    440
    441	if (params == NULL) {
    442		REG_SET(MPCC_OGAM_MODE[mpcc_id], 0, MPCC_OGAM_MODE, 0);
    443		return;
    444	}
    445
    446	current_mode = mpc20_get_ogam_current(mpc, mpcc_id);
    447	if (current_mode == LUT_BYPASS || current_mode == LUT_RAM_A)
    448		next_mode = LUT_RAM_B;
    449	else
    450		next_mode = LUT_RAM_A;
    451
    452	mpc20_power_on_ogam_lut(mpc, mpcc_id, true);
    453	mpc20_configure_ogam_lut(mpc, mpcc_id, next_mode == LUT_RAM_A);
    454
    455	if (next_mode == LUT_RAM_A)
    456		mpc2_program_luta(mpc, mpcc_id, params);
    457	else
    458		mpc2_program_lutb(mpc, mpcc_id, params);
    459
    460	apply_DEDCN20_305_wa(mpc, mpcc_id, current_mode, next_mode);
    461
    462	mpc20_program_ogam_pwl(
    463			mpc, mpcc_id, params->rgb_resulted, params->hw_points_num);
    464
    465	REG_SET(MPCC_OGAM_MODE[mpcc_id], 0, MPCC_OGAM_MODE,
    466		next_mode == LUT_RAM_A ? 1:2);
    467}
    468void mpc2_assert_idle_mpcc(struct mpc *mpc, int id)
    469{
    470	struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc);
    471	unsigned int mpc_disabled;
    472
    473	ASSERT(!(mpc20->mpcc_in_use_mask & 1 << id));
    474	REG_GET(MPCC_STATUS[id], MPCC_DISABLED, &mpc_disabled);
    475	if (mpc_disabled)
    476		return;
    477
    478	REG_WAIT(MPCC_STATUS[id],
    479			MPCC_IDLE, 1,
    480			1, 100000);
    481}
    482
    483void mpc2_assert_mpcc_idle_before_connect(struct mpc *mpc, int mpcc_id)
    484{
    485	struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc);
    486	unsigned int top_sel, mpc_busy, mpc_idle, mpc_disabled;
    487
    488	REG_GET(MPCC_TOP_SEL[mpcc_id],
    489			MPCC_TOP_SEL, &top_sel);
    490
    491	REG_GET_3(MPCC_STATUS[mpcc_id],
    492			MPCC_BUSY, &mpc_busy,
    493			MPCC_IDLE, &mpc_idle,
    494			MPCC_DISABLED, &mpc_disabled);
    495
    496	if (top_sel == 0xf) {
    497		ASSERT(!mpc_busy);
    498		ASSERT(mpc_idle);
    499		ASSERT(mpc_disabled);
    500	} else {
    501		ASSERT(!mpc_disabled);
    502		ASSERT(!mpc_idle);
    503	}
    504
    505	REG_SEQ_SUBMIT();
    506	PERF_TRACE();
    507	REG_SEQ_WAIT_DONE();
    508	PERF_TRACE();
    509}
    510
    511static void mpc2_init_mpcc(struct mpcc *mpcc, int mpcc_inst)
    512{
    513	mpcc->mpcc_id = mpcc_inst;
    514	mpcc->dpp_id = 0xf;
    515	mpcc->mpcc_bot = NULL;
    516	mpcc->blnd_cfg.overlap_only = false;
    517	mpcc->blnd_cfg.global_alpha = 0xff;
    518	mpcc->blnd_cfg.global_gain = 0xff;
    519	mpcc->blnd_cfg.background_color_bpc = 4;
    520	mpcc->blnd_cfg.bottom_gain_mode = 0;
    521	mpcc->blnd_cfg.top_gain = 0x1f000;
    522	mpcc->blnd_cfg.bottom_inside_gain = 0x1f000;
    523	mpcc->blnd_cfg.bottom_outside_gain = 0x1f000;
    524	mpcc->sm_cfg.enable = false;
    525}
    526
    527static struct mpcc *mpc2_get_mpcc_for_dpp(struct mpc_tree *tree, int dpp_id)
    528{
    529	struct mpcc *tmp_mpcc = tree->opp_list;
    530
    531	while (tmp_mpcc != NULL) {
    532		if (tmp_mpcc->dpp_id == 0xf || tmp_mpcc->dpp_id == dpp_id)
    533			return tmp_mpcc;
    534		tmp_mpcc = tmp_mpcc->mpcc_bot;
    535	}
    536	return NULL;
    537}
    538
    539const struct mpc_funcs dcn20_mpc_funcs = {
    540	.read_mpcc_state = mpc1_read_mpcc_state,
    541	.insert_plane = mpc1_insert_plane,
    542	.remove_mpcc = mpc1_remove_mpcc,
    543	.mpc_init = mpc1_mpc_init,
    544	.mpc_init_single_inst = mpc1_mpc_init_single_inst,
    545	.update_blending = mpc2_update_blending,
    546	.cursor_lock = mpc1_cursor_lock,
    547	.get_mpcc_for_dpp = mpc2_get_mpcc_for_dpp,
    548	.wait_for_idle = mpc2_assert_idle_mpcc,
    549	.assert_mpcc_idle_before_connect = mpc2_assert_mpcc_idle_before_connect,
    550	.init_mpcc_list_from_hw = mpc1_init_mpcc_list_from_hw,
    551	.set_denorm = mpc2_set_denorm,
    552	.set_denorm_clamp = mpc2_set_denorm_clamp,
    553	.set_output_csc = mpc2_set_output_csc,
    554	.set_ocsc_default = mpc2_set_ocsc_default,
    555	.set_output_gamma = mpc2_set_output_gamma,
    556	.power_on_mpc_mem_pwr = mpc20_power_on_ogam_lut,
    557	.get_mpc_out_mux = mpc1_get_mpc_out_mux,
    558	.set_bg_color = mpc1_set_bg_color,
    559};
    560
    561void dcn20_mpc_construct(struct dcn20_mpc *mpc20,
    562	struct dc_context *ctx,
    563	const struct dcn20_mpc_registers *mpc_regs,
    564	const struct dcn20_mpc_shift *mpc_shift,
    565	const struct dcn20_mpc_mask *mpc_mask,
    566	int num_mpcc)
    567{
    568	int i;
    569
    570	mpc20->base.ctx = ctx;
    571
    572	mpc20->base.funcs = &dcn20_mpc_funcs;
    573
    574	mpc20->mpc_regs = mpc_regs;
    575	mpc20->mpc_shift = mpc_shift;
    576	mpc20->mpc_mask = mpc_mask;
    577
    578	mpc20->mpcc_in_use_mask = 0;
    579	mpc20->num_mpcc = num_mpcc;
    580
    581	for (i = 0; i < MAX_MPCC; i++)
    582		mpc2_init_mpcc(&mpc20->base.mpcc_array[i], i);
    583}
    584