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