root/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. opp1_set_truncation
  2. opp1_set_spatial_dither
  3. opp1_program_bit_depth_reduction
  4. opp1_set_pixel_encoding
  5. opp1_set_clamping
  6. opp1_set_dyn_expansion
  7. opp1_program_clamping_and_pixel_encoding
  8. opp1_program_fmt
  9. opp1_program_stereo
  10. opp1_program_oppbuf
  11. opp1_pipe_clock_control
  12. opp1_destroy
  13. dcn10_opp_construct

   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 <linux/slab.h>
  27 
  28 #include "dm_services.h"
  29 #include "dcn10_opp.h"
  30 #include "reg_helper.h"
  31 
  32 #define REG(reg) \
  33         (oppn10->regs->reg)
  34 
  35 #undef FN
  36 #define FN(reg_name, field_name) \
  37         oppn10->opp_shift->field_name, oppn10->opp_mask->field_name
  38 
  39 #define CTX \
  40         oppn10->base.ctx
  41 
  42 
  43 /************* FORMATTER ************/
  44 
  45 /**
  46  *      set_truncation
  47  *      1) set truncation depth: 0 for 18 bpp or 1 for 24 bpp
  48  *      2) enable truncation
  49  *      3) HW remove 12bit FMT support for DCE11 power saving reason.
  50  */
  51 static void opp1_set_truncation(
  52                 struct dcn10_opp *oppn10,
  53                 const struct bit_depth_reduction_params *params)
  54 {
  55         REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
  56                 FMT_TRUNCATE_EN, params->flags.TRUNCATE_ENABLED,
  57                 FMT_TRUNCATE_DEPTH, params->flags.TRUNCATE_DEPTH,
  58                 FMT_TRUNCATE_MODE, params->flags.TRUNCATE_MODE);
  59 }
  60 
  61 static void opp1_set_spatial_dither(
  62         struct dcn10_opp *oppn10,
  63         const struct bit_depth_reduction_params *params)
  64 {
  65         /*Disable spatial (random) dithering*/
  66         REG_UPDATE_7(FMT_BIT_DEPTH_CONTROL,
  67                         FMT_SPATIAL_DITHER_EN, 0,
  68                         FMT_SPATIAL_DITHER_MODE, 0,
  69                         FMT_SPATIAL_DITHER_DEPTH, 0,
  70                         FMT_TEMPORAL_DITHER_EN, 0,
  71                         FMT_HIGHPASS_RANDOM_ENABLE, 0,
  72                         FMT_FRAME_RANDOM_ENABLE, 0,
  73                         FMT_RGB_RANDOM_ENABLE, 0);
  74 
  75 
  76         /* only use FRAME_COUNTER_MAX if frameRandom == 1*/
  77         if (params->flags.FRAME_RANDOM == 1) {
  78                 if (params->flags.SPATIAL_DITHER_DEPTH == 0 || params->flags.SPATIAL_DITHER_DEPTH == 1) {
  79                         REG_UPDATE_2(FMT_CONTROL,
  80                                         FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 15,
  81                                         FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 2);
  82                 } else if (params->flags.SPATIAL_DITHER_DEPTH == 2) {
  83                         REG_UPDATE_2(FMT_CONTROL,
  84                                         FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 3,
  85                                         FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 1);
  86                 } else {
  87                         return;
  88                 }
  89         } else {
  90                 REG_UPDATE_2(FMT_CONTROL,
  91                                 FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 0,
  92                                 FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 0);
  93         }
  94 
  95         /*Set seed for random values for
  96          * spatial dithering for R,G,B channels*/
  97 
  98         REG_SET(FMT_DITHER_RAND_R_SEED, 0,
  99                         FMT_RAND_R_SEED, params->r_seed_value);
 100 
 101         REG_SET(FMT_DITHER_RAND_G_SEED, 0,
 102                         FMT_RAND_G_SEED, params->g_seed_value);
 103 
 104         REG_SET(FMT_DITHER_RAND_B_SEED, 0,
 105                         FMT_RAND_B_SEED, params->b_seed_value);
 106 
 107         /* FMT_OFFSET_R_Cr  31:16 0x0 Setting the zero
 108          * offset for the R/Cr channel, lower 4LSB
 109          * is forced to zeros. Typically set to 0
 110          * RGB and 0x80000 YCbCr.
 111          */
 112         /* FMT_OFFSET_G_Y   31:16 0x0 Setting the zero
 113          * offset for the G/Y  channel, lower 4LSB is
 114          * forced to zeros. Typically set to 0 RGB
 115          * and 0x80000 YCbCr.
 116          */
 117         /* FMT_OFFSET_B_Cb  31:16 0x0 Setting the zero
 118          * offset for the B/Cb channel, lower 4LSB is
 119          * forced to zeros. Typically set to 0 RGB and
 120          * 0x80000 YCbCr.
 121          */
 122 
 123         REG_UPDATE_6(FMT_BIT_DEPTH_CONTROL,
 124                         /*Enable spatial dithering*/
 125                         FMT_SPATIAL_DITHER_EN, params->flags.SPATIAL_DITHER_ENABLED,
 126                         /* Set spatial dithering mode
 127                          * (default is Seed patterrn AAAA...)
 128                          */
 129                         FMT_SPATIAL_DITHER_MODE, params->flags.SPATIAL_DITHER_MODE,
 130                         /*Set spatial dithering bit depth*/
 131                         FMT_SPATIAL_DITHER_DEPTH, params->flags.SPATIAL_DITHER_DEPTH,
 132                         /*Disable High pass filter*/
 133                         FMT_HIGHPASS_RANDOM_ENABLE, params->flags.HIGHPASS_RANDOM,
 134                         /*Reset only at startup*/
 135                         FMT_FRAME_RANDOM_ENABLE, params->flags.FRAME_RANDOM,
 136                         /*Set RGB data dithered with x^28+x^3+1*/
 137                         FMT_RGB_RANDOM_ENABLE, params->flags.RGB_RANDOM);
 138 }
 139 
 140 void opp1_program_bit_depth_reduction(
 141         struct output_pixel_processor *opp,
 142         const struct bit_depth_reduction_params *params)
 143 {
 144         struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
 145 
 146         opp1_set_truncation(oppn10, params);
 147         opp1_set_spatial_dither(oppn10, params);
 148         /* TODO
 149          * set_temporal_dither(oppn10, params);
 150          */
 151 }
 152 
 153 /**
 154  *      set_pixel_encoding
 155  *
 156  *      Set Pixel Encoding
 157  *              0: RGB 4:4:4 or YCbCr 4:4:4 or YOnly
 158  *              1: YCbCr 4:2:2
 159  */
 160 static void opp1_set_pixel_encoding(
 161         struct dcn10_opp *oppn10,
 162         const struct clamping_and_pixel_encoding_params *params)
 163 {
 164         switch (params->pixel_encoding) {
 165 
 166         case PIXEL_ENCODING_RGB:
 167         case PIXEL_ENCODING_YCBCR444:
 168                 REG_UPDATE(FMT_CONTROL, FMT_PIXEL_ENCODING, 0);
 169                 break;
 170         case PIXEL_ENCODING_YCBCR422:
 171                 REG_UPDATE(FMT_CONTROL, FMT_PIXEL_ENCODING, 1);
 172                 break;
 173         case PIXEL_ENCODING_YCBCR420:
 174                 REG_UPDATE(FMT_CONTROL, FMT_PIXEL_ENCODING, 2);
 175                 break;
 176         default:
 177                 break;
 178         }
 179 }
 180 
 181 /**
 182  *      Set Clamping
 183  *      1) Set clamping format based on bpc - 0 for 6bpc (No clamping)
 184  *              1 for 8 bpc
 185  *              2 for 10 bpc
 186  *              3 for 12 bpc
 187  *              7 for programable
 188  *      2) Enable clamp if Limited range requested
 189  */
 190 static void opp1_set_clamping(
 191         struct dcn10_opp *oppn10,
 192         const struct clamping_and_pixel_encoding_params *params)
 193 {
 194         REG_UPDATE_2(FMT_CLAMP_CNTL,
 195                         FMT_CLAMP_DATA_EN, 0,
 196                         FMT_CLAMP_COLOR_FORMAT, 0);
 197 
 198         switch (params->clamping_level) {
 199         case CLAMPING_FULL_RANGE:
 200                 REG_UPDATE_2(FMT_CLAMP_CNTL,
 201                                 FMT_CLAMP_DATA_EN, 1,
 202                                 FMT_CLAMP_COLOR_FORMAT, 0);
 203                 break;
 204         case CLAMPING_LIMITED_RANGE_8BPC:
 205                 REG_UPDATE_2(FMT_CLAMP_CNTL,
 206                                 FMT_CLAMP_DATA_EN, 1,
 207                                 FMT_CLAMP_COLOR_FORMAT, 1);
 208                 break;
 209         case CLAMPING_LIMITED_RANGE_10BPC:
 210                 REG_UPDATE_2(FMT_CLAMP_CNTL,
 211                                 FMT_CLAMP_DATA_EN, 1,
 212                                 FMT_CLAMP_COLOR_FORMAT, 2);
 213 
 214                 break;
 215         case CLAMPING_LIMITED_RANGE_12BPC:
 216                 REG_UPDATE_2(FMT_CLAMP_CNTL,
 217                                 FMT_CLAMP_DATA_EN, 1,
 218                                 FMT_CLAMP_COLOR_FORMAT, 3);
 219                 break;
 220         case CLAMPING_LIMITED_RANGE_PROGRAMMABLE:
 221                 /* TODO */
 222         default:
 223                 break;
 224         }
 225 
 226 }
 227 
 228 void opp1_set_dyn_expansion(
 229         struct output_pixel_processor *opp,
 230         enum dc_color_space color_sp,
 231         enum dc_color_depth color_dpth,
 232         enum signal_type signal)
 233 {
 234         struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
 235 
 236         REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
 237                         FMT_DYNAMIC_EXP_EN, 0,
 238                         FMT_DYNAMIC_EXP_MODE, 0);
 239 
 240         /*00 - 10-bit -> 12-bit dynamic expansion*/
 241         /*01 - 8-bit  -> 12-bit dynamic expansion*/
 242         if (signal == SIGNAL_TYPE_HDMI_TYPE_A ||
 243                 signal == SIGNAL_TYPE_DISPLAY_PORT ||
 244                 signal == SIGNAL_TYPE_DISPLAY_PORT_MST ||
 245                 signal == SIGNAL_TYPE_VIRTUAL) {
 246                 switch (color_dpth) {
 247                 case COLOR_DEPTH_888:
 248                         REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
 249                                 FMT_DYNAMIC_EXP_EN, 1,
 250                                 FMT_DYNAMIC_EXP_MODE, 1);
 251                         break;
 252                 case COLOR_DEPTH_101010:
 253                         REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
 254                                 FMT_DYNAMIC_EXP_EN, 1,
 255                                 FMT_DYNAMIC_EXP_MODE, 0);
 256                         break;
 257                 case COLOR_DEPTH_121212:
 258                         REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
 259                                 FMT_DYNAMIC_EXP_EN, 1,/*otherwise last two bits are zero*/
 260                                 FMT_DYNAMIC_EXP_MODE, 0);
 261                         break;
 262                 default:
 263                         break;
 264                 }
 265         }
 266 }
 267 
 268 static void opp1_program_clamping_and_pixel_encoding(
 269         struct output_pixel_processor *opp,
 270         const struct clamping_and_pixel_encoding_params *params)
 271 {
 272         struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
 273 
 274         opp1_set_clamping(oppn10, params);
 275         opp1_set_pixel_encoding(oppn10, params);
 276 }
 277 
 278 void opp1_program_fmt(
 279         struct output_pixel_processor *opp,
 280         struct bit_depth_reduction_params *fmt_bit_depth,
 281         struct clamping_and_pixel_encoding_params *clamping)
 282 {
 283         struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
 284 
 285         if (clamping->pixel_encoding == PIXEL_ENCODING_YCBCR420)
 286                 REG_UPDATE(FMT_MAP420_MEMORY_CONTROL, FMT_MAP420MEM_PWR_FORCE, 0);
 287 
 288         /* dithering is affected by <CrtcSourceSelect>, hence should be
 289          * programmed afterwards */
 290         opp1_program_bit_depth_reduction(
 291                 opp,
 292                 fmt_bit_depth);
 293 
 294         opp1_program_clamping_and_pixel_encoding(
 295                 opp,
 296                 clamping);
 297 
 298         return;
 299 }
 300 
 301 void opp1_program_stereo(
 302         struct output_pixel_processor *opp,
 303         bool enable,
 304         const struct dc_crtc_timing *timing)
 305 {
 306         struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
 307 
 308         uint32_t active_width = timing->h_addressable - timing->h_border_right - timing->h_border_right;
 309         uint32_t space1_size = timing->v_total - timing->v_addressable;
 310         /* TODO: confirm computation of space2_size */
 311         uint32_t space2_size = timing->v_total - timing->v_addressable;
 312 
 313         if (!enable) {
 314                 active_width = 0;
 315                 space1_size = 0;
 316                 space2_size = 0;
 317         }
 318 
 319         /* TODO: for which cases should FMT_STEREOSYNC_OVERRIDE be set? */
 320         REG_UPDATE(FMT_CONTROL, FMT_STEREOSYNC_OVERRIDE, 0);
 321 
 322         REG_UPDATE(OPPBUF_CONTROL, OPPBUF_ACTIVE_WIDTH, active_width);
 323 
 324         /* Program OPPBUF_3D_VACT_SPACE1_SIZE and OPPBUF_VACT_SPACE2_SIZE registers
 325          * In 3D progressive frames, Vactive space happens only in between the 2 frames,
 326          * so only need to program OPPBUF_3D_VACT_SPACE1_SIZE
 327          * In 3D alternative frames, left and right frames, top and bottom field.
 328          */
 329         if (timing->timing_3d_format == TIMING_3D_FORMAT_FRAME_ALTERNATE)
 330                 REG_UPDATE(OPPBUF_3D_PARAMETERS_0, OPPBUF_3D_VACT_SPACE2_SIZE, space2_size);
 331         else
 332                 REG_UPDATE(OPPBUF_3D_PARAMETERS_0, OPPBUF_3D_VACT_SPACE1_SIZE, space1_size);
 333 
 334         /* TODO: Is programming of OPPBUF_DUMMY_DATA_R/G/B needed? */
 335         /*
 336         REG_UPDATE(OPPBUF_3D_PARAMETERS_0,
 337                         OPPBUF_DUMMY_DATA_R, data_r);
 338         REG_UPDATE(OPPBUF_3D_PARAMETERS_1,
 339                         OPPBUF_DUMMY_DATA_G, data_g);
 340         REG_UPDATE(OPPBUF_3D_PARAMETERS_1,
 341                         OPPBUF_DUMMY_DATA_B, _data_b);
 342         */
 343 }
 344 
 345 void opp1_program_oppbuf(
 346         struct output_pixel_processor *opp,
 347         struct oppbuf_params *oppbuf)
 348 {
 349         struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
 350 
 351         /* Program the oppbuf active width to be the frame width from mpc */
 352         REG_UPDATE(OPPBUF_CONTROL, OPPBUF_ACTIVE_WIDTH, oppbuf->active_width);
 353 
 354         /* Specifies the number of segments in multi-segment mode (DP-MSO operation)
 355          * description  "In 1/2/4 segment mode, specifies the horizontal active width in pixels of the display panel.
 356          * In 4 segment split left/right mode, specifies the horizontal 1/2 active width in pixels of the display panel.
 357          * Used to determine segment boundaries in multi-segment mode. Used to determine the width of the vertical active space in 3D frame packed modes.
 358          * OPPBUF_ACTIVE_WIDTH must be integer divisible by the total number of segments."
 359          */
 360         REG_UPDATE(OPPBUF_CONTROL, OPPBUF_DISPLAY_SEGMENTATION, oppbuf->mso_segmentation);
 361 
 362         /* description  "Specifies the number of overlap pixels (1-8 overlapping pixels supported), used in multi-segment mode (DP-MSO operation)" */
 363         REG_UPDATE(OPPBUF_CONTROL, OPPBUF_OVERLAP_PIXEL_NUM, oppbuf->mso_overlap_pixel_num);
 364 
 365         /* description  "Specifies the number of times a pixel is replicated (0-15 pixel replications supported).
 366          * A value of 0 disables replication. The total number of times a pixel is output is OPPBUF_PIXEL_REPETITION + 1."
 367          */
 368         REG_UPDATE(OPPBUF_CONTROL, OPPBUF_PIXEL_REPETITION, oppbuf->pixel_repetition);
 369 
 370 #if defined(CONFIG_DRM_AMD_DC_DCN2_0)
 371         /* Controls the number of padded pixels at the end of a segment */
 372         if (REG(OPPBUF_CONTROL1))
 373                 REG_UPDATE(OPPBUF_CONTROL1, OPPBUF_NUM_SEGMENT_PADDED_PIXELS, oppbuf->num_segment_padded_pixels);
 374 #endif
 375 }
 376 
 377 void opp1_pipe_clock_control(struct output_pixel_processor *opp, bool enable)
 378 {
 379         struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
 380         uint32_t regval = enable ? 1 : 0;
 381 
 382         REG_UPDATE(OPP_PIPE_CONTROL, OPP_PIPE_CLOCK_EN, regval);
 383 }
 384 
 385 /*****************************************/
 386 /* Constructor, Destructor               */
 387 /*****************************************/
 388 
 389 void opp1_destroy(struct output_pixel_processor **opp)
 390 {
 391         kfree(TO_DCN10_OPP(*opp));
 392         *opp = NULL;
 393 }
 394 
 395 static const struct opp_funcs dcn10_opp_funcs = {
 396                 .opp_set_dyn_expansion = opp1_set_dyn_expansion,
 397                 .opp_program_fmt = opp1_program_fmt,
 398                 .opp_program_bit_depth_reduction = opp1_program_bit_depth_reduction,
 399                 .opp_program_stereo = opp1_program_stereo,
 400                 .opp_pipe_clock_control = opp1_pipe_clock_control,
 401 #if defined(CONFIG_DRM_AMD_DC_DCN2_0)
 402                 .opp_set_disp_pattern_generator = NULL,
 403 #endif
 404                 .opp_destroy = opp1_destroy
 405 };
 406 
 407 void dcn10_opp_construct(struct dcn10_opp *oppn10,
 408         struct dc_context *ctx,
 409         uint32_t inst,
 410         const struct dcn10_opp_registers *regs,
 411         const struct dcn10_opp_shift *opp_shift,
 412         const struct dcn10_opp_mask *opp_mask)
 413 {
 414 
 415         oppn10->base.ctx = ctx;
 416         oppn10->base.inst = inst;
 417         oppn10->base.funcs = &dcn10_opp_funcs;
 418 
 419         oppn10->regs = regs;
 420         oppn10->opp_shift = opp_shift;
 421         oppn10->opp_mask = opp_mask;
 422 }

/* [<][>][^][v][top][bottom][index][help] */