0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027 #include <drm/drm_crtc_helper.h>
0028 #include <drm/amdgpu_drm.h>
0029 #include <drm/drm_fixed.h>
0030 #include "amdgpu.h"
0031 #include "atom.h"
0032 #include "atom-bits.h"
0033 #include "atombios_encoders.h"
0034 #include "atombios_crtc.h"
0035 #include "amdgpu_atombios.h"
0036 #include "amdgpu_pll.h"
0037 #include "amdgpu_connectors.h"
0038
0039 void amdgpu_atombios_crtc_overscan_setup(struct drm_crtc *crtc,
0040 struct drm_display_mode *mode,
0041 struct drm_display_mode *adjusted_mode)
0042 {
0043 struct drm_device *dev = crtc->dev;
0044 struct amdgpu_device *adev = drm_to_adev(dev);
0045 struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
0046 SET_CRTC_OVERSCAN_PS_ALLOCATION args;
0047 int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan);
0048 int a1, a2;
0049
0050 memset(&args, 0, sizeof(args));
0051
0052 args.ucCRTC = amdgpu_crtc->crtc_id;
0053
0054 switch (amdgpu_crtc->rmx_type) {
0055 case RMX_CENTER:
0056 args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2);
0057 args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2);
0058 args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2);
0059 args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2);
0060 break;
0061 case RMX_ASPECT:
0062 a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay;
0063 a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay;
0064
0065 if (a1 > a2) {
0066 args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2);
0067 args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2);
0068 } else if (a2 > a1) {
0069 args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2);
0070 args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2);
0071 }
0072 break;
0073 case RMX_FULL:
0074 default:
0075 args.usOverscanRight = cpu_to_le16(amdgpu_crtc->h_border);
0076 args.usOverscanLeft = cpu_to_le16(amdgpu_crtc->h_border);
0077 args.usOverscanBottom = cpu_to_le16(amdgpu_crtc->v_border);
0078 args.usOverscanTop = cpu_to_le16(amdgpu_crtc->v_border);
0079 break;
0080 }
0081 amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
0082 }
0083
0084 void amdgpu_atombios_crtc_scaler_setup(struct drm_crtc *crtc)
0085 {
0086 struct drm_device *dev = crtc->dev;
0087 struct amdgpu_device *adev = drm_to_adev(dev);
0088 struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
0089 ENABLE_SCALER_PS_ALLOCATION args;
0090 int index = GetIndexIntoMasterTable(COMMAND, EnableScaler);
0091
0092 memset(&args, 0, sizeof(args));
0093
0094 args.ucScaler = amdgpu_crtc->crtc_id;
0095
0096 switch (amdgpu_crtc->rmx_type) {
0097 case RMX_FULL:
0098 args.ucEnable = ATOM_SCALER_EXPANSION;
0099 break;
0100 case RMX_CENTER:
0101 args.ucEnable = ATOM_SCALER_CENTER;
0102 break;
0103 case RMX_ASPECT:
0104 args.ucEnable = ATOM_SCALER_EXPANSION;
0105 break;
0106 default:
0107 args.ucEnable = ATOM_SCALER_DISABLE;
0108 break;
0109 }
0110 amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
0111 }
0112
0113 void amdgpu_atombios_crtc_lock(struct drm_crtc *crtc, int lock)
0114 {
0115 struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
0116 struct drm_device *dev = crtc->dev;
0117 struct amdgpu_device *adev = drm_to_adev(dev);
0118 int index =
0119 GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters);
0120 ENABLE_CRTC_PS_ALLOCATION args;
0121
0122 memset(&args, 0, sizeof(args));
0123
0124 args.ucCRTC = amdgpu_crtc->crtc_id;
0125 args.ucEnable = lock;
0126
0127 amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
0128 }
0129
0130 void amdgpu_atombios_crtc_enable(struct drm_crtc *crtc, int state)
0131 {
0132 struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
0133 struct drm_device *dev = crtc->dev;
0134 struct amdgpu_device *adev = drm_to_adev(dev);
0135 int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC);
0136 ENABLE_CRTC_PS_ALLOCATION args;
0137
0138 memset(&args, 0, sizeof(args));
0139
0140 args.ucCRTC = amdgpu_crtc->crtc_id;
0141 args.ucEnable = state;
0142
0143 amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
0144 }
0145
0146 void amdgpu_atombios_crtc_blank(struct drm_crtc *crtc, int state)
0147 {
0148 struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
0149 struct drm_device *dev = crtc->dev;
0150 struct amdgpu_device *adev = drm_to_adev(dev);
0151 int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC);
0152 BLANK_CRTC_PS_ALLOCATION args;
0153
0154 memset(&args, 0, sizeof(args));
0155
0156 args.ucCRTC = amdgpu_crtc->crtc_id;
0157 args.ucBlanking = state;
0158
0159 amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
0160 }
0161
0162 void amdgpu_atombios_crtc_powergate(struct drm_crtc *crtc, int state)
0163 {
0164 struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
0165 struct drm_device *dev = crtc->dev;
0166 struct amdgpu_device *adev = drm_to_adev(dev);
0167 int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating);
0168 ENABLE_DISP_POWER_GATING_PS_ALLOCATION args;
0169
0170 memset(&args, 0, sizeof(args));
0171
0172 args.ucDispPipeId = amdgpu_crtc->crtc_id;
0173 args.ucEnable = state;
0174
0175 amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
0176 }
0177
0178 void amdgpu_atombios_crtc_powergate_init(struct amdgpu_device *adev)
0179 {
0180 int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating);
0181 ENABLE_DISP_POWER_GATING_PS_ALLOCATION args;
0182
0183 memset(&args, 0, sizeof(args));
0184
0185 args.ucEnable = ATOM_INIT;
0186
0187 amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
0188 }
0189
0190 void amdgpu_atombios_crtc_set_dtd_timing(struct drm_crtc *crtc,
0191 struct drm_display_mode *mode)
0192 {
0193 struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
0194 struct drm_device *dev = crtc->dev;
0195 struct amdgpu_device *adev = drm_to_adev(dev);
0196 SET_CRTC_USING_DTD_TIMING_PARAMETERS args;
0197 int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming);
0198 u16 misc = 0;
0199
0200 memset(&args, 0, sizeof(args));
0201 args.usH_Size = cpu_to_le16(mode->crtc_hdisplay - (amdgpu_crtc->h_border * 2));
0202 args.usH_Blanking_Time =
0203 cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay + (amdgpu_crtc->h_border * 2));
0204 args.usV_Size = cpu_to_le16(mode->crtc_vdisplay - (amdgpu_crtc->v_border * 2));
0205 args.usV_Blanking_Time =
0206 cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay + (amdgpu_crtc->v_border * 2));
0207 args.usH_SyncOffset =
0208 cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay + amdgpu_crtc->h_border);
0209 args.usH_SyncWidth =
0210 cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start);
0211 args.usV_SyncOffset =
0212 cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay + amdgpu_crtc->v_border);
0213 args.usV_SyncWidth =
0214 cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start);
0215 args.ucH_Border = amdgpu_crtc->h_border;
0216 args.ucV_Border = amdgpu_crtc->v_border;
0217
0218 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
0219 misc |= ATOM_VSYNC_POLARITY;
0220 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
0221 misc |= ATOM_HSYNC_POLARITY;
0222 if (mode->flags & DRM_MODE_FLAG_CSYNC)
0223 misc |= ATOM_COMPOSITESYNC;
0224 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
0225 misc |= ATOM_INTERLACE;
0226 if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
0227 misc |= ATOM_DOUBLE_CLOCK_MODE;
0228
0229 args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
0230 args.ucCRTC = amdgpu_crtc->crtc_id;
0231
0232 amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
0233 }
0234
0235 union atom_enable_ss {
0236 ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1;
0237 ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 v2;
0238 ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 v3;
0239 };
0240
0241 static void amdgpu_atombios_crtc_program_ss(struct amdgpu_device *adev,
0242 int enable,
0243 int pll_id,
0244 int crtc_id,
0245 struct amdgpu_atom_ss *ss)
0246 {
0247 unsigned i;
0248 int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL);
0249 union atom_enable_ss args;
0250
0251 if (enable) {
0252
0253
0254
0255
0256
0257 if (ss->percentage == 0)
0258 return;
0259 if (ss->type & ATOM_EXTERNAL_SS_MASK)
0260 return;
0261 } else {
0262 for (i = 0; i < adev->mode_info.num_crtc; i++) {
0263 if (adev->mode_info.crtcs[i] &&
0264 adev->mode_info.crtcs[i]->enabled &&
0265 i != crtc_id &&
0266 pll_id == adev->mode_info.crtcs[i]->pll_id) {
0267
0268
0269
0270
0271 return;
0272 }
0273 }
0274 }
0275
0276 memset(&args, 0, sizeof(args));
0277
0278 args.v3.usSpreadSpectrumAmountFrac = cpu_to_le16(0);
0279 args.v3.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
0280 switch (pll_id) {
0281 case ATOM_PPLL1:
0282 args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL;
0283 break;
0284 case ATOM_PPLL2:
0285 args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL;
0286 break;
0287 case ATOM_DCPLL:
0288 args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL;
0289 break;
0290 case ATOM_PPLL_INVALID:
0291 return;
0292 }
0293 args.v3.usSpreadSpectrumAmount = cpu_to_le16(ss->amount);
0294 args.v3.usSpreadSpectrumStep = cpu_to_le16(ss->step);
0295 args.v3.ucEnable = enable;
0296
0297 amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
0298 }
0299
0300 union adjust_pixel_clock {
0301 ADJUST_DISPLAY_PLL_PS_ALLOCATION v1;
0302 ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 v3;
0303 };
0304
0305 static u32 amdgpu_atombios_crtc_adjust_pll(struct drm_crtc *crtc,
0306 struct drm_display_mode *mode)
0307 {
0308 struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
0309 struct drm_device *dev = crtc->dev;
0310 struct amdgpu_device *adev = drm_to_adev(dev);
0311 struct drm_encoder *encoder = amdgpu_crtc->encoder;
0312 struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
0313 struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder);
0314 u32 adjusted_clock = mode->clock;
0315 int encoder_mode = amdgpu_atombios_encoder_get_encoder_mode(encoder);
0316 u32 dp_clock = mode->clock;
0317 u32 clock = mode->clock;
0318 int bpc = amdgpu_crtc->bpc;
0319 bool is_duallink = amdgpu_dig_monitor_is_duallink(encoder, mode->clock);
0320 union adjust_pixel_clock args;
0321 u8 frev, crev;
0322 int index;
0323
0324 amdgpu_crtc->pll_flags = AMDGPU_PLL_USE_FRAC_FB_DIV;
0325
0326 if ((amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
0327 (amdgpu_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)) {
0328 if (connector) {
0329 struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
0330 struct amdgpu_connector_atom_dig *dig_connector =
0331 amdgpu_connector->con_priv;
0332
0333 dp_clock = dig_connector->dp_clock;
0334 }
0335 }
0336
0337
0338 if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
0339 if (amdgpu_crtc->ss_enabled) {
0340 if (amdgpu_crtc->ss.refdiv) {
0341 amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_REF_DIV;
0342 amdgpu_crtc->pll_reference_div = amdgpu_crtc->ss.refdiv;
0343 amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_FRAC_FB_DIV;
0344 }
0345 }
0346 }
0347
0348
0349 if (amdgpu_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)
0350 adjusted_clock = mode->clock * 2;
0351 if (amdgpu_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
0352 amdgpu_crtc->pll_flags |= AMDGPU_PLL_PREFER_CLOSEST_LOWER;
0353 if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
0354 amdgpu_crtc->pll_flags |= AMDGPU_PLL_IS_LCD;
0355
0356
0357
0358 if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
0359 switch (bpc) {
0360 case 8:
0361 default:
0362 break;
0363 case 10:
0364 clock = (clock * 5) / 4;
0365 break;
0366 case 12:
0367 clock = (clock * 3) / 2;
0368 break;
0369 case 16:
0370 clock = clock * 2;
0371 break;
0372 }
0373 }
0374
0375
0376
0377
0378
0379 index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll);
0380 if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev,
0381 &crev))
0382 return adjusted_clock;
0383
0384 memset(&args, 0, sizeof(args));
0385
0386 switch (frev) {
0387 case 1:
0388 switch (crev) {
0389 case 1:
0390 case 2:
0391 args.v1.usPixelClock = cpu_to_le16(clock / 10);
0392 args.v1.ucTransmitterID = amdgpu_encoder->encoder_id;
0393 args.v1.ucEncodeMode = encoder_mode;
0394 if (amdgpu_crtc->ss_enabled && amdgpu_crtc->ss.percentage)
0395 args.v1.ucConfig |=
0396 ADJUST_DISPLAY_CONFIG_SS_ENABLE;
0397
0398 amdgpu_atom_execute_table(adev->mode_info.atom_context,
0399 index, (uint32_t *)&args);
0400 adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10;
0401 break;
0402 case 3:
0403 args.v3.sInput.usPixelClock = cpu_to_le16(clock / 10);
0404 args.v3.sInput.ucTransmitterID = amdgpu_encoder->encoder_id;
0405 args.v3.sInput.ucEncodeMode = encoder_mode;
0406 args.v3.sInput.ucDispPllConfig = 0;
0407 if (amdgpu_crtc->ss_enabled && amdgpu_crtc->ss.percentage)
0408 args.v3.sInput.ucDispPllConfig |=
0409 DISPPLL_CONFIG_SS_ENABLE;
0410 if (ENCODER_MODE_IS_DP(encoder_mode)) {
0411 args.v3.sInput.ucDispPllConfig |=
0412 DISPPLL_CONFIG_COHERENT_MODE;
0413
0414 args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10);
0415 } else if (amdgpu_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
0416 struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
0417 if (dig->coherent_mode)
0418 args.v3.sInput.ucDispPllConfig |=
0419 DISPPLL_CONFIG_COHERENT_MODE;
0420 if (is_duallink)
0421 args.v3.sInput.ucDispPllConfig |=
0422 DISPPLL_CONFIG_DUAL_LINK;
0423 }
0424 if (amdgpu_encoder_get_dp_bridge_encoder_id(encoder) !=
0425 ENCODER_OBJECT_ID_NONE)
0426 args.v3.sInput.ucExtTransmitterID =
0427 amdgpu_encoder_get_dp_bridge_encoder_id(encoder);
0428 else
0429 args.v3.sInput.ucExtTransmitterID = 0;
0430
0431 amdgpu_atom_execute_table(adev->mode_info.atom_context,
0432 index, (uint32_t *)&args);
0433 adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10;
0434 if (args.v3.sOutput.ucRefDiv) {
0435 amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_FRAC_FB_DIV;
0436 amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_REF_DIV;
0437 amdgpu_crtc->pll_reference_div = args.v3.sOutput.ucRefDiv;
0438 }
0439 if (args.v3.sOutput.ucPostDiv) {
0440 amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_FRAC_FB_DIV;
0441 amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_POST_DIV;
0442 amdgpu_crtc->pll_post_div = args.v3.sOutput.ucPostDiv;
0443 }
0444 break;
0445 default:
0446 DRM_ERROR("Unknown table version %d %d\n", frev, crev);
0447 return adjusted_clock;
0448 }
0449 break;
0450 default:
0451 DRM_ERROR("Unknown table version %d %d\n", frev, crev);
0452 return adjusted_clock;
0453 }
0454
0455 return adjusted_clock;
0456 }
0457
0458 union set_pixel_clock {
0459 SET_PIXEL_CLOCK_PS_ALLOCATION base;
0460 PIXEL_CLOCK_PARAMETERS v1;
0461 PIXEL_CLOCK_PARAMETERS_V2 v2;
0462 PIXEL_CLOCK_PARAMETERS_V3 v3;
0463 PIXEL_CLOCK_PARAMETERS_V5 v5;
0464 PIXEL_CLOCK_PARAMETERS_V6 v6;
0465 PIXEL_CLOCK_PARAMETERS_V7 v7;
0466 };
0467
0468
0469
0470
0471 void amdgpu_atombios_crtc_set_disp_eng_pll(struct amdgpu_device *adev,
0472 u32 dispclk)
0473 {
0474 u8 frev, crev;
0475 int index;
0476 union set_pixel_clock args;
0477
0478 memset(&args, 0, sizeof(args));
0479
0480 index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
0481 if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev,
0482 &crev))
0483 return;
0484
0485 switch (frev) {
0486 case 1:
0487 switch (crev) {
0488 case 5:
0489
0490
0491
0492 args.v5.ucCRTC = ATOM_CRTC_INVALID;
0493 args.v5.usPixelClock = cpu_to_le16(dispclk);
0494 args.v5.ucPpll = ATOM_DCPLL;
0495 break;
0496 case 6:
0497
0498
0499
0500 args.v6.ulDispEngClkFreq = cpu_to_le32(dispclk);
0501 if (adev->asic_type == CHIP_TAHITI ||
0502 adev->asic_type == CHIP_PITCAIRN ||
0503 adev->asic_type == CHIP_VERDE ||
0504 adev->asic_type == CHIP_OLAND)
0505 args.v6.ucPpll = ATOM_PPLL0;
0506 else
0507 args.v6.ucPpll = ATOM_EXT_PLL1;
0508 break;
0509 default:
0510 DRM_ERROR("Unknown table version %d %d\n", frev, crev);
0511 return;
0512 }
0513 break;
0514 default:
0515 DRM_ERROR("Unknown table version %d %d\n", frev, crev);
0516 return;
0517 }
0518 amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
0519 }
0520
0521 union set_dce_clock {
0522 SET_DCE_CLOCK_PS_ALLOCATION_V1_1 v1_1;
0523 SET_DCE_CLOCK_PS_ALLOCATION_V2_1 v2_1;
0524 };
0525
0526 u32 amdgpu_atombios_crtc_set_dce_clock(struct amdgpu_device *adev,
0527 u32 freq, u8 clk_type, u8 clk_src)
0528 {
0529 u8 frev, crev;
0530 int index;
0531 union set_dce_clock args;
0532 u32 ret_freq = 0;
0533
0534 memset(&args, 0, sizeof(args));
0535
0536 index = GetIndexIntoMasterTable(COMMAND, SetDCEClock);
0537 if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev,
0538 &crev))
0539 return 0;
0540
0541 switch (frev) {
0542 case 2:
0543 switch (crev) {
0544 case 1:
0545 args.v2_1.asParam.ulDCEClkFreq = cpu_to_le32(freq);
0546 args.v2_1.asParam.ucDCEClkType = clk_type;
0547 args.v2_1.asParam.ucDCEClkSrc = clk_src;
0548 amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
0549 ret_freq = le32_to_cpu(args.v2_1.asParam.ulDCEClkFreq) * 10;
0550 break;
0551 default:
0552 DRM_ERROR("Unknown table version %d %d\n", frev, crev);
0553 return 0;
0554 }
0555 break;
0556 default:
0557 DRM_ERROR("Unknown table version %d %d\n", frev, crev);
0558 return 0;
0559 }
0560
0561 return ret_freq;
0562 }
0563
0564 static bool is_pixel_clock_source_from_pll(u32 encoder_mode, int pll_id)
0565 {
0566 if (ENCODER_MODE_IS_DP(encoder_mode)) {
0567 if (pll_id < ATOM_EXT_PLL1)
0568 return true;
0569 else
0570 return false;
0571 } else {
0572 return true;
0573 }
0574 }
0575
0576 void amdgpu_atombios_crtc_program_pll(struct drm_crtc *crtc,
0577 u32 crtc_id,
0578 int pll_id,
0579 u32 encoder_mode,
0580 u32 encoder_id,
0581 u32 clock,
0582 u32 ref_div,
0583 u32 fb_div,
0584 u32 frac_fb_div,
0585 u32 post_div,
0586 int bpc,
0587 bool ss_enabled,
0588 struct amdgpu_atom_ss *ss)
0589 {
0590 struct drm_device *dev = crtc->dev;
0591 struct amdgpu_device *adev = drm_to_adev(dev);
0592 u8 frev, crev;
0593 int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
0594 union set_pixel_clock args;
0595
0596 memset(&args, 0, sizeof(args));
0597
0598 if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev,
0599 &crev))
0600 return;
0601
0602 switch (frev) {
0603 case 1:
0604 switch (crev) {
0605 case 1:
0606 if (clock == ATOM_DISABLE)
0607 return;
0608 args.v1.usPixelClock = cpu_to_le16(clock / 10);
0609 args.v1.usRefDiv = cpu_to_le16(ref_div);
0610 args.v1.usFbDiv = cpu_to_le16(fb_div);
0611 args.v1.ucFracFbDiv = frac_fb_div;
0612 args.v1.ucPostDiv = post_div;
0613 args.v1.ucPpll = pll_id;
0614 args.v1.ucCRTC = crtc_id;
0615 args.v1.ucRefDivSrc = 1;
0616 break;
0617 case 2:
0618 args.v2.usPixelClock = cpu_to_le16(clock / 10);
0619 args.v2.usRefDiv = cpu_to_le16(ref_div);
0620 args.v2.usFbDiv = cpu_to_le16(fb_div);
0621 args.v2.ucFracFbDiv = frac_fb_div;
0622 args.v2.ucPostDiv = post_div;
0623 args.v2.ucPpll = pll_id;
0624 args.v2.ucCRTC = crtc_id;
0625 args.v2.ucRefDivSrc = 1;
0626 break;
0627 case 3:
0628 args.v3.usPixelClock = cpu_to_le16(clock / 10);
0629 args.v3.usRefDiv = cpu_to_le16(ref_div);
0630 args.v3.usFbDiv = cpu_to_le16(fb_div);
0631 args.v3.ucFracFbDiv = frac_fb_div;
0632 args.v3.ucPostDiv = post_div;
0633 args.v3.ucPpll = pll_id;
0634 if (crtc_id == ATOM_CRTC2)
0635 args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC2;
0636 else
0637 args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC1;
0638 if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
0639 args.v3.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC;
0640 args.v3.ucTransmitterId = encoder_id;
0641 args.v3.ucEncoderMode = encoder_mode;
0642 break;
0643 case 5:
0644 args.v5.ucCRTC = crtc_id;
0645 args.v5.usPixelClock = cpu_to_le16(clock / 10);
0646 args.v5.ucRefDiv = ref_div;
0647 args.v5.usFbDiv = cpu_to_le16(fb_div);
0648 args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
0649 args.v5.ucPostDiv = post_div;
0650 args.v5.ucMiscInfo = 0;
0651 if ((ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) &&
0652 (pll_id < ATOM_EXT_PLL1))
0653 args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_REF_DIV_SRC;
0654 if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
0655 switch (bpc) {
0656 case 8:
0657 default:
0658 args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP;
0659 break;
0660 case 10:
0661
0662 args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_32BPP;
0663 break;
0664 case 12:
0665
0666 args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP;
0667 break;
0668 }
0669 }
0670 args.v5.ucTransmitterID = encoder_id;
0671 args.v5.ucEncoderMode = encoder_mode;
0672 args.v5.ucPpll = pll_id;
0673 break;
0674 case 6:
0675 args.v6.ulDispEngClkFreq = cpu_to_le32(crtc_id << 24 | clock / 10);
0676 args.v6.ucRefDiv = ref_div;
0677 args.v6.usFbDiv = cpu_to_le16(fb_div);
0678 args.v6.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
0679 args.v6.ucPostDiv = post_div;
0680 args.v6.ucMiscInfo = 0;
0681 if ((ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) &&
0682 (pll_id < ATOM_EXT_PLL1) &&
0683 !is_pixel_clock_source_from_pll(encoder_mode, pll_id))
0684 args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_REF_DIV_SRC;
0685 if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
0686 switch (bpc) {
0687 case 8:
0688 default:
0689 args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP;
0690 break;
0691 case 10:
0692 args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP_V6;
0693 break;
0694 case 12:
0695 args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP_V6;
0696 break;
0697 case 16:
0698 args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP;
0699 break;
0700 }
0701 }
0702 args.v6.ucTransmitterID = encoder_id;
0703 args.v6.ucEncoderMode = encoder_mode;
0704 args.v6.ucPpll = pll_id;
0705 break;
0706 case 7:
0707 args.v7.ulPixelClock = cpu_to_le32(clock * 10);
0708 args.v7.ucMiscInfo = 0;
0709 if ((encoder_mode == ATOM_ENCODER_MODE_DVI) &&
0710 (clock > 165000))
0711 args.v7.ucMiscInfo |= PIXEL_CLOCK_V7_MISC_DVI_DUALLINK_EN;
0712 args.v7.ucCRTC = crtc_id;
0713 if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
0714 switch (bpc) {
0715 case 8:
0716 default:
0717 args.v7.ucDeepColorRatio = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_DIS;
0718 break;
0719 case 10:
0720 args.v7.ucDeepColorRatio = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_5_4;
0721 break;
0722 case 12:
0723 args.v7.ucDeepColorRatio = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_3_2;
0724 break;
0725 case 16:
0726 args.v7.ucDeepColorRatio = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_2_1;
0727 break;
0728 }
0729 }
0730 args.v7.ucTransmitterID = encoder_id;
0731 args.v7.ucEncoderMode = encoder_mode;
0732 args.v7.ucPpll = pll_id;
0733 break;
0734 default:
0735 DRM_ERROR("Unknown table version %d %d\n", frev, crev);
0736 return;
0737 }
0738 break;
0739 default:
0740 DRM_ERROR("Unknown table version %d %d\n", frev, crev);
0741 return;
0742 }
0743
0744 amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
0745 }
0746
0747 int amdgpu_atombios_crtc_prepare_pll(struct drm_crtc *crtc,
0748 struct drm_display_mode *mode)
0749 {
0750 struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
0751 struct drm_device *dev = crtc->dev;
0752 struct amdgpu_device *adev = drm_to_adev(dev);
0753 struct amdgpu_encoder *amdgpu_encoder =
0754 to_amdgpu_encoder(amdgpu_crtc->encoder);
0755 int encoder_mode = amdgpu_atombios_encoder_get_encoder_mode(amdgpu_crtc->encoder);
0756
0757 amdgpu_crtc->bpc = 8;
0758 amdgpu_crtc->ss_enabled = false;
0759
0760 if ((amdgpu_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
0761 (amdgpu_encoder_get_dp_bridge_encoder_id(amdgpu_crtc->encoder) != ENCODER_OBJECT_ID_NONE)) {
0762 struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
0763 struct drm_connector *connector =
0764 amdgpu_get_connector_for_encoder(amdgpu_crtc->encoder);
0765 struct amdgpu_connector *amdgpu_connector =
0766 to_amdgpu_connector(connector);
0767 struct amdgpu_connector_atom_dig *dig_connector =
0768 amdgpu_connector->con_priv;
0769 int dp_clock;
0770
0771
0772 amdgpu_connector->pixelclock_for_modeset = mode->clock;
0773 amdgpu_crtc->bpc = amdgpu_connector_get_monitor_bpc(connector);
0774
0775 switch (encoder_mode) {
0776 case ATOM_ENCODER_MODE_DP_MST:
0777 case ATOM_ENCODER_MODE_DP:
0778
0779 dp_clock = dig_connector->dp_clock / 10;
0780 amdgpu_crtc->ss_enabled =
0781 amdgpu_atombios_get_asic_ss_info(adev, &amdgpu_crtc->ss,
0782 ASIC_INTERNAL_SS_ON_DP,
0783 dp_clock);
0784 break;
0785 case ATOM_ENCODER_MODE_LVDS:
0786 amdgpu_crtc->ss_enabled =
0787 amdgpu_atombios_get_asic_ss_info(adev,
0788 &amdgpu_crtc->ss,
0789 dig->lcd_ss_id,
0790 mode->clock / 10);
0791 break;
0792 case ATOM_ENCODER_MODE_DVI:
0793 amdgpu_crtc->ss_enabled =
0794 amdgpu_atombios_get_asic_ss_info(adev,
0795 &amdgpu_crtc->ss,
0796 ASIC_INTERNAL_SS_ON_TMDS,
0797 mode->clock / 10);
0798 break;
0799 case ATOM_ENCODER_MODE_HDMI:
0800 amdgpu_crtc->ss_enabled =
0801 amdgpu_atombios_get_asic_ss_info(adev,
0802 &amdgpu_crtc->ss,
0803 ASIC_INTERNAL_SS_ON_HDMI,
0804 mode->clock / 10);
0805 break;
0806 default:
0807 break;
0808 }
0809 }
0810
0811
0812 amdgpu_crtc->adjusted_clock = amdgpu_atombios_crtc_adjust_pll(crtc, mode);
0813
0814 return 0;
0815 }
0816
0817 void amdgpu_atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
0818 {
0819 struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
0820 struct drm_device *dev = crtc->dev;
0821 struct amdgpu_device *adev = drm_to_adev(dev);
0822 struct amdgpu_encoder *amdgpu_encoder =
0823 to_amdgpu_encoder(amdgpu_crtc->encoder);
0824 u32 pll_clock = mode->clock;
0825 u32 clock = mode->clock;
0826 u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0;
0827 struct amdgpu_pll *pll;
0828 int encoder_mode = amdgpu_atombios_encoder_get_encoder_mode(amdgpu_crtc->encoder);
0829
0830
0831 if ((encoder_mode == ATOM_ENCODER_MODE_HDMI) &&
0832 (amdgpu_crtc->bpc > 8))
0833 clock = amdgpu_crtc->adjusted_clock;
0834
0835 switch (amdgpu_crtc->pll_id) {
0836 case ATOM_PPLL1:
0837 pll = &adev->clock.ppll[0];
0838 break;
0839 case ATOM_PPLL2:
0840 pll = &adev->clock.ppll[1];
0841 break;
0842 case ATOM_PPLL0:
0843 case ATOM_PPLL_INVALID:
0844 default:
0845 pll = &adev->clock.ppll[2];
0846 break;
0847 }
0848
0849
0850 pll->flags = amdgpu_crtc->pll_flags;
0851 pll->reference_div = amdgpu_crtc->pll_reference_div;
0852 pll->post_div = amdgpu_crtc->pll_post_div;
0853
0854 amdgpu_pll_compute(adev, pll, amdgpu_crtc->adjusted_clock, &pll_clock,
0855 &fb_div, &frac_fb_div, &ref_div, &post_div);
0856
0857 amdgpu_atombios_crtc_program_ss(adev, ATOM_DISABLE, amdgpu_crtc->pll_id,
0858 amdgpu_crtc->crtc_id, &amdgpu_crtc->ss);
0859
0860 amdgpu_atombios_crtc_program_pll(crtc, amdgpu_crtc->crtc_id, amdgpu_crtc->pll_id,
0861 encoder_mode, amdgpu_encoder->encoder_id, clock,
0862 ref_div, fb_div, frac_fb_div, post_div,
0863 amdgpu_crtc->bpc, amdgpu_crtc->ss_enabled, &amdgpu_crtc->ss);
0864
0865 if (amdgpu_crtc->ss_enabled) {
0866
0867 u32 step_size;
0868 u32 amount = (((fb_div * 10) + frac_fb_div) *
0869 (u32)amdgpu_crtc->ss.percentage) /
0870 (100 * (u32)amdgpu_crtc->ss.percentage_divider);
0871 amdgpu_crtc->ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK;
0872 amdgpu_crtc->ss.amount |= ((amount - (amount / 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) &
0873 ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK;
0874 if (amdgpu_crtc->ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD)
0875 step_size = (4 * amount * ref_div * ((u32)amdgpu_crtc->ss.rate * 2048)) /
0876 (125 * 25 * pll->reference_freq / 100);
0877 else
0878 step_size = (2 * amount * ref_div * ((u32)amdgpu_crtc->ss.rate * 2048)) /
0879 (125 * 25 * pll->reference_freq / 100);
0880 amdgpu_crtc->ss.step = step_size;
0881
0882 amdgpu_atombios_crtc_program_ss(adev, ATOM_ENABLE, amdgpu_crtc->pll_id,
0883 amdgpu_crtc->crtc_id, &amdgpu_crtc->ss);
0884 }
0885 }
0886