Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2012-15 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 #include "dcn10_opp.h"
0028 #include "reg_helper.h"
0029 
0030 #define REG(reg) \
0031     (oppn10->regs->reg)
0032 
0033 #undef FN
0034 #define FN(reg_name, field_name) \
0035     oppn10->opp_shift->field_name, oppn10->opp_mask->field_name
0036 
0037 #define CTX \
0038     oppn10->base.ctx
0039 
0040 
0041 /************* FORMATTER ************/
0042 
0043 /**
0044  *  set_truncation
0045  *  1) set truncation depth: 0 for 18 bpp or 1 for 24 bpp
0046  *  2) enable truncation
0047  *  3) HW remove 12bit FMT support for DCE11 power saving reason.
0048  */
0049 static void opp1_set_truncation(
0050         struct dcn10_opp *oppn10,
0051         const struct bit_depth_reduction_params *params)
0052 {
0053     REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
0054         FMT_TRUNCATE_EN, params->flags.TRUNCATE_ENABLED,
0055         FMT_TRUNCATE_DEPTH, params->flags.TRUNCATE_DEPTH,
0056         FMT_TRUNCATE_MODE, params->flags.TRUNCATE_MODE);
0057 }
0058 
0059 static void opp1_set_spatial_dither(
0060     struct dcn10_opp *oppn10,
0061     const struct bit_depth_reduction_params *params)
0062 {
0063     /*Disable spatial (random) dithering*/
0064     REG_UPDATE_7(FMT_BIT_DEPTH_CONTROL,
0065             FMT_SPATIAL_DITHER_EN, 0,
0066             FMT_SPATIAL_DITHER_MODE, 0,
0067             FMT_SPATIAL_DITHER_DEPTH, 0,
0068             FMT_TEMPORAL_DITHER_EN, 0,
0069             FMT_HIGHPASS_RANDOM_ENABLE, 0,
0070             FMT_FRAME_RANDOM_ENABLE, 0,
0071             FMT_RGB_RANDOM_ENABLE, 0);
0072 
0073 
0074     /* only use FRAME_COUNTER_MAX if frameRandom == 1*/
0075     if (params->flags.FRAME_RANDOM == 1) {
0076         if (params->flags.SPATIAL_DITHER_DEPTH == 0 || params->flags.SPATIAL_DITHER_DEPTH == 1) {
0077             REG_UPDATE_2(FMT_CONTROL,
0078                     FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 15,
0079                     FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 2);
0080         } else if (params->flags.SPATIAL_DITHER_DEPTH == 2) {
0081             REG_UPDATE_2(FMT_CONTROL,
0082                     FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 3,
0083                     FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 1);
0084         } else {
0085             return;
0086         }
0087     } else {
0088         REG_UPDATE_2(FMT_CONTROL,
0089                 FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 0,
0090                 FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 0);
0091     }
0092 
0093     /*Set seed for random values for
0094      * spatial dithering for R,G,B channels*/
0095 
0096     REG_SET(FMT_DITHER_RAND_R_SEED, 0,
0097             FMT_RAND_R_SEED, params->r_seed_value);
0098 
0099     REG_SET(FMT_DITHER_RAND_G_SEED, 0,
0100             FMT_RAND_G_SEED, params->g_seed_value);
0101 
0102     REG_SET(FMT_DITHER_RAND_B_SEED, 0,
0103             FMT_RAND_B_SEED, params->b_seed_value);
0104 
0105     /* FMT_OFFSET_R_Cr  31:16 0x0 Setting the zero
0106      * offset for the R/Cr channel, lower 4LSB
0107      * is forced to zeros. Typically set to 0
0108      * RGB and 0x80000 YCbCr.
0109      */
0110     /* FMT_OFFSET_G_Y   31:16 0x0 Setting the zero
0111      * offset for the G/Y  channel, lower 4LSB is
0112      * forced to zeros. Typically set to 0 RGB
0113      * and 0x80000 YCbCr.
0114      */
0115     /* FMT_OFFSET_B_Cb  31:16 0x0 Setting the zero
0116      * offset for the B/Cb channel, lower 4LSB is
0117      * forced to zeros. Typically set to 0 RGB and
0118      * 0x80000 YCbCr.
0119      */
0120 
0121     REG_UPDATE_6(FMT_BIT_DEPTH_CONTROL,
0122             /*Enable spatial dithering*/
0123             FMT_SPATIAL_DITHER_EN, params->flags.SPATIAL_DITHER_ENABLED,
0124             /* Set spatial dithering mode
0125              * (default is Seed patterrn AAAA...)
0126              */
0127             FMT_SPATIAL_DITHER_MODE, params->flags.SPATIAL_DITHER_MODE,
0128             /*Set spatial dithering bit depth*/
0129             FMT_SPATIAL_DITHER_DEPTH, params->flags.SPATIAL_DITHER_DEPTH,
0130             /*Disable High pass filter*/
0131             FMT_HIGHPASS_RANDOM_ENABLE, params->flags.HIGHPASS_RANDOM,
0132             /*Reset only at startup*/
0133             FMT_FRAME_RANDOM_ENABLE, params->flags.FRAME_RANDOM,
0134             /*Set RGB data dithered with x^28+x^3+1*/
0135             FMT_RGB_RANDOM_ENABLE, params->flags.RGB_RANDOM);
0136 }
0137 
0138 void opp1_program_bit_depth_reduction(
0139     struct output_pixel_processor *opp,
0140     const struct bit_depth_reduction_params *params)
0141 {
0142     struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
0143 
0144     opp1_set_truncation(oppn10, params);
0145     opp1_set_spatial_dither(oppn10, params);
0146     /* TODO
0147      * set_temporal_dither(oppn10, params);
0148      */
0149 }
0150 
0151 /**
0152  *  set_pixel_encoding
0153  *
0154  *  Set Pixel Encoding
0155  *      0: RGB 4:4:4 or YCbCr 4:4:4 or YOnly
0156  *      1: YCbCr 4:2:2
0157  */
0158 static void opp1_set_pixel_encoding(
0159     struct dcn10_opp *oppn10,
0160     const struct clamping_and_pixel_encoding_params *params)
0161 {
0162     switch (params->pixel_encoding) {
0163 
0164     case PIXEL_ENCODING_RGB:
0165     case PIXEL_ENCODING_YCBCR444:
0166         REG_UPDATE(FMT_CONTROL, FMT_PIXEL_ENCODING, 0);
0167         break;
0168     case PIXEL_ENCODING_YCBCR422:
0169         REG_UPDATE_3(FMT_CONTROL,
0170                 FMT_PIXEL_ENCODING, 1,
0171                 FMT_SUBSAMPLING_MODE, 2,
0172                 FMT_CBCR_BIT_REDUCTION_BYPASS, 0);
0173         break;
0174     case PIXEL_ENCODING_YCBCR420:
0175         REG_UPDATE(FMT_CONTROL, FMT_PIXEL_ENCODING, 2);
0176         break;
0177     default:
0178         break;
0179     }
0180 }
0181 
0182 /**
0183  *  Set Clamping
0184  *  1) Set clamping format based on bpc - 0 for 6bpc (No clamping)
0185  *      1 for 8 bpc
0186  *      2 for 10 bpc
0187  *      3 for 12 bpc
0188  *      7 for programable
0189  *  2) Enable clamp if Limited range requested
0190  */
0191 static void opp1_set_clamping(
0192     struct dcn10_opp *oppn10,
0193     const struct clamping_and_pixel_encoding_params *params)
0194 {
0195     REG_UPDATE_2(FMT_CLAMP_CNTL,
0196             FMT_CLAMP_DATA_EN, 0,
0197             FMT_CLAMP_COLOR_FORMAT, 0);
0198 
0199     switch (params->clamping_level) {
0200     case CLAMPING_FULL_RANGE:
0201         REG_UPDATE_2(FMT_CLAMP_CNTL,
0202                 FMT_CLAMP_DATA_EN, 1,
0203                 FMT_CLAMP_COLOR_FORMAT, 0);
0204         break;
0205     case CLAMPING_LIMITED_RANGE_8BPC:
0206         REG_UPDATE_2(FMT_CLAMP_CNTL,
0207                 FMT_CLAMP_DATA_EN, 1,
0208                 FMT_CLAMP_COLOR_FORMAT, 1);
0209         break;
0210     case CLAMPING_LIMITED_RANGE_10BPC:
0211         REG_UPDATE_2(FMT_CLAMP_CNTL,
0212                 FMT_CLAMP_DATA_EN, 1,
0213                 FMT_CLAMP_COLOR_FORMAT, 2);
0214 
0215         break;
0216     case CLAMPING_LIMITED_RANGE_12BPC:
0217         REG_UPDATE_2(FMT_CLAMP_CNTL,
0218                 FMT_CLAMP_DATA_EN, 1,
0219                 FMT_CLAMP_COLOR_FORMAT, 3);
0220         break;
0221     case CLAMPING_LIMITED_RANGE_PROGRAMMABLE:
0222         /* TODO */
0223     default:
0224         break;
0225     }
0226 
0227 }
0228 
0229 void opp1_set_dyn_expansion(
0230     struct output_pixel_processor *opp,
0231     enum dc_color_space color_sp,
0232     enum dc_color_depth color_dpth,
0233     enum signal_type signal)
0234 {
0235     struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
0236 
0237     REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
0238             FMT_DYNAMIC_EXP_EN, 0,
0239             FMT_DYNAMIC_EXP_MODE, 0);
0240 
0241     if (opp->dyn_expansion == DYN_EXPANSION_DISABLE)
0242         return;
0243 
0244     /*00 - 10-bit -> 12-bit dynamic expansion*/
0245     /*01 - 8-bit  -> 12-bit dynamic expansion*/
0246     if (signal == SIGNAL_TYPE_HDMI_TYPE_A ||
0247         signal == SIGNAL_TYPE_DISPLAY_PORT ||
0248         signal == SIGNAL_TYPE_DISPLAY_PORT_MST ||
0249         signal == SIGNAL_TYPE_VIRTUAL) {
0250         switch (color_dpth) {
0251         case COLOR_DEPTH_888:
0252             REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
0253                 FMT_DYNAMIC_EXP_EN, 1,
0254                 FMT_DYNAMIC_EXP_MODE, 1);
0255             break;
0256         case COLOR_DEPTH_101010:
0257             REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
0258                 FMT_DYNAMIC_EXP_EN, 1,
0259                 FMT_DYNAMIC_EXP_MODE, 0);
0260             break;
0261         case COLOR_DEPTH_121212:
0262             REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
0263                 FMT_DYNAMIC_EXP_EN, 1,/*otherwise last two bits are zero*/
0264                 FMT_DYNAMIC_EXP_MODE, 0);
0265             break;
0266         default:
0267             break;
0268         }
0269     }
0270 }
0271 
0272 static void opp1_program_clamping_and_pixel_encoding(
0273     struct output_pixel_processor *opp,
0274     const struct clamping_and_pixel_encoding_params *params)
0275 {
0276     struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
0277 
0278     opp1_set_clamping(oppn10, params);
0279     opp1_set_pixel_encoding(oppn10, params);
0280 }
0281 
0282 void opp1_program_fmt(
0283     struct output_pixel_processor *opp,
0284     struct bit_depth_reduction_params *fmt_bit_depth,
0285     struct clamping_and_pixel_encoding_params *clamping)
0286 {
0287     struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
0288 
0289     if (clamping->pixel_encoding == PIXEL_ENCODING_YCBCR420)
0290         REG_UPDATE(FMT_MAP420_MEMORY_CONTROL, FMT_MAP420MEM_PWR_FORCE, 0);
0291 
0292     /* dithering is affected by <CrtcSourceSelect>, hence should be
0293      * programmed afterwards */
0294     opp1_program_bit_depth_reduction(
0295         opp,
0296         fmt_bit_depth);
0297 
0298     opp1_program_clamping_and_pixel_encoding(
0299         opp,
0300         clamping);
0301 
0302     return;
0303 }
0304 
0305 void opp1_program_stereo(
0306     struct output_pixel_processor *opp,
0307     bool enable,
0308     const struct dc_crtc_timing *timing)
0309 {
0310     struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
0311 
0312     uint32_t active_width = timing->h_addressable - timing->h_border_right - timing->h_border_right;
0313     uint32_t space1_size = timing->v_total - timing->v_addressable;
0314     /* TODO: confirm computation of space2_size */
0315     uint32_t space2_size = timing->v_total - timing->v_addressable;
0316 
0317     if (!enable) {
0318         active_width = 0;
0319         space1_size = 0;
0320         space2_size = 0;
0321     }
0322 
0323     /* TODO: for which cases should FMT_STEREOSYNC_OVERRIDE be set? */
0324     REG_UPDATE(FMT_CONTROL, FMT_STEREOSYNC_OVERRIDE, 0);
0325 
0326     REG_UPDATE(OPPBUF_CONTROL, OPPBUF_ACTIVE_WIDTH, active_width);
0327 
0328     /* Program OPPBUF_3D_VACT_SPACE1_SIZE and OPPBUF_VACT_SPACE2_SIZE registers
0329      * In 3D progressive frames, Vactive space happens only in between the 2 frames,
0330      * so only need to program OPPBUF_3D_VACT_SPACE1_SIZE
0331      * In 3D alternative frames, left and right frames, top and bottom field.
0332      */
0333     if (timing->timing_3d_format == TIMING_3D_FORMAT_FRAME_ALTERNATE)
0334         REG_UPDATE(OPPBUF_3D_PARAMETERS_0, OPPBUF_3D_VACT_SPACE2_SIZE, space2_size);
0335     else
0336         REG_UPDATE(OPPBUF_3D_PARAMETERS_0, OPPBUF_3D_VACT_SPACE1_SIZE, space1_size);
0337 
0338     /* TODO: Is programming of OPPBUF_DUMMY_DATA_R/G/B needed? */
0339     /*
0340     REG_UPDATE(OPPBUF_3D_PARAMETERS_0,
0341             OPPBUF_DUMMY_DATA_R, data_r);
0342     REG_UPDATE(OPPBUF_3D_PARAMETERS_1,
0343             OPPBUF_DUMMY_DATA_G, data_g);
0344     REG_UPDATE(OPPBUF_3D_PARAMETERS_1,
0345             OPPBUF_DUMMY_DATA_B, _data_b);
0346     */
0347 }
0348 
0349 void opp1_pipe_clock_control(struct output_pixel_processor *opp, bool enable)
0350 {
0351     struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
0352     uint32_t regval = enable ? 1 : 0;
0353 
0354     REG_UPDATE(OPP_PIPE_CONTROL, OPP_PIPE_CLOCK_EN, regval);
0355 }
0356 
0357 /*****************************************/
0358 /* Constructor, Destructor               */
0359 /*****************************************/
0360 
0361 void opp1_destroy(struct output_pixel_processor **opp)
0362 {
0363     kfree(TO_DCN10_OPP(*opp));
0364     *opp = NULL;
0365 }
0366 
0367 static const struct opp_funcs dcn10_opp_funcs = {
0368         .opp_set_dyn_expansion = opp1_set_dyn_expansion,
0369         .opp_program_fmt = opp1_program_fmt,
0370         .opp_program_bit_depth_reduction = opp1_program_bit_depth_reduction,
0371         .opp_program_stereo = opp1_program_stereo,
0372         .opp_pipe_clock_control = opp1_pipe_clock_control,
0373         .opp_set_disp_pattern_generator = NULL,
0374         .opp_program_dpg_dimensions = NULL,
0375         .dpg_is_blanked = NULL,
0376         .opp_destroy = opp1_destroy
0377 };
0378 
0379 void dcn10_opp_construct(struct dcn10_opp *oppn10,
0380     struct dc_context *ctx,
0381     uint32_t inst,
0382     const struct dcn10_opp_registers *regs,
0383     const struct dcn10_opp_shift *opp_shift,
0384     const struct dcn10_opp_mask *opp_mask)
0385 {
0386 
0387     oppn10->base.ctx = ctx;
0388     oppn10->base.inst = inst;
0389     oppn10->base.funcs = &dcn10_opp_funcs;
0390 
0391     oppn10->regs = regs;
0392     oppn10->opp_shift = opp_shift;
0393     oppn10->opp_mask = opp_mask;
0394 }