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