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: 51c93bb85bSJerome Glisse args.usOverscanTop = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2; 52c93bb85bSJerome Glisse args.usOverscanBottom = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2; 53c93bb85bSJerome Glisse args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2; 54c93bb85bSJerome Glisse args.usOverscanRight = (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) { 61c93bb85bSJerome Glisse args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2; 62c93bb85bSJerome Glisse args.usOverscanRight = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2; 63c93bb85bSJerome Glisse } else if (a2 > a1) { 64c93bb85bSJerome Glisse args.usOverscanLeft = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2; 65c93bb85bSJerome Glisse args.usOverscanRight = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2; 66c93bb85bSJerome Glisse } 67c93bb85bSJerome Glisse break; 68c93bb85bSJerome Glisse case RMX_FULL: 69c93bb85bSJerome Glisse default: 705b1714d3SAlex Deucher args.usOverscanRight = radeon_crtc->h_border; 715b1714d3SAlex Deucher args.usOverscanLeft = radeon_crtc->h_border; 725b1714d3SAlex Deucher args.usOverscanBottom = radeon_crtc->v_border; 735b1714d3SAlex Deucher args.usOverscanTop = 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)) { 422a572eaa3SAlex Deucher args.v3.usSpreadSpectrumAmountFrac = 0; 423a572eaa3SAlex Deucher args.v3.ucSpreadSpectrumType = ss->type; 424a572eaa3SAlex Deucher switch (pll_id) { 425a572eaa3SAlex Deucher case ATOM_PPLL1: 426a572eaa3SAlex Deucher args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL; 427a572eaa3SAlex Deucher args.v3.usSpreadSpectrumAmount = ss->amount; 428a572eaa3SAlex Deucher args.v3.usSpreadSpectrumStep = ss->step; 429a572eaa3SAlex Deucher break; 430a572eaa3SAlex Deucher case ATOM_PPLL2: 431a572eaa3SAlex Deucher args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL; 432a572eaa3SAlex Deucher args.v3.usSpreadSpectrumAmount = ss->amount; 433a572eaa3SAlex Deucher args.v3.usSpreadSpectrumStep = ss->step; 434a572eaa3SAlex Deucher break; 435a572eaa3SAlex Deucher case ATOM_DCPLL: 436a572eaa3SAlex Deucher args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL; 437a572eaa3SAlex Deucher args.v3.usSpreadSpectrumAmount = 0; 438a572eaa3SAlex Deucher args.v3.usSpreadSpectrumStep = 0; 439a572eaa3SAlex Deucher break; 440a572eaa3SAlex Deucher case ATOM_PPLL_INVALID: 441a572eaa3SAlex Deucher return; 442a572eaa3SAlex Deucher } 443a572eaa3SAlex Deucher args.v2.ucEnable = enable; 444a572eaa3SAlex Deucher } else if (ASIC_IS_DCE4(rdev)) { 445ba032a58SAlex Deucher args.v2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); 446ba032a58SAlex Deucher args.v2.ucSpreadSpectrumType = ss->type; 447ba032a58SAlex Deucher switch (pll_id) { 448ba032a58SAlex Deucher case ATOM_PPLL1: 449ba032a58SAlex Deucher args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P1PLL; 450ba032a58SAlex Deucher args.v2.usSpreadSpectrumAmount = ss->amount; 451ba032a58SAlex Deucher args.v2.usSpreadSpectrumStep = ss->step; 452ba032a58SAlex Deucher break; 453ba032a58SAlex Deucher case ATOM_PPLL2: 454ba032a58SAlex Deucher args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P2PLL; 455ba032a58SAlex Deucher args.v2.usSpreadSpectrumAmount = ss->amount; 456ba032a58SAlex Deucher args.v2.usSpreadSpectrumStep = ss->step; 457ba032a58SAlex Deucher break; 458ba032a58SAlex Deucher case ATOM_DCPLL: 459ba032a58SAlex Deucher args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_DCPLL; 460ba032a58SAlex Deucher args.v2.usSpreadSpectrumAmount = 0; 461ba032a58SAlex Deucher args.v2.usSpreadSpectrumStep = 0; 462ba032a58SAlex Deucher break; 463ba032a58SAlex Deucher case ATOM_PPLL_INVALID: 464ba032a58SAlex Deucher return; 465ba032a58SAlex Deucher } 466ba032a58SAlex Deucher args.v2.ucEnable = enable; 467ba032a58SAlex Deucher } else if (ASIC_IS_DCE3(rdev)) { 468ba032a58SAlex Deucher args.v1.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); 469ba032a58SAlex Deucher args.v1.ucSpreadSpectrumType = ss->type; 470ba032a58SAlex Deucher args.v1.ucSpreadSpectrumStep = ss->step; 471ba032a58SAlex Deucher args.v1.ucSpreadSpectrumDelay = ss->delay; 472ba032a58SAlex Deucher args.v1.ucSpreadSpectrumRange = ss->range; 473ba032a58SAlex Deucher args.v1.ucPpll = pll_id; 474ba032a58SAlex Deucher args.v1.ucEnable = enable; 475ba032a58SAlex Deucher } else if (ASIC_IS_AVIVO(rdev)) { 476ba032a58SAlex Deucher if (enable == ATOM_DISABLE) { 477ba032a58SAlex Deucher atombios_disable_ss(crtc); 478ba032a58SAlex Deucher return; 479ba032a58SAlex Deucher } 480ba032a58SAlex Deucher args.lvds_ss_2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); 481ba032a58SAlex Deucher args.lvds_ss_2.ucSpreadSpectrumType = ss->type; 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 { 487ba032a58SAlex Deucher if (enable == ATOM_DISABLE) { 488ba032a58SAlex Deucher atombios_disable_ss(crtc); 489ba032a58SAlex Deucher return; 490ba032a58SAlex Deucher } 491ba032a58SAlex Deucher args.lvds_ss.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); 492ba032a58SAlex Deucher args.lvds_ss.ucSpreadSpectrumType = ss->type; 493ba032a58SAlex Deucher args.lvds_ss.ucSpreadSpectrumStepSize_Delay = (ss->step & 3) << 2; 494ba032a58SAlex Deucher args.lvds_ss.ucSpreadSpectrumStepSize_Delay |= (ss->delay & 7) << 4; 495ba032a58SAlex Deucher args.lvds_ss.ucEnable = enable; 496ebbe1cb9SAlex Deucher } 49726b9fc3aSAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 498ebbe1cb9SAlex Deucher } 499ebbe1cb9SAlex Deucher 5004eaeca33SAlex Deucher union adjust_pixel_clock { 5014eaeca33SAlex Deucher ADJUST_DISPLAY_PLL_PS_ALLOCATION v1; 502bcc1c2a1SAlex Deucher ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 v3; 5034eaeca33SAlex Deucher }; 5044eaeca33SAlex Deucher 5054eaeca33SAlex Deucher static u32 atombios_adjust_pll(struct drm_crtc *crtc, 5064eaeca33SAlex Deucher struct drm_display_mode *mode, 507ba032a58SAlex Deucher struct radeon_pll *pll, 508ba032a58SAlex Deucher bool ss_enabled, 509ba032a58SAlex Deucher struct radeon_atom_ss *ss) 510771fe6b9SJerome Glisse { 511771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 512771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 513771fe6b9SJerome Glisse struct drm_encoder *encoder = NULL; 514771fe6b9SJerome Glisse struct radeon_encoder *radeon_encoder = NULL; 5154eaeca33SAlex Deucher u32 adjusted_clock = mode->clock; 516bcc1c2a1SAlex Deucher int encoder_mode = 0; 517fbee67a6SAlex Deucher u32 dp_clock = mode->clock; 518fbee67a6SAlex Deucher int bpc = 8; 519fc10332bSAlex Deucher 5204eaeca33SAlex Deucher /* reset the pll flags */ 5214eaeca33SAlex Deucher pll->flags = 0; 522771fe6b9SJerome Glisse 523771fe6b9SJerome Glisse if (ASIC_IS_AVIVO(rdev)) { 524eb1300bcSAlex Deucher if ((rdev->family == CHIP_RS600) || 525eb1300bcSAlex Deucher (rdev->family == CHIP_RS690) || 526eb1300bcSAlex Deucher (rdev->family == CHIP_RS740)) 5272ff776cfSAlex Deucher pll->flags |= (/*RADEON_PLL_USE_FRAC_FB_DIV |*/ 528eb1300bcSAlex Deucher RADEON_PLL_PREFER_CLOSEST_LOWER); 5295480f727SDave Airlie 5305480f727SDave Airlie if (ASIC_IS_DCE32(rdev) && mode->clock > 200000) /* range limits??? */ 5315480f727SDave Airlie pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; 5325480f727SDave Airlie else 5335480f727SDave Airlie pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; 5345480f727SDave Airlie } else { 535fc10332bSAlex Deucher pll->flags |= RADEON_PLL_LEGACY; 536771fe6b9SJerome Glisse 5375480f727SDave Airlie if (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; 5415480f727SDave Airlie 5425480f727SDave Airlie } 5435480f727SDave Airlie 544771fe6b9SJerome Glisse list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 545771fe6b9SJerome Glisse if (encoder->crtc == crtc) { 5464eaeca33SAlex Deucher radeon_encoder = to_radeon_encoder(encoder); 547bcc1c2a1SAlex Deucher encoder_mode = atombios_get_encoder_mode(encoder); 548fbee67a6SAlex Deucher if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) { 549fbee67a6SAlex Deucher struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); 550fbee67a6SAlex Deucher if (connector) { 551fbee67a6SAlex Deucher struct radeon_connector *radeon_connector = to_radeon_connector(connector); 552fbee67a6SAlex Deucher struct radeon_connector_atom_dig *dig_connector = 553fbee67a6SAlex Deucher radeon_connector->con_priv; 554fbee67a6SAlex Deucher 555fbee67a6SAlex Deucher dp_clock = dig_connector->dp_clock; 556fbee67a6SAlex Deucher } 557fbee67a6SAlex Deucher } 558e5fd205fSAlex Deucher #if 0 /* doesn't work properly on some laptops */ 559ba032a58SAlex Deucher /* use recommended ref_div for ss */ 560ba032a58SAlex Deucher if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 561ba032a58SAlex Deucher if (ss_enabled) { 562ba032a58SAlex Deucher if (ss->refdiv) { 563ba032a58SAlex Deucher pll->flags |= RADEON_PLL_USE_REF_DIV; 564ba032a58SAlex Deucher pll->reference_div = ss->refdiv; 565ba032a58SAlex Deucher } 566ba032a58SAlex Deucher } 567ba032a58SAlex Deucher } 568e5fd205fSAlex Deucher #endif 5694eaeca33SAlex Deucher if (ASIC_IS_AVIVO(rdev)) { 5704eaeca33SAlex Deucher /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ 5714eaeca33SAlex Deucher if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1) 5724eaeca33SAlex Deucher adjusted_clock = mode->clock * 2; 57348dfaaebSAlex Deucher if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 574a1a4b23bSAlex Deucher pll->flags |= RADEON_PLL_PREFER_CLOSEST_LOWER; 5754eaeca33SAlex Deucher } else { 5764eaeca33SAlex Deucher if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) 577fc10332bSAlex Deucher pll->flags |= RADEON_PLL_NO_ODD_POST_DIV; 5784eaeca33SAlex Deucher if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) 579fc10332bSAlex Deucher pll->flags |= RADEON_PLL_USE_REF_DIV; 580771fe6b9SJerome Glisse } 5813ce0a23dSJerome Glisse break; 582771fe6b9SJerome Glisse } 583771fe6b9SJerome Glisse } 584771fe6b9SJerome Glisse 5852606c886SAlex Deucher /* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock 5862606c886SAlex Deucher * accordingly based on the encoder/transmitter to work around 5872606c886SAlex Deucher * special hw requirements. 5882606c886SAlex Deucher */ 5892606c886SAlex Deucher if (ASIC_IS_DCE3(rdev)) { 5904eaeca33SAlex Deucher union adjust_pixel_clock args; 5914eaeca33SAlex Deucher u8 frev, crev; 5924eaeca33SAlex Deucher int index; 5932606c886SAlex Deucher 5942606c886SAlex Deucher index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll); 595a084e6eeSAlex Deucher if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 596a084e6eeSAlex Deucher &crev)) 597a084e6eeSAlex Deucher return adjusted_clock; 5984eaeca33SAlex Deucher 5994eaeca33SAlex Deucher memset(&args, 0, sizeof(args)); 6004eaeca33SAlex Deucher 6014eaeca33SAlex Deucher switch (frev) { 6024eaeca33SAlex Deucher case 1: 6034eaeca33SAlex Deucher switch (crev) { 6044eaeca33SAlex Deucher case 1: 6054eaeca33SAlex Deucher case 2: 6064eaeca33SAlex Deucher args.v1.usPixelClock = cpu_to_le16(mode->clock / 10); 6074eaeca33SAlex Deucher args.v1.ucTransmitterID = radeon_encoder->encoder_id; 608bcc1c2a1SAlex Deucher args.v1.ucEncodeMode = encoder_mode; 609fbee67a6SAlex Deucher if (encoder_mode == ATOM_ENCODER_MODE_DP) { 610ba032a58SAlex Deucher if (ss_enabled) 611ba032a58SAlex Deucher args.v1.ucConfig |= 612ba032a58SAlex Deucher ADJUST_DISPLAY_CONFIG_SS_ENABLE; 613fbee67a6SAlex Deucher } else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) { 614fbee67a6SAlex Deucher args.v1.ucConfig |= 615fbee67a6SAlex Deucher ADJUST_DISPLAY_CONFIG_SS_ENABLE; 616fbee67a6SAlex Deucher } 6174eaeca33SAlex Deucher 6182606c886SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, 6194eaeca33SAlex Deucher index, (uint32_t *)&args); 6204eaeca33SAlex Deucher adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10; 6214eaeca33SAlex Deucher break; 622bcc1c2a1SAlex Deucher case 3: 623bcc1c2a1SAlex Deucher args.v3.sInput.usPixelClock = cpu_to_le16(mode->clock / 10); 624bcc1c2a1SAlex Deucher args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id; 625bcc1c2a1SAlex Deucher args.v3.sInput.ucEncodeMode = encoder_mode; 626bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig = 0; 627bcc1c2a1SAlex Deucher if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { 628bcc1c2a1SAlex Deucher struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 629fbee67a6SAlex Deucher if (encoder_mode == ATOM_ENCODER_MODE_DP) { 630ba032a58SAlex Deucher if (ss_enabled) 631ba032a58SAlex Deucher args.v3.sInput.ucDispPllConfig |= 632ba032a58SAlex Deucher DISPPLL_CONFIG_SS_ENABLE; 633bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 634bcc1c2a1SAlex Deucher DISPPLL_CONFIG_COHERENT_MODE; 635fbee67a6SAlex Deucher /* 16200 or 27000 */ 636fbee67a6SAlex Deucher args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); 637fbee67a6SAlex Deucher } else { 638fbee67a6SAlex Deucher if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { 639fbee67a6SAlex Deucher /* deep color support */ 640fbee67a6SAlex Deucher args.v3.sInput.usPixelClock = 641fbee67a6SAlex Deucher cpu_to_le16((mode->clock * bpc / 8) / 10); 642fbee67a6SAlex Deucher } 643bcc1c2a1SAlex Deucher if (dig->coherent_mode) 644bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 645bcc1c2a1SAlex Deucher DISPPLL_CONFIG_COHERENT_MODE; 646bcc1c2a1SAlex Deucher if (mode->clock > 165000) 647bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 648bcc1c2a1SAlex Deucher DISPPLL_CONFIG_DUAL_LINK; 649bcc1c2a1SAlex Deucher } 650bcc1c2a1SAlex Deucher } else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 651fbee67a6SAlex Deucher if (encoder_mode == ATOM_ENCODER_MODE_DP) { 652ba032a58SAlex Deucher if (ss_enabled) 653ba032a58SAlex Deucher args.v3.sInput.ucDispPllConfig |= 654ba032a58SAlex Deucher DISPPLL_CONFIG_SS_ENABLE; 655bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 6569f998ad7SAlex Deucher DISPPLL_CONFIG_COHERENT_MODE; 657fbee67a6SAlex Deucher /* 16200 or 27000 */ 658fbee67a6SAlex Deucher args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); 659fbee67a6SAlex Deucher } else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) { 660ba032a58SAlex Deucher if (ss_enabled) 661ba032a58SAlex Deucher args.v3.sInput.ucDispPllConfig |= 662ba032a58SAlex Deucher DISPPLL_CONFIG_SS_ENABLE; 663fbee67a6SAlex Deucher } else { 664bcc1c2a1SAlex Deucher if (mode->clock > 165000) 665bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 666bcc1c2a1SAlex Deucher DISPPLL_CONFIG_DUAL_LINK; 667bcc1c2a1SAlex Deucher } 6689f998ad7SAlex Deucher } 669bcc1c2a1SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, 670bcc1c2a1SAlex Deucher index, (uint32_t *)&args); 671bcc1c2a1SAlex Deucher adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10; 672bcc1c2a1SAlex Deucher if (args.v3.sOutput.ucRefDiv) { 673bcc1c2a1SAlex Deucher pll->flags |= RADEON_PLL_USE_REF_DIV; 674bcc1c2a1SAlex Deucher pll->reference_div = args.v3.sOutput.ucRefDiv; 675bcc1c2a1SAlex Deucher } 676bcc1c2a1SAlex Deucher if (args.v3.sOutput.ucPostDiv) { 677bcc1c2a1SAlex Deucher pll->flags |= RADEON_PLL_USE_POST_DIV; 678bcc1c2a1SAlex Deucher pll->post_div = args.v3.sOutput.ucPostDiv; 679bcc1c2a1SAlex Deucher } 680bcc1c2a1SAlex Deucher break; 6814eaeca33SAlex Deucher default: 6824eaeca33SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 6834eaeca33SAlex Deucher return adjusted_clock; 684d56ef9c8SAlex Deucher } 6854eaeca33SAlex Deucher break; 6864eaeca33SAlex Deucher default: 6874eaeca33SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 6884eaeca33SAlex Deucher return adjusted_clock; 6894eaeca33SAlex Deucher } 6904eaeca33SAlex Deucher } 6914eaeca33SAlex Deucher return adjusted_clock; 6924eaeca33SAlex Deucher } 6934eaeca33SAlex Deucher 6944eaeca33SAlex Deucher union set_pixel_clock { 6954eaeca33SAlex Deucher SET_PIXEL_CLOCK_PS_ALLOCATION base; 6964eaeca33SAlex Deucher PIXEL_CLOCK_PARAMETERS v1; 6974eaeca33SAlex Deucher PIXEL_CLOCK_PARAMETERS_V2 v2; 6984eaeca33SAlex Deucher PIXEL_CLOCK_PARAMETERS_V3 v3; 699bcc1c2a1SAlex Deucher PIXEL_CLOCK_PARAMETERS_V5 v5; 700f82b3ddcSAlex Deucher PIXEL_CLOCK_PARAMETERS_V6 v6; 7014eaeca33SAlex Deucher }; 7024eaeca33SAlex Deucher 703f82b3ddcSAlex Deucher /* on DCE5, make sure the voltage is high enough to support the 704f82b3ddcSAlex Deucher * required disp clk. 705f82b3ddcSAlex Deucher */ 706f82b3ddcSAlex Deucher static void atombios_crtc_set_dcpll(struct drm_crtc *crtc, 707f82b3ddcSAlex Deucher u32 dispclk) 708bcc1c2a1SAlex Deucher { 709bcc1c2a1SAlex Deucher struct drm_device *dev = crtc->dev; 710bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 711bcc1c2a1SAlex Deucher u8 frev, crev; 712bcc1c2a1SAlex Deucher int index; 713bcc1c2a1SAlex Deucher union set_pixel_clock args; 714bcc1c2a1SAlex Deucher 715bcc1c2a1SAlex Deucher memset(&args, 0, sizeof(args)); 716bcc1c2a1SAlex Deucher 717bcc1c2a1SAlex Deucher index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); 718a084e6eeSAlex Deucher if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 719a084e6eeSAlex Deucher &crev)) 720a084e6eeSAlex Deucher return; 721bcc1c2a1SAlex Deucher 722bcc1c2a1SAlex Deucher switch (frev) { 723bcc1c2a1SAlex Deucher case 1: 724bcc1c2a1SAlex Deucher switch (crev) { 725bcc1c2a1SAlex Deucher case 5: 726bcc1c2a1SAlex Deucher /* if the default dcpll clock is specified, 727bcc1c2a1SAlex Deucher * SetPixelClock provides the dividers 728bcc1c2a1SAlex Deucher */ 729bcc1c2a1SAlex Deucher args.v5.ucCRTC = ATOM_CRTC_INVALID; 730f82b3ddcSAlex Deucher args.v5.usPixelClock = dispclk; 731bcc1c2a1SAlex Deucher args.v5.ucPpll = ATOM_DCPLL; 732bcc1c2a1SAlex Deucher break; 733f82b3ddcSAlex Deucher case 6: 734f82b3ddcSAlex Deucher /* if the default dcpll clock is specified, 735f82b3ddcSAlex Deucher * SetPixelClock provides the dividers 736f82b3ddcSAlex Deucher */ 737f82b3ddcSAlex Deucher args.v6.ulDispEngClkFreq = dispclk; 738f82b3ddcSAlex Deucher args.v6.ucPpll = ATOM_DCPLL; 739f82b3ddcSAlex Deucher break; 740bcc1c2a1SAlex Deucher default: 741bcc1c2a1SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 742bcc1c2a1SAlex Deucher return; 743bcc1c2a1SAlex Deucher } 744bcc1c2a1SAlex Deucher break; 745bcc1c2a1SAlex Deucher default: 746bcc1c2a1SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 747bcc1c2a1SAlex Deucher return; 748bcc1c2a1SAlex Deucher } 749bcc1c2a1SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 750bcc1c2a1SAlex Deucher } 751bcc1c2a1SAlex Deucher 75237f9003bSAlex Deucher static void atombios_crtc_program_pll(struct drm_crtc *crtc, 75337f9003bSAlex Deucher int crtc_id, 75437f9003bSAlex Deucher int pll_id, 75537f9003bSAlex Deucher u32 encoder_mode, 75637f9003bSAlex Deucher u32 encoder_id, 75737f9003bSAlex Deucher u32 clock, 75837f9003bSAlex Deucher u32 ref_div, 75937f9003bSAlex Deucher u32 fb_div, 76037f9003bSAlex Deucher u32 frac_fb_div, 76137f9003bSAlex Deucher u32 post_div) 76237f9003bSAlex Deucher { 76337f9003bSAlex Deucher struct drm_device *dev = crtc->dev; 76437f9003bSAlex Deucher struct radeon_device *rdev = dev->dev_private; 76537f9003bSAlex Deucher u8 frev, crev; 76637f9003bSAlex Deucher int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); 76737f9003bSAlex Deucher union set_pixel_clock args; 76837f9003bSAlex Deucher 76937f9003bSAlex Deucher memset(&args, 0, sizeof(args)); 77037f9003bSAlex Deucher 77137f9003bSAlex Deucher if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 77237f9003bSAlex Deucher &crev)) 77337f9003bSAlex Deucher return; 77437f9003bSAlex Deucher 77537f9003bSAlex Deucher switch (frev) { 77637f9003bSAlex Deucher case 1: 77737f9003bSAlex Deucher switch (crev) { 77837f9003bSAlex Deucher case 1: 77937f9003bSAlex Deucher if (clock == ATOM_DISABLE) 78037f9003bSAlex Deucher return; 78137f9003bSAlex Deucher args.v1.usPixelClock = cpu_to_le16(clock / 10); 78237f9003bSAlex Deucher args.v1.usRefDiv = cpu_to_le16(ref_div); 78337f9003bSAlex Deucher args.v1.usFbDiv = cpu_to_le16(fb_div); 78437f9003bSAlex Deucher args.v1.ucFracFbDiv = frac_fb_div; 78537f9003bSAlex Deucher args.v1.ucPostDiv = post_div; 78637f9003bSAlex Deucher args.v1.ucPpll = pll_id; 78737f9003bSAlex Deucher args.v1.ucCRTC = crtc_id; 78837f9003bSAlex Deucher args.v1.ucRefDivSrc = 1; 78937f9003bSAlex Deucher break; 79037f9003bSAlex Deucher case 2: 79137f9003bSAlex Deucher args.v2.usPixelClock = cpu_to_le16(clock / 10); 79237f9003bSAlex Deucher args.v2.usRefDiv = cpu_to_le16(ref_div); 79337f9003bSAlex Deucher args.v2.usFbDiv = cpu_to_le16(fb_div); 79437f9003bSAlex Deucher args.v2.ucFracFbDiv = frac_fb_div; 79537f9003bSAlex Deucher args.v2.ucPostDiv = post_div; 79637f9003bSAlex Deucher args.v2.ucPpll = pll_id; 79737f9003bSAlex Deucher args.v2.ucCRTC = crtc_id; 79837f9003bSAlex Deucher args.v2.ucRefDivSrc = 1; 79937f9003bSAlex Deucher break; 80037f9003bSAlex Deucher case 3: 80137f9003bSAlex Deucher args.v3.usPixelClock = cpu_to_le16(clock / 10); 80237f9003bSAlex Deucher args.v3.usRefDiv = cpu_to_le16(ref_div); 80337f9003bSAlex Deucher args.v3.usFbDiv = cpu_to_le16(fb_div); 80437f9003bSAlex Deucher args.v3.ucFracFbDiv = frac_fb_div; 80537f9003bSAlex Deucher args.v3.ucPostDiv = post_div; 80637f9003bSAlex Deucher args.v3.ucPpll = pll_id; 80737f9003bSAlex Deucher args.v3.ucMiscInfo = (pll_id << 2); 80837f9003bSAlex Deucher args.v3.ucTransmitterId = encoder_id; 80937f9003bSAlex Deucher args.v3.ucEncoderMode = encoder_mode; 81037f9003bSAlex Deucher break; 81137f9003bSAlex Deucher case 5: 81237f9003bSAlex Deucher args.v5.ucCRTC = crtc_id; 81337f9003bSAlex Deucher args.v5.usPixelClock = cpu_to_le16(clock / 10); 81437f9003bSAlex Deucher args.v5.ucRefDiv = ref_div; 81537f9003bSAlex Deucher args.v5.usFbDiv = cpu_to_le16(fb_div); 81637f9003bSAlex Deucher args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); 81737f9003bSAlex Deucher args.v5.ucPostDiv = post_div; 81837f9003bSAlex Deucher args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */ 81937f9003bSAlex Deucher args.v5.ucTransmitterID = encoder_id; 82037f9003bSAlex Deucher args.v5.ucEncoderMode = encoder_mode; 82137f9003bSAlex Deucher args.v5.ucPpll = pll_id; 82237f9003bSAlex Deucher break; 823f82b3ddcSAlex Deucher case 6: 824f82b3ddcSAlex Deucher args.v6.ulCrtcPclkFreq.ucCRTC = crtc_id; 825f82b3ddcSAlex Deucher args.v6.ulCrtcPclkFreq.ulPixelClock = cpu_to_le32(clock / 10); 826f82b3ddcSAlex Deucher args.v6.ucRefDiv = ref_div; 827f82b3ddcSAlex Deucher args.v6.usFbDiv = cpu_to_le16(fb_div); 828f82b3ddcSAlex Deucher args.v6.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); 829f82b3ddcSAlex Deucher args.v6.ucPostDiv = post_div; 830f82b3ddcSAlex Deucher args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */ 831f82b3ddcSAlex Deucher args.v6.ucTransmitterID = encoder_id; 832f82b3ddcSAlex Deucher args.v6.ucEncoderMode = encoder_mode; 833f82b3ddcSAlex Deucher args.v6.ucPpll = pll_id; 834f82b3ddcSAlex Deucher break; 83537f9003bSAlex Deucher default: 83637f9003bSAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 83737f9003bSAlex Deucher return; 83837f9003bSAlex Deucher } 83937f9003bSAlex Deucher break; 84037f9003bSAlex Deucher default: 84137f9003bSAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 84237f9003bSAlex Deucher return; 84337f9003bSAlex Deucher } 84437f9003bSAlex Deucher 84537f9003bSAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 84637f9003bSAlex Deucher } 84737f9003bSAlex Deucher 848bcc1c2a1SAlex Deucher static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) 8494eaeca33SAlex Deucher { 8504eaeca33SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 8514eaeca33SAlex Deucher struct drm_device *dev = crtc->dev; 8524eaeca33SAlex Deucher struct radeon_device *rdev = dev->dev_private; 8534eaeca33SAlex Deucher struct drm_encoder *encoder = NULL; 8544eaeca33SAlex Deucher struct radeon_encoder *radeon_encoder = NULL; 8554eaeca33SAlex Deucher u32 pll_clock = mode->clock; 8564eaeca33SAlex Deucher u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; 8574eaeca33SAlex Deucher struct radeon_pll *pll; 8584eaeca33SAlex Deucher u32 adjusted_clock; 859bcc1c2a1SAlex Deucher int encoder_mode = 0; 860ba032a58SAlex Deucher struct radeon_atom_ss ss; 861ba032a58SAlex Deucher bool ss_enabled = false; 8624eaeca33SAlex Deucher 8634eaeca33SAlex Deucher list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 8644eaeca33SAlex Deucher if (encoder->crtc == crtc) { 8654eaeca33SAlex Deucher radeon_encoder = to_radeon_encoder(encoder); 866bcc1c2a1SAlex Deucher encoder_mode = atombios_get_encoder_mode(encoder); 8674eaeca33SAlex Deucher break; 8684eaeca33SAlex Deucher } 8694eaeca33SAlex Deucher } 8704eaeca33SAlex Deucher 8714eaeca33SAlex Deucher if (!radeon_encoder) 8724eaeca33SAlex Deucher return; 8734eaeca33SAlex Deucher 874bcc1c2a1SAlex Deucher switch (radeon_crtc->pll_id) { 875bcc1c2a1SAlex Deucher case ATOM_PPLL1: 8764eaeca33SAlex Deucher pll = &rdev->clock.p1pll; 877bcc1c2a1SAlex Deucher break; 878bcc1c2a1SAlex Deucher case ATOM_PPLL2: 8794eaeca33SAlex Deucher pll = &rdev->clock.p2pll; 880bcc1c2a1SAlex Deucher break; 881bcc1c2a1SAlex Deucher case ATOM_DCPLL: 882bcc1c2a1SAlex Deucher case ATOM_PPLL_INVALID: 883921d98b5SStefan Richter default: 884bcc1c2a1SAlex Deucher pll = &rdev->clock.dcpll; 885bcc1c2a1SAlex Deucher break; 886bcc1c2a1SAlex Deucher } 8874eaeca33SAlex Deucher 888ba032a58SAlex Deucher if (radeon_encoder->active_device & 889ba032a58SAlex Deucher (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) { 890ba032a58SAlex Deucher struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 891ba032a58SAlex Deucher struct drm_connector *connector = 892ba032a58SAlex Deucher radeon_get_connector_for_encoder(encoder); 893ba032a58SAlex Deucher struct radeon_connector *radeon_connector = 894ba032a58SAlex Deucher to_radeon_connector(connector); 895ba032a58SAlex Deucher struct radeon_connector_atom_dig *dig_connector = 896ba032a58SAlex Deucher radeon_connector->con_priv; 897ba032a58SAlex Deucher int dp_clock; 898ba032a58SAlex Deucher 899ba032a58SAlex Deucher switch (encoder_mode) { 900ba032a58SAlex Deucher case ATOM_ENCODER_MODE_DP: 901ba032a58SAlex Deucher /* DP/eDP */ 902ba032a58SAlex Deucher dp_clock = dig_connector->dp_clock / 10; 903ba032a58SAlex Deucher if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) { 904ba032a58SAlex Deucher if (ASIC_IS_DCE4(rdev)) 905ba032a58SAlex Deucher ss_enabled = 906ba032a58SAlex Deucher radeon_atombios_get_asic_ss_info(rdev, &ss, 907ba032a58SAlex Deucher dig->lcd_ss_id, 908ba032a58SAlex Deucher dp_clock); 909ba032a58SAlex Deucher else 910ba032a58SAlex Deucher ss_enabled = 911ba032a58SAlex Deucher radeon_atombios_get_ppll_ss_info(rdev, &ss, 912ba032a58SAlex Deucher dig->lcd_ss_id); 913ba032a58SAlex Deucher } else { 914ba032a58SAlex Deucher if (ASIC_IS_DCE4(rdev)) 915ba032a58SAlex Deucher ss_enabled = 916ba032a58SAlex Deucher radeon_atombios_get_asic_ss_info(rdev, &ss, 917ba032a58SAlex Deucher ASIC_INTERNAL_SS_ON_DP, 918ba032a58SAlex Deucher dp_clock); 919ba032a58SAlex Deucher else { 920ba032a58SAlex Deucher if (dp_clock == 16200) { 921ba032a58SAlex Deucher ss_enabled = 922ba032a58SAlex Deucher radeon_atombios_get_ppll_ss_info(rdev, &ss, 923ba032a58SAlex Deucher ATOM_DP_SS_ID2); 924ba032a58SAlex Deucher if (!ss_enabled) 925ba032a58SAlex Deucher ss_enabled = 926ba032a58SAlex Deucher radeon_atombios_get_ppll_ss_info(rdev, &ss, 927ba032a58SAlex Deucher ATOM_DP_SS_ID1); 928ba032a58SAlex Deucher } else 929ba032a58SAlex Deucher ss_enabled = 930ba032a58SAlex Deucher radeon_atombios_get_ppll_ss_info(rdev, &ss, 931ba032a58SAlex Deucher ATOM_DP_SS_ID1); 932ba032a58SAlex Deucher } 933ba032a58SAlex Deucher } 934ba032a58SAlex Deucher break; 935ba032a58SAlex Deucher case ATOM_ENCODER_MODE_LVDS: 936ba032a58SAlex Deucher if (ASIC_IS_DCE4(rdev)) 937ba032a58SAlex Deucher ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &ss, 938ba032a58SAlex Deucher dig->lcd_ss_id, 939ba032a58SAlex Deucher mode->clock / 10); 940ba032a58SAlex Deucher else 941ba032a58SAlex Deucher ss_enabled = radeon_atombios_get_ppll_ss_info(rdev, &ss, 942ba032a58SAlex Deucher dig->lcd_ss_id); 943ba032a58SAlex Deucher break; 944ba032a58SAlex Deucher case ATOM_ENCODER_MODE_DVI: 945ba032a58SAlex Deucher if (ASIC_IS_DCE4(rdev)) 946ba032a58SAlex Deucher ss_enabled = 947ba032a58SAlex Deucher radeon_atombios_get_asic_ss_info(rdev, &ss, 948ba032a58SAlex Deucher ASIC_INTERNAL_SS_ON_TMDS, 949ba032a58SAlex Deucher mode->clock / 10); 950ba032a58SAlex Deucher break; 951ba032a58SAlex Deucher case ATOM_ENCODER_MODE_HDMI: 952ba032a58SAlex Deucher if (ASIC_IS_DCE4(rdev)) 953ba032a58SAlex Deucher ss_enabled = 954ba032a58SAlex Deucher radeon_atombios_get_asic_ss_info(rdev, &ss, 955ba032a58SAlex Deucher ASIC_INTERNAL_SS_ON_HDMI, 956ba032a58SAlex Deucher mode->clock / 10); 957ba032a58SAlex Deucher break; 958ba032a58SAlex Deucher default: 959ba032a58SAlex Deucher break; 960ba032a58SAlex Deucher } 961ba032a58SAlex Deucher } 962ba032a58SAlex Deucher 9634eaeca33SAlex Deucher /* adjust pixel clock as needed */ 964ba032a58SAlex Deucher adjusted_clock = atombios_adjust_pll(crtc, mode, pll, ss_enabled, &ss); 9652606c886SAlex Deucher 9662606c886SAlex Deucher radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, 967fc10332bSAlex Deucher &ref_div, &post_div); 968771fe6b9SJerome Glisse 969ba032a58SAlex Deucher atombios_crtc_program_ss(crtc, ATOM_DISABLE, radeon_crtc->pll_id, &ss); 970ba032a58SAlex Deucher 97137f9003bSAlex Deucher atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, 97237f9003bSAlex Deucher encoder_mode, radeon_encoder->encoder_id, mode->clock, 97337f9003bSAlex Deucher ref_div, fb_div, frac_fb_div, post_div); 974771fe6b9SJerome Glisse 975ba032a58SAlex Deucher if (ss_enabled) { 976ba032a58SAlex Deucher /* calculate ss amount and step size */ 977ba032a58SAlex Deucher if (ASIC_IS_DCE4(rdev)) { 978ba032a58SAlex Deucher u32 step_size; 979ba032a58SAlex Deucher u32 amount = (((fb_div * 10) + frac_fb_div) * ss.percentage) / 10000; 980ba032a58SAlex Deucher ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK; 981ba032a58SAlex Deucher ss.amount |= ((amount - (ss.amount * 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) & 982ba032a58SAlex Deucher ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK; 983ba032a58SAlex Deucher if (ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD) 984ba032a58SAlex Deucher step_size = (4 * amount * ref_div * (ss.rate * 2048)) / 985ba032a58SAlex Deucher (125 * 25 * pll->reference_freq / 100); 986ba032a58SAlex Deucher else 987ba032a58SAlex Deucher step_size = (2 * amount * ref_div * (ss.rate * 2048)) / 988ba032a58SAlex Deucher (125 * 25 * pll->reference_freq / 100); 989ba032a58SAlex Deucher ss.step = step_size; 990ba032a58SAlex Deucher } 991ba032a58SAlex Deucher 992ba032a58SAlex Deucher atombios_crtc_program_ss(crtc, ATOM_ENABLE, radeon_crtc->pll_id, &ss); 993ba032a58SAlex Deucher } 994771fe6b9SJerome Glisse } 995771fe6b9SJerome Glisse 9964dd19b0dSChris Ball static int evergreen_crtc_do_set_base(struct drm_crtc *crtc, 9974dd19b0dSChris Ball struct drm_framebuffer *fb, 9984dd19b0dSChris Ball int x, int y, int atomic) 999bcc1c2a1SAlex Deucher { 1000bcc1c2a1SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1001bcc1c2a1SAlex Deucher struct drm_device *dev = crtc->dev; 1002bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 1003bcc1c2a1SAlex Deucher struct radeon_framebuffer *radeon_fb; 10044dd19b0dSChris Ball struct drm_framebuffer *target_fb; 1005bcc1c2a1SAlex Deucher struct drm_gem_object *obj; 1006bcc1c2a1SAlex Deucher struct radeon_bo *rbo; 1007bcc1c2a1SAlex Deucher uint64_t fb_location; 1008bcc1c2a1SAlex Deucher uint32_t fb_format, fb_pitch_pixels, tiling_flags; 1009bcc1c2a1SAlex Deucher int r; 1010bcc1c2a1SAlex Deucher 1011bcc1c2a1SAlex Deucher /* no fb bound */ 10124dd19b0dSChris Ball if (!atomic && !crtc->fb) { 1013d9fdaafbSDave Airlie DRM_DEBUG_KMS("No FB bound\n"); 1014bcc1c2a1SAlex Deucher return 0; 1015bcc1c2a1SAlex Deucher } 1016bcc1c2a1SAlex Deucher 10174dd19b0dSChris Ball if (atomic) { 10184dd19b0dSChris Ball radeon_fb = to_radeon_framebuffer(fb); 10194dd19b0dSChris Ball target_fb = fb; 10204dd19b0dSChris Ball } 10214dd19b0dSChris Ball else { 1022bcc1c2a1SAlex Deucher radeon_fb = to_radeon_framebuffer(crtc->fb); 10234dd19b0dSChris Ball target_fb = crtc->fb; 10244dd19b0dSChris Ball } 1025bcc1c2a1SAlex Deucher 10264dd19b0dSChris Ball /* If atomic, assume fb object is pinned & idle & fenced and 10274dd19b0dSChris Ball * just update base pointers 10284dd19b0dSChris Ball */ 1029bcc1c2a1SAlex Deucher obj = radeon_fb->obj; 1030bcc1c2a1SAlex Deucher rbo = obj->driver_private; 1031bcc1c2a1SAlex Deucher r = radeon_bo_reserve(rbo, false); 1032bcc1c2a1SAlex Deucher if (unlikely(r != 0)) 1033bcc1c2a1SAlex Deucher return r; 10344dd19b0dSChris Ball 10354dd19b0dSChris Ball if (atomic) 10364dd19b0dSChris Ball fb_location = radeon_bo_gpu_offset(rbo); 10374dd19b0dSChris Ball else { 1038bcc1c2a1SAlex Deucher r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); 1039bcc1c2a1SAlex Deucher if (unlikely(r != 0)) { 1040bcc1c2a1SAlex Deucher radeon_bo_unreserve(rbo); 1041bcc1c2a1SAlex Deucher return -EINVAL; 1042bcc1c2a1SAlex Deucher } 10434dd19b0dSChris Ball } 10444dd19b0dSChris Ball 1045bcc1c2a1SAlex Deucher radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); 1046bcc1c2a1SAlex Deucher radeon_bo_unreserve(rbo); 1047bcc1c2a1SAlex Deucher 10484dd19b0dSChris Ball switch (target_fb->bits_per_pixel) { 1049bcc1c2a1SAlex Deucher case 8: 1050bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP) | 1051bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED)); 1052bcc1c2a1SAlex Deucher break; 1053bcc1c2a1SAlex Deucher case 15: 1054bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 1055bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB1555)); 1056bcc1c2a1SAlex Deucher break; 1057bcc1c2a1SAlex Deucher case 16: 1058bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 1059bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565)); 1060bcc1c2a1SAlex Deucher break; 1061bcc1c2a1SAlex Deucher case 24: 1062bcc1c2a1SAlex Deucher case 32: 1063bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) | 1064bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888)); 1065bcc1c2a1SAlex Deucher break; 1066bcc1c2a1SAlex Deucher default: 1067bcc1c2a1SAlex Deucher DRM_ERROR("Unsupported screen depth %d\n", 10684dd19b0dSChris Ball target_fb->bits_per_pixel); 1069bcc1c2a1SAlex Deucher return -EINVAL; 1070bcc1c2a1SAlex Deucher } 1071bcc1c2a1SAlex Deucher 107297d66328SAlex Deucher if (tiling_flags & RADEON_TILING_MACRO) 107397d66328SAlex Deucher fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1); 107497d66328SAlex Deucher else if (tiling_flags & RADEON_TILING_MICRO) 107597d66328SAlex Deucher fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1); 107697d66328SAlex Deucher 1077bcc1c2a1SAlex Deucher switch (radeon_crtc->crtc_id) { 1078bcc1c2a1SAlex Deucher case 0: 1079bcc1c2a1SAlex Deucher WREG32(AVIVO_D1VGA_CONTROL, 0); 1080bcc1c2a1SAlex Deucher break; 1081bcc1c2a1SAlex Deucher case 1: 1082bcc1c2a1SAlex Deucher WREG32(AVIVO_D2VGA_CONTROL, 0); 1083bcc1c2a1SAlex Deucher break; 1084bcc1c2a1SAlex Deucher case 2: 1085bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D3VGA_CONTROL, 0); 1086bcc1c2a1SAlex Deucher break; 1087bcc1c2a1SAlex Deucher case 3: 1088bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D4VGA_CONTROL, 0); 1089bcc1c2a1SAlex Deucher break; 1090bcc1c2a1SAlex Deucher case 4: 1091bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D5VGA_CONTROL, 0); 1092bcc1c2a1SAlex Deucher break; 1093bcc1c2a1SAlex Deucher case 5: 1094bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D6VGA_CONTROL, 0); 1095bcc1c2a1SAlex Deucher break; 1096bcc1c2a1SAlex Deucher default: 1097bcc1c2a1SAlex Deucher break; 1098bcc1c2a1SAlex Deucher } 1099bcc1c2a1SAlex Deucher 1100bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 1101bcc1c2a1SAlex Deucher upper_32_bits(fb_location)); 1102bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 1103bcc1c2a1SAlex Deucher upper_32_bits(fb_location)); 1104bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 1105bcc1c2a1SAlex Deucher (u32)fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK); 1106bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 1107bcc1c2a1SAlex Deucher (u32) fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK); 1108bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); 1109bcc1c2a1SAlex Deucher 1110bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); 1111bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); 1112bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_X_START + radeon_crtc->crtc_offset, 0); 1113bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_Y_START + radeon_crtc->crtc_offset, 0); 11144dd19b0dSChris Ball WREG32(EVERGREEN_GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width); 11154dd19b0dSChris Ball WREG32(EVERGREEN_GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height); 1116bcc1c2a1SAlex Deucher 11174dd19b0dSChris Ball fb_pitch_pixels = target_fb->pitch / (target_fb->bits_per_pixel / 8); 1118bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); 1119bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1); 1120bcc1c2a1SAlex Deucher 1121bcc1c2a1SAlex Deucher WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, 1122bcc1c2a1SAlex Deucher crtc->mode.vdisplay); 1123bcc1c2a1SAlex Deucher x &= ~3; 1124bcc1c2a1SAlex Deucher y &= ~1; 1125bcc1c2a1SAlex Deucher WREG32(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset, 1126bcc1c2a1SAlex Deucher (x << 16) | y); 1127bcc1c2a1SAlex Deucher WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset, 1128bcc1c2a1SAlex Deucher (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay); 1129bcc1c2a1SAlex Deucher 1130bcc1c2a1SAlex Deucher if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) 1131bcc1c2a1SAlex Deucher WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 1132bcc1c2a1SAlex Deucher EVERGREEN_INTERLEAVE_EN); 1133bcc1c2a1SAlex Deucher else 1134bcc1c2a1SAlex Deucher WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 0); 1135bcc1c2a1SAlex Deucher 11364dd19b0dSChris Ball if (!atomic && fb && fb != crtc->fb) { 11374dd19b0dSChris Ball radeon_fb = to_radeon_framebuffer(fb); 1138bcc1c2a1SAlex Deucher rbo = radeon_fb->obj->driver_private; 1139bcc1c2a1SAlex Deucher r = radeon_bo_reserve(rbo, false); 1140bcc1c2a1SAlex Deucher if (unlikely(r != 0)) 1141bcc1c2a1SAlex Deucher return r; 1142bcc1c2a1SAlex Deucher radeon_bo_unpin(rbo); 1143bcc1c2a1SAlex Deucher radeon_bo_unreserve(rbo); 1144bcc1c2a1SAlex Deucher } 1145bcc1c2a1SAlex Deucher 1146bcc1c2a1SAlex Deucher /* Bytes per pixel may have changed */ 1147bcc1c2a1SAlex Deucher radeon_bandwidth_update(rdev); 1148bcc1c2a1SAlex Deucher 1149bcc1c2a1SAlex Deucher return 0; 1150bcc1c2a1SAlex Deucher } 1151bcc1c2a1SAlex Deucher 11524dd19b0dSChris Ball static int avivo_crtc_do_set_base(struct drm_crtc *crtc, 11534dd19b0dSChris Ball struct drm_framebuffer *fb, 11544dd19b0dSChris Ball int x, int y, int atomic) 1155771fe6b9SJerome Glisse { 1156771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1157771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 1158771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 1159771fe6b9SJerome Glisse struct radeon_framebuffer *radeon_fb; 1160771fe6b9SJerome Glisse struct drm_gem_object *obj; 11614c788679SJerome Glisse struct radeon_bo *rbo; 11624dd19b0dSChris Ball struct drm_framebuffer *target_fb; 1163771fe6b9SJerome Glisse uint64_t fb_location; 1164e024e110SDave Airlie uint32_t fb_format, fb_pitch_pixels, tiling_flags; 11654c788679SJerome Glisse int r; 1166771fe6b9SJerome Glisse 11672de3b484SJerome Glisse /* no fb bound */ 11684dd19b0dSChris Ball if (!atomic && !crtc->fb) { 1169d9fdaafbSDave Airlie DRM_DEBUG_KMS("No FB bound\n"); 11702de3b484SJerome Glisse return 0; 11712de3b484SJerome Glisse } 1172771fe6b9SJerome Glisse 11734dd19b0dSChris Ball if (atomic) { 11744dd19b0dSChris Ball radeon_fb = to_radeon_framebuffer(fb); 11754dd19b0dSChris Ball target_fb = fb; 11764dd19b0dSChris Ball } 11774dd19b0dSChris Ball else { 1178771fe6b9SJerome Glisse radeon_fb = to_radeon_framebuffer(crtc->fb); 11794dd19b0dSChris Ball target_fb = crtc->fb; 11804dd19b0dSChris Ball } 1181771fe6b9SJerome Glisse 1182771fe6b9SJerome Glisse obj = radeon_fb->obj; 11834c788679SJerome Glisse rbo = obj->driver_private; 11844c788679SJerome Glisse r = radeon_bo_reserve(rbo, false); 11854c788679SJerome Glisse if (unlikely(r != 0)) 11864c788679SJerome Glisse return r; 11874dd19b0dSChris Ball 11884dd19b0dSChris Ball /* If atomic, assume fb object is pinned & idle & fenced and 11894dd19b0dSChris Ball * just update base pointers 11904dd19b0dSChris Ball */ 11914dd19b0dSChris Ball if (atomic) 11924dd19b0dSChris Ball fb_location = radeon_bo_gpu_offset(rbo); 11934dd19b0dSChris Ball else { 11944c788679SJerome Glisse r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); 11954c788679SJerome Glisse if (unlikely(r != 0)) { 11964c788679SJerome Glisse radeon_bo_unreserve(rbo); 1197771fe6b9SJerome Glisse return -EINVAL; 1198771fe6b9SJerome Glisse } 11994dd19b0dSChris Ball } 12004c788679SJerome Glisse radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); 12014c788679SJerome Glisse radeon_bo_unreserve(rbo); 1202771fe6b9SJerome Glisse 12034dd19b0dSChris Ball switch (target_fb->bits_per_pixel) { 120441456df2SDave Airlie case 8: 120541456df2SDave Airlie fb_format = 120641456df2SDave Airlie AVIVO_D1GRPH_CONTROL_DEPTH_8BPP | 120741456df2SDave Airlie AVIVO_D1GRPH_CONTROL_8BPP_INDEXED; 120841456df2SDave Airlie break; 1209771fe6b9SJerome Glisse case 15: 1210771fe6b9SJerome Glisse fb_format = 1211771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | 1212771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555; 1213771fe6b9SJerome Glisse break; 1214771fe6b9SJerome Glisse case 16: 1215771fe6b9SJerome Glisse fb_format = 1216771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | 1217771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_16BPP_RGB565; 1218771fe6b9SJerome Glisse break; 1219771fe6b9SJerome Glisse case 24: 1220771fe6b9SJerome Glisse case 32: 1221771fe6b9SJerome Glisse fb_format = 1222771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_32BPP | 1223771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888; 1224771fe6b9SJerome Glisse break; 1225771fe6b9SJerome Glisse default: 1226771fe6b9SJerome Glisse DRM_ERROR("Unsupported screen depth %d\n", 12274dd19b0dSChris Ball target_fb->bits_per_pixel); 1228771fe6b9SJerome Glisse return -EINVAL; 1229771fe6b9SJerome Glisse } 1230771fe6b9SJerome Glisse 123140c4ac1cSAlex Deucher if (rdev->family >= CHIP_R600) { 123240c4ac1cSAlex Deucher if (tiling_flags & RADEON_TILING_MACRO) 123340c4ac1cSAlex Deucher fb_format |= R600_D1GRPH_ARRAY_MODE_2D_TILED_THIN1; 123440c4ac1cSAlex Deucher else if (tiling_flags & RADEON_TILING_MICRO) 123540c4ac1cSAlex Deucher fb_format |= R600_D1GRPH_ARRAY_MODE_1D_TILED_THIN1; 123640c4ac1cSAlex Deucher } else { 1237cf2f05d3SDave Airlie if (tiling_flags & RADEON_TILING_MACRO) 1238cf2f05d3SDave Airlie fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE; 1239cf2f05d3SDave Airlie 1240e024e110SDave Airlie if (tiling_flags & RADEON_TILING_MICRO) 1241e024e110SDave Airlie fb_format |= AVIVO_D1GRPH_TILED; 124240c4ac1cSAlex Deucher } 1243e024e110SDave Airlie 1244771fe6b9SJerome Glisse if (radeon_crtc->crtc_id == 0) 1245771fe6b9SJerome Glisse WREG32(AVIVO_D1VGA_CONTROL, 0); 1246771fe6b9SJerome Glisse else 1247771fe6b9SJerome Glisse WREG32(AVIVO_D2VGA_CONTROL, 0); 1248c290dadfSAlex Deucher 1249c290dadfSAlex Deucher if (rdev->family >= CHIP_RV770) { 1250c290dadfSAlex Deucher if (radeon_crtc->crtc_id) { 125195347871SAlex Deucher WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 125295347871SAlex Deucher WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 1253c290dadfSAlex Deucher } else { 125495347871SAlex Deucher WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 125595347871SAlex Deucher WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 1256c290dadfSAlex Deucher } 1257c290dadfSAlex Deucher } 1258771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 1259771fe6b9SJerome Glisse (u32) fb_location); 1260771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + 1261771fe6b9SJerome Glisse radeon_crtc->crtc_offset, (u32) fb_location); 1262771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); 1263771fe6b9SJerome Glisse 1264771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); 1265771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); 1266771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0); 1267771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, 0); 12684dd19b0dSChris Ball WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width); 12694dd19b0dSChris Ball WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height); 1270771fe6b9SJerome Glisse 12714dd19b0dSChris Ball fb_pitch_pixels = target_fb->pitch / (target_fb->bits_per_pixel / 8); 1272771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); 1273771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1); 1274771fe6b9SJerome Glisse 1275771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, 1276771fe6b9SJerome Glisse crtc->mode.vdisplay); 1277771fe6b9SJerome Glisse x &= ~3; 1278771fe6b9SJerome Glisse y &= ~1; 1279771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset, 1280771fe6b9SJerome Glisse (x << 16) | y); 1281771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset, 1282771fe6b9SJerome Glisse (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay); 1283771fe6b9SJerome Glisse 1284771fe6b9SJerome Glisse if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) 1285771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 1286771fe6b9SJerome Glisse AVIVO_D1MODE_INTERLEAVE_EN); 1287771fe6b9SJerome Glisse else 1288771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0); 1289771fe6b9SJerome Glisse 12904dd19b0dSChris Ball if (!atomic && fb && fb != crtc->fb) { 12914dd19b0dSChris Ball radeon_fb = to_radeon_framebuffer(fb); 12924c788679SJerome Glisse rbo = radeon_fb->obj->driver_private; 12934c788679SJerome Glisse r = radeon_bo_reserve(rbo, false); 12944c788679SJerome Glisse if (unlikely(r != 0)) 12954c788679SJerome Glisse return r; 12964c788679SJerome Glisse radeon_bo_unpin(rbo); 12974c788679SJerome Glisse radeon_bo_unreserve(rbo); 1298771fe6b9SJerome Glisse } 1299f30f37deSMichel Dänzer 1300f30f37deSMichel Dänzer /* Bytes per pixel may have changed */ 1301f30f37deSMichel Dänzer radeon_bandwidth_update(rdev); 1302f30f37deSMichel Dänzer 1303771fe6b9SJerome Glisse return 0; 1304771fe6b9SJerome Glisse } 1305771fe6b9SJerome Glisse 130654f088a9SAlex Deucher int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, 130754f088a9SAlex Deucher struct drm_framebuffer *old_fb) 130854f088a9SAlex Deucher { 130954f088a9SAlex Deucher struct drm_device *dev = crtc->dev; 131054f088a9SAlex Deucher struct radeon_device *rdev = dev->dev_private; 131154f088a9SAlex Deucher 1312bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) 13134dd19b0dSChris Ball return evergreen_crtc_do_set_base(crtc, old_fb, x, y, 0); 1314bcc1c2a1SAlex Deucher else if (ASIC_IS_AVIVO(rdev)) 13154dd19b0dSChris Ball return avivo_crtc_do_set_base(crtc, old_fb, x, y, 0); 131654f088a9SAlex Deucher else 13174dd19b0dSChris Ball return radeon_crtc_do_set_base(crtc, old_fb, x, y, 0); 13184dd19b0dSChris Ball } 13194dd19b0dSChris Ball 13204dd19b0dSChris Ball int atombios_crtc_set_base_atomic(struct drm_crtc *crtc, 13214dd19b0dSChris Ball struct drm_framebuffer *fb, 132221c74a8eSJason Wessel int x, int y, enum mode_set_atomic state) 13234dd19b0dSChris Ball { 13244dd19b0dSChris Ball struct drm_device *dev = crtc->dev; 13254dd19b0dSChris Ball struct radeon_device *rdev = dev->dev_private; 13264dd19b0dSChris Ball 13274dd19b0dSChris Ball if (ASIC_IS_DCE4(rdev)) 13284dd19b0dSChris Ball return evergreen_crtc_do_set_base(crtc, fb, x, y, 1); 13294dd19b0dSChris Ball else if (ASIC_IS_AVIVO(rdev)) 13304dd19b0dSChris Ball return avivo_crtc_do_set_base(crtc, fb, x, y, 1); 13314dd19b0dSChris Ball else 13324dd19b0dSChris Ball return radeon_crtc_do_set_base(crtc, fb, x, y, 1); 133354f088a9SAlex Deucher } 133454f088a9SAlex Deucher 1335615e0cb6SAlex Deucher /* properly set additional regs when using atombios */ 1336615e0cb6SAlex Deucher static void radeon_legacy_atom_fixup(struct drm_crtc *crtc) 1337615e0cb6SAlex Deucher { 1338615e0cb6SAlex Deucher struct drm_device *dev = crtc->dev; 1339615e0cb6SAlex Deucher struct radeon_device *rdev = dev->dev_private; 1340615e0cb6SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1341615e0cb6SAlex Deucher u32 disp_merge_cntl; 1342615e0cb6SAlex Deucher 1343615e0cb6SAlex Deucher switch (radeon_crtc->crtc_id) { 1344615e0cb6SAlex Deucher case 0: 1345615e0cb6SAlex Deucher disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL); 1346615e0cb6SAlex Deucher disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; 1347615e0cb6SAlex Deucher WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl); 1348615e0cb6SAlex Deucher break; 1349615e0cb6SAlex Deucher case 1: 1350615e0cb6SAlex Deucher disp_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL); 1351615e0cb6SAlex Deucher disp_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN; 1352615e0cb6SAlex Deucher WREG32(RADEON_DISP2_MERGE_CNTL, disp_merge_cntl); 1353615e0cb6SAlex Deucher WREG32(RADEON_FP_H2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_H_SYNC_STRT_WID)); 1354615e0cb6SAlex Deucher WREG32(RADEON_FP_V2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_V_SYNC_STRT_WID)); 1355615e0cb6SAlex Deucher break; 1356615e0cb6SAlex Deucher } 1357615e0cb6SAlex Deucher } 1358615e0cb6SAlex Deucher 1359bcc1c2a1SAlex Deucher static int radeon_atom_pick_pll(struct drm_crtc *crtc) 1360bcc1c2a1SAlex Deucher { 1361bcc1c2a1SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1362bcc1c2a1SAlex Deucher struct drm_device *dev = crtc->dev; 1363bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 1364bcc1c2a1SAlex Deucher struct drm_encoder *test_encoder; 1365bcc1c2a1SAlex Deucher struct drm_crtc *test_crtc; 1366bcc1c2a1SAlex Deucher uint32_t pll_in_use = 0; 1367bcc1c2a1SAlex Deucher 1368bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) { 1369bcc1c2a1SAlex Deucher /* if crtc is driving DP and we have an ext clock, use that */ 1370bcc1c2a1SAlex Deucher list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { 1371bcc1c2a1SAlex Deucher if (test_encoder->crtc && (test_encoder->crtc == crtc)) { 1372bcc1c2a1SAlex Deucher if (atombios_get_encoder_mode(test_encoder) == ATOM_ENCODER_MODE_DP) { 1373bcc1c2a1SAlex Deucher if (rdev->clock.dp_extclk) 1374bcc1c2a1SAlex Deucher return ATOM_PPLL_INVALID; 1375bcc1c2a1SAlex Deucher } 1376bcc1c2a1SAlex Deucher } 1377bcc1c2a1SAlex Deucher } 1378bcc1c2a1SAlex Deucher 1379bcc1c2a1SAlex Deucher /* otherwise, pick one of the plls */ 1380bcc1c2a1SAlex Deucher list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { 1381bcc1c2a1SAlex Deucher struct radeon_crtc *radeon_test_crtc; 1382bcc1c2a1SAlex Deucher 1383bcc1c2a1SAlex Deucher if (crtc == test_crtc) 1384bcc1c2a1SAlex Deucher continue; 1385bcc1c2a1SAlex Deucher 1386bcc1c2a1SAlex Deucher radeon_test_crtc = to_radeon_crtc(test_crtc); 1387bcc1c2a1SAlex Deucher if ((radeon_test_crtc->pll_id >= ATOM_PPLL1) && 1388bcc1c2a1SAlex Deucher (radeon_test_crtc->pll_id <= ATOM_PPLL2)) 1389bcc1c2a1SAlex Deucher pll_in_use |= (1 << radeon_test_crtc->pll_id); 1390bcc1c2a1SAlex Deucher } 1391bcc1c2a1SAlex Deucher if (!(pll_in_use & 1)) 1392bcc1c2a1SAlex Deucher return ATOM_PPLL1; 1393bcc1c2a1SAlex Deucher return ATOM_PPLL2; 1394bcc1c2a1SAlex Deucher } else 1395bcc1c2a1SAlex Deucher return radeon_crtc->crtc_id; 1396bcc1c2a1SAlex Deucher 1397bcc1c2a1SAlex Deucher } 1398bcc1c2a1SAlex Deucher 1399771fe6b9SJerome Glisse int atombios_crtc_mode_set(struct drm_crtc *crtc, 1400771fe6b9SJerome Glisse struct drm_display_mode *mode, 1401771fe6b9SJerome Glisse struct drm_display_mode *adjusted_mode, 1402771fe6b9SJerome Glisse int x, int y, struct drm_framebuffer *old_fb) 1403771fe6b9SJerome Glisse { 1404771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1405771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 1406771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 140754bfe496SAlex Deucher struct drm_encoder *encoder; 140854bfe496SAlex Deucher bool is_tvcv = false; 1409771fe6b9SJerome Glisse 141054bfe496SAlex Deucher list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 141154bfe496SAlex Deucher /* find tv std */ 141254bfe496SAlex Deucher if (encoder->crtc == crtc) { 141354bfe496SAlex Deucher struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 141454bfe496SAlex Deucher if (radeon_encoder->active_device & 141554bfe496SAlex Deucher (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) 141654bfe496SAlex Deucher is_tvcv = true; 141754bfe496SAlex Deucher } 141854bfe496SAlex Deucher } 1419771fe6b9SJerome Glisse 1420bcc1c2a1SAlex Deucher /* always set DCPLL */ 1421ba032a58SAlex Deucher if (ASIC_IS_DCE4(rdev)) { 1422ba032a58SAlex Deucher struct radeon_atom_ss ss; 1423ba032a58SAlex Deucher bool ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &ss, 1424ba032a58SAlex Deucher ASIC_INTERNAL_SS_ON_DCPLL, 1425ba032a58SAlex Deucher rdev->clock.default_dispclk); 1426ba032a58SAlex Deucher if (ss_enabled) 1427ba032a58SAlex Deucher atombios_crtc_program_ss(crtc, ATOM_DISABLE, ATOM_DCPLL, &ss); 1428f82b3ddcSAlex Deucher /* XXX: DCE5, make sure voltage, dispclk is high enough */ 1429f82b3ddcSAlex Deucher atombios_crtc_set_dcpll(crtc, rdev->clock.default_dispclk); 1430ba032a58SAlex Deucher if (ss_enabled) 1431ba032a58SAlex Deucher atombios_crtc_program_ss(crtc, ATOM_ENABLE, ATOM_DCPLL, &ss); 1432ba032a58SAlex Deucher } 1433771fe6b9SJerome Glisse atombios_crtc_set_pll(crtc, adjusted_mode); 1434771fe6b9SJerome Glisse 143554bfe496SAlex Deucher if (ASIC_IS_DCE4(rdev)) 1436bcc1c2a1SAlex Deucher atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 143754bfe496SAlex Deucher else if (ASIC_IS_AVIVO(rdev)) { 143854bfe496SAlex Deucher if (is_tvcv) 143954bfe496SAlex Deucher atombios_crtc_set_timing(crtc, adjusted_mode); 144054bfe496SAlex Deucher else 144154bfe496SAlex Deucher atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 144254bfe496SAlex Deucher } else { 1443bcc1c2a1SAlex Deucher atombios_crtc_set_timing(crtc, adjusted_mode); 14445a9bcaccSAlex Deucher if (radeon_crtc->crtc_id == 0) 14455a9bcaccSAlex Deucher atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 1446615e0cb6SAlex Deucher radeon_legacy_atom_fixup(crtc); 1447771fe6b9SJerome Glisse } 1448bcc1c2a1SAlex Deucher atombios_crtc_set_base(crtc, x, y, old_fb); 1449c93bb85bSJerome Glisse atombios_overscan_setup(crtc, mode, adjusted_mode); 1450c93bb85bSJerome Glisse atombios_scaler_setup(crtc); 1451771fe6b9SJerome Glisse return 0; 1452771fe6b9SJerome Glisse } 1453771fe6b9SJerome Glisse 1454771fe6b9SJerome Glisse static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, 1455771fe6b9SJerome Glisse struct drm_display_mode *mode, 1456771fe6b9SJerome Glisse struct drm_display_mode *adjusted_mode) 1457771fe6b9SJerome Glisse { 145803214bd5SAlex Deucher struct drm_device *dev = crtc->dev; 145903214bd5SAlex Deucher struct radeon_device *rdev = dev->dev_private; 146003214bd5SAlex Deucher 146103214bd5SAlex Deucher /* adjust pm to upcoming mode change */ 146203214bd5SAlex Deucher radeon_pm_compute_clocks(rdev); 146303214bd5SAlex Deucher 1464c93bb85bSJerome Glisse if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) 1465c93bb85bSJerome Glisse return false; 1466771fe6b9SJerome Glisse return true; 1467771fe6b9SJerome Glisse } 1468771fe6b9SJerome Glisse 1469771fe6b9SJerome Glisse static void atombios_crtc_prepare(struct drm_crtc *crtc) 1470771fe6b9SJerome Glisse { 1471267364acSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1472267364acSAlex Deucher 1473267364acSAlex Deucher /* pick pll */ 1474267364acSAlex Deucher radeon_crtc->pll_id = radeon_atom_pick_pll(crtc); 1475267364acSAlex Deucher 147637b4390eSAlex Deucher atombios_lock_crtc(crtc, ATOM_ENABLE); 1477a348c84dSAlex Deucher atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 1478771fe6b9SJerome Glisse } 1479771fe6b9SJerome Glisse 1480771fe6b9SJerome Glisse static void atombios_crtc_commit(struct drm_crtc *crtc) 1481771fe6b9SJerome Glisse { 1482771fe6b9SJerome Glisse atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON); 148337b4390eSAlex Deucher atombios_lock_crtc(crtc, ATOM_DISABLE); 1484771fe6b9SJerome Glisse } 1485771fe6b9SJerome Glisse 148637f9003bSAlex Deucher static void atombios_crtc_disable(struct drm_crtc *crtc) 148737f9003bSAlex Deucher { 148837f9003bSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 148937f9003bSAlex Deucher atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 149037f9003bSAlex Deucher 149137f9003bSAlex Deucher switch (radeon_crtc->pll_id) { 149237f9003bSAlex Deucher case ATOM_PPLL1: 149337f9003bSAlex Deucher case ATOM_PPLL2: 149437f9003bSAlex Deucher /* disable the ppll */ 149537f9003bSAlex Deucher atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, 149637f9003bSAlex Deucher 0, 0, ATOM_DISABLE, 0, 0, 0, 0); 149737f9003bSAlex Deucher break; 149837f9003bSAlex Deucher default: 149937f9003bSAlex Deucher break; 150037f9003bSAlex Deucher } 150137f9003bSAlex Deucher radeon_crtc->pll_id = -1; 150237f9003bSAlex Deucher } 150337f9003bSAlex Deucher 1504771fe6b9SJerome Glisse static const struct drm_crtc_helper_funcs atombios_helper_funcs = { 1505771fe6b9SJerome Glisse .dpms = atombios_crtc_dpms, 1506771fe6b9SJerome Glisse .mode_fixup = atombios_crtc_mode_fixup, 1507771fe6b9SJerome Glisse .mode_set = atombios_crtc_mode_set, 1508771fe6b9SJerome Glisse .mode_set_base = atombios_crtc_set_base, 15094dd19b0dSChris Ball .mode_set_base_atomic = atombios_crtc_set_base_atomic, 1510771fe6b9SJerome Glisse .prepare = atombios_crtc_prepare, 1511771fe6b9SJerome Glisse .commit = atombios_crtc_commit, 1512068143d3SDave Airlie .load_lut = radeon_crtc_load_lut, 151337f9003bSAlex Deucher .disable = atombios_crtc_disable, 1514771fe6b9SJerome Glisse }; 1515771fe6b9SJerome Glisse 1516771fe6b9SJerome Glisse void radeon_atombios_init_crtc(struct drm_device *dev, 1517771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc) 1518771fe6b9SJerome Glisse { 1519bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 1520bcc1c2a1SAlex Deucher 1521bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) { 1522bcc1c2a1SAlex Deucher switch (radeon_crtc->crtc_id) { 1523bcc1c2a1SAlex Deucher case 0: 1524bcc1c2a1SAlex Deucher default: 152512d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC0_REGISTER_OFFSET; 1526bcc1c2a1SAlex Deucher break; 1527bcc1c2a1SAlex Deucher case 1: 152812d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC1_REGISTER_OFFSET; 1529bcc1c2a1SAlex Deucher break; 1530bcc1c2a1SAlex Deucher case 2: 153112d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC2_REGISTER_OFFSET; 1532bcc1c2a1SAlex Deucher break; 1533bcc1c2a1SAlex Deucher case 3: 153412d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC3_REGISTER_OFFSET; 1535bcc1c2a1SAlex Deucher break; 1536bcc1c2a1SAlex Deucher case 4: 153712d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC4_REGISTER_OFFSET; 1538bcc1c2a1SAlex Deucher break; 1539bcc1c2a1SAlex Deucher case 5: 154012d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC5_REGISTER_OFFSET; 1541bcc1c2a1SAlex Deucher break; 1542bcc1c2a1SAlex Deucher } 1543bcc1c2a1SAlex Deucher } else { 1544771fe6b9SJerome Glisse if (radeon_crtc->crtc_id == 1) 1545771fe6b9SJerome Glisse radeon_crtc->crtc_offset = 1546771fe6b9SJerome Glisse AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL; 1547bcc1c2a1SAlex Deucher else 1548bcc1c2a1SAlex Deucher radeon_crtc->crtc_offset = 0; 1549bcc1c2a1SAlex Deucher } 1550bcc1c2a1SAlex Deucher radeon_crtc->pll_id = -1; 1551771fe6b9SJerome Glisse drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); 1552771fe6b9SJerome Glisse } 1553