Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2016 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: AMD
0023  *
0024  */
0025 
0026 #include "dm_services.h"
0027 
0028 #include "core_types.h"
0029 
0030 #include "reg_helper.h"
0031 #include "dcn10_dpp.h"
0032 #include "basics/conversion.h"
0033 
0034 
0035 #define NUM_PHASES    64
0036 #define HORZ_MAX_TAPS 8
0037 #define VERT_MAX_TAPS 8
0038 
0039 #define BLACK_OFFSET_RGB_Y 0x0
0040 #define BLACK_OFFSET_CBCR  0x8000
0041 
0042 #define VISUAL_CONFIRM_RECT_HEIGHT_DEFAULT 3
0043 #define VISUAL_CONFIRM_RECT_HEIGHT_MIN 1
0044 #define VISUAL_CONFIRM_RECT_HEIGHT_MAX 10
0045 
0046 #define REG(reg)\
0047     dpp->tf_regs->reg
0048 
0049 #define CTX \
0050     dpp->base.ctx
0051 
0052 #undef FN
0053 #define FN(reg_name, field_name) \
0054     dpp->tf_shift->field_name, dpp->tf_mask->field_name
0055 
0056 enum dcn10_coef_filter_type_sel {
0057     SCL_COEF_LUMA_VERT_FILTER = 0,
0058     SCL_COEF_LUMA_HORZ_FILTER = 1,
0059     SCL_COEF_CHROMA_VERT_FILTER = 2,
0060     SCL_COEF_CHROMA_HORZ_FILTER = 3,
0061     SCL_COEF_ALPHA_VERT_FILTER = 4,
0062     SCL_COEF_ALPHA_HORZ_FILTER = 5
0063 };
0064 
0065 enum dscl_autocal_mode {
0066     AUTOCAL_MODE_OFF = 0,
0067 
0068     /* Autocal calculate the scaling ratio and initial phase and the
0069      * DSCL_MODE_SEL must be set to 1
0070      */
0071     AUTOCAL_MODE_AUTOSCALE = 1,
0072     /* Autocal perform auto centering without replication and the
0073      * DSCL_MODE_SEL must be set to 0
0074      */
0075     AUTOCAL_MODE_AUTOCENTER = 2,
0076     /* Autocal perform auto centering and auto replication and the
0077      * DSCL_MODE_SEL must be set to 0
0078      */
0079     AUTOCAL_MODE_AUTOREPLICATE = 3
0080 };
0081 
0082 enum dscl_mode_sel {
0083     DSCL_MODE_SCALING_444_BYPASS = 0,
0084     DSCL_MODE_SCALING_444_RGB_ENABLE = 1,
0085     DSCL_MODE_SCALING_444_YCBCR_ENABLE = 2,
0086     DSCL_MODE_SCALING_420_YCBCR_ENABLE = 3,
0087     DSCL_MODE_SCALING_420_LUMA_BYPASS = 4,
0088     DSCL_MODE_SCALING_420_CHROMA_BYPASS = 5,
0089     DSCL_MODE_DSCL_BYPASS = 6
0090 };
0091 
0092 static int dpp1_dscl_get_pixel_depth_val(enum lb_pixel_depth depth)
0093 {
0094     if (depth == LB_PIXEL_DEPTH_30BPP)
0095         return 0; /* 10 bpc */
0096     else if (depth == LB_PIXEL_DEPTH_24BPP)
0097         return 1; /* 8 bpc */
0098     else if (depth == LB_PIXEL_DEPTH_18BPP)
0099         return 2; /* 6 bpc */
0100     else if (depth == LB_PIXEL_DEPTH_36BPP)
0101         return 3; /* 12 bpc */
0102     else {
0103         ASSERT(0);
0104         return -1; /* Unsupported */
0105     }
0106 }
0107 
0108 static bool dpp1_dscl_is_video_format(enum pixel_format format)
0109 {
0110     if (format >= PIXEL_FORMAT_VIDEO_BEGIN
0111             && format <= PIXEL_FORMAT_VIDEO_END)
0112         return true;
0113     else
0114         return false;
0115 }
0116 
0117 static bool dpp1_dscl_is_420_format(enum pixel_format format)
0118 {
0119     if (format == PIXEL_FORMAT_420BPP8 ||
0120             format == PIXEL_FORMAT_420BPP10)
0121         return true;
0122     else
0123         return false;
0124 }
0125 
0126 static enum dscl_mode_sel dpp1_dscl_get_dscl_mode(
0127         struct dpp *dpp_base,
0128         const struct scaler_data *data,
0129         bool dbg_always_scale)
0130 {
0131     const long long one = dc_fixpt_one.value;
0132 
0133     if (dpp_base->caps->dscl_data_proc_format == DSCL_DATA_PRCESSING_FIXED_FORMAT) {
0134         /* DSCL is processing data in fixed format */
0135         if (data->format == PIXEL_FORMAT_FP16)
0136             return DSCL_MODE_DSCL_BYPASS;
0137     }
0138 
0139     if (data->ratios.horz.value == one
0140             && data->ratios.vert.value == one
0141             && data->ratios.horz_c.value == one
0142             && data->ratios.vert_c.value == one
0143             && !dbg_always_scale)
0144         return DSCL_MODE_SCALING_444_BYPASS;
0145 
0146     if (!dpp1_dscl_is_420_format(data->format)) {
0147         if (dpp1_dscl_is_video_format(data->format))
0148             return DSCL_MODE_SCALING_444_YCBCR_ENABLE;
0149         else
0150             return DSCL_MODE_SCALING_444_RGB_ENABLE;
0151     }
0152     if (data->ratios.horz.value == one && data->ratios.vert.value == one)
0153         return DSCL_MODE_SCALING_420_LUMA_BYPASS;
0154     if (data->ratios.horz_c.value == one && data->ratios.vert_c.value == one)
0155         return DSCL_MODE_SCALING_420_CHROMA_BYPASS;
0156 
0157     return DSCL_MODE_SCALING_420_YCBCR_ENABLE;
0158 }
0159 
0160 static void dpp1_power_on_dscl(
0161     struct dpp *dpp_base,
0162     bool power_on)
0163 {
0164     struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
0165 
0166     if (dpp->tf_regs->DSCL_MEM_PWR_CTRL) {
0167         if (power_on) {
0168             REG_UPDATE(DSCL_MEM_PWR_CTRL, LUT_MEM_PWR_FORCE, 0);
0169             REG_WAIT(DSCL_MEM_PWR_STATUS, LUT_MEM_PWR_STATE, 0, 1, 5);
0170         } else {
0171             if (dpp->base.ctx->dc->debug.enable_mem_low_power.bits.dscl) {
0172                 dpp->base.ctx->dc->optimized_required = true;
0173                 dpp->base.deferred_reg_writes.bits.disable_dscl = true;
0174             } else {
0175                 REG_UPDATE(DSCL_MEM_PWR_CTRL, LUT_MEM_PWR_FORCE, 3);
0176             }
0177         }
0178     }
0179 }
0180 
0181 
0182 static void dpp1_dscl_set_lb(
0183     struct dcn10_dpp *dpp,
0184     const struct line_buffer_params *lb_params,
0185     enum lb_memory_config mem_size_config)
0186 {
0187     uint32_t max_partitions = 63; /* Currently hardcoded on all ASICs before DCN 3.2 */
0188 
0189     /* LB */
0190     if (dpp->base.caps->dscl_data_proc_format == DSCL_DATA_PRCESSING_FIXED_FORMAT) {
0191         /* DSCL caps: pixel data processed in fixed format */
0192         uint32_t pixel_depth = dpp1_dscl_get_pixel_depth_val(lb_params->depth);
0193         uint32_t dyn_pix_depth = lb_params->dynamic_pixel_depth;
0194 
0195         REG_SET_7(LB_DATA_FORMAT, 0,
0196             PIXEL_DEPTH, pixel_depth, /* Pixel depth stored in LB */
0197             PIXEL_EXPAN_MODE, lb_params->pixel_expan_mode, /* Pixel expansion mode */
0198             PIXEL_REDUCE_MODE, 1, /* Pixel reduction mode: Rounding */
0199             DYNAMIC_PIXEL_DEPTH, dyn_pix_depth, /* Dynamic expansion pixel depth */
0200             DITHER_EN, 0, /* Dithering enable: Disabled */
0201             INTERLEAVE_EN, lb_params->interleave_en, /* Interleave source enable */
0202             LB_DATA_FORMAT__ALPHA_EN, lb_params->alpha_en); /* Alpha enable */
0203     }
0204     else {
0205         /* DSCL caps: pixel data processed in float format */
0206         REG_SET_2(LB_DATA_FORMAT, 0,
0207             INTERLEAVE_EN, lb_params->interleave_en, /* Interleave source enable */
0208             LB_DATA_FORMAT__ALPHA_EN, lb_params->alpha_en); /* Alpha enable */
0209     }
0210 
0211     if (dpp->base.caps->max_lb_partitions == 31)
0212         max_partitions = 31;
0213 
0214     REG_SET_2(LB_MEMORY_CTRL, 0,
0215         MEMORY_CONFIG, mem_size_config,
0216         LB_MAX_PARTITIONS, max_partitions);
0217 }
0218 
0219 static const uint16_t *dpp1_dscl_get_filter_coeffs_64p(int taps, struct fixed31_32 ratio)
0220 {
0221     if (taps == 8)
0222         return get_filter_8tap_64p(ratio);
0223     else if (taps == 7)
0224         return get_filter_7tap_64p(ratio);
0225     else if (taps == 6)
0226         return get_filter_6tap_64p(ratio);
0227     else if (taps == 5)
0228         return get_filter_5tap_64p(ratio);
0229     else if (taps == 4)
0230         return get_filter_4tap_64p(ratio);
0231     else if (taps == 3)
0232         return get_filter_3tap_64p(ratio);
0233     else if (taps == 2)
0234         return get_filter_2tap_64p();
0235     else if (taps == 1)
0236         return NULL;
0237     else {
0238         /* should never happen, bug */
0239         BREAK_TO_DEBUGGER();
0240         return NULL;
0241     }
0242 }
0243 
0244 static void dpp1_dscl_set_scaler_filter(
0245         struct dcn10_dpp *dpp,
0246         uint32_t taps,
0247         enum dcn10_coef_filter_type_sel filter_type,
0248         const uint16_t *filter)
0249 {
0250     const int tap_pairs = (taps + 1) / 2;
0251     int phase;
0252     int pair;
0253     uint16_t odd_coef, even_coef;
0254 
0255     REG_SET_3(SCL_COEF_RAM_TAP_SELECT, 0,
0256         SCL_COEF_RAM_TAP_PAIR_IDX, 0,
0257         SCL_COEF_RAM_PHASE, 0,
0258         SCL_COEF_RAM_FILTER_TYPE, filter_type);
0259 
0260     for (phase = 0; phase < (NUM_PHASES / 2 + 1); phase++) {
0261         for (pair = 0; pair < tap_pairs; pair++) {
0262             even_coef = filter[phase * taps + 2 * pair];
0263             if ((pair * 2 + 1) < taps)
0264                 odd_coef = filter[phase * taps + 2 * pair + 1];
0265             else
0266                 odd_coef = 0;
0267 
0268             REG_SET_4(SCL_COEF_RAM_TAP_DATA, 0,
0269                 /* Even tap coefficient (bits 1:0 fixed to 0) */
0270                 SCL_COEF_RAM_EVEN_TAP_COEF, even_coef,
0271                 /* Write/read control for even coefficient */
0272                 SCL_COEF_RAM_EVEN_TAP_COEF_EN, 1,
0273                 /* Odd tap coefficient (bits 1:0 fixed to 0) */
0274                 SCL_COEF_RAM_ODD_TAP_COEF, odd_coef,
0275                 /* Write/read control for odd coefficient */
0276                 SCL_COEF_RAM_ODD_TAP_COEF_EN, 1);
0277         }
0278     }
0279 
0280 }
0281 
0282 static void dpp1_dscl_set_scl_filter(
0283         struct dcn10_dpp *dpp,
0284         const struct scaler_data *scl_data,
0285         bool chroma_coef_mode)
0286 {
0287     bool h_2tap_hardcode_coef_en = false;
0288     bool v_2tap_hardcode_coef_en = false;
0289     bool h_2tap_sharp_en = false;
0290     bool v_2tap_sharp_en = false;
0291     uint32_t h_2tap_sharp_factor = scl_data->sharpness.horz;
0292     uint32_t v_2tap_sharp_factor = scl_data->sharpness.vert;
0293     bool coef_ram_current;
0294     const uint16_t *filter_h = NULL;
0295     const uint16_t *filter_v = NULL;
0296     const uint16_t *filter_h_c = NULL;
0297     const uint16_t *filter_v_c = NULL;
0298 
0299     h_2tap_hardcode_coef_en = scl_data->taps.h_taps < 3
0300                     && scl_data->taps.h_taps_c < 3
0301         && (scl_data->taps.h_taps > 1 && scl_data->taps.h_taps_c > 1);
0302     v_2tap_hardcode_coef_en = scl_data->taps.v_taps < 3
0303                     && scl_data->taps.v_taps_c < 3
0304         && (scl_data->taps.v_taps > 1 && scl_data->taps.v_taps_c > 1);
0305 
0306     h_2tap_sharp_en = h_2tap_hardcode_coef_en && h_2tap_sharp_factor != 0;
0307     v_2tap_sharp_en = v_2tap_hardcode_coef_en && v_2tap_sharp_factor != 0;
0308 
0309     REG_UPDATE_6(DSCL_2TAP_CONTROL,
0310         SCL_H_2TAP_HARDCODE_COEF_EN, h_2tap_hardcode_coef_en,
0311         SCL_H_2TAP_SHARP_EN, h_2tap_sharp_en,
0312         SCL_H_2TAP_SHARP_FACTOR, h_2tap_sharp_factor,
0313         SCL_V_2TAP_HARDCODE_COEF_EN, v_2tap_hardcode_coef_en,
0314         SCL_V_2TAP_SHARP_EN, v_2tap_sharp_en,
0315         SCL_V_2TAP_SHARP_FACTOR, v_2tap_sharp_factor);
0316 
0317     if (!v_2tap_hardcode_coef_en || !h_2tap_hardcode_coef_en) {
0318         bool filter_updated = false;
0319 
0320         filter_h = dpp1_dscl_get_filter_coeffs_64p(
0321                 scl_data->taps.h_taps, scl_data->ratios.horz);
0322         filter_v = dpp1_dscl_get_filter_coeffs_64p(
0323                 scl_data->taps.v_taps, scl_data->ratios.vert);
0324 
0325         filter_updated = (filter_h && (filter_h != dpp->filter_h))
0326                 || (filter_v && (filter_v != dpp->filter_v));
0327 
0328         if (chroma_coef_mode) {
0329             filter_h_c = dpp1_dscl_get_filter_coeffs_64p(
0330                     scl_data->taps.h_taps_c, scl_data->ratios.horz_c);
0331             filter_v_c = dpp1_dscl_get_filter_coeffs_64p(
0332                     scl_data->taps.v_taps_c, scl_data->ratios.vert_c);
0333             filter_updated = filter_updated || (filter_h_c && (filter_h_c != dpp->filter_h_c))
0334                             || (filter_v_c && (filter_v_c != dpp->filter_v_c));
0335         }
0336 
0337         if (filter_updated) {
0338             uint32_t scl_mode = REG_READ(SCL_MODE);
0339 
0340             if (!h_2tap_hardcode_coef_en && filter_h) {
0341                 dpp1_dscl_set_scaler_filter(
0342                     dpp, scl_data->taps.h_taps,
0343                     SCL_COEF_LUMA_HORZ_FILTER, filter_h);
0344             }
0345             dpp->filter_h = filter_h;
0346             if (!v_2tap_hardcode_coef_en && filter_v) {
0347                 dpp1_dscl_set_scaler_filter(
0348                     dpp, scl_data->taps.v_taps,
0349                     SCL_COEF_LUMA_VERT_FILTER, filter_v);
0350             }
0351             dpp->filter_v = filter_v;
0352             if (chroma_coef_mode) {
0353                 if (!h_2tap_hardcode_coef_en && filter_h_c) {
0354                     dpp1_dscl_set_scaler_filter(
0355                         dpp, scl_data->taps.h_taps_c,
0356                         SCL_COEF_CHROMA_HORZ_FILTER, filter_h_c);
0357                 }
0358                 if (!v_2tap_hardcode_coef_en && filter_v_c) {
0359                     dpp1_dscl_set_scaler_filter(
0360                         dpp, scl_data->taps.v_taps_c,
0361                         SCL_COEF_CHROMA_VERT_FILTER, filter_v_c);
0362                 }
0363             }
0364             dpp->filter_h_c = filter_h_c;
0365             dpp->filter_v_c = filter_v_c;
0366 
0367             coef_ram_current = get_reg_field_value_ex(
0368                 scl_mode, dpp->tf_mask->SCL_COEF_RAM_SELECT_CURRENT,
0369                 dpp->tf_shift->SCL_COEF_RAM_SELECT_CURRENT);
0370 
0371             /* Swap coefficient RAM and set chroma coefficient mode */
0372             REG_SET_2(SCL_MODE, scl_mode,
0373                     SCL_COEF_RAM_SELECT, !coef_ram_current,
0374                     SCL_CHROMA_COEF_MODE, chroma_coef_mode);
0375         }
0376     }
0377 }
0378 
0379 static int dpp1_dscl_get_lb_depth_bpc(enum lb_pixel_depth depth)
0380 {
0381     if (depth == LB_PIXEL_DEPTH_30BPP)
0382         return 10;
0383     else if (depth == LB_PIXEL_DEPTH_24BPP)
0384         return 8;
0385     else if (depth == LB_PIXEL_DEPTH_18BPP)
0386         return 6;
0387     else if (depth == LB_PIXEL_DEPTH_36BPP)
0388         return 12;
0389     else {
0390         BREAK_TO_DEBUGGER();
0391         return -1; /* Unsupported */
0392     }
0393 }
0394 
0395 void dpp1_dscl_calc_lb_num_partitions(
0396         const struct scaler_data *scl_data,
0397         enum lb_memory_config lb_config,
0398         int *num_part_y,
0399         int *num_part_c)
0400 {
0401     int lb_memory_size, lb_memory_size_c, lb_memory_size_a, num_partitions_a,
0402     lb_bpc, memory_line_size_y, memory_line_size_c, memory_line_size_a;
0403 
0404     int line_size = scl_data->viewport.width < scl_data->recout.width ?
0405             scl_data->viewport.width : scl_data->recout.width;
0406     int line_size_c = scl_data->viewport_c.width < scl_data->recout.width ?
0407             scl_data->viewport_c.width : scl_data->recout.width;
0408 
0409     if (line_size == 0)
0410         line_size = 1;
0411 
0412     if (line_size_c == 0)
0413         line_size_c = 1;
0414 
0415 
0416     lb_bpc = dpp1_dscl_get_lb_depth_bpc(scl_data->lb_params.depth);
0417     memory_line_size_y = (line_size * lb_bpc + 71) / 72; /* +71 to ceil */
0418     memory_line_size_c = (line_size_c * lb_bpc + 71) / 72; /* +71 to ceil */
0419     memory_line_size_a = (line_size + 5) / 6; /* +5 to ceil */
0420 
0421     if (lb_config == LB_MEMORY_CONFIG_1) {
0422         lb_memory_size = 816;
0423         lb_memory_size_c = 816;
0424         lb_memory_size_a = 984;
0425     } else if (lb_config == LB_MEMORY_CONFIG_2) {
0426         lb_memory_size = 1088;
0427         lb_memory_size_c = 1088;
0428         lb_memory_size_a = 1312;
0429     } else if (lb_config == LB_MEMORY_CONFIG_3) {
0430         /* 420 mode: using 3rd mem from Y, Cr and Cb */
0431         lb_memory_size = 816 + 1088 + 848 + 848 + 848;
0432         lb_memory_size_c = 816 + 1088;
0433         lb_memory_size_a = 984 + 1312 + 456;
0434     } else {
0435         lb_memory_size = 816 + 1088 + 848;
0436         lb_memory_size_c = 816 + 1088 + 848;
0437         lb_memory_size_a = 984 + 1312 + 456;
0438     }
0439     *num_part_y = lb_memory_size / memory_line_size_y;
0440     *num_part_c = lb_memory_size_c / memory_line_size_c;
0441     num_partitions_a = lb_memory_size_a / memory_line_size_a;
0442 
0443     if (scl_data->lb_params.alpha_en
0444             && (num_partitions_a < *num_part_y))
0445         *num_part_y = num_partitions_a;
0446 
0447     if (*num_part_y > 64)
0448         *num_part_y = 64;
0449     if (*num_part_c > 64)
0450         *num_part_c = 64;
0451 
0452 }
0453 
0454 bool dpp1_dscl_is_lb_conf_valid(int ceil_vratio, int num_partitions, int vtaps)
0455 {
0456     if (ceil_vratio > 2)
0457         return vtaps <= (num_partitions - ceil_vratio + 2);
0458     else
0459         return vtaps <= num_partitions;
0460 }
0461 
0462 /*find first match configuration which meets the min required lb size*/
0463 static enum lb_memory_config dpp1_dscl_find_lb_memory_config(struct dcn10_dpp *dpp,
0464         const struct scaler_data *scl_data)
0465 {
0466     int num_part_y, num_part_c;
0467     int vtaps = scl_data->taps.v_taps;
0468     int vtaps_c = scl_data->taps.v_taps_c;
0469     int ceil_vratio = dc_fixpt_ceil(scl_data->ratios.vert);
0470     int ceil_vratio_c = dc_fixpt_ceil(scl_data->ratios.vert_c);
0471 
0472     if (dpp->base.ctx->dc->debug.use_max_lb) {
0473         if (scl_data->format == PIXEL_FORMAT_420BPP8
0474                 || scl_data->format == PIXEL_FORMAT_420BPP10)
0475             return LB_MEMORY_CONFIG_3;
0476         return LB_MEMORY_CONFIG_0;
0477     }
0478 
0479     dpp->base.caps->dscl_calc_lb_num_partitions(
0480             scl_data, LB_MEMORY_CONFIG_1, &num_part_y, &num_part_c);
0481 
0482     if (dpp1_dscl_is_lb_conf_valid(ceil_vratio, num_part_y, vtaps)
0483             && dpp1_dscl_is_lb_conf_valid(ceil_vratio_c, num_part_c, vtaps_c))
0484         return LB_MEMORY_CONFIG_1;
0485 
0486     dpp->base.caps->dscl_calc_lb_num_partitions(
0487             scl_data, LB_MEMORY_CONFIG_2, &num_part_y, &num_part_c);
0488 
0489     if (dpp1_dscl_is_lb_conf_valid(ceil_vratio, num_part_y, vtaps)
0490             && dpp1_dscl_is_lb_conf_valid(ceil_vratio_c, num_part_c, vtaps_c))
0491         return LB_MEMORY_CONFIG_2;
0492 
0493     if (scl_data->format == PIXEL_FORMAT_420BPP8
0494             || scl_data->format == PIXEL_FORMAT_420BPP10) {
0495         dpp->base.caps->dscl_calc_lb_num_partitions(
0496                 scl_data, LB_MEMORY_CONFIG_3, &num_part_y, &num_part_c);
0497 
0498         if (dpp1_dscl_is_lb_conf_valid(ceil_vratio, num_part_y, vtaps)
0499                 && dpp1_dscl_is_lb_conf_valid(ceil_vratio_c, num_part_c, vtaps_c))
0500             return LB_MEMORY_CONFIG_3;
0501     }
0502 
0503     dpp->base.caps->dscl_calc_lb_num_partitions(
0504             scl_data, LB_MEMORY_CONFIG_0, &num_part_y, &num_part_c);
0505 
0506     /*Ensure we can support the requested number of vtaps*/
0507     ASSERT(dpp1_dscl_is_lb_conf_valid(ceil_vratio, num_part_y, vtaps)
0508             && dpp1_dscl_is_lb_conf_valid(ceil_vratio_c, num_part_c, vtaps_c));
0509 
0510     return LB_MEMORY_CONFIG_0;
0511 }
0512 
0513 
0514 static void dpp1_dscl_set_manual_ratio_init(
0515         struct dcn10_dpp *dpp, const struct scaler_data *data)
0516 {
0517     uint32_t init_frac = 0;
0518     uint32_t init_int = 0;
0519 
0520     REG_SET(SCL_HORZ_FILTER_SCALE_RATIO, 0,
0521             SCL_H_SCALE_RATIO, dc_fixpt_u3d19(data->ratios.horz) << 5);
0522 
0523     REG_SET(SCL_VERT_FILTER_SCALE_RATIO, 0,
0524             SCL_V_SCALE_RATIO, dc_fixpt_u3d19(data->ratios.vert) << 5);
0525 
0526     REG_SET(SCL_HORZ_FILTER_SCALE_RATIO_C, 0,
0527             SCL_H_SCALE_RATIO_C, dc_fixpt_u3d19(data->ratios.horz_c) << 5);
0528 
0529     REG_SET(SCL_VERT_FILTER_SCALE_RATIO_C, 0,
0530             SCL_V_SCALE_RATIO_C, dc_fixpt_u3d19(data->ratios.vert_c) << 5);
0531 
0532     /*
0533      * 0.24 format for fraction, first five bits zeroed
0534      */
0535     init_frac = dc_fixpt_u0d19(data->inits.h) << 5;
0536     init_int = dc_fixpt_floor(data->inits.h);
0537     REG_SET_2(SCL_HORZ_FILTER_INIT, 0,
0538         SCL_H_INIT_FRAC, init_frac,
0539         SCL_H_INIT_INT, init_int);
0540 
0541     init_frac = dc_fixpt_u0d19(data->inits.h_c) << 5;
0542     init_int = dc_fixpt_floor(data->inits.h_c);
0543     REG_SET_2(SCL_HORZ_FILTER_INIT_C, 0,
0544         SCL_H_INIT_FRAC_C, init_frac,
0545         SCL_H_INIT_INT_C, init_int);
0546 
0547     init_frac = dc_fixpt_u0d19(data->inits.v) << 5;
0548     init_int = dc_fixpt_floor(data->inits.v);
0549     REG_SET_2(SCL_VERT_FILTER_INIT, 0,
0550         SCL_V_INIT_FRAC, init_frac,
0551         SCL_V_INIT_INT, init_int);
0552 
0553     if (REG(SCL_VERT_FILTER_INIT_BOT)) {
0554         struct fixed31_32 bot = dc_fixpt_add(data->inits.v, data->ratios.vert);
0555 
0556         init_frac = dc_fixpt_u0d19(bot) << 5;
0557         init_int = dc_fixpt_floor(bot);
0558         REG_SET_2(SCL_VERT_FILTER_INIT_BOT, 0,
0559             SCL_V_INIT_FRAC_BOT, init_frac,
0560             SCL_V_INIT_INT_BOT, init_int);
0561     }
0562 
0563     init_frac = dc_fixpt_u0d19(data->inits.v_c) << 5;
0564     init_int = dc_fixpt_floor(data->inits.v_c);
0565     REG_SET_2(SCL_VERT_FILTER_INIT_C, 0,
0566         SCL_V_INIT_FRAC_C, init_frac,
0567         SCL_V_INIT_INT_C, init_int);
0568 
0569     if (REG(SCL_VERT_FILTER_INIT_BOT_C)) {
0570         struct fixed31_32 bot = dc_fixpt_add(data->inits.v_c, data->ratios.vert_c);
0571 
0572         init_frac = dc_fixpt_u0d19(bot) << 5;
0573         init_int = dc_fixpt_floor(bot);
0574         REG_SET_2(SCL_VERT_FILTER_INIT_BOT_C, 0,
0575             SCL_V_INIT_FRAC_BOT_C, init_frac,
0576             SCL_V_INIT_INT_BOT_C, init_int);
0577     }
0578 }
0579 
0580 /**
0581  * dpp1_dscl_set_recout - Set the first pixel of RECOUT in the OTG active area
0582  *
0583  * @dpp: DPP data struct
0584  * @recount: Rectangle information
0585  *
0586  * This function sets the MPC RECOUT_START and RECOUT_SIZE registers based on
0587  * the values specified in the recount parameter.
0588  *
0589  * Note: This function only have effect if AutoCal is disabled.
0590  */
0591 static void dpp1_dscl_set_recout(struct dcn10_dpp *dpp,
0592                  const struct rect *recout)
0593 {
0594     int visual_confirm_on = 0;
0595     unsigned short visual_confirm_rect_height = VISUAL_CONFIRM_RECT_HEIGHT_DEFAULT;
0596 
0597     if (dpp->base.ctx->dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE)
0598         visual_confirm_on = 1;
0599 
0600     /* Check bounds to ensure the VC bar height was set to a sane value */
0601     if ((dpp->base.ctx->dc->debug.visual_confirm_rect_height >= VISUAL_CONFIRM_RECT_HEIGHT_MIN) &&
0602             (dpp->base.ctx->dc->debug.visual_confirm_rect_height <= VISUAL_CONFIRM_RECT_HEIGHT_MAX)) {
0603         visual_confirm_rect_height = dpp->base.ctx->dc->debug.visual_confirm_rect_height;
0604     }
0605 
0606     REG_SET_2(RECOUT_START, 0,
0607           /* First pixel of RECOUT in the active OTG area */
0608           RECOUT_START_X, recout->x,
0609           /* First line of RECOUT in the active OTG area */
0610           RECOUT_START_Y, recout->y);
0611 
0612     REG_SET_2(RECOUT_SIZE, 0,
0613           /* Number of RECOUT horizontal pixels */
0614           RECOUT_WIDTH, recout->width,
0615           /* Number of RECOUT vertical lines */
0616           RECOUT_HEIGHT, recout->height
0617              - visual_confirm_on * 2 * (dpp->base.inst + visual_confirm_rect_height));
0618 }
0619 
0620 /**
0621  * dpp1_dscl_set_scaler_manual_scale - Manually program scaler and line buffer
0622  *
0623  * @dpp_base: High level DPP struct
0624  * @scl_data: scalaer_data info
0625  *
0626  * This is the primary function to program scaler and line buffer in manual
0627  * scaling mode. To execute the required operations for manual scale, we need
0628  * to disable AutoCal first.
0629  */
0630 void dpp1_dscl_set_scaler_manual_scale(struct dpp *dpp_base,
0631                        const struct scaler_data *scl_data)
0632 {
0633     enum lb_memory_config lb_config;
0634     struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
0635     enum dscl_mode_sel dscl_mode = dpp1_dscl_get_dscl_mode(
0636             dpp_base, scl_data, dpp_base->ctx->dc->debug.always_scale);
0637     bool ycbcr = scl_data->format >= PIXEL_FORMAT_VIDEO_BEGIN
0638                 && scl_data->format <= PIXEL_FORMAT_VIDEO_END;
0639 
0640     if (memcmp(&dpp->scl_data, scl_data, sizeof(*scl_data)) == 0)
0641         return;
0642 
0643     PERF_TRACE();
0644 
0645     dpp->scl_data = *scl_data;
0646 
0647     if (dpp_base->ctx->dc->debug.enable_mem_low_power.bits.dscl) {
0648         if (dscl_mode != DSCL_MODE_DSCL_BYPASS)
0649             dpp1_power_on_dscl(dpp_base, true);
0650     }
0651 
0652     /* Autocal off */
0653     REG_SET_3(DSCL_AUTOCAL, 0,
0654         AUTOCAL_MODE, AUTOCAL_MODE_OFF,
0655         AUTOCAL_NUM_PIPE, 0,
0656         AUTOCAL_PIPE_ID, 0);
0657 
0658     /* Recout */
0659     dpp1_dscl_set_recout(dpp, &scl_data->recout);
0660 
0661     /* MPC Size */
0662     REG_SET_2(MPC_SIZE, 0,
0663         /* Number of horizontal pixels of MPC */
0664              MPC_WIDTH, scl_data->h_active,
0665         /* Number of vertical lines of MPC */
0666              MPC_HEIGHT, scl_data->v_active);
0667 
0668     /* SCL mode */
0669     REG_UPDATE(SCL_MODE, DSCL_MODE, dscl_mode);
0670 
0671     if (dscl_mode == DSCL_MODE_DSCL_BYPASS) {
0672         if (dpp_base->ctx->dc->debug.enable_mem_low_power.bits.dscl)
0673             dpp1_power_on_dscl(dpp_base, false);
0674         return;
0675     }
0676 
0677     /* LB */
0678     lb_config =  dpp1_dscl_find_lb_memory_config(dpp, scl_data);
0679     dpp1_dscl_set_lb(dpp, &scl_data->lb_params, lb_config);
0680 
0681     if (dscl_mode == DSCL_MODE_SCALING_444_BYPASS)
0682         return;
0683 
0684     /* Black offsets */
0685     if (REG(SCL_BLACK_OFFSET)) {
0686         if (ycbcr)
0687             REG_SET_2(SCL_BLACK_OFFSET, 0,
0688                     SCL_BLACK_OFFSET_RGB_Y, BLACK_OFFSET_RGB_Y,
0689                     SCL_BLACK_OFFSET_CBCR, BLACK_OFFSET_CBCR);
0690         else
0691 
0692             REG_SET_2(SCL_BLACK_OFFSET, 0,
0693                     SCL_BLACK_OFFSET_RGB_Y, BLACK_OFFSET_RGB_Y,
0694                     SCL_BLACK_OFFSET_CBCR, BLACK_OFFSET_RGB_Y);
0695     }
0696 
0697     /* Manually calculate scale ratio and init values */
0698     dpp1_dscl_set_manual_ratio_init(dpp, scl_data);
0699 
0700     /* HTaps/VTaps */
0701     REG_SET_4(SCL_TAP_CONTROL, 0,
0702         SCL_V_NUM_TAPS, scl_data->taps.v_taps - 1,
0703         SCL_H_NUM_TAPS, scl_data->taps.h_taps - 1,
0704         SCL_V_NUM_TAPS_C, scl_data->taps.v_taps_c - 1,
0705         SCL_H_NUM_TAPS_C, scl_data->taps.h_taps_c - 1);
0706 
0707     dpp1_dscl_set_scl_filter(dpp, scl_data, ycbcr);
0708     PERF_TRACE();
0709 }