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 "dce110_transform_v.h" |
27 | #include "dm_services.h" |
28 | #include "dc.h" |
29 | #include "dce/dce_11_0_d.h" |
30 | #include "dce/dce_11_0_sh_mask.h" |
31 | |
32 | #define SCLV_PHASES 64 |
33 | #define DC_LOGGER \ |
34 | xfm->ctx->logger |
35 | |
36 | struct sclv_ratios_inits { |
37 | uint32_t h_int_scale_ratio_luma; |
38 | uint32_t h_int_scale_ratio_chroma; |
39 | uint32_t v_int_scale_ratio_luma; |
40 | uint32_t v_int_scale_ratio_chroma; |
41 | struct init_int_and_frac h_init_luma; |
42 | struct init_int_and_frac h_init_chroma; |
43 | struct init_int_and_frac v_init_luma; |
44 | struct init_int_and_frac v_init_chroma; |
45 | }; |
46 | |
47 | static void calculate_viewport( |
48 | const struct scaler_data *scl_data, |
49 | struct rect *luma_viewport, |
50 | struct rect *chroma_viewport) |
51 | { |
52 | /*Do not set chroma vp for rgb444 pixel format*/ |
53 | luma_viewport->x = scl_data->viewport.x - scl_data->viewport.x % 2; |
54 | luma_viewport->y = scl_data->viewport.y - scl_data->viewport.y % 2; |
55 | luma_viewport->width = |
56 | scl_data->viewport.width - scl_data->viewport.width % 2; |
57 | luma_viewport->height = |
58 | scl_data->viewport.height - scl_data->viewport.height % 2; |
59 | chroma_viewport->x = luma_viewport->x; |
60 | chroma_viewport->y = luma_viewport->y; |
61 | chroma_viewport->height = luma_viewport->height; |
62 | chroma_viewport->width = luma_viewport->width; |
63 | |
64 | if (scl_data->format == PIXEL_FORMAT_420BPP8) { |
65 | luma_viewport->height += luma_viewport->height % 2; |
66 | luma_viewport->width += luma_viewport->width % 2; |
67 | /*for 420 video chroma is 1/4 the area of luma, scaled |
68 | *vertically and horizontally |
69 | */ |
70 | chroma_viewport->x = luma_viewport->x / 2; |
71 | chroma_viewport->y = luma_viewport->y / 2; |
72 | chroma_viewport->height = luma_viewport->height / 2; |
73 | chroma_viewport->width = luma_viewport->width / 2; |
74 | } |
75 | } |
76 | |
77 | static void program_viewport( |
78 | struct dce_transform *xfm_dce, |
79 | struct rect *luma_view_port, |
80 | struct rect *chroma_view_port) |
81 | { |
82 | struct dc_context *ctx = xfm_dce->base.ctx; |
83 | uint32_t value = 0; |
84 | uint32_t addr = 0; |
85 | |
86 | if (luma_view_port->width != 0 && luma_view_port->height != 0) { |
87 | addr = mmSCLV_VIEWPORT_START; |
88 | value = 0; |
89 | set_reg_field_value( |
90 | value, |
91 | luma_view_port->x, |
92 | SCLV_VIEWPORT_START, |
93 | VIEWPORT_X_START); |
94 | set_reg_field_value( |
95 | value, |
96 | luma_view_port->y, |
97 | SCLV_VIEWPORT_START, |
98 | VIEWPORT_Y_START); |
99 | dm_write_reg(ctx, addr, value); |
100 | |
101 | addr = mmSCLV_VIEWPORT_SIZE; |
102 | value = 0; |
103 | set_reg_field_value( |
104 | value, |
105 | luma_view_port->height, |
106 | SCLV_VIEWPORT_SIZE, |
107 | VIEWPORT_HEIGHT); |
108 | set_reg_field_value( |
109 | value, |
110 | luma_view_port->width, |
111 | SCLV_VIEWPORT_SIZE, |
112 | VIEWPORT_WIDTH); |
113 | dm_write_reg(ctx, addr, value); |
114 | } |
115 | |
116 | if (chroma_view_port->width != 0 && chroma_view_port->height != 0) { |
117 | addr = mmSCLV_VIEWPORT_START_C; |
118 | value = 0; |
119 | set_reg_field_value( |
120 | value, |
121 | chroma_view_port->x, |
122 | SCLV_VIEWPORT_START_C, |
123 | VIEWPORT_X_START_C); |
124 | set_reg_field_value( |
125 | value, |
126 | chroma_view_port->y, |
127 | SCLV_VIEWPORT_START_C, |
128 | VIEWPORT_Y_START_C); |
129 | dm_write_reg(ctx, addr, value); |
130 | |
131 | addr = mmSCLV_VIEWPORT_SIZE_C; |
132 | value = 0; |
133 | set_reg_field_value( |
134 | value, |
135 | chroma_view_port->height, |
136 | SCLV_VIEWPORT_SIZE_C, |
137 | VIEWPORT_HEIGHT_C); |
138 | set_reg_field_value( |
139 | value, |
140 | chroma_view_port->width, |
141 | SCLV_VIEWPORT_SIZE_C, |
142 | VIEWPORT_WIDTH_C); |
143 | dm_write_reg(ctx, addr, value); |
144 | } |
145 | } |
146 | |
147 | /* |
148 | * Function: |
149 | * void setup_scaling_configuration |
150 | * |
151 | * Purpose: setup scaling mode : bypass, RGb, YCbCr and nummber of taps |
152 | * Input: data |
153 | * |
154 | * Output: |
155 | * void |
156 | */ |
157 | static bool setup_scaling_configuration( |
158 | struct dce_transform *xfm_dce, |
159 | const struct scaler_data *data) |
160 | { |
161 | bool is_scaling_needed = false; |
162 | struct dc_context *ctx = xfm_dce->base.ctx; |
163 | uint32_t value = 0; |
164 | |
165 | set_reg_field_value(value, data->taps.h_taps - 1, |
166 | SCLV_TAP_CONTROL, SCL_H_NUM_OF_TAPS); |
167 | set_reg_field_value(value, data->taps.v_taps - 1, |
168 | SCLV_TAP_CONTROL, SCL_V_NUM_OF_TAPS); |
169 | set_reg_field_value(value, data->taps.h_taps_c - 1, |
170 | SCLV_TAP_CONTROL, SCL_H_NUM_OF_TAPS_C); |
171 | set_reg_field_value(value, data->taps.v_taps_c - 1, |
172 | SCLV_TAP_CONTROL, SCL_V_NUM_OF_TAPS_C); |
173 | dm_write_reg(ctx, mmSCLV_TAP_CONTROL, value); |
174 | |
175 | value = 0; |
176 | if (data->taps.h_taps + data->taps.v_taps > 2) { |
177 | set_reg_field_value(value, 1, SCLV_MODE, SCL_MODE); |
178 | set_reg_field_value(value, 1, SCLV_MODE, SCL_PSCL_EN); |
179 | is_scaling_needed = true; |
180 | } else { |
181 | set_reg_field_value(value, 0, SCLV_MODE, SCL_MODE); |
182 | set_reg_field_value(value, 0, SCLV_MODE, SCL_PSCL_EN); |
183 | } |
184 | |
185 | if (data->taps.h_taps_c + data->taps.v_taps_c > 2) { |
186 | set_reg_field_value(value, 1, SCLV_MODE, SCL_MODE_C); |
187 | set_reg_field_value(value, 1, SCLV_MODE, SCL_PSCL_EN_C); |
188 | is_scaling_needed = true; |
189 | } else if (data->format != PIXEL_FORMAT_420BPP8) { |
190 | set_reg_field_value( |
191 | value, |
192 | get_reg_field_value(value, SCLV_MODE, SCL_MODE), |
193 | SCLV_MODE, |
194 | SCL_MODE_C); |
195 | set_reg_field_value( |
196 | value, |
197 | get_reg_field_value(value, SCLV_MODE, SCL_PSCL_EN), |
198 | SCLV_MODE, |
199 | SCL_PSCL_EN_C); |
200 | } else { |
201 | set_reg_field_value(value, 0, SCLV_MODE, SCL_MODE_C); |
202 | set_reg_field_value(value, 0, SCLV_MODE, SCL_PSCL_EN_C); |
203 | } |
204 | dm_write_reg(ctx, mmSCLV_MODE, value); |
205 | |
206 | value = 0; |
207 | /* |
208 | * 0 - Replaced out of bound pixels with black pixel |
209 | * (or any other required color) |
210 | * 1 - Replaced out of bound pixels with the edge pixel |
211 | */ |
212 | set_reg_field_value(value, 1, SCLV_CONTROL, SCL_BOUNDARY_MODE); |
213 | dm_write_reg(ctx, mmSCLV_CONTROL, value); |
214 | |
215 | return is_scaling_needed; |
216 | } |
217 | |
218 | /* |
219 | * Function: |
220 | * void program_overscan |
221 | * |
222 | * Purpose: Programs overscan border |
223 | * Input: overscan |
224 | * |
225 | * Output: void |
226 | */ |
227 | static void program_overscan( |
228 | struct dce_transform *xfm_dce, |
229 | const struct scaler_data *data) |
230 | { |
231 | uint32_t overscan_left_right = 0; |
232 | uint32_t overscan_top_bottom = 0; |
233 | |
234 | int overscan_right = data->h_active - data->recout.x - data->recout.width; |
235 | int overscan_bottom = data->v_active - data->recout.y - data->recout.height; |
236 | |
237 | if (xfm_dce->base.ctx->dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE) { |
238 | overscan_bottom += 2; |
239 | overscan_right += 2; |
240 | } |
241 | |
242 | if (overscan_right < 0) { |
243 | BREAK_TO_DEBUGGER(); |
244 | overscan_right = 0; |
245 | } |
246 | if (overscan_bottom < 0) { |
247 | BREAK_TO_DEBUGGER(); |
248 | overscan_bottom = 0; |
249 | } |
250 | |
251 | set_reg_field_value(overscan_left_right, data->recout.x, |
252 | EXT_OVERSCAN_LEFT_RIGHT, EXT_OVERSCAN_LEFT); |
253 | |
254 | set_reg_field_value(overscan_left_right, overscan_right, |
255 | EXT_OVERSCAN_LEFT_RIGHT, EXT_OVERSCAN_RIGHT); |
256 | |
257 | set_reg_field_value(overscan_top_bottom, data->recout.y, |
258 | EXT_OVERSCAN_TOP_BOTTOM, EXT_OVERSCAN_TOP); |
259 | |
260 | set_reg_field_value(overscan_top_bottom, overscan_bottom, |
261 | EXT_OVERSCAN_TOP_BOTTOM, EXT_OVERSCAN_BOTTOM); |
262 | |
263 | dm_write_reg(xfm_dce->base.ctx, |
264 | mmSCLV_EXT_OVERSCAN_LEFT_RIGHT, |
265 | overscan_left_right); |
266 | |
267 | dm_write_reg(xfm_dce->base.ctx, |
268 | mmSCLV_EXT_OVERSCAN_TOP_BOTTOM, |
269 | overscan_top_bottom); |
270 | } |
271 | |
272 | static void set_coeff_update_complete( |
273 | struct dce_transform *xfm_dce) |
274 | { |
275 | uint32_t value; |
276 | |
277 | value = dm_read_reg(xfm_dce->base.ctx, mmSCLV_UPDATE); |
278 | set_reg_field_value(value, 1, SCLV_UPDATE, SCL_COEF_UPDATE_COMPLETE); |
279 | dm_write_reg(xfm_dce->base.ctx, mmSCLV_UPDATE, value); |
280 | } |
281 | |
282 | static void program_multi_taps_filter( |
283 | struct dce_transform *xfm_dce, |
284 | int taps, |
285 | const uint16_t *coeffs, |
286 | enum ram_filter_type filter_type) |
287 | { |
288 | struct dc_context *ctx = xfm_dce->base.ctx; |
289 | int i, phase, pair; |
290 | int array_idx = 0; |
291 | int taps_pairs = (taps + 1) / 2; |
292 | int phases_to_program = SCLV_PHASES / 2 + 1; |
293 | |
294 | uint32_t select = 0; |
295 | uint32_t power_ctl, power_ctl_off; |
296 | |
297 | if (!coeffs) |
298 | return; |
299 | |
300 | /*We need to disable power gating on coeff memory to do programming*/ |
301 | power_ctl = dm_read_reg(ctx, mmDCFEV_MEM_PWR_CTRL); |
302 | power_ctl_off = power_ctl; |
303 | set_reg_field_value(power_ctl_off, 1, DCFEV_MEM_PWR_CTRL, SCLV_COEFF_MEM_PWR_DIS); |
304 | dm_write_reg(ctx, mmDCFEV_MEM_PWR_CTRL, power_ctl_off); |
305 | |
306 | /*Wait to disable gating:*/ |
307 | for (i = 0; i < 10; i++) { |
308 | if (get_reg_field_value( |
309 | dm_read_reg(ctx, mmDCFEV_MEM_PWR_STATUS), |
310 | DCFEV_MEM_PWR_STATUS, |
311 | SCLV_COEFF_MEM_PWR_STATE) == 0) |
312 | break; |
313 | |
314 | udelay(1); |
315 | } |
316 | |
317 | set_reg_field_value(select, filter_type, SCLV_COEF_RAM_SELECT, SCL_C_RAM_FILTER_TYPE); |
318 | |
319 | for (phase = 0; phase < phases_to_program; phase++) { |
320 | /*we always program N/2 + 1 phases, total phases N, but N/2-1 are just mirror |
321 | phase 0 is unique and phase N/2 is unique if N is even*/ |
322 | set_reg_field_value(select, phase, SCLV_COEF_RAM_SELECT, SCL_C_RAM_PHASE); |
323 | for (pair = 0; pair < taps_pairs; pair++) { |
324 | uint32_t data = 0; |
325 | |
326 | set_reg_field_value(select, pair, |
327 | SCLV_COEF_RAM_SELECT, SCL_C_RAM_TAP_PAIR_IDX); |
328 | |
329 | dm_write_reg(ctx, mmSCLV_COEF_RAM_SELECT, select); |
330 | |
331 | set_reg_field_value( |
332 | data, 1, |
333 | SCLV_COEF_RAM_TAP_DATA, |
334 | SCL_C_RAM_EVEN_TAP_COEF_EN); |
335 | set_reg_field_value( |
336 | data, coeffs[array_idx], |
337 | SCLV_COEF_RAM_TAP_DATA, |
338 | SCL_C_RAM_EVEN_TAP_COEF); |
339 | |
340 | if (taps % 2 && pair == taps_pairs - 1) { |
341 | set_reg_field_value( |
342 | data, 0, |
343 | SCLV_COEF_RAM_TAP_DATA, |
344 | SCL_C_RAM_ODD_TAP_COEF_EN); |
345 | array_idx++; |
346 | } else { |
347 | set_reg_field_value( |
348 | data, 1, |
349 | SCLV_COEF_RAM_TAP_DATA, |
350 | SCL_C_RAM_ODD_TAP_COEF_EN); |
351 | set_reg_field_value( |
352 | data, coeffs[array_idx + 1], |
353 | SCLV_COEF_RAM_TAP_DATA, |
354 | SCL_C_RAM_ODD_TAP_COEF); |
355 | |
356 | array_idx += 2; |
357 | } |
358 | |
359 | dm_write_reg(ctx, mmSCLV_COEF_RAM_TAP_DATA, data); |
360 | } |
361 | } |
362 | |
363 | /*We need to restore power gating on coeff memory to initial state*/ |
364 | dm_write_reg(ctx, mmDCFEV_MEM_PWR_CTRL, power_ctl); |
365 | } |
366 | |
367 | static void calculate_inits( |
368 | struct dce_transform *xfm_dce, |
369 | const struct scaler_data *data, |
370 | struct sclv_ratios_inits *inits, |
371 | struct rect *luma_viewport, |
372 | struct rect *chroma_viewport) |
373 | { |
374 | inits->h_int_scale_ratio_luma = |
375 | dc_fixpt_u2d19(arg: data->ratios.horz) << 5; |
376 | inits->v_int_scale_ratio_luma = |
377 | dc_fixpt_u2d19(arg: data->ratios.vert) << 5; |
378 | inits->h_int_scale_ratio_chroma = |
379 | dc_fixpt_u2d19(arg: data->ratios.horz_c) << 5; |
380 | inits->v_int_scale_ratio_chroma = |
381 | dc_fixpt_u2d19(arg: data->ratios.vert_c) << 5; |
382 | |
383 | inits->h_init_luma.integer = 1; |
384 | inits->v_init_luma.integer = 1; |
385 | inits->h_init_chroma.integer = 1; |
386 | inits->v_init_chroma.integer = 1; |
387 | } |
388 | |
389 | static void program_scl_ratios_inits( |
390 | struct dce_transform *xfm_dce, |
391 | struct sclv_ratios_inits *inits) |
392 | { |
393 | struct dc_context *ctx = xfm_dce->base.ctx; |
394 | uint32_t addr = mmSCLV_HORZ_FILTER_SCALE_RATIO; |
395 | uint32_t value = 0; |
396 | |
397 | set_reg_field_value( |
398 | value, |
399 | inits->h_int_scale_ratio_luma, |
400 | SCLV_HORZ_FILTER_SCALE_RATIO, |
401 | SCL_H_SCALE_RATIO); |
402 | dm_write_reg(ctx, addr, value); |
403 | |
404 | addr = mmSCLV_VERT_FILTER_SCALE_RATIO; |
405 | value = 0; |
406 | set_reg_field_value( |
407 | value, |
408 | inits->v_int_scale_ratio_luma, |
409 | SCLV_VERT_FILTER_SCALE_RATIO, |
410 | SCL_V_SCALE_RATIO); |
411 | dm_write_reg(ctx, addr, value); |
412 | |
413 | addr = mmSCLV_HORZ_FILTER_SCALE_RATIO_C; |
414 | value = 0; |
415 | set_reg_field_value( |
416 | value, |
417 | inits->h_int_scale_ratio_chroma, |
418 | SCLV_HORZ_FILTER_SCALE_RATIO_C, |
419 | SCL_H_SCALE_RATIO_C); |
420 | dm_write_reg(ctx, addr, value); |
421 | |
422 | addr = mmSCLV_VERT_FILTER_SCALE_RATIO_C; |
423 | value = 0; |
424 | set_reg_field_value( |
425 | value, |
426 | inits->v_int_scale_ratio_chroma, |
427 | SCLV_VERT_FILTER_SCALE_RATIO_C, |
428 | SCL_V_SCALE_RATIO_C); |
429 | dm_write_reg(ctx, addr, value); |
430 | |
431 | addr = mmSCLV_HORZ_FILTER_INIT; |
432 | value = 0; |
433 | set_reg_field_value( |
434 | value, |
435 | inits->h_init_luma.fraction, |
436 | SCLV_HORZ_FILTER_INIT, |
437 | SCL_H_INIT_FRAC); |
438 | set_reg_field_value( |
439 | value, |
440 | inits->h_init_luma.integer, |
441 | SCLV_HORZ_FILTER_INIT, |
442 | SCL_H_INIT_INT); |
443 | dm_write_reg(ctx, addr, value); |
444 | |
445 | addr = mmSCLV_VERT_FILTER_INIT; |
446 | value = 0; |
447 | set_reg_field_value( |
448 | value, |
449 | inits->v_init_luma.fraction, |
450 | SCLV_VERT_FILTER_INIT, |
451 | SCL_V_INIT_FRAC); |
452 | set_reg_field_value( |
453 | value, |
454 | inits->v_init_luma.integer, |
455 | SCLV_VERT_FILTER_INIT, |
456 | SCL_V_INIT_INT); |
457 | dm_write_reg(ctx, addr, value); |
458 | |
459 | addr = mmSCLV_HORZ_FILTER_INIT_C; |
460 | value = 0; |
461 | set_reg_field_value( |
462 | value, |
463 | inits->h_init_chroma.fraction, |
464 | SCLV_HORZ_FILTER_INIT_C, |
465 | SCL_H_INIT_FRAC_C); |
466 | set_reg_field_value( |
467 | value, |
468 | inits->h_init_chroma.integer, |
469 | SCLV_HORZ_FILTER_INIT_C, |
470 | SCL_H_INIT_INT_C); |
471 | dm_write_reg(ctx, addr, value); |
472 | |
473 | addr = mmSCLV_VERT_FILTER_INIT_C; |
474 | value = 0; |
475 | set_reg_field_value( |
476 | value, |
477 | inits->v_init_chroma.fraction, |
478 | SCLV_VERT_FILTER_INIT_C, |
479 | SCL_V_INIT_FRAC_C); |
480 | set_reg_field_value( |
481 | value, |
482 | inits->v_init_chroma.integer, |
483 | SCLV_VERT_FILTER_INIT_C, |
484 | SCL_V_INIT_INT_C); |
485 | dm_write_reg(ctx, addr, value); |
486 | } |
487 | |
488 | static const uint16_t *get_filter_coeffs_64p(int taps, struct fixed31_32 ratio) |
489 | { |
490 | if (taps == 4) |
491 | return get_filter_4tap_64p(ratio); |
492 | else if (taps == 2) |
493 | return get_filter_2tap_64p(); |
494 | else if (taps == 1) |
495 | return NULL; |
496 | else { |
497 | /* should never happen, bug */ |
498 | BREAK_TO_DEBUGGER(); |
499 | return NULL; |
500 | } |
501 | } |
502 | |
503 | static bool dce110_xfmv_power_up_line_buffer(struct transform *xfm) |
504 | { |
505 | struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm); |
506 | uint32_t value; |
507 | |
508 | value = dm_read_reg(xfm_dce->base.ctx, mmLBV_MEMORY_CTRL); |
509 | |
510 | /*Use all three pieces of memory always*/ |
511 | set_reg_field_value(value, 0, LBV_MEMORY_CTRL, LB_MEMORY_CONFIG); |
512 | /*hard coded number DCE11 1712(0x6B0) Partitions: 720/960/1712*/ |
513 | set_reg_field_value(value, xfm_dce->lb_memory_size, LBV_MEMORY_CTRL, |
514 | LB_MEMORY_SIZE); |
515 | |
516 | dm_write_reg(xfm_dce->base.ctx, mmLBV_MEMORY_CTRL, value); |
517 | |
518 | return true; |
519 | } |
520 | |
521 | static void dce110_xfmv_set_scaler( |
522 | struct transform *xfm, |
523 | const struct scaler_data *data) |
524 | { |
525 | struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm); |
526 | bool is_scaling_required = false; |
527 | bool filter_updated = false; |
528 | const uint16_t *coeffs_v, *coeffs_h, *coeffs_h_c, *coeffs_v_c; |
529 | struct rect luma_viewport = {0}; |
530 | struct rect chroma_viewport = {0}; |
531 | |
532 | dce110_xfmv_power_up_line_buffer(xfm); |
533 | /* 1. Calculate viewport, viewport programming should happen after init |
534 | * calculations as they may require an adjustment in the viewport. |
535 | */ |
536 | |
537 | calculate_viewport(scl_data: data, luma_viewport: &luma_viewport, chroma_viewport: &chroma_viewport); |
538 | |
539 | /* 2. Program overscan */ |
540 | program_overscan(xfm_dce, data); |
541 | |
542 | /* 3. Program taps and configuration */ |
543 | is_scaling_required = setup_scaling_configuration(xfm_dce, data); |
544 | |
545 | if (is_scaling_required) { |
546 | /* 4. Calculate and program ratio, filter initialization */ |
547 | |
548 | struct sclv_ratios_inits inits = { 0 }; |
549 | |
550 | calculate_inits( |
551 | xfm_dce, |
552 | data, |
553 | inits: &inits, |
554 | luma_viewport: &luma_viewport, |
555 | chroma_viewport: &chroma_viewport); |
556 | |
557 | program_scl_ratios_inits(xfm_dce, inits: &inits); |
558 | |
559 | coeffs_v = get_filter_coeffs_64p(taps: data->taps.v_taps, ratio: data->ratios.vert); |
560 | coeffs_h = get_filter_coeffs_64p(taps: data->taps.h_taps, ratio: data->ratios.horz); |
561 | coeffs_v_c = get_filter_coeffs_64p(taps: data->taps.v_taps_c, ratio: data->ratios.vert_c); |
562 | coeffs_h_c = get_filter_coeffs_64p(taps: data->taps.h_taps_c, ratio: data->ratios.horz_c); |
563 | |
564 | if (coeffs_v != xfm_dce->filter_v |
565 | || coeffs_v_c != xfm_dce->filter_v_c |
566 | || coeffs_h != xfm_dce->filter_h |
567 | || coeffs_h_c != xfm_dce->filter_h_c) { |
568 | /* 5. Program vertical filters */ |
569 | program_multi_taps_filter( |
570 | xfm_dce, |
571 | taps: data->taps.v_taps, |
572 | coeffs: coeffs_v, |
573 | filter_type: FILTER_TYPE_RGB_Y_VERTICAL); |
574 | program_multi_taps_filter( |
575 | xfm_dce, |
576 | taps: data->taps.v_taps_c, |
577 | coeffs: coeffs_v_c, |
578 | filter_type: FILTER_TYPE_CBCR_VERTICAL); |
579 | |
580 | /* 6. Program horizontal filters */ |
581 | program_multi_taps_filter( |
582 | xfm_dce, |
583 | taps: data->taps.h_taps, |
584 | coeffs: coeffs_h, |
585 | filter_type: FILTER_TYPE_RGB_Y_HORIZONTAL); |
586 | program_multi_taps_filter( |
587 | xfm_dce, |
588 | taps: data->taps.h_taps_c, |
589 | coeffs: coeffs_h_c, |
590 | filter_type: FILTER_TYPE_CBCR_HORIZONTAL); |
591 | |
592 | xfm_dce->filter_v = coeffs_v; |
593 | xfm_dce->filter_v_c = coeffs_v_c; |
594 | xfm_dce->filter_h = coeffs_h; |
595 | xfm_dce->filter_h_c = coeffs_h_c; |
596 | filter_updated = true; |
597 | } |
598 | } |
599 | |
600 | /* 7. Program the viewport */ |
601 | program_viewport(xfm_dce, luma_view_port: &luma_viewport, chroma_view_port: &chroma_viewport); |
602 | |
603 | /* 8. Set bit to flip to new coefficient memory */ |
604 | if (filter_updated) |
605 | set_coeff_update_complete(xfm_dce); |
606 | } |
607 | |
608 | static void dce110_xfmv_reset(struct transform *xfm) |
609 | { |
610 | struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm); |
611 | |
612 | xfm_dce->filter_h = NULL; |
613 | xfm_dce->filter_v = NULL; |
614 | xfm_dce->filter_h_c = NULL; |
615 | xfm_dce->filter_v_c = NULL; |
616 | } |
617 | |
618 | static void dce110_xfmv_set_gamut_remap( |
619 | struct transform *xfm, |
620 | const struct xfm_grph_csc_adjustment *adjust) |
621 | { |
622 | /* DO NOTHING*/ |
623 | } |
624 | |
625 | static void dce110_xfmv_set_pixel_storage_depth( |
626 | struct transform *xfm, |
627 | enum lb_pixel_depth depth, |
628 | const struct bit_depth_reduction_params *bit_depth_params) |
629 | { |
630 | struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm); |
631 | int pixel_depth = 0; |
632 | int expan_mode = 0; |
633 | uint32_t reg_data = 0; |
634 | |
635 | switch (depth) { |
636 | case LB_PIXEL_DEPTH_18BPP: |
637 | pixel_depth = 2; |
638 | expan_mode = 1; |
639 | break; |
640 | case LB_PIXEL_DEPTH_24BPP: |
641 | pixel_depth = 1; |
642 | expan_mode = 1; |
643 | break; |
644 | case LB_PIXEL_DEPTH_30BPP: |
645 | pixel_depth = 0; |
646 | expan_mode = 1; |
647 | break; |
648 | case LB_PIXEL_DEPTH_36BPP: |
649 | pixel_depth = 3; |
650 | expan_mode = 0; |
651 | break; |
652 | default: |
653 | BREAK_TO_DEBUGGER(); |
654 | break; |
655 | } |
656 | |
657 | set_reg_field_value( |
658 | reg_data, |
659 | expan_mode, |
660 | LBV_DATA_FORMAT, |
661 | PIXEL_EXPAN_MODE); |
662 | |
663 | set_reg_field_value( |
664 | reg_data, |
665 | pixel_depth, |
666 | LBV_DATA_FORMAT, |
667 | PIXEL_DEPTH); |
668 | |
669 | dm_write_reg(xfm->ctx, mmLBV_DATA_FORMAT, reg_data); |
670 | |
671 | if (!(xfm_dce->lb_pixel_depth_supported & depth)) { |
672 | /*we should use unsupported capabilities |
673 | * unless it is required by w/a*/ |
674 | DC_LOG_WARNING("%s: Capability not supported" , |
675 | __func__); |
676 | } |
677 | } |
678 | |
679 | static const struct transform_funcs dce110_xfmv_funcs = { |
680 | .transform_reset = dce110_xfmv_reset, |
681 | .transform_set_scaler = dce110_xfmv_set_scaler, |
682 | .transform_set_gamut_remap = |
683 | dce110_xfmv_set_gamut_remap, |
684 | .opp_set_csc_default = dce110_opp_v_set_csc_default, |
685 | .opp_set_csc_adjustment = dce110_opp_v_set_csc_adjustment, |
686 | .opp_power_on_regamma_lut = dce110_opp_power_on_regamma_lut_v, |
687 | .opp_program_regamma_pwl = dce110_opp_program_regamma_pwl_v, |
688 | .opp_set_regamma_mode = dce110_opp_set_regamma_mode_v, |
689 | .transform_set_pixel_storage_depth = |
690 | dce110_xfmv_set_pixel_storage_depth, |
691 | .transform_get_optimal_number_of_taps = |
692 | dce_transform_get_optimal_number_of_taps |
693 | }; |
694 | /*****************************************/ |
695 | /* Constructor, Destructor */ |
696 | /*****************************************/ |
697 | |
698 | bool dce110_transform_v_construct( |
699 | struct dce_transform *xfm_dce, |
700 | struct dc_context *ctx) |
701 | { |
702 | xfm_dce->base.ctx = ctx; |
703 | |
704 | xfm_dce->base.funcs = &dce110_xfmv_funcs; |
705 | |
706 | xfm_dce->lb_pixel_depth_supported = |
707 | LB_PIXEL_DEPTH_18BPP | |
708 | LB_PIXEL_DEPTH_24BPP | |
709 | LB_PIXEL_DEPTH_30BPP | |
710 | LB_PIXEL_DEPTH_36BPP; |
711 | |
712 | xfm_dce->prescaler_on = true; |
713 | xfm_dce->lb_bits_per_entry = LB_BITS_PER_ENTRY; |
714 | xfm_dce->lb_memory_size = LB_TOTAL_NUMBER_OF_ENTRIES; /*0x6B0*/ |
715 | |
716 | return true; |
717 | } |
718 | |