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 3583fa47d9eSAlex Deucher static void atombios_disable_ss(struct radeon_device *rdev, int pll_id) 359b792210eSAlex Deucher { 360b792210eSAlex Deucher u32 ss_cntl; 361b792210eSAlex Deucher 362b792210eSAlex Deucher if (ASIC_IS_DCE4(rdev)) { 3633fa47d9eSAlex Deucher switch (pll_id) { 364b792210eSAlex Deucher case ATOM_PPLL1: 365b792210eSAlex Deucher ss_cntl = RREG32(EVERGREEN_P1PLL_SS_CNTL); 366b792210eSAlex Deucher ss_cntl &= ~EVERGREEN_PxPLL_SS_EN; 367b792210eSAlex Deucher WREG32(EVERGREEN_P1PLL_SS_CNTL, ss_cntl); 368b792210eSAlex Deucher break; 369b792210eSAlex Deucher case ATOM_PPLL2: 370b792210eSAlex Deucher ss_cntl = RREG32(EVERGREEN_P2PLL_SS_CNTL); 371b792210eSAlex Deucher ss_cntl &= ~EVERGREEN_PxPLL_SS_EN; 372b792210eSAlex Deucher WREG32(EVERGREEN_P2PLL_SS_CNTL, ss_cntl); 373b792210eSAlex Deucher break; 374b792210eSAlex Deucher case ATOM_DCPLL: 375b792210eSAlex Deucher case ATOM_PPLL_INVALID: 376b792210eSAlex Deucher return; 377b792210eSAlex Deucher } 378b792210eSAlex Deucher } else if (ASIC_IS_AVIVO(rdev)) { 3793fa47d9eSAlex Deucher switch (pll_id) { 380b792210eSAlex Deucher case ATOM_PPLL1: 381b792210eSAlex Deucher ss_cntl = RREG32(AVIVO_P1PLL_INT_SS_CNTL); 382b792210eSAlex Deucher ss_cntl &= ~1; 383b792210eSAlex Deucher WREG32(AVIVO_P1PLL_INT_SS_CNTL, ss_cntl); 384b792210eSAlex Deucher break; 385b792210eSAlex Deucher case ATOM_PPLL2: 386b792210eSAlex Deucher ss_cntl = RREG32(AVIVO_P2PLL_INT_SS_CNTL); 387b792210eSAlex Deucher ss_cntl &= ~1; 388b792210eSAlex Deucher WREG32(AVIVO_P2PLL_INT_SS_CNTL, ss_cntl); 389b792210eSAlex Deucher break; 390b792210eSAlex Deucher case ATOM_DCPLL: 391b792210eSAlex Deucher case ATOM_PPLL_INVALID: 392b792210eSAlex Deucher return; 393b792210eSAlex Deucher } 394b792210eSAlex Deucher } 395b792210eSAlex Deucher } 396b792210eSAlex Deucher 397b792210eSAlex Deucher 39826b9fc3aSAlex Deucher union atom_enable_ss { 399ba032a58SAlex Deucher ENABLE_LVDS_SS_PARAMETERS lvds_ss; 400ba032a58SAlex Deucher ENABLE_LVDS_SS_PARAMETERS_V2 lvds_ss_2; 40126b9fc3aSAlex Deucher ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1; 402ba032a58SAlex Deucher ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 v2; 403a572eaa3SAlex Deucher ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 v3; 40426b9fc3aSAlex Deucher }; 40526b9fc3aSAlex Deucher 4063fa47d9eSAlex Deucher static void atombios_crtc_program_ss(struct radeon_device *rdev, 407ba032a58SAlex Deucher int enable, 408ba032a58SAlex Deucher int pll_id, 409ba032a58SAlex Deucher struct radeon_atom_ss *ss) 410ebbe1cb9SAlex Deucher { 411ebbe1cb9SAlex Deucher int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL); 41226b9fc3aSAlex Deucher union atom_enable_ss args; 413ebbe1cb9SAlex Deucher 414ebbe1cb9SAlex Deucher memset(&args, 0, sizeof(args)); 415ba032a58SAlex Deucher 416a572eaa3SAlex Deucher if (ASIC_IS_DCE5(rdev)) { 4174589433cSCédric Cano args.v3.usSpreadSpectrumAmountFrac = cpu_to_le16(0); 4188e8e523dSAlex Deucher args.v3.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 419a572eaa3SAlex Deucher switch (pll_id) { 420a572eaa3SAlex Deucher case ATOM_PPLL1: 421a572eaa3SAlex Deucher args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL; 4224589433cSCédric Cano args.v3.usSpreadSpectrumAmount = cpu_to_le16(ss->amount); 4234589433cSCédric Cano args.v3.usSpreadSpectrumStep = cpu_to_le16(ss->step); 424a572eaa3SAlex Deucher break; 425a572eaa3SAlex Deucher case ATOM_PPLL2: 426a572eaa3SAlex Deucher args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL; 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_DCPLL: 431a572eaa3SAlex Deucher args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL; 4324589433cSCédric Cano args.v3.usSpreadSpectrumAmount = cpu_to_le16(0); 4334589433cSCédric Cano args.v3.usSpreadSpectrumStep = cpu_to_le16(0); 434a572eaa3SAlex Deucher break; 435a572eaa3SAlex Deucher case ATOM_PPLL_INVALID: 436a572eaa3SAlex Deucher return; 437a572eaa3SAlex Deucher } 438d0ae3e89SAlex Deucher args.v3.ucEnable = enable; 4398e8e523dSAlex Deucher if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK)) 4408e8e523dSAlex Deucher args.v3.ucEnable = ATOM_DISABLE; 441a572eaa3SAlex Deucher } else if (ASIC_IS_DCE4(rdev)) { 442ba032a58SAlex Deucher args.v2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); 4438e8e523dSAlex Deucher args.v2.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 444ba032a58SAlex Deucher switch (pll_id) { 445ba032a58SAlex Deucher case ATOM_PPLL1: 446ba032a58SAlex Deucher args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P1PLL; 4474589433cSCédric Cano args.v2.usSpreadSpectrumAmount = cpu_to_le16(ss->amount); 4484589433cSCédric Cano args.v2.usSpreadSpectrumStep = cpu_to_le16(ss->step); 449ba032a58SAlex Deucher break; 450ba032a58SAlex Deucher case ATOM_PPLL2: 451ba032a58SAlex Deucher args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P2PLL; 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_DCPLL: 456ba032a58SAlex Deucher args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_DCPLL; 4574589433cSCédric Cano args.v2.usSpreadSpectrumAmount = cpu_to_le16(0); 4584589433cSCédric Cano args.v2.usSpreadSpectrumStep = cpu_to_le16(0); 459ba032a58SAlex Deucher break; 460ba032a58SAlex Deucher case ATOM_PPLL_INVALID: 461ba032a58SAlex Deucher return; 462ba032a58SAlex Deucher } 463ba032a58SAlex Deucher args.v2.ucEnable = enable; 46409cc6506SAlex Deucher if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK) || ASIC_IS_DCE41(rdev)) 4658e8e523dSAlex Deucher args.v2.ucEnable = ATOM_DISABLE; 466ba032a58SAlex Deucher } else if (ASIC_IS_DCE3(rdev)) { 467ba032a58SAlex Deucher args.v1.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); 4688e8e523dSAlex Deucher args.v1.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 469ba032a58SAlex Deucher args.v1.ucSpreadSpectrumStep = ss->step; 470ba032a58SAlex Deucher args.v1.ucSpreadSpectrumDelay = ss->delay; 471ba032a58SAlex Deucher args.v1.ucSpreadSpectrumRange = ss->range; 472ba032a58SAlex Deucher args.v1.ucPpll = pll_id; 473ba032a58SAlex Deucher args.v1.ucEnable = enable; 474ba032a58SAlex Deucher } else if (ASIC_IS_AVIVO(rdev)) { 4758e8e523dSAlex Deucher if ((enable == ATOM_DISABLE) || (ss->percentage == 0) || 4768e8e523dSAlex Deucher (ss->type & ATOM_EXTERNAL_SS_MASK)) { 4773fa47d9eSAlex Deucher atombios_disable_ss(rdev, pll_id); 478ba032a58SAlex Deucher return; 479ba032a58SAlex Deucher } 480ba032a58SAlex Deucher args.lvds_ss_2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); 4818e8e523dSAlex Deucher args.lvds_ss_2.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 482ba032a58SAlex Deucher args.lvds_ss_2.ucSpreadSpectrumStep = ss->step; 483ba032a58SAlex Deucher args.lvds_ss_2.ucSpreadSpectrumDelay = ss->delay; 484ba032a58SAlex Deucher args.lvds_ss_2.ucSpreadSpectrumRange = ss->range; 485ba032a58SAlex Deucher args.lvds_ss_2.ucEnable = enable; 486ebbe1cb9SAlex Deucher } else { 4878e8e523dSAlex Deucher if ((enable == ATOM_DISABLE) || (ss->percentage == 0) || 4888e8e523dSAlex Deucher (ss->type & ATOM_EXTERNAL_SS_MASK)) { 4893fa47d9eSAlex Deucher atombios_disable_ss(rdev, pll_id); 490ba032a58SAlex Deucher return; 491ba032a58SAlex Deucher } 492ba032a58SAlex Deucher args.lvds_ss.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); 4938e8e523dSAlex Deucher args.lvds_ss.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 494ba032a58SAlex Deucher args.lvds_ss.ucSpreadSpectrumStepSize_Delay = (ss->step & 3) << 2; 495ba032a58SAlex Deucher args.lvds_ss.ucSpreadSpectrumStepSize_Delay |= (ss->delay & 7) << 4; 496ba032a58SAlex Deucher args.lvds_ss.ucEnable = enable; 497ebbe1cb9SAlex Deucher } 49826b9fc3aSAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 499ebbe1cb9SAlex Deucher } 500ebbe1cb9SAlex Deucher 5014eaeca33SAlex Deucher union adjust_pixel_clock { 5024eaeca33SAlex Deucher ADJUST_DISPLAY_PLL_PS_ALLOCATION v1; 503bcc1c2a1SAlex Deucher ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 v3; 5044eaeca33SAlex Deucher }; 5054eaeca33SAlex Deucher 5064eaeca33SAlex Deucher static u32 atombios_adjust_pll(struct drm_crtc *crtc, 5074eaeca33SAlex Deucher struct drm_display_mode *mode, 508ba032a58SAlex Deucher struct radeon_pll *pll, 509ba032a58SAlex Deucher bool ss_enabled, 510ba032a58SAlex Deucher struct radeon_atom_ss *ss) 511771fe6b9SJerome Glisse { 512771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 513771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 514771fe6b9SJerome Glisse struct drm_encoder *encoder = NULL; 515771fe6b9SJerome Glisse struct radeon_encoder *radeon_encoder = NULL; 516df271becSAlex Deucher struct drm_connector *connector = NULL; 5174eaeca33SAlex Deucher u32 adjusted_clock = mode->clock; 518bcc1c2a1SAlex Deucher int encoder_mode = 0; 519fbee67a6SAlex Deucher u32 dp_clock = mode->clock; 520fbee67a6SAlex Deucher int bpc = 8; 5219aa59993SAlex Deucher bool is_duallink = false; 522fc10332bSAlex Deucher 5234eaeca33SAlex Deucher /* reset the pll flags */ 5244eaeca33SAlex Deucher pll->flags = 0; 525771fe6b9SJerome Glisse 526771fe6b9SJerome Glisse if (ASIC_IS_AVIVO(rdev)) { 527eb1300bcSAlex Deucher if ((rdev->family == CHIP_RS600) || 528eb1300bcSAlex Deucher (rdev->family == CHIP_RS690) || 529eb1300bcSAlex Deucher (rdev->family == CHIP_RS740)) 5302ff776cfSAlex Deucher pll->flags |= (/*RADEON_PLL_USE_FRAC_FB_DIV |*/ 531eb1300bcSAlex Deucher RADEON_PLL_PREFER_CLOSEST_LOWER); 5325480f727SDave Airlie 5335480f727SDave Airlie if (ASIC_IS_DCE32(rdev) && mode->clock > 200000) /* range limits??? */ 5345480f727SDave Airlie pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; 5355480f727SDave Airlie else 5365480f727SDave Airlie pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; 5379bb09fa1SAlex Deucher 5385785e53fSAlex Deucher if (rdev->family < CHIP_RV770) 5399bb09fa1SAlex Deucher pll->flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP; 5405480f727SDave Airlie } else { 541fc10332bSAlex Deucher pll->flags |= RADEON_PLL_LEGACY; 542771fe6b9SJerome Glisse 5435480f727SDave Airlie if (mode->clock > 200000) /* range limits??? */ 5445480f727SDave Airlie pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; 5455480f727SDave Airlie else 5465480f727SDave Airlie pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; 5475480f727SDave Airlie } 5485480f727SDave Airlie 549771fe6b9SJerome Glisse list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 550771fe6b9SJerome Glisse if (encoder->crtc == crtc) { 5514eaeca33SAlex Deucher radeon_encoder = to_radeon_encoder(encoder); 552df271becSAlex Deucher connector = radeon_get_connector_for_encoder(encoder); 55306e4cd64SDave Airlie if (connector && connector->display_info.bpc) 554df271becSAlex Deucher bpc = connector->display_info.bpc; 555bcc1c2a1SAlex Deucher encoder_mode = atombios_get_encoder_mode(encoder); 5569aa59993SAlex Deucher is_duallink = radeon_dig_monitor_is_duallink(encoder, mode->clock); 557eac4dff6SAlex Deucher if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) || 5581d33e1fcSAlex Deucher (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)) { 559fbee67a6SAlex Deucher if (connector) { 560fbee67a6SAlex Deucher struct radeon_connector *radeon_connector = to_radeon_connector(connector); 561fbee67a6SAlex Deucher struct radeon_connector_atom_dig *dig_connector = 562fbee67a6SAlex Deucher radeon_connector->con_priv; 563fbee67a6SAlex Deucher 564fbee67a6SAlex Deucher dp_clock = dig_connector->dp_clock; 565fbee67a6SAlex Deucher } 566fbee67a6SAlex Deucher } 5675b40ddf8SAlex Deucher 568ba032a58SAlex Deucher /* use recommended ref_div for ss */ 569ba032a58SAlex Deucher if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 570ba032a58SAlex Deucher if (ss_enabled) { 571ba032a58SAlex Deucher if (ss->refdiv) { 572ba032a58SAlex Deucher pll->flags |= RADEON_PLL_USE_REF_DIV; 573ba032a58SAlex Deucher pll->reference_div = ss->refdiv; 5745b40ddf8SAlex Deucher if (ASIC_IS_AVIVO(rdev)) 5755b40ddf8SAlex Deucher pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV; 576ba032a58SAlex Deucher } 577ba032a58SAlex Deucher } 578ba032a58SAlex Deucher } 5795b40ddf8SAlex Deucher 5804eaeca33SAlex Deucher if (ASIC_IS_AVIVO(rdev)) { 5814eaeca33SAlex Deucher /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ 5824eaeca33SAlex Deucher if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1) 5834eaeca33SAlex Deucher adjusted_clock = mode->clock * 2; 58448dfaaebSAlex Deucher if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 585a1a4b23bSAlex Deucher pll->flags |= RADEON_PLL_PREFER_CLOSEST_LOWER; 586619efb10SAlex Deucher if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) 587619efb10SAlex Deucher pll->flags |= RADEON_PLL_IS_LCD; 5884eaeca33SAlex Deucher } else { 5894eaeca33SAlex Deucher if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) 590fc10332bSAlex Deucher pll->flags |= RADEON_PLL_NO_ODD_POST_DIV; 5914eaeca33SAlex Deucher if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) 592fc10332bSAlex Deucher pll->flags |= RADEON_PLL_USE_REF_DIV; 593771fe6b9SJerome Glisse } 5943ce0a23dSJerome Glisse break; 595771fe6b9SJerome Glisse } 596771fe6b9SJerome Glisse } 597771fe6b9SJerome Glisse 5982606c886SAlex Deucher /* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock 5992606c886SAlex Deucher * accordingly based on the encoder/transmitter to work around 6002606c886SAlex Deucher * special hw requirements. 6012606c886SAlex Deucher */ 6022606c886SAlex Deucher if (ASIC_IS_DCE3(rdev)) { 6034eaeca33SAlex Deucher union adjust_pixel_clock args; 6044eaeca33SAlex Deucher u8 frev, crev; 6054eaeca33SAlex Deucher int index; 6062606c886SAlex Deucher 6072606c886SAlex Deucher index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll); 608a084e6eeSAlex Deucher if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 609a084e6eeSAlex Deucher &crev)) 610a084e6eeSAlex Deucher return adjusted_clock; 6114eaeca33SAlex Deucher 6124eaeca33SAlex Deucher memset(&args, 0, sizeof(args)); 6134eaeca33SAlex Deucher 6144eaeca33SAlex Deucher switch (frev) { 6154eaeca33SAlex Deucher case 1: 6164eaeca33SAlex Deucher switch (crev) { 6174eaeca33SAlex Deucher case 1: 6184eaeca33SAlex Deucher case 2: 6194eaeca33SAlex Deucher args.v1.usPixelClock = cpu_to_le16(mode->clock / 10); 6204eaeca33SAlex Deucher args.v1.ucTransmitterID = radeon_encoder->encoder_id; 621bcc1c2a1SAlex Deucher args.v1.ucEncodeMode = encoder_mode; 6228e8e523dSAlex Deucher if (ss_enabled && ss->percentage) 623ba032a58SAlex Deucher args.v1.ucConfig |= 624ba032a58SAlex Deucher ADJUST_DISPLAY_CONFIG_SS_ENABLE; 6254eaeca33SAlex Deucher 6262606c886SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, 6274eaeca33SAlex Deucher index, (uint32_t *)&args); 6284eaeca33SAlex Deucher adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10; 6294eaeca33SAlex Deucher break; 630bcc1c2a1SAlex Deucher case 3: 631bcc1c2a1SAlex Deucher args.v3.sInput.usPixelClock = cpu_to_le16(mode->clock / 10); 632bcc1c2a1SAlex Deucher args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id; 633bcc1c2a1SAlex Deucher args.v3.sInput.ucEncodeMode = encoder_mode; 634bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig = 0; 6358e8e523dSAlex Deucher if (ss_enabled && ss->percentage) 636ba032a58SAlex Deucher args.v3.sInput.ucDispPllConfig |= 637ba032a58SAlex Deucher DISPPLL_CONFIG_SS_ENABLE; 638996d5c59SAlex Deucher if (ENCODER_MODE_IS_DP(encoder_mode)) { 639bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 640bcc1c2a1SAlex Deucher DISPPLL_CONFIG_COHERENT_MODE; 641fbee67a6SAlex Deucher /* 16200 or 27000 */ 642fbee67a6SAlex Deucher args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); 643b4f15f80SAlex Deucher } else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { 644b4f15f80SAlex Deucher struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 645b4f15f80SAlex Deucher if (encoder_mode == ATOM_ENCODER_MODE_HDMI) 646fbee67a6SAlex Deucher /* deep color support */ 647fbee67a6SAlex Deucher args.v3.sInput.usPixelClock = 648fbee67a6SAlex Deucher cpu_to_le16((mode->clock * bpc / 8) / 10); 649bcc1c2a1SAlex Deucher if (dig->coherent_mode) 650bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 651bcc1c2a1SAlex Deucher DISPPLL_CONFIG_COHERENT_MODE; 6529aa59993SAlex Deucher if (is_duallink) 653bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 654bcc1c2a1SAlex Deucher DISPPLL_CONFIG_DUAL_LINK; 655bcc1c2a1SAlex Deucher } 6561d33e1fcSAlex Deucher if (radeon_encoder_get_dp_bridge_encoder_id(encoder) != 6571d33e1fcSAlex Deucher ENCODER_OBJECT_ID_NONE) 6581d33e1fcSAlex Deucher args.v3.sInput.ucExtTransmitterID = 6591d33e1fcSAlex Deucher radeon_encoder_get_dp_bridge_encoder_id(encoder); 6601d33e1fcSAlex Deucher else 661cc9f67a0SAlex Deucher args.v3.sInput.ucExtTransmitterID = 0; 662cc9f67a0SAlex Deucher 663bcc1c2a1SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, 664bcc1c2a1SAlex Deucher index, (uint32_t *)&args); 665bcc1c2a1SAlex Deucher adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10; 666bcc1c2a1SAlex Deucher if (args.v3.sOutput.ucRefDiv) { 6679f4283f4SAlex Deucher pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV; 668bcc1c2a1SAlex Deucher pll->flags |= RADEON_PLL_USE_REF_DIV; 669bcc1c2a1SAlex Deucher pll->reference_div = args.v3.sOutput.ucRefDiv; 670bcc1c2a1SAlex Deucher } 671bcc1c2a1SAlex Deucher if (args.v3.sOutput.ucPostDiv) { 6729f4283f4SAlex Deucher pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV; 673bcc1c2a1SAlex Deucher pll->flags |= RADEON_PLL_USE_POST_DIV; 674bcc1c2a1SAlex Deucher pll->post_div = args.v3.sOutput.ucPostDiv; 675bcc1c2a1SAlex Deucher } 676bcc1c2a1SAlex Deucher break; 6774eaeca33SAlex Deucher default: 6784eaeca33SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 6794eaeca33SAlex Deucher return adjusted_clock; 680d56ef9c8SAlex Deucher } 6814eaeca33SAlex Deucher break; 6824eaeca33SAlex Deucher default: 6834eaeca33SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 6844eaeca33SAlex Deucher return adjusted_clock; 6854eaeca33SAlex Deucher } 6864eaeca33SAlex Deucher } 6874eaeca33SAlex Deucher return adjusted_clock; 6884eaeca33SAlex Deucher } 6894eaeca33SAlex Deucher 6904eaeca33SAlex Deucher union set_pixel_clock { 6914eaeca33SAlex Deucher SET_PIXEL_CLOCK_PS_ALLOCATION base; 6924eaeca33SAlex Deucher PIXEL_CLOCK_PARAMETERS v1; 6934eaeca33SAlex Deucher PIXEL_CLOCK_PARAMETERS_V2 v2; 6944eaeca33SAlex Deucher PIXEL_CLOCK_PARAMETERS_V3 v3; 695bcc1c2a1SAlex Deucher PIXEL_CLOCK_PARAMETERS_V5 v5; 696f82b3ddcSAlex Deucher PIXEL_CLOCK_PARAMETERS_V6 v6; 6974eaeca33SAlex Deucher }; 6984eaeca33SAlex Deucher 699f82b3ddcSAlex Deucher /* on DCE5, make sure the voltage is high enough to support the 700f82b3ddcSAlex Deucher * required disp clk. 701f82b3ddcSAlex Deucher */ 7023fa47d9eSAlex Deucher static void atombios_crtc_set_dcpll(struct radeon_device *rdev, 703f82b3ddcSAlex Deucher u32 dispclk) 704bcc1c2a1SAlex Deucher { 705bcc1c2a1SAlex Deucher u8 frev, crev; 706bcc1c2a1SAlex Deucher int index; 707bcc1c2a1SAlex Deucher union set_pixel_clock args; 708bcc1c2a1SAlex Deucher 709bcc1c2a1SAlex Deucher memset(&args, 0, sizeof(args)); 710bcc1c2a1SAlex Deucher 711bcc1c2a1SAlex Deucher index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); 712a084e6eeSAlex Deucher if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 713a084e6eeSAlex Deucher &crev)) 714a084e6eeSAlex Deucher return; 715bcc1c2a1SAlex Deucher 716bcc1c2a1SAlex Deucher switch (frev) { 717bcc1c2a1SAlex Deucher case 1: 718bcc1c2a1SAlex Deucher switch (crev) { 719bcc1c2a1SAlex Deucher case 5: 720bcc1c2a1SAlex Deucher /* if the default dcpll clock is specified, 721bcc1c2a1SAlex Deucher * SetPixelClock provides the dividers 722bcc1c2a1SAlex Deucher */ 723bcc1c2a1SAlex Deucher args.v5.ucCRTC = ATOM_CRTC_INVALID; 7244589433cSCédric Cano args.v5.usPixelClock = cpu_to_le16(dispclk); 725bcc1c2a1SAlex Deucher args.v5.ucPpll = ATOM_DCPLL; 726bcc1c2a1SAlex Deucher break; 727f82b3ddcSAlex Deucher case 6: 728f82b3ddcSAlex Deucher /* if the default dcpll clock is specified, 729f82b3ddcSAlex Deucher * SetPixelClock provides the dividers 730f82b3ddcSAlex Deucher */ 731265aa6c8SAlex Deucher args.v6.ulDispEngClkFreq = cpu_to_le32(dispclk); 732f82b3ddcSAlex Deucher args.v6.ucPpll = ATOM_DCPLL; 733f82b3ddcSAlex Deucher break; 734bcc1c2a1SAlex Deucher default: 735bcc1c2a1SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 736bcc1c2a1SAlex Deucher return; 737bcc1c2a1SAlex Deucher } 738bcc1c2a1SAlex Deucher break; 739bcc1c2a1SAlex Deucher default: 740bcc1c2a1SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 741bcc1c2a1SAlex Deucher return; 742bcc1c2a1SAlex Deucher } 743bcc1c2a1SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 744bcc1c2a1SAlex Deucher } 745bcc1c2a1SAlex Deucher 74637f9003bSAlex Deucher static void atombios_crtc_program_pll(struct drm_crtc *crtc, 747f1bece7fSBenjamin Herrenschmidt u32 crtc_id, 74837f9003bSAlex Deucher int pll_id, 74937f9003bSAlex Deucher u32 encoder_mode, 75037f9003bSAlex Deucher u32 encoder_id, 75137f9003bSAlex Deucher u32 clock, 75237f9003bSAlex Deucher u32 ref_div, 75337f9003bSAlex Deucher u32 fb_div, 75437f9003bSAlex Deucher u32 frac_fb_div, 755df271becSAlex Deucher u32 post_div, 7568e8e523dSAlex Deucher int bpc, 7578e8e523dSAlex Deucher bool ss_enabled, 7588e8e523dSAlex Deucher struct radeon_atom_ss *ss) 75937f9003bSAlex Deucher { 76037f9003bSAlex Deucher struct drm_device *dev = crtc->dev; 76137f9003bSAlex Deucher struct radeon_device *rdev = dev->dev_private; 76237f9003bSAlex Deucher u8 frev, crev; 76337f9003bSAlex Deucher int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); 76437f9003bSAlex Deucher union set_pixel_clock args; 76537f9003bSAlex Deucher 76637f9003bSAlex Deucher memset(&args, 0, sizeof(args)); 76737f9003bSAlex Deucher 76837f9003bSAlex Deucher if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 76937f9003bSAlex Deucher &crev)) 77037f9003bSAlex Deucher return; 77137f9003bSAlex Deucher 77237f9003bSAlex Deucher switch (frev) { 77337f9003bSAlex Deucher case 1: 77437f9003bSAlex Deucher switch (crev) { 77537f9003bSAlex Deucher case 1: 77637f9003bSAlex Deucher if (clock == ATOM_DISABLE) 77737f9003bSAlex Deucher return; 77837f9003bSAlex Deucher args.v1.usPixelClock = cpu_to_le16(clock / 10); 77937f9003bSAlex Deucher args.v1.usRefDiv = cpu_to_le16(ref_div); 78037f9003bSAlex Deucher args.v1.usFbDiv = cpu_to_le16(fb_div); 78137f9003bSAlex Deucher args.v1.ucFracFbDiv = frac_fb_div; 78237f9003bSAlex Deucher args.v1.ucPostDiv = post_div; 78337f9003bSAlex Deucher args.v1.ucPpll = pll_id; 78437f9003bSAlex Deucher args.v1.ucCRTC = crtc_id; 78537f9003bSAlex Deucher args.v1.ucRefDivSrc = 1; 78637f9003bSAlex Deucher break; 78737f9003bSAlex Deucher case 2: 78837f9003bSAlex Deucher args.v2.usPixelClock = cpu_to_le16(clock / 10); 78937f9003bSAlex Deucher args.v2.usRefDiv = cpu_to_le16(ref_div); 79037f9003bSAlex Deucher args.v2.usFbDiv = cpu_to_le16(fb_div); 79137f9003bSAlex Deucher args.v2.ucFracFbDiv = frac_fb_div; 79237f9003bSAlex Deucher args.v2.ucPostDiv = post_div; 79337f9003bSAlex Deucher args.v2.ucPpll = pll_id; 79437f9003bSAlex Deucher args.v2.ucCRTC = crtc_id; 79537f9003bSAlex Deucher args.v2.ucRefDivSrc = 1; 79637f9003bSAlex Deucher break; 79737f9003bSAlex Deucher case 3: 79837f9003bSAlex Deucher args.v3.usPixelClock = cpu_to_le16(clock / 10); 79937f9003bSAlex Deucher args.v3.usRefDiv = cpu_to_le16(ref_div); 80037f9003bSAlex Deucher args.v3.usFbDiv = cpu_to_le16(fb_div); 80137f9003bSAlex Deucher args.v3.ucFracFbDiv = frac_fb_div; 80237f9003bSAlex Deucher args.v3.ucPostDiv = post_div; 80337f9003bSAlex Deucher args.v3.ucPpll = pll_id; 80437f9003bSAlex Deucher args.v3.ucMiscInfo = (pll_id << 2); 8056f15c506SAlex Deucher if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) 8066f15c506SAlex Deucher args.v3.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC; 80737f9003bSAlex Deucher args.v3.ucTransmitterId = encoder_id; 80837f9003bSAlex Deucher args.v3.ucEncoderMode = encoder_mode; 80937f9003bSAlex Deucher break; 81037f9003bSAlex Deucher case 5: 81137f9003bSAlex Deucher args.v5.ucCRTC = crtc_id; 81237f9003bSAlex Deucher args.v5.usPixelClock = cpu_to_le16(clock / 10); 81337f9003bSAlex Deucher args.v5.ucRefDiv = ref_div; 81437f9003bSAlex Deucher args.v5.usFbDiv = cpu_to_le16(fb_div); 81537f9003bSAlex Deucher args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); 81637f9003bSAlex Deucher args.v5.ucPostDiv = post_div; 81737f9003bSAlex Deucher args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */ 8188e8e523dSAlex Deucher if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) 8198e8e523dSAlex Deucher args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_REF_DIV_SRC; 820df271becSAlex Deucher switch (bpc) { 821df271becSAlex Deucher case 8: 822df271becSAlex Deucher default: 823df271becSAlex Deucher args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP; 824df271becSAlex Deucher break; 825df271becSAlex Deucher case 10: 826df271becSAlex Deucher args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP; 827df271becSAlex Deucher break; 828df271becSAlex Deucher } 82937f9003bSAlex Deucher args.v5.ucTransmitterID = encoder_id; 83037f9003bSAlex Deucher args.v5.ucEncoderMode = encoder_mode; 83137f9003bSAlex Deucher args.v5.ucPpll = pll_id; 83237f9003bSAlex Deucher break; 833f82b3ddcSAlex Deucher case 6: 834f1bece7fSBenjamin Herrenschmidt args.v6.ulDispEngClkFreq = cpu_to_le32(crtc_id << 24 | clock / 10); 835f82b3ddcSAlex Deucher args.v6.ucRefDiv = ref_div; 836f82b3ddcSAlex Deucher args.v6.usFbDiv = cpu_to_le16(fb_div); 837f82b3ddcSAlex Deucher args.v6.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); 838f82b3ddcSAlex Deucher args.v6.ucPostDiv = post_div; 839f82b3ddcSAlex Deucher args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */ 8408e8e523dSAlex Deucher if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) 8418e8e523dSAlex Deucher args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_REF_DIV_SRC; 842df271becSAlex Deucher switch (bpc) { 843df271becSAlex Deucher case 8: 844df271becSAlex Deucher default: 845df271becSAlex Deucher args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP; 846df271becSAlex Deucher break; 847df271becSAlex Deucher case 10: 848df271becSAlex Deucher args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP; 849df271becSAlex Deucher break; 850df271becSAlex Deucher case 12: 851df271becSAlex Deucher args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP; 852df271becSAlex Deucher break; 853df271becSAlex Deucher case 16: 854df271becSAlex Deucher args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP; 855df271becSAlex Deucher break; 856df271becSAlex Deucher } 857f82b3ddcSAlex Deucher args.v6.ucTransmitterID = encoder_id; 858f82b3ddcSAlex Deucher args.v6.ucEncoderMode = encoder_mode; 859f82b3ddcSAlex Deucher args.v6.ucPpll = pll_id; 860f82b3ddcSAlex Deucher break; 86137f9003bSAlex Deucher default: 86237f9003bSAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 86337f9003bSAlex Deucher return; 86437f9003bSAlex Deucher } 86537f9003bSAlex Deucher break; 86637f9003bSAlex Deucher default: 86737f9003bSAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 86837f9003bSAlex Deucher return; 86937f9003bSAlex Deucher } 87037f9003bSAlex Deucher 87137f9003bSAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 87237f9003bSAlex Deucher } 87337f9003bSAlex Deucher 874bcc1c2a1SAlex Deucher static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) 8754eaeca33SAlex Deucher { 8764eaeca33SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 8774eaeca33SAlex Deucher struct drm_device *dev = crtc->dev; 8784eaeca33SAlex Deucher struct radeon_device *rdev = dev->dev_private; 8794eaeca33SAlex Deucher struct drm_encoder *encoder = NULL; 8804eaeca33SAlex Deucher struct radeon_encoder *radeon_encoder = NULL; 8814eaeca33SAlex Deucher u32 pll_clock = mode->clock; 8824eaeca33SAlex Deucher u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; 8834eaeca33SAlex Deucher struct radeon_pll *pll; 8844eaeca33SAlex Deucher u32 adjusted_clock; 885bcc1c2a1SAlex Deucher int encoder_mode = 0; 886ba032a58SAlex Deucher struct radeon_atom_ss ss; 887ba032a58SAlex Deucher bool ss_enabled = false; 888df271becSAlex Deucher int bpc = 8; 8894eaeca33SAlex Deucher 8904eaeca33SAlex Deucher list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 8914eaeca33SAlex Deucher if (encoder->crtc == crtc) { 8924eaeca33SAlex Deucher radeon_encoder = to_radeon_encoder(encoder); 893bcc1c2a1SAlex Deucher encoder_mode = atombios_get_encoder_mode(encoder); 8944eaeca33SAlex Deucher break; 8954eaeca33SAlex Deucher } 8964eaeca33SAlex Deucher } 8974eaeca33SAlex Deucher 8984eaeca33SAlex Deucher if (!radeon_encoder) 8994eaeca33SAlex Deucher return; 9004eaeca33SAlex Deucher 901bcc1c2a1SAlex Deucher switch (radeon_crtc->pll_id) { 902bcc1c2a1SAlex Deucher case ATOM_PPLL1: 9034eaeca33SAlex Deucher pll = &rdev->clock.p1pll; 904bcc1c2a1SAlex Deucher break; 905bcc1c2a1SAlex Deucher case ATOM_PPLL2: 9064eaeca33SAlex Deucher pll = &rdev->clock.p2pll; 907bcc1c2a1SAlex Deucher break; 908bcc1c2a1SAlex Deucher case ATOM_DCPLL: 909bcc1c2a1SAlex Deucher case ATOM_PPLL_INVALID: 910921d98b5SStefan Richter default: 911bcc1c2a1SAlex Deucher pll = &rdev->clock.dcpll; 912bcc1c2a1SAlex Deucher break; 913bcc1c2a1SAlex Deucher } 9144eaeca33SAlex Deucher 915ba032a58SAlex Deucher if (radeon_encoder->active_device & 916ba032a58SAlex Deucher (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) { 917ba032a58SAlex Deucher struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 918ba032a58SAlex Deucher struct drm_connector *connector = 919ba032a58SAlex Deucher radeon_get_connector_for_encoder(encoder); 920ba032a58SAlex Deucher struct radeon_connector *radeon_connector = 921ba032a58SAlex Deucher to_radeon_connector(connector); 922ba032a58SAlex Deucher struct radeon_connector_atom_dig *dig_connector = 923ba032a58SAlex Deucher radeon_connector->con_priv; 924ba032a58SAlex Deucher int dp_clock; 925df271becSAlex Deucher bpc = connector->display_info.bpc; 926ba032a58SAlex Deucher 927ba032a58SAlex Deucher switch (encoder_mode) { 928996d5c59SAlex Deucher case ATOM_ENCODER_MODE_DP_MST: 929ba032a58SAlex Deucher case ATOM_ENCODER_MODE_DP: 930ba032a58SAlex Deucher /* DP/eDP */ 931ba032a58SAlex Deucher dp_clock = dig_connector->dp_clock / 10; 932ba032a58SAlex Deucher if (ASIC_IS_DCE4(rdev)) 933ba032a58SAlex Deucher ss_enabled = 934ba032a58SAlex Deucher radeon_atombios_get_asic_ss_info(rdev, &ss, 935ba032a58SAlex Deucher ASIC_INTERNAL_SS_ON_DP, 936ba032a58SAlex Deucher dp_clock); 937ba032a58SAlex Deucher else { 938ba032a58SAlex Deucher if (dp_clock == 16200) { 939ba032a58SAlex Deucher ss_enabled = 940ba032a58SAlex Deucher radeon_atombios_get_ppll_ss_info(rdev, &ss, 941ba032a58SAlex Deucher ATOM_DP_SS_ID2); 942ba032a58SAlex Deucher if (!ss_enabled) 943ba032a58SAlex Deucher ss_enabled = 944ba032a58SAlex Deucher radeon_atombios_get_ppll_ss_info(rdev, &ss, 945ba032a58SAlex Deucher ATOM_DP_SS_ID1); 946ba032a58SAlex Deucher } else 947ba032a58SAlex Deucher ss_enabled = 948ba032a58SAlex Deucher radeon_atombios_get_ppll_ss_info(rdev, &ss, 949ba032a58SAlex Deucher ATOM_DP_SS_ID1); 950ba032a58SAlex Deucher } 951ba032a58SAlex Deucher break; 952ba032a58SAlex Deucher case ATOM_ENCODER_MODE_LVDS: 953ba032a58SAlex Deucher if (ASIC_IS_DCE4(rdev)) 954ba032a58SAlex Deucher ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &ss, 955ba032a58SAlex Deucher dig->lcd_ss_id, 956ba032a58SAlex Deucher mode->clock / 10); 957ba032a58SAlex Deucher else 958ba032a58SAlex Deucher ss_enabled = radeon_atombios_get_ppll_ss_info(rdev, &ss, 959ba032a58SAlex Deucher dig->lcd_ss_id); 960ba032a58SAlex Deucher break; 961ba032a58SAlex Deucher case ATOM_ENCODER_MODE_DVI: 962ba032a58SAlex Deucher if (ASIC_IS_DCE4(rdev)) 963ba032a58SAlex Deucher ss_enabled = 964ba032a58SAlex Deucher radeon_atombios_get_asic_ss_info(rdev, &ss, 965ba032a58SAlex Deucher ASIC_INTERNAL_SS_ON_TMDS, 966ba032a58SAlex Deucher mode->clock / 10); 967ba032a58SAlex Deucher break; 968ba032a58SAlex Deucher case ATOM_ENCODER_MODE_HDMI: 969ba032a58SAlex Deucher if (ASIC_IS_DCE4(rdev)) 970ba032a58SAlex Deucher ss_enabled = 971ba032a58SAlex Deucher radeon_atombios_get_asic_ss_info(rdev, &ss, 972ba032a58SAlex Deucher ASIC_INTERNAL_SS_ON_HDMI, 973ba032a58SAlex Deucher mode->clock / 10); 974ba032a58SAlex Deucher break; 975ba032a58SAlex Deucher default: 976ba032a58SAlex Deucher break; 977ba032a58SAlex Deucher } 978ba032a58SAlex Deucher } 979ba032a58SAlex Deucher 9804eaeca33SAlex Deucher /* adjust pixel clock as needed */ 981ba032a58SAlex Deucher adjusted_clock = atombios_adjust_pll(crtc, mode, pll, ss_enabled, &ss); 9822606c886SAlex Deucher 98364146f8bSAlex Deucher if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 98464146f8bSAlex Deucher /* TV seems to prefer the legacy algo on some boards */ 98564146f8bSAlex Deucher radeon_compute_pll_legacy(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, 98664146f8bSAlex Deucher &ref_div, &post_div); 98764146f8bSAlex Deucher else if (ASIC_IS_AVIVO(rdev)) 988619efb10SAlex Deucher radeon_compute_pll_avivo(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, 989619efb10SAlex Deucher &ref_div, &post_div); 990619efb10SAlex Deucher else 991f523f74eSAlex Deucher radeon_compute_pll_legacy(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, 992fc10332bSAlex Deucher &ref_div, &post_div); 993771fe6b9SJerome Glisse 9943fa47d9eSAlex Deucher atombios_crtc_program_ss(rdev, ATOM_DISABLE, radeon_crtc->pll_id, &ss); 995ba032a58SAlex Deucher 99637f9003bSAlex Deucher atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, 99737f9003bSAlex Deucher encoder_mode, radeon_encoder->encoder_id, mode->clock, 9988e8e523dSAlex Deucher ref_div, fb_div, frac_fb_div, post_div, bpc, ss_enabled, &ss); 999771fe6b9SJerome Glisse 1000ba032a58SAlex Deucher if (ss_enabled) { 1001ba032a58SAlex Deucher /* calculate ss amount and step size */ 1002ba032a58SAlex Deucher if (ASIC_IS_DCE4(rdev)) { 1003ba032a58SAlex Deucher u32 step_size; 1004ba032a58SAlex Deucher u32 amount = (((fb_div * 10) + frac_fb_div) * ss.percentage) / 10000; 1005ba032a58SAlex Deucher ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK; 10068e8e523dSAlex Deucher ss.amount |= ((amount - (amount / 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) & 1007ba032a58SAlex Deucher ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK; 1008ba032a58SAlex Deucher if (ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD) 1009ba032a58SAlex Deucher step_size = (4 * amount * ref_div * (ss.rate * 2048)) / 1010ba032a58SAlex Deucher (125 * 25 * pll->reference_freq / 100); 1011ba032a58SAlex Deucher else 1012ba032a58SAlex Deucher step_size = (2 * amount * ref_div * (ss.rate * 2048)) / 1013ba032a58SAlex Deucher (125 * 25 * pll->reference_freq / 100); 1014ba032a58SAlex Deucher ss.step = step_size; 1015ba032a58SAlex Deucher } 1016ba032a58SAlex Deucher 10173fa47d9eSAlex Deucher atombios_crtc_program_ss(rdev, ATOM_ENABLE, radeon_crtc->pll_id, &ss); 1018ba032a58SAlex Deucher } 1019771fe6b9SJerome Glisse } 1020771fe6b9SJerome Glisse 1021c9417bddSAlex Deucher static int dce4_crtc_do_set_base(struct drm_crtc *crtc, 10224dd19b0dSChris Ball struct drm_framebuffer *fb, 10234dd19b0dSChris Ball int x, int y, int atomic) 1024bcc1c2a1SAlex Deucher { 1025bcc1c2a1SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1026bcc1c2a1SAlex Deucher struct drm_device *dev = crtc->dev; 1027bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 1028bcc1c2a1SAlex Deucher struct radeon_framebuffer *radeon_fb; 10294dd19b0dSChris Ball struct drm_framebuffer *target_fb; 1030bcc1c2a1SAlex Deucher struct drm_gem_object *obj; 1031bcc1c2a1SAlex Deucher struct radeon_bo *rbo; 1032bcc1c2a1SAlex Deucher uint64_t fb_location; 1033bcc1c2a1SAlex Deucher uint32_t fb_format, fb_pitch_pixels, tiling_flags; 1034fa6bee46SAlex Deucher u32 fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE); 1035adcfde51SAlex Deucher u32 tmp, viewport_w, viewport_h; 1036bcc1c2a1SAlex Deucher int r; 1037bcc1c2a1SAlex Deucher 1038bcc1c2a1SAlex Deucher /* no fb bound */ 10394dd19b0dSChris Ball if (!atomic && !crtc->fb) { 1040d9fdaafbSDave Airlie DRM_DEBUG_KMS("No FB bound\n"); 1041bcc1c2a1SAlex Deucher return 0; 1042bcc1c2a1SAlex Deucher } 1043bcc1c2a1SAlex Deucher 10444dd19b0dSChris Ball if (atomic) { 10454dd19b0dSChris Ball radeon_fb = to_radeon_framebuffer(fb); 10464dd19b0dSChris Ball target_fb = fb; 10474dd19b0dSChris Ball } 10484dd19b0dSChris Ball else { 1049bcc1c2a1SAlex Deucher radeon_fb = to_radeon_framebuffer(crtc->fb); 10504dd19b0dSChris Ball target_fb = crtc->fb; 10514dd19b0dSChris Ball } 1052bcc1c2a1SAlex Deucher 10534dd19b0dSChris Ball /* If atomic, assume fb object is pinned & idle & fenced and 10544dd19b0dSChris Ball * just update base pointers 10554dd19b0dSChris Ball */ 1056bcc1c2a1SAlex Deucher obj = radeon_fb->obj; 10577e4d15d9SDaniel Vetter rbo = gem_to_radeon_bo(obj); 1058bcc1c2a1SAlex Deucher r = radeon_bo_reserve(rbo, false); 1059bcc1c2a1SAlex Deucher if (unlikely(r != 0)) 1060bcc1c2a1SAlex Deucher return r; 10614dd19b0dSChris Ball 10624dd19b0dSChris Ball if (atomic) 10634dd19b0dSChris Ball fb_location = radeon_bo_gpu_offset(rbo); 10644dd19b0dSChris Ball else { 1065bcc1c2a1SAlex Deucher r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); 1066bcc1c2a1SAlex Deucher if (unlikely(r != 0)) { 1067bcc1c2a1SAlex Deucher radeon_bo_unreserve(rbo); 1068bcc1c2a1SAlex Deucher return -EINVAL; 1069bcc1c2a1SAlex Deucher } 10704dd19b0dSChris Ball } 10714dd19b0dSChris Ball 1072bcc1c2a1SAlex Deucher radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); 1073bcc1c2a1SAlex Deucher radeon_bo_unreserve(rbo); 1074bcc1c2a1SAlex Deucher 10754dd19b0dSChris Ball switch (target_fb->bits_per_pixel) { 1076bcc1c2a1SAlex Deucher case 8: 1077bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP) | 1078bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED)); 1079bcc1c2a1SAlex Deucher break; 1080bcc1c2a1SAlex Deucher case 15: 1081bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 1082bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB1555)); 1083bcc1c2a1SAlex Deucher break; 1084bcc1c2a1SAlex Deucher case 16: 1085bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 1086bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565)); 1087fa6bee46SAlex Deucher #ifdef __BIG_ENDIAN 1088fa6bee46SAlex Deucher fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16); 1089fa6bee46SAlex Deucher #endif 1090bcc1c2a1SAlex Deucher break; 1091bcc1c2a1SAlex Deucher case 24: 1092bcc1c2a1SAlex Deucher case 32: 1093bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) | 1094bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888)); 1095fa6bee46SAlex Deucher #ifdef __BIG_ENDIAN 1096fa6bee46SAlex Deucher fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32); 1097fa6bee46SAlex Deucher #endif 1098bcc1c2a1SAlex Deucher break; 1099bcc1c2a1SAlex Deucher default: 1100bcc1c2a1SAlex Deucher DRM_ERROR("Unsupported screen depth %d\n", 11014dd19b0dSChris Ball target_fb->bits_per_pixel); 1102bcc1c2a1SAlex Deucher return -EINVAL; 1103bcc1c2a1SAlex Deucher } 1104bcc1c2a1SAlex Deucher 1105392e3722SAlex Deucher if (tiling_flags & RADEON_TILING_MACRO) { 1106392e3722SAlex Deucher if (rdev->family >= CHIP_CAYMAN) 1107392e3722SAlex Deucher tmp = rdev->config.cayman.tile_config; 1108392e3722SAlex Deucher else 1109392e3722SAlex Deucher tmp = rdev->config.evergreen.tile_config; 1110392e3722SAlex Deucher 1111392e3722SAlex Deucher switch ((tmp & 0xf0) >> 4) { 1112392e3722SAlex Deucher case 0: /* 4 banks */ 1113392e3722SAlex Deucher fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_4_BANK); 1114392e3722SAlex Deucher break; 1115392e3722SAlex Deucher case 1: /* 8 banks */ 1116392e3722SAlex Deucher default: 1117392e3722SAlex Deucher fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_8_BANK); 1118392e3722SAlex Deucher break; 1119392e3722SAlex Deucher case 2: /* 16 banks */ 1120392e3722SAlex Deucher fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_16_BANK); 1121392e3722SAlex Deucher break; 1122392e3722SAlex Deucher } 1123392e3722SAlex Deucher 1124392e3722SAlex Deucher switch ((tmp & 0xf000) >> 12) { 1125392e3722SAlex Deucher case 0: /* 1KB rows */ 1126392e3722SAlex Deucher default: 1127392e3722SAlex Deucher fb_format |= EVERGREEN_GRPH_TILE_SPLIT(EVERGREEN_ADDR_SURF_TILE_SPLIT_1KB); 1128392e3722SAlex Deucher break; 1129392e3722SAlex Deucher case 1: /* 2KB rows */ 1130392e3722SAlex Deucher fb_format |= EVERGREEN_GRPH_TILE_SPLIT(EVERGREEN_ADDR_SURF_TILE_SPLIT_2KB); 1131392e3722SAlex Deucher break; 1132392e3722SAlex Deucher case 2: /* 4KB rows */ 1133392e3722SAlex Deucher fb_format |= EVERGREEN_GRPH_TILE_SPLIT(EVERGREEN_ADDR_SURF_TILE_SPLIT_4KB); 1134392e3722SAlex Deucher break; 1135392e3722SAlex Deucher } 1136392e3722SAlex Deucher 113797d66328SAlex Deucher fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1); 1138392e3722SAlex Deucher } else if (tiling_flags & RADEON_TILING_MICRO) 113997d66328SAlex Deucher fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1); 114097d66328SAlex Deucher 1141bcc1c2a1SAlex Deucher switch (radeon_crtc->crtc_id) { 1142bcc1c2a1SAlex Deucher case 0: 1143bcc1c2a1SAlex Deucher WREG32(AVIVO_D1VGA_CONTROL, 0); 1144bcc1c2a1SAlex Deucher break; 1145bcc1c2a1SAlex Deucher case 1: 1146bcc1c2a1SAlex Deucher WREG32(AVIVO_D2VGA_CONTROL, 0); 1147bcc1c2a1SAlex Deucher break; 1148bcc1c2a1SAlex Deucher case 2: 1149bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D3VGA_CONTROL, 0); 1150bcc1c2a1SAlex Deucher break; 1151bcc1c2a1SAlex Deucher case 3: 1152bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D4VGA_CONTROL, 0); 1153bcc1c2a1SAlex Deucher break; 1154bcc1c2a1SAlex Deucher case 4: 1155bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D5VGA_CONTROL, 0); 1156bcc1c2a1SAlex Deucher break; 1157bcc1c2a1SAlex Deucher case 5: 1158bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D6VGA_CONTROL, 0); 1159bcc1c2a1SAlex Deucher break; 1160bcc1c2a1SAlex Deucher default: 1161bcc1c2a1SAlex Deucher break; 1162bcc1c2a1SAlex Deucher } 1163bcc1c2a1SAlex Deucher 1164bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 1165bcc1c2a1SAlex Deucher upper_32_bits(fb_location)); 1166bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 1167bcc1c2a1SAlex Deucher upper_32_bits(fb_location)); 1168bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 1169bcc1c2a1SAlex Deucher (u32)fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK); 1170bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 1171bcc1c2a1SAlex Deucher (u32) fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK); 1172bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); 1173fa6bee46SAlex Deucher WREG32(EVERGREEN_GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap); 1174bcc1c2a1SAlex Deucher 1175bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); 1176bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); 1177bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_X_START + radeon_crtc->crtc_offset, 0); 1178bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_Y_START + radeon_crtc->crtc_offset, 0); 11794dd19b0dSChris Ball WREG32(EVERGREEN_GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width); 11804dd19b0dSChris Ball WREG32(EVERGREEN_GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height); 1181bcc1c2a1SAlex Deucher 118201f2c773SVille Syrjälä fb_pitch_pixels = target_fb->pitches[0] / (target_fb->bits_per_pixel / 8); 1183bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); 1184bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1); 1185bcc1c2a1SAlex Deucher 1186bcc1c2a1SAlex Deucher WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, 1187bcc1c2a1SAlex Deucher crtc->mode.vdisplay); 1188bcc1c2a1SAlex Deucher x &= ~3; 1189bcc1c2a1SAlex Deucher y &= ~1; 1190bcc1c2a1SAlex Deucher WREG32(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset, 1191bcc1c2a1SAlex Deucher (x << 16) | y); 1192adcfde51SAlex Deucher viewport_w = crtc->mode.hdisplay; 1193adcfde51SAlex Deucher viewport_h = (crtc->mode.vdisplay + 1) & ~1; 1194bcc1c2a1SAlex Deucher WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset, 1195adcfde51SAlex Deucher (viewport_w << 16) | viewport_h); 1196bcc1c2a1SAlex Deucher 1197fb9674bdSAlex Deucher /* pageflip setup */ 1198fb9674bdSAlex Deucher /* make sure flip is at vb rather than hb */ 1199fb9674bdSAlex Deucher tmp = RREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset); 1200fb9674bdSAlex Deucher tmp &= ~EVERGREEN_GRPH_SURFACE_UPDATE_H_RETRACE_EN; 1201fb9674bdSAlex Deucher WREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, tmp); 1202fb9674bdSAlex Deucher 1203fb9674bdSAlex Deucher /* set pageflip to happen anywhere in vblank interval */ 1204fb9674bdSAlex Deucher WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); 1205fb9674bdSAlex Deucher 12064dd19b0dSChris Ball if (!atomic && fb && fb != crtc->fb) { 12074dd19b0dSChris Ball radeon_fb = to_radeon_framebuffer(fb); 12087e4d15d9SDaniel Vetter rbo = gem_to_radeon_bo(radeon_fb->obj); 1209bcc1c2a1SAlex Deucher r = radeon_bo_reserve(rbo, false); 1210bcc1c2a1SAlex Deucher if (unlikely(r != 0)) 1211bcc1c2a1SAlex Deucher return r; 1212bcc1c2a1SAlex Deucher radeon_bo_unpin(rbo); 1213bcc1c2a1SAlex Deucher radeon_bo_unreserve(rbo); 1214bcc1c2a1SAlex Deucher } 1215bcc1c2a1SAlex Deucher 1216bcc1c2a1SAlex Deucher /* Bytes per pixel may have changed */ 1217bcc1c2a1SAlex Deucher radeon_bandwidth_update(rdev); 1218bcc1c2a1SAlex Deucher 1219bcc1c2a1SAlex Deucher return 0; 1220bcc1c2a1SAlex Deucher } 1221bcc1c2a1SAlex Deucher 12224dd19b0dSChris Ball static int avivo_crtc_do_set_base(struct drm_crtc *crtc, 12234dd19b0dSChris Ball struct drm_framebuffer *fb, 12244dd19b0dSChris Ball int x, int y, int atomic) 1225771fe6b9SJerome Glisse { 1226771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1227771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 1228771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 1229771fe6b9SJerome Glisse struct radeon_framebuffer *radeon_fb; 1230771fe6b9SJerome Glisse struct drm_gem_object *obj; 12314c788679SJerome Glisse struct radeon_bo *rbo; 12324dd19b0dSChris Ball struct drm_framebuffer *target_fb; 1233771fe6b9SJerome Glisse uint64_t fb_location; 1234e024e110SDave Airlie uint32_t fb_format, fb_pitch_pixels, tiling_flags; 1235fa6bee46SAlex Deucher u32 fb_swap = R600_D1GRPH_SWAP_ENDIAN_NONE; 1236adcfde51SAlex Deucher u32 tmp, viewport_w, viewport_h; 12374c788679SJerome Glisse int r; 1238771fe6b9SJerome Glisse 12392de3b484SJerome Glisse /* no fb bound */ 12404dd19b0dSChris Ball if (!atomic && !crtc->fb) { 1241d9fdaafbSDave Airlie DRM_DEBUG_KMS("No FB bound\n"); 12422de3b484SJerome Glisse return 0; 12432de3b484SJerome Glisse } 1244771fe6b9SJerome Glisse 12454dd19b0dSChris Ball if (atomic) { 12464dd19b0dSChris Ball radeon_fb = to_radeon_framebuffer(fb); 12474dd19b0dSChris Ball target_fb = fb; 12484dd19b0dSChris Ball } 12494dd19b0dSChris Ball else { 1250771fe6b9SJerome Glisse radeon_fb = to_radeon_framebuffer(crtc->fb); 12514dd19b0dSChris Ball target_fb = crtc->fb; 12524dd19b0dSChris Ball } 1253771fe6b9SJerome Glisse 1254771fe6b9SJerome Glisse obj = radeon_fb->obj; 12557e4d15d9SDaniel Vetter rbo = gem_to_radeon_bo(obj); 12564c788679SJerome Glisse r = radeon_bo_reserve(rbo, false); 12574c788679SJerome Glisse if (unlikely(r != 0)) 12584c788679SJerome Glisse return r; 12594dd19b0dSChris Ball 12604dd19b0dSChris Ball /* If atomic, assume fb object is pinned & idle & fenced and 12614dd19b0dSChris Ball * just update base pointers 12624dd19b0dSChris Ball */ 12634dd19b0dSChris Ball if (atomic) 12644dd19b0dSChris Ball fb_location = radeon_bo_gpu_offset(rbo); 12654dd19b0dSChris Ball else { 12664c788679SJerome Glisse r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); 12674c788679SJerome Glisse if (unlikely(r != 0)) { 12684c788679SJerome Glisse radeon_bo_unreserve(rbo); 1269771fe6b9SJerome Glisse return -EINVAL; 1270771fe6b9SJerome Glisse } 12714dd19b0dSChris Ball } 12724c788679SJerome Glisse radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); 12734c788679SJerome Glisse radeon_bo_unreserve(rbo); 1274771fe6b9SJerome Glisse 12754dd19b0dSChris Ball switch (target_fb->bits_per_pixel) { 127641456df2SDave Airlie case 8: 127741456df2SDave Airlie fb_format = 127841456df2SDave Airlie AVIVO_D1GRPH_CONTROL_DEPTH_8BPP | 127941456df2SDave Airlie AVIVO_D1GRPH_CONTROL_8BPP_INDEXED; 128041456df2SDave Airlie break; 1281771fe6b9SJerome Glisse case 15: 1282771fe6b9SJerome Glisse fb_format = 1283771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | 1284771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555; 1285771fe6b9SJerome Glisse break; 1286771fe6b9SJerome Glisse case 16: 1287771fe6b9SJerome Glisse fb_format = 1288771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | 1289771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_16BPP_RGB565; 1290fa6bee46SAlex Deucher #ifdef __BIG_ENDIAN 1291fa6bee46SAlex Deucher fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT; 1292fa6bee46SAlex Deucher #endif 1293771fe6b9SJerome Glisse break; 1294771fe6b9SJerome Glisse case 24: 1295771fe6b9SJerome Glisse case 32: 1296771fe6b9SJerome Glisse fb_format = 1297771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_32BPP | 1298771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888; 1299fa6bee46SAlex Deucher #ifdef __BIG_ENDIAN 1300fa6bee46SAlex Deucher fb_swap = R600_D1GRPH_SWAP_ENDIAN_32BIT; 1301fa6bee46SAlex Deucher #endif 1302771fe6b9SJerome Glisse break; 1303771fe6b9SJerome Glisse default: 1304771fe6b9SJerome Glisse DRM_ERROR("Unsupported screen depth %d\n", 13054dd19b0dSChris Ball target_fb->bits_per_pixel); 1306771fe6b9SJerome Glisse return -EINVAL; 1307771fe6b9SJerome Glisse } 1308771fe6b9SJerome Glisse 130940c4ac1cSAlex Deucher if (rdev->family >= CHIP_R600) { 131040c4ac1cSAlex Deucher if (tiling_flags & RADEON_TILING_MACRO) 131140c4ac1cSAlex Deucher fb_format |= R600_D1GRPH_ARRAY_MODE_2D_TILED_THIN1; 131240c4ac1cSAlex Deucher else if (tiling_flags & RADEON_TILING_MICRO) 131340c4ac1cSAlex Deucher fb_format |= R600_D1GRPH_ARRAY_MODE_1D_TILED_THIN1; 131440c4ac1cSAlex Deucher } else { 1315cf2f05d3SDave Airlie if (tiling_flags & RADEON_TILING_MACRO) 1316cf2f05d3SDave Airlie fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE; 1317cf2f05d3SDave Airlie 1318e024e110SDave Airlie if (tiling_flags & RADEON_TILING_MICRO) 1319e024e110SDave Airlie fb_format |= AVIVO_D1GRPH_TILED; 132040c4ac1cSAlex Deucher } 1321e024e110SDave Airlie 1322771fe6b9SJerome Glisse if (radeon_crtc->crtc_id == 0) 1323771fe6b9SJerome Glisse WREG32(AVIVO_D1VGA_CONTROL, 0); 1324771fe6b9SJerome Glisse else 1325771fe6b9SJerome Glisse WREG32(AVIVO_D2VGA_CONTROL, 0); 1326c290dadfSAlex Deucher 1327c290dadfSAlex Deucher if (rdev->family >= CHIP_RV770) { 1328c290dadfSAlex Deucher if (radeon_crtc->crtc_id) { 132995347871SAlex Deucher WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 133095347871SAlex Deucher WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 1331c290dadfSAlex Deucher } else { 133295347871SAlex Deucher WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 133395347871SAlex Deucher WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 1334c290dadfSAlex Deucher } 1335c290dadfSAlex Deucher } 1336771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 1337771fe6b9SJerome Glisse (u32) fb_location); 1338771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + 1339771fe6b9SJerome Glisse radeon_crtc->crtc_offset, (u32) fb_location); 1340771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); 1341fa6bee46SAlex Deucher if (rdev->family >= CHIP_R600) 1342fa6bee46SAlex Deucher WREG32(R600_D1GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap); 1343771fe6b9SJerome Glisse 1344771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); 1345771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); 1346771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0); 1347771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, 0); 13484dd19b0dSChris Ball WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width); 13494dd19b0dSChris Ball WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height); 1350771fe6b9SJerome Glisse 135101f2c773SVille Syrjälä fb_pitch_pixels = target_fb->pitches[0] / (target_fb->bits_per_pixel / 8); 1352771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); 1353771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1); 1354771fe6b9SJerome Glisse 1355771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, 1356771fe6b9SJerome Glisse crtc->mode.vdisplay); 1357771fe6b9SJerome Glisse x &= ~3; 1358771fe6b9SJerome Glisse y &= ~1; 1359771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset, 1360771fe6b9SJerome Glisse (x << 16) | y); 1361adcfde51SAlex Deucher viewport_w = crtc->mode.hdisplay; 1362adcfde51SAlex Deucher viewport_h = (crtc->mode.vdisplay + 1) & ~1; 1363771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset, 1364adcfde51SAlex Deucher (viewport_w << 16) | viewport_h); 1365771fe6b9SJerome Glisse 1366fb9674bdSAlex Deucher /* pageflip setup */ 1367fb9674bdSAlex Deucher /* make sure flip is at vb rather than hb */ 1368fb9674bdSAlex Deucher tmp = RREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset); 1369fb9674bdSAlex Deucher tmp &= ~AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN; 1370fb9674bdSAlex Deucher WREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, tmp); 1371fb9674bdSAlex Deucher 1372fb9674bdSAlex Deucher /* set pageflip to happen anywhere in vblank interval */ 1373fb9674bdSAlex Deucher WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); 1374fb9674bdSAlex Deucher 13754dd19b0dSChris Ball if (!atomic && fb && fb != crtc->fb) { 13764dd19b0dSChris Ball radeon_fb = to_radeon_framebuffer(fb); 13777e4d15d9SDaniel Vetter rbo = gem_to_radeon_bo(radeon_fb->obj); 13784c788679SJerome Glisse r = radeon_bo_reserve(rbo, false); 13794c788679SJerome Glisse if (unlikely(r != 0)) 13804c788679SJerome Glisse return r; 13814c788679SJerome Glisse radeon_bo_unpin(rbo); 13824c788679SJerome Glisse radeon_bo_unreserve(rbo); 1383771fe6b9SJerome Glisse } 1384f30f37deSMichel Dänzer 1385f30f37deSMichel Dänzer /* Bytes per pixel may have changed */ 1386f30f37deSMichel Dänzer radeon_bandwidth_update(rdev); 1387f30f37deSMichel Dänzer 1388771fe6b9SJerome Glisse return 0; 1389771fe6b9SJerome Glisse } 1390771fe6b9SJerome Glisse 139154f088a9SAlex Deucher int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, 139254f088a9SAlex Deucher struct drm_framebuffer *old_fb) 139354f088a9SAlex Deucher { 139454f088a9SAlex Deucher struct drm_device *dev = crtc->dev; 139554f088a9SAlex Deucher struct radeon_device *rdev = dev->dev_private; 139654f088a9SAlex Deucher 1397bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) 1398c9417bddSAlex Deucher return dce4_crtc_do_set_base(crtc, old_fb, x, y, 0); 1399bcc1c2a1SAlex Deucher else if (ASIC_IS_AVIVO(rdev)) 14004dd19b0dSChris Ball return avivo_crtc_do_set_base(crtc, old_fb, x, y, 0); 140154f088a9SAlex Deucher else 14024dd19b0dSChris Ball return radeon_crtc_do_set_base(crtc, old_fb, x, y, 0); 14034dd19b0dSChris Ball } 14044dd19b0dSChris Ball 14054dd19b0dSChris Ball int atombios_crtc_set_base_atomic(struct drm_crtc *crtc, 14064dd19b0dSChris Ball struct drm_framebuffer *fb, 140721c74a8eSJason Wessel int x, int y, enum mode_set_atomic state) 14084dd19b0dSChris Ball { 14094dd19b0dSChris Ball struct drm_device *dev = crtc->dev; 14104dd19b0dSChris Ball struct radeon_device *rdev = dev->dev_private; 14114dd19b0dSChris Ball 14124dd19b0dSChris Ball if (ASIC_IS_DCE4(rdev)) 1413c9417bddSAlex Deucher return dce4_crtc_do_set_base(crtc, fb, x, y, 1); 14144dd19b0dSChris Ball else if (ASIC_IS_AVIVO(rdev)) 14154dd19b0dSChris Ball return avivo_crtc_do_set_base(crtc, fb, x, y, 1); 14164dd19b0dSChris Ball else 14174dd19b0dSChris Ball return radeon_crtc_do_set_base(crtc, fb, x, y, 1); 141854f088a9SAlex Deucher } 141954f088a9SAlex Deucher 1420615e0cb6SAlex Deucher /* properly set additional regs when using atombios */ 1421615e0cb6SAlex Deucher static void radeon_legacy_atom_fixup(struct drm_crtc *crtc) 1422615e0cb6SAlex Deucher { 1423615e0cb6SAlex Deucher struct drm_device *dev = crtc->dev; 1424615e0cb6SAlex Deucher struct radeon_device *rdev = dev->dev_private; 1425615e0cb6SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1426615e0cb6SAlex Deucher u32 disp_merge_cntl; 1427615e0cb6SAlex Deucher 1428615e0cb6SAlex Deucher switch (radeon_crtc->crtc_id) { 1429615e0cb6SAlex Deucher case 0: 1430615e0cb6SAlex Deucher disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL); 1431615e0cb6SAlex Deucher disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; 1432615e0cb6SAlex Deucher WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl); 1433615e0cb6SAlex Deucher break; 1434615e0cb6SAlex Deucher case 1: 1435615e0cb6SAlex Deucher disp_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL); 1436615e0cb6SAlex Deucher disp_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN; 1437615e0cb6SAlex Deucher WREG32(RADEON_DISP2_MERGE_CNTL, disp_merge_cntl); 1438615e0cb6SAlex Deucher WREG32(RADEON_FP_H2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_H_SYNC_STRT_WID)); 1439615e0cb6SAlex Deucher WREG32(RADEON_FP_V2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_V_SYNC_STRT_WID)); 1440615e0cb6SAlex Deucher break; 1441615e0cb6SAlex Deucher } 1442615e0cb6SAlex Deucher } 1443615e0cb6SAlex Deucher 1444bcc1c2a1SAlex Deucher static int radeon_atom_pick_pll(struct drm_crtc *crtc) 1445bcc1c2a1SAlex Deucher { 1446bcc1c2a1SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1447bcc1c2a1SAlex Deucher struct drm_device *dev = crtc->dev; 1448bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 1449bcc1c2a1SAlex Deucher struct drm_encoder *test_encoder; 1450bcc1c2a1SAlex Deucher struct drm_crtc *test_crtc; 1451bcc1c2a1SAlex Deucher uint32_t pll_in_use = 0; 1452bcc1c2a1SAlex Deucher 1453bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) { 1454bcc1c2a1SAlex Deucher list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { 1455bcc1c2a1SAlex Deucher if (test_encoder->crtc && (test_encoder->crtc == crtc)) { 145686a94defSAlex Deucher /* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock, 145786a94defSAlex Deucher * depending on the asic: 145886a94defSAlex Deucher * DCE4: PPLL or ext clock 145986a94defSAlex Deucher * DCE5: DCPLL or ext clock 146086a94defSAlex Deucher * 146186a94defSAlex Deucher * Setting ATOM_PPLL_INVALID will cause SetPixelClock to skip 146286a94defSAlex Deucher * PPLL/DCPLL programming and only program the DP DTO for the 146386a94defSAlex Deucher * crtc virtual pixel clock. 146486a94defSAlex Deucher */ 1465996d5c59SAlex Deucher if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { 146686a94defSAlex Deucher if (ASIC_IS_DCE5(rdev) || rdev->clock.dp_extclk) 1467bcc1c2a1SAlex Deucher return ATOM_PPLL_INVALID; 1468bcc1c2a1SAlex Deucher } 1469bcc1c2a1SAlex Deucher } 1470bcc1c2a1SAlex Deucher } 1471bcc1c2a1SAlex Deucher 1472bcc1c2a1SAlex Deucher /* otherwise, pick one of the plls */ 1473bcc1c2a1SAlex Deucher list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { 1474bcc1c2a1SAlex Deucher struct radeon_crtc *radeon_test_crtc; 1475bcc1c2a1SAlex Deucher 1476bcc1c2a1SAlex Deucher if (crtc == test_crtc) 1477bcc1c2a1SAlex Deucher continue; 1478bcc1c2a1SAlex Deucher 1479bcc1c2a1SAlex Deucher radeon_test_crtc = to_radeon_crtc(test_crtc); 1480bcc1c2a1SAlex Deucher if ((radeon_test_crtc->pll_id >= ATOM_PPLL1) && 1481bcc1c2a1SAlex Deucher (radeon_test_crtc->pll_id <= ATOM_PPLL2)) 1482bcc1c2a1SAlex Deucher pll_in_use |= (1 << radeon_test_crtc->pll_id); 1483bcc1c2a1SAlex Deucher } 1484bcc1c2a1SAlex Deucher if (!(pll_in_use & 1)) 1485bcc1c2a1SAlex Deucher return ATOM_PPLL1; 1486bcc1c2a1SAlex Deucher return ATOM_PPLL2; 1487bcc1c2a1SAlex Deucher } else 1488bcc1c2a1SAlex Deucher return radeon_crtc->crtc_id; 1489bcc1c2a1SAlex Deucher 1490bcc1c2a1SAlex Deucher } 1491bcc1c2a1SAlex Deucher 14923fa47d9eSAlex Deucher void radeon_atom_dcpll_init(struct radeon_device *rdev) 14933fa47d9eSAlex Deucher { 14943fa47d9eSAlex Deucher /* always set DCPLL */ 14953fa47d9eSAlex Deucher if (ASIC_IS_DCE4(rdev)) { 14963fa47d9eSAlex Deucher struct radeon_atom_ss ss; 14973fa47d9eSAlex Deucher bool ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &ss, 14983fa47d9eSAlex Deucher ASIC_INTERNAL_SS_ON_DCPLL, 14993fa47d9eSAlex Deucher rdev->clock.default_dispclk); 15003fa47d9eSAlex Deucher if (ss_enabled) 15013fa47d9eSAlex Deucher atombios_crtc_program_ss(rdev, ATOM_DISABLE, ATOM_DCPLL, &ss); 15023fa47d9eSAlex Deucher /* XXX: DCE5, make sure voltage, dispclk is high enough */ 15033fa47d9eSAlex Deucher atombios_crtc_set_dcpll(rdev, rdev->clock.default_dispclk); 15043fa47d9eSAlex Deucher if (ss_enabled) 15053fa47d9eSAlex Deucher atombios_crtc_program_ss(rdev, ATOM_ENABLE, ATOM_DCPLL, &ss); 15063fa47d9eSAlex Deucher } 15073fa47d9eSAlex Deucher 15083fa47d9eSAlex Deucher } 15093fa47d9eSAlex Deucher 1510771fe6b9SJerome Glisse int atombios_crtc_mode_set(struct drm_crtc *crtc, 1511771fe6b9SJerome Glisse struct drm_display_mode *mode, 1512771fe6b9SJerome Glisse struct drm_display_mode *adjusted_mode, 1513771fe6b9SJerome Glisse int x, int y, struct drm_framebuffer *old_fb) 1514771fe6b9SJerome Glisse { 1515771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1516771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 1517771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 151854bfe496SAlex Deucher struct drm_encoder *encoder; 151954bfe496SAlex Deucher bool is_tvcv = false; 1520771fe6b9SJerome Glisse 152154bfe496SAlex Deucher list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 152254bfe496SAlex Deucher /* find tv std */ 152354bfe496SAlex Deucher if (encoder->crtc == crtc) { 152454bfe496SAlex Deucher struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 152554bfe496SAlex Deucher if (radeon_encoder->active_device & 152654bfe496SAlex Deucher (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) 152754bfe496SAlex Deucher is_tvcv = true; 152854bfe496SAlex Deucher } 152954bfe496SAlex Deucher } 1530771fe6b9SJerome Glisse 1531771fe6b9SJerome Glisse atombios_crtc_set_pll(crtc, adjusted_mode); 1532771fe6b9SJerome Glisse 153354bfe496SAlex Deucher if (ASIC_IS_DCE4(rdev)) 1534bcc1c2a1SAlex Deucher atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 153554bfe496SAlex Deucher else if (ASIC_IS_AVIVO(rdev)) { 153654bfe496SAlex Deucher if (is_tvcv) 153754bfe496SAlex Deucher atombios_crtc_set_timing(crtc, adjusted_mode); 153854bfe496SAlex Deucher else 153954bfe496SAlex Deucher atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 154054bfe496SAlex Deucher } else { 1541bcc1c2a1SAlex Deucher atombios_crtc_set_timing(crtc, adjusted_mode); 15425a9bcaccSAlex Deucher if (radeon_crtc->crtc_id == 0) 15435a9bcaccSAlex Deucher atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 1544615e0cb6SAlex Deucher radeon_legacy_atom_fixup(crtc); 1545771fe6b9SJerome Glisse } 1546bcc1c2a1SAlex Deucher atombios_crtc_set_base(crtc, x, y, old_fb); 1547c93bb85bSJerome Glisse atombios_overscan_setup(crtc, mode, adjusted_mode); 1548c93bb85bSJerome Glisse atombios_scaler_setup(crtc); 1549771fe6b9SJerome Glisse return 0; 1550771fe6b9SJerome Glisse } 1551771fe6b9SJerome Glisse 1552771fe6b9SJerome Glisse static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, 1553771fe6b9SJerome Glisse struct drm_display_mode *mode, 1554771fe6b9SJerome Glisse struct drm_display_mode *adjusted_mode) 1555771fe6b9SJerome Glisse { 1556c93bb85bSJerome Glisse if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) 1557c93bb85bSJerome Glisse return false; 1558771fe6b9SJerome Glisse return true; 1559771fe6b9SJerome Glisse } 1560771fe6b9SJerome Glisse 1561771fe6b9SJerome Glisse static void atombios_crtc_prepare(struct drm_crtc *crtc) 1562771fe6b9SJerome Glisse { 1563267364acSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1564267364acSAlex Deucher 1565267364acSAlex Deucher /* pick pll */ 1566267364acSAlex Deucher radeon_crtc->pll_id = radeon_atom_pick_pll(crtc); 1567267364acSAlex Deucher 156837b4390eSAlex Deucher atombios_lock_crtc(crtc, ATOM_ENABLE); 1569a348c84dSAlex Deucher atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 1570771fe6b9SJerome Glisse } 1571771fe6b9SJerome Glisse 1572771fe6b9SJerome Glisse static void atombios_crtc_commit(struct drm_crtc *crtc) 1573771fe6b9SJerome Glisse { 1574771fe6b9SJerome Glisse atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON); 157537b4390eSAlex Deucher atombios_lock_crtc(crtc, ATOM_DISABLE); 1576771fe6b9SJerome Glisse } 1577771fe6b9SJerome Glisse 157837f9003bSAlex Deucher static void atombios_crtc_disable(struct drm_crtc *crtc) 157937f9003bSAlex Deucher { 158037f9003bSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 15818e8e523dSAlex Deucher struct radeon_atom_ss ss; 15828e8e523dSAlex Deucher 158337f9003bSAlex Deucher atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 158437f9003bSAlex Deucher 158537f9003bSAlex Deucher switch (radeon_crtc->pll_id) { 158637f9003bSAlex Deucher case ATOM_PPLL1: 158737f9003bSAlex Deucher case ATOM_PPLL2: 158837f9003bSAlex Deucher /* disable the ppll */ 158937f9003bSAlex Deucher atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, 15908e8e523dSAlex Deucher 0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss); 159137f9003bSAlex Deucher break; 159237f9003bSAlex Deucher default: 159337f9003bSAlex Deucher break; 159437f9003bSAlex Deucher } 159537f9003bSAlex Deucher radeon_crtc->pll_id = -1; 159637f9003bSAlex Deucher } 159737f9003bSAlex Deucher 1598771fe6b9SJerome Glisse static const struct drm_crtc_helper_funcs atombios_helper_funcs = { 1599771fe6b9SJerome Glisse .dpms = atombios_crtc_dpms, 1600771fe6b9SJerome Glisse .mode_fixup = atombios_crtc_mode_fixup, 1601771fe6b9SJerome Glisse .mode_set = atombios_crtc_mode_set, 1602771fe6b9SJerome Glisse .mode_set_base = atombios_crtc_set_base, 16034dd19b0dSChris Ball .mode_set_base_atomic = atombios_crtc_set_base_atomic, 1604771fe6b9SJerome Glisse .prepare = atombios_crtc_prepare, 1605771fe6b9SJerome Glisse .commit = atombios_crtc_commit, 1606068143d3SDave Airlie .load_lut = radeon_crtc_load_lut, 160737f9003bSAlex Deucher .disable = atombios_crtc_disable, 1608771fe6b9SJerome Glisse }; 1609771fe6b9SJerome Glisse 1610771fe6b9SJerome Glisse void radeon_atombios_init_crtc(struct drm_device *dev, 1611771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc) 1612771fe6b9SJerome Glisse { 1613bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 1614bcc1c2a1SAlex Deucher 1615bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) { 1616bcc1c2a1SAlex Deucher switch (radeon_crtc->crtc_id) { 1617bcc1c2a1SAlex Deucher case 0: 1618bcc1c2a1SAlex Deucher default: 161912d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC0_REGISTER_OFFSET; 1620bcc1c2a1SAlex Deucher break; 1621bcc1c2a1SAlex Deucher case 1: 162212d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC1_REGISTER_OFFSET; 1623bcc1c2a1SAlex Deucher break; 1624bcc1c2a1SAlex Deucher case 2: 162512d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC2_REGISTER_OFFSET; 1626bcc1c2a1SAlex Deucher break; 1627bcc1c2a1SAlex Deucher case 3: 162812d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC3_REGISTER_OFFSET; 1629bcc1c2a1SAlex Deucher break; 1630bcc1c2a1SAlex Deucher case 4: 163112d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC4_REGISTER_OFFSET; 1632bcc1c2a1SAlex Deucher break; 1633bcc1c2a1SAlex Deucher case 5: 163412d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC5_REGISTER_OFFSET; 1635bcc1c2a1SAlex Deucher break; 1636bcc1c2a1SAlex Deucher } 1637bcc1c2a1SAlex Deucher } else { 1638771fe6b9SJerome Glisse if (radeon_crtc->crtc_id == 1) 1639771fe6b9SJerome Glisse radeon_crtc->crtc_offset = 1640771fe6b9SJerome Glisse AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL; 1641bcc1c2a1SAlex Deucher else 1642bcc1c2a1SAlex Deucher radeon_crtc->crtc_offset = 0; 1643bcc1c2a1SAlex Deucher } 1644bcc1c2a1SAlex Deucher radeon_crtc->pll_id = -1; 1645771fe6b9SJerome Glisse drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); 1646771fe6b9SJerome Glisse } 1647