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 "dcn10_dpp.h" |
32 | #include "basics/conversion.h" |
33 | |
34 | |
35 | #define NUM_PHASES 64 |
36 | #define HORZ_MAX_TAPS 8 |
37 | #define VERT_MAX_TAPS 8 |
38 | |
39 | #define BLACK_OFFSET_RGB_Y 0x0 |
40 | #define BLACK_OFFSET_CBCR 0x8000 |
41 | |
42 | |
43 | #define REG(reg)\ |
44 | dpp->tf_regs->reg |
45 | |
46 | #define CTX \ |
47 | dpp->base.ctx |
48 | |
49 | #undef FN |
50 | #define FN(reg_name, field_name) \ |
51 | dpp->tf_shift->field_name, dpp->tf_mask->field_name |
52 | |
53 | enum dcn10_coef_filter_type_sel { |
54 | SCL_COEF_LUMA_VERT_FILTER = 0, |
55 | SCL_COEF_LUMA_HORZ_FILTER = 1, |
56 | SCL_COEF_CHROMA_VERT_FILTER = 2, |
57 | SCL_COEF_CHROMA_HORZ_FILTER = 3, |
58 | SCL_COEF_ALPHA_VERT_FILTER = 4, |
59 | SCL_COEF_ALPHA_HORZ_FILTER = 5 |
60 | }; |
61 | |
62 | enum dscl_autocal_mode { |
63 | AUTOCAL_MODE_OFF = 0, |
64 | |
65 | /* Autocal calculate the scaling ratio and initial phase and the |
66 | * DSCL_MODE_SEL must be set to 1 |
67 | */ |
68 | AUTOCAL_MODE_AUTOSCALE = 1, |
69 | /* Autocal perform auto centering without replication and the |
70 | * DSCL_MODE_SEL must be set to 0 |
71 | */ |
72 | AUTOCAL_MODE_AUTOCENTER = 2, |
73 | /* Autocal perform auto centering and auto replication and the |
74 | * DSCL_MODE_SEL must be set to 0 |
75 | */ |
76 | AUTOCAL_MODE_AUTOREPLICATE = 3 |
77 | }; |
78 | |
79 | enum dscl_mode_sel { |
80 | DSCL_MODE_SCALING_444_BYPASS = 0, |
81 | DSCL_MODE_SCALING_444_RGB_ENABLE = 1, |
82 | DSCL_MODE_SCALING_444_YCBCR_ENABLE = 2, |
83 | DSCL_MODE_SCALING_420_YCBCR_ENABLE = 3, |
84 | DSCL_MODE_SCALING_420_LUMA_BYPASS = 4, |
85 | DSCL_MODE_SCALING_420_CHROMA_BYPASS = 5, |
86 | DSCL_MODE_DSCL_BYPASS = 6 |
87 | }; |
88 | |
89 | static int dpp1_dscl_get_pixel_depth_val(enum lb_pixel_depth depth) |
90 | { |
91 | if (depth == LB_PIXEL_DEPTH_30BPP) |
92 | return 0; /* 10 bpc */ |
93 | else if (depth == LB_PIXEL_DEPTH_24BPP) |
94 | return 1; /* 8 bpc */ |
95 | else if (depth == LB_PIXEL_DEPTH_18BPP) |
96 | return 2; /* 6 bpc */ |
97 | else if (depth == LB_PIXEL_DEPTH_36BPP) |
98 | return 3; /* 12 bpc */ |
99 | else { |
100 | ASSERT(0); |
101 | return -1; /* Unsupported */ |
102 | } |
103 | } |
104 | |
105 | static bool dpp1_dscl_is_video_format(enum pixel_format format) |
106 | { |
107 | if (format >= PIXEL_FORMAT_VIDEO_BEGIN |
108 | && format <= PIXEL_FORMAT_VIDEO_END) |
109 | return true; |
110 | else |
111 | return false; |
112 | } |
113 | |
114 | static bool dpp1_dscl_is_420_format(enum pixel_format format) |
115 | { |
116 | if (format == PIXEL_FORMAT_420BPP8 || |
117 | format == PIXEL_FORMAT_420BPP10) |
118 | return true; |
119 | else |
120 | return false; |
121 | } |
122 | |
123 | static enum dscl_mode_sel dpp1_dscl_get_dscl_mode( |
124 | struct dpp *dpp_base, |
125 | const struct scaler_data *data, |
126 | bool dbg_always_scale) |
127 | { |
128 | const long long one = dc_fixpt_one.value; |
129 | |
130 | if (dpp_base->caps->dscl_data_proc_format == DSCL_DATA_PRCESSING_FIXED_FORMAT) { |
131 | /* DSCL is processing data in fixed format */ |
132 | if (data->format == PIXEL_FORMAT_FP16) |
133 | return DSCL_MODE_DSCL_BYPASS; |
134 | } |
135 | |
136 | if (data->ratios.horz.value == one |
137 | && data->ratios.vert.value == one |
138 | && data->ratios.horz_c.value == one |
139 | && data->ratios.vert_c.value == one |
140 | && !dbg_always_scale) |
141 | return DSCL_MODE_SCALING_444_BYPASS; |
142 | |
143 | if (!dpp1_dscl_is_420_format(format: data->format)) { |
144 | if (dpp1_dscl_is_video_format(format: data->format)) |
145 | return DSCL_MODE_SCALING_444_YCBCR_ENABLE; |
146 | else |
147 | return DSCL_MODE_SCALING_444_RGB_ENABLE; |
148 | } |
149 | if (data->ratios.horz.value == one && data->ratios.vert.value == one) |
150 | return DSCL_MODE_SCALING_420_LUMA_BYPASS; |
151 | if (data->ratios.horz_c.value == one && data->ratios.vert_c.value == one) |
152 | return DSCL_MODE_SCALING_420_CHROMA_BYPASS; |
153 | |
154 | return DSCL_MODE_SCALING_420_YCBCR_ENABLE; |
155 | } |
156 | |
157 | static void dpp1_power_on_dscl( |
158 | struct dpp *dpp_base, |
159 | bool power_on) |
160 | { |
161 | struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); |
162 | |
163 | if (dpp->tf_regs->DSCL_MEM_PWR_CTRL) { |
164 | if (power_on) { |
165 | REG_UPDATE(DSCL_MEM_PWR_CTRL, LUT_MEM_PWR_FORCE, 0); |
166 | REG_WAIT(DSCL_MEM_PWR_STATUS, LUT_MEM_PWR_STATE, 0, 1, 5); |
167 | } else { |
168 | if (dpp->base.ctx->dc->debug.enable_mem_low_power.bits.dscl) { |
169 | dpp->base.ctx->dc->optimized_required = true; |
170 | dpp->base.deferred_reg_writes.bits.disable_dscl = true; |
171 | } else { |
172 | REG_UPDATE(DSCL_MEM_PWR_CTRL, LUT_MEM_PWR_FORCE, 3); |
173 | } |
174 | } |
175 | } |
176 | } |
177 | |
178 | |
179 | static void dpp1_dscl_set_lb( |
180 | struct dcn10_dpp *dpp, |
181 | const struct line_buffer_params *lb_params, |
182 | enum lb_memory_config mem_size_config) |
183 | { |
184 | uint32_t max_partitions = 63; /* Currently hardcoded on all ASICs before DCN 3.2 */ |
185 | |
186 | /* LB */ |
187 | if (dpp->base.caps->dscl_data_proc_format == DSCL_DATA_PRCESSING_FIXED_FORMAT) { |
188 | /* DSCL caps: pixel data processed in fixed format */ |
189 | uint32_t pixel_depth = dpp1_dscl_get_pixel_depth_val(depth: lb_params->depth); |
190 | uint32_t dyn_pix_depth = lb_params->dynamic_pixel_depth; |
191 | |
192 | REG_SET_7(LB_DATA_FORMAT, 0, |
193 | PIXEL_DEPTH, pixel_depth, /* Pixel depth stored in LB */ |
194 | PIXEL_EXPAN_MODE, lb_params->pixel_expan_mode, /* Pixel expansion mode */ |
195 | PIXEL_REDUCE_MODE, 1, /* Pixel reduction mode: Rounding */ |
196 | DYNAMIC_PIXEL_DEPTH, dyn_pix_depth, /* Dynamic expansion pixel depth */ |
197 | DITHER_EN, 0, /* Dithering enable: Disabled */ |
198 | INTERLEAVE_EN, lb_params->interleave_en, /* Interleave source enable */ |
199 | LB_DATA_FORMAT__ALPHA_EN, lb_params->alpha_en); /* Alpha enable */ |
200 | } else { |
201 | /* DSCL caps: pixel data processed in float format */ |
202 | REG_SET_2(LB_DATA_FORMAT, 0, |
203 | INTERLEAVE_EN, lb_params->interleave_en, /* Interleave source enable */ |
204 | LB_DATA_FORMAT__ALPHA_EN, lb_params->alpha_en); /* Alpha enable */ |
205 | } |
206 | |
207 | if (dpp->base.caps->max_lb_partitions == 31) |
208 | max_partitions = 31; |
209 | |
210 | REG_SET_2(LB_MEMORY_CTRL, 0, |
211 | MEMORY_CONFIG, mem_size_config, |
212 | LB_MAX_PARTITIONS, max_partitions); |
213 | } |
214 | |
215 | static const uint16_t *dpp1_dscl_get_filter_coeffs_64p(int taps, struct fixed31_32 ratio) |
216 | { |
217 | if (taps == 8) |
218 | return get_filter_8tap_64p(ratio); |
219 | else if (taps == 7) |
220 | return get_filter_7tap_64p(ratio); |
221 | else if (taps == 6) |
222 | return get_filter_6tap_64p(ratio); |
223 | else if (taps == 5) |
224 | return get_filter_5tap_64p(ratio); |
225 | else if (taps == 4) |
226 | return get_filter_4tap_64p(ratio); |
227 | else if (taps == 3) |
228 | return get_filter_3tap_64p(ratio); |
229 | else if (taps == 2) |
230 | return get_filter_2tap_64p(); |
231 | else if (taps == 1) |
232 | return NULL; |
233 | else { |
234 | /* should never happen, bug */ |
235 | BREAK_TO_DEBUGGER(); |
236 | return NULL; |
237 | } |
238 | } |
239 | |
240 | static void dpp1_dscl_set_scaler_filter( |
241 | struct dcn10_dpp *dpp, |
242 | uint32_t taps, |
243 | enum dcn10_coef_filter_type_sel filter_type, |
244 | const uint16_t *filter) |
245 | { |
246 | const int tap_pairs = (taps + 1) / 2; |
247 | int phase; |
248 | int pair; |
249 | uint16_t odd_coef, even_coef; |
250 | |
251 | REG_SET_3(SCL_COEF_RAM_TAP_SELECT, 0, |
252 | SCL_COEF_RAM_TAP_PAIR_IDX, 0, |
253 | SCL_COEF_RAM_PHASE, 0, |
254 | SCL_COEF_RAM_FILTER_TYPE, filter_type); |
255 | |
256 | for (phase = 0; phase < (NUM_PHASES / 2 + 1); phase++) { |
257 | for (pair = 0; pair < tap_pairs; pair++) { |
258 | even_coef = filter[phase * taps + 2 * pair]; |
259 | if ((pair * 2 + 1) < taps) |
260 | odd_coef = filter[phase * taps + 2 * pair + 1]; |
261 | else |
262 | odd_coef = 0; |
263 | |
264 | REG_SET_4(SCL_COEF_RAM_TAP_DATA, 0, |
265 | /* Even tap coefficient (bits 1:0 fixed to 0) */ |
266 | SCL_COEF_RAM_EVEN_TAP_COEF, even_coef, |
267 | /* Write/read control for even coefficient */ |
268 | SCL_COEF_RAM_EVEN_TAP_COEF_EN, 1, |
269 | /* Odd tap coefficient (bits 1:0 fixed to 0) */ |
270 | SCL_COEF_RAM_ODD_TAP_COEF, odd_coef, |
271 | /* Write/read control for odd coefficient */ |
272 | SCL_COEF_RAM_ODD_TAP_COEF_EN, 1); |
273 | } |
274 | } |
275 | |
276 | } |
277 | |
278 | static void dpp1_dscl_set_scl_filter( |
279 | struct dcn10_dpp *dpp, |
280 | const struct scaler_data *scl_data, |
281 | bool chroma_coef_mode) |
282 | { |
283 | bool h_2tap_hardcode_coef_en = false; |
284 | bool v_2tap_hardcode_coef_en = false; |
285 | bool h_2tap_sharp_en = false; |
286 | bool v_2tap_sharp_en = false; |
287 | uint32_t h_2tap_sharp_factor = scl_data->sharpness.horz; |
288 | uint32_t v_2tap_sharp_factor = scl_data->sharpness.vert; |
289 | bool coef_ram_current; |
290 | const uint16_t *filter_h = NULL; |
291 | const uint16_t *filter_v = NULL; |
292 | const uint16_t *filter_h_c = NULL; |
293 | const uint16_t *filter_v_c = NULL; |
294 | |
295 | h_2tap_hardcode_coef_en = scl_data->taps.h_taps < 3 |
296 | && scl_data->taps.h_taps_c < 3 |
297 | && (scl_data->taps.h_taps > 1 && scl_data->taps.h_taps_c > 1); |
298 | v_2tap_hardcode_coef_en = scl_data->taps.v_taps < 3 |
299 | && scl_data->taps.v_taps_c < 3 |
300 | && (scl_data->taps.v_taps > 1 && scl_data->taps.v_taps_c > 1); |
301 | |
302 | h_2tap_sharp_en = h_2tap_hardcode_coef_en && h_2tap_sharp_factor != 0; |
303 | v_2tap_sharp_en = v_2tap_hardcode_coef_en && v_2tap_sharp_factor != 0; |
304 | |
305 | REG_UPDATE_6(DSCL_2TAP_CONTROL, |
306 | SCL_H_2TAP_HARDCODE_COEF_EN, h_2tap_hardcode_coef_en, |
307 | SCL_H_2TAP_SHARP_EN, h_2tap_sharp_en, |
308 | SCL_H_2TAP_SHARP_FACTOR, h_2tap_sharp_factor, |
309 | SCL_V_2TAP_HARDCODE_COEF_EN, v_2tap_hardcode_coef_en, |
310 | SCL_V_2TAP_SHARP_EN, v_2tap_sharp_en, |
311 | SCL_V_2TAP_SHARP_FACTOR, v_2tap_sharp_factor); |
312 | |
313 | if (!v_2tap_hardcode_coef_en || !h_2tap_hardcode_coef_en) { |
314 | bool filter_updated = false; |
315 | |
316 | filter_h = dpp1_dscl_get_filter_coeffs_64p( |
317 | taps: scl_data->taps.h_taps, ratio: scl_data->ratios.horz); |
318 | filter_v = dpp1_dscl_get_filter_coeffs_64p( |
319 | taps: scl_data->taps.v_taps, ratio: scl_data->ratios.vert); |
320 | |
321 | filter_updated = (filter_h && (filter_h != dpp->filter_h)) |
322 | || (filter_v && (filter_v != dpp->filter_v)); |
323 | |
324 | if (chroma_coef_mode) { |
325 | filter_h_c = dpp1_dscl_get_filter_coeffs_64p( |
326 | taps: scl_data->taps.h_taps_c, ratio: scl_data->ratios.horz_c); |
327 | filter_v_c = dpp1_dscl_get_filter_coeffs_64p( |
328 | taps: scl_data->taps.v_taps_c, ratio: scl_data->ratios.vert_c); |
329 | filter_updated = filter_updated || (filter_h_c && (filter_h_c != dpp->filter_h_c)) |
330 | || (filter_v_c && (filter_v_c != dpp->filter_v_c)); |
331 | } |
332 | |
333 | if (filter_updated) { |
334 | uint32_t scl_mode = REG_READ(SCL_MODE); |
335 | |
336 | if (!h_2tap_hardcode_coef_en && filter_h) { |
337 | dpp1_dscl_set_scaler_filter( |
338 | dpp, taps: scl_data->taps.h_taps, |
339 | filter_type: SCL_COEF_LUMA_HORZ_FILTER, filter: filter_h); |
340 | } |
341 | dpp->filter_h = filter_h; |
342 | if (!v_2tap_hardcode_coef_en && filter_v) { |
343 | dpp1_dscl_set_scaler_filter( |
344 | dpp, taps: scl_data->taps.v_taps, |
345 | filter_type: SCL_COEF_LUMA_VERT_FILTER, filter: filter_v); |
346 | } |
347 | dpp->filter_v = filter_v; |
348 | if (chroma_coef_mode) { |
349 | if (!h_2tap_hardcode_coef_en && filter_h_c) { |
350 | dpp1_dscl_set_scaler_filter( |
351 | dpp, taps: scl_data->taps.h_taps_c, |
352 | filter_type: SCL_COEF_CHROMA_HORZ_FILTER, filter: filter_h_c); |
353 | } |
354 | if (!v_2tap_hardcode_coef_en && filter_v_c) { |
355 | dpp1_dscl_set_scaler_filter( |
356 | dpp, taps: scl_data->taps.v_taps_c, |
357 | filter_type: SCL_COEF_CHROMA_VERT_FILTER, filter: filter_v_c); |
358 | } |
359 | } |
360 | dpp->filter_h_c = filter_h_c; |
361 | dpp->filter_v_c = filter_v_c; |
362 | |
363 | coef_ram_current = get_reg_field_value_ex( |
364 | reg_value: scl_mode, mask: dpp->tf_mask->SCL_COEF_RAM_SELECT_CURRENT, |
365 | shift: dpp->tf_shift->SCL_COEF_RAM_SELECT_CURRENT); |
366 | |
367 | /* Swap coefficient RAM and set chroma coefficient mode */ |
368 | REG_SET_2(SCL_MODE, scl_mode, |
369 | SCL_COEF_RAM_SELECT, !coef_ram_current, |
370 | SCL_CHROMA_COEF_MODE, chroma_coef_mode); |
371 | } |
372 | } |
373 | } |
374 | |
375 | static int dpp1_dscl_get_lb_depth_bpc(enum lb_pixel_depth depth) |
376 | { |
377 | if (depth == LB_PIXEL_DEPTH_30BPP) |
378 | return 10; |
379 | else if (depth == LB_PIXEL_DEPTH_24BPP) |
380 | return 8; |
381 | else if (depth == LB_PIXEL_DEPTH_18BPP) |
382 | return 6; |
383 | else if (depth == LB_PIXEL_DEPTH_36BPP) |
384 | return 12; |
385 | else { |
386 | BREAK_TO_DEBUGGER(); |
387 | return -1; /* Unsupported */ |
388 | } |
389 | } |
390 | |
391 | void dpp1_dscl_calc_lb_num_partitions( |
392 | const struct scaler_data *scl_data, |
393 | enum lb_memory_config lb_config, |
394 | int *num_part_y, |
395 | int *num_part_c) |
396 | { |
397 | int lb_memory_size, lb_memory_size_c, lb_memory_size_a, num_partitions_a, |
398 | lb_bpc, memory_line_size_y, memory_line_size_c, memory_line_size_a; |
399 | |
400 | int line_size = scl_data->viewport.width < scl_data->recout.width ? |
401 | scl_data->viewport.width : scl_data->recout.width; |
402 | int line_size_c = scl_data->viewport_c.width < scl_data->recout.width ? |
403 | scl_data->viewport_c.width : scl_data->recout.width; |
404 | |
405 | if (line_size == 0) |
406 | line_size = 1; |
407 | |
408 | if (line_size_c == 0) |
409 | line_size_c = 1; |
410 | |
411 | |
412 | lb_bpc = dpp1_dscl_get_lb_depth_bpc(depth: scl_data->lb_params.depth); |
413 | memory_line_size_y = (line_size * lb_bpc + 71) / 72; /* +71 to ceil */ |
414 | memory_line_size_c = (line_size_c * lb_bpc + 71) / 72; /* +71 to ceil */ |
415 | memory_line_size_a = (line_size + 5) / 6; /* +5 to ceil */ |
416 | |
417 | if (lb_config == LB_MEMORY_CONFIG_1) { |
418 | lb_memory_size = 816; |
419 | lb_memory_size_c = 816; |
420 | lb_memory_size_a = 984; |
421 | } else if (lb_config == LB_MEMORY_CONFIG_2) { |
422 | lb_memory_size = 1088; |
423 | lb_memory_size_c = 1088; |
424 | lb_memory_size_a = 1312; |
425 | } else if (lb_config == LB_MEMORY_CONFIG_3) { |
426 | /* 420 mode: using 3rd mem from Y, Cr and Cb */ |
427 | lb_memory_size = 816 + 1088 + 848 + 848 + 848; |
428 | lb_memory_size_c = 816 + 1088; |
429 | lb_memory_size_a = 984 + 1312 + 456; |
430 | } else { |
431 | lb_memory_size = 816 + 1088 + 848; |
432 | lb_memory_size_c = 816 + 1088 + 848; |
433 | lb_memory_size_a = 984 + 1312 + 456; |
434 | } |
435 | *num_part_y = lb_memory_size / memory_line_size_y; |
436 | *num_part_c = lb_memory_size_c / memory_line_size_c; |
437 | num_partitions_a = lb_memory_size_a / memory_line_size_a; |
438 | |
439 | if (scl_data->lb_params.alpha_en |
440 | && (num_partitions_a < *num_part_y)) |
441 | *num_part_y = num_partitions_a; |
442 | |
443 | if (*num_part_y > 64) |
444 | *num_part_y = 64; |
445 | if (*num_part_c > 64) |
446 | *num_part_c = 64; |
447 | |
448 | } |
449 | |
450 | bool dpp1_dscl_is_lb_conf_valid(int ceil_vratio, int num_partitions, int vtaps) |
451 | { |
452 | if (ceil_vratio > 2) |
453 | return vtaps <= (num_partitions - ceil_vratio + 2); |
454 | else |
455 | return vtaps <= num_partitions; |
456 | } |
457 | |
458 | /*find first match configuration which meets the min required lb size*/ |
459 | static enum lb_memory_config dpp1_dscl_find_lb_memory_config(struct dcn10_dpp *dpp, |
460 | const struct scaler_data *scl_data) |
461 | { |
462 | int num_part_y, num_part_c; |
463 | int vtaps = scl_data->taps.v_taps; |
464 | int vtaps_c = scl_data->taps.v_taps_c; |
465 | int ceil_vratio = dc_fixpt_ceil(arg: scl_data->ratios.vert); |
466 | int ceil_vratio_c = dc_fixpt_ceil(arg: scl_data->ratios.vert_c); |
467 | |
468 | if (dpp->base.ctx->dc->debug.use_max_lb) { |
469 | if (scl_data->format == PIXEL_FORMAT_420BPP8 |
470 | || scl_data->format == PIXEL_FORMAT_420BPP10) |
471 | return LB_MEMORY_CONFIG_3; |
472 | return LB_MEMORY_CONFIG_0; |
473 | } |
474 | |
475 | dpp->base.caps->dscl_calc_lb_num_partitions( |
476 | scl_data, LB_MEMORY_CONFIG_1, &num_part_y, &num_part_c); |
477 | |
478 | if (dpp1_dscl_is_lb_conf_valid(ceil_vratio, num_partitions: num_part_y, vtaps) |
479 | && dpp1_dscl_is_lb_conf_valid(ceil_vratio: ceil_vratio_c, num_partitions: num_part_c, vtaps: vtaps_c)) |
480 | return LB_MEMORY_CONFIG_1; |
481 | |
482 | dpp->base.caps->dscl_calc_lb_num_partitions( |
483 | scl_data, LB_MEMORY_CONFIG_2, &num_part_y, &num_part_c); |
484 | |
485 | if (dpp1_dscl_is_lb_conf_valid(ceil_vratio, num_partitions: num_part_y, vtaps) |
486 | && dpp1_dscl_is_lb_conf_valid(ceil_vratio: ceil_vratio_c, num_partitions: num_part_c, vtaps: vtaps_c)) |
487 | return LB_MEMORY_CONFIG_2; |
488 | |
489 | if (scl_data->format == PIXEL_FORMAT_420BPP8 |
490 | || scl_data->format == PIXEL_FORMAT_420BPP10) { |
491 | dpp->base.caps->dscl_calc_lb_num_partitions( |
492 | scl_data, LB_MEMORY_CONFIG_3, &num_part_y, &num_part_c); |
493 | |
494 | if (dpp1_dscl_is_lb_conf_valid(ceil_vratio, num_partitions: num_part_y, vtaps) |
495 | && dpp1_dscl_is_lb_conf_valid(ceil_vratio: ceil_vratio_c, num_partitions: num_part_c, vtaps: vtaps_c)) |
496 | return LB_MEMORY_CONFIG_3; |
497 | } |
498 | |
499 | dpp->base.caps->dscl_calc_lb_num_partitions( |
500 | scl_data, LB_MEMORY_CONFIG_0, &num_part_y, &num_part_c); |
501 | |
502 | /*Ensure we can support the requested number of vtaps*/ |
503 | ASSERT(dpp1_dscl_is_lb_conf_valid(ceil_vratio, num_part_y, vtaps) |
504 | && dpp1_dscl_is_lb_conf_valid(ceil_vratio_c, num_part_c, vtaps_c)); |
505 | |
506 | return LB_MEMORY_CONFIG_0; |
507 | } |
508 | |
509 | |
510 | static void dpp1_dscl_set_manual_ratio_init( |
511 | struct dcn10_dpp *dpp, const struct scaler_data *data) |
512 | { |
513 | uint32_t init_frac = 0; |
514 | uint32_t init_int = 0; |
515 | |
516 | REG_SET(SCL_HORZ_FILTER_SCALE_RATIO, 0, |
517 | SCL_H_SCALE_RATIO, dc_fixpt_u3d19(data->ratios.horz) << 5); |
518 | |
519 | REG_SET(SCL_VERT_FILTER_SCALE_RATIO, 0, |
520 | SCL_V_SCALE_RATIO, dc_fixpt_u3d19(data->ratios.vert) << 5); |
521 | |
522 | REG_SET(SCL_HORZ_FILTER_SCALE_RATIO_C, 0, |
523 | SCL_H_SCALE_RATIO_C, dc_fixpt_u3d19(data->ratios.horz_c) << 5); |
524 | |
525 | REG_SET(SCL_VERT_FILTER_SCALE_RATIO_C, 0, |
526 | SCL_V_SCALE_RATIO_C, dc_fixpt_u3d19(data->ratios.vert_c) << 5); |
527 | |
528 | /* |
529 | * 0.24 format for fraction, first five bits zeroed |
530 | */ |
531 | init_frac = dc_fixpt_u0d19(arg: data->inits.h) << 5; |
532 | init_int = dc_fixpt_floor(arg: data->inits.h); |
533 | REG_SET_2(SCL_HORZ_FILTER_INIT, 0, |
534 | SCL_H_INIT_FRAC, init_frac, |
535 | SCL_H_INIT_INT, init_int); |
536 | |
537 | init_frac = dc_fixpt_u0d19(arg: data->inits.h_c) << 5; |
538 | init_int = dc_fixpt_floor(arg: data->inits.h_c); |
539 | REG_SET_2(SCL_HORZ_FILTER_INIT_C, 0, |
540 | SCL_H_INIT_FRAC_C, init_frac, |
541 | SCL_H_INIT_INT_C, init_int); |
542 | |
543 | init_frac = dc_fixpt_u0d19(arg: data->inits.v) << 5; |
544 | init_int = dc_fixpt_floor(arg: data->inits.v); |
545 | REG_SET_2(SCL_VERT_FILTER_INIT, 0, |
546 | SCL_V_INIT_FRAC, init_frac, |
547 | SCL_V_INIT_INT, init_int); |
548 | |
549 | if (REG(SCL_VERT_FILTER_INIT_BOT)) { |
550 | struct fixed31_32 bot = dc_fixpt_add(arg1: data->inits.v, arg2: data->ratios.vert); |
551 | |
552 | init_frac = dc_fixpt_u0d19(arg: bot) << 5; |
553 | init_int = dc_fixpt_floor(arg: bot); |
554 | REG_SET_2(SCL_VERT_FILTER_INIT_BOT, 0, |
555 | SCL_V_INIT_FRAC_BOT, init_frac, |
556 | SCL_V_INIT_INT_BOT, init_int); |
557 | } |
558 | |
559 | init_frac = dc_fixpt_u0d19(arg: data->inits.v_c) << 5; |
560 | init_int = dc_fixpt_floor(arg: data->inits.v_c); |
561 | REG_SET_2(SCL_VERT_FILTER_INIT_C, 0, |
562 | SCL_V_INIT_FRAC_C, init_frac, |
563 | SCL_V_INIT_INT_C, init_int); |
564 | |
565 | if (REG(SCL_VERT_FILTER_INIT_BOT_C)) { |
566 | struct fixed31_32 bot = dc_fixpt_add(arg1: data->inits.v_c, arg2: data->ratios.vert_c); |
567 | |
568 | init_frac = dc_fixpt_u0d19(arg: bot) << 5; |
569 | init_int = dc_fixpt_floor(arg: bot); |
570 | REG_SET_2(SCL_VERT_FILTER_INIT_BOT_C, 0, |
571 | SCL_V_INIT_FRAC_BOT_C, init_frac, |
572 | SCL_V_INIT_INT_BOT_C, init_int); |
573 | } |
574 | } |
575 | |
576 | /** |
577 | * dpp1_dscl_set_recout - Set the first pixel of RECOUT in the OTG active area |
578 | * |
579 | * @dpp: DPP data struct |
580 | * @recout: Rectangle information |
581 | * |
582 | * This function sets the MPC RECOUT_START and RECOUT_SIZE registers based on |
583 | * the values specified in the recount parameter. |
584 | * |
585 | * Note: This function only have effect if AutoCal is disabled. |
586 | */ |
587 | static void dpp1_dscl_set_recout(struct dcn10_dpp *dpp, |
588 | const struct rect *recout) |
589 | { |
590 | REG_SET_2(RECOUT_START, 0, |
591 | /* First pixel of RECOUT in the active OTG area */ |
592 | RECOUT_START_X, recout->x, |
593 | /* First line of RECOUT in the active OTG area */ |
594 | RECOUT_START_Y, recout->y); |
595 | |
596 | REG_SET_2(RECOUT_SIZE, 0, |
597 | /* Number of RECOUT horizontal pixels */ |
598 | RECOUT_WIDTH, recout->width, |
599 | /* Number of RECOUT vertical lines */ |
600 | RECOUT_HEIGHT, recout->height); |
601 | } |
602 | |
603 | /** |
604 | * dpp1_dscl_set_scaler_manual_scale - Manually program scaler and line buffer |
605 | * |
606 | * @dpp_base: High level DPP struct |
607 | * @scl_data: scalaer_data info |
608 | * |
609 | * This is the primary function to program scaler and line buffer in manual |
610 | * scaling mode. To execute the required operations for manual scale, we need |
611 | * to disable AutoCal first. |
612 | */ |
613 | void dpp1_dscl_set_scaler_manual_scale(struct dpp *dpp_base, |
614 | const struct scaler_data *scl_data) |
615 | { |
616 | enum lb_memory_config lb_config; |
617 | struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); |
618 | enum dscl_mode_sel dscl_mode = dpp1_dscl_get_dscl_mode( |
619 | dpp_base, data: scl_data, dbg_always_scale: dpp_base->ctx->dc->debug.always_scale); |
620 | bool ycbcr = scl_data->format >= PIXEL_FORMAT_VIDEO_BEGIN |
621 | && scl_data->format <= PIXEL_FORMAT_VIDEO_END; |
622 | |
623 | if (memcmp(p: &dpp->scl_data, q: scl_data, size: sizeof(*scl_data)) == 0) |
624 | return; |
625 | |
626 | PERF_TRACE(); |
627 | |
628 | dpp->scl_data = *scl_data; |
629 | |
630 | if (dpp_base->ctx->dc->debug.enable_mem_low_power.bits.dscl) { |
631 | if (dscl_mode != DSCL_MODE_DSCL_BYPASS) |
632 | dpp1_power_on_dscl(dpp_base, power_on: true); |
633 | } |
634 | |
635 | /* Autocal off */ |
636 | REG_SET_3(DSCL_AUTOCAL, 0, |
637 | AUTOCAL_MODE, AUTOCAL_MODE_OFF, |
638 | AUTOCAL_NUM_PIPE, 0, |
639 | AUTOCAL_PIPE_ID, 0); |
640 | |
641 | /*clean scaler boundary mode when Autocal off*/ |
642 | REG_SET(DSCL_CONTROL, 0, |
643 | SCL_BOUNDARY_MODE, 0); |
644 | |
645 | /* Recout */ |
646 | dpp1_dscl_set_recout(dpp, recout: &scl_data->recout); |
647 | |
648 | /* MPC Size */ |
649 | REG_SET_2(MPC_SIZE, 0, |
650 | /* Number of horizontal pixels of MPC */ |
651 | MPC_WIDTH, scl_data->h_active, |
652 | /* Number of vertical lines of MPC */ |
653 | MPC_HEIGHT, scl_data->v_active); |
654 | |
655 | /* SCL mode */ |
656 | REG_UPDATE(SCL_MODE, DSCL_MODE, dscl_mode); |
657 | |
658 | if (dscl_mode == DSCL_MODE_DSCL_BYPASS) { |
659 | if (dpp_base->ctx->dc->debug.enable_mem_low_power.bits.dscl) |
660 | dpp1_power_on_dscl(dpp_base, power_on: false); |
661 | return; |
662 | } |
663 | |
664 | /* LB */ |
665 | lb_config = dpp1_dscl_find_lb_memory_config(dpp, scl_data); |
666 | dpp1_dscl_set_lb(dpp, lb_params: &scl_data->lb_params, mem_size_config: lb_config); |
667 | |
668 | if (dscl_mode == DSCL_MODE_SCALING_444_BYPASS) |
669 | return; |
670 | |
671 | /* Black offsets */ |
672 | if (REG(SCL_BLACK_OFFSET)) { |
673 | if (ycbcr) |
674 | REG_SET_2(SCL_BLACK_OFFSET, 0, |
675 | SCL_BLACK_OFFSET_RGB_Y, BLACK_OFFSET_RGB_Y, |
676 | SCL_BLACK_OFFSET_CBCR, BLACK_OFFSET_CBCR); |
677 | else |
678 | |
679 | REG_SET_2(SCL_BLACK_OFFSET, 0, |
680 | SCL_BLACK_OFFSET_RGB_Y, BLACK_OFFSET_RGB_Y, |
681 | SCL_BLACK_OFFSET_CBCR, BLACK_OFFSET_RGB_Y); |
682 | } |
683 | |
684 | /* Manually calculate scale ratio and init values */ |
685 | dpp1_dscl_set_manual_ratio_init(dpp, data: scl_data); |
686 | |
687 | /* HTaps/VTaps */ |
688 | REG_SET_4(SCL_TAP_CONTROL, 0, |
689 | SCL_V_NUM_TAPS, scl_data->taps.v_taps - 1, |
690 | SCL_H_NUM_TAPS, scl_data->taps.h_taps - 1, |
691 | SCL_V_NUM_TAPS_C, scl_data->taps.v_taps_c - 1, |
692 | SCL_H_NUM_TAPS_C, scl_data->taps.h_taps_c - 1); |
693 | |
694 | dpp1_dscl_set_scl_filter(dpp, scl_data, chroma_coef_mode: ycbcr); |
695 | PERF_TRACE(); |
696 | } |
697 | |