2 * Copyright 2012-15 Advanced Micro Devices, Inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
26 #include "dce110_transform_v.h"
27 #include "dm_services.h"
29 #include "dce/dce_11_0_d.h"
30 #include "dce/dce_11_0_sh_mask.h"
32 #define SCLV_PHASES 64
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;
47 static void calculate_viewport(
48 const struct scaler_data *scl_data,
49 struct rect *luma_viewport,
50 struct rect *chroma_viewport)
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;
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
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;
77 static void program_viewport(
78 struct dce_transform *xfm_dce,
79 struct rect *luma_view_port,
80 struct rect *chroma_view_port)
82 struct dc_context *ctx = xfm_dce->base.ctx;
86 if (luma_view_port->width != 0 && luma_view_port->height != 0) {
87 addr = mmSCLV_VIEWPORT_START;
99 dm_write_reg(ctx, addr, value);
101 addr = mmSCLV_VIEWPORT_SIZE;
105 luma_view_port->height,
110 luma_view_port->width,
113 dm_write_reg(ctx, addr, value);
116 if (chroma_view_port->width != 0 && chroma_view_port->height != 0) {
117 addr = mmSCLV_VIEWPORT_START_C;
122 SCLV_VIEWPORT_START_C,
127 SCLV_VIEWPORT_START_C,
129 dm_write_reg(ctx, addr, value);
131 addr = mmSCLV_VIEWPORT_SIZE_C;
135 chroma_view_port->height,
136 SCLV_VIEWPORT_SIZE_C,
140 chroma_view_port->width,
141 SCLV_VIEWPORT_SIZE_C,
143 dm_write_reg(ctx, addr, value);
149 * void setup_scaling_configuration
151 * Purpose: setup scaling mode : bypass, RGb, YCbCr and nummber of taps
157 static bool setup_scaling_configuration(
158 struct dce_transform *xfm_dce,
159 const struct scaler_data *data)
161 bool is_scaling_needed = false;
162 struct dc_context *ctx = xfm_dce->base.ctx;
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);
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;
181 set_reg_field_value(value, 0, SCLV_MODE, SCL_MODE);
182 set_reg_field_value(value, 0, SCLV_MODE, SCL_PSCL_EN);
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) {
192 get_reg_field_value(value, SCLV_MODE, SCL_MODE),
197 get_reg_field_value(value, SCLV_MODE, SCL_PSCL_EN),
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);
204 dm_write_reg(ctx, mmSCLV_MODE, value);
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
212 set_reg_field_value(value, 1, SCLV_CONTROL, SCL_BOUNDARY_MODE);
213 dm_write_reg(ctx, mmSCLV_CONTROL, value);
215 return is_scaling_needed;
220 * void program_overscan
222 * Purpose: Programs overscan border
228 static void program_overscan(
229 struct dce_transform *xfm_dce,
230 const struct scaler_data *data)
232 uint32_t overscan_left_right = 0;
233 uint32_t overscan_top_bottom = 0;
235 int overscan_right = data->h_active - data->recout.x - data->recout.width;
236 int overscan_bottom = data->v_active - data->recout.y - data->recout.height;
238 if (xfm_dce->base.ctx->dc->debug.surface_visual_confirm) {
239 overscan_bottom += 2;
243 if (overscan_right < 0) {
247 if (overscan_bottom < 0) {
252 set_reg_field_value(overscan_left_right, data->recout.x,
253 EXT_OVERSCAN_LEFT_RIGHT, EXT_OVERSCAN_LEFT);
255 set_reg_field_value(overscan_left_right, overscan_right,
256 EXT_OVERSCAN_LEFT_RIGHT, EXT_OVERSCAN_RIGHT);
258 set_reg_field_value(overscan_top_bottom, data->recout.y,
259 EXT_OVERSCAN_TOP_BOTTOM, EXT_OVERSCAN_TOP);
261 set_reg_field_value(overscan_top_bottom, overscan_bottom,
262 EXT_OVERSCAN_TOP_BOTTOM, EXT_OVERSCAN_BOTTOM);
264 dm_write_reg(xfm_dce->base.ctx,
265 mmSCLV_EXT_OVERSCAN_LEFT_RIGHT,
266 overscan_left_right);
268 dm_write_reg(xfm_dce->base.ctx,
269 mmSCLV_EXT_OVERSCAN_TOP_BOTTOM,
270 overscan_top_bottom);
273 static void set_coeff_update_complete(
274 struct dce_transform *xfm_dce)
278 value = dm_read_reg(xfm_dce->base.ctx, mmSCLV_UPDATE);
279 set_reg_field_value(value, 1, SCLV_UPDATE, SCL_COEF_UPDATE_COMPLETE);
280 dm_write_reg(xfm_dce->base.ctx, mmSCLV_UPDATE, value);
283 static void program_multi_taps_filter(
284 struct dce_transform *xfm_dce,
286 const uint16_t *coeffs,
287 enum ram_filter_type filter_type)
289 struct dc_context *ctx = xfm_dce->base.ctx;
292 int taps_pairs = (taps + 1) / 2;
293 int phases_to_program = SCLV_PHASES / 2 + 1;
296 uint32_t power_ctl, power_ctl_off;
301 /*We need to disable power gating on coeff memory to do programming*/
302 power_ctl = dm_read_reg(ctx, mmDCFEV_MEM_PWR_CTRL);
303 power_ctl_off = power_ctl;
304 set_reg_field_value(power_ctl_off, 1, DCFEV_MEM_PWR_CTRL, SCLV_COEFF_MEM_PWR_DIS);
305 dm_write_reg(ctx, mmDCFEV_MEM_PWR_CTRL, power_ctl_off);
307 /*Wait to disable gating:*/
308 for (i = 0; i < 10; i++) {
309 if (get_reg_field_value(
310 dm_read_reg(ctx, mmDCFEV_MEM_PWR_STATUS),
311 DCFEV_MEM_PWR_STATUS,
312 SCLV_COEFF_MEM_PWR_STATE) == 0)
318 set_reg_field_value(select, filter_type, SCLV_COEF_RAM_SELECT, SCL_C_RAM_FILTER_TYPE);
320 for (phase = 0; phase < phases_to_program; phase++) {
321 /*we always program N/2 + 1 phases, total phases N, but N/2-1 are just mirror
322 phase 0 is unique and phase N/2 is unique if N is even*/
323 set_reg_field_value(select, phase, SCLV_COEF_RAM_SELECT, SCL_C_RAM_PHASE);
324 for (pair = 0; pair < taps_pairs; pair++) {
327 set_reg_field_value(select, pair,
328 SCLV_COEF_RAM_SELECT, SCL_C_RAM_TAP_PAIR_IDX);
330 dm_write_reg(ctx, mmSCLV_COEF_RAM_SELECT, select);
334 SCLV_COEF_RAM_TAP_DATA,
335 SCL_C_RAM_EVEN_TAP_COEF_EN);
337 data, coeffs[array_idx],
338 SCLV_COEF_RAM_TAP_DATA,
339 SCL_C_RAM_EVEN_TAP_COEF);
341 if (taps % 2 && pair == taps_pairs - 1) {
344 SCLV_COEF_RAM_TAP_DATA,
345 SCL_C_RAM_ODD_TAP_COEF_EN);
350 SCLV_COEF_RAM_TAP_DATA,
351 SCL_C_RAM_ODD_TAP_COEF_EN);
353 data, coeffs[array_idx + 1],
354 SCLV_COEF_RAM_TAP_DATA,
355 SCL_C_RAM_ODD_TAP_COEF);
360 dm_write_reg(ctx, mmSCLV_COEF_RAM_TAP_DATA, data);
364 /*We need to restore power gating on coeff memory to initial state*/
365 dm_write_reg(ctx, mmDCFEV_MEM_PWR_CTRL, power_ctl);
368 static void calculate_inits(
369 struct dce_transform *xfm_dce,
370 const struct scaler_data *data,
371 struct sclv_ratios_inits *inits,
372 struct rect *luma_viewport,
373 struct rect *chroma_viewport)
375 inits->h_int_scale_ratio_luma =
376 dal_fixed31_32_u2d19(data->ratios.horz) << 5;
377 inits->v_int_scale_ratio_luma =
378 dal_fixed31_32_u2d19(data->ratios.vert) << 5;
379 inits->h_int_scale_ratio_chroma =
380 dal_fixed31_32_u2d19(data->ratios.horz_c) << 5;
381 inits->v_int_scale_ratio_chroma =
382 dal_fixed31_32_u2d19(data->ratios.vert_c) << 5;
384 inits->h_init_luma.integer = 1;
385 inits->v_init_luma.integer = 1;
386 inits->h_init_chroma.integer = 1;
387 inits->v_init_chroma.integer = 1;
390 static void program_scl_ratios_inits(
391 struct dce_transform *xfm_dce,
392 struct sclv_ratios_inits *inits)
394 struct dc_context *ctx = xfm_dce->base.ctx;
395 uint32_t addr = mmSCLV_HORZ_FILTER_SCALE_RATIO;
400 inits->h_int_scale_ratio_luma,
401 SCLV_HORZ_FILTER_SCALE_RATIO,
403 dm_write_reg(ctx, addr, value);
405 addr = mmSCLV_VERT_FILTER_SCALE_RATIO;
409 inits->v_int_scale_ratio_luma,
410 SCLV_VERT_FILTER_SCALE_RATIO,
412 dm_write_reg(ctx, addr, value);
414 addr = mmSCLV_HORZ_FILTER_SCALE_RATIO_C;
418 inits->h_int_scale_ratio_chroma,
419 SCLV_HORZ_FILTER_SCALE_RATIO_C,
420 SCL_H_SCALE_RATIO_C);
421 dm_write_reg(ctx, addr, value);
423 addr = mmSCLV_VERT_FILTER_SCALE_RATIO_C;
427 inits->v_int_scale_ratio_chroma,
428 SCLV_VERT_FILTER_SCALE_RATIO_C,
429 SCL_V_SCALE_RATIO_C);
430 dm_write_reg(ctx, addr, value);
432 addr = mmSCLV_HORZ_FILTER_INIT;
436 inits->h_init_luma.fraction,
437 SCLV_HORZ_FILTER_INIT,
441 inits->h_init_luma.integer,
442 SCLV_HORZ_FILTER_INIT,
444 dm_write_reg(ctx, addr, value);
446 addr = mmSCLV_VERT_FILTER_INIT;
450 inits->v_init_luma.fraction,
451 SCLV_VERT_FILTER_INIT,
455 inits->v_init_luma.integer,
456 SCLV_VERT_FILTER_INIT,
458 dm_write_reg(ctx, addr, value);
460 addr = mmSCLV_HORZ_FILTER_INIT_C;
464 inits->h_init_chroma.fraction,
465 SCLV_HORZ_FILTER_INIT_C,
469 inits->h_init_chroma.integer,
470 SCLV_HORZ_FILTER_INIT_C,
472 dm_write_reg(ctx, addr, value);
474 addr = mmSCLV_VERT_FILTER_INIT_C;
478 inits->v_init_chroma.fraction,
479 SCLV_VERT_FILTER_INIT_C,
483 inits->v_init_chroma.integer,
484 SCLV_VERT_FILTER_INIT_C,
486 dm_write_reg(ctx, addr, value);
489 static const uint16_t *get_filter_coeffs_64p(int taps, struct fixed31_32 ratio)
492 return get_filter_4tap_64p(ratio);
494 return get_filter_2tap_64p();
498 /* should never happen, bug */
504 static bool dce110_xfmv_power_up_line_buffer(struct transform *xfm)
506 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
509 value = dm_read_reg(xfm_dce->base.ctx, mmLBV_MEMORY_CTRL);
511 /*Use all three pieces of memory always*/
512 set_reg_field_value(value, 0, LBV_MEMORY_CTRL, LB_MEMORY_CONFIG);
513 /*hard coded number DCE11 1712(0x6B0) Partitions: 720/960/1712*/
514 set_reg_field_value(value, xfm_dce->lb_memory_size, LBV_MEMORY_CTRL,
517 dm_write_reg(xfm_dce->base.ctx, mmLBV_MEMORY_CTRL, value);
522 static void dce110_xfmv_set_scaler(
523 struct transform *xfm,
524 const struct scaler_data *data)
526 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
527 bool is_scaling_required = false;
528 bool filter_updated = false;
529 const uint16_t *coeffs_v, *coeffs_h, *coeffs_h_c, *coeffs_v_c;
530 struct rect luma_viewport = {0};
531 struct rect chroma_viewport = {0};
533 dce110_xfmv_power_up_line_buffer(xfm);
534 /* 1. Calculate viewport, viewport programming should happen after init
535 * calculations as they may require an adjustment in the viewport.
538 calculate_viewport(data, &luma_viewport, &chroma_viewport);
540 /* 2. Program overscan */
541 program_overscan(xfm_dce, data);
543 /* 3. Program taps and configuration */
544 is_scaling_required = setup_scaling_configuration(xfm_dce, data);
546 if (is_scaling_required) {
547 /* 4. Calculate and program ratio, filter initialization */
549 struct sclv_ratios_inits inits = { 0 };
558 program_scl_ratios_inits(xfm_dce, &inits);
560 coeffs_v = get_filter_coeffs_64p(data->taps.v_taps, data->ratios.vert);
561 coeffs_h = get_filter_coeffs_64p(data->taps.h_taps, data->ratios.horz);
562 coeffs_v_c = get_filter_coeffs_64p(data->taps.v_taps_c, data->ratios.vert_c);
563 coeffs_h_c = get_filter_coeffs_64p(data->taps.h_taps_c, data->ratios.horz_c);
565 if (coeffs_v != xfm_dce->filter_v
566 || coeffs_v_c != xfm_dce->filter_v_c
567 || coeffs_h != xfm_dce->filter_h
568 || coeffs_h_c != xfm_dce->filter_h_c) {
569 /* 5. Program vertical filters */
570 program_multi_taps_filter(
574 FILTER_TYPE_RGB_Y_VERTICAL);
575 program_multi_taps_filter(
579 FILTER_TYPE_CBCR_VERTICAL);
581 /* 6. Program horizontal filters */
582 program_multi_taps_filter(
586 FILTER_TYPE_RGB_Y_HORIZONTAL);
587 program_multi_taps_filter(
591 FILTER_TYPE_CBCR_HORIZONTAL);
593 xfm_dce->filter_v = coeffs_v;
594 xfm_dce->filter_v_c = coeffs_v_c;
595 xfm_dce->filter_h = coeffs_h;
596 xfm_dce->filter_h_c = coeffs_h_c;
597 filter_updated = true;
601 /* 7. Program the viewport */
602 program_viewport(xfm_dce, &luma_viewport, &chroma_viewport);
604 /* 8. Set bit to flip to new coefficient memory */
606 set_coeff_update_complete(xfm_dce);
609 static void dce110_xfmv_reset(struct transform *xfm)
611 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
613 xfm_dce->filter_h = NULL;
614 xfm_dce->filter_v = NULL;
615 xfm_dce->filter_h_c = NULL;
616 xfm_dce->filter_v_c = NULL;
619 static void dce110_xfmv_set_gamut_remap(
620 struct transform *xfm,
621 const struct xfm_grph_csc_adjustment *adjust)
626 static void dce110_xfmv_set_pixel_storage_depth(
627 struct transform *xfm,
628 enum lb_pixel_depth depth,
629 const struct bit_depth_reduction_params *bit_depth_params)
631 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
634 uint32_t reg_data = 0;
637 case LB_PIXEL_DEPTH_18BPP:
641 case LB_PIXEL_DEPTH_24BPP:
645 case LB_PIXEL_DEPTH_30BPP:
649 case LB_PIXEL_DEPTH_36BPP:
670 dm_write_reg(xfm->ctx, mmLBV_DATA_FORMAT, reg_data);
672 if (!(xfm_dce->lb_pixel_depth_supported & depth)) {
673 /*we should use unsupported capabilities
674 * unless it is required by w/a*/
675 DC_LOG_WARNING("%s: Capability not supported",
680 static const struct transform_funcs dce110_xfmv_funcs = {
681 .transform_reset = dce110_xfmv_reset,
682 .transform_set_scaler = dce110_xfmv_set_scaler,
683 .transform_set_gamut_remap =
684 dce110_xfmv_set_gamut_remap,
685 .opp_set_csc_default = dce110_opp_v_set_csc_default,
686 .opp_set_csc_adjustment = dce110_opp_v_set_csc_adjustment,
687 .opp_power_on_regamma_lut = dce110_opp_power_on_regamma_lut_v,
688 .opp_program_regamma_pwl = dce110_opp_program_regamma_pwl_v,
689 .opp_set_regamma_mode = dce110_opp_set_regamma_mode_v,
690 .transform_set_pixel_storage_depth =
691 dce110_xfmv_set_pixel_storage_depth,
692 .transform_get_optimal_number_of_taps =
693 dce_transform_get_optimal_number_of_taps
695 /*****************************************/
696 /* Constructor, Destructor */
697 /*****************************************/
699 bool dce110_transform_v_construct(
700 struct dce_transform *xfm_dce,
701 struct dc_context *ctx)
703 xfm_dce->base.ctx = ctx;
705 xfm_dce->base.funcs = &dce110_xfmv_funcs;
707 xfm_dce->lb_pixel_depth_supported =
708 LB_PIXEL_DEPTH_18BPP |
709 LB_PIXEL_DEPTH_24BPP |
710 LB_PIXEL_DEPTH_30BPP;
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*/