1254885Sdumbbell/* 2254885Sdumbbell * Copyright 2007-8 Advanced Micro Devices, Inc. 3254885Sdumbbell * Copyright 2008 Red Hat Inc. 4254885Sdumbbell * 5254885Sdumbbell * Permission is hereby granted, free of charge, to any person obtaining a 6254885Sdumbbell * copy of this software and associated documentation files (the "Software"), 7254885Sdumbbell * to deal in the Software without restriction, including without limitation 8254885Sdumbbell * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9254885Sdumbbell * and/or sell copies of the Software, and to permit persons to whom the 10254885Sdumbbell * Software is furnished to do so, subject to the following conditions: 11254885Sdumbbell * 12254885Sdumbbell * The above copyright notice and this permission notice shall be included in 13254885Sdumbbell * all copies or substantial portions of the Software. 14254885Sdumbbell * 15254885Sdumbbell * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16254885Sdumbbell * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17254885Sdumbbell * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18254885Sdumbbell * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 19254885Sdumbbell * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20254885Sdumbbell * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21254885Sdumbbell * OTHER DEALINGS IN THE SOFTWARE. 22254885Sdumbbell * 23254885Sdumbbell * Authors: Dave Airlie 24254885Sdumbbell * Alex Deucher 25254885Sdumbbell */ 26254885Sdumbbell 27254885Sdumbbell#include <sys/cdefs.h> 28254885Sdumbbell__FBSDID("$FreeBSD$"); 29254885Sdumbbell 30254885Sdumbbell#include <dev/drm2/drmP.h> 31254885Sdumbbell#include <dev/drm2/drm_crtc_helper.h> 32254885Sdumbbell#include <dev/drm2/radeon/radeon_drm.h> 33254885Sdumbbell#include <dev/drm2/drm_fixed.h> 34254885Sdumbbell#include "radeon.h" 35254885Sdumbbell#include "atom.h" 36254885Sdumbbell#include "atom-bits.h" 37254885Sdumbbell 38254885Sdumbbellstatic void atombios_overscan_setup(struct drm_crtc *crtc, 39254885Sdumbbell struct drm_display_mode *mode, 40254885Sdumbbell struct drm_display_mode *adjusted_mode) 41254885Sdumbbell{ 42254885Sdumbbell struct drm_device *dev = crtc->dev; 43254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 44254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 45254885Sdumbbell SET_CRTC_OVERSCAN_PS_ALLOCATION args; 46254885Sdumbbell int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan); 47254885Sdumbbell int a1, a2; 48254885Sdumbbell 49254885Sdumbbell memset(&args, 0, sizeof(args)); 50254885Sdumbbell 51254885Sdumbbell args.ucCRTC = radeon_crtc->crtc_id; 52254885Sdumbbell 53254885Sdumbbell switch (radeon_crtc->rmx_type) { 54254885Sdumbbell case RMX_CENTER: 55254885Sdumbbell args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2); 56254885Sdumbbell args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2); 57254885Sdumbbell args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2); 58254885Sdumbbell args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2); 59254885Sdumbbell break; 60254885Sdumbbell case RMX_ASPECT: 61254885Sdumbbell a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay; 62254885Sdumbbell a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay; 63254885Sdumbbell 64254885Sdumbbell if (a1 > a2) { 65254885Sdumbbell args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2); 66254885Sdumbbell args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2); 67254885Sdumbbell } else if (a2 > a1) { 68254885Sdumbbell args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2); 69254885Sdumbbell args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2); 70254885Sdumbbell } 71254885Sdumbbell break; 72254885Sdumbbell case RMX_FULL: 73254885Sdumbbell default: 74254885Sdumbbell args.usOverscanRight = cpu_to_le16(radeon_crtc->h_border); 75254885Sdumbbell args.usOverscanLeft = cpu_to_le16(radeon_crtc->h_border); 76254885Sdumbbell args.usOverscanBottom = cpu_to_le16(radeon_crtc->v_border); 77254885Sdumbbell args.usOverscanTop = cpu_to_le16(radeon_crtc->v_border); 78254885Sdumbbell break; 79254885Sdumbbell } 80254885Sdumbbell atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 81254885Sdumbbell} 82254885Sdumbbell 83254885Sdumbbellstatic void atombios_scaler_setup(struct drm_crtc *crtc) 84254885Sdumbbell{ 85254885Sdumbbell struct drm_device *dev = crtc->dev; 86254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 87254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 88254885Sdumbbell ENABLE_SCALER_PS_ALLOCATION args; 89254885Sdumbbell int index = GetIndexIntoMasterTable(COMMAND, EnableScaler); 90254885Sdumbbell struct radeon_encoder *radeon_encoder = 91254885Sdumbbell to_radeon_encoder(radeon_crtc->encoder); 92254885Sdumbbell /* fixme - fill in enc_priv for atom dac */ 93254885Sdumbbell enum radeon_tv_std tv_std = TV_STD_NTSC; 94254885Sdumbbell bool is_tv = false, is_cv = false; 95254885Sdumbbell 96254885Sdumbbell if (!ASIC_IS_AVIVO(rdev) && radeon_crtc->crtc_id) 97254885Sdumbbell return; 98254885Sdumbbell 99254885Sdumbbell if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) { 100254885Sdumbbell struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv; 101254885Sdumbbell tv_std = tv_dac->tv_std; 102254885Sdumbbell is_tv = true; 103254885Sdumbbell } 104254885Sdumbbell 105254885Sdumbbell memset(&args, 0, sizeof(args)); 106254885Sdumbbell 107254885Sdumbbell args.ucScaler = radeon_crtc->crtc_id; 108254885Sdumbbell 109254885Sdumbbell if (is_tv) { 110254885Sdumbbell switch (tv_std) { 111254885Sdumbbell case TV_STD_NTSC: 112254885Sdumbbell default: 113254885Sdumbbell args.ucTVStandard = ATOM_TV_NTSC; 114254885Sdumbbell break; 115254885Sdumbbell case TV_STD_PAL: 116254885Sdumbbell args.ucTVStandard = ATOM_TV_PAL; 117254885Sdumbbell break; 118254885Sdumbbell case TV_STD_PAL_M: 119254885Sdumbbell args.ucTVStandard = ATOM_TV_PALM; 120254885Sdumbbell break; 121254885Sdumbbell case TV_STD_PAL_60: 122254885Sdumbbell args.ucTVStandard = ATOM_TV_PAL60; 123254885Sdumbbell break; 124254885Sdumbbell case TV_STD_NTSC_J: 125254885Sdumbbell args.ucTVStandard = ATOM_TV_NTSCJ; 126254885Sdumbbell break; 127254885Sdumbbell case TV_STD_SCART_PAL: 128254885Sdumbbell args.ucTVStandard = ATOM_TV_PAL; /* ??? */ 129254885Sdumbbell break; 130254885Sdumbbell case TV_STD_SECAM: 131254885Sdumbbell args.ucTVStandard = ATOM_TV_SECAM; 132254885Sdumbbell break; 133254885Sdumbbell case TV_STD_PAL_CN: 134254885Sdumbbell args.ucTVStandard = ATOM_TV_PALCN; 135254885Sdumbbell break; 136254885Sdumbbell } 137254885Sdumbbell args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; 138254885Sdumbbell } else if (is_cv) { 139254885Sdumbbell args.ucTVStandard = ATOM_TV_CV; 140254885Sdumbbell args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; 141254885Sdumbbell } else { 142254885Sdumbbell switch (radeon_crtc->rmx_type) { 143254885Sdumbbell case RMX_FULL: 144254885Sdumbbell args.ucEnable = ATOM_SCALER_EXPANSION; 145254885Sdumbbell break; 146254885Sdumbbell case RMX_CENTER: 147254885Sdumbbell args.ucEnable = ATOM_SCALER_CENTER; 148254885Sdumbbell break; 149254885Sdumbbell case RMX_ASPECT: 150254885Sdumbbell args.ucEnable = ATOM_SCALER_EXPANSION; 151254885Sdumbbell break; 152254885Sdumbbell default: 153254885Sdumbbell if (ASIC_IS_AVIVO(rdev)) 154254885Sdumbbell args.ucEnable = ATOM_SCALER_DISABLE; 155254885Sdumbbell else 156254885Sdumbbell args.ucEnable = ATOM_SCALER_CENTER; 157254885Sdumbbell break; 158254885Sdumbbell } 159254885Sdumbbell } 160254885Sdumbbell atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 161254885Sdumbbell if ((is_tv || is_cv) 162254885Sdumbbell && rdev->family >= CHIP_RV515 && rdev->family <= CHIP_R580) { 163254885Sdumbbell atom_rv515_force_tv_scaler(rdev, radeon_crtc); 164254885Sdumbbell } 165254885Sdumbbell} 166254885Sdumbbell 167254885Sdumbbellstatic void atombios_lock_crtc(struct drm_crtc *crtc, int lock) 168254885Sdumbbell{ 169254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 170254885Sdumbbell struct drm_device *dev = crtc->dev; 171254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 172254885Sdumbbell int index = 173254885Sdumbbell GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters); 174254885Sdumbbell ENABLE_CRTC_PS_ALLOCATION args; 175254885Sdumbbell 176254885Sdumbbell memset(&args, 0, sizeof(args)); 177254885Sdumbbell 178254885Sdumbbell args.ucCRTC = radeon_crtc->crtc_id; 179254885Sdumbbell args.ucEnable = lock; 180254885Sdumbbell 181254885Sdumbbell atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 182254885Sdumbbell} 183254885Sdumbbell 184254885Sdumbbellstatic void atombios_enable_crtc(struct drm_crtc *crtc, int state) 185254885Sdumbbell{ 186254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 187254885Sdumbbell struct drm_device *dev = crtc->dev; 188254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 189254885Sdumbbell int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC); 190254885Sdumbbell ENABLE_CRTC_PS_ALLOCATION args; 191254885Sdumbbell 192254885Sdumbbell memset(&args, 0, sizeof(args)); 193254885Sdumbbell 194254885Sdumbbell args.ucCRTC = radeon_crtc->crtc_id; 195254885Sdumbbell args.ucEnable = state; 196254885Sdumbbell 197254885Sdumbbell atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 198254885Sdumbbell} 199254885Sdumbbell 200254885Sdumbbellstatic void atombios_enable_crtc_memreq(struct drm_crtc *crtc, int state) 201254885Sdumbbell{ 202254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 203254885Sdumbbell struct drm_device *dev = crtc->dev; 204254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 205254885Sdumbbell int index = GetIndexIntoMasterTable(COMMAND, EnableCRTCMemReq); 206254885Sdumbbell ENABLE_CRTC_PS_ALLOCATION args; 207254885Sdumbbell 208254885Sdumbbell memset(&args, 0, sizeof(args)); 209254885Sdumbbell 210254885Sdumbbell args.ucCRTC = radeon_crtc->crtc_id; 211254885Sdumbbell args.ucEnable = state; 212254885Sdumbbell 213254885Sdumbbell atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 214254885Sdumbbell} 215254885Sdumbbell 216254885Sdumbbellstatic void atombios_blank_crtc(struct drm_crtc *crtc, int state) 217254885Sdumbbell{ 218254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 219254885Sdumbbell struct drm_device *dev = crtc->dev; 220254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 221254885Sdumbbell int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC); 222254885Sdumbbell BLANK_CRTC_PS_ALLOCATION args; 223254885Sdumbbell 224254885Sdumbbell memset(&args, 0, sizeof(args)); 225254885Sdumbbell 226254885Sdumbbell args.ucCRTC = radeon_crtc->crtc_id; 227254885Sdumbbell args.ucBlanking = state; 228254885Sdumbbell 229254885Sdumbbell atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 230254885Sdumbbell} 231254885Sdumbbell 232254885Sdumbbellstatic void atombios_powergate_crtc(struct drm_crtc *crtc, int state) 233254885Sdumbbell{ 234254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 235254885Sdumbbell struct drm_device *dev = crtc->dev; 236254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 237254885Sdumbbell int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating); 238254885Sdumbbell ENABLE_DISP_POWER_GATING_PARAMETERS_V2_1 args; 239254885Sdumbbell 240254885Sdumbbell memset(&args, 0, sizeof(args)); 241254885Sdumbbell 242254885Sdumbbell args.ucDispPipeId = radeon_crtc->crtc_id; 243254885Sdumbbell args.ucEnable = state; 244254885Sdumbbell 245254885Sdumbbell atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 246254885Sdumbbell} 247254885Sdumbbell 248254885Sdumbbellvoid atombios_crtc_dpms(struct drm_crtc *crtc, int mode) 249254885Sdumbbell{ 250254885Sdumbbell struct drm_device *dev = crtc->dev; 251254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 252254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 253254885Sdumbbell 254254885Sdumbbell switch (mode) { 255254885Sdumbbell case DRM_MODE_DPMS_ON: 256254885Sdumbbell radeon_crtc->enabled = true; 257254885Sdumbbell /* adjust pm to dpms changes BEFORE enabling crtcs */ 258254885Sdumbbell radeon_pm_compute_clocks(rdev); 259254885Sdumbbell if (ASIC_IS_DCE6(rdev) && !radeon_crtc->in_mode_set) 260254885Sdumbbell atombios_powergate_crtc(crtc, ATOM_DISABLE); 261254885Sdumbbell atombios_enable_crtc(crtc, ATOM_ENABLE); 262254885Sdumbbell if (ASIC_IS_DCE3(rdev) && !ASIC_IS_DCE6(rdev)) 263254885Sdumbbell atombios_enable_crtc_memreq(crtc, ATOM_ENABLE); 264254885Sdumbbell atombios_blank_crtc(crtc, ATOM_DISABLE); 265254885Sdumbbell drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); 266254885Sdumbbell radeon_crtc_load_lut(crtc); 267254885Sdumbbell break; 268254885Sdumbbell case DRM_MODE_DPMS_STANDBY: 269254885Sdumbbell case DRM_MODE_DPMS_SUSPEND: 270254885Sdumbbell case DRM_MODE_DPMS_OFF: 271254885Sdumbbell drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id); 272254885Sdumbbell if (radeon_crtc->enabled) 273254885Sdumbbell atombios_blank_crtc(crtc, ATOM_ENABLE); 274254885Sdumbbell if (ASIC_IS_DCE3(rdev) && !ASIC_IS_DCE6(rdev)) 275254885Sdumbbell atombios_enable_crtc_memreq(crtc, ATOM_DISABLE); 276254885Sdumbbell atombios_enable_crtc(crtc, ATOM_DISABLE); 277254885Sdumbbell radeon_crtc->enabled = false; 278254885Sdumbbell if (ASIC_IS_DCE6(rdev) && !radeon_crtc->in_mode_set) 279254885Sdumbbell atombios_powergate_crtc(crtc, ATOM_ENABLE); 280254885Sdumbbell /* adjust pm to dpms changes AFTER disabling crtcs */ 281254885Sdumbbell radeon_pm_compute_clocks(rdev); 282254885Sdumbbell break; 283254885Sdumbbell } 284254885Sdumbbell} 285254885Sdumbbell 286254885Sdumbbellstatic void 287254885Sdumbbellatombios_set_crtc_dtd_timing(struct drm_crtc *crtc, 288254885Sdumbbell struct drm_display_mode *mode) 289254885Sdumbbell{ 290254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 291254885Sdumbbell struct drm_device *dev = crtc->dev; 292254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 293254885Sdumbbell SET_CRTC_USING_DTD_TIMING_PARAMETERS args; 294254885Sdumbbell int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming); 295254885Sdumbbell u16 misc = 0; 296254885Sdumbbell 297254885Sdumbbell memset(&args, 0, sizeof(args)); 298254885Sdumbbell args.usH_Size = cpu_to_le16(mode->crtc_hdisplay - (radeon_crtc->h_border * 2)); 299254885Sdumbbell args.usH_Blanking_Time = 300254885Sdumbbell cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay + (radeon_crtc->h_border * 2)); 301254885Sdumbbell args.usV_Size = cpu_to_le16(mode->crtc_vdisplay - (radeon_crtc->v_border * 2)); 302254885Sdumbbell args.usV_Blanking_Time = 303254885Sdumbbell cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay + (radeon_crtc->v_border * 2)); 304254885Sdumbbell args.usH_SyncOffset = 305254885Sdumbbell cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay + radeon_crtc->h_border); 306254885Sdumbbell args.usH_SyncWidth = 307254885Sdumbbell cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start); 308254885Sdumbbell args.usV_SyncOffset = 309254885Sdumbbell cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay + radeon_crtc->v_border); 310254885Sdumbbell args.usV_SyncWidth = 311254885Sdumbbell cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start); 312254885Sdumbbell args.ucH_Border = radeon_crtc->h_border; 313254885Sdumbbell args.ucV_Border = radeon_crtc->v_border; 314254885Sdumbbell 315254885Sdumbbell if (mode->flags & DRM_MODE_FLAG_NVSYNC) 316254885Sdumbbell misc |= ATOM_VSYNC_POLARITY; 317254885Sdumbbell if (mode->flags & DRM_MODE_FLAG_NHSYNC) 318254885Sdumbbell misc |= ATOM_HSYNC_POLARITY; 319254885Sdumbbell if (mode->flags & DRM_MODE_FLAG_CSYNC) 320254885Sdumbbell misc |= ATOM_COMPOSITESYNC; 321254885Sdumbbell if (mode->flags & DRM_MODE_FLAG_INTERLACE) 322254885Sdumbbell misc |= ATOM_INTERLACE; 323254885Sdumbbell if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 324254885Sdumbbell misc |= ATOM_DOUBLE_CLOCK_MODE; 325254885Sdumbbell 326254885Sdumbbell args.susModeMiscInfo.usAccess = cpu_to_le16(misc); 327254885Sdumbbell args.ucCRTC = radeon_crtc->crtc_id; 328254885Sdumbbell 329254885Sdumbbell atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 330254885Sdumbbell} 331254885Sdumbbell 332254885Sdumbbellstatic void atombios_crtc_set_timing(struct drm_crtc *crtc, 333254885Sdumbbell struct drm_display_mode *mode) 334254885Sdumbbell{ 335254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 336254885Sdumbbell struct drm_device *dev = crtc->dev; 337254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 338254885Sdumbbell SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION args; 339254885Sdumbbell int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing); 340254885Sdumbbell u16 misc = 0; 341254885Sdumbbell 342254885Sdumbbell memset(&args, 0, sizeof(args)); 343254885Sdumbbell args.usH_Total = cpu_to_le16(mode->crtc_htotal); 344254885Sdumbbell args.usH_Disp = cpu_to_le16(mode->crtc_hdisplay); 345254885Sdumbbell args.usH_SyncStart = cpu_to_le16(mode->crtc_hsync_start); 346254885Sdumbbell args.usH_SyncWidth = 347254885Sdumbbell cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start); 348254885Sdumbbell args.usV_Total = cpu_to_le16(mode->crtc_vtotal); 349254885Sdumbbell args.usV_Disp = cpu_to_le16(mode->crtc_vdisplay); 350254885Sdumbbell args.usV_SyncStart = cpu_to_le16(mode->crtc_vsync_start); 351254885Sdumbbell args.usV_SyncWidth = 352254885Sdumbbell cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start); 353254885Sdumbbell 354254885Sdumbbell args.ucOverscanRight = radeon_crtc->h_border; 355254885Sdumbbell args.ucOverscanLeft = radeon_crtc->h_border; 356254885Sdumbbell args.ucOverscanBottom = radeon_crtc->v_border; 357254885Sdumbbell args.ucOverscanTop = radeon_crtc->v_border; 358254885Sdumbbell 359254885Sdumbbell if (mode->flags & DRM_MODE_FLAG_NVSYNC) 360254885Sdumbbell misc |= ATOM_VSYNC_POLARITY; 361254885Sdumbbell if (mode->flags & DRM_MODE_FLAG_NHSYNC) 362254885Sdumbbell misc |= ATOM_HSYNC_POLARITY; 363254885Sdumbbell if (mode->flags & DRM_MODE_FLAG_CSYNC) 364254885Sdumbbell misc |= ATOM_COMPOSITESYNC; 365254885Sdumbbell if (mode->flags & DRM_MODE_FLAG_INTERLACE) 366254885Sdumbbell misc |= ATOM_INTERLACE; 367254885Sdumbbell if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 368254885Sdumbbell misc |= ATOM_DOUBLE_CLOCK_MODE; 369254885Sdumbbell 370254885Sdumbbell args.susModeMiscInfo.usAccess = cpu_to_le16(misc); 371254885Sdumbbell args.ucCRTC = radeon_crtc->crtc_id; 372254885Sdumbbell 373254885Sdumbbell atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 374254885Sdumbbell} 375254885Sdumbbell 376254885Sdumbbellstatic void atombios_disable_ss(struct radeon_device *rdev, int pll_id) 377254885Sdumbbell{ 378254885Sdumbbell u32 ss_cntl; 379254885Sdumbbell 380254885Sdumbbell if (ASIC_IS_DCE4(rdev)) { 381254885Sdumbbell switch (pll_id) { 382254885Sdumbbell case ATOM_PPLL1: 383254885Sdumbbell ss_cntl = RREG32(EVERGREEN_P1PLL_SS_CNTL); 384254885Sdumbbell ss_cntl &= ~EVERGREEN_PxPLL_SS_EN; 385254885Sdumbbell WREG32(EVERGREEN_P1PLL_SS_CNTL, ss_cntl); 386254885Sdumbbell break; 387254885Sdumbbell case ATOM_PPLL2: 388254885Sdumbbell ss_cntl = RREG32(EVERGREEN_P2PLL_SS_CNTL); 389254885Sdumbbell ss_cntl &= ~EVERGREEN_PxPLL_SS_EN; 390254885Sdumbbell WREG32(EVERGREEN_P2PLL_SS_CNTL, ss_cntl); 391254885Sdumbbell break; 392254885Sdumbbell case ATOM_DCPLL: 393254885Sdumbbell case ATOM_PPLL_INVALID: 394254885Sdumbbell return; 395254885Sdumbbell } 396254885Sdumbbell } else if (ASIC_IS_AVIVO(rdev)) { 397254885Sdumbbell switch (pll_id) { 398254885Sdumbbell case ATOM_PPLL1: 399254885Sdumbbell ss_cntl = RREG32(AVIVO_P1PLL_INT_SS_CNTL); 400254885Sdumbbell ss_cntl &= ~1; 401254885Sdumbbell WREG32(AVIVO_P1PLL_INT_SS_CNTL, ss_cntl); 402254885Sdumbbell break; 403254885Sdumbbell case ATOM_PPLL2: 404254885Sdumbbell ss_cntl = RREG32(AVIVO_P2PLL_INT_SS_CNTL); 405254885Sdumbbell ss_cntl &= ~1; 406254885Sdumbbell WREG32(AVIVO_P2PLL_INT_SS_CNTL, ss_cntl); 407254885Sdumbbell break; 408254885Sdumbbell case ATOM_DCPLL: 409254885Sdumbbell case ATOM_PPLL_INVALID: 410254885Sdumbbell return; 411254885Sdumbbell } 412254885Sdumbbell } 413254885Sdumbbell} 414254885Sdumbbell 415254885Sdumbbell 416254885Sdumbbellunion atom_enable_ss { 417254885Sdumbbell ENABLE_LVDS_SS_PARAMETERS lvds_ss; 418254885Sdumbbell ENABLE_LVDS_SS_PARAMETERS_V2 lvds_ss_2; 419254885Sdumbbell ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1; 420254885Sdumbbell ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 v2; 421254885Sdumbbell ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 v3; 422254885Sdumbbell}; 423254885Sdumbbell 424254885Sdumbbellstatic void atombios_crtc_program_ss(struct radeon_device *rdev, 425254885Sdumbbell int enable, 426254885Sdumbbell int pll_id, 427254885Sdumbbell int crtc_id, 428254885Sdumbbell struct radeon_atom_ss *ss) 429254885Sdumbbell{ 430254885Sdumbbell unsigned i; 431254885Sdumbbell int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL); 432254885Sdumbbell union atom_enable_ss args; 433254885Sdumbbell 434254885Sdumbbell if (!enable) { 435254885Sdumbbell for (i = 0; i < rdev->num_crtc; i++) { 436254885Sdumbbell if (rdev->mode_info.crtcs[i] && 437254885Sdumbbell rdev->mode_info.crtcs[i]->enabled && 438254885Sdumbbell i != crtc_id && 439254885Sdumbbell pll_id == rdev->mode_info.crtcs[i]->pll_id) { 440254885Sdumbbell /* one other crtc is using this pll don't turn 441254885Sdumbbell * off spread spectrum as it might turn off 442254885Sdumbbell * display on active crtc 443254885Sdumbbell */ 444254885Sdumbbell return; 445254885Sdumbbell } 446254885Sdumbbell } 447254885Sdumbbell } 448254885Sdumbbell 449254885Sdumbbell memset(&args, 0, sizeof(args)); 450254885Sdumbbell 451254885Sdumbbell if (ASIC_IS_DCE5(rdev)) { 452254885Sdumbbell args.v3.usSpreadSpectrumAmountFrac = cpu_to_le16(0); 453254885Sdumbbell args.v3.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 454254885Sdumbbell switch (pll_id) { 455254885Sdumbbell case ATOM_PPLL1: 456254885Sdumbbell args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL; 457254885Sdumbbell break; 458254885Sdumbbell case ATOM_PPLL2: 459254885Sdumbbell args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL; 460254885Sdumbbell break; 461254885Sdumbbell case ATOM_DCPLL: 462254885Sdumbbell args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL; 463254885Sdumbbell break; 464254885Sdumbbell case ATOM_PPLL_INVALID: 465254885Sdumbbell return; 466254885Sdumbbell } 467254885Sdumbbell args.v3.usSpreadSpectrumAmount = cpu_to_le16(ss->amount); 468254885Sdumbbell args.v3.usSpreadSpectrumStep = cpu_to_le16(ss->step); 469254885Sdumbbell args.v3.ucEnable = enable; 470254885Sdumbbell if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK) || ASIC_IS_DCE61(rdev)) 471254885Sdumbbell args.v3.ucEnable = ATOM_DISABLE; 472254885Sdumbbell } else if (ASIC_IS_DCE4(rdev)) { 473254885Sdumbbell args.v2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); 474254885Sdumbbell args.v2.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 475254885Sdumbbell switch (pll_id) { 476254885Sdumbbell case ATOM_PPLL1: 477254885Sdumbbell args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P1PLL; 478254885Sdumbbell break; 479254885Sdumbbell case ATOM_PPLL2: 480254885Sdumbbell args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P2PLL; 481254885Sdumbbell break; 482254885Sdumbbell case ATOM_DCPLL: 483254885Sdumbbell args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_DCPLL; 484254885Sdumbbell break; 485254885Sdumbbell case ATOM_PPLL_INVALID: 486254885Sdumbbell return; 487254885Sdumbbell } 488254885Sdumbbell args.v2.usSpreadSpectrumAmount = cpu_to_le16(ss->amount); 489254885Sdumbbell args.v2.usSpreadSpectrumStep = cpu_to_le16(ss->step); 490254885Sdumbbell args.v2.ucEnable = enable; 491254885Sdumbbell if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK) || ASIC_IS_DCE41(rdev)) 492254885Sdumbbell args.v2.ucEnable = ATOM_DISABLE; 493254885Sdumbbell } else if (ASIC_IS_DCE3(rdev)) { 494254885Sdumbbell args.v1.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); 495254885Sdumbbell args.v1.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 496254885Sdumbbell args.v1.ucSpreadSpectrumStep = ss->step; 497254885Sdumbbell args.v1.ucSpreadSpectrumDelay = ss->delay; 498254885Sdumbbell args.v1.ucSpreadSpectrumRange = ss->range; 499254885Sdumbbell args.v1.ucPpll = pll_id; 500254885Sdumbbell args.v1.ucEnable = enable; 501254885Sdumbbell } else if (ASIC_IS_AVIVO(rdev)) { 502254885Sdumbbell if ((enable == ATOM_DISABLE) || (ss->percentage == 0) || 503254885Sdumbbell (ss->type & ATOM_EXTERNAL_SS_MASK)) { 504254885Sdumbbell atombios_disable_ss(rdev, pll_id); 505254885Sdumbbell return; 506254885Sdumbbell } 507254885Sdumbbell args.lvds_ss_2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); 508254885Sdumbbell args.lvds_ss_2.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 509254885Sdumbbell args.lvds_ss_2.ucSpreadSpectrumStep = ss->step; 510254885Sdumbbell args.lvds_ss_2.ucSpreadSpectrumDelay = ss->delay; 511254885Sdumbbell args.lvds_ss_2.ucSpreadSpectrumRange = ss->range; 512254885Sdumbbell args.lvds_ss_2.ucEnable = enable; 513254885Sdumbbell } else { 514254885Sdumbbell if ((enable == ATOM_DISABLE) || (ss->percentage == 0) || 515254885Sdumbbell (ss->type & ATOM_EXTERNAL_SS_MASK)) { 516254885Sdumbbell atombios_disable_ss(rdev, pll_id); 517254885Sdumbbell return; 518254885Sdumbbell } 519254885Sdumbbell args.lvds_ss.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); 520254885Sdumbbell args.lvds_ss.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 521254885Sdumbbell args.lvds_ss.ucSpreadSpectrumStepSize_Delay = (ss->step & 3) << 2; 522254885Sdumbbell args.lvds_ss.ucSpreadSpectrumStepSize_Delay |= (ss->delay & 7) << 4; 523254885Sdumbbell args.lvds_ss.ucEnable = enable; 524254885Sdumbbell } 525254885Sdumbbell atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 526254885Sdumbbell} 527254885Sdumbbell 528254885Sdumbbellunion adjust_pixel_clock { 529254885Sdumbbell ADJUST_DISPLAY_PLL_PS_ALLOCATION v1; 530254885Sdumbbell ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 v3; 531254885Sdumbbell}; 532254885Sdumbbell 533254885Sdumbbellstatic u32 atombios_adjust_pll(struct drm_crtc *crtc, 534254885Sdumbbell struct drm_display_mode *mode) 535254885Sdumbbell{ 536254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 537254885Sdumbbell struct drm_device *dev = crtc->dev; 538254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 539254885Sdumbbell struct drm_encoder *encoder = radeon_crtc->encoder; 540254885Sdumbbell struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 541254885Sdumbbell struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); 542254885Sdumbbell u32 adjusted_clock = mode->clock; 543254885Sdumbbell int encoder_mode = atombios_get_encoder_mode(encoder); 544254885Sdumbbell u32 dp_clock = mode->clock; 545254885Sdumbbell int bpc = radeon_get_monitor_bpc(connector); 546254885Sdumbbell bool is_duallink = radeon_dig_monitor_is_duallink(encoder, mode->clock); 547254885Sdumbbell 548254885Sdumbbell /* reset the pll flags */ 549254885Sdumbbell radeon_crtc->pll_flags = 0; 550254885Sdumbbell 551254885Sdumbbell if (ASIC_IS_AVIVO(rdev)) { 552254885Sdumbbell if ((rdev->family == CHIP_RS600) || 553254885Sdumbbell (rdev->family == CHIP_RS690) || 554254885Sdumbbell (rdev->family == CHIP_RS740)) 555254885Sdumbbell radeon_crtc->pll_flags |= (/*RADEON_PLL_USE_FRAC_FB_DIV |*/ 556254885Sdumbbell RADEON_PLL_PREFER_CLOSEST_LOWER); 557254885Sdumbbell 558254885Sdumbbell if (ASIC_IS_DCE32(rdev) && mode->clock > 200000) /* range limits??? */ 559254885Sdumbbell radeon_crtc->pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; 560254885Sdumbbell else 561254885Sdumbbell radeon_crtc->pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; 562254885Sdumbbell 563254885Sdumbbell if (rdev->family < CHIP_RV770) 564254885Sdumbbell radeon_crtc->pll_flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP; 565254885Sdumbbell /* use frac fb div on APUs */ 566254885Sdumbbell if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev)) 567254885Sdumbbell radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; 568254885Sdumbbell if (ASIC_IS_DCE32(rdev) && mode->clock > 165000) 569254885Sdumbbell radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; 570254885Sdumbbell } else { 571254885Sdumbbell radeon_crtc->pll_flags |= RADEON_PLL_LEGACY; 572254885Sdumbbell 573254885Sdumbbell if (mode->clock > 200000) /* range limits??? */ 574254885Sdumbbell radeon_crtc->pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; 575254885Sdumbbell else 576254885Sdumbbell radeon_crtc->pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; 577254885Sdumbbell } 578254885Sdumbbell 579254885Sdumbbell if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) || 580254885Sdumbbell (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)) { 581254885Sdumbbell if (connector) { 582254885Sdumbbell struct radeon_connector *radeon_connector = to_radeon_connector(connector); 583254885Sdumbbell struct radeon_connector_atom_dig *dig_connector = 584254885Sdumbbell radeon_connector->con_priv; 585254885Sdumbbell 586254885Sdumbbell dp_clock = dig_connector->dp_clock; 587254885Sdumbbell } 588254885Sdumbbell } 589254885Sdumbbell 590254885Sdumbbell /* use recommended ref_div for ss */ 591254885Sdumbbell if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 592254885Sdumbbell if (radeon_crtc->ss_enabled) { 593254885Sdumbbell if (radeon_crtc->ss.refdiv) { 594254885Sdumbbell radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV; 595254885Sdumbbell radeon_crtc->pll_reference_div = radeon_crtc->ss.refdiv; 596254885Sdumbbell if (ASIC_IS_AVIVO(rdev)) 597254885Sdumbbell radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; 598254885Sdumbbell } 599254885Sdumbbell } 600254885Sdumbbell } 601254885Sdumbbell 602254885Sdumbbell if (ASIC_IS_AVIVO(rdev)) { 603254885Sdumbbell /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ 604254885Sdumbbell if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1) 605254885Sdumbbell adjusted_clock = mode->clock * 2; 606254885Sdumbbell if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 607254885Sdumbbell radeon_crtc->pll_flags |= RADEON_PLL_PREFER_CLOSEST_LOWER; 608254885Sdumbbell if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) 609254885Sdumbbell radeon_crtc->pll_flags |= RADEON_PLL_IS_LCD; 610254885Sdumbbell } else { 611254885Sdumbbell if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) 612254885Sdumbbell radeon_crtc->pll_flags |= RADEON_PLL_NO_ODD_POST_DIV; 613254885Sdumbbell if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) 614254885Sdumbbell radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV; 615254885Sdumbbell } 616254885Sdumbbell 617254885Sdumbbell /* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock 618254885Sdumbbell * accordingly based on the encoder/transmitter to work around 619254885Sdumbbell * special hw requirements. 620254885Sdumbbell */ 621254885Sdumbbell if (ASIC_IS_DCE3(rdev)) { 622254885Sdumbbell union adjust_pixel_clock args; 623254885Sdumbbell u8 frev, crev; 624254885Sdumbbell int index; 625254885Sdumbbell 626254885Sdumbbell index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll); 627254885Sdumbbell if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 628254885Sdumbbell &crev)) 629254885Sdumbbell return adjusted_clock; 630254885Sdumbbell 631254885Sdumbbell memset(&args, 0, sizeof(args)); 632254885Sdumbbell 633254885Sdumbbell switch (frev) { 634254885Sdumbbell case 1: 635254885Sdumbbell switch (crev) { 636254885Sdumbbell case 1: 637254885Sdumbbell case 2: 638254885Sdumbbell args.v1.usPixelClock = cpu_to_le16(mode->clock / 10); 639254885Sdumbbell args.v1.ucTransmitterID = radeon_encoder->encoder_id; 640254885Sdumbbell args.v1.ucEncodeMode = encoder_mode; 641254885Sdumbbell if (radeon_crtc->ss_enabled && radeon_crtc->ss.percentage) 642254885Sdumbbell args.v1.ucConfig |= 643254885Sdumbbell ADJUST_DISPLAY_CONFIG_SS_ENABLE; 644254885Sdumbbell 645254885Sdumbbell atom_execute_table(rdev->mode_info.atom_context, 646254885Sdumbbell index, (uint32_t *)&args); 647254885Sdumbbell adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10; 648254885Sdumbbell break; 649254885Sdumbbell case 3: 650254885Sdumbbell args.v3.sInput.usPixelClock = cpu_to_le16(mode->clock / 10); 651254885Sdumbbell args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id; 652254885Sdumbbell args.v3.sInput.ucEncodeMode = encoder_mode; 653254885Sdumbbell args.v3.sInput.ucDispPllConfig = 0; 654254885Sdumbbell if (radeon_crtc->ss_enabled && radeon_crtc->ss.percentage) 655254885Sdumbbell args.v3.sInput.ucDispPllConfig |= 656254885Sdumbbell DISPPLL_CONFIG_SS_ENABLE; 657254885Sdumbbell if (ENCODER_MODE_IS_DP(encoder_mode)) { 658254885Sdumbbell args.v3.sInput.ucDispPllConfig |= 659254885Sdumbbell DISPPLL_CONFIG_COHERENT_MODE; 660254885Sdumbbell /* 16200 or 27000 */ 661254885Sdumbbell args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); 662254885Sdumbbell } else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { 663254885Sdumbbell struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 664254885Sdumbbell if (encoder_mode == ATOM_ENCODER_MODE_HDMI) 665254885Sdumbbell /* deep color support */ 666254885Sdumbbell args.v3.sInput.usPixelClock = 667254885Sdumbbell cpu_to_le16((mode->clock * bpc / 8) / 10); 668254885Sdumbbell if (dig->coherent_mode) 669254885Sdumbbell args.v3.sInput.ucDispPllConfig |= 670254885Sdumbbell DISPPLL_CONFIG_COHERENT_MODE; 671254885Sdumbbell if (is_duallink) 672254885Sdumbbell args.v3.sInput.ucDispPllConfig |= 673254885Sdumbbell DISPPLL_CONFIG_DUAL_LINK; 674254885Sdumbbell } 675254885Sdumbbell if (radeon_encoder_get_dp_bridge_encoder_id(encoder) != 676254885Sdumbbell ENCODER_OBJECT_ID_NONE) 677254885Sdumbbell args.v3.sInput.ucExtTransmitterID = 678254885Sdumbbell radeon_encoder_get_dp_bridge_encoder_id(encoder); 679254885Sdumbbell else 680254885Sdumbbell args.v3.sInput.ucExtTransmitterID = 0; 681254885Sdumbbell 682254885Sdumbbell atom_execute_table(rdev->mode_info.atom_context, 683254885Sdumbbell index, (uint32_t *)&args); 684254885Sdumbbell adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10; 685254885Sdumbbell if (args.v3.sOutput.ucRefDiv) { 686254885Sdumbbell radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; 687254885Sdumbbell radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV; 688254885Sdumbbell radeon_crtc->pll_reference_div = args.v3.sOutput.ucRefDiv; 689254885Sdumbbell } 690254885Sdumbbell if (args.v3.sOutput.ucPostDiv) { 691254885Sdumbbell radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; 692254885Sdumbbell radeon_crtc->pll_flags |= RADEON_PLL_USE_POST_DIV; 693254885Sdumbbell radeon_crtc->pll_post_div = args.v3.sOutput.ucPostDiv; 694254885Sdumbbell } 695254885Sdumbbell break; 696254885Sdumbbell default: 697254885Sdumbbell DRM_ERROR("Unknown table version %d %d\n", frev, crev); 698254885Sdumbbell return adjusted_clock; 699254885Sdumbbell } 700254885Sdumbbell break; 701254885Sdumbbell default: 702254885Sdumbbell DRM_ERROR("Unknown table version %d %d\n", frev, crev); 703254885Sdumbbell return adjusted_clock; 704254885Sdumbbell } 705254885Sdumbbell } 706254885Sdumbbell return adjusted_clock; 707254885Sdumbbell} 708254885Sdumbbell 709254885Sdumbbellunion set_pixel_clock { 710254885Sdumbbell SET_PIXEL_CLOCK_PS_ALLOCATION base; 711254885Sdumbbell PIXEL_CLOCK_PARAMETERS v1; 712254885Sdumbbell PIXEL_CLOCK_PARAMETERS_V2 v2; 713254885Sdumbbell PIXEL_CLOCK_PARAMETERS_V3 v3; 714254885Sdumbbell PIXEL_CLOCK_PARAMETERS_V5 v5; 715254885Sdumbbell PIXEL_CLOCK_PARAMETERS_V6 v6; 716254885Sdumbbell}; 717254885Sdumbbell 718254885Sdumbbell/* on DCE5, make sure the voltage is high enough to support the 719254885Sdumbbell * required disp clk. 720254885Sdumbbell */ 721254885Sdumbbellstatic void atombios_crtc_set_disp_eng_pll(struct radeon_device *rdev, 722254885Sdumbbell u32 dispclk) 723254885Sdumbbell{ 724254885Sdumbbell u8 frev, crev; 725254885Sdumbbell int index; 726254885Sdumbbell union set_pixel_clock args; 727254885Sdumbbell 728254885Sdumbbell memset(&args, 0, sizeof(args)); 729254885Sdumbbell 730254885Sdumbbell index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); 731254885Sdumbbell if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 732254885Sdumbbell &crev)) 733254885Sdumbbell return; 734254885Sdumbbell 735254885Sdumbbell switch (frev) { 736254885Sdumbbell case 1: 737254885Sdumbbell switch (crev) { 738254885Sdumbbell case 5: 739254885Sdumbbell /* if the default dcpll clock is specified, 740254885Sdumbbell * SetPixelClock provides the dividers 741254885Sdumbbell */ 742254885Sdumbbell args.v5.ucCRTC = ATOM_CRTC_INVALID; 743254885Sdumbbell args.v5.usPixelClock = cpu_to_le16(dispclk); 744254885Sdumbbell args.v5.ucPpll = ATOM_DCPLL; 745254885Sdumbbell break; 746254885Sdumbbell case 6: 747254885Sdumbbell /* if the default dcpll clock is specified, 748254885Sdumbbell * SetPixelClock provides the dividers 749254885Sdumbbell */ 750254885Sdumbbell args.v6.ulDispEngClkFreq = cpu_to_le32(dispclk); 751254885Sdumbbell if (ASIC_IS_DCE61(rdev)) 752254885Sdumbbell args.v6.ucPpll = ATOM_EXT_PLL1; 753254885Sdumbbell else if (ASIC_IS_DCE6(rdev)) 754254885Sdumbbell args.v6.ucPpll = ATOM_PPLL0; 755254885Sdumbbell else 756254885Sdumbbell args.v6.ucPpll = ATOM_DCPLL; 757254885Sdumbbell break; 758254885Sdumbbell default: 759254885Sdumbbell DRM_ERROR("Unknown table version %d %d\n", frev, crev); 760254885Sdumbbell return; 761254885Sdumbbell } 762254885Sdumbbell break; 763254885Sdumbbell default: 764254885Sdumbbell DRM_ERROR("Unknown table version %d %d\n", frev, crev); 765254885Sdumbbell return; 766254885Sdumbbell } 767254885Sdumbbell atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 768254885Sdumbbell} 769254885Sdumbbell 770254885Sdumbbellstatic void atombios_crtc_program_pll(struct drm_crtc *crtc, 771254885Sdumbbell u32 crtc_id, 772254885Sdumbbell int pll_id, 773254885Sdumbbell u32 encoder_mode, 774254885Sdumbbell u32 encoder_id, 775254885Sdumbbell u32 clock, 776254885Sdumbbell u32 ref_div, 777254885Sdumbbell u32 fb_div, 778254885Sdumbbell u32 frac_fb_div, 779254885Sdumbbell u32 post_div, 780254885Sdumbbell int bpc, 781254885Sdumbbell bool ss_enabled, 782254885Sdumbbell struct radeon_atom_ss *ss) 783254885Sdumbbell{ 784254885Sdumbbell struct drm_device *dev = crtc->dev; 785254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 786254885Sdumbbell u8 frev, crev; 787254885Sdumbbell int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); 788254885Sdumbbell union set_pixel_clock args; 789254885Sdumbbell 790254885Sdumbbell memset(&args, 0, sizeof(args)); 791254885Sdumbbell 792254885Sdumbbell if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 793254885Sdumbbell &crev)) 794254885Sdumbbell return; 795254885Sdumbbell 796254885Sdumbbell switch (frev) { 797254885Sdumbbell case 1: 798254885Sdumbbell switch (crev) { 799254885Sdumbbell case 1: 800254885Sdumbbell if (clock == ATOM_DISABLE) 801254885Sdumbbell return; 802254885Sdumbbell args.v1.usPixelClock = cpu_to_le16(clock / 10); 803254885Sdumbbell args.v1.usRefDiv = cpu_to_le16(ref_div); 804254885Sdumbbell args.v1.usFbDiv = cpu_to_le16(fb_div); 805254885Sdumbbell args.v1.ucFracFbDiv = frac_fb_div; 806254885Sdumbbell args.v1.ucPostDiv = post_div; 807254885Sdumbbell args.v1.ucPpll = pll_id; 808254885Sdumbbell args.v1.ucCRTC = crtc_id; 809254885Sdumbbell args.v1.ucRefDivSrc = 1; 810254885Sdumbbell break; 811254885Sdumbbell case 2: 812254885Sdumbbell args.v2.usPixelClock = cpu_to_le16(clock / 10); 813254885Sdumbbell args.v2.usRefDiv = cpu_to_le16(ref_div); 814254885Sdumbbell args.v2.usFbDiv = cpu_to_le16(fb_div); 815254885Sdumbbell args.v2.ucFracFbDiv = frac_fb_div; 816254885Sdumbbell args.v2.ucPostDiv = post_div; 817254885Sdumbbell args.v2.ucPpll = pll_id; 818254885Sdumbbell args.v2.ucCRTC = crtc_id; 819254885Sdumbbell args.v2.ucRefDivSrc = 1; 820254885Sdumbbell break; 821254885Sdumbbell case 3: 822254885Sdumbbell args.v3.usPixelClock = cpu_to_le16(clock / 10); 823254885Sdumbbell args.v3.usRefDiv = cpu_to_le16(ref_div); 824254885Sdumbbell args.v3.usFbDiv = cpu_to_le16(fb_div); 825254885Sdumbbell args.v3.ucFracFbDiv = frac_fb_div; 826254885Sdumbbell args.v3.ucPostDiv = post_div; 827254885Sdumbbell args.v3.ucPpll = pll_id; 828254885Sdumbbell if (crtc_id == ATOM_CRTC2) 829254885Sdumbbell args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC2; 830254885Sdumbbell else 831254885Sdumbbell args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC1; 832254885Sdumbbell if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) 833254885Sdumbbell args.v3.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC; 834254885Sdumbbell args.v3.ucTransmitterId = encoder_id; 835254885Sdumbbell args.v3.ucEncoderMode = encoder_mode; 836254885Sdumbbell break; 837254885Sdumbbell case 5: 838254885Sdumbbell args.v5.ucCRTC = crtc_id; 839254885Sdumbbell args.v5.usPixelClock = cpu_to_le16(clock / 10); 840254885Sdumbbell args.v5.ucRefDiv = ref_div; 841254885Sdumbbell args.v5.usFbDiv = cpu_to_le16(fb_div); 842254885Sdumbbell args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); 843254885Sdumbbell args.v5.ucPostDiv = post_div; 844254885Sdumbbell args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */ 845254885Sdumbbell if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) 846254885Sdumbbell args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_REF_DIV_SRC; 847254885Sdumbbell switch (bpc) { 848254885Sdumbbell case 8: 849254885Sdumbbell default: 850254885Sdumbbell args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP; 851254885Sdumbbell break; 852254885Sdumbbell case 10: 853254885Sdumbbell args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP; 854254885Sdumbbell break; 855254885Sdumbbell } 856254885Sdumbbell args.v5.ucTransmitterID = encoder_id; 857254885Sdumbbell args.v5.ucEncoderMode = encoder_mode; 858254885Sdumbbell args.v5.ucPpll = pll_id; 859254885Sdumbbell break; 860254885Sdumbbell case 6: 861254885Sdumbbell args.v6.ulDispEngClkFreq = cpu_to_le32(crtc_id << 24 | clock / 10); 862254885Sdumbbell args.v6.ucRefDiv = ref_div; 863254885Sdumbbell args.v6.usFbDiv = cpu_to_le16(fb_div); 864254885Sdumbbell args.v6.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); 865254885Sdumbbell args.v6.ucPostDiv = post_div; 866254885Sdumbbell args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */ 867254885Sdumbbell if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) 868254885Sdumbbell args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_REF_DIV_SRC; 869254885Sdumbbell switch (bpc) { 870254885Sdumbbell case 8: 871254885Sdumbbell default: 872254885Sdumbbell args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP; 873254885Sdumbbell break; 874254885Sdumbbell case 10: 875254885Sdumbbell args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP; 876254885Sdumbbell break; 877254885Sdumbbell case 12: 878254885Sdumbbell args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP; 879254885Sdumbbell break; 880254885Sdumbbell case 16: 881254885Sdumbbell args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP; 882254885Sdumbbell break; 883254885Sdumbbell } 884254885Sdumbbell args.v6.ucTransmitterID = encoder_id; 885254885Sdumbbell args.v6.ucEncoderMode = encoder_mode; 886254885Sdumbbell args.v6.ucPpll = pll_id; 887254885Sdumbbell break; 888254885Sdumbbell default: 889254885Sdumbbell DRM_ERROR("Unknown table version %d %d\n", frev, crev); 890254885Sdumbbell return; 891254885Sdumbbell } 892254885Sdumbbell break; 893254885Sdumbbell default: 894254885Sdumbbell DRM_ERROR("Unknown table version %d %d\n", frev, crev); 895254885Sdumbbell return; 896254885Sdumbbell } 897254885Sdumbbell 898254885Sdumbbell atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 899254885Sdumbbell} 900254885Sdumbbell 901254885Sdumbbellstatic bool atombios_crtc_prepare_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) 902254885Sdumbbell{ 903254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 904254885Sdumbbell struct drm_device *dev = crtc->dev; 905254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 906254885Sdumbbell struct radeon_encoder *radeon_encoder = 907254885Sdumbbell to_radeon_encoder(radeon_crtc->encoder); 908254885Sdumbbell int encoder_mode = atombios_get_encoder_mode(radeon_crtc->encoder); 909254885Sdumbbell 910254885Sdumbbell radeon_crtc->bpc = 8; 911254885Sdumbbell radeon_crtc->ss_enabled = false; 912254885Sdumbbell 913254885Sdumbbell if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) || 914254885Sdumbbell (radeon_encoder_get_dp_bridge_encoder_id(radeon_crtc->encoder) != ENCODER_OBJECT_ID_NONE)) { 915254885Sdumbbell struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 916254885Sdumbbell struct drm_connector *connector = 917254885Sdumbbell radeon_get_connector_for_encoder(radeon_crtc->encoder); 918254885Sdumbbell struct radeon_connector *radeon_connector = 919254885Sdumbbell to_radeon_connector(connector); 920254885Sdumbbell struct radeon_connector_atom_dig *dig_connector = 921254885Sdumbbell radeon_connector->con_priv; 922254885Sdumbbell int dp_clock; 923254885Sdumbbell radeon_crtc->bpc = radeon_get_monitor_bpc(connector); 924254885Sdumbbell 925254885Sdumbbell switch (encoder_mode) { 926254885Sdumbbell case ATOM_ENCODER_MODE_DP_MST: 927254885Sdumbbell case ATOM_ENCODER_MODE_DP: 928254885Sdumbbell /* DP/eDP */ 929254885Sdumbbell dp_clock = dig_connector->dp_clock / 10; 930254885Sdumbbell if (ASIC_IS_DCE4(rdev)) 931254885Sdumbbell radeon_crtc->ss_enabled = 932254885Sdumbbell radeon_atombios_get_asic_ss_info(rdev, &radeon_crtc->ss, 933254885Sdumbbell ASIC_INTERNAL_SS_ON_DP, 934254885Sdumbbell dp_clock); 935254885Sdumbbell else { 936254885Sdumbbell if (dp_clock == 16200) { 937254885Sdumbbell radeon_crtc->ss_enabled = 938254885Sdumbbell radeon_atombios_get_ppll_ss_info(rdev, 939254885Sdumbbell &radeon_crtc->ss, 940254885Sdumbbell ATOM_DP_SS_ID2); 941254885Sdumbbell if (!radeon_crtc->ss_enabled) 942254885Sdumbbell radeon_crtc->ss_enabled = 943254885Sdumbbell radeon_atombios_get_ppll_ss_info(rdev, 944254885Sdumbbell &radeon_crtc->ss, 945254885Sdumbbell ATOM_DP_SS_ID1); 946254885Sdumbbell } else 947254885Sdumbbell radeon_crtc->ss_enabled = 948254885Sdumbbell radeon_atombios_get_ppll_ss_info(rdev, 949254885Sdumbbell &radeon_crtc->ss, 950254885Sdumbbell ATOM_DP_SS_ID1); 951254885Sdumbbell } 952254885Sdumbbell break; 953254885Sdumbbell case ATOM_ENCODER_MODE_LVDS: 954254885Sdumbbell if (ASIC_IS_DCE4(rdev)) 955254885Sdumbbell radeon_crtc->ss_enabled = 956254885Sdumbbell radeon_atombios_get_asic_ss_info(rdev, 957254885Sdumbbell &radeon_crtc->ss, 958254885Sdumbbell dig->lcd_ss_id, 959254885Sdumbbell mode->clock / 10); 960254885Sdumbbell else 961254885Sdumbbell radeon_crtc->ss_enabled = 962254885Sdumbbell radeon_atombios_get_ppll_ss_info(rdev, 963254885Sdumbbell &radeon_crtc->ss, 964254885Sdumbbell dig->lcd_ss_id); 965254885Sdumbbell break; 966254885Sdumbbell case ATOM_ENCODER_MODE_DVI: 967254885Sdumbbell if (ASIC_IS_DCE4(rdev)) 968254885Sdumbbell radeon_crtc->ss_enabled = 969254885Sdumbbell radeon_atombios_get_asic_ss_info(rdev, 970254885Sdumbbell &radeon_crtc->ss, 971254885Sdumbbell ASIC_INTERNAL_SS_ON_TMDS, 972254885Sdumbbell mode->clock / 10); 973254885Sdumbbell break; 974254885Sdumbbell case ATOM_ENCODER_MODE_HDMI: 975254885Sdumbbell if (ASIC_IS_DCE4(rdev)) 976254885Sdumbbell radeon_crtc->ss_enabled = 977254885Sdumbbell radeon_atombios_get_asic_ss_info(rdev, 978254885Sdumbbell &radeon_crtc->ss, 979254885Sdumbbell ASIC_INTERNAL_SS_ON_HDMI, 980254885Sdumbbell mode->clock / 10); 981254885Sdumbbell break; 982254885Sdumbbell default: 983254885Sdumbbell break; 984254885Sdumbbell } 985254885Sdumbbell } 986254885Sdumbbell 987254885Sdumbbell /* adjust pixel clock as needed */ 988254885Sdumbbell radeon_crtc->adjusted_clock = atombios_adjust_pll(crtc, mode); 989254885Sdumbbell 990254885Sdumbbell return true; 991254885Sdumbbell} 992254885Sdumbbell 993254885Sdumbbellstatic void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) 994254885Sdumbbell{ 995254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 996254885Sdumbbell struct drm_device *dev = crtc->dev; 997254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 998254885Sdumbbell struct radeon_encoder *radeon_encoder = 999254885Sdumbbell to_radeon_encoder(radeon_crtc->encoder); 1000254885Sdumbbell u32 pll_clock = mode->clock; 1001254885Sdumbbell u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; 1002254885Sdumbbell struct radeon_pll *pll; 1003254885Sdumbbell int encoder_mode = atombios_get_encoder_mode(radeon_crtc->encoder); 1004254885Sdumbbell 1005254885Sdumbbell switch (radeon_crtc->pll_id) { 1006254885Sdumbbell case ATOM_PPLL1: 1007254885Sdumbbell pll = &rdev->clock.p1pll; 1008254885Sdumbbell break; 1009254885Sdumbbell case ATOM_PPLL2: 1010254885Sdumbbell pll = &rdev->clock.p2pll; 1011254885Sdumbbell break; 1012254885Sdumbbell case ATOM_DCPLL: 1013254885Sdumbbell case ATOM_PPLL_INVALID: 1014254885Sdumbbell default: 1015254885Sdumbbell pll = &rdev->clock.dcpll; 1016254885Sdumbbell break; 1017254885Sdumbbell } 1018254885Sdumbbell 1019254885Sdumbbell /* update pll params */ 1020254885Sdumbbell pll->flags = radeon_crtc->pll_flags; 1021254885Sdumbbell pll->reference_div = radeon_crtc->pll_reference_div; 1022254885Sdumbbell pll->post_div = radeon_crtc->pll_post_div; 1023254885Sdumbbell 1024254885Sdumbbell if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 1025254885Sdumbbell /* TV seems to prefer the legacy algo on some boards */ 1026254885Sdumbbell radeon_compute_pll_legacy(pll, radeon_crtc->adjusted_clock, &pll_clock, 1027254885Sdumbbell &fb_div, &frac_fb_div, &ref_div, &post_div); 1028254885Sdumbbell else if (ASIC_IS_AVIVO(rdev)) 1029254885Sdumbbell radeon_compute_pll_avivo(pll, radeon_crtc->adjusted_clock, &pll_clock, 1030254885Sdumbbell &fb_div, &frac_fb_div, &ref_div, &post_div); 1031254885Sdumbbell else 1032254885Sdumbbell radeon_compute_pll_legacy(pll, radeon_crtc->adjusted_clock, &pll_clock, 1033254885Sdumbbell &fb_div, &frac_fb_div, &ref_div, &post_div); 1034254885Sdumbbell 1035254885Sdumbbell atombios_crtc_program_ss(rdev, ATOM_DISABLE, radeon_crtc->pll_id, 1036254885Sdumbbell radeon_crtc->crtc_id, &radeon_crtc->ss); 1037254885Sdumbbell 1038254885Sdumbbell atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, 1039254885Sdumbbell encoder_mode, radeon_encoder->encoder_id, mode->clock, 1040254885Sdumbbell ref_div, fb_div, frac_fb_div, post_div, 1041254885Sdumbbell radeon_crtc->bpc, radeon_crtc->ss_enabled, &radeon_crtc->ss); 1042254885Sdumbbell 1043254885Sdumbbell if (radeon_crtc->ss_enabled) { 1044254885Sdumbbell /* calculate ss amount and step size */ 1045254885Sdumbbell if (ASIC_IS_DCE4(rdev)) { 1046254885Sdumbbell u32 step_size; 1047254885Sdumbbell u32 amount = (((fb_div * 10) + frac_fb_div) * radeon_crtc->ss.percentage) / 10000; 1048254885Sdumbbell radeon_crtc->ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK; 1049254885Sdumbbell radeon_crtc->ss.amount |= ((amount - (amount / 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) & 1050254885Sdumbbell ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK; 1051254885Sdumbbell if (radeon_crtc->ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD) 1052254885Sdumbbell step_size = (4 * amount * ref_div * (radeon_crtc->ss.rate * 2048)) / 1053254885Sdumbbell (125 * 25 * pll->reference_freq / 100); 1054254885Sdumbbell else 1055254885Sdumbbell step_size = (2 * amount * ref_div * (radeon_crtc->ss.rate * 2048)) / 1056254885Sdumbbell (125 * 25 * pll->reference_freq / 100); 1057254885Sdumbbell radeon_crtc->ss.step = step_size; 1058254885Sdumbbell } 1059254885Sdumbbell 1060254885Sdumbbell atombios_crtc_program_ss(rdev, ATOM_ENABLE, radeon_crtc->pll_id, 1061254885Sdumbbell radeon_crtc->crtc_id, &radeon_crtc->ss); 1062254885Sdumbbell } 1063254885Sdumbbell} 1064254885Sdumbbell 1065254885Sdumbbellstatic int dce4_crtc_do_set_base(struct drm_crtc *crtc, 1066254885Sdumbbell struct drm_framebuffer *fb, 1067254885Sdumbbell int x, int y, int atomic) 1068254885Sdumbbell{ 1069254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1070254885Sdumbbell struct drm_device *dev = crtc->dev; 1071254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 1072254885Sdumbbell struct radeon_framebuffer *radeon_fb; 1073254885Sdumbbell struct drm_framebuffer *target_fb; 1074254885Sdumbbell struct drm_gem_object *obj; 1075254885Sdumbbell struct radeon_bo *rbo; 1076254885Sdumbbell uint64_t fb_location; 1077254885Sdumbbell uint32_t fb_format, fb_pitch_pixels, tiling_flags; 1078254885Sdumbbell unsigned bankw, bankh, mtaspect, tile_split; 1079254885Sdumbbell u32 fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE); 1080254885Sdumbbell u32 tmp, viewport_w, viewport_h; 1081254885Sdumbbell int r; 1082254885Sdumbbell 1083254885Sdumbbell /* no fb bound */ 1084254885Sdumbbell if (!atomic && !crtc->fb) { 1085254885Sdumbbell DRM_DEBUG_KMS("No FB bound\n"); 1086254885Sdumbbell return 0; 1087254885Sdumbbell } 1088254885Sdumbbell 1089254885Sdumbbell if (atomic) { 1090254885Sdumbbell radeon_fb = to_radeon_framebuffer(fb); 1091254885Sdumbbell target_fb = fb; 1092254885Sdumbbell } 1093254885Sdumbbell else { 1094254885Sdumbbell radeon_fb = to_radeon_framebuffer(crtc->fb); 1095254885Sdumbbell target_fb = crtc->fb; 1096254885Sdumbbell } 1097254885Sdumbbell 1098254885Sdumbbell /* If atomic, assume fb object is pinned & idle & fenced and 1099254885Sdumbbell * just update base pointers 1100254885Sdumbbell */ 1101254885Sdumbbell obj = radeon_fb->obj; 1102254885Sdumbbell rbo = gem_to_radeon_bo(obj); 1103254885Sdumbbell r = radeon_bo_reserve(rbo, false); 1104254885Sdumbbell if (unlikely(r != 0)) 1105254885Sdumbbell return r; 1106254885Sdumbbell 1107254885Sdumbbell if (atomic) 1108254885Sdumbbell fb_location = radeon_bo_gpu_offset(rbo); 1109254885Sdumbbell else { 1110254885Sdumbbell r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); 1111254885Sdumbbell if (unlikely(r != 0)) { 1112254885Sdumbbell radeon_bo_unreserve(rbo); 1113254885Sdumbbell return -EINVAL; 1114254885Sdumbbell } 1115254885Sdumbbell } 1116254885Sdumbbell 1117254885Sdumbbell radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); 1118254885Sdumbbell radeon_bo_unreserve(rbo); 1119254885Sdumbbell 1120254885Sdumbbell switch (target_fb->bits_per_pixel) { 1121254885Sdumbbell case 8: 1122254885Sdumbbell fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP) | 1123254885Sdumbbell EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED)); 1124254885Sdumbbell break; 1125254885Sdumbbell case 15: 1126254885Sdumbbell fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 1127254885Sdumbbell EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB1555)); 1128254885Sdumbbell break; 1129254885Sdumbbell case 16: 1130254885Sdumbbell fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 1131254885Sdumbbell EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565)); 1132254885Sdumbbell#ifdef __BIG_ENDIAN 1133254885Sdumbbell fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16); 1134254885Sdumbbell#endif 1135254885Sdumbbell break; 1136254885Sdumbbell case 24: 1137254885Sdumbbell case 32: 1138254885Sdumbbell fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) | 1139254885Sdumbbell EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888)); 1140254885Sdumbbell#ifdef __BIG_ENDIAN 1141254885Sdumbbell fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32); 1142254885Sdumbbell#endif 1143254885Sdumbbell break; 1144254885Sdumbbell default: 1145254885Sdumbbell DRM_ERROR("Unsupported screen depth %d\n", 1146254885Sdumbbell target_fb->bits_per_pixel); 1147254885Sdumbbell return -EINVAL; 1148254885Sdumbbell } 1149254885Sdumbbell 1150254885Sdumbbell if (tiling_flags & RADEON_TILING_MACRO) { 1151254885Sdumbbell if (rdev->family >= CHIP_TAHITI) 1152254885Sdumbbell tmp = rdev->config.si.tile_config; 1153254885Sdumbbell else if (rdev->family >= CHIP_CAYMAN) 1154254885Sdumbbell tmp = rdev->config.cayman.tile_config; 1155254885Sdumbbell else 1156254885Sdumbbell tmp = rdev->config.evergreen.tile_config; 1157254885Sdumbbell 1158254885Sdumbbell switch ((tmp & 0xf0) >> 4) { 1159254885Sdumbbell case 0: /* 4 banks */ 1160254885Sdumbbell fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_4_BANK); 1161254885Sdumbbell break; 1162254885Sdumbbell case 1: /* 8 banks */ 1163254885Sdumbbell default: 1164254885Sdumbbell fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_8_BANK); 1165254885Sdumbbell break; 1166254885Sdumbbell case 2: /* 16 banks */ 1167254885Sdumbbell fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_16_BANK); 1168254885Sdumbbell break; 1169254885Sdumbbell } 1170254885Sdumbbell 1171254885Sdumbbell fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1); 1172254885Sdumbbell 1173254885Sdumbbell evergreen_tiling_fields(tiling_flags, &bankw, &bankh, &mtaspect, &tile_split); 1174254885Sdumbbell fb_format |= EVERGREEN_GRPH_TILE_SPLIT(tile_split); 1175254885Sdumbbell fb_format |= EVERGREEN_GRPH_BANK_WIDTH(bankw); 1176254885Sdumbbell fb_format |= EVERGREEN_GRPH_BANK_HEIGHT(bankh); 1177254885Sdumbbell fb_format |= EVERGREEN_GRPH_MACRO_TILE_ASPECT(mtaspect); 1178254885Sdumbbell } else if (tiling_flags & RADEON_TILING_MICRO) 1179254885Sdumbbell fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1); 1180254885Sdumbbell 1181254885Sdumbbell if ((rdev->family == CHIP_TAHITI) || 1182254885Sdumbbell (rdev->family == CHIP_PITCAIRN)) 1183254885Sdumbbell fb_format |= SI_GRPH_PIPE_CONFIG(SI_ADDR_SURF_P8_32x32_8x16); 1184254885Sdumbbell else if (rdev->family == CHIP_VERDE) 1185254885Sdumbbell fb_format |= SI_GRPH_PIPE_CONFIG(SI_ADDR_SURF_P4_8x16); 1186254885Sdumbbell 1187254885Sdumbbell switch (radeon_crtc->crtc_id) { 1188254885Sdumbbell case 0: 1189254885Sdumbbell WREG32(AVIVO_D1VGA_CONTROL, 0); 1190254885Sdumbbell break; 1191254885Sdumbbell case 1: 1192254885Sdumbbell WREG32(AVIVO_D2VGA_CONTROL, 0); 1193254885Sdumbbell break; 1194254885Sdumbbell case 2: 1195254885Sdumbbell WREG32(EVERGREEN_D3VGA_CONTROL, 0); 1196254885Sdumbbell break; 1197254885Sdumbbell case 3: 1198254885Sdumbbell WREG32(EVERGREEN_D4VGA_CONTROL, 0); 1199254885Sdumbbell break; 1200254885Sdumbbell case 4: 1201254885Sdumbbell WREG32(EVERGREEN_D5VGA_CONTROL, 0); 1202254885Sdumbbell break; 1203254885Sdumbbell case 5: 1204254885Sdumbbell WREG32(EVERGREEN_D6VGA_CONTROL, 0); 1205254885Sdumbbell break; 1206254885Sdumbbell default: 1207254885Sdumbbell break; 1208254885Sdumbbell } 1209254885Sdumbbell 1210254885Sdumbbell WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 1211254885Sdumbbell upper_32_bits(fb_location)); 1212254885Sdumbbell WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 1213254885Sdumbbell upper_32_bits(fb_location)); 1214254885Sdumbbell WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 1215254885Sdumbbell (u32)fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK); 1216254885Sdumbbell WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 1217254885Sdumbbell (u32) fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK); 1218254885Sdumbbell WREG32(EVERGREEN_GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); 1219254885Sdumbbell WREG32(EVERGREEN_GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap); 1220254885Sdumbbell 1221254885Sdumbbell WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); 1222254885Sdumbbell WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); 1223254885Sdumbbell WREG32(EVERGREEN_GRPH_X_START + radeon_crtc->crtc_offset, 0); 1224254885Sdumbbell WREG32(EVERGREEN_GRPH_Y_START + radeon_crtc->crtc_offset, 0); 1225254885Sdumbbell WREG32(EVERGREEN_GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width); 1226254885Sdumbbell WREG32(EVERGREEN_GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height); 1227254885Sdumbbell 1228254885Sdumbbell fb_pitch_pixels = target_fb->pitches[0] / (target_fb->bits_per_pixel / 8); 1229254885Sdumbbell WREG32(EVERGREEN_GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); 1230254885Sdumbbell WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1); 1231254885Sdumbbell 1232254885Sdumbbell WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, 1233254885Sdumbbell target_fb->height); 1234254885Sdumbbell x &= ~3; 1235254885Sdumbbell y &= ~1; 1236254885Sdumbbell WREG32(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset, 1237254885Sdumbbell (x << 16) | y); 1238254885Sdumbbell viewport_w = crtc->mode.hdisplay; 1239254885Sdumbbell viewport_h = (crtc->mode.vdisplay + 1) & ~1; 1240254885Sdumbbell WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset, 1241254885Sdumbbell (viewport_w << 16) | viewport_h); 1242254885Sdumbbell 1243254885Sdumbbell /* pageflip setup */ 1244254885Sdumbbell /* make sure flip is at vb rather than hb */ 1245254885Sdumbbell tmp = RREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset); 1246254885Sdumbbell tmp &= ~EVERGREEN_GRPH_SURFACE_UPDATE_H_RETRACE_EN; 1247254885Sdumbbell WREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, tmp); 1248254885Sdumbbell 1249254885Sdumbbell /* set pageflip to happen anywhere in vblank interval */ 1250254885Sdumbbell WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); 1251254885Sdumbbell 1252254885Sdumbbell if (!atomic && fb && fb != crtc->fb) { 1253254885Sdumbbell radeon_fb = to_radeon_framebuffer(fb); 1254254885Sdumbbell rbo = gem_to_radeon_bo(radeon_fb->obj); 1255254885Sdumbbell r = radeon_bo_reserve(rbo, false); 1256254885Sdumbbell if (unlikely(r != 0)) 1257254885Sdumbbell return r; 1258254885Sdumbbell radeon_bo_unpin(rbo); 1259254885Sdumbbell radeon_bo_unreserve(rbo); 1260254885Sdumbbell } 1261254885Sdumbbell 1262254885Sdumbbell /* Bytes per pixel may have changed */ 1263254885Sdumbbell radeon_bandwidth_update(rdev); 1264254885Sdumbbell 1265254885Sdumbbell return 0; 1266254885Sdumbbell} 1267254885Sdumbbell 1268254885Sdumbbellstatic int avivo_crtc_do_set_base(struct drm_crtc *crtc, 1269254885Sdumbbell struct drm_framebuffer *fb, 1270254885Sdumbbell int x, int y, int atomic) 1271254885Sdumbbell{ 1272254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1273254885Sdumbbell struct drm_device *dev = crtc->dev; 1274254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 1275254885Sdumbbell struct radeon_framebuffer *radeon_fb; 1276254885Sdumbbell struct drm_gem_object *obj; 1277254885Sdumbbell struct radeon_bo *rbo; 1278254885Sdumbbell struct drm_framebuffer *target_fb; 1279254885Sdumbbell uint64_t fb_location; 1280254885Sdumbbell uint32_t fb_format, fb_pitch_pixels, tiling_flags; 1281254885Sdumbbell u32 fb_swap = R600_D1GRPH_SWAP_ENDIAN_NONE; 1282254885Sdumbbell u32 tmp, viewport_w, viewport_h; 1283254885Sdumbbell int r; 1284254885Sdumbbell 1285254885Sdumbbell /* no fb bound */ 1286254885Sdumbbell if (!atomic && !crtc->fb) { 1287254885Sdumbbell DRM_DEBUG_KMS("No FB bound\n"); 1288254885Sdumbbell return 0; 1289254885Sdumbbell } 1290254885Sdumbbell 1291254885Sdumbbell if (atomic) { 1292254885Sdumbbell radeon_fb = to_radeon_framebuffer(fb); 1293254885Sdumbbell target_fb = fb; 1294254885Sdumbbell } 1295254885Sdumbbell else { 1296254885Sdumbbell radeon_fb = to_radeon_framebuffer(crtc->fb); 1297254885Sdumbbell target_fb = crtc->fb; 1298254885Sdumbbell } 1299254885Sdumbbell 1300254885Sdumbbell obj = radeon_fb->obj; 1301254885Sdumbbell rbo = gem_to_radeon_bo(obj); 1302254885Sdumbbell r = radeon_bo_reserve(rbo, false); 1303254885Sdumbbell if (unlikely(r != 0)) 1304254885Sdumbbell return r; 1305254885Sdumbbell 1306254885Sdumbbell /* If atomic, assume fb object is pinned & idle & fenced and 1307254885Sdumbbell * just update base pointers 1308254885Sdumbbell */ 1309254885Sdumbbell if (atomic) 1310254885Sdumbbell fb_location = radeon_bo_gpu_offset(rbo); 1311254885Sdumbbell else { 1312254885Sdumbbell r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); 1313254885Sdumbbell if (unlikely(r != 0)) { 1314254885Sdumbbell radeon_bo_unreserve(rbo); 1315254885Sdumbbell return -EINVAL; 1316254885Sdumbbell } 1317254885Sdumbbell } 1318254885Sdumbbell radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); 1319254885Sdumbbell radeon_bo_unreserve(rbo); 1320254885Sdumbbell 1321254885Sdumbbell switch (target_fb->bits_per_pixel) { 1322254885Sdumbbell case 8: 1323254885Sdumbbell fb_format = 1324254885Sdumbbell AVIVO_D1GRPH_CONTROL_DEPTH_8BPP | 1325254885Sdumbbell AVIVO_D1GRPH_CONTROL_8BPP_INDEXED; 1326254885Sdumbbell break; 1327254885Sdumbbell case 15: 1328254885Sdumbbell fb_format = 1329254885Sdumbbell AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | 1330254885Sdumbbell AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555; 1331254885Sdumbbell break; 1332254885Sdumbbell case 16: 1333254885Sdumbbell fb_format = 1334254885Sdumbbell AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | 1335254885Sdumbbell AVIVO_D1GRPH_CONTROL_16BPP_RGB565; 1336254885Sdumbbell#ifdef __BIG_ENDIAN 1337254885Sdumbbell fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT; 1338254885Sdumbbell#endif 1339254885Sdumbbell break; 1340254885Sdumbbell case 24: 1341254885Sdumbbell case 32: 1342254885Sdumbbell fb_format = 1343254885Sdumbbell AVIVO_D1GRPH_CONTROL_DEPTH_32BPP | 1344254885Sdumbbell AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888; 1345254885Sdumbbell#ifdef __BIG_ENDIAN 1346254885Sdumbbell fb_swap = R600_D1GRPH_SWAP_ENDIAN_32BIT; 1347254885Sdumbbell#endif 1348254885Sdumbbell break; 1349254885Sdumbbell default: 1350254885Sdumbbell DRM_ERROR("Unsupported screen depth %d\n", 1351254885Sdumbbell target_fb->bits_per_pixel); 1352254885Sdumbbell return -EINVAL; 1353254885Sdumbbell } 1354254885Sdumbbell 1355254885Sdumbbell if (rdev->family >= CHIP_R600) { 1356254885Sdumbbell if (tiling_flags & RADEON_TILING_MACRO) 1357254885Sdumbbell fb_format |= R600_D1GRPH_ARRAY_MODE_2D_TILED_THIN1; 1358254885Sdumbbell else if (tiling_flags & RADEON_TILING_MICRO) 1359254885Sdumbbell fb_format |= R600_D1GRPH_ARRAY_MODE_1D_TILED_THIN1; 1360254885Sdumbbell } else { 1361254885Sdumbbell if (tiling_flags & RADEON_TILING_MACRO) 1362254885Sdumbbell fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE; 1363254885Sdumbbell 1364254885Sdumbbell if (tiling_flags & RADEON_TILING_MICRO) 1365254885Sdumbbell fb_format |= AVIVO_D1GRPH_TILED; 1366254885Sdumbbell } 1367254885Sdumbbell 1368254885Sdumbbell if (radeon_crtc->crtc_id == 0) 1369254885Sdumbbell WREG32(AVIVO_D1VGA_CONTROL, 0); 1370254885Sdumbbell else 1371254885Sdumbbell WREG32(AVIVO_D2VGA_CONTROL, 0); 1372254885Sdumbbell 1373254885Sdumbbell if (rdev->family >= CHIP_RV770) { 1374254885Sdumbbell if (radeon_crtc->crtc_id) { 1375254885Sdumbbell WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 1376254885Sdumbbell WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 1377254885Sdumbbell } else { 1378254885Sdumbbell WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 1379254885Sdumbbell WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 1380254885Sdumbbell } 1381254885Sdumbbell } 1382254885Sdumbbell WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 1383254885Sdumbbell (u32) fb_location); 1384254885Sdumbbell WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + 1385254885Sdumbbell radeon_crtc->crtc_offset, (u32) fb_location); 1386254885Sdumbbell WREG32(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); 1387254885Sdumbbell if (rdev->family >= CHIP_R600) 1388254885Sdumbbell WREG32(R600_D1GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap); 1389254885Sdumbbell 1390254885Sdumbbell WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); 1391254885Sdumbbell WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); 1392254885Sdumbbell WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0); 1393254885Sdumbbell WREG32(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, 0); 1394254885Sdumbbell WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width); 1395254885Sdumbbell WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height); 1396254885Sdumbbell 1397254885Sdumbbell fb_pitch_pixels = target_fb->pitches[0] / (target_fb->bits_per_pixel / 8); 1398254885Sdumbbell WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); 1399254885Sdumbbell WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1); 1400254885Sdumbbell 1401254885Sdumbbell WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, 1402254885Sdumbbell target_fb->height); 1403254885Sdumbbell x &= ~3; 1404254885Sdumbbell y &= ~1; 1405254885Sdumbbell WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset, 1406254885Sdumbbell (x << 16) | y); 1407254885Sdumbbell viewport_w = crtc->mode.hdisplay; 1408254885Sdumbbell viewport_h = (crtc->mode.vdisplay + 1) & ~1; 1409254885Sdumbbell WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset, 1410254885Sdumbbell (viewport_w << 16) | viewport_h); 1411254885Sdumbbell 1412254885Sdumbbell /* pageflip setup */ 1413254885Sdumbbell /* make sure flip is at vb rather than hb */ 1414254885Sdumbbell tmp = RREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset); 1415254885Sdumbbell tmp &= ~AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN; 1416254885Sdumbbell WREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, tmp); 1417254885Sdumbbell 1418254885Sdumbbell /* set pageflip to happen anywhere in vblank interval */ 1419254885Sdumbbell WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); 1420254885Sdumbbell 1421254885Sdumbbell if (!atomic && fb && fb != crtc->fb) { 1422254885Sdumbbell radeon_fb = to_radeon_framebuffer(fb); 1423254885Sdumbbell rbo = gem_to_radeon_bo(radeon_fb->obj); 1424254885Sdumbbell r = radeon_bo_reserve(rbo, false); 1425254885Sdumbbell if (unlikely(r != 0)) 1426254885Sdumbbell return r; 1427254885Sdumbbell radeon_bo_unpin(rbo); 1428254885Sdumbbell radeon_bo_unreserve(rbo); 1429254885Sdumbbell } 1430254885Sdumbbell 1431254885Sdumbbell /* Bytes per pixel may have changed */ 1432254885Sdumbbell radeon_bandwidth_update(rdev); 1433254885Sdumbbell 1434254885Sdumbbell return 0; 1435254885Sdumbbell} 1436254885Sdumbbell 1437254885Sdumbbellint atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, 1438254885Sdumbbell struct drm_framebuffer *old_fb) 1439254885Sdumbbell{ 1440254885Sdumbbell struct drm_device *dev = crtc->dev; 1441254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 1442254885Sdumbbell 1443254885Sdumbbell if (ASIC_IS_DCE4(rdev)) 1444254885Sdumbbell return dce4_crtc_do_set_base(crtc, old_fb, x, y, 0); 1445254885Sdumbbell else if (ASIC_IS_AVIVO(rdev)) 1446254885Sdumbbell return avivo_crtc_do_set_base(crtc, old_fb, x, y, 0); 1447254885Sdumbbell else 1448254885Sdumbbell return radeon_crtc_do_set_base(crtc, old_fb, x, y, 0); 1449254885Sdumbbell} 1450254885Sdumbbell 1451254885Sdumbbellint atombios_crtc_set_base_atomic(struct drm_crtc *crtc, 1452254885Sdumbbell struct drm_framebuffer *fb, 1453254885Sdumbbell int x, int y, enum mode_set_atomic state) 1454254885Sdumbbell{ 1455254885Sdumbbell struct drm_device *dev = crtc->dev; 1456254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 1457254885Sdumbbell 1458254885Sdumbbell if (ASIC_IS_DCE4(rdev)) 1459254885Sdumbbell return dce4_crtc_do_set_base(crtc, fb, x, y, 1); 1460254885Sdumbbell else if (ASIC_IS_AVIVO(rdev)) 1461254885Sdumbbell return avivo_crtc_do_set_base(crtc, fb, x, y, 1); 1462254885Sdumbbell else 1463254885Sdumbbell return radeon_crtc_do_set_base(crtc, fb, x, y, 1); 1464254885Sdumbbell} 1465254885Sdumbbell 1466254885Sdumbbell/* properly set additional regs when using atombios */ 1467254885Sdumbbellstatic void radeon_legacy_atom_fixup(struct drm_crtc *crtc) 1468254885Sdumbbell{ 1469254885Sdumbbell struct drm_device *dev = crtc->dev; 1470254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 1471254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1472254885Sdumbbell u32 disp_merge_cntl; 1473254885Sdumbbell 1474254885Sdumbbell switch (radeon_crtc->crtc_id) { 1475254885Sdumbbell case 0: 1476254885Sdumbbell disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL); 1477254885Sdumbbell disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; 1478254885Sdumbbell WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl); 1479254885Sdumbbell break; 1480254885Sdumbbell case 1: 1481254885Sdumbbell disp_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL); 1482254885Sdumbbell disp_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN; 1483254885Sdumbbell WREG32(RADEON_DISP2_MERGE_CNTL, disp_merge_cntl); 1484254885Sdumbbell WREG32(RADEON_FP_H2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_H_SYNC_STRT_WID)); 1485254885Sdumbbell WREG32(RADEON_FP_V2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_V_SYNC_STRT_WID)); 1486254885Sdumbbell break; 1487254885Sdumbbell } 1488254885Sdumbbell} 1489254885Sdumbbell 1490254885Sdumbbell/** 1491254885Sdumbbell * radeon_get_pll_use_mask - look up a mask of which pplls are in use 1492254885Sdumbbell * 1493254885Sdumbbell * @crtc: drm crtc 1494254885Sdumbbell * 1495254885Sdumbbell * Returns the mask of which PPLLs (Pixel PLLs) are in use. 1496254885Sdumbbell */ 1497254885Sdumbbellstatic u32 radeon_get_pll_use_mask(struct drm_crtc *crtc) 1498254885Sdumbbell{ 1499254885Sdumbbell struct drm_device *dev = crtc->dev; 1500254885Sdumbbell struct drm_crtc *test_crtc; 1501254885Sdumbbell struct radeon_crtc *test_radeon_crtc; 1502254885Sdumbbell u32 pll_in_use = 0; 1503254885Sdumbbell 1504254885Sdumbbell list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { 1505254885Sdumbbell if (crtc == test_crtc) 1506254885Sdumbbell continue; 1507254885Sdumbbell 1508254885Sdumbbell test_radeon_crtc = to_radeon_crtc(test_crtc); 1509254885Sdumbbell if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID) 1510254885Sdumbbell pll_in_use |= (1 << test_radeon_crtc->pll_id); 1511254885Sdumbbell } 1512254885Sdumbbell return pll_in_use; 1513254885Sdumbbell} 1514254885Sdumbbell 1515254885Sdumbbell/** 1516254885Sdumbbell * radeon_get_shared_dp_ppll - return the PPLL used by another crtc for DP 1517254885Sdumbbell * 1518254885Sdumbbell * @crtc: drm crtc 1519254885Sdumbbell * 1520254885Sdumbbell * Returns the PPLL (Pixel PLL) used by another crtc/encoder which is 1521254885Sdumbbell * also in DP mode. For DP, a single PPLL can be used for all DP 1522254885Sdumbbell * crtcs/encoders. 1523254885Sdumbbell */ 1524254885Sdumbbellstatic int radeon_get_shared_dp_ppll(struct drm_crtc *crtc) 1525254885Sdumbbell{ 1526254885Sdumbbell struct drm_device *dev = crtc->dev; 1527254885Sdumbbell struct drm_crtc *test_crtc; 1528254885Sdumbbell struct radeon_crtc *test_radeon_crtc; 1529254885Sdumbbell 1530254885Sdumbbell list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { 1531254885Sdumbbell if (crtc == test_crtc) 1532254885Sdumbbell continue; 1533254885Sdumbbell test_radeon_crtc = to_radeon_crtc(test_crtc); 1534254885Sdumbbell if (test_radeon_crtc->encoder && 1535254885Sdumbbell ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_radeon_crtc->encoder))) { 1536254885Sdumbbell /* for DP use the same PLL for all */ 1537254885Sdumbbell if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID) 1538254885Sdumbbell return test_radeon_crtc->pll_id; 1539254885Sdumbbell } 1540254885Sdumbbell } 1541254885Sdumbbell return ATOM_PPLL_INVALID; 1542254885Sdumbbell} 1543254885Sdumbbell 1544254885Sdumbbell/** 1545254885Sdumbbell * radeon_get_shared_nondp_ppll - return the PPLL used by another non-DP crtc 1546254885Sdumbbell * 1547254885Sdumbbell * @crtc: drm crtc 1548254885Sdumbbell * @encoder: drm encoder 1549254885Sdumbbell * 1550254885Sdumbbell * Returns the PPLL (Pixel PLL) used by another non-DP crtc/encoder which can 1551254885Sdumbbell * be shared (i.e., same clock). 1552254885Sdumbbell */ 1553254885Sdumbbellstatic int radeon_get_shared_nondp_ppll(struct drm_crtc *crtc) 1554254885Sdumbbell{ 1555254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1556254885Sdumbbell struct drm_device *dev = crtc->dev; 1557254885Sdumbbell struct drm_crtc *test_crtc; 1558254885Sdumbbell struct radeon_crtc *test_radeon_crtc; 1559254885Sdumbbell u32 adjusted_clock, test_adjusted_clock; 1560254885Sdumbbell 1561254885Sdumbbell adjusted_clock = radeon_crtc->adjusted_clock; 1562254885Sdumbbell 1563254885Sdumbbell if (adjusted_clock == 0) 1564254885Sdumbbell return ATOM_PPLL_INVALID; 1565254885Sdumbbell 1566254885Sdumbbell list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { 1567254885Sdumbbell if (crtc == test_crtc) 1568254885Sdumbbell continue; 1569254885Sdumbbell test_radeon_crtc = to_radeon_crtc(test_crtc); 1570254885Sdumbbell if (test_radeon_crtc->encoder && 1571254885Sdumbbell !ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_radeon_crtc->encoder))) { 1572254885Sdumbbell /* check if we are already driving this connector with another crtc */ 1573254885Sdumbbell if (test_radeon_crtc->connector == radeon_crtc->connector) { 1574254885Sdumbbell /* if we are, return that pll */ 1575254885Sdumbbell if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID) 1576254885Sdumbbell return test_radeon_crtc->pll_id; 1577254885Sdumbbell } 1578254885Sdumbbell /* for non-DP check the clock */ 1579254885Sdumbbell test_adjusted_clock = test_radeon_crtc->adjusted_clock; 1580254885Sdumbbell if ((crtc->mode.clock == test_crtc->mode.clock) && 1581254885Sdumbbell (adjusted_clock == test_adjusted_clock) && 1582254885Sdumbbell (radeon_crtc->ss_enabled == test_radeon_crtc->ss_enabled) && 1583254885Sdumbbell (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID)) 1584254885Sdumbbell return test_radeon_crtc->pll_id; 1585254885Sdumbbell } 1586254885Sdumbbell } 1587254885Sdumbbell return ATOM_PPLL_INVALID; 1588254885Sdumbbell} 1589254885Sdumbbell 1590254885Sdumbbell/** 1591254885Sdumbbell * radeon_atom_pick_pll - Allocate a PPLL for use by the crtc. 1592254885Sdumbbell * 1593254885Sdumbbell * @crtc: drm crtc 1594254885Sdumbbell * 1595254885Sdumbbell * Returns the PPLL (Pixel PLL) to be used by the crtc. For DP monitors 1596254885Sdumbbell * a single PPLL can be used for all DP crtcs/encoders. For non-DP 1597254885Sdumbbell * monitors a dedicated PPLL must be used. If a particular board has 1598254885Sdumbbell * an external DP PLL, return ATOM_PPLL_INVALID to skip PLL programming 1599254885Sdumbbell * as there is no need to program the PLL itself. If we are not able to 1600254885Sdumbbell * allocate a PLL, return ATOM_PPLL_INVALID to skip PLL programming to 1601254885Sdumbbell * avoid messing up an existing monitor. 1602254885Sdumbbell * 1603254885Sdumbbell * Asic specific PLL information 1604254885Sdumbbell * 1605254885Sdumbbell * DCE 6.1 1606254885Sdumbbell * - PPLL2 is only available to UNIPHYA (both DP and non-DP) 1607254885Sdumbbell * - PPLL0, PPLL1 are available for UNIPHYB/C/D/E/F (both DP and non-DP) 1608254885Sdumbbell * 1609254885Sdumbbell * DCE 6.0 1610254885Sdumbbell * - PPLL0 is available to all UNIPHY (DP only) 1611254885Sdumbbell * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC 1612254885Sdumbbell * 1613254885Sdumbbell * DCE 5.0 1614254885Sdumbbell * - DCPLL is available to all UNIPHY (DP only) 1615254885Sdumbbell * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC 1616254885Sdumbbell * 1617254885Sdumbbell * DCE 3.0/4.0/4.1 1618254885Sdumbbell * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC 1619254885Sdumbbell * 1620254885Sdumbbell */ 1621254885Sdumbbellstatic int radeon_atom_pick_pll(struct drm_crtc *crtc) 1622254885Sdumbbell{ 1623254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1624254885Sdumbbell struct drm_device *dev = crtc->dev; 1625254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 1626254885Sdumbbell struct radeon_encoder *radeon_encoder = 1627254885Sdumbbell to_radeon_encoder(radeon_crtc->encoder); 1628254885Sdumbbell u32 pll_in_use; 1629254885Sdumbbell int pll; 1630254885Sdumbbell 1631254885Sdumbbell if (ASIC_IS_DCE61(rdev)) { 1632254885Sdumbbell struct radeon_encoder_atom_dig *dig = 1633254885Sdumbbell radeon_encoder->enc_priv; 1634254885Sdumbbell 1635254885Sdumbbell if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY) && 1636254885Sdumbbell (dig->linkb == false)) 1637254885Sdumbbell /* UNIPHY A uses PPLL2 */ 1638254885Sdumbbell return ATOM_PPLL2; 1639254885Sdumbbell else if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { 1640254885Sdumbbell /* UNIPHY B/C/D/E/F */ 1641254885Sdumbbell if (rdev->clock.dp_extclk) 1642254885Sdumbbell /* skip PPLL programming if using ext clock */ 1643254885Sdumbbell return ATOM_PPLL_INVALID; 1644254885Sdumbbell else { 1645254885Sdumbbell /* use the same PPLL for all DP monitors */ 1646254885Sdumbbell pll = radeon_get_shared_dp_ppll(crtc); 1647254885Sdumbbell if (pll != ATOM_PPLL_INVALID) 1648254885Sdumbbell return pll; 1649254885Sdumbbell } 1650254885Sdumbbell } else { 1651254885Sdumbbell /* use the same PPLL for all monitors with the same clock */ 1652254885Sdumbbell pll = radeon_get_shared_nondp_ppll(crtc); 1653254885Sdumbbell if (pll != ATOM_PPLL_INVALID) 1654254885Sdumbbell return pll; 1655254885Sdumbbell } 1656254885Sdumbbell /* UNIPHY B/C/D/E/F */ 1657254885Sdumbbell pll_in_use = radeon_get_pll_use_mask(crtc); 1658254885Sdumbbell if (!(pll_in_use & (1 << ATOM_PPLL0))) 1659254885Sdumbbell return ATOM_PPLL0; 1660254885Sdumbbell if (!(pll_in_use & (1 << ATOM_PPLL1))) 1661254885Sdumbbell return ATOM_PPLL1; 1662254885Sdumbbell DRM_ERROR("unable to allocate a PPLL\n"); 1663254885Sdumbbell return ATOM_PPLL_INVALID; 1664254885Sdumbbell } else if (ASIC_IS_DCE4(rdev)) { 1665254885Sdumbbell /* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock, 1666254885Sdumbbell * depending on the asic: 1667254885Sdumbbell * DCE4: PPLL or ext clock 1668254885Sdumbbell * DCE5: PPLL, DCPLL, or ext clock 1669254885Sdumbbell * DCE6: PPLL, PPLL0, or ext clock 1670254885Sdumbbell * 1671254885Sdumbbell * Setting ATOM_PPLL_INVALID will cause SetPixelClock to skip 1672254885Sdumbbell * PPLL/DCPLL programming and only program the DP DTO for the 1673254885Sdumbbell * crtc virtual pixel clock. 1674254885Sdumbbell */ 1675254885Sdumbbell if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { 1676254885Sdumbbell if (rdev->clock.dp_extclk) 1677254885Sdumbbell /* skip PPLL programming if using ext clock */ 1678254885Sdumbbell return ATOM_PPLL_INVALID; 1679254885Sdumbbell else if (ASIC_IS_DCE6(rdev)) 1680254885Sdumbbell /* use PPLL0 for all DP */ 1681254885Sdumbbell return ATOM_PPLL0; 1682254885Sdumbbell else if (ASIC_IS_DCE5(rdev)) 1683254885Sdumbbell /* use DCPLL for all DP */ 1684254885Sdumbbell return ATOM_DCPLL; 1685254885Sdumbbell else { 1686254885Sdumbbell /* use the same PPLL for all DP monitors */ 1687254885Sdumbbell pll = radeon_get_shared_dp_ppll(crtc); 1688254885Sdumbbell if (pll != ATOM_PPLL_INVALID) 1689254885Sdumbbell return pll; 1690254885Sdumbbell } 1691254885Sdumbbell } else { 1692254885Sdumbbell /* use the same PPLL for all monitors with the same clock */ 1693254885Sdumbbell pll = radeon_get_shared_nondp_ppll(crtc); 1694254885Sdumbbell if (pll != ATOM_PPLL_INVALID) 1695254885Sdumbbell return pll; 1696254885Sdumbbell } 1697254885Sdumbbell /* all other cases */ 1698254885Sdumbbell pll_in_use = radeon_get_pll_use_mask(crtc); 1699254885Sdumbbell if (!(pll_in_use & (1 << ATOM_PPLL1))) 1700254885Sdumbbell return ATOM_PPLL1; 1701254885Sdumbbell if (!(pll_in_use & (1 << ATOM_PPLL2))) 1702254885Sdumbbell return ATOM_PPLL2; 1703254885Sdumbbell DRM_ERROR("unable to allocate a PPLL\n"); 1704254885Sdumbbell return ATOM_PPLL_INVALID; 1705254885Sdumbbell } else { 1706254885Sdumbbell /* on pre-R5xx asics, the crtc to pll mapping is hardcoded */ 1707254885Sdumbbell /* some atombios (observed in some DCE2/DCE3) code have a bug, 1708254885Sdumbbell * the matching btw pll and crtc is done through 1709254885Sdumbbell * PCLK_CRTC[1|2]_CNTL (0x480/0x484) but atombios code use the 1710254885Sdumbbell * pll (1 or 2) to select which register to write. ie if using 1711254885Sdumbbell * pll1 it will use PCLK_CRTC1_CNTL (0x480) and if using pll2 1712254885Sdumbbell * it will use PCLK_CRTC2_CNTL (0x484), it then use crtc id to 1713254885Sdumbbell * choose which value to write. Which is reverse order from 1714254885Sdumbbell * register logic. So only case that works is when pllid is 1715254885Sdumbbell * same as crtcid or when both pll and crtc are enabled and 1716254885Sdumbbell * both use same clock. 1717254885Sdumbbell * 1718254885Sdumbbell * So just return crtc id as if crtc and pll were hard linked 1719254885Sdumbbell * together even if they aren't 1720254885Sdumbbell */ 1721254885Sdumbbell return radeon_crtc->crtc_id; 1722254885Sdumbbell } 1723254885Sdumbbell} 1724254885Sdumbbell 1725254885Sdumbbellvoid radeon_atom_disp_eng_pll_init(struct radeon_device *rdev) 1726254885Sdumbbell{ 1727254885Sdumbbell /* always set DCPLL */ 1728254885Sdumbbell if (ASIC_IS_DCE6(rdev)) 1729254885Sdumbbell atombios_crtc_set_disp_eng_pll(rdev, rdev->clock.default_dispclk); 1730254885Sdumbbell else if (ASIC_IS_DCE4(rdev)) { 1731254885Sdumbbell struct radeon_atom_ss ss; 1732254885Sdumbbell bool ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &ss, 1733254885Sdumbbell ASIC_INTERNAL_SS_ON_DCPLL, 1734254885Sdumbbell rdev->clock.default_dispclk); 1735254885Sdumbbell if (ss_enabled) 1736254885Sdumbbell atombios_crtc_program_ss(rdev, ATOM_DISABLE, ATOM_DCPLL, -1, &ss); 1737254885Sdumbbell /* XXX: DCE5, make sure voltage, dispclk is high enough */ 1738254885Sdumbbell atombios_crtc_set_disp_eng_pll(rdev, rdev->clock.default_dispclk); 1739254885Sdumbbell if (ss_enabled) 1740254885Sdumbbell atombios_crtc_program_ss(rdev, ATOM_ENABLE, ATOM_DCPLL, -1, &ss); 1741254885Sdumbbell } 1742254885Sdumbbell 1743254885Sdumbbell} 1744254885Sdumbbell 1745254885Sdumbbellint atombios_crtc_mode_set(struct drm_crtc *crtc, 1746254885Sdumbbell struct drm_display_mode *mode, 1747254885Sdumbbell struct drm_display_mode *adjusted_mode, 1748254885Sdumbbell int x, int y, struct drm_framebuffer *old_fb) 1749254885Sdumbbell{ 1750254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1751254885Sdumbbell struct drm_device *dev = crtc->dev; 1752254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 1753254885Sdumbbell struct radeon_encoder *radeon_encoder = 1754254885Sdumbbell to_radeon_encoder(radeon_crtc->encoder); 1755254885Sdumbbell bool is_tvcv = false; 1756254885Sdumbbell 1757254885Sdumbbell if (radeon_encoder->active_device & 1758254885Sdumbbell (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) 1759254885Sdumbbell is_tvcv = true; 1760254885Sdumbbell 1761254885Sdumbbell atombios_crtc_set_pll(crtc, adjusted_mode); 1762254885Sdumbbell 1763254885Sdumbbell if (ASIC_IS_DCE4(rdev)) 1764254885Sdumbbell atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 1765254885Sdumbbell else if (ASIC_IS_AVIVO(rdev)) { 1766254885Sdumbbell if (is_tvcv) 1767254885Sdumbbell atombios_crtc_set_timing(crtc, adjusted_mode); 1768254885Sdumbbell else 1769254885Sdumbbell atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 1770254885Sdumbbell } else { 1771254885Sdumbbell atombios_crtc_set_timing(crtc, adjusted_mode); 1772254885Sdumbbell if (radeon_crtc->crtc_id == 0) 1773254885Sdumbbell atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 1774254885Sdumbbell radeon_legacy_atom_fixup(crtc); 1775254885Sdumbbell } 1776254885Sdumbbell atombios_crtc_set_base(crtc, x, y, old_fb); 1777254885Sdumbbell atombios_overscan_setup(crtc, mode, adjusted_mode); 1778254885Sdumbbell atombios_scaler_setup(crtc); 1779254885Sdumbbell return 0; 1780254885Sdumbbell} 1781254885Sdumbbell 1782254885Sdumbbellstatic bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, 1783254885Sdumbbell const struct drm_display_mode *mode, 1784254885Sdumbbell struct drm_display_mode *adjusted_mode) 1785254885Sdumbbell{ 1786254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1787254885Sdumbbell struct drm_device *dev = crtc->dev; 1788254885Sdumbbell struct drm_encoder *encoder; 1789254885Sdumbbell 1790254885Sdumbbell /* assign the encoder to the radeon crtc to avoid repeated lookups later */ 1791254885Sdumbbell list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 1792254885Sdumbbell if (encoder->crtc == crtc) { 1793254885Sdumbbell radeon_crtc->encoder = encoder; 1794254885Sdumbbell radeon_crtc->connector = radeon_get_connector_for_encoder(encoder); 1795254885Sdumbbell break; 1796254885Sdumbbell } 1797254885Sdumbbell } 1798254885Sdumbbell if ((radeon_crtc->encoder == NULL) || (radeon_crtc->connector == NULL)) { 1799254885Sdumbbell radeon_crtc->encoder = NULL; 1800254885Sdumbbell radeon_crtc->connector = NULL; 1801254885Sdumbbell return false; 1802254885Sdumbbell } 1803254885Sdumbbell if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) 1804254885Sdumbbell return false; 1805254885Sdumbbell if (!atombios_crtc_prepare_pll(crtc, adjusted_mode)) 1806254885Sdumbbell return false; 1807254885Sdumbbell /* pick pll */ 1808254885Sdumbbell radeon_crtc->pll_id = radeon_atom_pick_pll(crtc); 1809254885Sdumbbell /* if we can't get a PPLL for a non-DP encoder, fail */ 1810254885Sdumbbell if ((radeon_crtc->pll_id == ATOM_PPLL_INVALID) && 1811254885Sdumbbell !ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) 1812254885Sdumbbell return false; 1813254885Sdumbbell 1814254885Sdumbbell return true; 1815254885Sdumbbell} 1816254885Sdumbbell 1817254885Sdumbbellstatic void atombios_crtc_prepare(struct drm_crtc *crtc) 1818254885Sdumbbell{ 1819254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1820254885Sdumbbell struct drm_device *dev = crtc->dev; 1821254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 1822254885Sdumbbell 1823254885Sdumbbell radeon_crtc->in_mode_set = true; 1824254885Sdumbbell 1825254885Sdumbbell /* disable crtc pair power gating before programming */ 1826254885Sdumbbell if (ASIC_IS_DCE6(rdev)) 1827254885Sdumbbell atombios_powergate_crtc(crtc, ATOM_DISABLE); 1828254885Sdumbbell 1829254885Sdumbbell atombios_lock_crtc(crtc, ATOM_ENABLE); 1830254885Sdumbbell atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 1831254885Sdumbbell} 1832254885Sdumbbell 1833254885Sdumbbellstatic void atombios_crtc_commit(struct drm_crtc *crtc) 1834254885Sdumbbell{ 1835254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1836254885Sdumbbell 1837254885Sdumbbell atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON); 1838254885Sdumbbell atombios_lock_crtc(crtc, ATOM_DISABLE); 1839254885Sdumbbell radeon_crtc->in_mode_set = false; 1840254885Sdumbbell} 1841254885Sdumbbell 1842254885Sdumbbellstatic void atombios_crtc_disable(struct drm_crtc *crtc) 1843254885Sdumbbell{ 1844254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1845254885Sdumbbell struct drm_device *dev = crtc->dev; 1846254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 1847254885Sdumbbell struct radeon_atom_ss ss; 1848254885Sdumbbell int i; 1849254885Sdumbbell 1850254885Sdumbbell atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 1851254885Sdumbbell 1852254885Sdumbbell for (i = 0; i < rdev->num_crtc; i++) { 1853254885Sdumbbell if (rdev->mode_info.crtcs[i] && 1854254885Sdumbbell rdev->mode_info.crtcs[i]->enabled && 1855254885Sdumbbell i != radeon_crtc->crtc_id && 1856254885Sdumbbell radeon_crtc->pll_id == rdev->mode_info.crtcs[i]->pll_id) { 1857254885Sdumbbell /* one other crtc is using this pll don't turn 1858254885Sdumbbell * off the pll 1859254885Sdumbbell */ 1860254885Sdumbbell goto done; 1861254885Sdumbbell } 1862254885Sdumbbell } 1863254885Sdumbbell 1864254885Sdumbbell switch (radeon_crtc->pll_id) { 1865254885Sdumbbell case ATOM_PPLL1: 1866254885Sdumbbell case ATOM_PPLL2: 1867254885Sdumbbell /* disable the ppll */ 1868254885Sdumbbell atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, 1869254885Sdumbbell 0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss); 1870254885Sdumbbell break; 1871254885Sdumbbell case ATOM_PPLL0: 1872254885Sdumbbell /* disable the ppll */ 1873254885Sdumbbell if (ASIC_IS_DCE61(rdev)) 1874254885Sdumbbell atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, 1875254885Sdumbbell 0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss); 1876254885Sdumbbell break; 1877254885Sdumbbell default: 1878254885Sdumbbell break; 1879254885Sdumbbell } 1880254885Sdumbbelldone: 1881254885Sdumbbell radeon_crtc->pll_id = ATOM_PPLL_INVALID; 1882254885Sdumbbell radeon_crtc->adjusted_clock = 0; 1883254885Sdumbbell radeon_crtc->encoder = NULL; 1884254885Sdumbbell radeon_crtc->connector = NULL; 1885254885Sdumbbell} 1886254885Sdumbbell 1887254885Sdumbbellstatic const struct drm_crtc_helper_funcs atombios_helper_funcs = { 1888254885Sdumbbell .dpms = atombios_crtc_dpms, 1889254885Sdumbbell .mode_fixup = atombios_crtc_mode_fixup, 1890254885Sdumbbell .mode_set = atombios_crtc_mode_set, 1891254885Sdumbbell .mode_set_base = atombios_crtc_set_base, 1892254885Sdumbbell .mode_set_base_atomic = atombios_crtc_set_base_atomic, 1893254885Sdumbbell .prepare = atombios_crtc_prepare, 1894254885Sdumbbell .commit = atombios_crtc_commit, 1895254885Sdumbbell .load_lut = radeon_crtc_load_lut, 1896254885Sdumbbell .disable = atombios_crtc_disable, 1897254885Sdumbbell}; 1898254885Sdumbbell 1899254885Sdumbbellvoid radeon_atombios_init_crtc(struct drm_device *dev, 1900254885Sdumbbell struct radeon_crtc *radeon_crtc) 1901254885Sdumbbell{ 1902254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 1903254885Sdumbbell 1904254885Sdumbbell if (ASIC_IS_DCE4(rdev)) { 1905254885Sdumbbell switch (radeon_crtc->crtc_id) { 1906254885Sdumbbell case 0: 1907254885Sdumbbell default: 1908254885Sdumbbell radeon_crtc->crtc_offset = EVERGREEN_CRTC0_REGISTER_OFFSET; 1909254885Sdumbbell break; 1910254885Sdumbbell case 1: 1911254885Sdumbbell radeon_crtc->crtc_offset = EVERGREEN_CRTC1_REGISTER_OFFSET; 1912254885Sdumbbell break; 1913254885Sdumbbell case 2: 1914254885Sdumbbell radeon_crtc->crtc_offset = EVERGREEN_CRTC2_REGISTER_OFFSET; 1915254885Sdumbbell break; 1916254885Sdumbbell case 3: 1917254885Sdumbbell radeon_crtc->crtc_offset = EVERGREEN_CRTC3_REGISTER_OFFSET; 1918254885Sdumbbell break; 1919254885Sdumbbell case 4: 1920254885Sdumbbell radeon_crtc->crtc_offset = EVERGREEN_CRTC4_REGISTER_OFFSET; 1921254885Sdumbbell break; 1922254885Sdumbbell case 5: 1923254885Sdumbbell radeon_crtc->crtc_offset = EVERGREEN_CRTC5_REGISTER_OFFSET; 1924254885Sdumbbell break; 1925254885Sdumbbell } 1926254885Sdumbbell } else { 1927254885Sdumbbell if (radeon_crtc->crtc_id == 1) 1928254885Sdumbbell radeon_crtc->crtc_offset = 1929254885Sdumbbell AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL; 1930254885Sdumbbell else 1931254885Sdumbbell radeon_crtc->crtc_offset = 0; 1932254885Sdumbbell } 1933254885Sdumbbell radeon_crtc->pll_id = ATOM_PPLL_INVALID; 1934254885Sdumbbell radeon_crtc->adjusted_clock = 0; 1935254885Sdumbbell radeon_crtc->encoder = NULL; 1936254885Sdumbbell radeon_crtc->connector = NULL; 1937254885Sdumbbell drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); 1938254885Sdumbbell} 1939