162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright 2007-8 Advanced Micro Devices, Inc. 362306a36Sopenharmony_ci * Copyright 2008 Red Hat Inc. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 662306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 762306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation 862306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 962306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 1062306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 1362306a36Sopenharmony_ci * all copies or substantial portions of the Software. 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1662306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1762306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1862306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 1962306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 2062306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2162306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * Authors: Dave Airlie 2462306a36Sopenharmony_ci * Alex Deucher 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include <drm/amdgpu_drm.h> 2862306a36Sopenharmony_ci#include <drm/drm_fixed.h> 2962306a36Sopenharmony_ci#include "amdgpu.h" 3062306a36Sopenharmony_ci#include "atom.h" 3162306a36Sopenharmony_ci#include "atom-bits.h" 3262306a36Sopenharmony_ci#include "atombios_encoders.h" 3362306a36Sopenharmony_ci#include "atombios_crtc.h" 3462306a36Sopenharmony_ci#include "amdgpu_atombios.h" 3562306a36Sopenharmony_ci#include "amdgpu_pll.h" 3662306a36Sopenharmony_ci#include "amdgpu_connectors.h" 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_civoid amdgpu_atombios_crtc_overscan_setup(struct drm_crtc *crtc, 3962306a36Sopenharmony_ci struct drm_display_mode *mode, 4062306a36Sopenharmony_ci struct drm_display_mode *adjusted_mode) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci struct drm_device *dev = crtc->dev; 4362306a36Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(dev); 4462306a36Sopenharmony_ci struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); 4562306a36Sopenharmony_ci SET_CRTC_OVERSCAN_PS_ALLOCATION args; 4662306a36Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan); 4762306a36Sopenharmony_ci int a1, a2; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci memset(&args, 0, sizeof(args)); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci args.ucCRTC = amdgpu_crtc->crtc_id; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci switch (amdgpu_crtc->rmx_type) { 5462306a36Sopenharmony_ci case RMX_CENTER: 5562306a36Sopenharmony_ci args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2); 5662306a36Sopenharmony_ci args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2); 5762306a36Sopenharmony_ci args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2); 5862306a36Sopenharmony_ci args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2); 5962306a36Sopenharmony_ci break; 6062306a36Sopenharmony_ci case RMX_ASPECT: 6162306a36Sopenharmony_ci a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay; 6262306a36Sopenharmony_ci a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (a1 > a2) { 6562306a36Sopenharmony_ci args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2); 6662306a36Sopenharmony_ci args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2); 6762306a36Sopenharmony_ci } else if (a2 > a1) { 6862306a36Sopenharmony_ci args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2); 6962306a36Sopenharmony_ci args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2); 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci break; 7262306a36Sopenharmony_ci case RMX_FULL: 7362306a36Sopenharmony_ci default: 7462306a36Sopenharmony_ci args.usOverscanRight = cpu_to_le16(amdgpu_crtc->h_border); 7562306a36Sopenharmony_ci args.usOverscanLeft = cpu_to_le16(amdgpu_crtc->h_border); 7662306a36Sopenharmony_ci args.usOverscanBottom = cpu_to_le16(amdgpu_crtc->v_border); 7762306a36Sopenharmony_ci args.usOverscanTop = cpu_to_le16(amdgpu_crtc->v_border); 7862306a36Sopenharmony_ci break; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_civoid amdgpu_atombios_crtc_scaler_setup(struct drm_crtc *crtc) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci struct drm_device *dev = crtc->dev; 8662306a36Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(dev); 8762306a36Sopenharmony_ci struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); 8862306a36Sopenharmony_ci ENABLE_SCALER_PS_ALLOCATION args; 8962306a36Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, EnableScaler); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci memset(&args, 0, sizeof(args)); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci args.ucScaler = amdgpu_crtc->crtc_id; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci switch (amdgpu_crtc->rmx_type) { 9662306a36Sopenharmony_ci case RMX_FULL: 9762306a36Sopenharmony_ci args.ucEnable = ATOM_SCALER_EXPANSION; 9862306a36Sopenharmony_ci break; 9962306a36Sopenharmony_ci case RMX_CENTER: 10062306a36Sopenharmony_ci args.ucEnable = ATOM_SCALER_CENTER; 10162306a36Sopenharmony_ci break; 10262306a36Sopenharmony_ci case RMX_ASPECT: 10362306a36Sopenharmony_ci args.ucEnable = ATOM_SCALER_EXPANSION; 10462306a36Sopenharmony_ci break; 10562306a36Sopenharmony_ci default: 10662306a36Sopenharmony_ci args.ucEnable = ATOM_SCALER_DISABLE; 10762306a36Sopenharmony_ci break; 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_civoid amdgpu_atombios_crtc_lock(struct drm_crtc *crtc, int lock) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); 11562306a36Sopenharmony_ci struct drm_device *dev = crtc->dev; 11662306a36Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(dev); 11762306a36Sopenharmony_ci int index = 11862306a36Sopenharmony_ci GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters); 11962306a36Sopenharmony_ci ENABLE_CRTC_PS_ALLOCATION args; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci memset(&args, 0, sizeof(args)); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci args.ucCRTC = amdgpu_crtc->crtc_id; 12462306a36Sopenharmony_ci args.ucEnable = lock; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_civoid amdgpu_atombios_crtc_enable(struct drm_crtc *crtc, int state) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); 13262306a36Sopenharmony_ci struct drm_device *dev = crtc->dev; 13362306a36Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(dev); 13462306a36Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC); 13562306a36Sopenharmony_ci ENABLE_CRTC_PS_ALLOCATION args; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci memset(&args, 0, sizeof(args)); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci args.ucCRTC = amdgpu_crtc->crtc_id; 14062306a36Sopenharmony_ci args.ucEnable = state; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_civoid amdgpu_atombios_crtc_blank(struct drm_crtc *crtc, int state) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); 14862306a36Sopenharmony_ci struct drm_device *dev = crtc->dev; 14962306a36Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(dev); 15062306a36Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC); 15162306a36Sopenharmony_ci BLANK_CRTC_PS_ALLOCATION args; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci memset(&args, 0, sizeof(args)); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci args.ucCRTC = amdgpu_crtc->crtc_id; 15662306a36Sopenharmony_ci args.ucBlanking = state; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_civoid amdgpu_atombios_crtc_powergate(struct drm_crtc *crtc, int state) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); 16462306a36Sopenharmony_ci struct drm_device *dev = crtc->dev; 16562306a36Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(dev); 16662306a36Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating); 16762306a36Sopenharmony_ci ENABLE_DISP_POWER_GATING_PS_ALLOCATION args; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci memset(&args, 0, sizeof(args)); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci args.ucDispPipeId = amdgpu_crtc->crtc_id; 17262306a36Sopenharmony_ci args.ucEnable = state; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_civoid amdgpu_atombios_crtc_powergate_init(struct amdgpu_device *adev) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating); 18062306a36Sopenharmony_ci ENABLE_DISP_POWER_GATING_PS_ALLOCATION args; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci memset(&args, 0, sizeof(args)); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci args.ucEnable = ATOM_INIT; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_civoid amdgpu_atombios_crtc_set_dtd_timing(struct drm_crtc *crtc, 19062306a36Sopenharmony_ci struct drm_display_mode *mode) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); 19362306a36Sopenharmony_ci struct drm_device *dev = crtc->dev; 19462306a36Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(dev); 19562306a36Sopenharmony_ci SET_CRTC_USING_DTD_TIMING_PARAMETERS args; 19662306a36Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming); 19762306a36Sopenharmony_ci u16 misc = 0; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci memset(&args, 0, sizeof(args)); 20062306a36Sopenharmony_ci args.usH_Size = cpu_to_le16(mode->crtc_hdisplay - (amdgpu_crtc->h_border * 2)); 20162306a36Sopenharmony_ci args.usH_Blanking_Time = 20262306a36Sopenharmony_ci cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay + (amdgpu_crtc->h_border * 2)); 20362306a36Sopenharmony_ci args.usV_Size = cpu_to_le16(mode->crtc_vdisplay - (amdgpu_crtc->v_border * 2)); 20462306a36Sopenharmony_ci args.usV_Blanking_Time = 20562306a36Sopenharmony_ci cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay + (amdgpu_crtc->v_border * 2)); 20662306a36Sopenharmony_ci args.usH_SyncOffset = 20762306a36Sopenharmony_ci cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay + amdgpu_crtc->h_border); 20862306a36Sopenharmony_ci args.usH_SyncWidth = 20962306a36Sopenharmony_ci cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start); 21062306a36Sopenharmony_ci args.usV_SyncOffset = 21162306a36Sopenharmony_ci cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay + amdgpu_crtc->v_border); 21262306a36Sopenharmony_ci args.usV_SyncWidth = 21362306a36Sopenharmony_ci cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start); 21462306a36Sopenharmony_ci args.ucH_Border = amdgpu_crtc->h_border; 21562306a36Sopenharmony_ci args.ucV_Border = amdgpu_crtc->v_border; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_NVSYNC) 21862306a36Sopenharmony_ci misc |= ATOM_VSYNC_POLARITY; 21962306a36Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_NHSYNC) 22062306a36Sopenharmony_ci misc |= ATOM_HSYNC_POLARITY; 22162306a36Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_CSYNC) 22262306a36Sopenharmony_ci misc |= ATOM_COMPOSITESYNC; 22362306a36Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_INTERLACE) 22462306a36Sopenharmony_ci misc |= ATOM_INTERLACE; 22562306a36Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 22662306a36Sopenharmony_ci misc |= ATOM_DOUBLE_CLOCK_MODE; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci args.susModeMiscInfo.usAccess = cpu_to_le16(misc); 22962306a36Sopenharmony_ci args.ucCRTC = amdgpu_crtc->crtc_id; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ciunion atom_enable_ss { 23562306a36Sopenharmony_ci ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1; 23662306a36Sopenharmony_ci ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 v2; 23762306a36Sopenharmony_ci ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 v3; 23862306a36Sopenharmony_ci}; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic void amdgpu_atombios_crtc_program_ss(struct amdgpu_device *adev, 24162306a36Sopenharmony_ci int enable, 24262306a36Sopenharmony_ci int pll_id, 24362306a36Sopenharmony_ci int crtc_id, 24462306a36Sopenharmony_ci struct amdgpu_atom_ss *ss) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci unsigned i; 24762306a36Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL); 24862306a36Sopenharmony_ci union atom_enable_ss args; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (enable) { 25162306a36Sopenharmony_ci /* Don't mess with SS if percentage is 0 or external ss. 25262306a36Sopenharmony_ci * SS is already disabled previously, and disabling it 25362306a36Sopenharmony_ci * again can cause display problems if the pll is already 25462306a36Sopenharmony_ci * programmed. 25562306a36Sopenharmony_ci */ 25662306a36Sopenharmony_ci if (ss->percentage == 0) 25762306a36Sopenharmony_ci return; 25862306a36Sopenharmony_ci if (ss->type & ATOM_EXTERNAL_SS_MASK) 25962306a36Sopenharmony_ci return; 26062306a36Sopenharmony_ci } else { 26162306a36Sopenharmony_ci for (i = 0; i < adev->mode_info.num_crtc; i++) { 26262306a36Sopenharmony_ci if (adev->mode_info.crtcs[i] && 26362306a36Sopenharmony_ci adev->mode_info.crtcs[i]->enabled && 26462306a36Sopenharmony_ci i != crtc_id && 26562306a36Sopenharmony_ci pll_id == adev->mode_info.crtcs[i]->pll_id) { 26662306a36Sopenharmony_ci /* one other crtc is using this pll don't turn 26762306a36Sopenharmony_ci * off spread spectrum as it might turn off 26862306a36Sopenharmony_ci * display on active crtc 26962306a36Sopenharmony_ci */ 27062306a36Sopenharmony_ci return; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci memset(&args, 0, sizeof(args)); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci args.v3.usSpreadSpectrumAmountFrac = cpu_to_le16(0); 27862306a36Sopenharmony_ci args.v3.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 27962306a36Sopenharmony_ci switch (pll_id) { 28062306a36Sopenharmony_ci case ATOM_PPLL1: 28162306a36Sopenharmony_ci args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL; 28262306a36Sopenharmony_ci break; 28362306a36Sopenharmony_ci case ATOM_PPLL2: 28462306a36Sopenharmony_ci args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL; 28562306a36Sopenharmony_ci break; 28662306a36Sopenharmony_ci case ATOM_DCPLL: 28762306a36Sopenharmony_ci args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL; 28862306a36Sopenharmony_ci break; 28962306a36Sopenharmony_ci case ATOM_PPLL_INVALID: 29062306a36Sopenharmony_ci return; 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci args.v3.usSpreadSpectrumAmount = cpu_to_le16(ss->amount); 29362306a36Sopenharmony_ci args.v3.usSpreadSpectrumStep = cpu_to_le16(ss->step); 29462306a36Sopenharmony_ci args.v3.ucEnable = enable; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ciunion adjust_pixel_clock { 30062306a36Sopenharmony_ci ADJUST_DISPLAY_PLL_PS_ALLOCATION v1; 30162306a36Sopenharmony_ci ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 v3; 30262306a36Sopenharmony_ci}; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic u32 amdgpu_atombios_crtc_adjust_pll(struct drm_crtc *crtc, 30562306a36Sopenharmony_ci struct drm_display_mode *mode) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); 30862306a36Sopenharmony_ci struct drm_device *dev = crtc->dev; 30962306a36Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(dev); 31062306a36Sopenharmony_ci struct drm_encoder *encoder = amdgpu_crtc->encoder; 31162306a36Sopenharmony_ci struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); 31262306a36Sopenharmony_ci struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder); 31362306a36Sopenharmony_ci u32 adjusted_clock = mode->clock; 31462306a36Sopenharmony_ci int encoder_mode = amdgpu_atombios_encoder_get_encoder_mode(encoder); 31562306a36Sopenharmony_ci u32 dp_clock = mode->clock; 31662306a36Sopenharmony_ci u32 clock = mode->clock; 31762306a36Sopenharmony_ci int bpc = amdgpu_crtc->bpc; 31862306a36Sopenharmony_ci bool is_duallink = amdgpu_dig_monitor_is_duallink(encoder, mode->clock); 31962306a36Sopenharmony_ci union adjust_pixel_clock args; 32062306a36Sopenharmony_ci u8 frev, crev; 32162306a36Sopenharmony_ci int index; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci amdgpu_crtc->pll_flags = AMDGPU_PLL_USE_FRAC_FB_DIV; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci if ((amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) || 32662306a36Sopenharmony_ci (amdgpu_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)) { 32762306a36Sopenharmony_ci if (connector) { 32862306a36Sopenharmony_ci struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); 32962306a36Sopenharmony_ci struct amdgpu_connector_atom_dig *dig_connector = 33062306a36Sopenharmony_ci amdgpu_connector->con_priv; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci dp_clock = dig_connector->dp_clock; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* use recommended ref_div for ss */ 33762306a36Sopenharmony_ci if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 33862306a36Sopenharmony_ci if (amdgpu_crtc->ss_enabled) { 33962306a36Sopenharmony_ci if (amdgpu_crtc->ss.refdiv) { 34062306a36Sopenharmony_ci amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_REF_DIV; 34162306a36Sopenharmony_ci amdgpu_crtc->pll_reference_div = amdgpu_crtc->ss.refdiv; 34262306a36Sopenharmony_ci amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_FRAC_FB_DIV; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ 34862306a36Sopenharmony_ci if (amdgpu_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1) 34962306a36Sopenharmony_ci adjusted_clock = mode->clock * 2; 35062306a36Sopenharmony_ci if (amdgpu_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 35162306a36Sopenharmony_ci amdgpu_crtc->pll_flags |= AMDGPU_PLL_PREFER_CLOSEST_LOWER; 35262306a36Sopenharmony_ci if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) 35362306a36Sopenharmony_ci amdgpu_crtc->pll_flags |= AMDGPU_PLL_IS_LCD; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* adjust pll for deep color modes */ 35762306a36Sopenharmony_ci if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { 35862306a36Sopenharmony_ci switch (bpc) { 35962306a36Sopenharmony_ci case 8: 36062306a36Sopenharmony_ci default: 36162306a36Sopenharmony_ci break; 36262306a36Sopenharmony_ci case 10: 36362306a36Sopenharmony_ci clock = (clock * 5) / 4; 36462306a36Sopenharmony_ci break; 36562306a36Sopenharmony_ci case 12: 36662306a36Sopenharmony_ci clock = (clock * 3) / 2; 36762306a36Sopenharmony_ci break; 36862306a36Sopenharmony_ci case 16: 36962306a36Sopenharmony_ci clock = clock * 2; 37062306a36Sopenharmony_ci break; 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci /* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock 37562306a36Sopenharmony_ci * accordingly based on the encoder/transmitter to work around 37662306a36Sopenharmony_ci * special hw requirements. 37762306a36Sopenharmony_ci */ 37862306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll); 37962306a36Sopenharmony_ci if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, 38062306a36Sopenharmony_ci &crev)) 38162306a36Sopenharmony_ci return adjusted_clock; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci memset(&args, 0, sizeof(args)); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci switch (frev) { 38662306a36Sopenharmony_ci case 1: 38762306a36Sopenharmony_ci switch (crev) { 38862306a36Sopenharmony_ci case 1: 38962306a36Sopenharmony_ci case 2: 39062306a36Sopenharmony_ci args.v1.usPixelClock = cpu_to_le16(clock / 10); 39162306a36Sopenharmony_ci args.v1.ucTransmitterID = amdgpu_encoder->encoder_id; 39262306a36Sopenharmony_ci args.v1.ucEncodeMode = encoder_mode; 39362306a36Sopenharmony_ci if (amdgpu_crtc->ss_enabled && amdgpu_crtc->ss.percentage) 39462306a36Sopenharmony_ci args.v1.ucConfig |= 39562306a36Sopenharmony_ci ADJUST_DISPLAY_CONFIG_SS_ENABLE; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci amdgpu_atom_execute_table(adev->mode_info.atom_context, 39862306a36Sopenharmony_ci index, (uint32_t *)&args); 39962306a36Sopenharmony_ci adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10; 40062306a36Sopenharmony_ci break; 40162306a36Sopenharmony_ci case 3: 40262306a36Sopenharmony_ci args.v3.sInput.usPixelClock = cpu_to_le16(clock / 10); 40362306a36Sopenharmony_ci args.v3.sInput.ucTransmitterID = amdgpu_encoder->encoder_id; 40462306a36Sopenharmony_ci args.v3.sInput.ucEncodeMode = encoder_mode; 40562306a36Sopenharmony_ci args.v3.sInput.ucDispPllConfig = 0; 40662306a36Sopenharmony_ci if (amdgpu_crtc->ss_enabled && amdgpu_crtc->ss.percentage) 40762306a36Sopenharmony_ci args.v3.sInput.ucDispPllConfig |= 40862306a36Sopenharmony_ci DISPPLL_CONFIG_SS_ENABLE; 40962306a36Sopenharmony_ci if (ENCODER_MODE_IS_DP(encoder_mode)) { 41062306a36Sopenharmony_ci args.v3.sInput.ucDispPllConfig |= 41162306a36Sopenharmony_ci DISPPLL_CONFIG_COHERENT_MODE; 41262306a36Sopenharmony_ci /* 16200 or 27000 */ 41362306a36Sopenharmony_ci args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); 41462306a36Sopenharmony_ci } else if (amdgpu_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { 41562306a36Sopenharmony_ci struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; 41662306a36Sopenharmony_ci if (dig->coherent_mode) 41762306a36Sopenharmony_ci args.v3.sInput.ucDispPllConfig |= 41862306a36Sopenharmony_ci DISPPLL_CONFIG_COHERENT_MODE; 41962306a36Sopenharmony_ci if (is_duallink) 42062306a36Sopenharmony_ci args.v3.sInput.ucDispPllConfig |= 42162306a36Sopenharmony_ci DISPPLL_CONFIG_DUAL_LINK; 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci if (amdgpu_encoder_get_dp_bridge_encoder_id(encoder) != 42462306a36Sopenharmony_ci ENCODER_OBJECT_ID_NONE) 42562306a36Sopenharmony_ci args.v3.sInput.ucExtTransmitterID = 42662306a36Sopenharmony_ci amdgpu_encoder_get_dp_bridge_encoder_id(encoder); 42762306a36Sopenharmony_ci else 42862306a36Sopenharmony_ci args.v3.sInput.ucExtTransmitterID = 0; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci amdgpu_atom_execute_table(adev->mode_info.atom_context, 43162306a36Sopenharmony_ci index, (uint32_t *)&args); 43262306a36Sopenharmony_ci adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10; 43362306a36Sopenharmony_ci if (args.v3.sOutput.ucRefDiv) { 43462306a36Sopenharmony_ci amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_FRAC_FB_DIV; 43562306a36Sopenharmony_ci amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_REF_DIV; 43662306a36Sopenharmony_ci amdgpu_crtc->pll_reference_div = args.v3.sOutput.ucRefDiv; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci if (args.v3.sOutput.ucPostDiv) { 43962306a36Sopenharmony_ci amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_FRAC_FB_DIV; 44062306a36Sopenharmony_ci amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_POST_DIV; 44162306a36Sopenharmony_ci amdgpu_crtc->pll_post_div = args.v3.sOutput.ucPostDiv; 44262306a36Sopenharmony_ci } 44362306a36Sopenharmony_ci break; 44462306a36Sopenharmony_ci default: 44562306a36Sopenharmony_ci DRM_ERROR("Unknown table version %d %d\n", frev, crev); 44662306a36Sopenharmony_ci return adjusted_clock; 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci break; 44962306a36Sopenharmony_ci default: 45062306a36Sopenharmony_ci DRM_ERROR("Unknown table version %d %d\n", frev, crev); 45162306a36Sopenharmony_ci return adjusted_clock; 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci return adjusted_clock; 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ciunion set_pixel_clock { 45862306a36Sopenharmony_ci SET_PIXEL_CLOCK_PS_ALLOCATION base; 45962306a36Sopenharmony_ci PIXEL_CLOCK_PARAMETERS v1; 46062306a36Sopenharmony_ci PIXEL_CLOCK_PARAMETERS_V2 v2; 46162306a36Sopenharmony_ci PIXEL_CLOCK_PARAMETERS_V3 v3; 46262306a36Sopenharmony_ci PIXEL_CLOCK_PARAMETERS_V5 v5; 46362306a36Sopenharmony_ci PIXEL_CLOCK_PARAMETERS_V6 v6; 46462306a36Sopenharmony_ci PIXEL_CLOCK_PARAMETERS_V7 v7; 46562306a36Sopenharmony_ci}; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci/* on DCE5, make sure the voltage is high enough to support the 46862306a36Sopenharmony_ci * required disp clk. 46962306a36Sopenharmony_ci */ 47062306a36Sopenharmony_civoid amdgpu_atombios_crtc_set_disp_eng_pll(struct amdgpu_device *adev, 47162306a36Sopenharmony_ci u32 dispclk) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci u8 frev, crev; 47462306a36Sopenharmony_ci int index; 47562306a36Sopenharmony_ci union set_pixel_clock args; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci memset(&args, 0, sizeof(args)); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); 48062306a36Sopenharmony_ci if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, 48162306a36Sopenharmony_ci &crev)) 48262306a36Sopenharmony_ci return; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci switch (frev) { 48562306a36Sopenharmony_ci case 1: 48662306a36Sopenharmony_ci switch (crev) { 48762306a36Sopenharmony_ci case 5: 48862306a36Sopenharmony_ci /* if the default dcpll clock is specified, 48962306a36Sopenharmony_ci * SetPixelClock provides the dividers 49062306a36Sopenharmony_ci */ 49162306a36Sopenharmony_ci args.v5.ucCRTC = ATOM_CRTC_INVALID; 49262306a36Sopenharmony_ci args.v5.usPixelClock = cpu_to_le16(dispclk); 49362306a36Sopenharmony_ci args.v5.ucPpll = ATOM_DCPLL; 49462306a36Sopenharmony_ci break; 49562306a36Sopenharmony_ci case 6: 49662306a36Sopenharmony_ci /* if the default dcpll clock is specified, 49762306a36Sopenharmony_ci * SetPixelClock provides the dividers 49862306a36Sopenharmony_ci */ 49962306a36Sopenharmony_ci args.v6.ulDispEngClkFreq = cpu_to_le32(dispclk); 50062306a36Sopenharmony_ci if (adev->asic_type == CHIP_TAHITI || 50162306a36Sopenharmony_ci adev->asic_type == CHIP_PITCAIRN || 50262306a36Sopenharmony_ci adev->asic_type == CHIP_VERDE || 50362306a36Sopenharmony_ci adev->asic_type == CHIP_OLAND) 50462306a36Sopenharmony_ci args.v6.ucPpll = ATOM_PPLL0; 50562306a36Sopenharmony_ci else 50662306a36Sopenharmony_ci args.v6.ucPpll = ATOM_EXT_PLL1; 50762306a36Sopenharmony_ci break; 50862306a36Sopenharmony_ci default: 50962306a36Sopenharmony_ci DRM_ERROR("Unknown table version %d %d\n", frev, crev); 51062306a36Sopenharmony_ci return; 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci break; 51362306a36Sopenharmony_ci default: 51462306a36Sopenharmony_ci DRM_ERROR("Unknown table version %d %d\n", frev, crev); 51562306a36Sopenharmony_ci return; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ciunion set_dce_clock { 52162306a36Sopenharmony_ci SET_DCE_CLOCK_PS_ALLOCATION_V1_1 v1_1; 52262306a36Sopenharmony_ci SET_DCE_CLOCK_PS_ALLOCATION_V2_1 v2_1; 52362306a36Sopenharmony_ci}; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ciu32 amdgpu_atombios_crtc_set_dce_clock(struct amdgpu_device *adev, 52662306a36Sopenharmony_ci u32 freq, u8 clk_type, u8 clk_src) 52762306a36Sopenharmony_ci{ 52862306a36Sopenharmony_ci u8 frev, crev; 52962306a36Sopenharmony_ci int index; 53062306a36Sopenharmony_ci union set_dce_clock args; 53162306a36Sopenharmony_ci u32 ret_freq = 0; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci memset(&args, 0, sizeof(args)); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, SetDCEClock); 53662306a36Sopenharmony_ci if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, 53762306a36Sopenharmony_ci &crev)) 53862306a36Sopenharmony_ci return 0; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci switch (frev) { 54162306a36Sopenharmony_ci case 2: 54262306a36Sopenharmony_ci switch (crev) { 54362306a36Sopenharmony_ci case 1: 54462306a36Sopenharmony_ci args.v2_1.asParam.ulDCEClkFreq = cpu_to_le32(freq); /* 10kHz units */ 54562306a36Sopenharmony_ci args.v2_1.asParam.ucDCEClkType = clk_type; 54662306a36Sopenharmony_ci args.v2_1.asParam.ucDCEClkSrc = clk_src; 54762306a36Sopenharmony_ci amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); 54862306a36Sopenharmony_ci ret_freq = le32_to_cpu(args.v2_1.asParam.ulDCEClkFreq) * 10; 54962306a36Sopenharmony_ci break; 55062306a36Sopenharmony_ci default: 55162306a36Sopenharmony_ci DRM_ERROR("Unknown table version %d %d\n", frev, crev); 55262306a36Sopenharmony_ci return 0; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci break; 55562306a36Sopenharmony_ci default: 55662306a36Sopenharmony_ci DRM_ERROR("Unknown table version %d %d\n", frev, crev); 55762306a36Sopenharmony_ci return 0; 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci return ret_freq; 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_cistatic bool is_pixel_clock_source_from_pll(u32 encoder_mode, int pll_id) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci if (ENCODER_MODE_IS_DP(encoder_mode)) { 56662306a36Sopenharmony_ci if (pll_id < ATOM_EXT_PLL1) 56762306a36Sopenharmony_ci return true; 56862306a36Sopenharmony_ci else 56962306a36Sopenharmony_ci return false; 57062306a36Sopenharmony_ci } else { 57162306a36Sopenharmony_ci return true; 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci} 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_civoid amdgpu_atombios_crtc_program_pll(struct drm_crtc *crtc, 57662306a36Sopenharmony_ci u32 crtc_id, 57762306a36Sopenharmony_ci int pll_id, 57862306a36Sopenharmony_ci u32 encoder_mode, 57962306a36Sopenharmony_ci u32 encoder_id, 58062306a36Sopenharmony_ci u32 clock, 58162306a36Sopenharmony_ci u32 ref_div, 58262306a36Sopenharmony_ci u32 fb_div, 58362306a36Sopenharmony_ci u32 frac_fb_div, 58462306a36Sopenharmony_ci u32 post_div, 58562306a36Sopenharmony_ci int bpc, 58662306a36Sopenharmony_ci bool ss_enabled, 58762306a36Sopenharmony_ci struct amdgpu_atom_ss *ss) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci struct drm_device *dev = crtc->dev; 59062306a36Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(dev); 59162306a36Sopenharmony_ci u8 frev, crev; 59262306a36Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); 59362306a36Sopenharmony_ci union set_pixel_clock args; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci memset(&args, 0, sizeof(args)); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, 59862306a36Sopenharmony_ci &crev)) 59962306a36Sopenharmony_ci return; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci switch (frev) { 60262306a36Sopenharmony_ci case 1: 60362306a36Sopenharmony_ci switch (crev) { 60462306a36Sopenharmony_ci case 1: 60562306a36Sopenharmony_ci if (clock == ATOM_DISABLE) 60662306a36Sopenharmony_ci return; 60762306a36Sopenharmony_ci args.v1.usPixelClock = cpu_to_le16(clock / 10); 60862306a36Sopenharmony_ci args.v1.usRefDiv = cpu_to_le16(ref_div); 60962306a36Sopenharmony_ci args.v1.usFbDiv = cpu_to_le16(fb_div); 61062306a36Sopenharmony_ci args.v1.ucFracFbDiv = frac_fb_div; 61162306a36Sopenharmony_ci args.v1.ucPostDiv = post_div; 61262306a36Sopenharmony_ci args.v1.ucPpll = pll_id; 61362306a36Sopenharmony_ci args.v1.ucCRTC = crtc_id; 61462306a36Sopenharmony_ci args.v1.ucRefDivSrc = 1; 61562306a36Sopenharmony_ci break; 61662306a36Sopenharmony_ci case 2: 61762306a36Sopenharmony_ci args.v2.usPixelClock = cpu_to_le16(clock / 10); 61862306a36Sopenharmony_ci args.v2.usRefDiv = cpu_to_le16(ref_div); 61962306a36Sopenharmony_ci args.v2.usFbDiv = cpu_to_le16(fb_div); 62062306a36Sopenharmony_ci args.v2.ucFracFbDiv = frac_fb_div; 62162306a36Sopenharmony_ci args.v2.ucPostDiv = post_div; 62262306a36Sopenharmony_ci args.v2.ucPpll = pll_id; 62362306a36Sopenharmony_ci args.v2.ucCRTC = crtc_id; 62462306a36Sopenharmony_ci args.v2.ucRefDivSrc = 1; 62562306a36Sopenharmony_ci break; 62662306a36Sopenharmony_ci case 3: 62762306a36Sopenharmony_ci args.v3.usPixelClock = cpu_to_le16(clock / 10); 62862306a36Sopenharmony_ci args.v3.usRefDiv = cpu_to_le16(ref_div); 62962306a36Sopenharmony_ci args.v3.usFbDiv = cpu_to_le16(fb_div); 63062306a36Sopenharmony_ci args.v3.ucFracFbDiv = frac_fb_div; 63162306a36Sopenharmony_ci args.v3.ucPostDiv = post_div; 63262306a36Sopenharmony_ci args.v3.ucPpll = pll_id; 63362306a36Sopenharmony_ci if (crtc_id == ATOM_CRTC2) 63462306a36Sopenharmony_ci args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC2; 63562306a36Sopenharmony_ci else 63662306a36Sopenharmony_ci args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC1; 63762306a36Sopenharmony_ci if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) 63862306a36Sopenharmony_ci args.v3.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC; 63962306a36Sopenharmony_ci args.v3.ucTransmitterId = encoder_id; 64062306a36Sopenharmony_ci args.v3.ucEncoderMode = encoder_mode; 64162306a36Sopenharmony_ci break; 64262306a36Sopenharmony_ci case 5: 64362306a36Sopenharmony_ci args.v5.ucCRTC = crtc_id; 64462306a36Sopenharmony_ci args.v5.usPixelClock = cpu_to_le16(clock / 10); 64562306a36Sopenharmony_ci args.v5.ucRefDiv = ref_div; 64662306a36Sopenharmony_ci args.v5.usFbDiv = cpu_to_le16(fb_div); 64762306a36Sopenharmony_ci args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); 64862306a36Sopenharmony_ci args.v5.ucPostDiv = post_div; 64962306a36Sopenharmony_ci args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */ 65062306a36Sopenharmony_ci if ((ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) && 65162306a36Sopenharmony_ci (pll_id < ATOM_EXT_PLL1)) 65262306a36Sopenharmony_ci args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_REF_DIV_SRC; 65362306a36Sopenharmony_ci if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { 65462306a36Sopenharmony_ci switch (bpc) { 65562306a36Sopenharmony_ci case 8: 65662306a36Sopenharmony_ci default: 65762306a36Sopenharmony_ci args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP; 65862306a36Sopenharmony_ci break; 65962306a36Sopenharmony_ci case 10: 66062306a36Sopenharmony_ci /* yes this is correct, the atom define is wrong */ 66162306a36Sopenharmony_ci args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_32BPP; 66262306a36Sopenharmony_ci break; 66362306a36Sopenharmony_ci case 12: 66462306a36Sopenharmony_ci /* yes this is correct, the atom define is wrong */ 66562306a36Sopenharmony_ci args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP; 66662306a36Sopenharmony_ci break; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci args.v5.ucTransmitterID = encoder_id; 67062306a36Sopenharmony_ci args.v5.ucEncoderMode = encoder_mode; 67162306a36Sopenharmony_ci args.v5.ucPpll = pll_id; 67262306a36Sopenharmony_ci break; 67362306a36Sopenharmony_ci case 6: 67462306a36Sopenharmony_ci args.v6.ulDispEngClkFreq = cpu_to_le32(crtc_id << 24 | clock / 10); 67562306a36Sopenharmony_ci args.v6.ucRefDiv = ref_div; 67662306a36Sopenharmony_ci args.v6.usFbDiv = cpu_to_le16(fb_div); 67762306a36Sopenharmony_ci args.v6.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); 67862306a36Sopenharmony_ci args.v6.ucPostDiv = post_div; 67962306a36Sopenharmony_ci args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */ 68062306a36Sopenharmony_ci if ((ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) && 68162306a36Sopenharmony_ci (pll_id < ATOM_EXT_PLL1) && 68262306a36Sopenharmony_ci !is_pixel_clock_source_from_pll(encoder_mode, pll_id)) 68362306a36Sopenharmony_ci args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_REF_DIV_SRC; 68462306a36Sopenharmony_ci if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { 68562306a36Sopenharmony_ci switch (bpc) { 68662306a36Sopenharmony_ci case 8: 68762306a36Sopenharmony_ci default: 68862306a36Sopenharmony_ci args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP; 68962306a36Sopenharmony_ci break; 69062306a36Sopenharmony_ci case 10: 69162306a36Sopenharmony_ci args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP_V6; 69262306a36Sopenharmony_ci break; 69362306a36Sopenharmony_ci case 12: 69462306a36Sopenharmony_ci args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP_V6; 69562306a36Sopenharmony_ci break; 69662306a36Sopenharmony_ci case 16: 69762306a36Sopenharmony_ci args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP; 69862306a36Sopenharmony_ci break; 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci args.v6.ucTransmitterID = encoder_id; 70262306a36Sopenharmony_ci args.v6.ucEncoderMode = encoder_mode; 70362306a36Sopenharmony_ci args.v6.ucPpll = pll_id; 70462306a36Sopenharmony_ci break; 70562306a36Sopenharmony_ci case 7: 70662306a36Sopenharmony_ci args.v7.ulPixelClock = cpu_to_le32(clock * 10); /* 100 hz units */ 70762306a36Sopenharmony_ci args.v7.ucMiscInfo = 0; 70862306a36Sopenharmony_ci if ((encoder_mode == ATOM_ENCODER_MODE_DVI) && 70962306a36Sopenharmony_ci (clock > 165000)) 71062306a36Sopenharmony_ci args.v7.ucMiscInfo |= PIXEL_CLOCK_V7_MISC_DVI_DUALLINK_EN; 71162306a36Sopenharmony_ci args.v7.ucCRTC = crtc_id; 71262306a36Sopenharmony_ci if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { 71362306a36Sopenharmony_ci switch (bpc) { 71462306a36Sopenharmony_ci case 8: 71562306a36Sopenharmony_ci default: 71662306a36Sopenharmony_ci args.v7.ucDeepColorRatio = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_DIS; 71762306a36Sopenharmony_ci break; 71862306a36Sopenharmony_ci case 10: 71962306a36Sopenharmony_ci args.v7.ucDeepColorRatio = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_5_4; 72062306a36Sopenharmony_ci break; 72162306a36Sopenharmony_ci case 12: 72262306a36Sopenharmony_ci args.v7.ucDeepColorRatio = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_3_2; 72362306a36Sopenharmony_ci break; 72462306a36Sopenharmony_ci case 16: 72562306a36Sopenharmony_ci args.v7.ucDeepColorRatio = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_2_1; 72662306a36Sopenharmony_ci break; 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci args.v7.ucTransmitterID = encoder_id; 73062306a36Sopenharmony_ci args.v7.ucEncoderMode = encoder_mode; 73162306a36Sopenharmony_ci args.v7.ucPpll = pll_id; 73262306a36Sopenharmony_ci break; 73362306a36Sopenharmony_ci default: 73462306a36Sopenharmony_ci DRM_ERROR("Unknown table version %d %d\n", frev, crev); 73562306a36Sopenharmony_ci return; 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci break; 73862306a36Sopenharmony_ci default: 73962306a36Sopenharmony_ci DRM_ERROR("Unknown table version %d %d\n", frev, crev); 74062306a36Sopenharmony_ci return; 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); 74462306a36Sopenharmony_ci} 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ciint amdgpu_atombios_crtc_prepare_pll(struct drm_crtc *crtc, 74762306a36Sopenharmony_ci struct drm_display_mode *mode) 74862306a36Sopenharmony_ci{ 74962306a36Sopenharmony_ci struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); 75062306a36Sopenharmony_ci struct drm_device *dev = crtc->dev; 75162306a36Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(dev); 75262306a36Sopenharmony_ci struct amdgpu_encoder *amdgpu_encoder = 75362306a36Sopenharmony_ci to_amdgpu_encoder(amdgpu_crtc->encoder); 75462306a36Sopenharmony_ci int encoder_mode = amdgpu_atombios_encoder_get_encoder_mode(amdgpu_crtc->encoder); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci amdgpu_crtc->bpc = 8; 75762306a36Sopenharmony_ci amdgpu_crtc->ss_enabled = false; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci if ((amdgpu_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) || 76062306a36Sopenharmony_ci (amdgpu_encoder_get_dp_bridge_encoder_id(amdgpu_crtc->encoder) != ENCODER_OBJECT_ID_NONE)) { 76162306a36Sopenharmony_ci struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; 76262306a36Sopenharmony_ci struct drm_connector *connector = 76362306a36Sopenharmony_ci amdgpu_get_connector_for_encoder(amdgpu_crtc->encoder); 76462306a36Sopenharmony_ci struct amdgpu_connector *amdgpu_connector = 76562306a36Sopenharmony_ci to_amdgpu_connector(connector); 76662306a36Sopenharmony_ci struct amdgpu_connector_atom_dig *dig_connector = 76762306a36Sopenharmony_ci amdgpu_connector->con_priv; 76862306a36Sopenharmony_ci int dp_clock; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci /* Assign mode clock for hdmi deep color max clock limit check */ 77162306a36Sopenharmony_ci amdgpu_connector->pixelclock_for_modeset = mode->clock; 77262306a36Sopenharmony_ci amdgpu_crtc->bpc = amdgpu_connector_get_monitor_bpc(connector); 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci switch (encoder_mode) { 77562306a36Sopenharmony_ci case ATOM_ENCODER_MODE_DP_MST: 77662306a36Sopenharmony_ci case ATOM_ENCODER_MODE_DP: 77762306a36Sopenharmony_ci /* DP/eDP */ 77862306a36Sopenharmony_ci dp_clock = dig_connector->dp_clock / 10; 77962306a36Sopenharmony_ci amdgpu_crtc->ss_enabled = 78062306a36Sopenharmony_ci amdgpu_atombios_get_asic_ss_info(adev, &amdgpu_crtc->ss, 78162306a36Sopenharmony_ci ASIC_INTERNAL_SS_ON_DP, 78262306a36Sopenharmony_ci dp_clock); 78362306a36Sopenharmony_ci break; 78462306a36Sopenharmony_ci case ATOM_ENCODER_MODE_LVDS: 78562306a36Sopenharmony_ci amdgpu_crtc->ss_enabled = 78662306a36Sopenharmony_ci amdgpu_atombios_get_asic_ss_info(adev, 78762306a36Sopenharmony_ci &amdgpu_crtc->ss, 78862306a36Sopenharmony_ci dig->lcd_ss_id, 78962306a36Sopenharmony_ci mode->clock / 10); 79062306a36Sopenharmony_ci break; 79162306a36Sopenharmony_ci case ATOM_ENCODER_MODE_DVI: 79262306a36Sopenharmony_ci amdgpu_crtc->ss_enabled = 79362306a36Sopenharmony_ci amdgpu_atombios_get_asic_ss_info(adev, 79462306a36Sopenharmony_ci &amdgpu_crtc->ss, 79562306a36Sopenharmony_ci ASIC_INTERNAL_SS_ON_TMDS, 79662306a36Sopenharmony_ci mode->clock / 10); 79762306a36Sopenharmony_ci break; 79862306a36Sopenharmony_ci case ATOM_ENCODER_MODE_HDMI: 79962306a36Sopenharmony_ci amdgpu_crtc->ss_enabled = 80062306a36Sopenharmony_ci amdgpu_atombios_get_asic_ss_info(adev, 80162306a36Sopenharmony_ci &amdgpu_crtc->ss, 80262306a36Sopenharmony_ci ASIC_INTERNAL_SS_ON_HDMI, 80362306a36Sopenharmony_ci mode->clock / 10); 80462306a36Sopenharmony_ci break; 80562306a36Sopenharmony_ci default: 80662306a36Sopenharmony_ci break; 80762306a36Sopenharmony_ci } 80862306a36Sopenharmony_ci } 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci /* adjust pixel clock as needed */ 81162306a36Sopenharmony_ci amdgpu_crtc->adjusted_clock = amdgpu_atombios_crtc_adjust_pll(crtc, mode); 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci return 0; 81462306a36Sopenharmony_ci} 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_civoid amdgpu_atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) 81762306a36Sopenharmony_ci{ 81862306a36Sopenharmony_ci struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); 81962306a36Sopenharmony_ci struct drm_device *dev = crtc->dev; 82062306a36Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(dev); 82162306a36Sopenharmony_ci struct amdgpu_encoder *amdgpu_encoder = 82262306a36Sopenharmony_ci to_amdgpu_encoder(amdgpu_crtc->encoder); 82362306a36Sopenharmony_ci u32 pll_clock = mode->clock; 82462306a36Sopenharmony_ci u32 clock = mode->clock; 82562306a36Sopenharmony_ci u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; 82662306a36Sopenharmony_ci struct amdgpu_pll *pll; 82762306a36Sopenharmony_ci int encoder_mode = amdgpu_atombios_encoder_get_encoder_mode(amdgpu_crtc->encoder); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci /* pass the actual clock to amdgpu_atombios_crtc_program_pll for HDMI */ 83062306a36Sopenharmony_ci if ((encoder_mode == ATOM_ENCODER_MODE_HDMI) && 83162306a36Sopenharmony_ci (amdgpu_crtc->bpc > 8)) 83262306a36Sopenharmony_ci clock = amdgpu_crtc->adjusted_clock; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci switch (amdgpu_crtc->pll_id) { 83562306a36Sopenharmony_ci case ATOM_PPLL1: 83662306a36Sopenharmony_ci pll = &adev->clock.ppll[0]; 83762306a36Sopenharmony_ci break; 83862306a36Sopenharmony_ci case ATOM_PPLL2: 83962306a36Sopenharmony_ci pll = &adev->clock.ppll[1]; 84062306a36Sopenharmony_ci break; 84162306a36Sopenharmony_ci case ATOM_PPLL0: 84262306a36Sopenharmony_ci case ATOM_PPLL_INVALID: 84362306a36Sopenharmony_ci default: 84462306a36Sopenharmony_ci pll = &adev->clock.ppll[2]; 84562306a36Sopenharmony_ci break; 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci /* update pll params */ 84962306a36Sopenharmony_ci pll->flags = amdgpu_crtc->pll_flags; 85062306a36Sopenharmony_ci pll->reference_div = amdgpu_crtc->pll_reference_div; 85162306a36Sopenharmony_ci pll->post_div = amdgpu_crtc->pll_post_div; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci amdgpu_pll_compute(adev, pll, amdgpu_crtc->adjusted_clock, &pll_clock, 85462306a36Sopenharmony_ci &fb_div, &frac_fb_div, &ref_div, &post_div); 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci amdgpu_atombios_crtc_program_ss(adev, ATOM_DISABLE, amdgpu_crtc->pll_id, 85762306a36Sopenharmony_ci amdgpu_crtc->crtc_id, &amdgpu_crtc->ss); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci amdgpu_atombios_crtc_program_pll(crtc, amdgpu_crtc->crtc_id, amdgpu_crtc->pll_id, 86062306a36Sopenharmony_ci encoder_mode, amdgpu_encoder->encoder_id, clock, 86162306a36Sopenharmony_ci ref_div, fb_div, frac_fb_div, post_div, 86262306a36Sopenharmony_ci amdgpu_crtc->bpc, amdgpu_crtc->ss_enabled, &amdgpu_crtc->ss); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci if (amdgpu_crtc->ss_enabled) { 86562306a36Sopenharmony_ci /* calculate ss amount and step size */ 86662306a36Sopenharmony_ci u32 step_size; 86762306a36Sopenharmony_ci u32 amount = (((fb_div * 10) + frac_fb_div) * 86862306a36Sopenharmony_ci (u32)amdgpu_crtc->ss.percentage) / 86962306a36Sopenharmony_ci (100 * (u32)amdgpu_crtc->ss.percentage_divider); 87062306a36Sopenharmony_ci amdgpu_crtc->ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK; 87162306a36Sopenharmony_ci amdgpu_crtc->ss.amount |= ((amount - (amount / 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) & 87262306a36Sopenharmony_ci ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK; 87362306a36Sopenharmony_ci if (amdgpu_crtc->ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD) 87462306a36Sopenharmony_ci step_size = (4 * amount * ref_div * ((u32)amdgpu_crtc->ss.rate * 2048)) / 87562306a36Sopenharmony_ci (125 * 25 * pll->reference_freq / 100); 87662306a36Sopenharmony_ci else 87762306a36Sopenharmony_ci step_size = (2 * amount * ref_div * ((u32)amdgpu_crtc->ss.rate * 2048)) / 87862306a36Sopenharmony_ci (125 * 25 * pll->reference_freq / 100); 87962306a36Sopenharmony_ci amdgpu_crtc->ss.step = step_size; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci amdgpu_atombios_crtc_program_ss(adev, ATOM_ENABLE, amdgpu_crtc->pll_id, 88262306a36Sopenharmony_ci amdgpu_crtc->crtc_id, &amdgpu_crtc->ss); 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci} 88562306a36Sopenharmony_ci 886