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); 560eac4dff6SAlex Deucher if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) || 561eac4dff6SAlex Deucher radeon_encoder_is_dp_bridge(encoder)) { 562fbee67a6SAlex Deucher if (connector) { 563fbee67a6SAlex Deucher struct radeon_connector *radeon_connector = to_radeon_connector(connector); 564fbee67a6SAlex Deucher struct radeon_connector_atom_dig *dig_connector = 565fbee67a6SAlex Deucher radeon_connector->con_priv; 566fbee67a6SAlex Deucher 567fbee67a6SAlex Deucher dp_clock = dig_connector->dp_clock; 568fbee67a6SAlex Deucher } 569fbee67a6SAlex Deucher } 5705b40ddf8SAlex Deucher 571ba032a58SAlex Deucher /* use recommended ref_div for ss */ 572ba032a58SAlex Deucher if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 573ba032a58SAlex Deucher if (ss_enabled) { 574ba032a58SAlex Deucher if (ss->refdiv) { 575ba032a58SAlex Deucher pll->flags |= RADEON_PLL_USE_REF_DIV; 576ba032a58SAlex Deucher pll->reference_div = ss->refdiv; 5775b40ddf8SAlex Deucher if (ASIC_IS_AVIVO(rdev)) 5785b40ddf8SAlex Deucher pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV; 579ba032a58SAlex Deucher } 580ba032a58SAlex Deucher } 581ba032a58SAlex Deucher } 5825b40ddf8SAlex Deucher 5834eaeca33SAlex Deucher if (ASIC_IS_AVIVO(rdev)) { 5844eaeca33SAlex Deucher /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ 5854eaeca33SAlex Deucher if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1) 5864eaeca33SAlex Deucher adjusted_clock = mode->clock * 2; 58748dfaaebSAlex Deucher if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 588a1a4b23bSAlex Deucher pll->flags |= RADEON_PLL_PREFER_CLOSEST_LOWER; 589619efb10SAlex Deucher if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) 590619efb10SAlex Deucher pll->flags |= RADEON_PLL_IS_LCD; 5914eaeca33SAlex Deucher } else { 5924eaeca33SAlex Deucher if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) 593fc10332bSAlex Deucher pll->flags |= RADEON_PLL_NO_ODD_POST_DIV; 5944eaeca33SAlex Deucher if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) 595fc10332bSAlex Deucher pll->flags |= RADEON_PLL_USE_REF_DIV; 596771fe6b9SJerome Glisse } 5973ce0a23dSJerome Glisse break; 598771fe6b9SJerome Glisse } 599771fe6b9SJerome Glisse } 600771fe6b9SJerome Glisse 6012606c886SAlex Deucher /* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock 6022606c886SAlex Deucher * accordingly based on the encoder/transmitter to work around 6032606c886SAlex Deucher * special hw requirements. 6042606c886SAlex Deucher */ 6052606c886SAlex Deucher if (ASIC_IS_DCE3(rdev)) { 6064eaeca33SAlex Deucher union adjust_pixel_clock args; 6074eaeca33SAlex Deucher u8 frev, crev; 6084eaeca33SAlex Deucher int index; 6092606c886SAlex Deucher 6102606c886SAlex Deucher index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll); 611a084e6eeSAlex Deucher if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 612a084e6eeSAlex Deucher &crev)) 613a084e6eeSAlex Deucher return adjusted_clock; 6144eaeca33SAlex Deucher 6154eaeca33SAlex Deucher memset(&args, 0, sizeof(args)); 6164eaeca33SAlex Deucher 6174eaeca33SAlex Deucher switch (frev) { 6184eaeca33SAlex Deucher case 1: 6194eaeca33SAlex Deucher switch (crev) { 6204eaeca33SAlex Deucher case 1: 6214eaeca33SAlex Deucher case 2: 6224eaeca33SAlex Deucher args.v1.usPixelClock = cpu_to_le16(mode->clock / 10); 6234eaeca33SAlex Deucher args.v1.ucTransmitterID = radeon_encoder->encoder_id; 624bcc1c2a1SAlex Deucher args.v1.ucEncodeMode = encoder_mode; 6258e8e523dSAlex Deucher if (ss_enabled && ss->percentage) 626ba032a58SAlex Deucher args.v1.ucConfig |= 627ba032a58SAlex Deucher ADJUST_DISPLAY_CONFIG_SS_ENABLE; 6284eaeca33SAlex Deucher 6292606c886SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, 6304eaeca33SAlex Deucher index, (uint32_t *)&args); 6314eaeca33SAlex Deucher adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10; 6324eaeca33SAlex Deucher break; 633bcc1c2a1SAlex Deucher case 3: 634bcc1c2a1SAlex Deucher args.v3.sInput.usPixelClock = cpu_to_le16(mode->clock / 10); 635bcc1c2a1SAlex Deucher args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id; 636bcc1c2a1SAlex Deucher args.v3.sInput.ucEncodeMode = encoder_mode; 637bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig = 0; 6388e8e523dSAlex Deucher if (ss_enabled && ss->percentage) 639ba032a58SAlex Deucher args.v3.sInput.ucDispPllConfig |= 640ba032a58SAlex Deucher DISPPLL_CONFIG_SS_ENABLE; 641eac4dff6SAlex Deucher if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT) || 642eac4dff6SAlex Deucher radeon_encoder_is_dp_bridge(encoder)) { 643b526ce22SAlex Deucher struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 644b526ce22SAlex Deucher if (encoder_mode == ATOM_ENCODER_MODE_DP) { 645bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 646bcc1c2a1SAlex Deucher DISPPLL_CONFIG_COHERENT_MODE; 647fbee67a6SAlex Deucher /* 16200 or 27000 */ 648fbee67a6SAlex Deucher args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); 649fbee67a6SAlex Deucher } else { 650fbee67a6SAlex Deucher if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { 651fbee67a6SAlex Deucher /* deep color support */ 652fbee67a6SAlex Deucher args.v3.sInput.usPixelClock = 653fbee67a6SAlex Deucher cpu_to_le16((mode->clock * bpc / 8) / 10); 654fbee67a6SAlex Deucher } 655bcc1c2a1SAlex Deucher if (dig->coherent_mode) 656bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 657bcc1c2a1SAlex Deucher DISPPLL_CONFIG_COHERENT_MODE; 658bcc1c2a1SAlex Deucher if (mode->clock > 165000) 659bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 660bcc1c2a1SAlex Deucher DISPPLL_CONFIG_DUAL_LINK; 661bcc1c2a1SAlex Deucher } 662bcc1c2a1SAlex Deucher } else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 663fbee67a6SAlex Deucher if (encoder_mode == ATOM_ENCODER_MODE_DP) { 664bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 6659f998ad7SAlex Deucher DISPPLL_CONFIG_COHERENT_MODE; 666fbee67a6SAlex Deucher /* 16200 or 27000 */ 667fbee67a6SAlex Deucher args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); 668b526ce22SAlex Deucher } else if (encoder_mode != ATOM_ENCODER_MODE_LVDS) { 669bcc1c2a1SAlex Deucher if (mode->clock > 165000) 670bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 671bcc1c2a1SAlex Deucher DISPPLL_CONFIG_DUAL_LINK; 672bcc1c2a1SAlex Deucher } 6739f998ad7SAlex Deucher } 674bcc1c2a1SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, 675bcc1c2a1SAlex Deucher index, (uint32_t *)&args); 676bcc1c2a1SAlex Deucher adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10; 677bcc1c2a1SAlex Deucher if (args.v3.sOutput.ucRefDiv) { 6789f4283f4SAlex Deucher pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV; 679bcc1c2a1SAlex Deucher pll->flags |= RADEON_PLL_USE_REF_DIV; 680bcc1c2a1SAlex Deucher pll->reference_div = args.v3.sOutput.ucRefDiv; 681bcc1c2a1SAlex Deucher } 682bcc1c2a1SAlex Deucher if (args.v3.sOutput.ucPostDiv) { 6839f4283f4SAlex Deucher pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV; 684bcc1c2a1SAlex Deucher pll->flags |= RADEON_PLL_USE_POST_DIV; 685bcc1c2a1SAlex Deucher pll->post_div = args.v3.sOutput.ucPostDiv; 686bcc1c2a1SAlex Deucher } 687bcc1c2a1SAlex Deucher break; 6884eaeca33SAlex Deucher default: 6894eaeca33SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 6904eaeca33SAlex Deucher return adjusted_clock; 691d56ef9c8SAlex Deucher } 6924eaeca33SAlex Deucher break; 6934eaeca33SAlex Deucher default: 6944eaeca33SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 6954eaeca33SAlex Deucher return adjusted_clock; 6964eaeca33SAlex Deucher } 6974eaeca33SAlex Deucher } 6984eaeca33SAlex Deucher return adjusted_clock; 6994eaeca33SAlex Deucher } 7004eaeca33SAlex Deucher 7014eaeca33SAlex Deucher union set_pixel_clock { 7024eaeca33SAlex Deucher SET_PIXEL_CLOCK_PS_ALLOCATION base; 7034eaeca33SAlex Deucher PIXEL_CLOCK_PARAMETERS v1; 7044eaeca33SAlex Deucher PIXEL_CLOCK_PARAMETERS_V2 v2; 7054eaeca33SAlex Deucher PIXEL_CLOCK_PARAMETERS_V3 v3; 706bcc1c2a1SAlex Deucher PIXEL_CLOCK_PARAMETERS_V5 v5; 707f82b3ddcSAlex Deucher PIXEL_CLOCK_PARAMETERS_V6 v6; 7084eaeca33SAlex Deucher }; 7094eaeca33SAlex Deucher 710f82b3ddcSAlex Deucher /* on DCE5, make sure the voltage is high enough to support the 711f82b3ddcSAlex Deucher * required disp clk. 712f82b3ddcSAlex Deucher */ 713f82b3ddcSAlex Deucher static void atombios_crtc_set_dcpll(struct drm_crtc *crtc, 714f82b3ddcSAlex Deucher u32 dispclk) 715bcc1c2a1SAlex Deucher { 716bcc1c2a1SAlex Deucher struct drm_device *dev = crtc->dev; 717bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 718bcc1c2a1SAlex Deucher u8 frev, crev; 719bcc1c2a1SAlex Deucher int index; 720bcc1c2a1SAlex Deucher union set_pixel_clock args; 721bcc1c2a1SAlex Deucher 722bcc1c2a1SAlex Deucher memset(&args, 0, sizeof(args)); 723bcc1c2a1SAlex Deucher 724bcc1c2a1SAlex Deucher index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); 725a084e6eeSAlex Deucher if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 726a084e6eeSAlex Deucher &crev)) 727a084e6eeSAlex Deucher return; 728bcc1c2a1SAlex Deucher 729bcc1c2a1SAlex Deucher switch (frev) { 730bcc1c2a1SAlex Deucher case 1: 731bcc1c2a1SAlex Deucher switch (crev) { 732bcc1c2a1SAlex Deucher case 5: 733bcc1c2a1SAlex Deucher /* if the default dcpll clock is specified, 734bcc1c2a1SAlex Deucher * SetPixelClock provides the dividers 735bcc1c2a1SAlex Deucher */ 736bcc1c2a1SAlex Deucher args.v5.ucCRTC = ATOM_CRTC_INVALID; 7374589433cSCédric Cano args.v5.usPixelClock = cpu_to_le16(dispclk); 738bcc1c2a1SAlex Deucher args.v5.ucPpll = ATOM_DCPLL; 739bcc1c2a1SAlex Deucher break; 740f82b3ddcSAlex Deucher case 6: 741f82b3ddcSAlex Deucher /* if the default dcpll clock is specified, 742f82b3ddcSAlex Deucher * SetPixelClock provides the dividers 743f82b3ddcSAlex Deucher */ 744265aa6c8SAlex Deucher args.v6.ulDispEngClkFreq = cpu_to_le32(dispclk); 745f82b3ddcSAlex Deucher args.v6.ucPpll = ATOM_DCPLL; 746f82b3ddcSAlex Deucher break; 747bcc1c2a1SAlex Deucher default: 748bcc1c2a1SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 749bcc1c2a1SAlex Deucher return; 750bcc1c2a1SAlex Deucher } 751bcc1c2a1SAlex Deucher break; 752bcc1c2a1SAlex Deucher default: 753bcc1c2a1SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 754bcc1c2a1SAlex Deucher return; 755bcc1c2a1SAlex Deucher } 756bcc1c2a1SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 757bcc1c2a1SAlex Deucher } 758bcc1c2a1SAlex Deucher 75937f9003bSAlex Deucher static void atombios_crtc_program_pll(struct drm_crtc *crtc, 76037f9003bSAlex Deucher int crtc_id, 76137f9003bSAlex Deucher int pll_id, 76237f9003bSAlex Deucher u32 encoder_mode, 76337f9003bSAlex Deucher u32 encoder_id, 76437f9003bSAlex Deucher u32 clock, 76537f9003bSAlex Deucher u32 ref_div, 76637f9003bSAlex Deucher u32 fb_div, 76737f9003bSAlex Deucher u32 frac_fb_div, 768df271becSAlex Deucher u32 post_div, 7698e8e523dSAlex Deucher int bpc, 7708e8e523dSAlex Deucher bool ss_enabled, 7718e8e523dSAlex Deucher struct radeon_atom_ss *ss) 77237f9003bSAlex Deucher { 77337f9003bSAlex Deucher struct drm_device *dev = crtc->dev; 77437f9003bSAlex Deucher struct radeon_device *rdev = dev->dev_private; 77537f9003bSAlex Deucher u8 frev, crev; 77637f9003bSAlex Deucher int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); 77737f9003bSAlex Deucher union set_pixel_clock args; 77837f9003bSAlex Deucher 77937f9003bSAlex Deucher memset(&args, 0, sizeof(args)); 78037f9003bSAlex Deucher 78137f9003bSAlex Deucher if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 78237f9003bSAlex Deucher &crev)) 78337f9003bSAlex Deucher return; 78437f9003bSAlex Deucher 78537f9003bSAlex Deucher switch (frev) { 78637f9003bSAlex Deucher case 1: 78737f9003bSAlex Deucher switch (crev) { 78837f9003bSAlex Deucher case 1: 78937f9003bSAlex Deucher if (clock == ATOM_DISABLE) 79037f9003bSAlex Deucher return; 79137f9003bSAlex Deucher args.v1.usPixelClock = cpu_to_le16(clock / 10); 79237f9003bSAlex Deucher args.v1.usRefDiv = cpu_to_le16(ref_div); 79337f9003bSAlex Deucher args.v1.usFbDiv = cpu_to_le16(fb_div); 79437f9003bSAlex Deucher args.v1.ucFracFbDiv = frac_fb_div; 79537f9003bSAlex Deucher args.v1.ucPostDiv = post_div; 79637f9003bSAlex Deucher args.v1.ucPpll = pll_id; 79737f9003bSAlex Deucher args.v1.ucCRTC = crtc_id; 79837f9003bSAlex Deucher args.v1.ucRefDivSrc = 1; 79937f9003bSAlex Deucher break; 80037f9003bSAlex Deucher case 2: 80137f9003bSAlex Deucher args.v2.usPixelClock = cpu_to_le16(clock / 10); 80237f9003bSAlex Deucher args.v2.usRefDiv = cpu_to_le16(ref_div); 80337f9003bSAlex Deucher args.v2.usFbDiv = cpu_to_le16(fb_div); 80437f9003bSAlex Deucher args.v2.ucFracFbDiv = frac_fb_div; 80537f9003bSAlex Deucher args.v2.ucPostDiv = post_div; 80637f9003bSAlex Deucher args.v2.ucPpll = pll_id; 80737f9003bSAlex Deucher args.v2.ucCRTC = crtc_id; 80837f9003bSAlex Deucher args.v2.ucRefDivSrc = 1; 80937f9003bSAlex Deucher break; 81037f9003bSAlex Deucher case 3: 81137f9003bSAlex Deucher args.v3.usPixelClock = cpu_to_le16(clock / 10); 81237f9003bSAlex Deucher args.v3.usRefDiv = cpu_to_le16(ref_div); 81337f9003bSAlex Deucher args.v3.usFbDiv = cpu_to_le16(fb_div); 81437f9003bSAlex Deucher args.v3.ucFracFbDiv = frac_fb_div; 81537f9003bSAlex Deucher args.v3.ucPostDiv = post_div; 81637f9003bSAlex Deucher args.v3.ucPpll = pll_id; 81737f9003bSAlex Deucher args.v3.ucMiscInfo = (pll_id << 2); 81837f9003bSAlex Deucher args.v3.ucTransmitterId = encoder_id; 81937f9003bSAlex Deucher args.v3.ucEncoderMode = encoder_mode; 82037f9003bSAlex Deucher break; 82137f9003bSAlex Deucher case 5: 82237f9003bSAlex Deucher args.v5.ucCRTC = crtc_id; 82337f9003bSAlex Deucher args.v5.usPixelClock = cpu_to_le16(clock / 10); 82437f9003bSAlex Deucher args.v5.ucRefDiv = ref_div; 82537f9003bSAlex Deucher args.v5.usFbDiv = cpu_to_le16(fb_div); 82637f9003bSAlex Deucher args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); 82737f9003bSAlex Deucher args.v5.ucPostDiv = post_div; 82837f9003bSAlex Deucher args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */ 8298e8e523dSAlex Deucher if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) 8308e8e523dSAlex Deucher args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_REF_DIV_SRC; 831df271becSAlex Deucher switch (bpc) { 832df271becSAlex Deucher case 8: 833df271becSAlex Deucher default: 834df271becSAlex Deucher args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP; 835df271becSAlex Deucher break; 836df271becSAlex Deucher case 10: 837df271becSAlex Deucher args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP; 838df271becSAlex Deucher break; 839df271becSAlex Deucher } 84037f9003bSAlex Deucher args.v5.ucTransmitterID = encoder_id; 84137f9003bSAlex Deucher args.v5.ucEncoderMode = encoder_mode; 84237f9003bSAlex Deucher args.v5.ucPpll = pll_id; 84337f9003bSAlex Deucher break; 844f82b3ddcSAlex Deucher case 6: 845f82b3ddcSAlex Deucher args.v6.ulCrtcPclkFreq.ucCRTC = crtc_id; 846f82b3ddcSAlex Deucher args.v6.ulCrtcPclkFreq.ulPixelClock = cpu_to_le32(clock / 10); 847f82b3ddcSAlex Deucher args.v6.ucRefDiv = ref_div; 848f82b3ddcSAlex Deucher args.v6.usFbDiv = cpu_to_le16(fb_div); 849f82b3ddcSAlex Deucher args.v6.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); 850f82b3ddcSAlex Deucher args.v6.ucPostDiv = post_div; 851f82b3ddcSAlex Deucher args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */ 8528e8e523dSAlex Deucher if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) 8538e8e523dSAlex Deucher args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_REF_DIV_SRC; 854df271becSAlex Deucher switch (bpc) { 855df271becSAlex Deucher case 8: 856df271becSAlex Deucher default: 857df271becSAlex Deucher args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP; 858df271becSAlex Deucher break; 859df271becSAlex Deucher case 10: 860df271becSAlex Deucher args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP; 861df271becSAlex Deucher break; 862df271becSAlex Deucher case 12: 863df271becSAlex Deucher args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP; 864df271becSAlex Deucher break; 865df271becSAlex Deucher case 16: 866df271becSAlex Deucher args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP; 867df271becSAlex Deucher break; 868df271becSAlex Deucher } 869f82b3ddcSAlex Deucher args.v6.ucTransmitterID = encoder_id; 870f82b3ddcSAlex Deucher args.v6.ucEncoderMode = encoder_mode; 871f82b3ddcSAlex Deucher args.v6.ucPpll = pll_id; 872f82b3ddcSAlex Deucher break; 87337f9003bSAlex Deucher default: 87437f9003bSAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 87537f9003bSAlex Deucher return; 87637f9003bSAlex Deucher } 87737f9003bSAlex Deucher break; 87837f9003bSAlex Deucher default: 87937f9003bSAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 88037f9003bSAlex Deucher return; 88137f9003bSAlex Deucher } 88237f9003bSAlex Deucher 88337f9003bSAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 88437f9003bSAlex Deucher } 88537f9003bSAlex Deucher 886bcc1c2a1SAlex Deucher static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) 8874eaeca33SAlex Deucher { 8884eaeca33SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 8894eaeca33SAlex Deucher struct drm_device *dev = crtc->dev; 8904eaeca33SAlex Deucher struct radeon_device *rdev = dev->dev_private; 8914eaeca33SAlex Deucher struct drm_encoder *encoder = NULL; 8924eaeca33SAlex Deucher struct radeon_encoder *radeon_encoder = NULL; 8934eaeca33SAlex Deucher u32 pll_clock = mode->clock; 8944eaeca33SAlex Deucher u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; 8954eaeca33SAlex Deucher struct radeon_pll *pll; 8964eaeca33SAlex Deucher u32 adjusted_clock; 897bcc1c2a1SAlex Deucher int encoder_mode = 0; 898ba032a58SAlex Deucher struct radeon_atom_ss ss; 899ba032a58SAlex Deucher bool ss_enabled = false; 900df271becSAlex Deucher int bpc = 8; 9014eaeca33SAlex Deucher 9024eaeca33SAlex Deucher list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 9034eaeca33SAlex Deucher if (encoder->crtc == crtc) { 9044eaeca33SAlex Deucher radeon_encoder = to_radeon_encoder(encoder); 905bcc1c2a1SAlex Deucher encoder_mode = atombios_get_encoder_mode(encoder); 9064eaeca33SAlex Deucher break; 9074eaeca33SAlex Deucher } 9084eaeca33SAlex Deucher } 9094eaeca33SAlex Deucher 9104eaeca33SAlex Deucher if (!radeon_encoder) 9114eaeca33SAlex Deucher return; 9124eaeca33SAlex Deucher 913bcc1c2a1SAlex Deucher switch (radeon_crtc->pll_id) { 914bcc1c2a1SAlex Deucher case ATOM_PPLL1: 9154eaeca33SAlex Deucher pll = &rdev->clock.p1pll; 916bcc1c2a1SAlex Deucher break; 917bcc1c2a1SAlex Deucher case ATOM_PPLL2: 9184eaeca33SAlex Deucher pll = &rdev->clock.p2pll; 919bcc1c2a1SAlex Deucher break; 920bcc1c2a1SAlex Deucher case ATOM_DCPLL: 921bcc1c2a1SAlex Deucher case ATOM_PPLL_INVALID: 922921d98b5SStefan Richter default: 923bcc1c2a1SAlex Deucher pll = &rdev->clock.dcpll; 924bcc1c2a1SAlex Deucher break; 925bcc1c2a1SAlex Deucher } 9264eaeca33SAlex Deucher 927ba032a58SAlex Deucher if (radeon_encoder->active_device & 928ba032a58SAlex Deucher (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) { 929ba032a58SAlex Deucher struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 930ba032a58SAlex Deucher struct drm_connector *connector = 931ba032a58SAlex Deucher radeon_get_connector_for_encoder(encoder); 932ba032a58SAlex Deucher struct radeon_connector *radeon_connector = 933ba032a58SAlex Deucher to_radeon_connector(connector); 934ba032a58SAlex Deucher struct radeon_connector_atom_dig *dig_connector = 935ba032a58SAlex Deucher radeon_connector->con_priv; 936ba032a58SAlex Deucher int dp_clock; 937df271becSAlex Deucher bpc = connector->display_info.bpc; 938ba032a58SAlex Deucher 939ba032a58SAlex Deucher switch (encoder_mode) { 940ba032a58SAlex Deucher case ATOM_ENCODER_MODE_DP: 941ba032a58SAlex Deucher /* DP/eDP */ 942ba032a58SAlex Deucher dp_clock = dig_connector->dp_clock / 10; 943ba032a58SAlex Deucher if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) { 9448e8e523dSAlex Deucher if (ASIC_IS_DCE4(rdev)) { 9458e8e523dSAlex Deucher /* first try ASIC_INTERNAL_SS_ON_DP */ 9468e8e523dSAlex Deucher ss_enabled = 9478e8e523dSAlex Deucher radeon_atombios_get_asic_ss_info(rdev, &ss, 9488e8e523dSAlex Deucher ASIC_INTERNAL_SS_ON_DP, 9498e8e523dSAlex Deucher dp_clock); 9508e8e523dSAlex Deucher if (!ss_enabled) 951ba032a58SAlex Deucher ss_enabled = 952ba032a58SAlex Deucher radeon_atombios_get_asic_ss_info(rdev, &ss, 953ba032a58SAlex Deucher dig->lcd_ss_id, 954ba032a58SAlex Deucher dp_clock); 9558e8e523dSAlex Deucher } else 956ba032a58SAlex Deucher ss_enabled = 957ba032a58SAlex Deucher radeon_atombios_get_ppll_ss_info(rdev, &ss, 958ba032a58SAlex Deucher dig->lcd_ss_id); 959ba032a58SAlex Deucher } else { 960ba032a58SAlex Deucher if (ASIC_IS_DCE4(rdev)) 961ba032a58SAlex Deucher ss_enabled = 962ba032a58SAlex Deucher radeon_atombios_get_asic_ss_info(rdev, &ss, 963ba032a58SAlex Deucher ASIC_INTERNAL_SS_ON_DP, 964ba032a58SAlex Deucher dp_clock); 965ba032a58SAlex Deucher else { 966ba032a58SAlex Deucher if (dp_clock == 16200) { 967ba032a58SAlex Deucher ss_enabled = 968ba032a58SAlex Deucher radeon_atombios_get_ppll_ss_info(rdev, &ss, 969ba032a58SAlex Deucher ATOM_DP_SS_ID2); 970ba032a58SAlex Deucher if (!ss_enabled) 971ba032a58SAlex Deucher ss_enabled = 972ba032a58SAlex Deucher radeon_atombios_get_ppll_ss_info(rdev, &ss, 973ba032a58SAlex Deucher ATOM_DP_SS_ID1); 974ba032a58SAlex Deucher } else 975ba032a58SAlex Deucher ss_enabled = 976ba032a58SAlex Deucher radeon_atombios_get_ppll_ss_info(rdev, &ss, 977ba032a58SAlex Deucher ATOM_DP_SS_ID1); 978ba032a58SAlex Deucher } 979ba032a58SAlex Deucher } 980ba032a58SAlex Deucher break; 981ba032a58SAlex Deucher case ATOM_ENCODER_MODE_LVDS: 982ba032a58SAlex Deucher if (ASIC_IS_DCE4(rdev)) 983ba032a58SAlex Deucher ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &ss, 984ba032a58SAlex Deucher dig->lcd_ss_id, 985ba032a58SAlex Deucher mode->clock / 10); 986ba032a58SAlex Deucher else 987ba032a58SAlex Deucher ss_enabled = radeon_atombios_get_ppll_ss_info(rdev, &ss, 988ba032a58SAlex Deucher dig->lcd_ss_id); 989ba032a58SAlex Deucher break; 990ba032a58SAlex Deucher case ATOM_ENCODER_MODE_DVI: 991ba032a58SAlex Deucher if (ASIC_IS_DCE4(rdev)) 992ba032a58SAlex Deucher ss_enabled = 993ba032a58SAlex Deucher radeon_atombios_get_asic_ss_info(rdev, &ss, 994ba032a58SAlex Deucher ASIC_INTERNAL_SS_ON_TMDS, 995ba032a58SAlex Deucher mode->clock / 10); 996ba032a58SAlex Deucher break; 997ba032a58SAlex Deucher case ATOM_ENCODER_MODE_HDMI: 998ba032a58SAlex Deucher if (ASIC_IS_DCE4(rdev)) 999ba032a58SAlex Deucher ss_enabled = 1000ba032a58SAlex Deucher radeon_atombios_get_asic_ss_info(rdev, &ss, 1001ba032a58SAlex Deucher ASIC_INTERNAL_SS_ON_HDMI, 1002ba032a58SAlex Deucher mode->clock / 10); 1003ba032a58SAlex Deucher break; 1004ba032a58SAlex Deucher default: 1005ba032a58SAlex Deucher break; 1006ba032a58SAlex Deucher } 1007ba032a58SAlex Deucher } 1008ba032a58SAlex Deucher 10094eaeca33SAlex Deucher /* adjust pixel clock as needed */ 1010ba032a58SAlex Deucher adjusted_clock = atombios_adjust_pll(crtc, mode, pll, ss_enabled, &ss); 10112606c886SAlex Deucher 101264146f8bSAlex Deucher if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 101364146f8bSAlex Deucher /* TV seems to prefer the legacy algo on some boards */ 101464146f8bSAlex Deucher radeon_compute_pll_legacy(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, 101564146f8bSAlex Deucher &ref_div, &post_div); 101664146f8bSAlex Deucher else if (ASIC_IS_AVIVO(rdev)) 1017619efb10SAlex Deucher radeon_compute_pll_avivo(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, 1018619efb10SAlex Deucher &ref_div, &post_div); 1019619efb10SAlex Deucher else 1020f523f74eSAlex Deucher radeon_compute_pll_legacy(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, 1021fc10332bSAlex Deucher &ref_div, &post_div); 1022771fe6b9SJerome Glisse 1023ba032a58SAlex Deucher atombios_crtc_program_ss(crtc, ATOM_DISABLE, radeon_crtc->pll_id, &ss); 1024ba032a58SAlex Deucher 102537f9003bSAlex Deucher atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, 102637f9003bSAlex Deucher encoder_mode, radeon_encoder->encoder_id, mode->clock, 10278e8e523dSAlex Deucher ref_div, fb_div, frac_fb_div, post_div, bpc, ss_enabled, &ss); 1028771fe6b9SJerome Glisse 1029ba032a58SAlex Deucher if (ss_enabled) { 1030ba032a58SAlex Deucher /* calculate ss amount and step size */ 1031ba032a58SAlex Deucher if (ASIC_IS_DCE4(rdev)) { 1032ba032a58SAlex Deucher u32 step_size; 1033ba032a58SAlex Deucher u32 amount = (((fb_div * 10) + frac_fb_div) * ss.percentage) / 10000; 1034ba032a58SAlex Deucher ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK; 10358e8e523dSAlex Deucher ss.amount |= ((amount - (amount / 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) & 1036ba032a58SAlex Deucher ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK; 1037ba032a58SAlex Deucher if (ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD) 1038ba032a58SAlex Deucher step_size = (4 * amount * ref_div * (ss.rate * 2048)) / 1039ba032a58SAlex Deucher (125 * 25 * pll->reference_freq / 100); 1040ba032a58SAlex Deucher else 1041ba032a58SAlex Deucher step_size = (2 * amount * ref_div * (ss.rate * 2048)) / 1042ba032a58SAlex Deucher (125 * 25 * pll->reference_freq / 100); 1043ba032a58SAlex Deucher ss.step = step_size; 1044ba032a58SAlex Deucher } 1045ba032a58SAlex Deucher 1046ba032a58SAlex Deucher atombios_crtc_program_ss(crtc, ATOM_ENABLE, radeon_crtc->pll_id, &ss); 1047ba032a58SAlex Deucher } 1048771fe6b9SJerome Glisse } 1049771fe6b9SJerome Glisse 1050c9417bddSAlex Deucher static int dce4_crtc_do_set_base(struct drm_crtc *crtc, 10514dd19b0dSChris Ball struct drm_framebuffer *fb, 10524dd19b0dSChris Ball int x, int y, int atomic) 1053bcc1c2a1SAlex Deucher { 1054bcc1c2a1SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1055bcc1c2a1SAlex Deucher struct drm_device *dev = crtc->dev; 1056bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 1057bcc1c2a1SAlex Deucher struct radeon_framebuffer *radeon_fb; 10584dd19b0dSChris Ball struct drm_framebuffer *target_fb; 1059bcc1c2a1SAlex Deucher struct drm_gem_object *obj; 1060bcc1c2a1SAlex Deucher struct radeon_bo *rbo; 1061bcc1c2a1SAlex Deucher uint64_t fb_location; 1062bcc1c2a1SAlex Deucher uint32_t fb_format, fb_pitch_pixels, tiling_flags; 1063fa6bee46SAlex Deucher u32 fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE); 1064fb9674bdSAlex Deucher u32 tmp; 1065bcc1c2a1SAlex Deucher int r; 1066bcc1c2a1SAlex Deucher 1067bcc1c2a1SAlex Deucher /* no fb bound */ 10684dd19b0dSChris Ball if (!atomic && !crtc->fb) { 1069d9fdaafbSDave Airlie DRM_DEBUG_KMS("No FB bound\n"); 1070bcc1c2a1SAlex Deucher return 0; 1071bcc1c2a1SAlex Deucher } 1072bcc1c2a1SAlex Deucher 10734dd19b0dSChris Ball if (atomic) { 10744dd19b0dSChris Ball radeon_fb = to_radeon_framebuffer(fb); 10754dd19b0dSChris Ball target_fb = fb; 10764dd19b0dSChris Ball } 10774dd19b0dSChris Ball else { 1078bcc1c2a1SAlex Deucher radeon_fb = to_radeon_framebuffer(crtc->fb); 10794dd19b0dSChris Ball target_fb = crtc->fb; 10804dd19b0dSChris Ball } 1081bcc1c2a1SAlex Deucher 10824dd19b0dSChris Ball /* If atomic, assume fb object is pinned & idle & fenced and 10834dd19b0dSChris Ball * just update base pointers 10844dd19b0dSChris Ball */ 1085bcc1c2a1SAlex Deucher obj = radeon_fb->obj; 10867e4d15d9SDaniel Vetter rbo = gem_to_radeon_bo(obj); 1087bcc1c2a1SAlex Deucher r = radeon_bo_reserve(rbo, false); 1088bcc1c2a1SAlex Deucher if (unlikely(r != 0)) 1089bcc1c2a1SAlex Deucher return r; 10904dd19b0dSChris Ball 10914dd19b0dSChris Ball if (atomic) 10924dd19b0dSChris Ball fb_location = radeon_bo_gpu_offset(rbo); 10934dd19b0dSChris Ball else { 1094bcc1c2a1SAlex Deucher r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); 1095bcc1c2a1SAlex Deucher if (unlikely(r != 0)) { 1096bcc1c2a1SAlex Deucher radeon_bo_unreserve(rbo); 1097bcc1c2a1SAlex Deucher return -EINVAL; 1098bcc1c2a1SAlex Deucher } 10994dd19b0dSChris Ball } 11004dd19b0dSChris Ball 1101bcc1c2a1SAlex Deucher radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); 1102bcc1c2a1SAlex Deucher radeon_bo_unreserve(rbo); 1103bcc1c2a1SAlex Deucher 11044dd19b0dSChris Ball switch (target_fb->bits_per_pixel) { 1105bcc1c2a1SAlex Deucher case 8: 1106bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP) | 1107bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED)); 1108bcc1c2a1SAlex Deucher break; 1109bcc1c2a1SAlex Deucher case 15: 1110bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 1111bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB1555)); 1112bcc1c2a1SAlex Deucher break; 1113bcc1c2a1SAlex Deucher case 16: 1114bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 1115bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565)); 1116fa6bee46SAlex Deucher #ifdef __BIG_ENDIAN 1117fa6bee46SAlex Deucher fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16); 1118fa6bee46SAlex Deucher #endif 1119bcc1c2a1SAlex Deucher break; 1120bcc1c2a1SAlex Deucher case 24: 1121bcc1c2a1SAlex Deucher case 32: 1122bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) | 1123bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888)); 1124fa6bee46SAlex Deucher #ifdef __BIG_ENDIAN 1125fa6bee46SAlex Deucher fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32); 1126fa6bee46SAlex Deucher #endif 1127bcc1c2a1SAlex Deucher break; 1128bcc1c2a1SAlex Deucher default: 1129bcc1c2a1SAlex Deucher DRM_ERROR("Unsupported screen depth %d\n", 11304dd19b0dSChris Ball target_fb->bits_per_pixel); 1131bcc1c2a1SAlex Deucher return -EINVAL; 1132bcc1c2a1SAlex Deucher } 1133bcc1c2a1SAlex Deucher 113497d66328SAlex Deucher if (tiling_flags & RADEON_TILING_MACRO) 113597d66328SAlex Deucher fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1); 113697d66328SAlex Deucher else if (tiling_flags & RADEON_TILING_MICRO) 113797d66328SAlex Deucher fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1); 113897d66328SAlex Deucher 1139bcc1c2a1SAlex Deucher switch (radeon_crtc->crtc_id) { 1140bcc1c2a1SAlex Deucher case 0: 1141bcc1c2a1SAlex Deucher WREG32(AVIVO_D1VGA_CONTROL, 0); 1142bcc1c2a1SAlex Deucher break; 1143bcc1c2a1SAlex Deucher case 1: 1144bcc1c2a1SAlex Deucher WREG32(AVIVO_D2VGA_CONTROL, 0); 1145bcc1c2a1SAlex Deucher break; 1146bcc1c2a1SAlex Deucher case 2: 1147bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D3VGA_CONTROL, 0); 1148bcc1c2a1SAlex Deucher break; 1149bcc1c2a1SAlex Deucher case 3: 1150bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D4VGA_CONTROL, 0); 1151bcc1c2a1SAlex Deucher break; 1152bcc1c2a1SAlex Deucher case 4: 1153bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D5VGA_CONTROL, 0); 1154bcc1c2a1SAlex Deucher break; 1155bcc1c2a1SAlex Deucher case 5: 1156bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D6VGA_CONTROL, 0); 1157bcc1c2a1SAlex Deucher break; 1158bcc1c2a1SAlex Deucher default: 1159bcc1c2a1SAlex Deucher break; 1160bcc1c2a1SAlex Deucher } 1161bcc1c2a1SAlex Deucher 1162bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 1163bcc1c2a1SAlex Deucher upper_32_bits(fb_location)); 1164bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 1165bcc1c2a1SAlex Deucher upper_32_bits(fb_location)); 1166bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 1167bcc1c2a1SAlex Deucher (u32)fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK); 1168bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 1169bcc1c2a1SAlex Deucher (u32) fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK); 1170bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); 1171fa6bee46SAlex Deucher WREG32(EVERGREEN_GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap); 1172bcc1c2a1SAlex Deucher 1173bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); 1174bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); 1175bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_X_START + radeon_crtc->crtc_offset, 0); 1176bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_Y_START + radeon_crtc->crtc_offset, 0); 11774dd19b0dSChris Ball WREG32(EVERGREEN_GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width); 11784dd19b0dSChris Ball WREG32(EVERGREEN_GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height); 1179bcc1c2a1SAlex Deucher 11804dd19b0dSChris Ball fb_pitch_pixels = target_fb->pitch / (target_fb->bits_per_pixel / 8); 1181bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); 1182bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1); 1183bcc1c2a1SAlex Deucher 1184bcc1c2a1SAlex Deucher WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, 1185bcc1c2a1SAlex Deucher crtc->mode.vdisplay); 1186bcc1c2a1SAlex Deucher x &= ~3; 1187bcc1c2a1SAlex Deucher y &= ~1; 1188bcc1c2a1SAlex Deucher WREG32(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset, 1189bcc1c2a1SAlex Deucher (x << 16) | y); 1190bcc1c2a1SAlex Deucher WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset, 1191bcc1c2a1SAlex Deucher (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay); 1192bcc1c2a1SAlex Deucher 1193fb9674bdSAlex Deucher /* pageflip setup */ 1194fb9674bdSAlex Deucher /* make sure flip is at vb rather than hb */ 1195fb9674bdSAlex Deucher tmp = RREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset); 1196fb9674bdSAlex Deucher tmp &= ~EVERGREEN_GRPH_SURFACE_UPDATE_H_RETRACE_EN; 1197fb9674bdSAlex Deucher WREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, tmp); 1198fb9674bdSAlex Deucher 1199fb9674bdSAlex Deucher /* set pageflip to happen anywhere in vblank interval */ 1200fb9674bdSAlex Deucher WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); 1201fb9674bdSAlex Deucher 12024dd19b0dSChris Ball if (!atomic && fb && fb != crtc->fb) { 12034dd19b0dSChris Ball radeon_fb = to_radeon_framebuffer(fb); 12047e4d15d9SDaniel Vetter rbo = gem_to_radeon_bo(radeon_fb->obj); 1205bcc1c2a1SAlex Deucher r = radeon_bo_reserve(rbo, false); 1206bcc1c2a1SAlex Deucher if (unlikely(r != 0)) 1207bcc1c2a1SAlex Deucher return r; 1208bcc1c2a1SAlex Deucher radeon_bo_unpin(rbo); 1209bcc1c2a1SAlex Deucher radeon_bo_unreserve(rbo); 1210bcc1c2a1SAlex Deucher } 1211bcc1c2a1SAlex Deucher 1212bcc1c2a1SAlex Deucher /* Bytes per pixel may have changed */ 1213bcc1c2a1SAlex Deucher radeon_bandwidth_update(rdev); 1214bcc1c2a1SAlex Deucher 1215bcc1c2a1SAlex Deucher return 0; 1216bcc1c2a1SAlex Deucher } 1217bcc1c2a1SAlex Deucher 12184dd19b0dSChris Ball static int avivo_crtc_do_set_base(struct drm_crtc *crtc, 12194dd19b0dSChris Ball struct drm_framebuffer *fb, 12204dd19b0dSChris Ball int x, int y, int atomic) 1221771fe6b9SJerome Glisse { 1222771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1223771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 1224771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 1225771fe6b9SJerome Glisse struct radeon_framebuffer *radeon_fb; 1226771fe6b9SJerome Glisse struct drm_gem_object *obj; 12274c788679SJerome Glisse struct radeon_bo *rbo; 12284dd19b0dSChris Ball struct drm_framebuffer *target_fb; 1229771fe6b9SJerome Glisse uint64_t fb_location; 1230e024e110SDave Airlie uint32_t fb_format, fb_pitch_pixels, tiling_flags; 1231fa6bee46SAlex Deucher u32 fb_swap = R600_D1GRPH_SWAP_ENDIAN_NONE; 1232fb9674bdSAlex Deucher u32 tmp; 12334c788679SJerome Glisse int r; 1234771fe6b9SJerome Glisse 12352de3b484SJerome Glisse /* no fb bound */ 12364dd19b0dSChris Ball if (!atomic && !crtc->fb) { 1237d9fdaafbSDave Airlie DRM_DEBUG_KMS("No FB bound\n"); 12382de3b484SJerome Glisse return 0; 12392de3b484SJerome Glisse } 1240771fe6b9SJerome Glisse 12414dd19b0dSChris Ball if (atomic) { 12424dd19b0dSChris Ball radeon_fb = to_radeon_framebuffer(fb); 12434dd19b0dSChris Ball target_fb = fb; 12444dd19b0dSChris Ball } 12454dd19b0dSChris Ball else { 1246771fe6b9SJerome Glisse radeon_fb = to_radeon_framebuffer(crtc->fb); 12474dd19b0dSChris Ball target_fb = crtc->fb; 12484dd19b0dSChris Ball } 1249771fe6b9SJerome Glisse 1250771fe6b9SJerome Glisse obj = radeon_fb->obj; 12517e4d15d9SDaniel Vetter rbo = gem_to_radeon_bo(obj); 12524c788679SJerome Glisse r = radeon_bo_reserve(rbo, false); 12534c788679SJerome Glisse if (unlikely(r != 0)) 12544c788679SJerome Glisse return r; 12554dd19b0dSChris Ball 12564dd19b0dSChris Ball /* If atomic, assume fb object is pinned & idle & fenced and 12574dd19b0dSChris Ball * just update base pointers 12584dd19b0dSChris Ball */ 12594dd19b0dSChris Ball if (atomic) 12604dd19b0dSChris Ball fb_location = radeon_bo_gpu_offset(rbo); 12614dd19b0dSChris Ball else { 12624c788679SJerome Glisse r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); 12634c788679SJerome Glisse if (unlikely(r != 0)) { 12644c788679SJerome Glisse radeon_bo_unreserve(rbo); 1265771fe6b9SJerome Glisse return -EINVAL; 1266771fe6b9SJerome Glisse } 12674dd19b0dSChris Ball } 12684c788679SJerome Glisse radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); 12694c788679SJerome Glisse radeon_bo_unreserve(rbo); 1270771fe6b9SJerome Glisse 12714dd19b0dSChris Ball switch (target_fb->bits_per_pixel) { 127241456df2SDave Airlie case 8: 127341456df2SDave Airlie fb_format = 127441456df2SDave Airlie AVIVO_D1GRPH_CONTROL_DEPTH_8BPP | 127541456df2SDave Airlie AVIVO_D1GRPH_CONTROL_8BPP_INDEXED; 127641456df2SDave Airlie break; 1277771fe6b9SJerome Glisse case 15: 1278771fe6b9SJerome Glisse fb_format = 1279771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | 1280771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555; 1281771fe6b9SJerome Glisse break; 1282771fe6b9SJerome Glisse case 16: 1283771fe6b9SJerome Glisse fb_format = 1284771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | 1285771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_16BPP_RGB565; 1286fa6bee46SAlex Deucher #ifdef __BIG_ENDIAN 1287fa6bee46SAlex Deucher fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT; 1288fa6bee46SAlex Deucher #endif 1289771fe6b9SJerome Glisse break; 1290771fe6b9SJerome Glisse case 24: 1291771fe6b9SJerome Glisse case 32: 1292771fe6b9SJerome Glisse fb_format = 1293771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_32BPP | 1294771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888; 1295fa6bee46SAlex Deucher #ifdef __BIG_ENDIAN 1296fa6bee46SAlex Deucher fb_swap = R600_D1GRPH_SWAP_ENDIAN_32BIT; 1297fa6bee46SAlex Deucher #endif 1298771fe6b9SJerome Glisse break; 1299771fe6b9SJerome Glisse default: 1300771fe6b9SJerome Glisse DRM_ERROR("Unsupported screen depth %d\n", 13014dd19b0dSChris Ball target_fb->bits_per_pixel); 1302771fe6b9SJerome Glisse return -EINVAL; 1303771fe6b9SJerome Glisse } 1304771fe6b9SJerome Glisse 130540c4ac1cSAlex Deucher if (rdev->family >= CHIP_R600) { 130640c4ac1cSAlex Deucher if (tiling_flags & RADEON_TILING_MACRO) 130740c4ac1cSAlex Deucher fb_format |= R600_D1GRPH_ARRAY_MODE_2D_TILED_THIN1; 130840c4ac1cSAlex Deucher else if (tiling_flags & RADEON_TILING_MICRO) 130940c4ac1cSAlex Deucher fb_format |= R600_D1GRPH_ARRAY_MODE_1D_TILED_THIN1; 131040c4ac1cSAlex Deucher } else { 1311cf2f05d3SDave Airlie if (tiling_flags & RADEON_TILING_MACRO) 1312cf2f05d3SDave Airlie fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE; 1313cf2f05d3SDave Airlie 1314e024e110SDave Airlie if (tiling_flags & RADEON_TILING_MICRO) 1315e024e110SDave Airlie fb_format |= AVIVO_D1GRPH_TILED; 131640c4ac1cSAlex Deucher } 1317e024e110SDave Airlie 1318771fe6b9SJerome Glisse if (radeon_crtc->crtc_id == 0) 1319771fe6b9SJerome Glisse WREG32(AVIVO_D1VGA_CONTROL, 0); 1320771fe6b9SJerome Glisse else 1321771fe6b9SJerome Glisse WREG32(AVIVO_D2VGA_CONTROL, 0); 1322c290dadfSAlex Deucher 1323c290dadfSAlex Deucher if (rdev->family >= CHIP_RV770) { 1324c290dadfSAlex Deucher if (radeon_crtc->crtc_id) { 132595347871SAlex Deucher WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 132695347871SAlex Deucher WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 1327c290dadfSAlex Deucher } else { 132895347871SAlex Deucher WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 132995347871SAlex Deucher WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 1330c290dadfSAlex Deucher } 1331c290dadfSAlex Deucher } 1332771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 1333771fe6b9SJerome Glisse (u32) fb_location); 1334771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + 1335771fe6b9SJerome Glisse radeon_crtc->crtc_offset, (u32) fb_location); 1336771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); 1337fa6bee46SAlex Deucher if (rdev->family >= CHIP_R600) 1338fa6bee46SAlex Deucher WREG32(R600_D1GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap); 1339771fe6b9SJerome Glisse 1340771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); 1341771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); 1342771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0); 1343771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, 0); 13444dd19b0dSChris Ball WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width); 13454dd19b0dSChris Ball WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height); 1346771fe6b9SJerome Glisse 13474dd19b0dSChris Ball fb_pitch_pixels = target_fb->pitch / (target_fb->bits_per_pixel / 8); 1348771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); 1349771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1); 1350771fe6b9SJerome Glisse 1351771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, 1352771fe6b9SJerome Glisse crtc->mode.vdisplay); 1353771fe6b9SJerome Glisse x &= ~3; 1354771fe6b9SJerome Glisse y &= ~1; 1355771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset, 1356771fe6b9SJerome Glisse (x << 16) | y); 1357771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset, 1358771fe6b9SJerome Glisse (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay); 1359771fe6b9SJerome Glisse 1360fb9674bdSAlex Deucher /* pageflip setup */ 1361fb9674bdSAlex Deucher /* make sure flip is at vb rather than hb */ 1362fb9674bdSAlex Deucher tmp = RREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset); 1363fb9674bdSAlex Deucher tmp &= ~AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN; 1364fb9674bdSAlex Deucher WREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, tmp); 1365fb9674bdSAlex Deucher 1366fb9674bdSAlex Deucher /* set pageflip to happen anywhere in vblank interval */ 1367fb9674bdSAlex Deucher WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); 1368fb9674bdSAlex Deucher 13694dd19b0dSChris Ball if (!atomic && fb && fb != crtc->fb) { 13704dd19b0dSChris Ball radeon_fb = to_radeon_framebuffer(fb); 13717e4d15d9SDaniel Vetter rbo = gem_to_radeon_bo(radeon_fb->obj); 13724c788679SJerome Glisse r = radeon_bo_reserve(rbo, false); 13734c788679SJerome Glisse if (unlikely(r != 0)) 13744c788679SJerome Glisse return r; 13754c788679SJerome Glisse radeon_bo_unpin(rbo); 13764c788679SJerome Glisse radeon_bo_unreserve(rbo); 1377771fe6b9SJerome Glisse } 1378f30f37deSMichel Dänzer 1379f30f37deSMichel Dänzer /* Bytes per pixel may have changed */ 1380f30f37deSMichel Dänzer radeon_bandwidth_update(rdev); 1381f30f37deSMichel Dänzer 1382771fe6b9SJerome Glisse return 0; 1383771fe6b9SJerome Glisse } 1384771fe6b9SJerome Glisse 138554f088a9SAlex Deucher int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, 138654f088a9SAlex Deucher struct drm_framebuffer *old_fb) 138754f088a9SAlex Deucher { 138854f088a9SAlex Deucher struct drm_device *dev = crtc->dev; 138954f088a9SAlex Deucher struct radeon_device *rdev = dev->dev_private; 139054f088a9SAlex Deucher 1391bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) 1392c9417bddSAlex Deucher return dce4_crtc_do_set_base(crtc, old_fb, x, y, 0); 1393bcc1c2a1SAlex Deucher else if (ASIC_IS_AVIVO(rdev)) 13944dd19b0dSChris Ball return avivo_crtc_do_set_base(crtc, old_fb, x, y, 0); 139554f088a9SAlex Deucher else 13964dd19b0dSChris Ball return radeon_crtc_do_set_base(crtc, old_fb, x, y, 0); 13974dd19b0dSChris Ball } 13984dd19b0dSChris Ball 13994dd19b0dSChris Ball int atombios_crtc_set_base_atomic(struct drm_crtc *crtc, 14004dd19b0dSChris Ball struct drm_framebuffer *fb, 140121c74a8eSJason Wessel int x, int y, enum mode_set_atomic state) 14024dd19b0dSChris Ball { 14034dd19b0dSChris Ball struct drm_device *dev = crtc->dev; 14044dd19b0dSChris Ball struct radeon_device *rdev = dev->dev_private; 14054dd19b0dSChris Ball 14064dd19b0dSChris Ball if (ASIC_IS_DCE4(rdev)) 1407c9417bddSAlex Deucher return dce4_crtc_do_set_base(crtc, fb, x, y, 1); 14084dd19b0dSChris Ball else if (ASIC_IS_AVIVO(rdev)) 14094dd19b0dSChris Ball return avivo_crtc_do_set_base(crtc, fb, x, y, 1); 14104dd19b0dSChris Ball else 14114dd19b0dSChris Ball return radeon_crtc_do_set_base(crtc, fb, x, y, 1); 141254f088a9SAlex Deucher } 141354f088a9SAlex Deucher 1414615e0cb6SAlex Deucher /* properly set additional regs when using atombios */ 1415615e0cb6SAlex Deucher static void radeon_legacy_atom_fixup(struct drm_crtc *crtc) 1416615e0cb6SAlex Deucher { 1417615e0cb6SAlex Deucher struct drm_device *dev = crtc->dev; 1418615e0cb6SAlex Deucher struct radeon_device *rdev = dev->dev_private; 1419615e0cb6SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1420615e0cb6SAlex Deucher u32 disp_merge_cntl; 1421615e0cb6SAlex Deucher 1422615e0cb6SAlex Deucher switch (radeon_crtc->crtc_id) { 1423615e0cb6SAlex Deucher case 0: 1424615e0cb6SAlex Deucher disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL); 1425615e0cb6SAlex Deucher disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; 1426615e0cb6SAlex Deucher WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl); 1427615e0cb6SAlex Deucher break; 1428615e0cb6SAlex Deucher case 1: 1429615e0cb6SAlex Deucher disp_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL); 1430615e0cb6SAlex Deucher disp_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN; 1431615e0cb6SAlex Deucher WREG32(RADEON_DISP2_MERGE_CNTL, disp_merge_cntl); 1432615e0cb6SAlex Deucher WREG32(RADEON_FP_H2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_H_SYNC_STRT_WID)); 1433615e0cb6SAlex Deucher WREG32(RADEON_FP_V2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_V_SYNC_STRT_WID)); 1434615e0cb6SAlex Deucher break; 1435615e0cb6SAlex Deucher } 1436615e0cb6SAlex Deucher } 1437615e0cb6SAlex Deucher 1438bcc1c2a1SAlex Deucher static int radeon_atom_pick_pll(struct drm_crtc *crtc) 1439bcc1c2a1SAlex Deucher { 1440bcc1c2a1SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1441bcc1c2a1SAlex Deucher struct drm_device *dev = crtc->dev; 1442bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 1443bcc1c2a1SAlex Deucher struct drm_encoder *test_encoder; 1444bcc1c2a1SAlex Deucher struct drm_crtc *test_crtc; 1445bcc1c2a1SAlex Deucher uint32_t pll_in_use = 0; 1446bcc1c2a1SAlex Deucher 1447bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) { 1448bcc1c2a1SAlex Deucher list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { 1449bcc1c2a1SAlex Deucher if (test_encoder->crtc && (test_encoder->crtc == crtc)) { 145086a94defSAlex Deucher /* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock, 145186a94defSAlex Deucher * depending on the asic: 145286a94defSAlex Deucher * DCE4: PPLL or ext clock 145386a94defSAlex Deucher * DCE5: DCPLL or ext clock 145486a94defSAlex Deucher * 145586a94defSAlex Deucher * Setting ATOM_PPLL_INVALID will cause SetPixelClock to skip 145686a94defSAlex Deucher * PPLL/DCPLL programming and only program the DP DTO for the 145786a94defSAlex Deucher * crtc virtual pixel clock. 145886a94defSAlex Deucher */ 1459bcc1c2a1SAlex Deucher if (atombios_get_encoder_mode(test_encoder) == ATOM_ENCODER_MODE_DP) { 146086a94defSAlex Deucher if (ASIC_IS_DCE5(rdev) || rdev->clock.dp_extclk) 1461bcc1c2a1SAlex Deucher return ATOM_PPLL_INVALID; 1462bcc1c2a1SAlex Deucher } 1463bcc1c2a1SAlex Deucher } 1464bcc1c2a1SAlex Deucher } 1465bcc1c2a1SAlex Deucher 1466bcc1c2a1SAlex Deucher /* otherwise, pick one of the plls */ 1467bcc1c2a1SAlex Deucher list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { 1468bcc1c2a1SAlex Deucher struct radeon_crtc *radeon_test_crtc; 1469bcc1c2a1SAlex Deucher 1470bcc1c2a1SAlex Deucher if (crtc == test_crtc) 1471bcc1c2a1SAlex Deucher continue; 1472bcc1c2a1SAlex Deucher 1473bcc1c2a1SAlex Deucher radeon_test_crtc = to_radeon_crtc(test_crtc); 1474bcc1c2a1SAlex Deucher if ((radeon_test_crtc->pll_id >= ATOM_PPLL1) && 1475bcc1c2a1SAlex Deucher (radeon_test_crtc->pll_id <= ATOM_PPLL2)) 1476bcc1c2a1SAlex Deucher pll_in_use |= (1 << radeon_test_crtc->pll_id); 1477bcc1c2a1SAlex Deucher } 1478bcc1c2a1SAlex Deucher if (!(pll_in_use & 1)) 1479bcc1c2a1SAlex Deucher return ATOM_PPLL1; 1480bcc1c2a1SAlex Deucher return ATOM_PPLL2; 1481bcc1c2a1SAlex Deucher } else 1482bcc1c2a1SAlex Deucher return radeon_crtc->crtc_id; 1483bcc1c2a1SAlex Deucher 1484bcc1c2a1SAlex Deucher } 1485bcc1c2a1SAlex Deucher 1486771fe6b9SJerome Glisse int atombios_crtc_mode_set(struct drm_crtc *crtc, 1487771fe6b9SJerome Glisse struct drm_display_mode *mode, 1488771fe6b9SJerome Glisse struct drm_display_mode *adjusted_mode, 1489771fe6b9SJerome Glisse int x, int y, struct drm_framebuffer *old_fb) 1490771fe6b9SJerome Glisse { 1491771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1492771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 1493771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 149454bfe496SAlex Deucher struct drm_encoder *encoder; 149554bfe496SAlex Deucher bool is_tvcv = false; 1496771fe6b9SJerome Glisse 149754bfe496SAlex Deucher list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 149854bfe496SAlex Deucher /* find tv std */ 149954bfe496SAlex Deucher if (encoder->crtc == crtc) { 150054bfe496SAlex Deucher struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 150154bfe496SAlex Deucher if (radeon_encoder->active_device & 150254bfe496SAlex Deucher (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) 150354bfe496SAlex Deucher is_tvcv = true; 150454bfe496SAlex Deucher } 150554bfe496SAlex Deucher } 1506771fe6b9SJerome Glisse 1507bcc1c2a1SAlex Deucher /* always set DCPLL */ 1508ba032a58SAlex Deucher if (ASIC_IS_DCE4(rdev)) { 1509ba032a58SAlex Deucher struct radeon_atom_ss ss; 1510ba032a58SAlex Deucher bool ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &ss, 1511ba032a58SAlex Deucher ASIC_INTERNAL_SS_ON_DCPLL, 1512ba032a58SAlex Deucher rdev->clock.default_dispclk); 1513ba032a58SAlex Deucher if (ss_enabled) 1514ba032a58SAlex Deucher atombios_crtc_program_ss(crtc, ATOM_DISABLE, ATOM_DCPLL, &ss); 1515f82b3ddcSAlex Deucher /* XXX: DCE5, make sure voltage, dispclk is high enough */ 1516f82b3ddcSAlex Deucher atombios_crtc_set_dcpll(crtc, rdev->clock.default_dispclk); 1517ba032a58SAlex Deucher if (ss_enabled) 1518ba032a58SAlex Deucher atombios_crtc_program_ss(crtc, ATOM_ENABLE, ATOM_DCPLL, &ss); 1519ba032a58SAlex Deucher } 1520771fe6b9SJerome Glisse atombios_crtc_set_pll(crtc, adjusted_mode); 1521771fe6b9SJerome Glisse 152254bfe496SAlex Deucher if (ASIC_IS_DCE4(rdev)) 1523bcc1c2a1SAlex Deucher atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 152454bfe496SAlex Deucher else if (ASIC_IS_AVIVO(rdev)) { 152554bfe496SAlex Deucher if (is_tvcv) 152654bfe496SAlex Deucher atombios_crtc_set_timing(crtc, adjusted_mode); 152754bfe496SAlex Deucher else 152854bfe496SAlex Deucher atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 152954bfe496SAlex Deucher } else { 1530bcc1c2a1SAlex Deucher atombios_crtc_set_timing(crtc, adjusted_mode); 15315a9bcaccSAlex Deucher if (radeon_crtc->crtc_id == 0) 15325a9bcaccSAlex Deucher atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 1533615e0cb6SAlex Deucher radeon_legacy_atom_fixup(crtc); 1534771fe6b9SJerome Glisse } 1535bcc1c2a1SAlex Deucher atombios_crtc_set_base(crtc, x, y, old_fb); 1536c93bb85bSJerome Glisse atombios_overscan_setup(crtc, mode, adjusted_mode); 1537c93bb85bSJerome Glisse atombios_scaler_setup(crtc); 1538771fe6b9SJerome Glisse return 0; 1539771fe6b9SJerome Glisse } 1540771fe6b9SJerome Glisse 1541771fe6b9SJerome Glisse static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, 1542771fe6b9SJerome Glisse struct drm_display_mode *mode, 1543771fe6b9SJerome Glisse struct drm_display_mode *adjusted_mode) 1544771fe6b9SJerome Glisse { 154503214bd5SAlex Deucher struct drm_device *dev = crtc->dev; 154603214bd5SAlex Deucher struct radeon_device *rdev = dev->dev_private; 154703214bd5SAlex Deucher 154803214bd5SAlex Deucher /* adjust pm to upcoming mode change */ 154903214bd5SAlex Deucher radeon_pm_compute_clocks(rdev); 155003214bd5SAlex Deucher 1551c93bb85bSJerome Glisse if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) 1552c93bb85bSJerome Glisse return false; 1553771fe6b9SJerome Glisse return true; 1554771fe6b9SJerome Glisse } 1555771fe6b9SJerome Glisse 1556771fe6b9SJerome Glisse static void atombios_crtc_prepare(struct drm_crtc *crtc) 1557771fe6b9SJerome Glisse { 1558267364acSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1559267364acSAlex Deucher 1560267364acSAlex Deucher /* pick pll */ 1561267364acSAlex Deucher radeon_crtc->pll_id = radeon_atom_pick_pll(crtc); 1562267364acSAlex Deucher 156337b4390eSAlex Deucher atombios_lock_crtc(crtc, ATOM_ENABLE); 1564a348c84dSAlex Deucher atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 1565771fe6b9SJerome Glisse } 1566771fe6b9SJerome Glisse 1567771fe6b9SJerome Glisse static void atombios_crtc_commit(struct drm_crtc *crtc) 1568771fe6b9SJerome Glisse { 1569771fe6b9SJerome Glisse atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON); 157037b4390eSAlex Deucher atombios_lock_crtc(crtc, ATOM_DISABLE); 1571771fe6b9SJerome Glisse } 1572771fe6b9SJerome Glisse 157337f9003bSAlex Deucher static void atombios_crtc_disable(struct drm_crtc *crtc) 157437f9003bSAlex Deucher { 157537f9003bSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 15768e8e523dSAlex Deucher struct radeon_atom_ss ss; 15778e8e523dSAlex Deucher 157837f9003bSAlex Deucher atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 157937f9003bSAlex Deucher 158037f9003bSAlex Deucher switch (radeon_crtc->pll_id) { 158137f9003bSAlex Deucher case ATOM_PPLL1: 158237f9003bSAlex Deucher case ATOM_PPLL2: 158337f9003bSAlex Deucher /* disable the ppll */ 158437f9003bSAlex Deucher atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, 15858e8e523dSAlex Deucher 0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss); 158637f9003bSAlex Deucher break; 158737f9003bSAlex Deucher default: 158837f9003bSAlex Deucher break; 158937f9003bSAlex Deucher } 159037f9003bSAlex Deucher radeon_crtc->pll_id = -1; 159137f9003bSAlex Deucher } 159237f9003bSAlex Deucher 1593771fe6b9SJerome Glisse static const struct drm_crtc_helper_funcs atombios_helper_funcs = { 1594771fe6b9SJerome Glisse .dpms = atombios_crtc_dpms, 1595771fe6b9SJerome Glisse .mode_fixup = atombios_crtc_mode_fixup, 1596771fe6b9SJerome Glisse .mode_set = atombios_crtc_mode_set, 1597771fe6b9SJerome Glisse .mode_set_base = atombios_crtc_set_base, 15984dd19b0dSChris Ball .mode_set_base_atomic = atombios_crtc_set_base_atomic, 1599771fe6b9SJerome Glisse .prepare = atombios_crtc_prepare, 1600771fe6b9SJerome Glisse .commit = atombios_crtc_commit, 1601068143d3SDave Airlie .load_lut = radeon_crtc_load_lut, 160237f9003bSAlex Deucher .disable = atombios_crtc_disable, 1603771fe6b9SJerome Glisse }; 1604771fe6b9SJerome Glisse 1605771fe6b9SJerome Glisse void radeon_atombios_init_crtc(struct drm_device *dev, 1606771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc) 1607771fe6b9SJerome Glisse { 1608bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 1609bcc1c2a1SAlex Deucher 1610bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) { 1611bcc1c2a1SAlex Deucher switch (radeon_crtc->crtc_id) { 1612bcc1c2a1SAlex Deucher case 0: 1613bcc1c2a1SAlex Deucher default: 161412d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC0_REGISTER_OFFSET; 1615bcc1c2a1SAlex Deucher break; 1616bcc1c2a1SAlex Deucher case 1: 161712d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC1_REGISTER_OFFSET; 1618bcc1c2a1SAlex Deucher break; 1619bcc1c2a1SAlex Deucher case 2: 162012d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC2_REGISTER_OFFSET; 1621bcc1c2a1SAlex Deucher break; 1622bcc1c2a1SAlex Deucher case 3: 162312d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC3_REGISTER_OFFSET; 1624bcc1c2a1SAlex Deucher break; 1625bcc1c2a1SAlex Deucher case 4: 162612d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC4_REGISTER_OFFSET; 1627bcc1c2a1SAlex Deucher break; 1628bcc1c2a1SAlex Deucher case 5: 162912d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC5_REGISTER_OFFSET; 1630bcc1c2a1SAlex Deucher break; 1631bcc1c2a1SAlex Deucher } 1632bcc1c2a1SAlex Deucher } else { 1633771fe6b9SJerome Glisse if (radeon_crtc->crtc_id == 1) 1634771fe6b9SJerome Glisse radeon_crtc->crtc_offset = 1635771fe6b9SJerome Glisse AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL; 1636bcc1c2a1SAlex Deucher else 1637bcc1c2a1SAlex Deucher radeon_crtc->crtc_offset = 0; 1638bcc1c2a1SAlex Deucher } 1639bcc1c2a1SAlex Deucher radeon_crtc->pll_id = -1; 1640771fe6b9SJerome Glisse drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); 1641771fe6b9SJerome Glisse } 1642