linux/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c
<<
>>
Prefs
   1/*
   2 * Copyright 2007-8 Advanced Micro Devices, Inc.
   3 * Copyright 2008 Red Hat Inc.
   4 *
   5 * Permission is hereby granted, free of charge, to any person obtaining a
   6 * copy of this software and associated documentation files (the "Software"),
   7 * to deal in the Software without restriction, including without limitation
   8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   9 * and/or sell copies of the Software, and to permit persons to whom the
  10 * Software is furnished to do so, subject to the following conditions:
  11 *
  12 * The above copyright notice and this permission notice shall be included in
  13 * all copies or substantial portions of the Software.
  14 *
  15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  18 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  21 * OTHER DEALINGS IN THE SOFTWARE.
  22 *
  23 * Authors: Dave Airlie
  24 *          Alex Deucher
  25 */
  26#include <drm/drmP.h>
  27#include <drm/drm_crtc_helper.h>
  28#include <drm/amdgpu_drm.h>
  29#include <drm/drm_fixed.h>
  30#include "amdgpu.h"
  31#include "atom.h"
  32#include "atom-bits.h"
  33#include "atombios_encoders.h"
  34#include "atombios_crtc.h"
  35#include "amdgpu_atombios.h"
  36#include "amdgpu_pll.h"
  37#include "amdgpu_connectors.h"
  38
  39void amdgpu_atombios_crtc_overscan_setup(struct drm_crtc *crtc,
  40                                  struct drm_display_mode *mode,
  41                                  struct drm_display_mode *adjusted_mode)
  42{
  43        struct drm_device *dev = crtc->dev;
  44        struct amdgpu_device *adev = dev->dev_private;
  45        struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
  46        SET_CRTC_OVERSCAN_PS_ALLOCATION args;
  47        int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan);
  48        int a1, a2;
  49
  50        memset(&args, 0, sizeof(args));
  51
  52        args.ucCRTC = amdgpu_crtc->crtc_id;
  53
  54        switch (amdgpu_crtc->rmx_type) {
  55        case RMX_CENTER:
  56                args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2);
  57                args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2);
  58                args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2);
  59                args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2);
  60                break;
  61        case RMX_ASPECT:
  62                a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay;
  63                a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay;
  64
  65                if (a1 > a2) {
  66                        args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2);
  67                        args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2);
  68                } else if (a2 > a1) {
  69                        args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2);
  70                        args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2);
  71                }
  72                break;
  73        case RMX_FULL:
  74        default:
  75                args.usOverscanRight = cpu_to_le16(amdgpu_crtc->h_border);
  76                args.usOverscanLeft = cpu_to_le16(amdgpu_crtc->h_border);
  77                args.usOverscanBottom = cpu_to_le16(amdgpu_crtc->v_border);
  78                args.usOverscanTop = cpu_to_le16(amdgpu_crtc->v_border);
  79                break;
  80        }
  81        amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
  82}
  83
  84void amdgpu_atombios_crtc_scaler_setup(struct drm_crtc *crtc)
  85{
  86        struct drm_device *dev = crtc->dev;
  87        struct amdgpu_device *adev = dev->dev_private;
  88        struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
  89        ENABLE_SCALER_PS_ALLOCATION args;
  90        int index = GetIndexIntoMasterTable(COMMAND, EnableScaler);
  91
  92        memset(&args, 0, sizeof(args));
  93
  94        args.ucScaler = amdgpu_crtc->crtc_id;
  95
  96        switch (amdgpu_crtc->rmx_type) {
  97        case RMX_FULL:
  98                args.ucEnable = ATOM_SCALER_EXPANSION;
  99                break;
 100        case RMX_CENTER:
 101                args.ucEnable = ATOM_SCALER_CENTER;
 102                break;
 103        case RMX_ASPECT:
 104                args.ucEnable = ATOM_SCALER_EXPANSION;
 105                break;
 106        default:
 107                args.ucEnable = ATOM_SCALER_DISABLE;
 108                break;
 109        }
 110        amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
 111}
 112
 113void amdgpu_atombios_crtc_lock(struct drm_crtc *crtc, int lock)
 114{
 115        struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
 116        struct drm_device *dev = crtc->dev;
 117        struct amdgpu_device *adev = dev->dev_private;
 118        int index =
 119            GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters);
 120        ENABLE_CRTC_PS_ALLOCATION args;
 121
 122        memset(&args, 0, sizeof(args));
 123
 124        args.ucCRTC = amdgpu_crtc->crtc_id;
 125        args.ucEnable = lock;
 126
 127        amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
 128}
 129
 130void amdgpu_atombios_crtc_enable(struct drm_crtc *crtc, int state)
 131{
 132        struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
 133        struct drm_device *dev = crtc->dev;
 134        struct amdgpu_device *adev = dev->dev_private;
 135        int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC);
 136        ENABLE_CRTC_PS_ALLOCATION args;
 137
 138        memset(&args, 0, sizeof(args));
 139
 140        args.ucCRTC = amdgpu_crtc->crtc_id;
 141        args.ucEnable = state;
 142
 143        amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
 144}
 145
 146void amdgpu_atombios_crtc_blank(struct drm_crtc *crtc, int state)
 147{
 148        struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
 149        struct drm_device *dev = crtc->dev;
 150        struct amdgpu_device *adev = dev->dev_private;
 151        int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC);
 152        BLANK_CRTC_PS_ALLOCATION args;
 153
 154        memset(&args, 0, sizeof(args));
 155
 156        args.ucCRTC = amdgpu_crtc->crtc_id;
 157        args.ucBlanking = state;
 158
 159        amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
 160}
 161
 162void amdgpu_atombios_crtc_powergate(struct drm_crtc *crtc, int state)
 163{
 164        struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
 165        struct drm_device *dev = crtc->dev;
 166        struct amdgpu_device *adev = dev->dev_private;
 167        int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating);
 168        ENABLE_DISP_POWER_GATING_PS_ALLOCATION args;
 169
 170        memset(&args, 0, sizeof(args));
 171
 172        args.ucDispPipeId = amdgpu_crtc->crtc_id;
 173        args.ucEnable = state;
 174
 175        amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
 176}
 177
 178void amdgpu_atombios_crtc_powergate_init(struct amdgpu_device *adev)
 179{
 180        int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating);
 181        ENABLE_DISP_POWER_GATING_PS_ALLOCATION args;
 182
 183        memset(&args, 0, sizeof(args));
 184
 185        args.ucEnable = ATOM_INIT;
 186
 187        amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
 188}
 189
 190void amdgpu_atombios_crtc_set_dtd_timing(struct drm_crtc *crtc,
 191                                  struct drm_display_mode *mode)
 192{
 193        struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
 194        struct drm_device *dev = crtc->dev;
 195        struct amdgpu_device *adev = dev->dev_private;
 196        SET_CRTC_USING_DTD_TIMING_PARAMETERS args;
 197        int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming);
 198        u16 misc = 0;
 199
 200        memset(&args, 0, sizeof(args));
 201        args.usH_Size = cpu_to_le16(mode->crtc_hdisplay - (amdgpu_crtc->h_border * 2));
 202        args.usH_Blanking_Time =
 203                cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay + (amdgpu_crtc->h_border * 2));
 204        args.usV_Size = cpu_to_le16(mode->crtc_vdisplay - (amdgpu_crtc->v_border * 2));
 205        args.usV_Blanking_Time =
 206                cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay + (amdgpu_crtc->v_border * 2));
 207        args.usH_SyncOffset =
 208                cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay + amdgpu_crtc->h_border);
 209        args.usH_SyncWidth =
 210                cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start);
 211        args.usV_SyncOffset =
 212                cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay + amdgpu_crtc->v_border);
 213        args.usV_SyncWidth =
 214                cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start);
 215        args.ucH_Border = amdgpu_crtc->h_border;
 216        args.ucV_Border = amdgpu_crtc->v_border;
 217
 218        if (mode->flags & DRM_MODE_FLAG_NVSYNC)
 219                misc |= ATOM_VSYNC_POLARITY;
 220        if (mode->flags & DRM_MODE_FLAG_NHSYNC)
 221                misc |= ATOM_HSYNC_POLARITY;
 222        if (mode->flags & DRM_MODE_FLAG_CSYNC)
 223                misc |= ATOM_COMPOSITESYNC;
 224        if (mode->flags & DRM_MODE_FLAG_INTERLACE)
 225                misc |= ATOM_INTERLACE;
 226        if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
 227                misc |= ATOM_DOUBLE_CLOCK_MODE;
 228
 229        args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
 230        args.ucCRTC = amdgpu_crtc->crtc_id;
 231
 232        amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
 233}
 234
 235union atom_enable_ss {
 236        ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1;
 237        ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 v2;
 238        ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 v3;
 239};
 240
 241static void amdgpu_atombios_crtc_program_ss(struct amdgpu_device *adev,
 242                                     int enable,
 243                                     int pll_id,
 244                                     int crtc_id,
 245                                     struct amdgpu_atom_ss *ss)
 246{
 247        unsigned i;
 248        int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL);
 249        union atom_enable_ss args;
 250
 251        if (enable) {
 252                /* Don't mess with SS if percentage is 0 or external ss.
 253                 * SS is already disabled previously, and disabling it
 254                 * again can cause display problems if the pll is already
 255                 * programmed.
 256                 */
 257                if (ss->percentage == 0)
 258                        return;
 259                if (ss->type & ATOM_EXTERNAL_SS_MASK)
 260                        return;
 261        } else {
 262                for (i = 0; i < adev->mode_info.num_crtc; i++) {
 263                        if (adev->mode_info.crtcs[i] &&
 264                            adev->mode_info.crtcs[i]->enabled &&
 265                            i != crtc_id &&
 266                            pll_id == adev->mode_info.crtcs[i]->pll_id) {
 267                                /* one other crtc is using this pll don't turn
 268                                 * off spread spectrum as it might turn off
 269                                 * display on active crtc
 270                                 */
 271                                return;
 272                        }
 273                }
 274        }
 275
 276        memset(&args, 0, sizeof(args));
 277
 278        args.v3.usSpreadSpectrumAmountFrac = cpu_to_le16(0);
 279        args.v3.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
 280        switch (pll_id) {
 281        case ATOM_PPLL1:
 282                args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL;
 283                break;
 284        case ATOM_PPLL2:
 285                args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL;
 286                break;
 287        case ATOM_DCPLL:
 288                args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL;
 289                break;
 290        case ATOM_PPLL_INVALID:
 291                return;
 292        }
 293        args.v3.usSpreadSpectrumAmount = cpu_to_le16(ss->amount);
 294        args.v3.usSpreadSpectrumStep = cpu_to_le16(ss->step);
 295        args.v3.ucEnable = enable;
 296
 297        amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
 298}
 299
 300union adjust_pixel_clock {
 301        ADJUST_DISPLAY_PLL_PS_ALLOCATION v1;
 302        ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 v3;
 303};
 304
 305static u32 amdgpu_atombios_crtc_adjust_pll(struct drm_crtc *crtc,
 306                                    struct drm_display_mode *mode)
 307{
 308        struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
 309        struct drm_device *dev = crtc->dev;
 310        struct amdgpu_device *adev = dev->dev_private;
 311        struct drm_encoder *encoder = amdgpu_crtc->encoder;
 312        struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
 313        struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder);
 314        u32 adjusted_clock = mode->clock;
 315        int encoder_mode = amdgpu_atombios_encoder_get_encoder_mode(encoder);
 316        u32 dp_clock = mode->clock;
 317        u32 clock = mode->clock;
 318        int bpc = amdgpu_crtc->bpc;
 319        bool is_duallink = amdgpu_dig_monitor_is_duallink(encoder, mode->clock);
 320        union adjust_pixel_clock args;
 321        u8 frev, crev;
 322        int index;
 323
 324        amdgpu_crtc->pll_flags = AMDGPU_PLL_USE_FRAC_FB_DIV;
 325
 326        if ((amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
 327            (amdgpu_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)) {
 328                if (connector) {
 329                        struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
 330                        struct amdgpu_connector_atom_dig *dig_connector =
 331                                amdgpu_connector->con_priv;
 332
 333                        dp_clock = dig_connector->dp_clock;
 334                }
 335        }
 336
 337        /* use recommended ref_div for ss */
 338        if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
 339                if (amdgpu_crtc->ss_enabled) {
 340                        if (amdgpu_crtc->ss.refdiv) {
 341                                amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_REF_DIV;
 342                                amdgpu_crtc->pll_reference_div = amdgpu_crtc->ss.refdiv;
 343                                amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_FRAC_FB_DIV;
 344                        }
 345                }
 346        }
 347
 348        /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */
 349        if (amdgpu_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)
 350                adjusted_clock = mode->clock * 2;
 351        if (amdgpu_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
 352                amdgpu_crtc->pll_flags |= AMDGPU_PLL_PREFER_CLOSEST_LOWER;
 353        if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
 354                amdgpu_crtc->pll_flags |= AMDGPU_PLL_IS_LCD;
 355
 356
 357        /* adjust pll for deep color modes */
 358        if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
 359                switch (bpc) {
 360                case 8:
 361                default:
 362                        break;
 363                case 10:
 364                        clock = (clock * 5) / 4;
 365                        break;
 366                case 12:
 367                        clock = (clock * 3) / 2;
 368                        break;
 369                case 16:
 370                        clock = clock * 2;
 371                        break;
 372                }
 373        }
 374
 375        /* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock
 376         * accordingly based on the encoder/transmitter to work around
 377         * special hw requirements.
 378         */
 379        index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll);
 380        if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev,
 381                                   &crev))
 382                return adjusted_clock;
 383
 384        memset(&args, 0, sizeof(args));
 385
 386        switch (frev) {
 387        case 1:
 388                switch (crev) {
 389                case 1:
 390                case 2:
 391                        args.v1.usPixelClock = cpu_to_le16(clock / 10);
 392                        args.v1.ucTransmitterID = amdgpu_encoder->encoder_id;
 393                        args.v1.ucEncodeMode = encoder_mode;
 394                        if (amdgpu_crtc->ss_enabled && amdgpu_crtc->ss.percentage)
 395                                args.v1.ucConfig |=
 396                                        ADJUST_DISPLAY_CONFIG_SS_ENABLE;
 397
 398                        amdgpu_atom_execute_table(adev->mode_info.atom_context,
 399                                           index, (uint32_t *)&args);
 400                        adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10;
 401                        break;
 402                case 3:
 403                        args.v3.sInput.usPixelClock = cpu_to_le16(clock / 10);
 404                        args.v3.sInput.ucTransmitterID = amdgpu_encoder->encoder_id;
 405                        args.v3.sInput.ucEncodeMode = encoder_mode;
 406                        args.v3.sInput.ucDispPllConfig = 0;
 407                        if (amdgpu_crtc->ss_enabled && amdgpu_crtc->ss.percentage)
 408                                args.v3.sInput.ucDispPllConfig |=
 409                                        DISPPLL_CONFIG_SS_ENABLE;
 410                        if (ENCODER_MODE_IS_DP(encoder_mode)) {
 411                                args.v3.sInput.ucDispPllConfig |=
 412                                        DISPPLL_CONFIG_COHERENT_MODE;
 413                                /* 16200 or 27000 */
 414                                args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10);
 415                        } else if (amdgpu_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
 416                                struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
 417                                if (dig->coherent_mode)
 418                                        args.v3.sInput.ucDispPllConfig |=
 419                                                DISPPLL_CONFIG_COHERENT_MODE;
 420                                if (is_duallink)
 421                                        args.v3.sInput.ucDispPllConfig |=
 422                                                DISPPLL_CONFIG_DUAL_LINK;
 423                        }
 424                        if (amdgpu_encoder_get_dp_bridge_encoder_id(encoder) !=
 425                            ENCODER_OBJECT_ID_NONE)
 426                                args.v3.sInput.ucExtTransmitterID =
 427                                        amdgpu_encoder_get_dp_bridge_encoder_id(encoder);
 428                        else
 429                                args.v3.sInput.ucExtTransmitterID = 0;
 430
 431                        amdgpu_atom_execute_table(adev->mode_info.atom_context,
 432                                           index, (uint32_t *)&args);
 433                        adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10;
 434                        if (args.v3.sOutput.ucRefDiv) {
 435                                amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_FRAC_FB_DIV;
 436                                amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_REF_DIV;
 437                                amdgpu_crtc->pll_reference_div = args.v3.sOutput.ucRefDiv;
 438                        }
 439                        if (args.v3.sOutput.ucPostDiv) {
 440                                amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_FRAC_FB_DIV;
 441                                amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_POST_DIV;
 442                                amdgpu_crtc->pll_post_div = args.v3.sOutput.ucPostDiv;
 443                        }
 444                        break;
 445                default:
 446                        DRM_ERROR("Unknown table version %d %d\n", frev, crev);
 447                        return adjusted_clock;
 448                }
 449                break;
 450        default:
 451                DRM_ERROR("Unknown table version %d %d\n", frev, crev);
 452                return adjusted_clock;
 453        }
 454
 455        return adjusted_clock;
 456}
 457
 458union set_pixel_clock {
 459        SET_PIXEL_CLOCK_PS_ALLOCATION base;
 460        PIXEL_CLOCK_PARAMETERS v1;
 461        PIXEL_CLOCK_PARAMETERS_V2 v2;
 462        PIXEL_CLOCK_PARAMETERS_V3 v3;
 463        PIXEL_CLOCK_PARAMETERS_V5 v5;
 464        PIXEL_CLOCK_PARAMETERS_V6 v6;
 465        PIXEL_CLOCK_PARAMETERS_V7 v7;
 466};
 467
 468/* on DCE5, make sure the voltage is high enough to support the
 469 * required disp clk.
 470 */
 471void amdgpu_atombios_crtc_set_disp_eng_pll(struct amdgpu_device *adev,
 472                                           u32 dispclk)
 473{
 474        u8 frev, crev;
 475        int index;
 476        union set_pixel_clock args;
 477
 478        memset(&args, 0, sizeof(args));
 479
 480        index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
 481        if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev,
 482                                   &crev))
 483                return;
 484
 485        switch (frev) {
 486        case 1:
 487                switch (crev) {
 488                case 5:
 489                        /* if the default dcpll clock is specified,
 490                         * SetPixelClock provides the dividers
 491                         */
 492                        args.v5.ucCRTC = ATOM_CRTC_INVALID;
 493                        args.v5.usPixelClock = cpu_to_le16(dispclk);
 494                        args.v5.ucPpll = ATOM_DCPLL;
 495                        break;
 496                case 6:
 497                        /* if the default dcpll clock is specified,
 498                         * SetPixelClock provides the dividers
 499                         */
 500                        args.v6.ulDispEngClkFreq = cpu_to_le32(dispclk);
 501                        if (adev->asic_type == CHIP_TAHITI ||
 502                            adev->asic_type == CHIP_PITCAIRN ||
 503                            adev->asic_type == CHIP_VERDE ||
 504                            adev->asic_type == CHIP_OLAND)
 505                                args.v6.ucPpll = ATOM_PPLL0;
 506                        else
 507                                args.v6.ucPpll = ATOM_EXT_PLL1;
 508                        break;
 509                default:
 510                        DRM_ERROR("Unknown table version %d %d\n", frev, crev);
 511                        return;
 512                }
 513                break;
 514        default:
 515                DRM_ERROR("Unknown table version %d %d\n", frev, crev);
 516                return;
 517        }
 518        amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
 519}
 520
 521union set_dce_clock {
 522        SET_DCE_CLOCK_PS_ALLOCATION_V1_1 v1_1;
 523        SET_DCE_CLOCK_PS_ALLOCATION_V2_1 v2_1;
 524};
 525
 526u32 amdgpu_atombios_crtc_set_dce_clock(struct amdgpu_device *adev,
 527                                       u32 freq, u8 clk_type, u8 clk_src)
 528{
 529        u8 frev, crev;
 530        int index;
 531        union set_dce_clock args;
 532        u32 ret_freq = 0;
 533
 534        memset(&args, 0, sizeof(args));
 535
 536        index = GetIndexIntoMasterTable(COMMAND, SetDCEClock);
 537        if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev,
 538                                   &crev))
 539                return 0;
 540
 541        switch (frev) {
 542        case 2:
 543                switch (crev) {
 544                case 1:
 545                        args.v2_1.asParam.ulDCEClkFreq = cpu_to_le32(freq); /* 10kHz units */
 546                        args.v2_1.asParam.ucDCEClkType = clk_type;
 547                        args.v2_1.asParam.ucDCEClkSrc = clk_src;
 548                        amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
 549                        ret_freq = le32_to_cpu(args.v2_1.asParam.ulDCEClkFreq) * 10;
 550                        break;
 551                default:
 552                        DRM_ERROR("Unknown table version %d %d\n", frev, crev);
 553                        return 0;
 554                }
 555                break;
 556        default:
 557                DRM_ERROR("Unknown table version %d %d\n", frev, crev);
 558                return 0;
 559        }
 560
 561        return ret_freq;
 562}
 563
 564static bool is_pixel_clock_source_from_pll(u32 encoder_mode, int pll_id)
 565{
 566        if (ENCODER_MODE_IS_DP(encoder_mode)) {
 567                if (pll_id < ATOM_EXT_PLL1)
 568                        return true;
 569                else
 570                        return false;
 571        } else {
 572                return true;
 573        }
 574}
 575
 576void amdgpu_atombios_crtc_program_pll(struct drm_crtc *crtc,
 577                                      u32 crtc_id,
 578                                      int pll_id,
 579                                      u32 encoder_mode,
 580                                      u32 encoder_id,
 581                                      u32 clock,
 582                                      u32 ref_div,
 583                                      u32 fb_div,
 584                                      u32 frac_fb_div,
 585                                      u32 post_div,
 586                                      int bpc,
 587                                      bool ss_enabled,
 588                                      struct amdgpu_atom_ss *ss)
 589{
 590        struct drm_device *dev = crtc->dev;
 591        struct amdgpu_device *adev = dev->dev_private;
 592        u8 frev, crev;
 593        int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
 594        union set_pixel_clock args;
 595
 596        memset(&args, 0, sizeof(args));
 597
 598        if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev,
 599                                   &crev))
 600                return;
 601
 602        switch (frev) {
 603        case 1:
 604                switch (crev) {
 605                case 1:
 606                        if (clock == ATOM_DISABLE)
 607                                return;
 608                        args.v1.usPixelClock = cpu_to_le16(clock / 10);
 609                        args.v1.usRefDiv = cpu_to_le16(ref_div);
 610                        args.v1.usFbDiv = cpu_to_le16(fb_div);
 611                        args.v1.ucFracFbDiv = frac_fb_div;
 612                        args.v1.ucPostDiv = post_div;
 613                        args.v1.ucPpll = pll_id;
 614                        args.v1.ucCRTC = crtc_id;
 615                        args.v1.ucRefDivSrc = 1;
 616                        break;
 617                case 2:
 618                        args.v2.usPixelClock = cpu_to_le16(clock / 10);
 619                        args.v2.usRefDiv = cpu_to_le16(ref_div);
 620                        args.v2.usFbDiv = cpu_to_le16(fb_div);
 621                        args.v2.ucFracFbDiv = frac_fb_div;
 622                        args.v2.ucPostDiv = post_div;
 623                        args.v2.ucPpll = pll_id;
 624                        args.v2.ucCRTC = crtc_id;
 625                        args.v2.ucRefDivSrc = 1;
 626                        break;
 627                case 3:
 628                        args.v3.usPixelClock = cpu_to_le16(clock / 10);
 629                        args.v3.usRefDiv = cpu_to_le16(ref_div);
 630                        args.v3.usFbDiv = cpu_to_le16(fb_div);
 631                        args.v3.ucFracFbDiv = frac_fb_div;
 632                        args.v3.ucPostDiv = post_div;
 633                        args.v3.ucPpll = pll_id;
 634                        if (crtc_id == ATOM_CRTC2)
 635                                args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC2;
 636                        else
 637                                args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC1;
 638                        if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
 639                                args.v3.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC;
 640                        args.v3.ucTransmitterId = encoder_id;
 641                        args.v3.ucEncoderMode = encoder_mode;
 642                        break;
 643                case 5:
 644                        args.v5.ucCRTC = crtc_id;
 645                        args.v5.usPixelClock = cpu_to_le16(clock / 10);
 646                        args.v5.ucRefDiv = ref_div;
 647                        args.v5.usFbDiv = cpu_to_le16(fb_div);
 648                        args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
 649                        args.v5.ucPostDiv = post_div;
 650                        args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */
 651                        if ((ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) &&
 652                            (pll_id < ATOM_EXT_PLL1))
 653                                args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_REF_DIV_SRC;
 654                        if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
 655                                switch (bpc) {
 656                                case 8:
 657                                default:
 658                                        args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP;
 659                                        break;
 660                                case 10:
 661                                        /* yes this is correct, the atom define is wrong */
 662                                        args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_32BPP;
 663                                        break;
 664                                case 12:
 665                                        /* yes this is correct, the atom define is wrong */
 666                                        args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP;
 667                                        break;
 668                                }
 669                        }
 670                        args.v5.ucTransmitterID = encoder_id;
 671                        args.v5.ucEncoderMode = encoder_mode;
 672                        args.v5.ucPpll = pll_id;
 673                        break;
 674                case 6:
 675                        args.v6.ulDispEngClkFreq = cpu_to_le32(crtc_id << 24 | clock / 10);
 676                        args.v6.ucRefDiv = ref_div;
 677                        args.v6.usFbDiv = cpu_to_le16(fb_div);
 678                        args.v6.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
 679                        args.v6.ucPostDiv = post_div;
 680                        args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */
 681                        if ((ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) &&
 682                            (pll_id < ATOM_EXT_PLL1) &&
 683                            !is_pixel_clock_source_from_pll(encoder_mode, pll_id))
 684                                args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_REF_DIV_SRC;
 685                        if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
 686                                switch (bpc) {
 687                                case 8:
 688                                default:
 689                                        args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP;
 690                                        break;
 691                                case 10:
 692                                        args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP_V6;
 693                                        break;
 694                                case 12:
 695                                        args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP_V6;
 696                                        break;
 697                                case 16:
 698                                        args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP;
 699                                        break;
 700                                }
 701                        }
 702                        args.v6.ucTransmitterID = encoder_id;
 703                        args.v6.ucEncoderMode = encoder_mode;
 704                        args.v6.ucPpll = pll_id;
 705                        break;
 706                case 7:
 707                        args.v7.ulPixelClock = cpu_to_le32(clock * 10); /* 100 hz units */
 708                        args.v7.ucMiscInfo = 0;
 709                        if ((encoder_mode == ATOM_ENCODER_MODE_DVI) &&
 710                            (clock > 165000))
 711                                args.v7.ucMiscInfo |= PIXEL_CLOCK_V7_MISC_DVI_DUALLINK_EN;
 712                        args.v7.ucCRTC = crtc_id;
 713                        if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
 714                                switch (bpc) {
 715                                case 8:
 716                                default:
 717                                        args.v7.ucDeepColorRatio = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_DIS;
 718                                        break;
 719                                case 10:
 720                                        args.v7.ucDeepColorRatio = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_5_4;
 721                                        break;
 722                                case 12:
 723                                        args.v7.ucDeepColorRatio = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_3_2;
 724                                        break;
 725                                case 16:
 726                                        args.v7.ucDeepColorRatio = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_2_1;
 727                                        break;
 728                                }
 729                        }
 730                        args.v7.ucTransmitterID = encoder_id;
 731                        args.v7.ucEncoderMode = encoder_mode;
 732                        args.v7.ucPpll = pll_id;
 733                        break;
 734                default:
 735                        DRM_ERROR("Unknown table version %d %d\n", frev, crev);
 736                        return;
 737                }
 738                break;
 739        default:
 740                DRM_ERROR("Unknown table version %d %d\n", frev, crev);
 741                return;
 742        }
 743
 744        amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
 745}
 746
 747int amdgpu_atombios_crtc_prepare_pll(struct drm_crtc *crtc,
 748                              struct drm_display_mode *mode)
 749{
 750        struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
 751        struct drm_device *dev = crtc->dev;
 752        struct amdgpu_device *adev = dev->dev_private;
 753        struct amdgpu_encoder *amdgpu_encoder =
 754                to_amdgpu_encoder(amdgpu_crtc->encoder);
 755        int encoder_mode = amdgpu_atombios_encoder_get_encoder_mode(amdgpu_crtc->encoder);
 756
 757        amdgpu_crtc->bpc = 8;
 758        amdgpu_crtc->ss_enabled = false;
 759
 760        if ((amdgpu_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
 761            (amdgpu_encoder_get_dp_bridge_encoder_id(amdgpu_crtc->encoder) != ENCODER_OBJECT_ID_NONE)) {
 762                struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
 763                struct drm_connector *connector =
 764                        amdgpu_get_connector_for_encoder(amdgpu_crtc->encoder);
 765                struct amdgpu_connector *amdgpu_connector =
 766                        to_amdgpu_connector(connector);
 767                struct amdgpu_connector_atom_dig *dig_connector =
 768                        amdgpu_connector->con_priv;
 769                int dp_clock;
 770
 771                /* Assign mode clock for hdmi deep color max clock limit check */
 772                amdgpu_connector->pixelclock_for_modeset = mode->clock;
 773                amdgpu_crtc->bpc = amdgpu_connector_get_monitor_bpc(connector);
 774
 775                switch (encoder_mode) {
 776                case ATOM_ENCODER_MODE_DP_MST:
 777                case ATOM_ENCODER_MODE_DP:
 778                        /* DP/eDP */
 779                        dp_clock = dig_connector->dp_clock / 10;
 780                        amdgpu_crtc->ss_enabled =
 781                                amdgpu_atombios_get_asic_ss_info(adev, &amdgpu_crtc->ss,
 782                                                                 ASIC_INTERNAL_SS_ON_DP,
 783                                                                 dp_clock);
 784                        break;
 785                case ATOM_ENCODER_MODE_LVDS:
 786                        amdgpu_crtc->ss_enabled =
 787                                amdgpu_atombios_get_asic_ss_info(adev,
 788                                                                 &amdgpu_crtc->ss,
 789                                                                 dig->lcd_ss_id,
 790                                                                 mode->clock / 10);
 791                        break;
 792                case ATOM_ENCODER_MODE_DVI:
 793                        amdgpu_crtc->ss_enabled =
 794                                amdgpu_atombios_get_asic_ss_info(adev,
 795                                                                 &amdgpu_crtc->ss,
 796                                                                 ASIC_INTERNAL_SS_ON_TMDS,
 797                                                                 mode->clock / 10);
 798                        break;
 799                case ATOM_ENCODER_MODE_HDMI:
 800                        amdgpu_crtc->ss_enabled =
 801                                amdgpu_atombios_get_asic_ss_info(adev,
 802                                                                 &amdgpu_crtc->ss,
 803                                                                 ASIC_INTERNAL_SS_ON_HDMI,
 804                                                                 mode->clock / 10);
 805                        break;
 806                default:
 807                        break;
 808                }
 809        }
 810
 811        /* adjust pixel clock as needed */
 812        amdgpu_crtc->adjusted_clock = amdgpu_atombios_crtc_adjust_pll(crtc, mode);
 813
 814        return 0;
 815}
 816
 817void amdgpu_atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
 818{
 819        struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
 820        struct drm_device *dev = crtc->dev;
 821        struct amdgpu_device *adev = dev->dev_private;
 822        struct amdgpu_encoder *amdgpu_encoder =
 823                to_amdgpu_encoder(amdgpu_crtc->encoder);
 824        u32 pll_clock = mode->clock;
 825        u32 clock = mode->clock;
 826        u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0;
 827        struct amdgpu_pll *pll;
 828        int encoder_mode = amdgpu_atombios_encoder_get_encoder_mode(amdgpu_crtc->encoder);
 829
 830        /* pass the actual clock to amdgpu_atombios_crtc_program_pll for HDMI */
 831        if ((encoder_mode == ATOM_ENCODER_MODE_HDMI) &&
 832            (amdgpu_crtc->bpc > 8))
 833                clock = amdgpu_crtc->adjusted_clock;
 834
 835        switch (amdgpu_crtc->pll_id) {
 836        case ATOM_PPLL1:
 837                pll = &adev->clock.ppll[0];
 838                break;
 839        case ATOM_PPLL2:
 840                pll = &adev->clock.ppll[1];
 841                break;
 842        case ATOM_PPLL0:
 843        case ATOM_PPLL_INVALID:
 844        default:
 845                pll = &adev->clock.ppll[2];
 846                break;
 847        }
 848
 849        /* update pll params */
 850        pll->flags = amdgpu_crtc->pll_flags;
 851        pll->reference_div = amdgpu_crtc->pll_reference_div;
 852        pll->post_div = amdgpu_crtc->pll_post_div;
 853
 854        amdgpu_pll_compute(pll, amdgpu_crtc->adjusted_clock, &pll_clock,
 855                            &fb_div, &frac_fb_div, &ref_div, &post_div);
 856
 857        amdgpu_atombios_crtc_program_ss(adev, ATOM_DISABLE, amdgpu_crtc->pll_id,
 858                                 amdgpu_crtc->crtc_id, &amdgpu_crtc->ss);
 859
 860        amdgpu_atombios_crtc_program_pll(crtc, amdgpu_crtc->crtc_id, amdgpu_crtc->pll_id,
 861                                  encoder_mode, amdgpu_encoder->encoder_id, clock,
 862                                  ref_div, fb_div, frac_fb_div, post_div,
 863                                  amdgpu_crtc->bpc, amdgpu_crtc->ss_enabled, &amdgpu_crtc->ss);
 864
 865        if (amdgpu_crtc->ss_enabled) {
 866                /* calculate ss amount and step size */
 867                u32 step_size;
 868                u32 amount = (((fb_div * 10) + frac_fb_div) *
 869                              (u32)amdgpu_crtc->ss.percentage) /
 870                        (100 * (u32)amdgpu_crtc->ss.percentage_divider);
 871                amdgpu_crtc->ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK;
 872                amdgpu_crtc->ss.amount |= ((amount - (amount / 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) &
 873                        ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK;
 874                if (amdgpu_crtc->ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD)
 875                        step_size = (4 * amount * ref_div * ((u32)amdgpu_crtc->ss.rate * 2048)) /
 876                                (125 * 25 * pll->reference_freq / 100);
 877                else
 878                        step_size = (2 * amount * ref_div * ((u32)amdgpu_crtc->ss.rate * 2048)) /
 879                                (125 * 25 * pll->reference_freq / 100);
 880                amdgpu_crtc->ss.step = step_size;
 881
 882                amdgpu_atombios_crtc_program_ss(adev, ATOM_ENABLE, amdgpu_crtc->pll_id,
 883                                         amdgpu_crtc->crtc_id, &amdgpu_crtc->ss);
 884        }
 885}
 886
 887