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); 25637b4390eSAlex Deucher atombios_blank_crtc(crtc, ATOM_ENABLE); 257771fe6b9SJerome Glisse if (ASIC_IS_DCE3(rdev)) 25837b4390eSAlex Deucher atombios_enable_crtc_memreq(crtc, ATOM_DISABLE); 25937b4390eSAlex Deucher atombios_enable_crtc(crtc, ATOM_DISABLE); 260a48b9b4eSAlex Deucher radeon_crtc->enabled = false; 261d7311171SAlex Deucher /* adjust pm to dpms changes AFTER disabling crtcs */ 262d7311171SAlex Deucher radeon_pm_compute_clocks(rdev); 263771fe6b9SJerome Glisse break; 264771fe6b9SJerome Glisse } 265771fe6b9SJerome Glisse } 266771fe6b9SJerome Glisse 267771fe6b9SJerome Glisse static void 268771fe6b9SJerome Glisse atombios_set_crtc_dtd_timing(struct drm_crtc *crtc, 2695a9bcaccSAlex Deucher struct drm_display_mode *mode) 270771fe6b9SJerome Glisse { 2715a9bcaccSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 272771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 273771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 2745a9bcaccSAlex Deucher SET_CRTC_USING_DTD_TIMING_PARAMETERS args; 275771fe6b9SJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming); 2765a9bcaccSAlex Deucher u16 misc = 0; 277771fe6b9SJerome Glisse 2785a9bcaccSAlex Deucher memset(&args, 0, sizeof(args)); 2795b1714d3SAlex Deucher args.usH_Size = cpu_to_le16(mode->crtc_hdisplay - (radeon_crtc->h_border * 2)); 2805a9bcaccSAlex Deucher args.usH_Blanking_Time = 2815b1714d3SAlex Deucher cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay + (radeon_crtc->h_border * 2)); 2825b1714d3SAlex Deucher args.usV_Size = cpu_to_le16(mode->crtc_vdisplay - (radeon_crtc->v_border * 2)); 2835a9bcaccSAlex Deucher args.usV_Blanking_Time = 2845b1714d3SAlex Deucher cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay + (radeon_crtc->v_border * 2)); 2855a9bcaccSAlex Deucher args.usH_SyncOffset = 2865b1714d3SAlex Deucher cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay + radeon_crtc->h_border); 2875a9bcaccSAlex Deucher args.usH_SyncWidth = 2885a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start); 2895a9bcaccSAlex Deucher args.usV_SyncOffset = 2905b1714d3SAlex Deucher cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay + radeon_crtc->v_border); 2915a9bcaccSAlex Deucher args.usV_SyncWidth = 2925a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start); 2935b1714d3SAlex Deucher args.ucH_Border = radeon_crtc->h_border; 2945b1714d3SAlex Deucher args.ucV_Border = radeon_crtc->v_border; 2955a9bcaccSAlex Deucher 2965a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_NVSYNC) 2975a9bcaccSAlex Deucher misc |= ATOM_VSYNC_POLARITY; 2985a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_NHSYNC) 2995a9bcaccSAlex Deucher misc |= ATOM_HSYNC_POLARITY; 3005a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_CSYNC) 3015a9bcaccSAlex Deucher misc |= ATOM_COMPOSITESYNC; 3025a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_INTERLACE) 3035a9bcaccSAlex Deucher misc |= ATOM_INTERLACE; 3045a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 3055a9bcaccSAlex Deucher misc |= ATOM_DOUBLE_CLOCK_MODE; 3065a9bcaccSAlex Deucher 3075a9bcaccSAlex Deucher args.susModeMiscInfo.usAccess = cpu_to_le16(misc); 3085a9bcaccSAlex Deucher args.ucCRTC = radeon_crtc->crtc_id; 309771fe6b9SJerome Glisse 3105a9bcaccSAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 311771fe6b9SJerome Glisse } 312771fe6b9SJerome Glisse 3135a9bcaccSAlex Deucher static void atombios_crtc_set_timing(struct drm_crtc *crtc, 3145a9bcaccSAlex Deucher struct drm_display_mode *mode) 315771fe6b9SJerome Glisse { 3165a9bcaccSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 317771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 318771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 3195a9bcaccSAlex Deucher SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION args; 320771fe6b9SJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing); 3215a9bcaccSAlex Deucher u16 misc = 0; 322771fe6b9SJerome Glisse 3235a9bcaccSAlex Deucher memset(&args, 0, sizeof(args)); 3245a9bcaccSAlex Deucher args.usH_Total = cpu_to_le16(mode->crtc_htotal); 3255a9bcaccSAlex Deucher args.usH_Disp = cpu_to_le16(mode->crtc_hdisplay); 3265a9bcaccSAlex Deucher args.usH_SyncStart = cpu_to_le16(mode->crtc_hsync_start); 3275a9bcaccSAlex Deucher args.usH_SyncWidth = 3285a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start); 3295a9bcaccSAlex Deucher args.usV_Total = cpu_to_le16(mode->crtc_vtotal); 3305a9bcaccSAlex Deucher args.usV_Disp = cpu_to_le16(mode->crtc_vdisplay); 3315a9bcaccSAlex Deucher args.usV_SyncStart = cpu_to_le16(mode->crtc_vsync_start); 3325a9bcaccSAlex Deucher args.usV_SyncWidth = 3335a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start); 3345a9bcaccSAlex Deucher 3355a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_NVSYNC) 3365a9bcaccSAlex Deucher misc |= ATOM_VSYNC_POLARITY; 3375a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_NHSYNC) 3385a9bcaccSAlex Deucher misc |= ATOM_HSYNC_POLARITY; 3395a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_CSYNC) 3405a9bcaccSAlex Deucher misc |= ATOM_COMPOSITESYNC; 3415a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_INTERLACE) 3425a9bcaccSAlex Deucher misc |= ATOM_INTERLACE; 3435a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 3445a9bcaccSAlex Deucher misc |= ATOM_DOUBLE_CLOCK_MODE; 3455a9bcaccSAlex Deucher 3465a9bcaccSAlex Deucher args.susModeMiscInfo.usAccess = cpu_to_le16(misc); 3475a9bcaccSAlex Deucher args.ucCRTC = radeon_crtc->crtc_id; 348771fe6b9SJerome Glisse 3495a9bcaccSAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 350771fe6b9SJerome Glisse } 351771fe6b9SJerome Glisse 352b792210eSAlex Deucher static void atombios_disable_ss(struct drm_crtc *crtc) 353b792210eSAlex Deucher { 354b792210eSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 355b792210eSAlex Deucher struct drm_device *dev = crtc->dev; 356b792210eSAlex Deucher struct radeon_device *rdev = dev->dev_private; 357b792210eSAlex Deucher u32 ss_cntl; 358b792210eSAlex Deucher 359b792210eSAlex Deucher if (ASIC_IS_DCE4(rdev)) { 360b792210eSAlex Deucher switch (radeon_crtc->pll_id) { 361b792210eSAlex Deucher case ATOM_PPLL1: 362b792210eSAlex Deucher ss_cntl = RREG32(EVERGREEN_P1PLL_SS_CNTL); 363b792210eSAlex Deucher ss_cntl &= ~EVERGREEN_PxPLL_SS_EN; 364b792210eSAlex Deucher WREG32(EVERGREEN_P1PLL_SS_CNTL, ss_cntl); 365b792210eSAlex Deucher break; 366b792210eSAlex Deucher case ATOM_PPLL2: 367b792210eSAlex Deucher ss_cntl = RREG32(EVERGREEN_P2PLL_SS_CNTL); 368b792210eSAlex Deucher ss_cntl &= ~EVERGREEN_PxPLL_SS_EN; 369b792210eSAlex Deucher WREG32(EVERGREEN_P2PLL_SS_CNTL, ss_cntl); 370b792210eSAlex Deucher break; 371b792210eSAlex Deucher case ATOM_DCPLL: 372b792210eSAlex Deucher case ATOM_PPLL_INVALID: 373b792210eSAlex Deucher return; 374b792210eSAlex Deucher } 375b792210eSAlex Deucher } else if (ASIC_IS_AVIVO(rdev)) { 376b792210eSAlex Deucher switch (radeon_crtc->pll_id) { 377b792210eSAlex Deucher case ATOM_PPLL1: 378b792210eSAlex Deucher ss_cntl = RREG32(AVIVO_P1PLL_INT_SS_CNTL); 379b792210eSAlex Deucher ss_cntl &= ~1; 380b792210eSAlex Deucher WREG32(AVIVO_P1PLL_INT_SS_CNTL, ss_cntl); 381b792210eSAlex Deucher break; 382b792210eSAlex Deucher case ATOM_PPLL2: 383b792210eSAlex Deucher ss_cntl = RREG32(AVIVO_P2PLL_INT_SS_CNTL); 384b792210eSAlex Deucher ss_cntl &= ~1; 385b792210eSAlex Deucher WREG32(AVIVO_P2PLL_INT_SS_CNTL, ss_cntl); 386b792210eSAlex Deucher break; 387b792210eSAlex Deucher case ATOM_DCPLL: 388b792210eSAlex Deucher case ATOM_PPLL_INVALID: 389b792210eSAlex Deucher return; 390b792210eSAlex Deucher } 391b792210eSAlex Deucher } 392b792210eSAlex Deucher } 393b792210eSAlex Deucher 394b792210eSAlex Deucher 39526b9fc3aSAlex Deucher union atom_enable_ss { 39626b9fc3aSAlex Deucher ENABLE_LVDS_SS_PARAMETERS legacy; 39726b9fc3aSAlex Deucher ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1; 39826b9fc3aSAlex Deucher }; 39926b9fc3aSAlex Deucher 400b792210eSAlex Deucher static void atombios_enable_ss(struct drm_crtc *crtc) 401ebbe1cb9SAlex Deucher { 402ebbe1cb9SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 403ebbe1cb9SAlex Deucher struct drm_device *dev = crtc->dev; 404ebbe1cb9SAlex Deucher struct radeon_device *rdev = dev->dev_private; 405ebbe1cb9SAlex Deucher struct drm_encoder *encoder = NULL; 406ebbe1cb9SAlex Deucher struct radeon_encoder *radeon_encoder = NULL; 407ebbe1cb9SAlex Deucher struct radeon_encoder_atom_dig *dig = NULL; 408ebbe1cb9SAlex Deucher int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL); 40926b9fc3aSAlex Deucher union atom_enable_ss args; 410ebbe1cb9SAlex Deucher uint16_t percentage = 0; 411ebbe1cb9SAlex Deucher uint8_t type = 0, step = 0, delay = 0, range = 0; 412ebbe1cb9SAlex Deucher 413bcc1c2a1SAlex Deucher /* XXX add ss support for DCE4 */ 414bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) 415bcc1c2a1SAlex Deucher return; 416bcc1c2a1SAlex Deucher 417ebbe1cb9SAlex Deucher list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 418ebbe1cb9SAlex Deucher if (encoder->crtc == crtc) { 419ebbe1cb9SAlex Deucher radeon_encoder = to_radeon_encoder(encoder); 420ebbe1cb9SAlex Deucher /* only enable spread spectrum on LVDS */ 421d11aa88bSAlex Deucher if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 422d11aa88bSAlex Deucher dig = radeon_encoder->enc_priv; 423ebbe1cb9SAlex Deucher if (dig && dig->ss) { 424ebbe1cb9SAlex Deucher percentage = dig->ss->percentage; 425ebbe1cb9SAlex Deucher type = dig->ss->type; 426ebbe1cb9SAlex Deucher step = dig->ss->step; 427ebbe1cb9SAlex Deucher delay = dig->ss->delay; 428ebbe1cb9SAlex Deucher range = dig->ss->range; 429b792210eSAlex Deucher } else 430ebbe1cb9SAlex Deucher return; 431b792210eSAlex Deucher } else 432d11aa88bSAlex Deucher return; 433ebbe1cb9SAlex Deucher break; 434ebbe1cb9SAlex Deucher } 435ebbe1cb9SAlex Deucher } 436ebbe1cb9SAlex Deucher 437ebbe1cb9SAlex Deucher if (!radeon_encoder) 438ebbe1cb9SAlex Deucher return; 439ebbe1cb9SAlex Deucher 440ebbe1cb9SAlex Deucher memset(&args, 0, sizeof(args)); 44126b9fc3aSAlex Deucher if (ASIC_IS_AVIVO(rdev)) { 44226b9fc3aSAlex Deucher args.v1.usSpreadSpectrumPercentage = cpu_to_le16(percentage); 44326b9fc3aSAlex Deucher args.v1.ucSpreadSpectrumType = type; 44426b9fc3aSAlex Deucher args.v1.ucSpreadSpectrumStep = step; 44526b9fc3aSAlex Deucher args.v1.ucSpreadSpectrumDelay = delay; 44626b9fc3aSAlex Deucher args.v1.ucSpreadSpectrumRange = range; 44726b9fc3aSAlex Deucher args.v1.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; 448b792210eSAlex Deucher args.v1.ucEnable = ATOM_ENABLE; 449ebbe1cb9SAlex Deucher } else { 45026b9fc3aSAlex Deucher args.legacy.usSpreadSpectrumPercentage = cpu_to_le16(percentage); 45126b9fc3aSAlex Deucher args.legacy.ucSpreadSpectrumType = type; 45226b9fc3aSAlex Deucher args.legacy.ucSpreadSpectrumStepSize_Delay = (step & 3) << 2; 45326b9fc3aSAlex Deucher args.legacy.ucSpreadSpectrumStepSize_Delay |= (delay & 7) << 4; 454b792210eSAlex Deucher args.legacy.ucEnable = ATOM_ENABLE; 455ebbe1cb9SAlex Deucher } 45626b9fc3aSAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 457ebbe1cb9SAlex Deucher } 458ebbe1cb9SAlex Deucher 4594eaeca33SAlex Deucher union adjust_pixel_clock { 4604eaeca33SAlex Deucher ADJUST_DISPLAY_PLL_PS_ALLOCATION v1; 461bcc1c2a1SAlex Deucher ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 v3; 4624eaeca33SAlex Deucher }; 4634eaeca33SAlex Deucher 4644eaeca33SAlex Deucher static u32 atombios_adjust_pll(struct drm_crtc *crtc, 4654eaeca33SAlex Deucher struct drm_display_mode *mode, 4664eaeca33SAlex Deucher struct radeon_pll *pll) 467771fe6b9SJerome Glisse { 468771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 469771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 470771fe6b9SJerome Glisse struct drm_encoder *encoder = NULL; 471771fe6b9SJerome Glisse struct radeon_encoder *radeon_encoder = NULL; 4724eaeca33SAlex Deucher u32 adjusted_clock = mode->clock; 473bcc1c2a1SAlex Deucher int encoder_mode = 0; 474fbee67a6SAlex Deucher u32 dp_clock = mode->clock; 475fbee67a6SAlex Deucher int bpc = 8; 476fc10332bSAlex Deucher 4774eaeca33SAlex Deucher /* reset the pll flags */ 4784eaeca33SAlex Deucher pll->flags = 0; 479771fe6b9SJerome Glisse 4807c27f87dSAlex Deucher /* select the PLL algo */ 4817c27f87dSAlex Deucher if (ASIC_IS_AVIVO(rdev)) { 482383be5d1SAlex Deucher if (radeon_new_pll == 0) 483383be5d1SAlex Deucher pll->algo = PLL_ALGO_LEGACY; 484383be5d1SAlex Deucher else 485383be5d1SAlex Deucher pll->algo = PLL_ALGO_NEW; 486383be5d1SAlex Deucher } else { 487383be5d1SAlex Deucher if (radeon_new_pll == 1) 488383be5d1SAlex Deucher pll->algo = PLL_ALGO_NEW; 4897c27f87dSAlex Deucher else 4907c27f87dSAlex Deucher pll->algo = PLL_ALGO_LEGACY; 491383be5d1SAlex Deucher } 4927c27f87dSAlex Deucher 493771fe6b9SJerome Glisse if (ASIC_IS_AVIVO(rdev)) { 494eb1300bcSAlex Deucher if ((rdev->family == CHIP_RS600) || 495eb1300bcSAlex Deucher (rdev->family == CHIP_RS690) || 496eb1300bcSAlex Deucher (rdev->family == CHIP_RS740)) 4972ff776cfSAlex Deucher pll->flags |= (/*RADEON_PLL_USE_FRAC_FB_DIV |*/ 498eb1300bcSAlex Deucher RADEON_PLL_PREFER_CLOSEST_LOWER); 499eb1300bcSAlex Deucher 500771fe6b9SJerome Glisse if (ASIC_IS_DCE32(rdev) && mode->clock > 200000) /* range limits??? */ 501fc10332bSAlex Deucher pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; 502771fe6b9SJerome Glisse else 503fc10332bSAlex Deucher pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; 504771fe6b9SJerome Glisse } else { 505fc10332bSAlex Deucher pll->flags |= RADEON_PLL_LEGACY; 506771fe6b9SJerome Glisse 507771fe6b9SJerome Glisse if (mode->clock > 200000) /* range limits??? */ 508fc10332bSAlex Deucher pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; 509771fe6b9SJerome Glisse else 510fc10332bSAlex Deucher pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; 511771fe6b9SJerome Glisse 512771fe6b9SJerome Glisse } 513771fe6b9SJerome Glisse 514771fe6b9SJerome Glisse list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 515771fe6b9SJerome Glisse if (encoder->crtc == crtc) { 5164eaeca33SAlex Deucher radeon_encoder = to_radeon_encoder(encoder); 517bcc1c2a1SAlex Deucher encoder_mode = atombios_get_encoder_mode(encoder); 518fbee67a6SAlex Deucher if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) { 519fbee67a6SAlex Deucher struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); 520fbee67a6SAlex Deucher if (connector) { 521fbee67a6SAlex Deucher struct radeon_connector *radeon_connector = to_radeon_connector(connector); 522fbee67a6SAlex Deucher struct radeon_connector_atom_dig *dig_connector = 523fbee67a6SAlex Deucher radeon_connector->con_priv; 524fbee67a6SAlex Deucher 525fbee67a6SAlex Deucher dp_clock = dig_connector->dp_clock; 526fbee67a6SAlex Deucher } 527fbee67a6SAlex Deucher } 528fbee67a6SAlex Deucher 5294eaeca33SAlex Deucher if (ASIC_IS_AVIVO(rdev)) { 5304eaeca33SAlex Deucher /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ 5314eaeca33SAlex Deucher if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1) 5324eaeca33SAlex Deucher adjusted_clock = mode->clock * 2; 533a1a4b23bSAlex Deucher if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) { 534a1a4b23bSAlex Deucher pll->algo = PLL_ALGO_LEGACY; 535a1a4b23bSAlex Deucher pll->flags |= RADEON_PLL_PREFER_CLOSEST_LOWER; 536a1a4b23bSAlex Deucher } 5370d9958b1SAlex Deucher /* There is some evidence (often anecdotal) that RV515 LVDS 5380d9958b1SAlex Deucher * (on some boards at least) prefers the legacy algo. I'm not 5390d9958b1SAlex Deucher * sure whether this should handled generically or on a 5400d9958b1SAlex Deucher * case-by-case quirk basis. Both algos should work fine in the 5410d9958b1SAlex Deucher * majority of cases. 5420d9958b1SAlex Deucher */ 5430d9958b1SAlex Deucher if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) && 5440d9958b1SAlex Deucher (rdev->family == CHIP_RV515)) { 5450d9958b1SAlex Deucher /* allow the user to overrride just in case */ 5460d9958b1SAlex Deucher if (radeon_new_pll == 1) 5470d9958b1SAlex Deucher pll->algo = PLL_ALGO_NEW; 5480d9958b1SAlex Deucher else 5490d9958b1SAlex Deucher pll->algo = PLL_ALGO_LEGACY; 5500d9958b1SAlex Deucher } 5514eaeca33SAlex Deucher } else { 5524eaeca33SAlex Deucher if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) 553fc10332bSAlex Deucher pll->flags |= RADEON_PLL_NO_ODD_POST_DIV; 5544eaeca33SAlex Deucher if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) 555fc10332bSAlex Deucher pll->flags |= RADEON_PLL_USE_REF_DIV; 556771fe6b9SJerome Glisse } 5573ce0a23dSJerome Glisse break; 558771fe6b9SJerome Glisse } 559771fe6b9SJerome Glisse } 560771fe6b9SJerome Glisse 5612606c886SAlex Deucher /* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock 5622606c886SAlex Deucher * accordingly based on the encoder/transmitter to work around 5632606c886SAlex Deucher * special hw requirements. 5642606c886SAlex Deucher */ 5652606c886SAlex Deucher if (ASIC_IS_DCE3(rdev)) { 5664eaeca33SAlex Deucher union adjust_pixel_clock args; 5674eaeca33SAlex Deucher u8 frev, crev; 5684eaeca33SAlex Deucher int index; 5692606c886SAlex Deucher 5702606c886SAlex Deucher index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll); 571a084e6eeSAlex Deucher if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 572a084e6eeSAlex Deucher &crev)) 573a084e6eeSAlex Deucher return adjusted_clock; 5744eaeca33SAlex Deucher 5754eaeca33SAlex Deucher memset(&args, 0, sizeof(args)); 5764eaeca33SAlex Deucher 5774eaeca33SAlex Deucher switch (frev) { 5784eaeca33SAlex Deucher case 1: 5794eaeca33SAlex Deucher switch (crev) { 5804eaeca33SAlex Deucher case 1: 5814eaeca33SAlex Deucher case 2: 5824eaeca33SAlex Deucher args.v1.usPixelClock = cpu_to_le16(mode->clock / 10); 5834eaeca33SAlex Deucher args.v1.ucTransmitterID = radeon_encoder->encoder_id; 584bcc1c2a1SAlex Deucher args.v1.ucEncodeMode = encoder_mode; 585fbee67a6SAlex Deucher if (encoder_mode == ATOM_ENCODER_MODE_DP) { 586fbee67a6SAlex Deucher /* may want to enable SS on DP eventually */ 587fbee67a6SAlex Deucher /* args.v1.ucConfig |= 588fbee67a6SAlex Deucher ADJUST_DISPLAY_CONFIG_SS_ENABLE;*/ 589fbee67a6SAlex Deucher } else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) { 590fbee67a6SAlex Deucher args.v1.ucConfig |= 591fbee67a6SAlex Deucher ADJUST_DISPLAY_CONFIG_SS_ENABLE; 592fbee67a6SAlex Deucher } 5934eaeca33SAlex Deucher 5942606c886SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, 5954eaeca33SAlex Deucher index, (uint32_t *)&args); 5964eaeca33SAlex Deucher adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10; 5974eaeca33SAlex Deucher break; 598bcc1c2a1SAlex Deucher case 3: 599bcc1c2a1SAlex Deucher args.v3.sInput.usPixelClock = cpu_to_le16(mode->clock / 10); 600bcc1c2a1SAlex Deucher args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id; 601bcc1c2a1SAlex Deucher args.v3.sInput.ucEncodeMode = encoder_mode; 602bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig = 0; 603bcc1c2a1SAlex Deucher if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { 604bcc1c2a1SAlex Deucher struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 605bcc1c2a1SAlex Deucher 606fbee67a6SAlex Deucher if (encoder_mode == ATOM_ENCODER_MODE_DP) { 607fbee67a6SAlex Deucher /* may want to enable SS on DP/eDP eventually */ 608fbee67a6SAlex Deucher /*args.v3.sInput.ucDispPllConfig |= 609fbee67a6SAlex Deucher DISPPLL_CONFIG_SS_ENABLE;*/ 610bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 611bcc1c2a1SAlex Deucher DISPPLL_CONFIG_COHERENT_MODE; 612fbee67a6SAlex Deucher /* 16200 or 27000 */ 613fbee67a6SAlex Deucher args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); 614fbee67a6SAlex Deucher } else { 615fbee67a6SAlex Deucher if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { 616fbee67a6SAlex Deucher /* deep color support */ 617fbee67a6SAlex Deucher args.v3.sInput.usPixelClock = 618fbee67a6SAlex Deucher cpu_to_le16((mode->clock * bpc / 8) / 10); 619fbee67a6SAlex Deucher } 620bcc1c2a1SAlex Deucher if (dig->coherent_mode) 621bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 622bcc1c2a1SAlex Deucher DISPPLL_CONFIG_COHERENT_MODE; 623bcc1c2a1SAlex Deucher if (mode->clock > 165000) 624bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 625bcc1c2a1SAlex Deucher DISPPLL_CONFIG_DUAL_LINK; 626bcc1c2a1SAlex Deucher } 627bcc1c2a1SAlex Deucher } else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 628fbee67a6SAlex Deucher if (encoder_mode == ATOM_ENCODER_MODE_DP) { 629bcc1c2a1SAlex Deucher /* may want to enable SS on DP/eDP eventually */ 6309f998ad7SAlex Deucher /*args.v3.sInput.ucDispPllConfig |= 6319f998ad7SAlex Deucher DISPPLL_CONFIG_SS_ENABLE;*/ 632bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 6339f998ad7SAlex Deucher DISPPLL_CONFIG_COHERENT_MODE; 634fbee67a6SAlex Deucher /* 16200 or 27000 */ 635fbee67a6SAlex Deucher args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); 636fbee67a6SAlex Deucher } else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) { 637fbee67a6SAlex Deucher /* want to enable SS on LVDS eventually */ 638fbee67a6SAlex Deucher /*args.v3.sInput.ucDispPllConfig |= 639fbee67a6SAlex Deucher DISPPLL_CONFIG_SS_ENABLE;*/ 640fbee67a6SAlex Deucher } else { 641bcc1c2a1SAlex Deucher if (mode->clock > 165000) 642bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 643bcc1c2a1SAlex Deucher DISPPLL_CONFIG_DUAL_LINK; 644bcc1c2a1SAlex Deucher } 6459f998ad7SAlex Deucher } 646bcc1c2a1SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, 647bcc1c2a1SAlex Deucher index, (uint32_t *)&args); 648bcc1c2a1SAlex Deucher adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10; 649bcc1c2a1SAlex Deucher if (args.v3.sOutput.ucRefDiv) { 650bcc1c2a1SAlex Deucher pll->flags |= RADEON_PLL_USE_REF_DIV; 651bcc1c2a1SAlex Deucher pll->reference_div = args.v3.sOutput.ucRefDiv; 652bcc1c2a1SAlex Deucher } 653bcc1c2a1SAlex Deucher if (args.v3.sOutput.ucPostDiv) { 654bcc1c2a1SAlex Deucher pll->flags |= RADEON_PLL_USE_POST_DIV; 655bcc1c2a1SAlex Deucher pll->post_div = args.v3.sOutput.ucPostDiv; 656bcc1c2a1SAlex Deucher } 657bcc1c2a1SAlex Deucher break; 6584eaeca33SAlex Deucher default: 6594eaeca33SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 6604eaeca33SAlex Deucher return adjusted_clock; 661d56ef9c8SAlex Deucher } 6624eaeca33SAlex Deucher break; 6634eaeca33SAlex Deucher default: 6644eaeca33SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 6654eaeca33SAlex Deucher return adjusted_clock; 6664eaeca33SAlex Deucher } 6674eaeca33SAlex Deucher } 6684eaeca33SAlex Deucher return adjusted_clock; 6694eaeca33SAlex Deucher } 6704eaeca33SAlex Deucher 6714eaeca33SAlex Deucher union set_pixel_clock { 6724eaeca33SAlex Deucher SET_PIXEL_CLOCK_PS_ALLOCATION base; 6734eaeca33SAlex Deucher PIXEL_CLOCK_PARAMETERS v1; 6744eaeca33SAlex Deucher PIXEL_CLOCK_PARAMETERS_V2 v2; 6754eaeca33SAlex Deucher PIXEL_CLOCK_PARAMETERS_V3 v3; 676bcc1c2a1SAlex Deucher PIXEL_CLOCK_PARAMETERS_V5 v5; 6774eaeca33SAlex Deucher }; 6784eaeca33SAlex Deucher 679bcc1c2a1SAlex Deucher static void atombios_crtc_set_dcpll(struct drm_crtc *crtc) 680bcc1c2a1SAlex Deucher { 681bcc1c2a1SAlex Deucher struct drm_device *dev = crtc->dev; 682bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 683bcc1c2a1SAlex Deucher u8 frev, crev; 684bcc1c2a1SAlex Deucher int index; 685bcc1c2a1SAlex Deucher union set_pixel_clock args; 686bcc1c2a1SAlex Deucher 687bcc1c2a1SAlex Deucher memset(&args, 0, sizeof(args)); 688bcc1c2a1SAlex Deucher 689bcc1c2a1SAlex Deucher index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); 690a084e6eeSAlex Deucher if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 691a084e6eeSAlex Deucher &crev)) 692a084e6eeSAlex Deucher return; 693bcc1c2a1SAlex Deucher 694bcc1c2a1SAlex Deucher switch (frev) { 695bcc1c2a1SAlex Deucher case 1: 696bcc1c2a1SAlex Deucher switch (crev) { 697bcc1c2a1SAlex Deucher case 5: 698bcc1c2a1SAlex Deucher /* if the default dcpll clock is specified, 699bcc1c2a1SAlex Deucher * SetPixelClock provides the dividers 700bcc1c2a1SAlex Deucher */ 701bcc1c2a1SAlex Deucher args.v5.ucCRTC = ATOM_CRTC_INVALID; 702bcc1c2a1SAlex Deucher args.v5.usPixelClock = rdev->clock.default_dispclk; 703bcc1c2a1SAlex Deucher args.v5.ucPpll = ATOM_DCPLL; 704bcc1c2a1SAlex Deucher break; 705bcc1c2a1SAlex Deucher default: 706bcc1c2a1SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 707bcc1c2a1SAlex Deucher return; 708bcc1c2a1SAlex Deucher } 709bcc1c2a1SAlex Deucher break; 710bcc1c2a1SAlex Deucher default: 711bcc1c2a1SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 712bcc1c2a1SAlex Deucher return; 713bcc1c2a1SAlex Deucher } 714bcc1c2a1SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 715bcc1c2a1SAlex Deucher } 716bcc1c2a1SAlex Deucher 71737f9003bSAlex Deucher static void atombios_crtc_program_pll(struct drm_crtc *crtc, 71837f9003bSAlex Deucher int crtc_id, 71937f9003bSAlex Deucher int pll_id, 72037f9003bSAlex Deucher u32 encoder_mode, 72137f9003bSAlex Deucher u32 encoder_id, 72237f9003bSAlex Deucher u32 clock, 72337f9003bSAlex Deucher u32 ref_div, 72437f9003bSAlex Deucher u32 fb_div, 72537f9003bSAlex Deucher u32 frac_fb_div, 72637f9003bSAlex Deucher u32 post_div) 72737f9003bSAlex Deucher { 72837f9003bSAlex Deucher struct drm_device *dev = crtc->dev; 72937f9003bSAlex Deucher struct radeon_device *rdev = dev->dev_private; 73037f9003bSAlex Deucher u8 frev, crev; 73137f9003bSAlex Deucher int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); 73237f9003bSAlex Deucher union set_pixel_clock args; 73337f9003bSAlex Deucher 73437f9003bSAlex Deucher memset(&args, 0, sizeof(args)); 73537f9003bSAlex Deucher 73637f9003bSAlex Deucher if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 73737f9003bSAlex Deucher &crev)) 73837f9003bSAlex Deucher return; 73937f9003bSAlex Deucher 74037f9003bSAlex Deucher switch (frev) { 74137f9003bSAlex Deucher case 1: 74237f9003bSAlex Deucher switch (crev) { 74337f9003bSAlex Deucher case 1: 74437f9003bSAlex Deucher if (clock == ATOM_DISABLE) 74537f9003bSAlex Deucher return; 74637f9003bSAlex Deucher args.v1.usPixelClock = cpu_to_le16(clock / 10); 74737f9003bSAlex Deucher args.v1.usRefDiv = cpu_to_le16(ref_div); 74837f9003bSAlex Deucher args.v1.usFbDiv = cpu_to_le16(fb_div); 74937f9003bSAlex Deucher args.v1.ucFracFbDiv = frac_fb_div; 75037f9003bSAlex Deucher args.v1.ucPostDiv = post_div; 75137f9003bSAlex Deucher args.v1.ucPpll = pll_id; 75237f9003bSAlex Deucher args.v1.ucCRTC = crtc_id; 75337f9003bSAlex Deucher args.v1.ucRefDivSrc = 1; 75437f9003bSAlex Deucher break; 75537f9003bSAlex Deucher case 2: 75637f9003bSAlex Deucher args.v2.usPixelClock = cpu_to_le16(clock / 10); 75737f9003bSAlex Deucher args.v2.usRefDiv = cpu_to_le16(ref_div); 75837f9003bSAlex Deucher args.v2.usFbDiv = cpu_to_le16(fb_div); 75937f9003bSAlex Deucher args.v2.ucFracFbDiv = frac_fb_div; 76037f9003bSAlex Deucher args.v2.ucPostDiv = post_div; 76137f9003bSAlex Deucher args.v2.ucPpll = pll_id; 76237f9003bSAlex Deucher args.v2.ucCRTC = crtc_id; 76337f9003bSAlex Deucher args.v2.ucRefDivSrc = 1; 76437f9003bSAlex Deucher break; 76537f9003bSAlex Deucher case 3: 76637f9003bSAlex Deucher args.v3.usPixelClock = cpu_to_le16(clock / 10); 76737f9003bSAlex Deucher args.v3.usRefDiv = cpu_to_le16(ref_div); 76837f9003bSAlex Deucher args.v3.usFbDiv = cpu_to_le16(fb_div); 76937f9003bSAlex Deucher args.v3.ucFracFbDiv = frac_fb_div; 77037f9003bSAlex Deucher args.v3.ucPostDiv = post_div; 77137f9003bSAlex Deucher args.v3.ucPpll = pll_id; 77237f9003bSAlex Deucher args.v3.ucMiscInfo = (pll_id << 2); 77337f9003bSAlex Deucher args.v3.ucTransmitterId = encoder_id; 77437f9003bSAlex Deucher args.v3.ucEncoderMode = encoder_mode; 77537f9003bSAlex Deucher break; 77637f9003bSAlex Deucher case 5: 77737f9003bSAlex Deucher args.v5.ucCRTC = crtc_id; 77837f9003bSAlex Deucher args.v5.usPixelClock = cpu_to_le16(clock / 10); 77937f9003bSAlex Deucher args.v5.ucRefDiv = ref_div; 78037f9003bSAlex Deucher args.v5.usFbDiv = cpu_to_le16(fb_div); 78137f9003bSAlex Deucher args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); 78237f9003bSAlex Deucher args.v5.ucPostDiv = post_div; 78337f9003bSAlex Deucher args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */ 78437f9003bSAlex Deucher args.v5.ucTransmitterID = encoder_id; 78537f9003bSAlex Deucher args.v5.ucEncoderMode = encoder_mode; 78637f9003bSAlex Deucher args.v5.ucPpll = pll_id; 78737f9003bSAlex Deucher break; 78837f9003bSAlex Deucher default: 78937f9003bSAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 79037f9003bSAlex Deucher return; 79137f9003bSAlex Deucher } 79237f9003bSAlex Deucher break; 79337f9003bSAlex Deucher default: 79437f9003bSAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 79537f9003bSAlex Deucher return; 79637f9003bSAlex Deucher } 79737f9003bSAlex Deucher 79837f9003bSAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 79937f9003bSAlex Deucher } 80037f9003bSAlex Deucher 801bcc1c2a1SAlex Deucher static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) 8024eaeca33SAlex Deucher { 8034eaeca33SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 8044eaeca33SAlex Deucher struct drm_device *dev = crtc->dev; 8054eaeca33SAlex Deucher struct radeon_device *rdev = dev->dev_private; 8064eaeca33SAlex Deucher struct drm_encoder *encoder = NULL; 8074eaeca33SAlex Deucher struct radeon_encoder *radeon_encoder = NULL; 8084eaeca33SAlex Deucher u32 pll_clock = mode->clock; 8094eaeca33SAlex Deucher u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; 8104eaeca33SAlex Deucher struct radeon_pll *pll; 8114eaeca33SAlex Deucher u32 adjusted_clock; 812bcc1c2a1SAlex Deucher int encoder_mode = 0; 8134eaeca33SAlex Deucher 8144eaeca33SAlex Deucher list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 8154eaeca33SAlex Deucher if (encoder->crtc == crtc) { 8164eaeca33SAlex Deucher radeon_encoder = to_radeon_encoder(encoder); 817bcc1c2a1SAlex Deucher encoder_mode = atombios_get_encoder_mode(encoder); 8184eaeca33SAlex Deucher break; 8194eaeca33SAlex Deucher } 8204eaeca33SAlex Deucher } 8214eaeca33SAlex Deucher 8224eaeca33SAlex Deucher if (!radeon_encoder) 8234eaeca33SAlex Deucher return; 8244eaeca33SAlex Deucher 825bcc1c2a1SAlex Deucher switch (radeon_crtc->pll_id) { 826bcc1c2a1SAlex Deucher case ATOM_PPLL1: 8274eaeca33SAlex Deucher pll = &rdev->clock.p1pll; 828bcc1c2a1SAlex Deucher break; 829bcc1c2a1SAlex Deucher case ATOM_PPLL2: 8304eaeca33SAlex Deucher pll = &rdev->clock.p2pll; 831bcc1c2a1SAlex Deucher break; 832bcc1c2a1SAlex Deucher case ATOM_DCPLL: 833bcc1c2a1SAlex Deucher case ATOM_PPLL_INVALID: 834921d98b5SStefan Richter default: 835bcc1c2a1SAlex Deucher pll = &rdev->clock.dcpll; 836bcc1c2a1SAlex Deucher break; 837bcc1c2a1SAlex Deucher } 8384eaeca33SAlex Deucher 8394eaeca33SAlex Deucher /* adjust pixel clock as needed */ 8404eaeca33SAlex Deucher adjusted_clock = atombios_adjust_pll(crtc, mode, pll); 8412606c886SAlex Deucher 8422606c886SAlex Deucher radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, 843fc10332bSAlex Deucher &ref_div, &post_div); 844771fe6b9SJerome Glisse 84537f9003bSAlex Deucher atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, 84637f9003bSAlex Deucher encoder_mode, radeon_encoder->encoder_id, mode->clock, 84737f9003bSAlex Deucher ref_div, fb_div, frac_fb_div, post_div); 848771fe6b9SJerome Glisse 849771fe6b9SJerome Glisse } 850771fe6b9SJerome Glisse 851bcc1c2a1SAlex Deucher static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y, 852bcc1c2a1SAlex Deucher struct drm_framebuffer *old_fb) 853bcc1c2a1SAlex Deucher { 854bcc1c2a1SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 855bcc1c2a1SAlex Deucher struct drm_device *dev = crtc->dev; 856bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 857bcc1c2a1SAlex Deucher struct radeon_framebuffer *radeon_fb; 858bcc1c2a1SAlex Deucher struct drm_gem_object *obj; 859bcc1c2a1SAlex Deucher struct radeon_bo *rbo; 860bcc1c2a1SAlex Deucher uint64_t fb_location; 861bcc1c2a1SAlex Deucher uint32_t fb_format, fb_pitch_pixels, tiling_flags; 862bcc1c2a1SAlex Deucher int r; 863bcc1c2a1SAlex Deucher 864bcc1c2a1SAlex Deucher /* no fb bound */ 865bcc1c2a1SAlex Deucher if (!crtc->fb) { 866d9fdaafbSDave Airlie DRM_DEBUG_KMS("No FB bound\n"); 867bcc1c2a1SAlex Deucher return 0; 868bcc1c2a1SAlex Deucher } 869bcc1c2a1SAlex Deucher 870bcc1c2a1SAlex Deucher radeon_fb = to_radeon_framebuffer(crtc->fb); 871bcc1c2a1SAlex Deucher 872bcc1c2a1SAlex Deucher /* Pin framebuffer & get tilling informations */ 873bcc1c2a1SAlex Deucher obj = radeon_fb->obj; 874bcc1c2a1SAlex Deucher rbo = obj->driver_private; 875bcc1c2a1SAlex Deucher r = radeon_bo_reserve(rbo, false); 876bcc1c2a1SAlex Deucher if (unlikely(r != 0)) 877bcc1c2a1SAlex Deucher return r; 878bcc1c2a1SAlex Deucher r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); 879bcc1c2a1SAlex Deucher if (unlikely(r != 0)) { 880bcc1c2a1SAlex Deucher radeon_bo_unreserve(rbo); 881bcc1c2a1SAlex Deucher return -EINVAL; 882bcc1c2a1SAlex Deucher } 883bcc1c2a1SAlex Deucher radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); 884bcc1c2a1SAlex Deucher radeon_bo_unreserve(rbo); 885bcc1c2a1SAlex Deucher 886bcc1c2a1SAlex Deucher switch (crtc->fb->bits_per_pixel) { 887bcc1c2a1SAlex Deucher case 8: 888bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP) | 889bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED)); 890bcc1c2a1SAlex Deucher break; 891bcc1c2a1SAlex Deucher case 15: 892bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 893bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB1555)); 894bcc1c2a1SAlex Deucher break; 895bcc1c2a1SAlex Deucher case 16: 896bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 897bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565)); 898bcc1c2a1SAlex Deucher break; 899bcc1c2a1SAlex Deucher case 24: 900bcc1c2a1SAlex Deucher case 32: 901bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) | 902bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888)); 903bcc1c2a1SAlex Deucher break; 904bcc1c2a1SAlex Deucher default: 905bcc1c2a1SAlex Deucher DRM_ERROR("Unsupported screen depth %d\n", 906bcc1c2a1SAlex Deucher crtc->fb->bits_per_pixel); 907bcc1c2a1SAlex Deucher return -EINVAL; 908bcc1c2a1SAlex Deucher } 909bcc1c2a1SAlex Deucher 91097d66328SAlex Deucher if (tiling_flags & RADEON_TILING_MACRO) 91197d66328SAlex Deucher fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1); 91297d66328SAlex Deucher else if (tiling_flags & RADEON_TILING_MICRO) 91397d66328SAlex Deucher fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1); 91497d66328SAlex Deucher 915bcc1c2a1SAlex Deucher switch (radeon_crtc->crtc_id) { 916bcc1c2a1SAlex Deucher case 0: 917bcc1c2a1SAlex Deucher WREG32(AVIVO_D1VGA_CONTROL, 0); 918bcc1c2a1SAlex Deucher break; 919bcc1c2a1SAlex Deucher case 1: 920bcc1c2a1SAlex Deucher WREG32(AVIVO_D2VGA_CONTROL, 0); 921bcc1c2a1SAlex Deucher break; 922bcc1c2a1SAlex Deucher case 2: 923bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D3VGA_CONTROL, 0); 924bcc1c2a1SAlex Deucher break; 925bcc1c2a1SAlex Deucher case 3: 926bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D4VGA_CONTROL, 0); 927bcc1c2a1SAlex Deucher break; 928bcc1c2a1SAlex Deucher case 4: 929bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D5VGA_CONTROL, 0); 930bcc1c2a1SAlex Deucher break; 931bcc1c2a1SAlex Deucher case 5: 932bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D6VGA_CONTROL, 0); 933bcc1c2a1SAlex Deucher break; 934bcc1c2a1SAlex Deucher default: 935bcc1c2a1SAlex Deucher break; 936bcc1c2a1SAlex Deucher } 937bcc1c2a1SAlex Deucher 938bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 939bcc1c2a1SAlex Deucher upper_32_bits(fb_location)); 940bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 941bcc1c2a1SAlex Deucher upper_32_bits(fb_location)); 942bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 943bcc1c2a1SAlex Deucher (u32)fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK); 944bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 945bcc1c2a1SAlex Deucher (u32) fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK); 946bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); 947bcc1c2a1SAlex Deucher 948bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); 949bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); 950bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_X_START + radeon_crtc->crtc_offset, 0); 951bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_Y_START + radeon_crtc->crtc_offset, 0); 952bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_X_END + radeon_crtc->crtc_offset, crtc->fb->width); 953bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_Y_END + radeon_crtc->crtc_offset, crtc->fb->height); 954bcc1c2a1SAlex Deucher 955bcc1c2a1SAlex Deucher fb_pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8); 956bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); 957bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1); 958bcc1c2a1SAlex Deucher 959bcc1c2a1SAlex Deucher WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, 960bcc1c2a1SAlex Deucher crtc->mode.vdisplay); 961bcc1c2a1SAlex Deucher x &= ~3; 962bcc1c2a1SAlex Deucher y &= ~1; 963bcc1c2a1SAlex Deucher WREG32(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset, 964bcc1c2a1SAlex Deucher (x << 16) | y); 965bcc1c2a1SAlex Deucher WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset, 966bcc1c2a1SAlex Deucher (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay); 967bcc1c2a1SAlex Deucher 968bcc1c2a1SAlex Deucher if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) 969bcc1c2a1SAlex Deucher WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 970bcc1c2a1SAlex Deucher EVERGREEN_INTERLEAVE_EN); 971bcc1c2a1SAlex Deucher else 972bcc1c2a1SAlex Deucher WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 0); 973bcc1c2a1SAlex Deucher 974bcc1c2a1SAlex Deucher if (old_fb && old_fb != crtc->fb) { 975bcc1c2a1SAlex Deucher radeon_fb = to_radeon_framebuffer(old_fb); 976bcc1c2a1SAlex Deucher rbo = radeon_fb->obj->driver_private; 977bcc1c2a1SAlex Deucher r = radeon_bo_reserve(rbo, false); 978bcc1c2a1SAlex Deucher if (unlikely(r != 0)) 979bcc1c2a1SAlex Deucher return r; 980bcc1c2a1SAlex Deucher radeon_bo_unpin(rbo); 981bcc1c2a1SAlex Deucher radeon_bo_unreserve(rbo); 982bcc1c2a1SAlex Deucher } 983bcc1c2a1SAlex Deucher 984bcc1c2a1SAlex Deucher /* Bytes per pixel may have changed */ 985bcc1c2a1SAlex Deucher radeon_bandwidth_update(rdev); 986bcc1c2a1SAlex Deucher 987bcc1c2a1SAlex Deucher return 0; 988bcc1c2a1SAlex Deucher } 989bcc1c2a1SAlex Deucher 99054f088a9SAlex Deucher static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y, 991771fe6b9SJerome Glisse struct drm_framebuffer *old_fb) 992771fe6b9SJerome Glisse { 993771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 994771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 995771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 996771fe6b9SJerome Glisse struct radeon_framebuffer *radeon_fb; 997771fe6b9SJerome Glisse struct drm_gem_object *obj; 9984c788679SJerome Glisse struct radeon_bo *rbo; 999771fe6b9SJerome Glisse uint64_t fb_location; 1000e024e110SDave Airlie uint32_t fb_format, fb_pitch_pixels, tiling_flags; 10014c788679SJerome Glisse int r; 1002771fe6b9SJerome Glisse 10032de3b484SJerome Glisse /* no fb bound */ 10042de3b484SJerome Glisse if (!crtc->fb) { 1005d9fdaafbSDave Airlie DRM_DEBUG_KMS("No FB bound\n"); 10062de3b484SJerome Glisse return 0; 10072de3b484SJerome Glisse } 1008771fe6b9SJerome Glisse 1009771fe6b9SJerome Glisse radeon_fb = to_radeon_framebuffer(crtc->fb); 1010771fe6b9SJerome Glisse 10114c788679SJerome Glisse /* Pin framebuffer & get tilling informations */ 1012771fe6b9SJerome Glisse obj = radeon_fb->obj; 10134c788679SJerome Glisse rbo = obj->driver_private; 10144c788679SJerome Glisse r = radeon_bo_reserve(rbo, false); 10154c788679SJerome Glisse if (unlikely(r != 0)) 10164c788679SJerome Glisse return r; 10174c788679SJerome Glisse r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); 10184c788679SJerome Glisse if (unlikely(r != 0)) { 10194c788679SJerome Glisse radeon_bo_unreserve(rbo); 1020771fe6b9SJerome Glisse return -EINVAL; 1021771fe6b9SJerome Glisse } 10224c788679SJerome Glisse radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); 10234c788679SJerome Glisse radeon_bo_unreserve(rbo); 1024771fe6b9SJerome Glisse 1025771fe6b9SJerome Glisse switch (crtc->fb->bits_per_pixel) { 102641456df2SDave Airlie case 8: 102741456df2SDave Airlie fb_format = 102841456df2SDave Airlie AVIVO_D1GRPH_CONTROL_DEPTH_8BPP | 102941456df2SDave Airlie AVIVO_D1GRPH_CONTROL_8BPP_INDEXED; 103041456df2SDave Airlie break; 1031771fe6b9SJerome Glisse case 15: 1032771fe6b9SJerome Glisse fb_format = 1033771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | 1034771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555; 1035771fe6b9SJerome Glisse break; 1036771fe6b9SJerome Glisse case 16: 1037771fe6b9SJerome Glisse fb_format = 1038771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | 1039771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_16BPP_RGB565; 1040771fe6b9SJerome Glisse break; 1041771fe6b9SJerome Glisse case 24: 1042771fe6b9SJerome Glisse case 32: 1043771fe6b9SJerome Glisse fb_format = 1044771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_32BPP | 1045771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888; 1046771fe6b9SJerome Glisse break; 1047771fe6b9SJerome Glisse default: 1048771fe6b9SJerome Glisse DRM_ERROR("Unsupported screen depth %d\n", 1049771fe6b9SJerome Glisse crtc->fb->bits_per_pixel); 1050771fe6b9SJerome Glisse return -EINVAL; 1051771fe6b9SJerome Glisse } 1052771fe6b9SJerome Glisse 105340c4ac1cSAlex Deucher if (rdev->family >= CHIP_R600) { 105440c4ac1cSAlex Deucher if (tiling_flags & RADEON_TILING_MACRO) 105540c4ac1cSAlex Deucher fb_format |= R600_D1GRPH_ARRAY_MODE_2D_TILED_THIN1; 105640c4ac1cSAlex Deucher else if (tiling_flags & RADEON_TILING_MICRO) 105740c4ac1cSAlex Deucher fb_format |= R600_D1GRPH_ARRAY_MODE_1D_TILED_THIN1; 105840c4ac1cSAlex Deucher } else { 1059cf2f05d3SDave Airlie if (tiling_flags & RADEON_TILING_MACRO) 1060cf2f05d3SDave Airlie fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE; 1061cf2f05d3SDave Airlie 1062e024e110SDave Airlie if (tiling_flags & RADEON_TILING_MICRO) 1063e024e110SDave Airlie fb_format |= AVIVO_D1GRPH_TILED; 106440c4ac1cSAlex Deucher } 1065e024e110SDave Airlie 1066771fe6b9SJerome Glisse if (radeon_crtc->crtc_id == 0) 1067771fe6b9SJerome Glisse WREG32(AVIVO_D1VGA_CONTROL, 0); 1068771fe6b9SJerome Glisse else 1069771fe6b9SJerome Glisse WREG32(AVIVO_D2VGA_CONTROL, 0); 1070c290dadfSAlex Deucher 1071c290dadfSAlex Deucher if (rdev->family >= CHIP_RV770) { 1072c290dadfSAlex Deucher if (radeon_crtc->crtc_id) { 1073c290dadfSAlex Deucher WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, 0); 1074c290dadfSAlex Deucher WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, 0); 1075c290dadfSAlex Deucher } else { 1076c290dadfSAlex Deucher WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, 0); 1077c290dadfSAlex Deucher WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, 0); 1078c290dadfSAlex Deucher } 1079c290dadfSAlex Deucher } 1080771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 1081771fe6b9SJerome Glisse (u32) fb_location); 1082771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + 1083771fe6b9SJerome Glisse radeon_crtc->crtc_offset, (u32) fb_location); 1084771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); 1085771fe6b9SJerome Glisse 1086771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); 1087771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); 1088771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0); 1089771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, 0); 1090771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, crtc->fb->width); 1091771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, crtc->fb->height); 1092771fe6b9SJerome Glisse 1093771fe6b9SJerome Glisse fb_pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8); 1094771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); 1095771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1); 1096771fe6b9SJerome Glisse 1097771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, 1098771fe6b9SJerome Glisse crtc->mode.vdisplay); 1099771fe6b9SJerome Glisse x &= ~3; 1100771fe6b9SJerome Glisse y &= ~1; 1101771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset, 1102771fe6b9SJerome Glisse (x << 16) | y); 1103771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset, 1104771fe6b9SJerome Glisse (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay); 1105771fe6b9SJerome Glisse 1106771fe6b9SJerome Glisse if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) 1107771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 1108771fe6b9SJerome Glisse AVIVO_D1MODE_INTERLEAVE_EN); 1109771fe6b9SJerome Glisse else 1110771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0); 1111771fe6b9SJerome Glisse 1112771fe6b9SJerome Glisse if (old_fb && old_fb != crtc->fb) { 1113771fe6b9SJerome Glisse radeon_fb = to_radeon_framebuffer(old_fb); 11144c788679SJerome Glisse rbo = radeon_fb->obj->driver_private; 11154c788679SJerome Glisse r = radeon_bo_reserve(rbo, false); 11164c788679SJerome Glisse if (unlikely(r != 0)) 11174c788679SJerome Glisse return r; 11184c788679SJerome Glisse radeon_bo_unpin(rbo); 11194c788679SJerome Glisse radeon_bo_unreserve(rbo); 1120771fe6b9SJerome Glisse } 1121f30f37deSMichel Dänzer 1122f30f37deSMichel Dänzer /* Bytes per pixel may have changed */ 1123f30f37deSMichel Dänzer radeon_bandwidth_update(rdev); 1124f30f37deSMichel Dänzer 1125771fe6b9SJerome Glisse return 0; 1126771fe6b9SJerome Glisse } 1127771fe6b9SJerome Glisse 112854f088a9SAlex Deucher int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, 112954f088a9SAlex Deucher struct drm_framebuffer *old_fb) 113054f088a9SAlex Deucher { 113154f088a9SAlex Deucher struct drm_device *dev = crtc->dev; 113254f088a9SAlex Deucher struct radeon_device *rdev = dev->dev_private; 113354f088a9SAlex Deucher 1134bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) 1135bcc1c2a1SAlex Deucher return evergreen_crtc_set_base(crtc, x, y, old_fb); 1136bcc1c2a1SAlex Deucher else if (ASIC_IS_AVIVO(rdev)) 113754f088a9SAlex Deucher return avivo_crtc_set_base(crtc, x, y, old_fb); 113854f088a9SAlex Deucher else 113954f088a9SAlex Deucher return radeon_crtc_set_base(crtc, x, y, old_fb); 114054f088a9SAlex Deucher } 114154f088a9SAlex Deucher 1142615e0cb6SAlex Deucher /* properly set additional regs when using atombios */ 1143615e0cb6SAlex Deucher static void radeon_legacy_atom_fixup(struct drm_crtc *crtc) 1144615e0cb6SAlex Deucher { 1145615e0cb6SAlex Deucher struct drm_device *dev = crtc->dev; 1146615e0cb6SAlex Deucher struct radeon_device *rdev = dev->dev_private; 1147615e0cb6SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1148615e0cb6SAlex Deucher u32 disp_merge_cntl; 1149615e0cb6SAlex Deucher 1150615e0cb6SAlex Deucher switch (radeon_crtc->crtc_id) { 1151615e0cb6SAlex Deucher case 0: 1152615e0cb6SAlex Deucher disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL); 1153615e0cb6SAlex Deucher disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; 1154615e0cb6SAlex Deucher WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl); 1155615e0cb6SAlex Deucher break; 1156615e0cb6SAlex Deucher case 1: 1157615e0cb6SAlex Deucher disp_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL); 1158615e0cb6SAlex Deucher disp_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN; 1159615e0cb6SAlex Deucher WREG32(RADEON_DISP2_MERGE_CNTL, disp_merge_cntl); 1160615e0cb6SAlex Deucher WREG32(RADEON_FP_H2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_H_SYNC_STRT_WID)); 1161615e0cb6SAlex Deucher WREG32(RADEON_FP_V2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_V_SYNC_STRT_WID)); 1162615e0cb6SAlex Deucher break; 1163615e0cb6SAlex Deucher } 1164615e0cb6SAlex Deucher } 1165615e0cb6SAlex Deucher 1166bcc1c2a1SAlex Deucher static int radeon_atom_pick_pll(struct drm_crtc *crtc) 1167bcc1c2a1SAlex Deucher { 1168bcc1c2a1SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1169bcc1c2a1SAlex Deucher struct drm_device *dev = crtc->dev; 1170bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 1171bcc1c2a1SAlex Deucher struct drm_encoder *test_encoder; 1172bcc1c2a1SAlex Deucher struct drm_crtc *test_crtc; 1173bcc1c2a1SAlex Deucher uint32_t pll_in_use = 0; 1174bcc1c2a1SAlex Deucher 1175bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) { 1176bcc1c2a1SAlex Deucher /* if crtc is driving DP and we have an ext clock, use that */ 1177bcc1c2a1SAlex Deucher list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { 1178bcc1c2a1SAlex Deucher if (test_encoder->crtc && (test_encoder->crtc == crtc)) { 1179bcc1c2a1SAlex Deucher if (atombios_get_encoder_mode(test_encoder) == ATOM_ENCODER_MODE_DP) { 1180bcc1c2a1SAlex Deucher if (rdev->clock.dp_extclk) 1181bcc1c2a1SAlex Deucher return ATOM_PPLL_INVALID; 1182bcc1c2a1SAlex Deucher } 1183bcc1c2a1SAlex Deucher } 1184bcc1c2a1SAlex Deucher } 1185bcc1c2a1SAlex Deucher 1186bcc1c2a1SAlex Deucher /* otherwise, pick one of the plls */ 1187bcc1c2a1SAlex Deucher list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { 1188bcc1c2a1SAlex Deucher struct radeon_crtc *radeon_test_crtc; 1189bcc1c2a1SAlex Deucher 1190bcc1c2a1SAlex Deucher if (crtc == test_crtc) 1191bcc1c2a1SAlex Deucher continue; 1192bcc1c2a1SAlex Deucher 1193bcc1c2a1SAlex Deucher radeon_test_crtc = to_radeon_crtc(test_crtc); 1194bcc1c2a1SAlex Deucher if ((radeon_test_crtc->pll_id >= ATOM_PPLL1) && 1195bcc1c2a1SAlex Deucher (radeon_test_crtc->pll_id <= ATOM_PPLL2)) 1196bcc1c2a1SAlex Deucher pll_in_use |= (1 << radeon_test_crtc->pll_id); 1197bcc1c2a1SAlex Deucher } 1198bcc1c2a1SAlex Deucher if (!(pll_in_use & 1)) 1199bcc1c2a1SAlex Deucher return ATOM_PPLL1; 1200bcc1c2a1SAlex Deucher return ATOM_PPLL2; 1201bcc1c2a1SAlex Deucher } else 1202bcc1c2a1SAlex Deucher return radeon_crtc->crtc_id; 1203bcc1c2a1SAlex Deucher 1204bcc1c2a1SAlex Deucher } 1205bcc1c2a1SAlex Deucher 1206771fe6b9SJerome Glisse int atombios_crtc_mode_set(struct drm_crtc *crtc, 1207771fe6b9SJerome Glisse struct drm_display_mode *mode, 1208771fe6b9SJerome Glisse struct drm_display_mode *adjusted_mode, 1209771fe6b9SJerome Glisse int x, int y, struct drm_framebuffer *old_fb) 1210771fe6b9SJerome Glisse { 1211771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1212771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 1213771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 1214771fe6b9SJerome Glisse 1215771fe6b9SJerome Glisse /* TODO color tiling */ 1216771fe6b9SJerome Glisse 1217b792210eSAlex Deucher atombios_disable_ss(crtc); 1218bcc1c2a1SAlex Deucher /* always set DCPLL */ 1219bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) 1220bcc1c2a1SAlex Deucher atombios_crtc_set_dcpll(crtc); 1221771fe6b9SJerome Glisse atombios_crtc_set_pll(crtc, adjusted_mode); 1222b792210eSAlex Deucher atombios_enable_ss(crtc); 1223771fe6b9SJerome Glisse 12245b1714d3SAlex Deucher if (ASIC_IS_AVIVO(rdev)) 1225bcc1c2a1SAlex Deucher atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 1226771fe6b9SJerome Glisse else { 1227bcc1c2a1SAlex Deucher atombios_crtc_set_timing(crtc, adjusted_mode); 12285a9bcaccSAlex Deucher if (radeon_crtc->crtc_id == 0) 12295a9bcaccSAlex Deucher atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 1230615e0cb6SAlex Deucher radeon_legacy_atom_fixup(crtc); 1231771fe6b9SJerome Glisse } 1232bcc1c2a1SAlex Deucher atombios_crtc_set_base(crtc, x, y, old_fb); 1233c93bb85bSJerome Glisse atombios_overscan_setup(crtc, mode, adjusted_mode); 1234c93bb85bSJerome Glisse atombios_scaler_setup(crtc); 1235771fe6b9SJerome Glisse return 0; 1236771fe6b9SJerome Glisse } 1237771fe6b9SJerome Glisse 1238771fe6b9SJerome Glisse static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, 1239771fe6b9SJerome Glisse struct drm_display_mode *mode, 1240771fe6b9SJerome Glisse struct drm_display_mode *adjusted_mode) 1241771fe6b9SJerome Glisse { 124203214bd5SAlex Deucher struct drm_device *dev = crtc->dev; 124303214bd5SAlex Deucher struct radeon_device *rdev = dev->dev_private; 124403214bd5SAlex Deucher 124503214bd5SAlex Deucher /* adjust pm to upcoming mode change */ 124603214bd5SAlex Deucher radeon_pm_compute_clocks(rdev); 124703214bd5SAlex Deucher 1248c93bb85bSJerome Glisse if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) 1249c93bb85bSJerome Glisse return false; 1250771fe6b9SJerome Glisse return true; 1251771fe6b9SJerome Glisse } 1252771fe6b9SJerome Glisse 1253771fe6b9SJerome Glisse static void atombios_crtc_prepare(struct drm_crtc *crtc) 1254771fe6b9SJerome Glisse { 1255267364acSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1256267364acSAlex Deucher 1257267364acSAlex Deucher /* pick pll */ 1258267364acSAlex Deucher radeon_crtc->pll_id = radeon_atom_pick_pll(crtc); 1259267364acSAlex Deucher 126037b4390eSAlex Deucher atombios_lock_crtc(crtc, ATOM_ENABLE); 1261a348c84dSAlex Deucher atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 1262771fe6b9SJerome Glisse } 1263771fe6b9SJerome Glisse 1264771fe6b9SJerome Glisse static void atombios_crtc_commit(struct drm_crtc *crtc) 1265771fe6b9SJerome Glisse { 1266771fe6b9SJerome Glisse atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON); 126737b4390eSAlex Deucher atombios_lock_crtc(crtc, ATOM_DISABLE); 1268771fe6b9SJerome Glisse } 1269771fe6b9SJerome Glisse 127037f9003bSAlex Deucher static void atombios_crtc_disable(struct drm_crtc *crtc) 127137f9003bSAlex Deucher { 127237f9003bSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 127337f9003bSAlex Deucher atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 127437f9003bSAlex Deucher 127537f9003bSAlex Deucher switch (radeon_crtc->pll_id) { 127637f9003bSAlex Deucher case ATOM_PPLL1: 127737f9003bSAlex Deucher case ATOM_PPLL2: 127837f9003bSAlex Deucher /* disable the ppll */ 127937f9003bSAlex Deucher atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, 128037f9003bSAlex Deucher 0, 0, ATOM_DISABLE, 0, 0, 0, 0); 128137f9003bSAlex Deucher break; 128237f9003bSAlex Deucher default: 128337f9003bSAlex Deucher break; 128437f9003bSAlex Deucher } 128537f9003bSAlex Deucher radeon_crtc->pll_id = -1; 128637f9003bSAlex Deucher } 128737f9003bSAlex Deucher 1288771fe6b9SJerome Glisse static const struct drm_crtc_helper_funcs atombios_helper_funcs = { 1289771fe6b9SJerome Glisse .dpms = atombios_crtc_dpms, 1290771fe6b9SJerome Glisse .mode_fixup = atombios_crtc_mode_fixup, 1291771fe6b9SJerome Glisse .mode_set = atombios_crtc_mode_set, 1292771fe6b9SJerome Glisse .mode_set_base = atombios_crtc_set_base, 1293771fe6b9SJerome Glisse .prepare = atombios_crtc_prepare, 1294771fe6b9SJerome Glisse .commit = atombios_crtc_commit, 1295068143d3SDave Airlie .load_lut = radeon_crtc_load_lut, 129637f9003bSAlex Deucher .disable = atombios_crtc_disable, 1297771fe6b9SJerome Glisse }; 1298771fe6b9SJerome Glisse 1299771fe6b9SJerome Glisse void radeon_atombios_init_crtc(struct drm_device *dev, 1300771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc) 1301771fe6b9SJerome Glisse { 1302bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 1303bcc1c2a1SAlex Deucher 1304bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) { 1305bcc1c2a1SAlex Deucher switch (radeon_crtc->crtc_id) { 1306bcc1c2a1SAlex Deucher case 0: 1307bcc1c2a1SAlex Deucher default: 130812d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC0_REGISTER_OFFSET; 1309bcc1c2a1SAlex Deucher break; 1310bcc1c2a1SAlex Deucher case 1: 131112d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC1_REGISTER_OFFSET; 1312bcc1c2a1SAlex Deucher break; 1313bcc1c2a1SAlex Deucher case 2: 131412d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC2_REGISTER_OFFSET; 1315bcc1c2a1SAlex Deucher break; 1316bcc1c2a1SAlex Deucher case 3: 131712d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC3_REGISTER_OFFSET; 1318bcc1c2a1SAlex Deucher break; 1319bcc1c2a1SAlex Deucher case 4: 132012d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC4_REGISTER_OFFSET; 1321bcc1c2a1SAlex Deucher break; 1322bcc1c2a1SAlex Deucher case 5: 132312d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC5_REGISTER_OFFSET; 1324bcc1c2a1SAlex Deucher break; 1325bcc1c2a1SAlex Deucher } 1326bcc1c2a1SAlex Deucher } else { 1327771fe6b9SJerome Glisse if (radeon_crtc->crtc_id == 1) 1328771fe6b9SJerome Glisse radeon_crtc->crtc_offset = 1329771fe6b9SJerome Glisse AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL; 1330bcc1c2a1SAlex Deucher else 1331bcc1c2a1SAlex Deucher radeon_crtc->crtc_offset = 0; 1332bcc1c2a1SAlex Deucher } 1333bcc1c2a1SAlex Deucher radeon_crtc->pll_id = -1; 1334771fe6b9SJerome Glisse drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); 1335771fe6b9SJerome Glisse } 1336