Commit | Line | Data |
---|---|---|
f789b0b8 HW |
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 | ||
e8027e08 NA |
36 | #define IND_REG(index) \ |
37 | (index) | |
38 | ||
f789b0b8 HW |
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 | ||
48 | void 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 | ||
f789b0b8 HW |
70 | mpcc->blnd_cfg = *blnd_cfg; |
71 | } | |
72 | ||
73 | void 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 | ||
111 | void 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 | ||
131 | void 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 | { | |
e8027e08 | 137 | uint32_t cur_mode; |
f789b0b8 HW |
138 | struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); |
139 | struct color_matrices_reg ocsc_regs; | |
140 | ||
e8027e08 NA |
141 | if (ocsc_mode == MPC_OUTPUT_CSC_DISABLE) { |
142 | REG_SET(CSC_MODE[opp_id], 0, MPC_OCSC_MODE, ocsc_mode); | |
f789b0b8 | 143 | return; |
e8027e08 | 144 | } |
f789b0b8 HW |
145 | |
146 | if (regval == NULL) { | |
147 | BREAK_TO_DEBUGGER(); | |
148 | return; | |
149 | } | |
150 | ||
e8027e08 NA |
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 | */ | |
c1e34175 NA |
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); | |
e8027e08 NA |
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 | ||
f789b0b8 HW |
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 | } | |
e8027e08 | 176 | |
f789b0b8 HW |
177 | cm_helper_program_color_matrices( |
178 | mpc20->base.ctx, | |
179 | regval, | |
180 | &ocsc_regs); | |
e8027e08 NA |
181 | |
182 | REG_SET(CSC_MODE[opp_id], 0, MPC_OCSC_MODE, ocsc_mode); | |
f789b0b8 HW |
183 | } |
184 | ||
185 | void 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 | { | |
e8027e08 | 191 | uint32_t cur_mode; |
f789b0b8 HW |
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 | ||
e8027e08 NA |
197 | if (ocsc_mode == MPC_OUTPUT_CSC_DISABLE) { |
198 | REG_SET(CSC_MODE[opp_id], 0, MPC_OCSC_MODE, ocsc_mode); | |
f789b0b8 | 199 | return; |
e8027e08 | 200 | } |
f789b0b8 HW |
201 | |
202 | regval = find_color_matrix(color_space, &arr_size); | |
203 | ||
204 | if (regval == NULL) { | |
205 | BREAK_TO_DEBUGGER(); | |
206 | return; | |
207 | } | |
208 | ||
e8027e08 NA |
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 | */ | |
c1e34175 NA |
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); | |
e8027e08 NA |
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 | ||
f789b0b8 HW |
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); | |
e8027e08 NA |
240 | |
241 | REG_SET(CSC_MODE[opp_id], 0, MPC_OCSC_MODE, ocsc_mode); | |
f789b0b8 HW |
242 | } |
243 | ||
244 | static 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 | ||
54461859 | 272 | void mpc20_power_on_ogam_lut( |
f789b0b8 HW |
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, | |
54461859 | 279 | MPCC_OGAM_MEM_PWR_DIS, power_on == true ? 1:0); |
f789b0b8 HW |
280 | |
281 | } | |
282 | ||
283 | static 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 | ||
296 | static 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 | ||
292956cf JC |
302 | REG_GET(MPCC_OGAM_LUT_RAM_CONTROL[mpcc_id], MPCC_OGAM_CONFIG_STATUS, &state_mode); |
303 | ||
304 | switch (state_mode) { | |
305 | case 0: | |
306 | mode = LUT_BYPASS; | |
307 | break; | |
308 | case 1: | |
309 | mode = LUT_RAM_A; | |
310 | break; | |
311 | case 2: | |
312 | mode = LUT_RAM_B; | |
313 | break; | |
314 | default: | |
315 | mode = LUT_BYPASS; | |
316 | break; | |
317 | } | |
318 | ||
319 | return mode; | |
f789b0b8 HW |
320 | } |
321 | ||
322 | static 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 | ||
349 | static 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 | ||
376 | static 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 | ||
3a1627b0 NK |
384 | PERF_TRACE(); |
385 | REG_SEQ_START(); | |
3a1627b0 | 386 | |
f789b0b8 HW |
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 | ||
240e6d25 IB |
403 | static 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) | |
f789b0b8 HW |
406 | { |
407 | struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); | |
408 | ||
290129c2 QZ |
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 | ||
f789b0b8 HW |
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 | ||
427 | void 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 | ||
290129c2 QZ |
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 | ||
f789b0b8 HW |
441 | if (params == NULL) { |
442 | REG_SET(MPCC_OGAM_MODE[mpcc_id], 0, MPCC_OGAM_MODE, 0); | |
443 | return; | |
444 | } | |
290129c2 | 445 | |
f789b0b8 HW |
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); | |
2367cad7 | 453 | mpc20_configure_ogam_lut(mpc, mpcc_id, next_mode == LUT_RAM_A); |
f789b0b8 HW |
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 | } | |
468 | void 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 | ||
483 | void 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; | |
f789b0b8 HW |
487 | |
488 | REG_GET(MPCC_TOP_SEL[mpcc_id], | |
489 | MPCC_TOP_SEL, &top_sel); | |
490 | ||
0488a564 EY |
491 | REG_GET_3(MPCC_STATUS[mpcc_id], |
492 | MPCC_BUSY, &mpc_busy, | |
493 | MPCC_IDLE, &mpc_idle, | |
494 | MPCC_DISABLED, &mpc_disabled); | |
f789b0b8 | 495 | |
0488a564 EY |
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); | |
f789b0b8 | 503 | } |
2200eb9e | 504 | |
3a1627b0 NK |
505 | REG_SEQ_SUBMIT(); |
506 | PERF_TRACE(); | |
507 | REG_SEQ_WAIT_DONE(); | |
508 | PERF_TRACE(); | |
f789b0b8 HW |
509 | } |
510 | ||
511 | static 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 | ||
240e6d25 | 527 | static struct mpcc *mpc2_get_mpcc_for_dpp(struct mpc_tree *tree, int dpp_id) |
f789b0b8 HW |
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; | |
615fc502 JP |
534 | |
535 | /* avoid circular linked list */ | |
536 | ASSERT(tmp_mpcc != tmp_mpcc->mpcc_bot); | |
537 | if (tmp_mpcc == tmp_mpcc->mpcc_bot) | |
538 | break; | |
539 | ||
f789b0b8 HW |
540 | tmp_mpcc = tmp_mpcc->mpcc_bot; |
541 | } | |
542 | return NULL; | |
543 | } | |
544 | ||
545 | const struct mpc_funcs dcn20_mpc_funcs = { | |
546 | .read_mpcc_state = mpc1_read_mpcc_state, | |
547 | .insert_plane = mpc1_insert_plane, | |
548 | .remove_mpcc = mpc1_remove_mpcc, | |
549 | .mpc_init = mpc1_mpc_init, | |
5ec43eda | 550 | .mpc_init_single_inst = mpc1_mpc_init_single_inst, |
f789b0b8 | 551 | .update_blending = mpc2_update_blending, |
1e461c37 | 552 | .cursor_lock = mpc1_cursor_lock, |
f789b0b8 HW |
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, | |
54461859 | 562 | .power_on_mpc_mem_pwr = mpc20_power_on_ogam_lut, |
110b055b | 563 | .get_mpc_out_mux = mpc1_get_mpc_out_mux, |
60df8441 | 564 | .set_bg_color = mpc1_set_bg_color, |
f789b0b8 HW |
565 | }; |
566 | ||
567 | void dcn20_mpc_construct(struct dcn20_mpc *mpc20, | |
568 | struct dc_context *ctx, | |
569 | const struct dcn20_mpc_registers *mpc_regs, | |
570 | const struct dcn20_mpc_shift *mpc_shift, | |
571 | const struct dcn20_mpc_mask *mpc_mask, | |
572 | int num_mpcc) | |
573 | { | |
574 | int i; | |
575 | ||
576 | mpc20->base.ctx = ctx; | |
577 | ||
578 | mpc20->base.funcs = &dcn20_mpc_funcs; | |
579 | ||
580 | mpc20->mpc_regs = mpc_regs; | |
581 | mpc20->mpc_shift = mpc_shift; | |
582 | mpc20->mpc_mask = mpc_mask; | |
583 | ||
584 | mpc20->mpcc_in_use_mask = 0; | |
585 | mpc20->num_mpcc = num_mpcc; | |
586 | ||
587 | for (i = 0; i < MAX_MPCC; i++) | |
588 | mpc2_init_mpcc(&mpc20->base.mpcc_array[i], i); | |
589 | } | |
590 |