1 | /* |
2 | * Copyright 2016 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 "dm_services.h" |
27 | |
28 | #include "core_types.h" |
29 | |
30 | #include "reg_helper.h" |
31 | #include "dcn20_dpp.h" |
32 | #include "basics/conversion.h" |
33 | |
34 | #define NUM_PHASES 64 |
35 | #define HORZ_MAX_TAPS 8 |
36 | #define VERT_MAX_TAPS 8 |
37 | |
38 | #define BLACK_OFFSET_RGB_Y 0x0 |
39 | #define BLACK_OFFSET_CBCR 0x8000 |
40 | |
41 | #define REG(reg)\ |
42 | dpp->tf_regs->reg |
43 | |
44 | #define CTX \ |
45 | dpp->base.ctx |
46 | |
47 | #undef FN |
48 | #define FN(reg_name, field_name) \ |
49 | dpp->tf_shift->field_name, dpp->tf_mask->field_name |
50 | |
51 | void dpp20_read_state(struct dpp *dpp_base, |
52 | struct dcn_dpp_state *s) |
53 | { |
54 | struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); |
55 | |
56 | REG_GET(DPP_CONTROL, |
57 | DPP_CLOCK_ENABLE, &s->is_enabled); |
58 | |
59 | // Degamma LUT (RAM) |
60 | REG_GET(CM_DGAM_CONTROL, |
61 | CM_DGAM_LUT_MODE, &s->dgam_lut_mode); |
62 | |
63 | // Shaper LUT (RAM), 3D LUT (mode, bit-depth, size) |
64 | REG_GET(CM_SHAPER_CONTROL, |
65 | CM_SHAPER_LUT_MODE, &s->shaper_lut_mode); |
66 | REG_GET_2(CM_3DLUT_READ_WRITE_CONTROL, |
67 | CM_3DLUT_CONFIG_STATUS, &s->lut3d_mode, |
68 | CM_3DLUT_30BIT_EN, &s->lut3d_bit_depth); |
69 | REG_GET(CM_3DLUT_MODE, |
70 | CM_3DLUT_SIZE, &s->lut3d_size); |
71 | |
72 | // Blend/Out Gamma (RAM) |
73 | REG_GET(CM_BLNDGAM_LUT_WRITE_EN_MASK, |
74 | CM_BLNDGAM_CONFIG_STATUS, &s->rgam_lut_mode); |
75 | } |
76 | |
77 | void dpp2_power_on_obuf( |
78 | struct dpp *dpp_base, |
79 | bool power_on) |
80 | { |
81 | struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); |
82 | |
83 | REG_UPDATE(CM_MEM_PWR_CTRL, SHARED_MEM_PWR_DIS, power_on == true ? 1:0); |
84 | |
85 | REG_UPDATE(OBUF_MEM_PWR_CTRL, |
86 | OBUF_MEM_PWR_FORCE, power_on == true ? 0:1); |
87 | |
88 | REG_UPDATE(DSCL_MEM_PWR_CTRL, |
89 | LUT_MEM_PWR_FORCE, power_on == true ? 0:1); |
90 | } |
91 | |
92 | void dpp2_dummy_program_input_lut( |
93 | struct dpp *dpp_base, |
94 | const struct dc_gamma *gamma) |
95 | {} |
96 | |
97 | static void dpp2_cnv_setup ( |
98 | struct dpp *dpp_base, |
99 | enum surface_pixel_format format, |
100 | enum expansion_mode mode, |
101 | struct dc_csc_transform input_csc_color_matrix, |
102 | enum dc_color_space input_color_space, |
103 | struct cnv_alpha_2bit_lut *alpha_2bit_lut) |
104 | { |
105 | struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); |
106 | uint32_t pixel_format = 0; |
107 | uint32_t alpha_en = 1; |
108 | enum dc_color_space color_space = COLOR_SPACE_SRGB; |
109 | enum dcn20_input_csc_select select = DCN2_ICSC_SELECT_BYPASS; |
110 | bool force_disable_cursor = false; |
111 | struct out_csc_color_matrix tbl_entry; |
112 | uint32_t is_2bit = 0; |
113 | int i = 0; |
114 | |
115 | REG_SET_2(FORMAT_CONTROL, 0, |
116 | CNVC_BYPASS, 0, |
117 | FORMAT_EXPANSION_MODE, mode); |
118 | |
119 | //hardcode default |
120 | //FORMAT_CONTROL. FORMAT_CNV16 default 0: U0.16/S.1.15; 1: U1.15/ S.1.14 |
121 | //FORMAT_CONTROL. CNVC_BYPASS_MSB_ALIGN default 0: disabled 1: enabled |
122 | //FORMAT_CONTROL. CLAMP_POSITIVE default 0: disabled 1: enabled |
123 | //FORMAT_CONTROL. CLAMP_POSITIVE_C default 0: disabled 1: enabled |
124 | REG_UPDATE(FORMAT_CONTROL, FORMAT_CNV16, 0); |
125 | REG_UPDATE(FORMAT_CONTROL, CNVC_BYPASS_MSB_ALIGN, 0); |
126 | REG_UPDATE(FORMAT_CONTROL, CLAMP_POSITIVE, 0); |
127 | REG_UPDATE(FORMAT_CONTROL, CLAMP_POSITIVE_C, 0); |
128 | |
129 | switch (format) { |
130 | case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555: |
131 | pixel_format = 1; |
132 | break; |
133 | case SURFACE_PIXEL_FORMAT_GRPH_RGB565: |
134 | pixel_format = 3; |
135 | alpha_en = 0; |
136 | break; |
137 | case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888: |
138 | case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888: |
139 | pixel_format = 8; |
140 | break; |
141 | case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010: |
142 | case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010: |
143 | pixel_format = 10; |
144 | is_2bit = 1; |
145 | break; |
146 | case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr: |
147 | force_disable_cursor = false; |
148 | pixel_format = 65; |
149 | color_space = COLOR_SPACE_YCBCR709; |
150 | select = DCN2_ICSC_SELECT_ICSC_A; |
151 | break; |
152 | case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb: |
153 | force_disable_cursor = true; |
154 | pixel_format = 64; |
155 | color_space = COLOR_SPACE_YCBCR709; |
156 | select = DCN2_ICSC_SELECT_ICSC_A; |
157 | break; |
158 | case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr: |
159 | force_disable_cursor = true; |
160 | pixel_format = 67; |
161 | color_space = COLOR_SPACE_YCBCR709; |
162 | select = DCN2_ICSC_SELECT_ICSC_A; |
163 | break; |
164 | case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb: |
165 | force_disable_cursor = true; |
166 | pixel_format = 66; |
167 | color_space = COLOR_SPACE_YCBCR709; |
168 | select = DCN2_ICSC_SELECT_ICSC_A; |
169 | break; |
170 | case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: |
171 | case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: |
172 | pixel_format = 26; /* ARGB16161616_UNORM */ |
173 | break; |
174 | case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: |
175 | pixel_format = 24; |
176 | break; |
177 | case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: |
178 | pixel_format = 25; |
179 | break; |
180 | case SURFACE_PIXEL_FORMAT_VIDEO_AYCrCb8888: |
181 | pixel_format = 12; |
182 | color_space = COLOR_SPACE_YCBCR709; |
183 | select = DCN2_ICSC_SELECT_ICSC_A; |
184 | break; |
185 | case SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FIX: |
186 | pixel_format = 112; |
187 | alpha_en = 0; |
188 | break; |
189 | case SURFACE_PIXEL_FORMAT_GRPH_BGR101111_FIX: |
190 | pixel_format = 113; |
191 | alpha_en = 0; |
192 | break; |
193 | case SURFACE_PIXEL_FORMAT_VIDEO_ACrYCb2101010: |
194 | pixel_format = 114; |
195 | color_space = COLOR_SPACE_YCBCR709; |
196 | select = DCN2_ICSC_SELECT_ICSC_A; |
197 | is_2bit = 1; |
198 | break; |
199 | case SURFACE_PIXEL_FORMAT_VIDEO_CrYCbA1010102: |
200 | pixel_format = 115; |
201 | color_space = COLOR_SPACE_YCBCR709; |
202 | select = DCN2_ICSC_SELECT_ICSC_A; |
203 | is_2bit = 1; |
204 | break; |
205 | case SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FLOAT: |
206 | pixel_format = 118; |
207 | alpha_en = 0; |
208 | break; |
209 | case SURFACE_PIXEL_FORMAT_GRPH_BGR101111_FLOAT: |
210 | pixel_format = 119; |
211 | alpha_en = 0; |
212 | break; |
213 | default: |
214 | break; |
215 | } |
216 | |
217 | /* Set default color space based on format if none is given. */ |
218 | color_space = input_color_space ? input_color_space : color_space; |
219 | |
220 | if (is_2bit == 1 && alpha_2bit_lut != NULL) { |
221 | REG_UPDATE(ALPHA_2BIT_LUT, ALPHA_2BIT_LUT0, alpha_2bit_lut->lut0); |
222 | REG_UPDATE(ALPHA_2BIT_LUT, ALPHA_2BIT_LUT1, alpha_2bit_lut->lut1); |
223 | REG_UPDATE(ALPHA_2BIT_LUT, ALPHA_2BIT_LUT2, alpha_2bit_lut->lut2); |
224 | REG_UPDATE(ALPHA_2BIT_LUT, ALPHA_2BIT_LUT3, alpha_2bit_lut->lut3); |
225 | } |
226 | |
227 | REG_SET(CNVC_SURFACE_PIXEL_FORMAT, 0, |
228 | CNVC_SURFACE_PIXEL_FORMAT, pixel_format); |
229 | REG_UPDATE(FORMAT_CONTROL, FORMAT_CONTROL__ALPHA_EN, alpha_en); |
230 | |
231 | // if input adjustments exist, program icsc with those values |
232 | if (input_csc_color_matrix.enable_adjustment |
233 | == true) { |
234 | for (i = 0; i < 12; i++) |
235 | tbl_entry.regval[i] = input_csc_color_matrix.matrix[i]; |
236 | |
237 | tbl_entry.color_space = input_color_space; |
238 | |
239 | if (color_space >= COLOR_SPACE_YCBCR601) |
240 | select = DCN2_ICSC_SELECT_ICSC_A; |
241 | else |
242 | select = DCN2_ICSC_SELECT_BYPASS; |
243 | |
244 | dpp2_program_input_csc(dpp_base, color_space, input_select: select, tbl_entry: &tbl_entry); |
245 | } else |
246 | dpp2_program_input_csc(dpp_base, color_space, input_select: select, NULL); |
247 | |
248 | if (force_disable_cursor) { |
249 | REG_UPDATE(CURSOR_CONTROL, |
250 | CURSOR_ENABLE, 0); |
251 | REG_UPDATE(CURSOR0_CONTROL, |
252 | CUR0_ENABLE, 0); |
253 | |
254 | } |
255 | dpp2_power_on_obuf(dpp_base, power_on: true); |
256 | |
257 | } |
258 | |
259 | /*compute the maximum number of lines that we can fit in the line buffer*/ |
260 | void dscl2_calc_lb_num_partitions( |
261 | const struct scaler_data *scl_data, |
262 | enum lb_memory_config lb_config, |
263 | int *num_part_y, |
264 | int *num_part_c) |
265 | { |
266 | int memory_line_size_y, memory_line_size_c, memory_line_size_a, |
267 | lb_memory_size, lb_memory_size_c, lb_memory_size_a, num_partitions_a; |
268 | |
269 | int line_size = scl_data->viewport.width < scl_data->recout.width ? |
270 | scl_data->viewport.width : scl_data->recout.width; |
271 | int line_size_c = scl_data->viewport_c.width < scl_data->recout.width ? |
272 | scl_data->viewport_c.width : scl_data->recout.width; |
273 | |
274 | if (line_size == 0) |
275 | line_size = 1; |
276 | |
277 | if (line_size_c == 0) |
278 | line_size_c = 1; |
279 | |
280 | memory_line_size_y = (line_size + 5) / 6; /* +5 to ceil */ |
281 | memory_line_size_c = (line_size_c + 5) / 6; /* +5 to ceil */ |
282 | memory_line_size_a = (line_size + 5) / 6; /* +5 to ceil */ |
283 | |
284 | if (lb_config == LB_MEMORY_CONFIG_1) { |
285 | lb_memory_size = 970; |
286 | lb_memory_size_c = 970; |
287 | lb_memory_size_a = 970; |
288 | } else if (lb_config == LB_MEMORY_CONFIG_2) { |
289 | lb_memory_size = 1290; |
290 | lb_memory_size_c = 1290; |
291 | lb_memory_size_a = 1290; |
292 | } else if (lb_config == LB_MEMORY_CONFIG_3) { |
293 | /* 420 mode: using 3rd mem from Y, Cr and Cb */ |
294 | lb_memory_size = 970 + 1290 + 484 + 484 + 484; |
295 | lb_memory_size_c = 970 + 1290; |
296 | lb_memory_size_a = 970 + 1290 + 484; |
297 | } else { |
298 | lb_memory_size = 970 + 1290 + 484; |
299 | lb_memory_size_c = 970 + 1290 + 484; |
300 | lb_memory_size_a = 970 + 1290 + 484; |
301 | } |
302 | *num_part_y = lb_memory_size / memory_line_size_y; |
303 | *num_part_c = lb_memory_size_c / memory_line_size_c; |
304 | num_partitions_a = lb_memory_size_a / memory_line_size_a; |
305 | |
306 | if (scl_data->lb_params.alpha_en |
307 | && (num_partitions_a < *num_part_y)) |
308 | *num_part_y = num_partitions_a; |
309 | |
310 | if (*num_part_y > 64) |
311 | *num_part_y = 64; |
312 | if (*num_part_c > 64) |
313 | *num_part_c = 64; |
314 | } |
315 | |
316 | void dpp2_cnv_set_alpha_keyer( |
317 | struct dpp *dpp_base, |
318 | struct cnv_color_keyer_params *color_keyer) |
319 | { |
320 | struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); |
321 | |
322 | REG_UPDATE(COLOR_KEYER_CONTROL, COLOR_KEYER_EN, color_keyer->color_keyer_en); |
323 | |
324 | REG_UPDATE(COLOR_KEYER_CONTROL, COLOR_KEYER_MODE, color_keyer->color_keyer_mode); |
325 | |
326 | REG_UPDATE(COLOR_KEYER_ALPHA, COLOR_KEYER_ALPHA_LOW, color_keyer->color_keyer_alpha_low); |
327 | REG_UPDATE(COLOR_KEYER_ALPHA, COLOR_KEYER_ALPHA_HIGH, color_keyer->color_keyer_alpha_high); |
328 | |
329 | REG_UPDATE(COLOR_KEYER_RED, COLOR_KEYER_RED_LOW, color_keyer->color_keyer_red_low); |
330 | REG_UPDATE(COLOR_KEYER_RED, COLOR_KEYER_RED_HIGH, color_keyer->color_keyer_red_high); |
331 | |
332 | REG_UPDATE(COLOR_KEYER_GREEN, COLOR_KEYER_GREEN_LOW, color_keyer->color_keyer_green_low); |
333 | REG_UPDATE(COLOR_KEYER_GREEN, COLOR_KEYER_GREEN_HIGH, color_keyer->color_keyer_green_high); |
334 | |
335 | REG_UPDATE(COLOR_KEYER_BLUE, COLOR_KEYER_BLUE_LOW, color_keyer->color_keyer_blue_low); |
336 | REG_UPDATE(COLOR_KEYER_BLUE, COLOR_KEYER_BLUE_HIGH, color_keyer->color_keyer_blue_high); |
337 | } |
338 | |
339 | void dpp2_set_cursor_attributes( |
340 | struct dpp *dpp_base, |
341 | struct dc_cursor_attributes *cursor_attributes) |
342 | { |
343 | enum dc_cursor_color_format color_format = cursor_attributes->color_format; |
344 | struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); |
345 | int cur_rom_en = 0; |
346 | |
347 | if (color_format == CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA || |
348 | color_format == CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA) { |
349 | if (cursor_attributes->attribute_flags.bits.ENABLE_CURSOR_DEGAMMA) { |
350 | cur_rom_en = 1; |
351 | } |
352 | } |
353 | |
354 | REG_UPDATE_3(CURSOR0_CONTROL, |
355 | CUR0_MODE, color_format, |
356 | CUR0_EXPANSION_MODE, 0, |
357 | CUR0_ROM_EN, cur_rom_en); |
358 | |
359 | if (color_format == CURSOR_MODE_MONO) { |
360 | /* todo: clarify what to program these to */ |
361 | REG_UPDATE(CURSOR0_COLOR0, |
362 | CUR0_COLOR0, 0x00000000); |
363 | REG_UPDATE(CURSOR0_COLOR1, |
364 | CUR0_COLOR1, 0xFFFFFFFF); |
365 | } |
366 | } |
367 | |
368 | void oppn20_dummy_program_regamma_pwl( |
369 | struct dpp *dpp, |
370 | const struct pwl_params *params, |
371 | enum opp_regamma mode) |
372 | {} |
373 | |
374 | static struct dpp_funcs dcn20_dpp_funcs = { |
375 | .dpp_read_state = dpp20_read_state, |
376 | .dpp_reset = dpp_reset, |
377 | .dpp_set_scaler = dpp1_dscl_set_scaler_manual_scale, |
378 | .dpp_get_optimal_number_of_taps = dpp1_get_optimal_number_of_taps, |
379 | .dpp_set_gamut_remap = dpp2_cm_set_gamut_remap, |
380 | .dpp_set_csc_adjustment = NULL, |
381 | .dpp_set_csc_default = NULL, |
382 | .dpp_program_regamma_pwl = oppn20_dummy_program_regamma_pwl, |
383 | .dpp_set_degamma = dpp2_set_degamma, |
384 | .dpp_program_input_lut = dpp2_dummy_program_input_lut, |
385 | .dpp_full_bypass = dpp1_full_bypass, |
386 | .dpp_setup = dpp2_cnv_setup, |
387 | .dpp_program_degamma_pwl = dpp2_set_degamma_pwl, |
388 | .dpp_program_blnd_lut = dpp20_program_blnd_lut, |
389 | .dpp_program_shaper_lut = dpp20_program_shaper, |
390 | .dpp_program_3dlut = dpp20_program_3dlut, |
391 | .dpp_program_bias_and_scale = NULL, |
392 | .dpp_cnv_set_alpha_keyer = dpp2_cnv_set_alpha_keyer, |
393 | .set_cursor_attributes = dpp2_set_cursor_attributes, |
394 | .set_cursor_position = dpp1_set_cursor_position, |
395 | .set_optional_cursor_attributes = dpp1_cnv_set_optional_cursor_attributes, |
396 | .dpp_dppclk_control = dpp1_dppclk_control, |
397 | .dpp_set_hdr_multiplier = dpp2_set_hdr_multiplier, |
398 | .dpp_get_gamut_remap = dpp2_cm_get_gamut_remap, |
399 | }; |
400 | |
401 | static struct dpp_caps dcn20_dpp_cap = { |
402 | .dscl_data_proc_format = DSCL_DATA_PRCESSING_FLOAT_FORMAT, |
403 | .dscl_calc_lb_num_partitions = dscl2_calc_lb_num_partitions, |
404 | }; |
405 | |
406 | bool dpp2_construct( |
407 | struct dcn20_dpp *dpp, |
408 | struct dc_context *ctx, |
409 | uint32_t inst, |
410 | const struct dcn2_dpp_registers *tf_regs, |
411 | const struct dcn2_dpp_shift *tf_shift, |
412 | const struct dcn2_dpp_mask *tf_mask) |
413 | { |
414 | dpp->base.ctx = ctx; |
415 | |
416 | dpp->base.inst = inst; |
417 | dpp->base.funcs = &dcn20_dpp_funcs; |
418 | dpp->base.caps = &dcn20_dpp_cap; |
419 | |
420 | dpp->tf_regs = tf_regs; |
421 | dpp->tf_shift = tf_shift; |
422 | dpp->tf_mask = tf_mask; |
423 | |
424 | dpp->lb_pixel_depth_supported = |
425 | LB_PIXEL_DEPTH_18BPP | |
426 | LB_PIXEL_DEPTH_24BPP | |
427 | LB_PIXEL_DEPTH_30BPP | |
428 | LB_PIXEL_DEPTH_36BPP; |
429 | |
430 | dpp->lb_bits_per_entry = LB_BITS_PER_ENTRY; |
431 | dpp->lb_memory_size = LB_TOTAL_NUMBER_OF_ENTRIES; /*0x1404*/ |
432 | |
433 | return true; |
434 | } |
435 | |
436 | |