1771fe6b9SJerome Glisse /* 2771fe6b9SJerome Glisse * Copyright 2007-8 Advanced Micro Devices, Inc. 3771fe6b9SJerome Glisse * Copyright 2008 Red Hat Inc. 4771fe6b9SJerome Glisse * 5771fe6b9SJerome Glisse * Permission is hereby granted, free of charge, to any person obtaining a 6771fe6b9SJerome Glisse * copy of this software and associated documentation files (the "Software"), 7771fe6b9SJerome Glisse * to deal in the Software without restriction, including without limitation 8771fe6b9SJerome Glisse * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9771fe6b9SJerome Glisse * and/or sell copies of the Software, and to permit persons to whom the 10771fe6b9SJerome Glisse * Software is furnished to do so, subject to the following conditions: 11771fe6b9SJerome Glisse * 12771fe6b9SJerome Glisse * The above copyright notice and this permission notice shall be included in 13771fe6b9SJerome Glisse * all copies or substantial portions of the Software. 14771fe6b9SJerome Glisse * 15771fe6b9SJerome Glisse * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16771fe6b9SJerome Glisse * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17771fe6b9SJerome Glisse * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18771fe6b9SJerome Glisse * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 19771fe6b9SJerome Glisse * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20771fe6b9SJerome Glisse * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21771fe6b9SJerome Glisse * OTHER DEALINGS IN THE SOFTWARE. 22771fe6b9SJerome Glisse * 23771fe6b9SJerome Glisse * Authors: Dave Airlie 24771fe6b9SJerome Glisse * Alex Deucher 25771fe6b9SJerome Glisse */ 26771fe6b9SJerome Glisse #include <drm/drmP.h> 27771fe6b9SJerome Glisse #include <drm/drm_crtc_helper.h> 28771fe6b9SJerome Glisse #include <drm/radeon_drm.h> 2968adac5eSBen Skeggs #include <drm/drm_fixed.h> 30771fe6b9SJerome Glisse #include "radeon.h" 31771fe6b9SJerome Glisse #include "atom.h" 32771fe6b9SJerome Glisse #include "atom-bits.h" 33771fe6b9SJerome Glisse 34c93bb85bSJerome Glisse static void atombios_overscan_setup(struct drm_crtc *crtc, 35c93bb85bSJerome Glisse struct drm_display_mode *mode, 36c93bb85bSJerome Glisse struct drm_display_mode *adjusted_mode) 37c93bb85bSJerome Glisse { 38c93bb85bSJerome Glisse struct drm_device *dev = crtc->dev; 39c93bb85bSJerome Glisse struct radeon_device *rdev = dev->dev_private; 40c93bb85bSJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 41c93bb85bSJerome Glisse SET_CRTC_OVERSCAN_PS_ALLOCATION args; 42c93bb85bSJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan); 43c93bb85bSJerome Glisse int a1, a2; 44c93bb85bSJerome Glisse 45c93bb85bSJerome Glisse memset(&args, 0, sizeof(args)); 46c93bb85bSJerome Glisse 47c93bb85bSJerome Glisse args.ucCRTC = radeon_crtc->crtc_id; 48c93bb85bSJerome Glisse 49c93bb85bSJerome Glisse switch (radeon_crtc->rmx_type) { 50c93bb85bSJerome Glisse case RMX_CENTER: 514589433cSCédric Cano args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2); 524589433cSCédric Cano args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2); 534589433cSCédric Cano args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2); 544589433cSCédric Cano args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2); 55c93bb85bSJerome Glisse break; 56c93bb85bSJerome Glisse case RMX_ASPECT: 57c93bb85bSJerome Glisse a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay; 58c93bb85bSJerome Glisse a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay; 59c93bb85bSJerome Glisse 60c93bb85bSJerome Glisse if (a1 > a2) { 614589433cSCédric Cano args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2); 624589433cSCédric Cano args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2); 63c93bb85bSJerome Glisse } else if (a2 > a1) { 64942b0e95SAlex Deucher args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2); 65942b0e95SAlex Deucher args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2); 66c93bb85bSJerome Glisse } 67c93bb85bSJerome Glisse break; 68c93bb85bSJerome Glisse case RMX_FULL: 69c93bb85bSJerome Glisse default: 704589433cSCédric Cano args.usOverscanRight = cpu_to_le16(radeon_crtc->h_border); 714589433cSCédric Cano args.usOverscanLeft = cpu_to_le16(radeon_crtc->h_border); 724589433cSCédric Cano args.usOverscanBottom = cpu_to_le16(radeon_crtc->v_border); 734589433cSCédric Cano args.usOverscanTop = cpu_to_le16(radeon_crtc->v_border); 74c93bb85bSJerome Glisse break; 75c93bb85bSJerome Glisse } 765b1714d3SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 77c93bb85bSJerome Glisse } 78c93bb85bSJerome Glisse 79c93bb85bSJerome Glisse static void atombios_scaler_setup(struct drm_crtc *crtc) 80c93bb85bSJerome Glisse { 81c93bb85bSJerome Glisse struct drm_device *dev = crtc->dev; 82c93bb85bSJerome Glisse struct radeon_device *rdev = dev->dev_private; 83c93bb85bSJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 84c93bb85bSJerome Glisse ENABLE_SCALER_PS_ALLOCATION args; 85c93bb85bSJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, EnableScaler); 864ce001abSDave Airlie 87c93bb85bSJerome Glisse /* fixme - fill in enc_priv for atom dac */ 88c93bb85bSJerome Glisse enum radeon_tv_std tv_std = TV_STD_NTSC; 894ce001abSDave Airlie bool is_tv = false, is_cv = false; 904ce001abSDave Airlie struct drm_encoder *encoder; 91c93bb85bSJerome Glisse 92c93bb85bSJerome Glisse if (!ASIC_IS_AVIVO(rdev) && radeon_crtc->crtc_id) 93c93bb85bSJerome Glisse return; 94c93bb85bSJerome Glisse 954ce001abSDave Airlie list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 964ce001abSDave Airlie /* find tv std */ 974ce001abSDave Airlie if (encoder->crtc == crtc) { 984ce001abSDave Airlie struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 994ce001abSDave Airlie if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) { 1004ce001abSDave Airlie struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv; 1014ce001abSDave Airlie tv_std = tv_dac->tv_std; 1024ce001abSDave Airlie is_tv = true; 1034ce001abSDave Airlie } 1044ce001abSDave Airlie } 1054ce001abSDave Airlie } 1064ce001abSDave Airlie 107c93bb85bSJerome Glisse memset(&args, 0, sizeof(args)); 108c93bb85bSJerome Glisse 109c93bb85bSJerome Glisse args.ucScaler = radeon_crtc->crtc_id; 110c93bb85bSJerome Glisse 1114ce001abSDave Airlie if (is_tv) { 112c93bb85bSJerome Glisse switch (tv_std) { 113c93bb85bSJerome Glisse case TV_STD_NTSC: 114c93bb85bSJerome Glisse default: 115c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_NTSC; 116c93bb85bSJerome Glisse break; 117c93bb85bSJerome Glisse case TV_STD_PAL: 118c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_PAL; 119c93bb85bSJerome Glisse break; 120c93bb85bSJerome Glisse case TV_STD_PAL_M: 121c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_PALM; 122c93bb85bSJerome Glisse break; 123c93bb85bSJerome Glisse case TV_STD_PAL_60: 124c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_PAL60; 125c93bb85bSJerome Glisse break; 126c93bb85bSJerome Glisse case TV_STD_NTSC_J: 127c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_NTSCJ; 128c93bb85bSJerome Glisse break; 129c93bb85bSJerome Glisse case TV_STD_SCART_PAL: 130c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_PAL; /* ??? */ 131c93bb85bSJerome Glisse break; 132c93bb85bSJerome Glisse case TV_STD_SECAM: 133c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_SECAM; 134c93bb85bSJerome Glisse break; 135c93bb85bSJerome Glisse case TV_STD_PAL_CN: 136c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_PALCN; 137c93bb85bSJerome Glisse break; 138c93bb85bSJerome Glisse } 139c93bb85bSJerome Glisse args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; 1404ce001abSDave Airlie } else if (is_cv) { 141c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_CV; 142c93bb85bSJerome Glisse args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; 143c93bb85bSJerome Glisse } else { 144c93bb85bSJerome Glisse switch (radeon_crtc->rmx_type) { 145c93bb85bSJerome Glisse case RMX_FULL: 146c93bb85bSJerome Glisse args.ucEnable = ATOM_SCALER_EXPANSION; 147c93bb85bSJerome Glisse break; 148c93bb85bSJerome Glisse case RMX_CENTER: 149c93bb85bSJerome Glisse args.ucEnable = ATOM_SCALER_CENTER; 150c93bb85bSJerome Glisse break; 151c93bb85bSJerome Glisse case RMX_ASPECT: 152c93bb85bSJerome Glisse args.ucEnable = ATOM_SCALER_EXPANSION; 153c93bb85bSJerome Glisse break; 154c93bb85bSJerome Glisse default: 155c93bb85bSJerome Glisse if (ASIC_IS_AVIVO(rdev)) 156c93bb85bSJerome Glisse args.ucEnable = ATOM_SCALER_DISABLE; 157c93bb85bSJerome Glisse else 158c93bb85bSJerome Glisse args.ucEnable = ATOM_SCALER_CENTER; 159c93bb85bSJerome Glisse break; 160c93bb85bSJerome Glisse } 161c93bb85bSJerome Glisse } 162c93bb85bSJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 1634ce001abSDave Airlie if ((is_tv || is_cv) 1644ce001abSDave Airlie && rdev->family >= CHIP_RV515 && rdev->family <= CHIP_R580) { 1654ce001abSDave Airlie atom_rv515_force_tv_scaler(rdev, radeon_crtc); 166c93bb85bSJerome Glisse } 167c93bb85bSJerome Glisse } 168c93bb85bSJerome Glisse 169771fe6b9SJerome Glisse static void atombios_lock_crtc(struct drm_crtc *crtc, int lock) 170771fe6b9SJerome Glisse { 171771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 172771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 173771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 174771fe6b9SJerome Glisse int index = 175771fe6b9SJerome Glisse GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters); 176771fe6b9SJerome Glisse ENABLE_CRTC_PS_ALLOCATION args; 177771fe6b9SJerome Glisse 178771fe6b9SJerome Glisse memset(&args, 0, sizeof(args)); 179771fe6b9SJerome Glisse 180771fe6b9SJerome Glisse args.ucCRTC = radeon_crtc->crtc_id; 181771fe6b9SJerome Glisse args.ucEnable = lock; 182771fe6b9SJerome Glisse 183771fe6b9SJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 184771fe6b9SJerome Glisse } 185771fe6b9SJerome Glisse 186771fe6b9SJerome Glisse static void atombios_enable_crtc(struct drm_crtc *crtc, int state) 187771fe6b9SJerome Glisse { 188771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 189771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 190771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 191771fe6b9SJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC); 192771fe6b9SJerome Glisse ENABLE_CRTC_PS_ALLOCATION args; 193771fe6b9SJerome Glisse 194771fe6b9SJerome Glisse memset(&args, 0, sizeof(args)); 195771fe6b9SJerome Glisse 196771fe6b9SJerome Glisse args.ucCRTC = radeon_crtc->crtc_id; 197771fe6b9SJerome Glisse args.ucEnable = state; 198771fe6b9SJerome Glisse 199771fe6b9SJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 200771fe6b9SJerome Glisse } 201771fe6b9SJerome Glisse 202771fe6b9SJerome Glisse static void atombios_enable_crtc_memreq(struct drm_crtc *crtc, int state) 203771fe6b9SJerome Glisse { 204771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 205771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 206771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 207771fe6b9SJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, EnableCRTCMemReq); 208771fe6b9SJerome Glisse ENABLE_CRTC_PS_ALLOCATION args; 209771fe6b9SJerome Glisse 210771fe6b9SJerome Glisse memset(&args, 0, sizeof(args)); 211771fe6b9SJerome Glisse 212771fe6b9SJerome Glisse args.ucCRTC = radeon_crtc->crtc_id; 213771fe6b9SJerome Glisse args.ucEnable = state; 214771fe6b9SJerome Glisse 215771fe6b9SJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 216771fe6b9SJerome Glisse } 217771fe6b9SJerome Glisse 218771fe6b9SJerome Glisse static void atombios_blank_crtc(struct drm_crtc *crtc, int state) 219771fe6b9SJerome Glisse { 220771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 221771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 222771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 223771fe6b9SJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC); 224771fe6b9SJerome Glisse BLANK_CRTC_PS_ALLOCATION args; 225771fe6b9SJerome Glisse 226771fe6b9SJerome Glisse memset(&args, 0, sizeof(args)); 227771fe6b9SJerome Glisse 228771fe6b9SJerome Glisse args.ucCRTC = radeon_crtc->crtc_id; 229771fe6b9SJerome Glisse args.ucBlanking = state; 230771fe6b9SJerome Glisse 231771fe6b9SJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 232771fe6b9SJerome Glisse } 233771fe6b9SJerome Glisse 234771fe6b9SJerome Glisse void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) 235771fe6b9SJerome Glisse { 236771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 237771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 238500b7587SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 239771fe6b9SJerome Glisse 240771fe6b9SJerome Glisse switch (mode) { 241771fe6b9SJerome Glisse case DRM_MODE_DPMS_ON: 242d7311171SAlex Deucher radeon_crtc->enabled = true; 243d7311171SAlex Deucher /* adjust pm to dpms changes BEFORE enabling crtcs */ 244d7311171SAlex Deucher radeon_pm_compute_clocks(rdev); 24537b4390eSAlex Deucher atombios_enable_crtc(crtc, ATOM_ENABLE); 246771fe6b9SJerome Glisse if (ASIC_IS_DCE3(rdev)) 24737b4390eSAlex Deucher atombios_enable_crtc_memreq(crtc, ATOM_ENABLE); 24837b4390eSAlex Deucher atombios_blank_crtc(crtc, ATOM_DISABLE); 249500b7587SAlex Deucher drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); 250500b7587SAlex Deucher radeon_crtc_load_lut(crtc); 251771fe6b9SJerome Glisse break; 252771fe6b9SJerome Glisse case DRM_MODE_DPMS_STANDBY: 253771fe6b9SJerome Glisse case DRM_MODE_DPMS_SUSPEND: 254771fe6b9SJerome Glisse case DRM_MODE_DPMS_OFF: 255500b7587SAlex Deucher drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id); 256a93f344dSAlex Deucher if (radeon_crtc->enabled) 25737b4390eSAlex Deucher atombios_blank_crtc(crtc, ATOM_ENABLE); 258771fe6b9SJerome Glisse if (ASIC_IS_DCE3(rdev)) 25937b4390eSAlex Deucher atombios_enable_crtc_memreq(crtc, ATOM_DISABLE); 26037b4390eSAlex Deucher atombios_enable_crtc(crtc, ATOM_DISABLE); 261a48b9b4eSAlex Deucher radeon_crtc->enabled = false; 262d7311171SAlex Deucher /* adjust pm to dpms changes AFTER disabling crtcs */ 263d7311171SAlex Deucher radeon_pm_compute_clocks(rdev); 264771fe6b9SJerome Glisse break; 265771fe6b9SJerome Glisse } 266771fe6b9SJerome Glisse } 267771fe6b9SJerome Glisse 268771fe6b9SJerome Glisse static void 269771fe6b9SJerome Glisse atombios_set_crtc_dtd_timing(struct drm_crtc *crtc, 2705a9bcaccSAlex Deucher struct drm_display_mode *mode) 271771fe6b9SJerome Glisse { 2725a9bcaccSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 273771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 274771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 2755a9bcaccSAlex Deucher SET_CRTC_USING_DTD_TIMING_PARAMETERS args; 276771fe6b9SJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming); 2775a9bcaccSAlex Deucher u16 misc = 0; 278771fe6b9SJerome Glisse 2795a9bcaccSAlex Deucher memset(&args, 0, sizeof(args)); 2805b1714d3SAlex Deucher args.usH_Size = cpu_to_le16(mode->crtc_hdisplay - (radeon_crtc->h_border * 2)); 2815a9bcaccSAlex Deucher args.usH_Blanking_Time = 2825b1714d3SAlex Deucher cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay + (radeon_crtc->h_border * 2)); 2835b1714d3SAlex Deucher args.usV_Size = cpu_to_le16(mode->crtc_vdisplay - (radeon_crtc->v_border * 2)); 2845a9bcaccSAlex Deucher args.usV_Blanking_Time = 2855b1714d3SAlex Deucher cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay + (radeon_crtc->v_border * 2)); 2865a9bcaccSAlex Deucher args.usH_SyncOffset = 2875b1714d3SAlex Deucher cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay + radeon_crtc->h_border); 2885a9bcaccSAlex Deucher args.usH_SyncWidth = 2895a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start); 2905a9bcaccSAlex Deucher args.usV_SyncOffset = 2915b1714d3SAlex Deucher cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay + radeon_crtc->v_border); 2925a9bcaccSAlex Deucher args.usV_SyncWidth = 2935a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start); 2945b1714d3SAlex Deucher args.ucH_Border = radeon_crtc->h_border; 2955b1714d3SAlex Deucher args.ucV_Border = radeon_crtc->v_border; 2965a9bcaccSAlex Deucher 2975a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_NVSYNC) 2985a9bcaccSAlex Deucher misc |= ATOM_VSYNC_POLARITY; 2995a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_NHSYNC) 3005a9bcaccSAlex Deucher misc |= ATOM_HSYNC_POLARITY; 3015a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_CSYNC) 3025a9bcaccSAlex Deucher misc |= ATOM_COMPOSITESYNC; 3035a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_INTERLACE) 3045a9bcaccSAlex Deucher misc |= ATOM_INTERLACE; 3055a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 3065a9bcaccSAlex Deucher misc |= ATOM_DOUBLE_CLOCK_MODE; 3075a9bcaccSAlex Deucher 3085a9bcaccSAlex Deucher args.susModeMiscInfo.usAccess = cpu_to_le16(misc); 3095a9bcaccSAlex Deucher args.ucCRTC = radeon_crtc->crtc_id; 310771fe6b9SJerome Glisse 3115a9bcaccSAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 312771fe6b9SJerome Glisse } 313771fe6b9SJerome Glisse 3145a9bcaccSAlex Deucher static void atombios_crtc_set_timing(struct drm_crtc *crtc, 3155a9bcaccSAlex Deucher struct drm_display_mode *mode) 316771fe6b9SJerome Glisse { 3175a9bcaccSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 318771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 319771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 3205a9bcaccSAlex Deucher SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION args; 321771fe6b9SJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing); 3225a9bcaccSAlex Deucher u16 misc = 0; 323771fe6b9SJerome Glisse 3245a9bcaccSAlex Deucher memset(&args, 0, sizeof(args)); 3255a9bcaccSAlex Deucher args.usH_Total = cpu_to_le16(mode->crtc_htotal); 3265a9bcaccSAlex Deucher args.usH_Disp = cpu_to_le16(mode->crtc_hdisplay); 3275a9bcaccSAlex Deucher args.usH_SyncStart = cpu_to_le16(mode->crtc_hsync_start); 3285a9bcaccSAlex Deucher args.usH_SyncWidth = 3295a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start); 3305a9bcaccSAlex Deucher args.usV_Total = cpu_to_le16(mode->crtc_vtotal); 3315a9bcaccSAlex Deucher args.usV_Disp = cpu_to_le16(mode->crtc_vdisplay); 3325a9bcaccSAlex Deucher args.usV_SyncStart = cpu_to_le16(mode->crtc_vsync_start); 3335a9bcaccSAlex Deucher args.usV_SyncWidth = 3345a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start); 3355a9bcaccSAlex Deucher 33654bfe496SAlex Deucher args.ucOverscanRight = radeon_crtc->h_border; 33754bfe496SAlex Deucher args.ucOverscanLeft = radeon_crtc->h_border; 33854bfe496SAlex Deucher args.ucOverscanBottom = radeon_crtc->v_border; 33954bfe496SAlex Deucher args.ucOverscanTop = radeon_crtc->v_border; 34054bfe496SAlex Deucher 3415a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_NVSYNC) 3425a9bcaccSAlex Deucher misc |= ATOM_VSYNC_POLARITY; 3435a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_NHSYNC) 3445a9bcaccSAlex Deucher misc |= ATOM_HSYNC_POLARITY; 3455a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_CSYNC) 3465a9bcaccSAlex Deucher misc |= ATOM_COMPOSITESYNC; 3475a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_INTERLACE) 3485a9bcaccSAlex Deucher misc |= ATOM_INTERLACE; 3495a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 3505a9bcaccSAlex Deucher misc |= ATOM_DOUBLE_CLOCK_MODE; 3515a9bcaccSAlex Deucher 3525a9bcaccSAlex Deucher args.susModeMiscInfo.usAccess = cpu_to_le16(misc); 3535a9bcaccSAlex Deucher args.ucCRTC = radeon_crtc->crtc_id; 354771fe6b9SJerome Glisse 3555a9bcaccSAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 356771fe6b9SJerome Glisse } 357771fe6b9SJerome Glisse 358b792210eSAlex Deucher static void atombios_disable_ss(struct drm_crtc *crtc) 359b792210eSAlex Deucher { 360b792210eSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 361b792210eSAlex Deucher struct drm_device *dev = crtc->dev; 362b792210eSAlex Deucher struct radeon_device *rdev = dev->dev_private; 363b792210eSAlex Deucher u32 ss_cntl; 364b792210eSAlex Deucher 365b792210eSAlex Deucher if (ASIC_IS_DCE4(rdev)) { 366b792210eSAlex Deucher switch (radeon_crtc->pll_id) { 367b792210eSAlex Deucher case ATOM_PPLL1: 368b792210eSAlex Deucher ss_cntl = RREG32(EVERGREEN_P1PLL_SS_CNTL); 369b792210eSAlex Deucher ss_cntl &= ~EVERGREEN_PxPLL_SS_EN; 370b792210eSAlex Deucher WREG32(EVERGREEN_P1PLL_SS_CNTL, ss_cntl); 371b792210eSAlex Deucher break; 372b792210eSAlex Deucher case ATOM_PPLL2: 373b792210eSAlex Deucher ss_cntl = RREG32(EVERGREEN_P2PLL_SS_CNTL); 374b792210eSAlex Deucher ss_cntl &= ~EVERGREEN_PxPLL_SS_EN; 375b792210eSAlex Deucher WREG32(EVERGREEN_P2PLL_SS_CNTL, ss_cntl); 376b792210eSAlex Deucher break; 377b792210eSAlex Deucher case ATOM_DCPLL: 378b792210eSAlex Deucher case ATOM_PPLL_INVALID: 379b792210eSAlex Deucher return; 380b792210eSAlex Deucher } 381b792210eSAlex Deucher } else if (ASIC_IS_AVIVO(rdev)) { 382b792210eSAlex Deucher switch (radeon_crtc->pll_id) { 383b792210eSAlex Deucher case ATOM_PPLL1: 384b792210eSAlex Deucher ss_cntl = RREG32(AVIVO_P1PLL_INT_SS_CNTL); 385b792210eSAlex Deucher ss_cntl &= ~1; 386b792210eSAlex Deucher WREG32(AVIVO_P1PLL_INT_SS_CNTL, ss_cntl); 387b792210eSAlex Deucher break; 388b792210eSAlex Deucher case ATOM_PPLL2: 389b792210eSAlex Deucher ss_cntl = RREG32(AVIVO_P2PLL_INT_SS_CNTL); 390b792210eSAlex Deucher ss_cntl &= ~1; 391b792210eSAlex Deucher WREG32(AVIVO_P2PLL_INT_SS_CNTL, ss_cntl); 392b792210eSAlex Deucher break; 393b792210eSAlex Deucher case ATOM_DCPLL: 394b792210eSAlex Deucher case ATOM_PPLL_INVALID: 395b792210eSAlex Deucher return; 396b792210eSAlex Deucher } 397b792210eSAlex Deucher } 398b792210eSAlex Deucher } 399b792210eSAlex Deucher 400b792210eSAlex Deucher 40126b9fc3aSAlex Deucher union atom_enable_ss { 402ba032a58SAlex Deucher ENABLE_LVDS_SS_PARAMETERS lvds_ss; 403ba032a58SAlex Deucher ENABLE_LVDS_SS_PARAMETERS_V2 lvds_ss_2; 40426b9fc3aSAlex Deucher ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1; 405ba032a58SAlex Deucher ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 v2; 406a572eaa3SAlex Deucher ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 v3; 40726b9fc3aSAlex Deucher }; 40826b9fc3aSAlex Deucher 409ba032a58SAlex Deucher static void atombios_crtc_program_ss(struct drm_crtc *crtc, 410ba032a58SAlex Deucher int enable, 411ba032a58SAlex Deucher int pll_id, 412ba032a58SAlex Deucher struct radeon_atom_ss *ss) 413ebbe1cb9SAlex Deucher { 414ebbe1cb9SAlex Deucher struct drm_device *dev = crtc->dev; 415ebbe1cb9SAlex Deucher struct radeon_device *rdev = dev->dev_private; 416ebbe1cb9SAlex Deucher int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL); 41726b9fc3aSAlex Deucher union atom_enable_ss args; 418ebbe1cb9SAlex Deucher 419ebbe1cb9SAlex Deucher memset(&args, 0, sizeof(args)); 420ba032a58SAlex Deucher 421a572eaa3SAlex Deucher if (ASIC_IS_DCE5(rdev)) { 4224589433cSCédric Cano args.v3.usSpreadSpectrumAmountFrac = cpu_to_le16(0); 4238e8e523dSAlex Deucher args.v3.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 424a572eaa3SAlex Deucher switch (pll_id) { 425a572eaa3SAlex Deucher case ATOM_PPLL1: 426a572eaa3SAlex Deucher args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL; 4274589433cSCédric Cano args.v3.usSpreadSpectrumAmount = cpu_to_le16(ss->amount); 4284589433cSCédric Cano args.v3.usSpreadSpectrumStep = cpu_to_le16(ss->step); 429a572eaa3SAlex Deucher break; 430a572eaa3SAlex Deucher case ATOM_PPLL2: 431a572eaa3SAlex Deucher args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL; 4324589433cSCédric Cano args.v3.usSpreadSpectrumAmount = cpu_to_le16(ss->amount); 4334589433cSCédric Cano args.v3.usSpreadSpectrumStep = cpu_to_le16(ss->step); 434a572eaa3SAlex Deucher break; 435a572eaa3SAlex Deucher case ATOM_DCPLL: 436a572eaa3SAlex Deucher args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL; 4374589433cSCédric Cano args.v3.usSpreadSpectrumAmount = cpu_to_le16(0); 4384589433cSCédric Cano args.v3.usSpreadSpectrumStep = cpu_to_le16(0); 439a572eaa3SAlex Deucher break; 440a572eaa3SAlex Deucher case ATOM_PPLL_INVALID: 441a572eaa3SAlex Deucher return; 442a572eaa3SAlex Deucher } 443a572eaa3SAlex Deucher args.v2.ucEnable = enable; 4448e8e523dSAlex Deucher if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK)) 4458e8e523dSAlex Deucher args.v3.ucEnable = ATOM_DISABLE; 446a572eaa3SAlex Deucher } else if (ASIC_IS_DCE4(rdev)) { 447ba032a58SAlex Deucher args.v2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); 4488e8e523dSAlex Deucher args.v2.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 449ba032a58SAlex Deucher switch (pll_id) { 450ba032a58SAlex Deucher case ATOM_PPLL1: 451ba032a58SAlex Deucher args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P1PLL; 4524589433cSCédric Cano args.v2.usSpreadSpectrumAmount = cpu_to_le16(ss->amount); 4534589433cSCédric Cano args.v2.usSpreadSpectrumStep = cpu_to_le16(ss->step); 454ba032a58SAlex Deucher break; 455ba032a58SAlex Deucher case ATOM_PPLL2: 456ba032a58SAlex Deucher args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P2PLL; 4574589433cSCédric Cano args.v2.usSpreadSpectrumAmount = cpu_to_le16(ss->amount); 4584589433cSCédric Cano args.v2.usSpreadSpectrumStep = cpu_to_le16(ss->step); 459ba032a58SAlex Deucher break; 460ba032a58SAlex Deucher case ATOM_DCPLL: 461ba032a58SAlex Deucher args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_DCPLL; 4624589433cSCédric Cano args.v2.usSpreadSpectrumAmount = cpu_to_le16(0); 4634589433cSCédric Cano args.v2.usSpreadSpectrumStep = cpu_to_le16(0); 464ba032a58SAlex Deucher break; 465ba032a58SAlex Deucher case ATOM_PPLL_INVALID: 466ba032a58SAlex Deucher return; 467ba032a58SAlex Deucher } 468ba032a58SAlex Deucher args.v2.ucEnable = enable; 4698e8e523dSAlex Deucher if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK)) 4708e8e523dSAlex Deucher args.v2.ucEnable = ATOM_DISABLE; 471ba032a58SAlex Deucher } else if (ASIC_IS_DCE3(rdev)) { 472ba032a58SAlex Deucher args.v1.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); 4738e8e523dSAlex Deucher args.v1.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 474ba032a58SAlex Deucher args.v1.ucSpreadSpectrumStep = ss->step; 475ba032a58SAlex Deucher args.v1.ucSpreadSpectrumDelay = ss->delay; 476ba032a58SAlex Deucher args.v1.ucSpreadSpectrumRange = ss->range; 477ba032a58SAlex Deucher args.v1.ucPpll = pll_id; 478ba032a58SAlex Deucher args.v1.ucEnable = enable; 479ba032a58SAlex Deucher } else if (ASIC_IS_AVIVO(rdev)) { 4808e8e523dSAlex Deucher if ((enable == ATOM_DISABLE) || (ss->percentage == 0) || 4818e8e523dSAlex Deucher (ss->type & ATOM_EXTERNAL_SS_MASK)) { 482ba032a58SAlex Deucher atombios_disable_ss(crtc); 483ba032a58SAlex Deucher return; 484ba032a58SAlex Deucher } 485ba032a58SAlex Deucher args.lvds_ss_2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); 4868e8e523dSAlex Deucher args.lvds_ss_2.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 487ba032a58SAlex Deucher args.lvds_ss_2.ucSpreadSpectrumStep = ss->step; 488ba032a58SAlex Deucher args.lvds_ss_2.ucSpreadSpectrumDelay = ss->delay; 489ba032a58SAlex Deucher args.lvds_ss_2.ucSpreadSpectrumRange = ss->range; 490ba032a58SAlex Deucher args.lvds_ss_2.ucEnable = enable; 491ebbe1cb9SAlex Deucher } else { 4928e8e523dSAlex Deucher if ((enable == ATOM_DISABLE) || (ss->percentage == 0) || 4938e8e523dSAlex Deucher (ss->type & ATOM_EXTERNAL_SS_MASK)) { 494ba032a58SAlex Deucher atombios_disable_ss(crtc); 495ba032a58SAlex Deucher return; 496ba032a58SAlex Deucher } 497ba032a58SAlex Deucher args.lvds_ss.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); 4988e8e523dSAlex Deucher args.lvds_ss.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 499ba032a58SAlex Deucher args.lvds_ss.ucSpreadSpectrumStepSize_Delay = (ss->step & 3) << 2; 500ba032a58SAlex Deucher args.lvds_ss.ucSpreadSpectrumStepSize_Delay |= (ss->delay & 7) << 4; 501ba032a58SAlex Deucher args.lvds_ss.ucEnable = enable; 502ebbe1cb9SAlex Deucher } 50326b9fc3aSAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 504ebbe1cb9SAlex Deucher } 505ebbe1cb9SAlex Deucher 5064eaeca33SAlex Deucher union adjust_pixel_clock { 5074eaeca33SAlex Deucher ADJUST_DISPLAY_PLL_PS_ALLOCATION v1; 508bcc1c2a1SAlex Deucher ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 v3; 5094eaeca33SAlex Deucher }; 5104eaeca33SAlex Deucher 5114eaeca33SAlex Deucher static u32 atombios_adjust_pll(struct drm_crtc *crtc, 5124eaeca33SAlex Deucher struct drm_display_mode *mode, 513ba032a58SAlex Deucher struct radeon_pll *pll, 514ba032a58SAlex Deucher bool ss_enabled, 515ba032a58SAlex Deucher struct radeon_atom_ss *ss) 516771fe6b9SJerome Glisse { 517771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 518771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 519771fe6b9SJerome Glisse struct drm_encoder *encoder = NULL; 520771fe6b9SJerome Glisse struct radeon_encoder *radeon_encoder = NULL; 521df271becSAlex Deucher struct drm_connector *connector = NULL; 5224eaeca33SAlex Deucher u32 adjusted_clock = mode->clock; 523bcc1c2a1SAlex Deucher int encoder_mode = 0; 524fbee67a6SAlex Deucher u32 dp_clock = mode->clock; 525fbee67a6SAlex Deucher int bpc = 8; 526fc10332bSAlex Deucher 5274eaeca33SAlex Deucher /* reset the pll flags */ 5284eaeca33SAlex Deucher pll->flags = 0; 529771fe6b9SJerome Glisse 530771fe6b9SJerome Glisse if (ASIC_IS_AVIVO(rdev)) { 531eb1300bcSAlex Deucher if ((rdev->family == CHIP_RS600) || 532eb1300bcSAlex Deucher (rdev->family == CHIP_RS690) || 533eb1300bcSAlex Deucher (rdev->family == CHIP_RS740)) 5342ff776cfSAlex Deucher pll->flags |= (/*RADEON_PLL_USE_FRAC_FB_DIV |*/ 535eb1300bcSAlex Deucher RADEON_PLL_PREFER_CLOSEST_LOWER); 5365480f727SDave Airlie 5375480f727SDave Airlie if (ASIC_IS_DCE32(rdev) && mode->clock > 200000) /* range limits??? */ 5385480f727SDave Airlie pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; 5395480f727SDave Airlie else 5405480f727SDave Airlie pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; 5419bb09fa1SAlex Deucher 5425785e53fSAlex Deucher if (rdev->family < CHIP_RV770) 5439bb09fa1SAlex Deucher pll->flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP; 5445480f727SDave Airlie } else { 545fc10332bSAlex Deucher pll->flags |= RADEON_PLL_LEGACY; 546771fe6b9SJerome Glisse 5475480f727SDave Airlie if (mode->clock > 200000) /* range limits??? */ 5485480f727SDave Airlie pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; 5495480f727SDave Airlie else 5505480f727SDave Airlie pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; 5515480f727SDave Airlie } 5525480f727SDave Airlie 553771fe6b9SJerome Glisse list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 554771fe6b9SJerome Glisse if (encoder->crtc == crtc) { 5554eaeca33SAlex Deucher radeon_encoder = to_radeon_encoder(encoder); 556df271becSAlex Deucher connector = radeon_get_connector_for_encoder(encoder); 557df271becSAlex Deucher if (connector) 558df271becSAlex Deucher bpc = connector->display_info.bpc; 559bcc1c2a1SAlex Deucher encoder_mode = atombios_get_encoder_mode(encoder); 560fbee67a6SAlex Deucher if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) { 561fbee67a6SAlex Deucher if (connector) { 562fbee67a6SAlex Deucher struct radeon_connector *radeon_connector = to_radeon_connector(connector); 563fbee67a6SAlex Deucher struct radeon_connector_atom_dig *dig_connector = 564fbee67a6SAlex Deucher radeon_connector->con_priv; 565fbee67a6SAlex Deucher 566fbee67a6SAlex Deucher dp_clock = dig_connector->dp_clock; 567fbee67a6SAlex Deucher } 568fbee67a6SAlex Deucher } 5695b40ddf8SAlex Deucher 570ba032a58SAlex Deucher /* use recommended ref_div for ss */ 571ba032a58SAlex Deucher if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 572ba032a58SAlex Deucher if (ss_enabled) { 573ba032a58SAlex Deucher if (ss->refdiv) { 574ba032a58SAlex Deucher pll->flags |= RADEON_PLL_USE_REF_DIV; 575ba032a58SAlex Deucher pll->reference_div = ss->refdiv; 5765b40ddf8SAlex Deucher if (ASIC_IS_AVIVO(rdev)) 5775b40ddf8SAlex Deucher pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV; 578ba032a58SAlex Deucher } 579ba032a58SAlex Deucher } 580ba032a58SAlex Deucher } 5815b40ddf8SAlex Deucher 5824eaeca33SAlex Deucher if (ASIC_IS_AVIVO(rdev)) { 5834eaeca33SAlex Deucher /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ 5844eaeca33SAlex Deucher if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1) 5854eaeca33SAlex Deucher adjusted_clock = mode->clock * 2; 58648dfaaebSAlex Deucher if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 587a1a4b23bSAlex Deucher pll->flags |= RADEON_PLL_PREFER_CLOSEST_LOWER; 588619efb10SAlex Deucher if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) 589619efb10SAlex Deucher pll->flags |= RADEON_PLL_IS_LCD; 5904eaeca33SAlex Deucher } else { 5914eaeca33SAlex Deucher if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) 592fc10332bSAlex Deucher pll->flags |= RADEON_PLL_NO_ODD_POST_DIV; 5934eaeca33SAlex Deucher if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) 594fc10332bSAlex Deucher pll->flags |= RADEON_PLL_USE_REF_DIV; 595771fe6b9SJerome Glisse } 5963ce0a23dSJerome Glisse break; 597771fe6b9SJerome Glisse } 598771fe6b9SJerome Glisse } 599771fe6b9SJerome Glisse 6002606c886SAlex Deucher /* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock 6012606c886SAlex Deucher * accordingly based on the encoder/transmitter to work around 6022606c886SAlex Deucher * special hw requirements. 6032606c886SAlex Deucher */ 6042606c886SAlex Deucher if (ASIC_IS_DCE3(rdev)) { 6054eaeca33SAlex Deucher union adjust_pixel_clock args; 6064eaeca33SAlex Deucher u8 frev, crev; 6074eaeca33SAlex Deucher int index; 6082606c886SAlex Deucher 6092606c886SAlex Deucher index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll); 610a084e6eeSAlex Deucher if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 611a084e6eeSAlex Deucher &crev)) 612a084e6eeSAlex Deucher return adjusted_clock; 6134eaeca33SAlex Deucher 6144eaeca33SAlex Deucher memset(&args, 0, sizeof(args)); 6154eaeca33SAlex Deucher 6164eaeca33SAlex Deucher switch (frev) { 6174eaeca33SAlex Deucher case 1: 6184eaeca33SAlex Deucher switch (crev) { 6194eaeca33SAlex Deucher case 1: 6204eaeca33SAlex Deucher case 2: 6214eaeca33SAlex Deucher args.v1.usPixelClock = cpu_to_le16(mode->clock / 10); 6224eaeca33SAlex Deucher args.v1.ucTransmitterID = radeon_encoder->encoder_id; 623bcc1c2a1SAlex Deucher args.v1.ucEncodeMode = encoder_mode; 6248e8e523dSAlex Deucher if (ss_enabled && ss->percentage) 625ba032a58SAlex Deucher args.v1.ucConfig |= 626ba032a58SAlex Deucher ADJUST_DISPLAY_CONFIG_SS_ENABLE; 6274eaeca33SAlex Deucher 6282606c886SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, 6294eaeca33SAlex Deucher index, (uint32_t *)&args); 6304eaeca33SAlex Deucher adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10; 6314eaeca33SAlex Deucher break; 632bcc1c2a1SAlex Deucher case 3: 633bcc1c2a1SAlex Deucher args.v3.sInput.usPixelClock = cpu_to_le16(mode->clock / 10); 634bcc1c2a1SAlex Deucher args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id; 635bcc1c2a1SAlex Deucher args.v3.sInput.ucEncodeMode = encoder_mode; 636bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig = 0; 6378e8e523dSAlex Deucher if (ss_enabled && ss->percentage) 638ba032a58SAlex Deucher args.v3.sInput.ucDispPllConfig |= 639ba032a58SAlex Deucher DISPPLL_CONFIG_SS_ENABLE; 640b526ce22SAlex Deucher if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { 641b526ce22SAlex Deucher struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 642b526ce22SAlex Deucher if (encoder_mode == ATOM_ENCODER_MODE_DP) { 643bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 644bcc1c2a1SAlex Deucher DISPPLL_CONFIG_COHERENT_MODE; 645fbee67a6SAlex Deucher /* 16200 or 27000 */ 646fbee67a6SAlex Deucher args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); 647fbee67a6SAlex Deucher } else { 648fbee67a6SAlex Deucher if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { 649fbee67a6SAlex Deucher /* deep color support */ 650fbee67a6SAlex Deucher args.v3.sInput.usPixelClock = 651fbee67a6SAlex Deucher cpu_to_le16((mode->clock * bpc / 8) / 10); 652fbee67a6SAlex Deucher } 653bcc1c2a1SAlex Deucher if (dig->coherent_mode) 654bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 655bcc1c2a1SAlex Deucher DISPPLL_CONFIG_COHERENT_MODE; 656bcc1c2a1SAlex Deucher if (mode->clock > 165000) 657bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 658bcc1c2a1SAlex Deucher DISPPLL_CONFIG_DUAL_LINK; 659bcc1c2a1SAlex Deucher } 660bcc1c2a1SAlex Deucher } else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 661fbee67a6SAlex Deucher if (encoder_mode == ATOM_ENCODER_MODE_DP) { 662bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 6639f998ad7SAlex Deucher DISPPLL_CONFIG_COHERENT_MODE; 664fbee67a6SAlex Deucher /* 16200 or 27000 */ 665fbee67a6SAlex Deucher args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); 666b526ce22SAlex Deucher } else if (encoder_mode != ATOM_ENCODER_MODE_LVDS) { 667bcc1c2a1SAlex Deucher if (mode->clock > 165000) 668bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 669bcc1c2a1SAlex Deucher DISPPLL_CONFIG_DUAL_LINK; 670bcc1c2a1SAlex Deucher } 6719f998ad7SAlex Deucher } 672bcc1c2a1SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, 673bcc1c2a1SAlex Deucher index, (uint32_t *)&args); 674bcc1c2a1SAlex Deucher adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10; 675bcc1c2a1SAlex Deucher if (args.v3.sOutput.ucRefDiv) { 6769f4283f4SAlex Deucher pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV; 677bcc1c2a1SAlex Deucher pll->flags |= RADEON_PLL_USE_REF_DIV; 678bcc1c2a1SAlex Deucher pll->reference_div = args.v3.sOutput.ucRefDiv; 679bcc1c2a1SAlex Deucher } 680bcc1c2a1SAlex Deucher if (args.v3.sOutput.ucPostDiv) { 6819f4283f4SAlex Deucher pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV; 682bcc1c2a1SAlex Deucher pll->flags |= RADEON_PLL_USE_POST_DIV; 683bcc1c2a1SAlex Deucher pll->post_div = args.v3.sOutput.ucPostDiv; 684bcc1c2a1SAlex Deucher } 685bcc1c2a1SAlex Deucher break; 6864eaeca33SAlex Deucher default: 6874eaeca33SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 6884eaeca33SAlex Deucher return adjusted_clock; 689d56ef9c8SAlex Deucher } 6904eaeca33SAlex Deucher break; 6914eaeca33SAlex Deucher default: 6924eaeca33SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 6934eaeca33SAlex Deucher return adjusted_clock; 6944eaeca33SAlex Deucher } 6954eaeca33SAlex Deucher } 6964eaeca33SAlex Deucher return adjusted_clock; 6974eaeca33SAlex Deucher } 6984eaeca33SAlex Deucher 6994eaeca33SAlex Deucher union set_pixel_clock { 7004eaeca33SAlex Deucher SET_PIXEL_CLOCK_PS_ALLOCATION base; 7014eaeca33SAlex Deucher PIXEL_CLOCK_PARAMETERS v1; 7024eaeca33SAlex Deucher PIXEL_CLOCK_PARAMETERS_V2 v2; 7034eaeca33SAlex Deucher PIXEL_CLOCK_PARAMETERS_V3 v3; 704bcc1c2a1SAlex Deucher PIXEL_CLOCK_PARAMETERS_V5 v5; 705f82b3ddcSAlex Deucher PIXEL_CLOCK_PARAMETERS_V6 v6; 7064eaeca33SAlex Deucher }; 7074eaeca33SAlex Deucher 708f82b3ddcSAlex Deucher /* on DCE5, make sure the voltage is high enough to support the 709f82b3ddcSAlex Deucher * required disp clk. 710f82b3ddcSAlex Deucher */ 711f82b3ddcSAlex Deucher static void atombios_crtc_set_dcpll(struct drm_crtc *crtc, 712f82b3ddcSAlex Deucher u32 dispclk) 713bcc1c2a1SAlex Deucher { 714bcc1c2a1SAlex Deucher struct drm_device *dev = crtc->dev; 715bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 716bcc1c2a1SAlex Deucher u8 frev, crev; 717bcc1c2a1SAlex Deucher int index; 718bcc1c2a1SAlex Deucher union set_pixel_clock args; 719bcc1c2a1SAlex Deucher 720bcc1c2a1SAlex Deucher memset(&args, 0, sizeof(args)); 721bcc1c2a1SAlex Deucher 722bcc1c2a1SAlex Deucher index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); 723a084e6eeSAlex Deucher if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 724a084e6eeSAlex Deucher &crev)) 725a084e6eeSAlex Deucher return; 726bcc1c2a1SAlex Deucher 727bcc1c2a1SAlex Deucher switch (frev) { 728bcc1c2a1SAlex Deucher case 1: 729bcc1c2a1SAlex Deucher switch (crev) { 730bcc1c2a1SAlex Deucher case 5: 731bcc1c2a1SAlex Deucher /* if the default dcpll clock is specified, 732bcc1c2a1SAlex Deucher * SetPixelClock provides the dividers 733bcc1c2a1SAlex Deucher */ 734bcc1c2a1SAlex Deucher args.v5.ucCRTC = ATOM_CRTC_INVALID; 7354589433cSCédric Cano args.v5.usPixelClock = cpu_to_le16(dispclk); 736bcc1c2a1SAlex Deucher args.v5.ucPpll = ATOM_DCPLL; 737bcc1c2a1SAlex Deucher break; 738f82b3ddcSAlex Deucher case 6: 739f82b3ddcSAlex Deucher /* if the default dcpll clock is specified, 740f82b3ddcSAlex Deucher * SetPixelClock provides the dividers 741f82b3ddcSAlex Deucher */ 742265aa6c8SAlex Deucher args.v6.ulDispEngClkFreq = cpu_to_le32(dispclk); 743f82b3ddcSAlex Deucher args.v6.ucPpll = ATOM_DCPLL; 744f82b3ddcSAlex Deucher break; 745bcc1c2a1SAlex Deucher default: 746bcc1c2a1SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 747bcc1c2a1SAlex Deucher return; 748bcc1c2a1SAlex Deucher } 749bcc1c2a1SAlex Deucher break; 750bcc1c2a1SAlex Deucher default: 751bcc1c2a1SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 752bcc1c2a1SAlex Deucher return; 753bcc1c2a1SAlex Deucher } 754bcc1c2a1SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 755bcc1c2a1SAlex Deucher } 756bcc1c2a1SAlex Deucher 75737f9003bSAlex Deucher static void atombios_crtc_program_pll(struct drm_crtc *crtc, 75837f9003bSAlex Deucher int crtc_id, 75937f9003bSAlex Deucher int pll_id, 76037f9003bSAlex Deucher u32 encoder_mode, 76137f9003bSAlex Deucher u32 encoder_id, 76237f9003bSAlex Deucher u32 clock, 76337f9003bSAlex Deucher u32 ref_div, 76437f9003bSAlex Deucher u32 fb_div, 76537f9003bSAlex Deucher u32 frac_fb_div, 766df271becSAlex Deucher u32 post_div, 7678e8e523dSAlex Deucher int bpc, 7688e8e523dSAlex Deucher bool ss_enabled, 7698e8e523dSAlex Deucher struct radeon_atom_ss *ss) 77037f9003bSAlex Deucher { 77137f9003bSAlex Deucher struct drm_device *dev = crtc->dev; 77237f9003bSAlex Deucher struct radeon_device *rdev = dev->dev_private; 77337f9003bSAlex Deucher u8 frev, crev; 77437f9003bSAlex Deucher int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); 77537f9003bSAlex Deucher union set_pixel_clock args; 77637f9003bSAlex Deucher 77737f9003bSAlex Deucher memset(&args, 0, sizeof(args)); 77837f9003bSAlex Deucher 77937f9003bSAlex Deucher if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 78037f9003bSAlex Deucher &crev)) 78137f9003bSAlex Deucher return; 78237f9003bSAlex Deucher 78337f9003bSAlex Deucher switch (frev) { 78437f9003bSAlex Deucher case 1: 78537f9003bSAlex Deucher switch (crev) { 78637f9003bSAlex Deucher case 1: 78737f9003bSAlex Deucher if (clock == ATOM_DISABLE) 78837f9003bSAlex Deucher return; 78937f9003bSAlex Deucher args.v1.usPixelClock = cpu_to_le16(clock / 10); 79037f9003bSAlex Deucher args.v1.usRefDiv = cpu_to_le16(ref_div); 79137f9003bSAlex Deucher args.v1.usFbDiv = cpu_to_le16(fb_div); 79237f9003bSAlex Deucher args.v1.ucFracFbDiv = frac_fb_div; 79337f9003bSAlex Deucher args.v1.ucPostDiv = post_div; 79437f9003bSAlex Deucher args.v1.ucPpll = pll_id; 79537f9003bSAlex Deucher args.v1.ucCRTC = crtc_id; 79637f9003bSAlex Deucher args.v1.ucRefDivSrc = 1; 79737f9003bSAlex Deucher break; 79837f9003bSAlex Deucher case 2: 79937f9003bSAlex Deucher args.v2.usPixelClock = cpu_to_le16(clock / 10); 80037f9003bSAlex Deucher args.v2.usRefDiv = cpu_to_le16(ref_div); 80137f9003bSAlex Deucher args.v2.usFbDiv = cpu_to_le16(fb_div); 80237f9003bSAlex Deucher args.v2.ucFracFbDiv = frac_fb_div; 80337f9003bSAlex Deucher args.v2.ucPostDiv = post_div; 80437f9003bSAlex Deucher args.v2.ucPpll = pll_id; 80537f9003bSAlex Deucher args.v2.ucCRTC = crtc_id; 80637f9003bSAlex Deucher args.v2.ucRefDivSrc = 1; 80737f9003bSAlex Deucher break; 80837f9003bSAlex Deucher case 3: 80937f9003bSAlex Deucher args.v3.usPixelClock = cpu_to_le16(clock / 10); 81037f9003bSAlex Deucher args.v3.usRefDiv = cpu_to_le16(ref_div); 81137f9003bSAlex Deucher args.v3.usFbDiv = cpu_to_le16(fb_div); 81237f9003bSAlex Deucher args.v3.ucFracFbDiv = frac_fb_div; 81337f9003bSAlex Deucher args.v3.ucPostDiv = post_div; 81437f9003bSAlex Deucher args.v3.ucPpll = pll_id; 81537f9003bSAlex Deucher args.v3.ucMiscInfo = (pll_id << 2); 81637f9003bSAlex Deucher args.v3.ucTransmitterId = encoder_id; 81737f9003bSAlex Deucher args.v3.ucEncoderMode = encoder_mode; 81837f9003bSAlex Deucher break; 81937f9003bSAlex Deucher case 5: 82037f9003bSAlex Deucher args.v5.ucCRTC = crtc_id; 82137f9003bSAlex Deucher args.v5.usPixelClock = cpu_to_le16(clock / 10); 82237f9003bSAlex Deucher args.v5.ucRefDiv = ref_div; 82337f9003bSAlex Deucher args.v5.usFbDiv = cpu_to_le16(fb_div); 82437f9003bSAlex Deucher args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); 82537f9003bSAlex Deucher args.v5.ucPostDiv = post_div; 82637f9003bSAlex Deucher args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */ 8278e8e523dSAlex Deucher if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) 8288e8e523dSAlex Deucher args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_REF_DIV_SRC; 829df271becSAlex Deucher switch (bpc) { 830df271becSAlex Deucher case 8: 831df271becSAlex Deucher default: 832df271becSAlex Deucher args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP; 833df271becSAlex Deucher break; 834df271becSAlex Deucher case 10: 835df271becSAlex Deucher args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP; 836df271becSAlex Deucher break; 837df271becSAlex Deucher } 83837f9003bSAlex Deucher args.v5.ucTransmitterID = encoder_id; 83937f9003bSAlex Deucher args.v5.ucEncoderMode = encoder_mode; 84037f9003bSAlex Deucher args.v5.ucPpll = pll_id; 84137f9003bSAlex Deucher break; 842f82b3ddcSAlex Deucher case 6: 843f82b3ddcSAlex Deucher args.v6.ulCrtcPclkFreq.ucCRTC = crtc_id; 844f82b3ddcSAlex Deucher args.v6.ulCrtcPclkFreq.ulPixelClock = cpu_to_le32(clock / 10); 845f82b3ddcSAlex Deucher args.v6.ucRefDiv = ref_div; 846f82b3ddcSAlex Deucher args.v6.usFbDiv = cpu_to_le16(fb_div); 847f82b3ddcSAlex Deucher args.v6.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); 848f82b3ddcSAlex Deucher args.v6.ucPostDiv = post_div; 849f82b3ddcSAlex Deucher args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */ 8508e8e523dSAlex Deucher if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) 8518e8e523dSAlex Deucher args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_REF_DIV_SRC; 852df271becSAlex Deucher switch (bpc) { 853df271becSAlex Deucher case 8: 854df271becSAlex Deucher default: 855df271becSAlex Deucher args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP; 856df271becSAlex Deucher break; 857df271becSAlex Deucher case 10: 858df271becSAlex Deucher args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP; 859df271becSAlex Deucher break; 860df271becSAlex Deucher case 12: 861df271becSAlex Deucher args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP; 862df271becSAlex Deucher break; 863df271becSAlex Deucher case 16: 864df271becSAlex Deucher args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP; 865df271becSAlex Deucher break; 866df271becSAlex Deucher } 867f82b3ddcSAlex Deucher args.v6.ucTransmitterID = encoder_id; 868f82b3ddcSAlex Deucher args.v6.ucEncoderMode = encoder_mode; 869f82b3ddcSAlex Deucher args.v6.ucPpll = pll_id; 870f82b3ddcSAlex Deucher break; 87137f9003bSAlex Deucher default: 87237f9003bSAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 87337f9003bSAlex Deucher return; 87437f9003bSAlex Deucher } 87537f9003bSAlex Deucher break; 87637f9003bSAlex Deucher default: 87737f9003bSAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 87837f9003bSAlex Deucher return; 87937f9003bSAlex Deucher } 88037f9003bSAlex Deucher 88137f9003bSAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 88237f9003bSAlex Deucher } 88337f9003bSAlex Deucher 884bcc1c2a1SAlex Deucher static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) 8854eaeca33SAlex Deucher { 8864eaeca33SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 8874eaeca33SAlex Deucher struct drm_device *dev = crtc->dev; 8884eaeca33SAlex Deucher struct radeon_device *rdev = dev->dev_private; 8894eaeca33SAlex Deucher struct drm_encoder *encoder = NULL; 8904eaeca33SAlex Deucher struct radeon_encoder *radeon_encoder = NULL; 8914eaeca33SAlex Deucher u32 pll_clock = mode->clock; 8924eaeca33SAlex Deucher u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; 8934eaeca33SAlex Deucher struct radeon_pll *pll; 8944eaeca33SAlex Deucher u32 adjusted_clock; 895bcc1c2a1SAlex Deucher int encoder_mode = 0; 896ba032a58SAlex Deucher struct radeon_atom_ss ss; 897ba032a58SAlex Deucher bool ss_enabled = false; 898df271becSAlex Deucher int bpc = 8; 8994eaeca33SAlex Deucher 9004eaeca33SAlex Deucher list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 9014eaeca33SAlex Deucher if (encoder->crtc == crtc) { 9024eaeca33SAlex Deucher radeon_encoder = to_radeon_encoder(encoder); 903bcc1c2a1SAlex Deucher encoder_mode = atombios_get_encoder_mode(encoder); 9044eaeca33SAlex Deucher break; 9054eaeca33SAlex Deucher } 9064eaeca33SAlex Deucher } 9074eaeca33SAlex Deucher 9084eaeca33SAlex Deucher if (!radeon_encoder) 9094eaeca33SAlex Deucher return; 9104eaeca33SAlex Deucher 911bcc1c2a1SAlex Deucher switch (radeon_crtc->pll_id) { 912bcc1c2a1SAlex Deucher case ATOM_PPLL1: 9134eaeca33SAlex Deucher pll = &rdev->clock.p1pll; 914bcc1c2a1SAlex Deucher break; 915bcc1c2a1SAlex Deucher case ATOM_PPLL2: 9164eaeca33SAlex Deucher pll = &rdev->clock.p2pll; 917bcc1c2a1SAlex Deucher break; 918bcc1c2a1SAlex Deucher case ATOM_DCPLL: 919bcc1c2a1SAlex Deucher case ATOM_PPLL_INVALID: 920921d98b5SStefan Richter default: 921bcc1c2a1SAlex Deucher pll = &rdev->clock.dcpll; 922bcc1c2a1SAlex Deucher break; 923bcc1c2a1SAlex Deucher } 9244eaeca33SAlex Deucher 925ba032a58SAlex Deucher if (radeon_encoder->active_device & 926ba032a58SAlex Deucher (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) { 927ba032a58SAlex Deucher struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 928ba032a58SAlex Deucher struct drm_connector *connector = 929ba032a58SAlex Deucher radeon_get_connector_for_encoder(encoder); 930ba032a58SAlex Deucher struct radeon_connector *radeon_connector = 931ba032a58SAlex Deucher to_radeon_connector(connector); 932ba032a58SAlex Deucher struct radeon_connector_atom_dig *dig_connector = 933ba032a58SAlex Deucher radeon_connector->con_priv; 934ba032a58SAlex Deucher int dp_clock; 935df271becSAlex Deucher bpc = connector->display_info.bpc; 936ba032a58SAlex Deucher 937ba032a58SAlex Deucher switch (encoder_mode) { 938ba032a58SAlex Deucher case ATOM_ENCODER_MODE_DP: 939ba032a58SAlex Deucher /* DP/eDP */ 940ba032a58SAlex Deucher dp_clock = dig_connector->dp_clock / 10; 941ba032a58SAlex Deucher if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) { 9428e8e523dSAlex Deucher if (ASIC_IS_DCE4(rdev)) { 9438e8e523dSAlex Deucher /* first try ASIC_INTERNAL_SS_ON_DP */ 9448e8e523dSAlex Deucher ss_enabled = 9458e8e523dSAlex Deucher radeon_atombios_get_asic_ss_info(rdev, &ss, 9468e8e523dSAlex Deucher ASIC_INTERNAL_SS_ON_DP, 9478e8e523dSAlex Deucher dp_clock); 9488e8e523dSAlex Deucher if (!ss_enabled) 949ba032a58SAlex Deucher ss_enabled = 950ba032a58SAlex Deucher radeon_atombios_get_asic_ss_info(rdev, &ss, 951ba032a58SAlex Deucher dig->lcd_ss_id, 952ba032a58SAlex Deucher dp_clock); 9538e8e523dSAlex Deucher } else 954ba032a58SAlex Deucher ss_enabled = 955ba032a58SAlex Deucher radeon_atombios_get_ppll_ss_info(rdev, &ss, 956ba032a58SAlex Deucher dig->lcd_ss_id); 957ba032a58SAlex Deucher } else { 958ba032a58SAlex Deucher if (ASIC_IS_DCE4(rdev)) 959ba032a58SAlex Deucher ss_enabled = 960ba032a58SAlex Deucher radeon_atombios_get_asic_ss_info(rdev, &ss, 961ba032a58SAlex Deucher ASIC_INTERNAL_SS_ON_DP, 962ba032a58SAlex Deucher dp_clock); 963ba032a58SAlex Deucher else { 964ba032a58SAlex Deucher if (dp_clock == 16200) { 965ba032a58SAlex Deucher ss_enabled = 966ba032a58SAlex Deucher radeon_atombios_get_ppll_ss_info(rdev, &ss, 967ba032a58SAlex Deucher ATOM_DP_SS_ID2); 968ba032a58SAlex Deucher if (!ss_enabled) 969ba032a58SAlex Deucher ss_enabled = 970ba032a58SAlex Deucher radeon_atombios_get_ppll_ss_info(rdev, &ss, 971ba032a58SAlex Deucher ATOM_DP_SS_ID1); 972ba032a58SAlex Deucher } else 973ba032a58SAlex Deucher ss_enabled = 974ba032a58SAlex Deucher radeon_atombios_get_ppll_ss_info(rdev, &ss, 975ba032a58SAlex Deucher ATOM_DP_SS_ID1); 976ba032a58SAlex Deucher } 977ba032a58SAlex Deucher } 978ba032a58SAlex Deucher break; 979ba032a58SAlex Deucher case ATOM_ENCODER_MODE_LVDS: 980ba032a58SAlex Deucher if (ASIC_IS_DCE4(rdev)) 981ba032a58SAlex Deucher ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &ss, 982ba032a58SAlex Deucher dig->lcd_ss_id, 983ba032a58SAlex Deucher mode->clock / 10); 984ba032a58SAlex Deucher else 985ba032a58SAlex Deucher ss_enabled = radeon_atombios_get_ppll_ss_info(rdev, &ss, 986ba032a58SAlex Deucher dig->lcd_ss_id); 987ba032a58SAlex Deucher break; 988ba032a58SAlex Deucher case ATOM_ENCODER_MODE_DVI: 989ba032a58SAlex Deucher if (ASIC_IS_DCE4(rdev)) 990ba032a58SAlex Deucher ss_enabled = 991ba032a58SAlex Deucher radeon_atombios_get_asic_ss_info(rdev, &ss, 992ba032a58SAlex Deucher ASIC_INTERNAL_SS_ON_TMDS, 993ba032a58SAlex Deucher mode->clock / 10); 994ba032a58SAlex Deucher break; 995ba032a58SAlex Deucher case ATOM_ENCODER_MODE_HDMI: 996ba032a58SAlex Deucher if (ASIC_IS_DCE4(rdev)) 997ba032a58SAlex Deucher ss_enabled = 998ba032a58SAlex Deucher radeon_atombios_get_asic_ss_info(rdev, &ss, 999ba032a58SAlex Deucher ASIC_INTERNAL_SS_ON_HDMI, 1000ba032a58SAlex Deucher mode->clock / 10); 1001ba032a58SAlex Deucher break; 1002ba032a58SAlex Deucher default: 1003ba032a58SAlex Deucher break; 1004ba032a58SAlex Deucher } 1005ba032a58SAlex Deucher } 1006ba032a58SAlex Deucher 10074eaeca33SAlex Deucher /* adjust pixel clock as needed */ 1008ba032a58SAlex Deucher adjusted_clock = atombios_adjust_pll(crtc, mode, pll, ss_enabled, &ss); 10092606c886SAlex Deucher 101064146f8bSAlex Deucher if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 101164146f8bSAlex Deucher /* TV seems to prefer the legacy algo on some boards */ 101264146f8bSAlex Deucher radeon_compute_pll_legacy(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, 101364146f8bSAlex Deucher &ref_div, &post_div); 101464146f8bSAlex Deucher else if (ASIC_IS_AVIVO(rdev)) 1015619efb10SAlex Deucher radeon_compute_pll_avivo(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, 1016619efb10SAlex Deucher &ref_div, &post_div); 1017619efb10SAlex Deucher else 1018f523f74eSAlex Deucher radeon_compute_pll_legacy(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, 1019fc10332bSAlex Deucher &ref_div, &post_div); 1020771fe6b9SJerome Glisse 1021ba032a58SAlex Deucher atombios_crtc_program_ss(crtc, ATOM_DISABLE, radeon_crtc->pll_id, &ss); 1022ba032a58SAlex Deucher 102337f9003bSAlex Deucher atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, 102437f9003bSAlex Deucher encoder_mode, radeon_encoder->encoder_id, mode->clock, 10258e8e523dSAlex Deucher ref_div, fb_div, frac_fb_div, post_div, bpc, ss_enabled, &ss); 1026771fe6b9SJerome Glisse 1027ba032a58SAlex Deucher if (ss_enabled) { 1028ba032a58SAlex Deucher /* calculate ss amount and step size */ 1029ba032a58SAlex Deucher if (ASIC_IS_DCE4(rdev)) { 1030ba032a58SAlex Deucher u32 step_size; 1031ba032a58SAlex Deucher u32 amount = (((fb_div * 10) + frac_fb_div) * ss.percentage) / 10000; 1032ba032a58SAlex Deucher ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK; 10338e8e523dSAlex Deucher ss.amount |= ((amount - (amount / 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) & 1034ba032a58SAlex Deucher ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK; 1035ba032a58SAlex Deucher if (ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD) 1036ba032a58SAlex Deucher step_size = (4 * amount * ref_div * (ss.rate * 2048)) / 1037ba032a58SAlex Deucher (125 * 25 * pll->reference_freq / 100); 1038ba032a58SAlex Deucher else 1039ba032a58SAlex Deucher step_size = (2 * amount * ref_div * (ss.rate * 2048)) / 1040ba032a58SAlex Deucher (125 * 25 * pll->reference_freq / 100); 1041ba032a58SAlex Deucher ss.step = step_size; 1042ba032a58SAlex Deucher } 1043ba032a58SAlex Deucher 1044ba032a58SAlex Deucher atombios_crtc_program_ss(crtc, ATOM_ENABLE, radeon_crtc->pll_id, &ss); 1045ba032a58SAlex Deucher } 1046771fe6b9SJerome Glisse } 1047771fe6b9SJerome Glisse 1048c9417bddSAlex Deucher static int dce4_crtc_do_set_base(struct drm_crtc *crtc, 10494dd19b0dSChris Ball struct drm_framebuffer *fb, 10504dd19b0dSChris Ball int x, int y, int atomic) 1051bcc1c2a1SAlex Deucher { 1052bcc1c2a1SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1053bcc1c2a1SAlex Deucher struct drm_device *dev = crtc->dev; 1054bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 1055bcc1c2a1SAlex Deucher struct radeon_framebuffer *radeon_fb; 10564dd19b0dSChris Ball struct drm_framebuffer *target_fb; 1057bcc1c2a1SAlex Deucher struct drm_gem_object *obj; 1058bcc1c2a1SAlex Deucher struct radeon_bo *rbo; 1059bcc1c2a1SAlex Deucher uint64_t fb_location; 1060bcc1c2a1SAlex Deucher uint32_t fb_format, fb_pitch_pixels, tiling_flags; 1061fa6bee46SAlex Deucher u32 fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE); 1062fb9674bdSAlex Deucher u32 tmp; 1063bcc1c2a1SAlex Deucher int r; 1064bcc1c2a1SAlex Deucher 1065bcc1c2a1SAlex Deucher /* no fb bound */ 10664dd19b0dSChris Ball if (!atomic && !crtc->fb) { 1067d9fdaafbSDave Airlie DRM_DEBUG_KMS("No FB bound\n"); 1068bcc1c2a1SAlex Deucher return 0; 1069bcc1c2a1SAlex Deucher } 1070bcc1c2a1SAlex Deucher 10714dd19b0dSChris Ball if (atomic) { 10724dd19b0dSChris Ball radeon_fb = to_radeon_framebuffer(fb); 10734dd19b0dSChris Ball target_fb = fb; 10744dd19b0dSChris Ball } 10754dd19b0dSChris Ball else { 1076bcc1c2a1SAlex Deucher radeon_fb = to_radeon_framebuffer(crtc->fb); 10774dd19b0dSChris Ball target_fb = crtc->fb; 10784dd19b0dSChris Ball } 1079bcc1c2a1SAlex Deucher 10804dd19b0dSChris Ball /* If atomic, assume fb object is pinned & idle & fenced and 10814dd19b0dSChris Ball * just update base pointers 10824dd19b0dSChris Ball */ 1083bcc1c2a1SAlex Deucher obj = radeon_fb->obj; 10847e4d15d9SDaniel Vetter rbo = gem_to_radeon_bo(obj); 1085bcc1c2a1SAlex Deucher r = radeon_bo_reserve(rbo, false); 1086bcc1c2a1SAlex Deucher if (unlikely(r != 0)) 1087bcc1c2a1SAlex Deucher return r; 10884dd19b0dSChris Ball 10894dd19b0dSChris Ball if (atomic) 10904dd19b0dSChris Ball fb_location = radeon_bo_gpu_offset(rbo); 10914dd19b0dSChris Ball else { 1092bcc1c2a1SAlex Deucher r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); 1093bcc1c2a1SAlex Deucher if (unlikely(r != 0)) { 1094bcc1c2a1SAlex Deucher radeon_bo_unreserve(rbo); 1095bcc1c2a1SAlex Deucher return -EINVAL; 1096bcc1c2a1SAlex Deucher } 10974dd19b0dSChris Ball } 10984dd19b0dSChris Ball 1099bcc1c2a1SAlex Deucher radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); 1100bcc1c2a1SAlex Deucher radeon_bo_unreserve(rbo); 1101bcc1c2a1SAlex Deucher 11024dd19b0dSChris Ball switch (target_fb->bits_per_pixel) { 1103bcc1c2a1SAlex Deucher case 8: 1104bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP) | 1105bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED)); 1106bcc1c2a1SAlex Deucher break; 1107bcc1c2a1SAlex Deucher case 15: 1108bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 1109bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB1555)); 1110bcc1c2a1SAlex Deucher break; 1111bcc1c2a1SAlex Deucher case 16: 1112bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 1113bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565)); 1114fa6bee46SAlex Deucher #ifdef __BIG_ENDIAN 1115fa6bee46SAlex Deucher fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16); 1116fa6bee46SAlex Deucher #endif 1117bcc1c2a1SAlex Deucher break; 1118bcc1c2a1SAlex Deucher case 24: 1119bcc1c2a1SAlex Deucher case 32: 1120bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) | 1121bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888)); 1122fa6bee46SAlex Deucher #ifdef __BIG_ENDIAN 1123fa6bee46SAlex Deucher fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32); 1124fa6bee46SAlex Deucher #endif 1125bcc1c2a1SAlex Deucher break; 1126bcc1c2a1SAlex Deucher default: 1127bcc1c2a1SAlex Deucher DRM_ERROR("Unsupported screen depth %d\n", 11284dd19b0dSChris Ball target_fb->bits_per_pixel); 1129bcc1c2a1SAlex Deucher return -EINVAL; 1130bcc1c2a1SAlex Deucher } 1131bcc1c2a1SAlex Deucher 113297d66328SAlex Deucher if (tiling_flags & RADEON_TILING_MACRO) 113397d66328SAlex Deucher fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1); 113497d66328SAlex Deucher else if (tiling_flags & RADEON_TILING_MICRO) 113597d66328SAlex Deucher fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1); 113697d66328SAlex Deucher 1137bcc1c2a1SAlex Deucher switch (radeon_crtc->crtc_id) { 1138bcc1c2a1SAlex Deucher case 0: 1139bcc1c2a1SAlex Deucher WREG32(AVIVO_D1VGA_CONTROL, 0); 1140bcc1c2a1SAlex Deucher break; 1141bcc1c2a1SAlex Deucher case 1: 1142bcc1c2a1SAlex Deucher WREG32(AVIVO_D2VGA_CONTROL, 0); 1143bcc1c2a1SAlex Deucher break; 1144bcc1c2a1SAlex Deucher case 2: 1145bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D3VGA_CONTROL, 0); 1146bcc1c2a1SAlex Deucher break; 1147bcc1c2a1SAlex Deucher case 3: 1148bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D4VGA_CONTROL, 0); 1149bcc1c2a1SAlex Deucher break; 1150bcc1c2a1SAlex Deucher case 4: 1151bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D5VGA_CONTROL, 0); 1152bcc1c2a1SAlex Deucher break; 1153bcc1c2a1SAlex Deucher case 5: 1154bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D6VGA_CONTROL, 0); 1155bcc1c2a1SAlex Deucher break; 1156bcc1c2a1SAlex Deucher default: 1157bcc1c2a1SAlex Deucher break; 1158bcc1c2a1SAlex Deucher } 1159bcc1c2a1SAlex Deucher 1160bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 1161bcc1c2a1SAlex Deucher upper_32_bits(fb_location)); 1162bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 1163bcc1c2a1SAlex Deucher upper_32_bits(fb_location)); 1164bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 1165bcc1c2a1SAlex Deucher (u32)fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK); 1166bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 1167bcc1c2a1SAlex Deucher (u32) fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK); 1168bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); 1169fa6bee46SAlex Deucher WREG32(EVERGREEN_GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap); 1170bcc1c2a1SAlex Deucher 1171bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); 1172bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); 1173bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_X_START + radeon_crtc->crtc_offset, 0); 1174bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_Y_START + radeon_crtc->crtc_offset, 0); 11754dd19b0dSChris Ball WREG32(EVERGREEN_GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width); 11764dd19b0dSChris Ball WREG32(EVERGREEN_GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height); 1177bcc1c2a1SAlex Deucher 11784dd19b0dSChris Ball fb_pitch_pixels = target_fb->pitch / (target_fb->bits_per_pixel / 8); 1179bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); 1180bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1); 1181bcc1c2a1SAlex Deucher 1182bcc1c2a1SAlex Deucher WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, 1183bcc1c2a1SAlex Deucher crtc->mode.vdisplay); 1184bcc1c2a1SAlex Deucher x &= ~3; 1185bcc1c2a1SAlex Deucher y &= ~1; 1186bcc1c2a1SAlex Deucher WREG32(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset, 1187bcc1c2a1SAlex Deucher (x << 16) | y); 1188bcc1c2a1SAlex Deucher WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset, 1189bcc1c2a1SAlex Deucher (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay); 1190bcc1c2a1SAlex Deucher 1191fb9674bdSAlex Deucher /* pageflip setup */ 1192fb9674bdSAlex Deucher /* make sure flip is at vb rather than hb */ 1193fb9674bdSAlex Deucher tmp = RREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset); 1194fb9674bdSAlex Deucher tmp &= ~EVERGREEN_GRPH_SURFACE_UPDATE_H_RETRACE_EN; 1195fb9674bdSAlex Deucher WREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, tmp); 1196fb9674bdSAlex Deucher 1197fb9674bdSAlex Deucher /* set pageflip to happen anywhere in vblank interval */ 1198fb9674bdSAlex Deucher WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); 1199fb9674bdSAlex Deucher 12004dd19b0dSChris Ball if (!atomic && fb && fb != crtc->fb) { 12014dd19b0dSChris Ball radeon_fb = to_radeon_framebuffer(fb); 12027e4d15d9SDaniel Vetter rbo = gem_to_radeon_bo(radeon_fb->obj); 1203bcc1c2a1SAlex Deucher r = radeon_bo_reserve(rbo, false); 1204bcc1c2a1SAlex Deucher if (unlikely(r != 0)) 1205bcc1c2a1SAlex Deucher return r; 1206bcc1c2a1SAlex Deucher radeon_bo_unpin(rbo); 1207bcc1c2a1SAlex Deucher radeon_bo_unreserve(rbo); 1208bcc1c2a1SAlex Deucher } 1209bcc1c2a1SAlex Deucher 1210bcc1c2a1SAlex Deucher /* Bytes per pixel may have changed */ 1211bcc1c2a1SAlex Deucher radeon_bandwidth_update(rdev); 1212bcc1c2a1SAlex Deucher 1213bcc1c2a1SAlex Deucher return 0; 1214bcc1c2a1SAlex Deucher } 1215bcc1c2a1SAlex Deucher 12164dd19b0dSChris Ball static int avivo_crtc_do_set_base(struct drm_crtc *crtc, 12174dd19b0dSChris Ball struct drm_framebuffer *fb, 12184dd19b0dSChris Ball int x, int y, int atomic) 1219771fe6b9SJerome Glisse { 1220771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1221771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 1222771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 1223771fe6b9SJerome Glisse struct radeon_framebuffer *radeon_fb; 1224771fe6b9SJerome Glisse struct drm_gem_object *obj; 12254c788679SJerome Glisse struct radeon_bo *rbo; 12264dd19b0dSChris Ball struct drm_framebuffer *target_fb; 1227771fe6b9SJerome Glisse uint64_t fb_location; 1228e024e110SDave Airlie uint32_t fb_format, fb_pitch_pixels, tiling_flags; 1229fa6bee46SAlex Deucher u32 fb_swap = R600_D1GRPH_SWAP_ENDIAN_NONE; 1230fb9674bdSAlex Deucher u32 tmp; 12314c788679SJerome Glisse int r; 1232771fe6b9SJerome Glisse 12332de3b484SJerome Glisse /* no fb bound */ 12344dd19b0dSChris Ball if (!atomic && !crtc->fb) { 1235d9fdaafbSDave Airlie DRM_DEBUG_KMS("No FB bound\n"); 12362de3b484SJerome Glisse return 0; 12372de3b484SJerome Glisse } 1238771fe6b9SJerome Glisse 12394dd19b0dSChris Ball if (atomic) { 12404dd19b0dSChris Ball radeon_fb = to_radeon_framebuffer(fb); 12414dd19b0dSChris Ball target_fb = fb; 12424dd19b0dSChris Ball } 12434dd19b0dSChris Ball else { 1244771fe6b9SJerome Glisse radeon_fb = to_radeon_framebuffer(crtc->fb); 12454dd19b0dSChris Ball target_fb = crtc->fb; 12464dd19b0dSChris Ball } 1247771fe6b9SJerome Glisse 1248771fe6b9SJerome Glisse obj = radeon_fb->obj; 12497e4d15d9SDaniel Vetter rbo = gem_to_radeon_bo(obj); 12504c788679SJerome Glisse r = radeon_bo_reserve(rbo, false); 12514c788679SJerome Glisse if (unlikely(r != 0)) 12524c788679SJerome Glisse return r; 12534dd19b0dSChris Ball 12544dd19b0dSChris Ball /* If atomic, assume fb object is pinned & idle & fenced and 12554dd19b0dSChris Ball * just update base pointers 12564dd19b0dSChris Ball */ 12574dd19b0dSChris Ball if (atomic) 12584dd19b0dSChris Ball fb_location = radeon_bo_gpu_offset(rbo); 12594dd19b0dSChris Ball else { 12604c788679SJerome Glisse r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); 12614c788679SJerome Glisse if (unlikely(r != 0)) { 12624c788679SJerome Glisse radeon_bo_unreserve(rbo); 1263771fe6b9SJerome Glisse return -EINVAL; 1264771fe6b9SJerome Glisse } 12654dd19b0dSChris Ball } 12664c788679SJerome Glisse radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); 12674c788679SJerome Glisse radeon_bo_unreserve(rbo); 1268771fe6b9SJerome Glisse 12694dd19b0dSChris Ball switch (target_fb->bits_per_pixel) { 127041456df2SDave Airlie case 8: 127141456df2SDave Airlie fb_format = 127241456df2SDave Airlie AVIVO_D1GRPH_CONTROL_DEPTH_8BPP | 127341456df2SDave Airlie AVIVO_D1GRPH_CONTROL_8BPP_INDEXED; 127441456df2SDave Airlie break; 1275771fe6b9SJerome Glisse case 15: 1276771fe6b9SJerome Glisse fb_format = 1277771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | 1278771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555; 1279771fe6b9SJerome Glisse break; 1280771fe6b9SJerome Glisse case 16: 1281771fe6b9SJerome Glisse fb_format = 1282771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | 1283771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_16BPP_RGB565; 1284fa6bee46SAlex Deucher #ifdef __BIG_ENDIAN 1285fa6bee46SAlex Deucher fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT; 1286fa6bee46SAlex Deucher #endif 1287771fe6b9SJerome Glisse break; 1288771fe6b9SJerome Glisse case 24: 1289771fe6b9SJerome Glisse case 32: 1290771fe6b9SJerome Glisse fb_format = 1291771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_32BPP | 1292771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888; 1293fa6bee46SAlex Deucher #ifdef __BIG_ENDIAN 1294fa6bee46SAlex Deucher fb_swap = R600_D1GRPH_SWAP_ENDIAN_32BIT; 1295fa6bee46SAlex Deucher #endif 1296771fe6b9SJerome Glisse break; 1297771fe6b9SJerome Glisse default: 1298771fe6b9SJerome Glisse DRM_ERROR("Unsupported screen depth %d\n", 12994dd19b0dSChris Ball target_fb->bits_per_pixel); 1300771fe6b9SJerome Glisse return -EINVAL; 1301771fe6b9SJerome Glisse } 1302771fe6b9SJerome Glisse 130340c4ac1cSAlex Deucher if (rdev->family >= CHIP_R600) { 130440c4ac1cSAlex Deucher if (tiling_flags & RADEON_TILING_MACRO) 130540c4ac1cSAlex Deucher fb_format |= R600_D1GRPH_ARRAY_MODE_2D_TILED_THIN1; 130640c4ac1cSAlex Deucher else if (tiling_flags & RADEON_TILING_MICRO) 130740c4ac1cSAlex Deucher fb_format |= R600_D1GRPH_ARRAY_MODE_1D_TILED_THIN1; 130840c4ac1cSAlex Deucher } else { 1309cf2f05d3SDave Airlie if (tiling_flags & RADEON_TILING_MACRO) 1310cf2f05d3SDave Airlie fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE; 1311cf2f05d3SDave Airlie 1312e024e110SDave Airlie if (tiling_flags & RADEON_TILING_MICRO) 1313e024e110SDave Airlie fb_format |= AVIVO_D1GRPH_TILED; 131440c4ac1cSAlex Deucher } 1315e024e110SDave Airlie 1316771fe6b9SJerome Glisse if (radeon_crtc->crtc_id == 0) 1317771fe6b9SJerome Glisse WREG32(AVIVO_D1VGA_CONTROL, 0); 1318771fe6b9SJerome Glisse else 1319771fe6b9SJerome Glisse WREG32(AVIVO_D2VGA_CONTROL, 0); 1320c290dadfSAlex Deucher 1321c290dadfSAlex Deucher if (rdev->family >= CHIP_RV770) { 1322c290dadfSAlex Deucher if (radeon_crtc->crtc_id) { 132395347871SAlex Deucher WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 132495347871SAlex Deucher WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 1325c290dadfSAlex Deucher } else { 132695347871SAlex Deucher WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 132795347871SAlex Deucher WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 1328c290dadfSAlex Deucher } 1329c290dadfSAlex Deucher } 1330771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 1331771fe6b9SJerome Glisse (u32) fb_location); 1332771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + 1333771fe6b9SJerome Glisse radeon_crtc->crtc_offset, (u32) fb_location); 1334771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); 1335fa6bee46SAlex Deucher if (rdev->family >= CHIP_R600) 1336fa6bee46SAlex Deucher WREG32(R600_D1GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap); 1337771fe6b9SJerome Glisse 1338771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); 1339771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); 1340771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0); 1341771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, 0); 13424dd19b0dSChris Ball WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width); 13434dd19b0dSChris Ball WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height); 1344771fe6b9SJerome Glisse 13454dd19b0dSChris Ball fb_pitch_pixels = target_fb->pitch / (target_fb->bits_per_pixel / 8); 1346771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); 1347771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1); 1348771fe6b9SJerome Glisse 1349771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, 1350771fe6b9SJerome Glisse crtc->mode.vdisplay); 1351771fe6b9SJerome Glisse x &= ~3; 1352771fe6b9SJerome Glisse y &= ~1; 1353771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset, 1354771fe6b9SJerome Glisse (x << 16) | y); 1355771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset, 1356771fe6b9SJerome Glisse (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay); 1357771fe6b9SJerome Glisse 1358fb9674bdSAlex Deucher /* pageflip setup */ 1359fb9674bdSAlex Deucher /* make sure flip is at vb rather than hb */ 1360fb9674bdSAlex Deucher tmp = RREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset); 1361fb9674bdSAlex Deucher tmp &= ~AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN; 1362fb9674bdSAlex Deucher WREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, tmp); 1363fb9674bdSAlex Deucher 1364fb9674bdSAlex Deucher /* set pageflip to happen anywhere in vblank interval */ 1365fb9674bdSAlex Deucher WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); 1366fb9674bdSAlex Deucher 13674dd19b0dSChris Ball if (!atomic && fb && fb != crtc->fb) { 13684dd19b0dSChris Ball radeon_fb = to_radeon_framebuffer(fb); 13697e4d15d9SDaniel Vetter rbo = gem_to_radeon_bo(radeon_fb->obj); 13704c788679SJerome Glisse r = radeon_bo_reserve(rbo, false); 13714c788679SJerome Glisse if (unlikely(r != 0)) 13724c788679SJerome Glisse return r; 13734c788679SJerome Glisse radeon_bo_unpin(rbo); 13744c788679SJerome Glisse radeon_bo_unreserve(rbo); 1375771fe6b9SJerome Glisse } 1376f30f37deSMichel Dänzer 1377f30f37deSMichel Dänzer /* Bytes per pixel may have changed */ 1378f30f37deSMichel Dänzer radeon_bandwidth_update(rdev); 1379f30f37deSMichel Dänzer 1380771fe6b9SJerome Glisse return 0; 1381771fe6b9SJerome Glisse } 1382771fe6b9SJerome Glisse 138354f088a9SAlex Deucher int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, 138454f088a9SAlex Deucher struct drm_framebuffer *old_fb) 138554f088a9SAlex Deucher { 138654f088a9SAlex Deucher struct drm_device *dev = crtc->dev; 138754f088a9SAlex Deucher struct radeon_device *rdev = dev->dev_private; 138854f088a9SAlex Deucher 1389bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) 1390c9417bddSAlex Deucher return dce4_crtc_do_set_base(crtc, old_fb, x, y, 0); 1391bcc1c2a1SAlex Deucher else if (ASIC_IS_AVIVO(rdev)) 13924dd19b0dSChris Ball return avivo_crtc_do_set_base(crtc, old_fb, x, y, 0); 139354f088a9SAlex Deucher else 13944dd19b0dSChris Ball return radeon_crtc_do_set_base(crtc, old_fb, x, y, 0); 13954dd19b0dSChris Ball } 13964dd19b0dSChris Ball 13974dd19b0dSChris Ball int atombios_crtc_set_base_atomic(struct drm_crtc *crtc, 13984dd19b0dSChris Ball struct drm_framebuffer *fb, 139921c74a8eSJason Wessel int x, int y, enum mode_set_atomic state) 14004dd19b0dSChris Ball { 14014dd19b0dSChris Ball struct drm_device *dev = crtc->dev; 14024dd19b0dSChris Ball struct radeon_device *rdev = dev->dev_private; 14034dd19b0dSChris Ball 14044dd19b0dSChris Ball if (ASIC_IS_DCE4(rdev)) 1405c9417bddSAlex Deucher return dce4_crtc_do_set_base(crtc, fb, x, y, 1); 14064dd19b0dSChris Ball else if (ASIC_IS_AVIVO(rdev)) 14074dd19b0dSChris Ball return avivo_crtc_do_set_base(crtc, fb, x, y, 1); 14084dd19b0dSChris Ball else 14094dd19b0dSChris Ball return radeon_crtc_do_set_base(crtc, fb, x, y, 1); 141054f088a9SAlex Deucher } 141154f088a9SAlex Deucher 1412615e0cb6SAlex Deucher /* properly set additional regs when using atombios */ 1413615e0cb6SAlex Deucher static void radeon_legacy_atom_fixup(struct drm_crtc *crtc) 1414615e0cb6SAlex Deucher { 1415615e0cb6SAlex Deucher struct drm_device *dev = crtc->dev; 1416615e0cb6SAlex Deucher struct radeon_device *rdev = dev->dev_private; 1417615e0cb6SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1418615e0cb6SAlex Deucher u32 disp_merge_cntl; 1419615e0cb6SAlex Deucher 1420615e0cb6SAlex Deucher switch (radeon_crtc->crtc_id) { 1421615e0cb6SAlex Deucher case 0: 1422615e0cb6SAlex Deucher disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL); 1423615e0cb6SAlex Deucher disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; 1424615e0cb6SAlex Deucher WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl); 1425615e0cb6SAlex Deucher break; 1426615e0cb6SAlex Deucher case 1: 1427615e0cb6SAlex Deucher disp_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL); 1428615e0cb6SAlex Deucher disp_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN; 1429615e0cb6SAlex Deucher WREG32(RADEON_DISP2_MERGE_CNTL, disp_merge_cntl); 1430615e0cb6SAlex Deucher WREG32(RADEON_FP_H2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_H_SYNC_STRT_WID)); 1431615e0cb6SAlex Deucher WREG32(RADEON_FP_V2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_V_SYNC_STRT_WID)); 1432615e0cb6SAlex Deucher break; 1433615e0cb6SAlex Deucher } 1434615e0cb6SAlex Deucher } 1435615e0cb6SAlex Deucher 1436bcc1c2a1SAlex Deucher static int radeon_atom_pick_pll(struct drm_crtc *crtc) 1437bcc1c2a1SAlex Deucher { 1438bcc1c2a1SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1439bcc1c2a1SAlex Deucher struct drm_device *dev = crtc->dev; 1440bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 1441bcc1c2a1SAlex Deucher struct drm_encoder *test_encoder; 1442bcc1c2a1SAlex Deucher struct drm_crtc *test_crtc; 1443bcc1c2a1SAlex Deucher uint32_t pll_in_use = 0; 1444bcc1c2a1SAlex Deucher 1445bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) { 1446bcc1c2a1SAlex Deucher /* if crtc is driving DP and we have an ext clock, use that */ 1447bcc1c2a1SAlex Deucher list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { 1448bcc1c2a1SAlex Deucher if (test_encoder->crtc && (test_encoder->crtc == crtc)) { 1449bcc1c2a1SAlex Deucher if (atombios_get_encoder_mode(test_encoder) == ATOM_ENCODER_MODE_DP) { 1450bcc1c2a1SAlex Deucher if (rdev->clock.dp_extclk) 1451bcc1c2a1SAlex Deucher return ATOM_PPLL_INVALID; 1452bcc1c2a1SAlex Deucher } 1453bcc1c2a1SAlex Deucher } 1454bcc1c2a1SAlex Deucher } 1455bcc1c2a1SAlex Deucher 1456bcc1c2a1SAlex Deucher /* otherwise, pick one of the plls */ 1457bcc1c2a1SAlex Deucher list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { 1458bcc1c2a1SAlex Deucher struct radeon_crtc *radeon_test_crtc; 1459bcc1c2a1SAlex Deucher 1460bcc1c2a1SAlex Deucher if (crtc == test_crtc) 1461bcc1c2a1SAlex Deucher continue; 1462bcc1c2a1SAlex Deucher 1463bcc1c2a1SAlex Deucher radeon_test_crtc = to_radeon_crtc(test_crtc); 1464bcc1c2a1SAlex Deucher if ((radeon_test_crtc->pll_id >= ATOM_PPLL1) && 1465bcc1c2a1SAlex Deucher (radeon_test_crtc->pll_id <= ATOM_PPLL2)) 1466bcc1c2a1SAlex Deucher pll_in_use |= (1 << radeon_test_crtc->pll_id); 1467bcc1c2a1SAlex Deucher } 1468bcc1c2a1SAlex Deucher if (!(pll_in_use & 1)) 1469bcc1c2a1SAlex Deucher return ATOM_PPLL1; 1470bcc1c2a1SAlex Deucher return ATOM_PPLL2; 1471bcc1c2a1SAlex Deucher } else 1472bcc1c2a1SAlex Deucher return radeon_crtc->crtc_id; 1473bcc1c2a1SAlex Deucher 1474bcc1c2a1SAlex Deucher } 1475bcc1c2a1SAlex Deucher 1476771fe6b9SJerome Glisse int atombios_crtc_mode_set(struct drm_crtc *crtc, 1477771fe6b9SJerome Glisse struct drm_display_mode *mode, 1478771fe6b9SJerome Glisse struct drm_display_mode *adjusted_mode, 1479771fe6b9SJerome Glisse int x, int y, struct drm_framebuffer *old_fb) 1480771fe6b9SJerome Glisse { 1481771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1482771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 1483771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 148454bfe496SAlex Deucher struct drm_encoder *encoder; 148554bfe496SAlex Deucher bool is_tvcv = false; 1486771fe6b9SJerome Glisse 148754bfe496SAlex Deucher list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 148854bfe496SAlex Deucher /* find tv std */ 148954bfe496SAlex Deucher if (encoder->crtc == crtc) { 149054bfe496SAlex Deucher struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 149154bfe496SAlex Deucher if (radeon_encoder->active_device & 149254bfe496SAlex Deucher (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) 149354bfe496SAlex Deucher is_tvcv = true; 149454bfe496SAlex Deucher } 149554bfe496SAlex Deucher } 1496771fe6b9SJerome Glisse 1497bcc1c2a1SAlex Deucher /* always set DCPLL */ 1498ba032a58SAlex Deucher if (ASIC_IS_DCE4(rdev)) { 1499ba032a58SAlex Deucher struct radeon_atom_ss ss; 1500ba032a58SAlex Deucher bool ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &ss, 1501ba032a58SAlex Deucher ASIC_INTERNAL_SS_ON_DCPLL, 1502ba032a58SAlex Deucher rdev->clock.default_dispclk); 1503ba032a58SAlex Deucher if (ss_enabled) 1504ba032a58SAlex Deucher atombios_crtc_program_ss(crtc, ATOM_DISABLE, ATOM_DCPLL, &ss); 1505f82b3ddcSAlex Deucher /* XXX: DCE5, make sure voltage, dispclk is high enough */ 1506f82b3ddcSAlex Deucher atombios_crtc_set_dcpll(crtc, rdev->clock.default_dispclk); 1507ba032a58SAlex Deucher if (ss_enabled) 1508ba032a58SAlex Deucher atombios_crtc_program_ss(crtc, ATOM_ENABLE, ATOM_DCPLL, &ss); 1509ba032a58SAlex Deucher } 1510771fe6b9SJerome Glisse atombios_crtc_set_pll(crtc, adjusted_mode); 1511771fe6b9SJerome Glisse 151254bfe496SAlex Deucher if (ASIC_IS_DCE4(rdev)) 1513bcc1c2a1SAlex Deucher atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 151454bfe496SAlex Deucher else if (ASIC_IS_AVIVO(rdev)) { 151554bfe496SAlex Deucher if (is_tvcv) 151654bfe496SAlex Deucher atombios_crtc_set_timing(crtc, adjusted_mode); 151754bfe496SAlex Deucher else 151854bfe496SAlex Deucher atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 151954bfe496SAlex Deucher } else { 1520bcc1c2a1SAlex Deucher atombios_crtc_set_timing(crtc, adjusted_mode); 15215a9bcaccSAlex Deucher if (radeon_crtc->crtc_id == 0) 15225a9bcaccSAlex Deucher atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 1523615e0cb6SAlex Deucher radeon_legacy_atom_fixup(crtc); 1524771fe6b9SJerome Glisse } 1525bcc1c2a1SAlex Deucher atombios_crtc_set_base(crtc, x, y, old_fb); 1526c93bb85bSJerome Glisse atombios_overscan_setup(crtc, mode, adjusted_mode); 1527c93bb85bSJerome Glisse atombios_scaler_setup(crtc); 1528771fe6b9SJerome Glisse return 0; 1529771fe6b9SJerome Glisse } 1530771fe6b9SJerome Glisse 1531771fe6b9SJerome Glisse static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, 1532771fe6b9SJerome Glisse struct drm_display_mode *mode, 1533771fe6b9SJerome Glisse struct drm_display_mode *adjusted_mode) 1534771fe6b9SJerome Glisse { 153503214bd5SAlex Deucher struct drm_device *dev = crtc->dev; 153603214bd5SAlex Deucher struct radeon_device *rdev = dev->dev_private; 153703214bd5SAlex Deucher 153803214bd5SAlex Deucher /* adjust pm to upcoming mode change */ 153903214bd5SAlex Deucher radeon_pm_compute_clocks(rdev); 154003214bd5SAlex Deucher 1541c93bb85bSJerome Glisse if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) 1542c93bb85bSJerome Glisse return false; 1543771fe6b9SJerome Glisse return true; 1544771fe6b9SJerome Glisse } 1545771fe6b9SJerome Glisse 1546771fe6b9SJerome Glisse static void atombios_crtc_prepare(struct drm_crtc *crtc) 1547771fe6b9SJerome Glisse { 1548267364acSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1549267364acSAlex Deucher 1550267364acSAlex Deucher /* pick pll */ 1551267364acSAlex Deucher radeon_crtc->pll_id = radeon_atom_pick_pll(crtc); 1552267364acSAlex Deucher 155337b4390eSAlex Deucher atombios_lock_crtc(crtc, ATOM_ENABLE); 1554a348c84dSAlex Deucher atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 1555771fe6b9SJerome Glisse } 1556771fe6b9SJerome Glisse 1557771fe6b9SJerome Glisse static void atombios_crtc_commit(struct drm_crtc *crtc) 1558771fe6b9SJerome Glisse { 1559771fe6b9SJerome Glisse atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON); 156037b4390eSAlex Deucher atombios_lock_crtc(crtc, ATOM_DISABLE); 1561771fe6b9SJerome Glisse } 1562771fe6b9SJerome Glisse 156337f9003bSAlex Deucher static void atombios_crtc_disable(struct drm_crtc *crtc) 156437f9003bSAlex Deucher { 156537f9003bSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 15668e8e523dSAlex Deucher struct radeon_atom_ss ss; 15678e8e523dSAlex Deucher 156837f9003bSAlex Deucher atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 156937f9003bSAlex Deucher 157037f9003bSAlex Deucher switch (radeon_crtc->pll_id) { 157137f9003bSAlex Deucher case ATOM_PPLL1: 157237f9003bSAlex Deucher case ATOM_PPLL2: 157337f9003bSAlex Deucher /* disable the ppll */ 157437f9003bSAlex Deucher atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, 15758e8e523dSAlex Deucher 0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss); 157637f9003bSAlex Deucher break; 157737f9003bSAlex Deucher default: 157837f9003bSAlex Deucher break; 157937f9003bSAlex Deucher } 158037f9003bSAlex Deucher radeon_crtc->pll_id = -1; 158137f9003bSAlex Deucher } 158237f9003bSAlex Deucher 1583771fe6b9SJerome Glisse static const struct drm_crtc_helper_funcs atombios_helper_funcs = { 1584771fe6b9SJerome Glisse .dpms = atombios_crtc_dpms, 1585771fe6b9SJerome Glisse .mode_fixup = atombios_crtc_mode_fixup, 1586771fe6b9SJerome Glisse .mode_set = atombios_crtc_mode_set, 1587771fe6b9SJerome Glisse .mode_set_base = atombios_crtc_set_base, 15884dd19b0dSChris Ball .mode_set_base_atomic = atombios_crtc_set_base_atomic, 1589771fe6b9SJerome Glisse .prepare = atombios_crtc_prepare, 1590771fe6b9SJerome Glisse .commit = atombios_crtc_commit, 1591068143d3SDave Airlie .load_lut = radeon_crtc_load_lut, 159237f9003bSAlex Deucher .disable = atombios_crtc_disable, 1593771fe6b9SJerome Glisse }; 1594771fe6b9SJerome Glisse 1595771fe6b9SJerome Glisse void radeon_atombios_init_crtc(struct drm_device *dev, 1596771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc) 1597771fe6b9SJerome Glisse { 1598bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 1599bcc1c2a1SAlex Deucher 1600bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) { 1601bcc1c2a1SAlex Deucher switch (radeon_crtc->crtc_id) { 1602bcc1c2a1SAlex Deucher case 0: 1603bcc1c2a1SAlex Deucher default: 160412d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC0_REGISTER_OFFSET; 1605bcc1c2a1SAlex Deucher break; 1606bcc1c2a1SAlex Deucher case 1: 160712d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC1_REGISTER_OFFSET; 1608bcc1c2a1SAlex Deucher break; 1609bcc1c2a1SAlex Deucher case 2: 161012d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC2_REGISTER_OFFSET; 1611bcc1c2a1SAlex Deucher break; 1612bcc1c2a1SAlex Deucher case 3: 161312d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC3_REGISTER_OFFSET; 1614bcc1c2a1SAlex Deucher break; 1615bcc1c2a1SAlex Deucher case 4: 161612d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC4_REGISTER_OFFSET; 1617bcc1c2a1SAlex Deucher break; 1618bcc1c2a1SAlex Deucher case 5: 161912d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC5_REGISTER_OFFSET; 1620bcc1c2a1SAlex Deucher break; 1621bcc1c2a1SAlex Deucher } 1622bcc1c2a1SAlex Deucher } else { 1623771fe6b9SJerome Glisse if (radeon_crtc->crtc_id == 1) 1624771fe6b9SJerome Glisse radeon_crtc->crtc_offset = 1625771fe6b9SJerome Glisse AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL; 1626bcc1c2a1SAlex Deucher else 1627bcc1c2a1SAlex Deucher radeon_crtc->crtc_offset = 0; 1628bcc1c2a1SAlex Deucher } 1629bcc1c2a1SAlex Deucher radeon_crtc->pll_id = -1; 1630771fe6b9SJerome Glisse drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); 1631771fe6b9SJerome Glisse } 1632