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 33554bfe496SAlex Deucher args.ucOverscanRight = radeon_crtc->h_border; 33654bfe496SAlex Deucher args.ucOverscanLeft = radeon_crtc->h_border; 33754bfe496SAlex Deucher args.ucOverscanBottom = radeon_crtc->v_border; 33854bfe496SAlex Deucher args.ucOverscanTop = radeon_crtc->v_border; 33954bfe496SAlex Deucher 3405a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_NVSYNC) 3415a9bcaccSAlex Deucher misc |= ATOM_VSYNC_POLARITY; 3425a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_NHSYNC) 3435a9bcaccSAlex Deucher misc |= ATOM_HSYNC_POLARITY; 3445a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_CSYNC) 3455a9bcaccSAlex Deucher misc |= ATOM_COMPOSITESYNC; 3465a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_INTERLACE) 3475a9bcaccSAlex Deucher misc |= ATOM_INTERLACE; 3485a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 3495a9bcaccSAlex Deucher misc |= ATOM_DOUBLE_CLOCK_MODE; 3505a9bcaccSAlex Deucher 3515a9bcaccSAlex Deucher args.susModeMiscInfo.usAccess = cpu_to_le16(misc); 3525a9bcaccSAlex Deucher args.ucCRTC = radeon_crtc->crtc_id; 353771fe6b9SJerome Glisse 3545a9bcaccSAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 355771fe6b9SJerome Glisse } 356771fe6b9SJerome Glisse 357b792210eSAlex Deucher static void atombios_disable_ss(struct drm_crtc *crtc) 358b792210eSAlex Deucher { 359b792210eSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 360b792210eSAlex Deucher struct drm_device *dev = crtc->dev; 361b792210eSAlex Deucher struct radeon_device *rdev = dev->dev_private; 362b792210eSAlex Deucher u32 ss_cntl; 363b792210eSAlex Deucher 364b792210eSAlex Deucher if (ASIC_IS_DCE4(rdev)) { 365b792210eSAlex Deucher switch (radeon_crtc->pll_id) { 366b792210eSAlex Deucher case ATOM_PPLL1: 367b792210eSAlex Deucher ss_cntl = RREG32(EVERGREEN_P1PLL_SS_CNTL); 368b792210eSAlex Deucher ss_cntl &= ~EVERGREEN_PxPLL_SS_EN; 369b792210eSAlex Deucher WREG32(EVERGREEN_P1PLL_SS_CNTL, ss_cntl); 370b792210eSAlex Deucher break; 371b792210eSAlex Deucher case ATOM_PPLL2: 372b792210eSAlex Deucher ss_cntl = RREG32(EVERGREEN_P2PLL_SS_CNTL); 373b792210eSAlex Deucher ss_cntl &= ~EVERGREEN_PxPLL_SS_EN; 374b792210eSAlex Deucher WREG32(EVERGREEN_P2PLL_SS_CNTL, ss_cntl); 375b792210eSAlex Deucher break; 376b792210eSAlex Deucher case ATOM_DCPLL: 377b792210eSAlex Deucher case ATOM_PPLL_INVALID: 378b792210eSAlex Deucher return; 379b792210eSAlex Deucher } 380b792210eSAlex Deucher } else if (ASIC_IS_AVIVO(rdev)) { 381b792210eSAlex Deucher switch (radeon_crtc->pll_id) { 382b792210eSAlex Deucher case ATOM_PPLL1: 383b792210eSAlex Deucher ss_cntl = RREG32(AVIVO_P1PLL_INT_SS_CNTL); 384b792210eSAlex Deucher ss_cntl &= ~1; 385b792210eSAlex Deucher WREG32(AVIVO_P1PLL_INT_SS_CNTL, ss_cntl); 386b792210eSAlex Deucher break; 387b792210eSAlex Deucher case ATOM_PPLL2: 388b792210eSAlex Deucher ss_cntl = RREG32(AVIVO_P2PLL_INT_SS_CNTL); 389b792210eSAlex Deucher ss_cntl &= ~1; 390b792210eSAlex Deucher WREG32(AVIVO_P2PLL_INT_SS_CNTL, ss_cntl); 391b792210eSAlex Deucher break; 392b792210eSAlex Deucher case ATOM_DCPLL: 393b792210eSAlex Deucher case ATOM_PPLL_INVALID: 394b792210eSAlex Deucher return; 395b792210eSAlex Deucher } 396b792210eSAlex Deucher } 397b792210eSAlex Deucher } 398b792210eSAlex Deucher 399b792210eSAlex Deucher 40026b9fc3aSAlex Deucher union atom_enable_ss { 40126b9fc3aSAlex Deucher ENABLE_LVDS_SS_PARAMETERS legacy; 40226b9fc3aSAlex Deucher ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1; 40326b9fc3aSAlex Deucher }; 40426b9fc3aSAlex Deucher 405b792210eSAlex Deucher static void atombios_enable_ss(struct drm_crtc *crtc) 406ebbe1cb9SAlex Deucher { 407ebbe1cb9SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 408ebbe1cb9SAlex Deucher struct drm_device *dev = crtc->dev; 409ebbe1cb9SAlex Deucher struct radeon_device *rdev = dev->dev_private; 410ebbe1cb9SAlex Deucher struct drm_encoder *encoder = NULL; 411ebbe1cb9SAlex Deucher struct radeon_encoder *radeon_encoder = NULL; 412ebbe1cb9SAlex Deucher struct radeon_encoder_atom_dig *dig = NULL; 413ebbe1cb9SAlex Deucher int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL); 41426b9fc3aSAlex Deucher union atom_enable_ss args; 415ebbe1cb9SAlex Deucher uint16_t percentage = 0; 416ebbe1cb9SAlex Deucher uint8_t type = 0, step = 0, delay = 0, range = 0; 417ebbe1cb9SAlex Deucher 418bcc1c2a1SAlex Deucher /* XXX add ss support for DCE4 */ 419bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) 420bcc1c2a1SAlex Deucher return; 421bcc1c2a1SAlex Deucher 422ebbe1cb9SAlex Deucher list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 423ebbe1cb9SAlex Deucher if (encoder->crtc == crtc) { 424ebbe1cb9SAlex Deucher radeon_encoder = to_radeon_encoder(encoder); 425ebbe1cb9SAlex Deucher /* only enable spread spectrum on LVDS */ 426d11aa88bSAlex Deucher if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 427d11aa88bSAlex Deucher dig = radeon_encoder->enc_priv; 428ebbe1cb9SAlex Deucher if (dig && dig->ss) { 429ebbe1cb9SAlex Deucher percentage = dig->ss->percentage; 430ebbe1cb9SAlex Deucher type = dig->ss->type; 431ebbe1cb9SAlex Deucher step = dig->ss->step; 432ebbe1cb9SAlex Deucher delay = dig->ss->delay; 433ebbe1cb9SAlex Deucher range = dig->ss->range; 434b792210eSAlex Deucher } else 435ebbe1cb9SAlex Deucher return; 436b792210eSAlex Deucher } else 437d11aa88bSAlex Deucher return; 438ebbe1cb9SAlex Deucher break; 439ebbe1cb9SAlex Deucher } 440ebbe1cb9SAlex Deucher } 441ebbe1cb9SAlex Deucher 442ebbe1cb9SAlex Deucher if (!radeon_encoder) 443ebbe1cb9SAlex Deucher return; 444ebbe1cb9SAlex Deucher 445ebbe1cb9SAlex Deucher memset(&args, 0, sizeof(args)); 44626b9fc3aSAlex Deucher if (ASIC_IS_AVIVO(rdev)) { 44726b9fc3aSAlex Deucher args.v1.usSpreadSpectrumPercentage = cpu_to_le16(percentage); 44826b9fc3aSAlex Deucher args.v1.ucSpreadSpectrumType = type; 44926b9fc3aSAlex Deucher args.v1.ucSpreadSpectrumStep = step; 45026b9fc3aSAlex Deucher args.v1.ucSpreadSpectrumDelay = delay; 45126b9fc3aSAlex Deucher args.v1.ucSpreadSpectrumRange = range; 45226b9fc3aSAlex Deucher args.v1.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; 453b792210eSAlex Deucher args.v1.ucEnable = ATOM_ENABLE; 454ebbe1cb9SAlex Deucher } else { 45526b9fc3aSAlex Deucher args.legacy.usSpreadSpectrumPercentage = cpu_to_le16(percentage); 45626b9fc3aSAlex Deucher args.legacy.ucSpreadSpectrumType = type; 45726b9fc3aSAlex Deucher args.legacy.ucSpreadSpectrumStepSize_Delay = (step & 3) << 2; 45826b9fc3aSAlex Deucher args.legacy.ucSpreadSpectrumStepSize_Delay |= (delay & 7) << 4; 459b792210eSAlex Deucher args.legacy.ucEnable = ATOM_ENABLE; 460ebbe1cb9SAlex Deucher } 46126b9fc3aSAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 462ebbe1cb9SAlex Deucher } 463ebbe1cb9SAlex Deucher 4644eaeca33SAlex Deucher union adjust_pixel_clock { 4654eaeca33SAlex Deucher ADJUST_DISPLAY_PLL_PS_ALLOCATION v1; 466bcc1c2a1SAlex Deucher ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 v3; 4674eaeca33SAlex Deucher }; 4684eaeca33SAlex Deucher 4694eaeca33SAlex Deucher static u32 atombios_adjust_pll(struct drm_crtc *crtc, 4704eaeca33SAlex Deucher struct drm_display_mode *mode, 4714eaeca33SAlex Deucher struct radeon_pll *pll) 472771fe6b9SJerome Glisse { 473771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 474771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 475771fe6b9SJerome Glisse struct drm_encoder *encoder = NULL; 476771fe6b9SJerome Glisse struct radeon_encoder *radeon_encoder = NULL; 4774eaeca33SAlex Deucher u32 adjusted_clock = mode->clock; 478bcc1c2a1SAlex Deucher int encoder_mode = 0; 479fbee67a6SAlex Deucher u32 dp_clock = mode->clock; 480fbee67a6SAlex Deucher int bpc = 8; 481fc10332bSAlex Deucher 4824eaeca33SAlex Deucher /* reset the pll flags */ 4834eaeca33SAlex Deucher pll->flags = 0; 484771fe6b9SJerome Glisse 4857c27f87dSAlex Deucher /* select the PLL algo */ 4867c27f87dSAlex Deucher if (ASIC_IS_AVIVO(rdev)) { 487383be5d1SAlex Deucher if (radeon_new_pll == 0) 488383be5d1SAlex Deucher pll->algo = PLL_ALGO_LEGACY; 489383be5d1SAlex Deucher else 490383be5d1SAlex Deucher pll->algo = PLL_ALGO_NEW; 491383be5d1SAlex Deucher } else { 492383be5d1SAlex Deucher if (radeon_new_pll == 1) 493383be5d1SAlex Deucher pll->algo = PLL_ALGO_NEW; 4947c27f87dSAlex Deucher else 4957c27f87dSAlex Deucher pll->algo = PLL_ALGO_LEGACY; 496383be5d1SAlex Deucher } 4977c27f87dSAlex Deucher 498771fe6b9SJerome Glisse if (ASIC_IS_AVIVO(rdev)) { 499eb1300bcSAlex Deucher if ((rdev->family == CHIP_RS600) || 500eb1300bcSAlex Deucher (rdev->family == CHIP_RS690) || 501eb1300bcSAlex Deucher (rdev->family == CHIP_RS740)) 5022ff776cfSAlex Deucher pll->flags |= (/*RADEON_PLL_USE_FRAC_FB_DIV |*/ 503eb1300bcSAlex Deucher RADEON_PLL_PREFER_CLOSEST_LOWER); 504eb1300bcSAlex Deucher 505771fe6b9SJerome Glisse if (ASIC_IS_DCE32(rdev) && mode->clock > 200000) /* range limits??? */ 506fc10332bSAlex Deucher pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; 507771fe6b9SJerome Glisse else 508fc10332bSAlex Deucher pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; 509771fe6b9SJerome Glisse } else { 510fc10332bSAlex Deucher pll->flags |= RADEON_PLL_LEGACY; 511771fe6b9SJerome Glisse 512771fe6b9SJerome Glisse if (mode->clock > 200000) /* range limits??? */ 513fc10332bSAlex Deucher pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; 514771fe6b9SJerome Glisse else 515fc10332bSAlex Deucher pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; 516771fe6b9SJerome Glisse 517771fe6b9SJerome Glisse } 518771fe6b9SJerome Glisse 519771fe6b9SJerome Glisse list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 520771fe6b9SJerome Glisse if (encoder->crtc == crtc) { 5214eaeca33SAlex Deucher radeon_encoder = to_radeon_encoder(encoder); 522bcc1c2a1SAlex Deucher encoder_mode = atombios_get_encoder_mode(encoder); 523fbee67a6SAlex Deucher if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) { 524fbee67a6SAlex Deucher struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); 525fbee67a6SAlex Deucher if (connector) { 526fbee67a6SAlex Deucher struct radeon_connector *radeon_connector = to_radeon_connector(connector); 527fbee67a6SAlex Deucher struct radeon_connector_atom_dig *dig_connector = 528fbee67a6SAlex Deucher radeon_connector->con_priv; 529fbee67a6SAlex Deucher 530fbee67a6SAlex Deucher dp_clock = dig_connector->dp_clock; 531fbee67a6SAlex Deucher } 532fbee67a6SAlex Deucher } 533fbee67a6SAlex Deucher 5344eaeca33SAlex Deucher if (ASIC_IS_AVIVO(rdev)) { 5354eaeca33SAlex Deucher /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ 5364eaeca33SAlex Deucher if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1) 5374eaeca33SAlex Deucher adjusted_clock = mode->clock * 2; 538a1a4b23bSAlex Deucher if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) { 539a1a4b23bSAlex Deucher pll->algo = PLL_ALGO_LEGACY; 540a1a4b23bSAlex Deucher pll->flags |= RADEON_PLL_PREFER_CLOSEST_LOWER; 541a1a4b23bSAlex Deucher } 542f90087eeSAlex Deucher /* There is some evidence (often anecdotal) that RV515/RV620 LVDS 5430d9958b1SAlex Deucher * (on some boards at least) prefers the legacy algo. I'm not 5440d9958b1SAlex Deucher * sure whether this should handled generically or on a 5450d9958b1SAlex Deucher * case-by-case quirk basis. Both algos should work fine in the 5460d9958b1SAlex Deucher * majority of cases. 5470d9958b1SAlex Deucher */ 5480d9958b1SAlex Deucher if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) && 549f90087eeSAlex Deucher ((rdev->family == CHIP_RV515) || 550f90087eeSAlex Deucher (rdev->family == CHIP_RV620))) { 5510d9958b1SAlex Deucher /* allow the user to overrride just in case */ 5520d9958b1SAlex Deucher if (radeon_new_pll == 1) 5530d9958b1SAlex Deucher pll->algo = PLL_ALGO_NEW; 5540d9958b1SAlex Deucher else 5550d9958b1SAlex Deucher pll->algo = PLL_ALGO_LEGACY; 5560d9958b1SAlex Deucher } 5574eaeca33SAlex Deucher } else { 5584eaeca33SAlex Deucher if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) 559fc10332bSAlex Deucher pll->flags |= RADEON_PLL_NO_ODD_POST_DIV; 5604eaeca33SAlex Deucher if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) 561fc10332bSAlex Deucher pll->flags |= RADEON_PLL_USE_REF_DIV; 562771fe6b9SJerome Glisse } 5633ce0a23dSJerome Glisse break; 564771fe6b9SJerome Glisse } 565771fe6b9SJerome Glisse } 566771fe6b9SJerome Glisse 5672606c886SAlex Deucher /* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock 5682606c886SAlex Deucher * accordingly based on the encoder/transmitter to work around 5692606c886SAlex Deucher * special hw requirements. 5702606c886SAlex Deucher */ 5712606c886SAlex Deucher if (ASIC_IS_DCE3(rdev)) { 5724eaeca33SAlex Deucher union adjust_pixel_clock args; 5734eaeca33SAlex Deucher u8 frev, crev; 5744eaeca33SAlex Deucher int index; 5752606c886SAlex Deucher 5762606c886SAlex Deucher index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll); 577a084e6eeSAlex Deucher if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 578a084e6eeSAlex Deucher &crev)) 579a084e6eeSAlex Deucher return adjusted_clock; 5804eaeca33SAlex Deucher 5814eaeca33SAlex Deucher memset(&args, 0, sizeof(args)); 5824eaeca33SAlex Deucher 5834eaeca33SAlex Deucher switch (frev) { 5844eaeca33SAlex Deucher case 1: 5854eaeca33SAlex Deucher switch (crev) { 5864eaeca33SAlex Deucher case 1: 5874eaeca33SAlex Deucher case 2: 5884eaeca33SAlex Deucher args.v1.usPixelClock = cpu_to_le16(mode->clock / 10); 5894eaeca33SAlex Deucher args.v1.ucTransmitterID = radeon_encoder->encoder_id; 590bcc1c2a1SAlex Deucher args.v1.ucEncodeMode = encoder_mode; 591fbee67a6SAlex Deucher if (encoder_mode == ATOM_ENCODER_MODE_DP) { 592fbee67a6SAlex Deucher /* may want to enable SS on DP eventually */ 593fbee67a6SAlex Deucher /* args.v1.ucConfig |= 594fbee67a6SAlex Deucher ADJUST_DISPLAY_CONFIG_SS_ENABLE;*/ 595fbee67a6SAlex Deucher } else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) { 596fbee67a6SAlex Deucher args.v1.ucConfig |= 597fbee67a6SAlex Deucher ADJUST_DISPLAY_CONFIG_SS_ENABLE; 598fbee67a6SAlex Deucher } 5994eaeca33SAlex Deucher 6002606c886SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, 6014eaeca33SAlex Deucher index, (uint32_t *)&args); 6024eaeca33SAlex Deucher adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10; 6034eaeca33SAlex Deucher break; 604bcc1c2a1SAlex Deucher case 3: 605bcc1c2a1SAlex Deucher args.v3.sInput.usPixelClock = cpu_to_le16(mode->clock / 10); 606bcc1c2a1SAlex Deucher args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id; 607bcc1c2a1SAlex Deucher args.v3.sInput.ucEncodeMode = encoder_mode; 608bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig = 0; 609bcc1c2a1SAlex Deucher if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { 610bcc1c2a1SAlex Deucher struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 611bcc1c2a1SAlex Deucher 612fbee67a6SAlex Deucher if (encoder_mode == ATOM_ENCODER_MODE_DP) { 613fbee67a6SAlex Deucher /* may want to enable SS on DP/eDP eventually */ 614fbee67a6SAlex Deucher /*args.v3.sInput.ucDispPllConfig |= 615fbee67a6SAlex Deucher DISPPLL_CONFIG_SS_ENABLE;*/ 616bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 617bcc1c2a1SAlex Deucher DISPPLL_CONFIG_COHERENT_MODE; 618fbee67a6SAlex Deucher /* 16200 or 27000 */ 619fbee67a6SAlex Deucher args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); 620fbee67a6SAlex Deucher } else { 621fbee67a6SAlex Deucher if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { 622fbee67a6SAlex Deucher /* deep color support */ 623fbee67a6SAlex Deucher args.v3.sInput.usPixelClock = 624fbee67a6SAlex Deucher cpu_to_le16((mode->clock * bpc / 8) / 10); 625fbee67a6SAlex Deucher } 626bcc1c2a1SAlex Deucher if (dig->coherent_mode) 627bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 628bcc1c2a1SAlex Deucher DISPPLL_CONFIG_COHERENT_MODE; 629bcc1c2a1SAlex Deucher if (mode->clock > 165000) 630bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 631bcc1c2a1SAlex Deucher DISPPLL_CONFIG_DUAL_LINK; 632bcc1c2a1SAlex Deucher } 633bcc1c2a1SAlex Deucher } else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 634fbee67a6SAlex Deucher if (encoder_mode == ATOM_ENCODER_MODE_DP) { 635bcc1c2a1SAlex Deucher /* may want to enable SS on DP/eDP eventually */ 6369f998ad7SAlex Deucher /*args.v3.sInput.ucDispPllConfig |= 6379f998ad7SAlex Deucher DISPPLL_CONFIG_SS_ENABLE;*/ 638bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 6399f998ad7SAlex Deucher DISPPLL_CONFIG_COHERENT_MODE; 640fbee67a6SAlex Deucher /* 16200 or 27000 */ 641fbee67a6SAlex Deucher args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); 642fbee67a6SAlex Deucher } else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) { 643fbee67a6SAlex Deucher /* want to enable SS on LVDS eventually */ 644fbee67a6SAlex Deucher /*args.v3.sInput.ucDispPllConfig |= 645fbee67a6SAlex Deucher DISPPLL_CONFIG_SS_ENABLE;*/ 646fbee67a6SAlex Deucher } else { 647bcc1c2a1SAlex Deucher if (mode->clock > 165000) 648bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 649bcc1c2a1SAlex Deucher DISPPLL_CONFIG_DUAL_LINK; 650bcc1c2a1SAlex Deucher } 6519f998ad7SAlex Deucher } 652bcc1c2a1SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, 653bcc1c2a1SAlex Deucher index, (uint32_t *)&args); 654bcc1c2a1SAlex Deucher adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10; 655bcc1c2a1SAlex Deucher if (args.v3.sOutput.ucRefDiv) { 656bcc1c2a1SAlex Deucher pll->flags |= RADEON_PLL_USE_REF_DIV; 657bcc1c2a1SAlex Deucher pll->reference_div = args.v3.sOutput.ucRefDiv; 658bcc1c2a1SAlex Deucher } 659bcc1c2a1SAlex Deucher if (args.v3.sOutput.ucPostDiv) { 660bcc1c2a1SAlex Deucher pll->flags |= RADEON_PLL_USE_POST_DIV; 661bcc1c2a1SAlex Deucher pll->post_div = args.v3.sOutput.ucPostDiv; 662bcc1c2a1SAlex Deucher } 663bcc1c2a1SAlex Deucher break; 6644eaeca33SAlex Deucher default: 6654eaeca33SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 6664eaeca33SAlex Deucher return adjusted_clock; 667d56ef9c8SAlex Deucher } 6684eaeca33SAlex Deucher break; 6694eaeca33SAlex Deucher default: 6704eaeca33SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 6714eaeca33SAlex Deucher return adjusted_clock; 6724eaeca33SAlex Deucher } 6734eaeca33SAlex Deucher } 6744eaeca33SAlex Deucher return adjusted_clock; 6754eaeca33SAlex Deucher } 6764eaeca33SAlex Deucher 6774eaeca33SAlex Deucher union set_pixel_clock { 6784eaeca33SAlex Deucher SET_PIXEL_CLOCK_PS_ALLOCATION base; 6794eaeca33SAlex Deucher PIXEL_CLOCK_PARAMETERS v1; 6804eaeca33SAlex Deucher PIXEL_CLOCK_PARAMETERS_V2 v2; 6814eaeca33SAlex Deucher PIXEL_CLOCK_PARAMETERS_V3 v3; 682bcc1c2a1SAlex Deucher PIXEL_CLOCK_PARAMETERS_V5 v5; 6834eaeca33SAlex Deucher }; 6844eaeca33SAlex Deucher 685bcc1c2a1SAlex Deucher static void atombios_crtc_set_dcpll(struct drm_crtc *crtc) 686bcc1c2a1SAlex Deucher { 687bcc1c2a1SAlex Deucher struct drm_device *dev = crtc->dev; 688bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 689bcc1c2a1SAlex Deucher u8 frev, crev; 690bcc1c2a1SAlex Deucher int index; 691bcc1c2a1SAlex Deucher union set_pixel_clock args; 692bcc1c2a1SAlex Deucher 693bcc1c2a1SAlex Deucher memset(&args, 0, sizeof(args)); 694bcc1c2a1SAlex Deucher 695bcc1c2a1SAlex Deucher index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); 696a084e6eeSAlex Deucher if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 697a084e6eeSAlex Deucher &crev)) 698a084e6eeSAlex Deucher return; 699bcc1c2a1SAlex Deucher 700bcc1c2a1SAlex Deucher switch (frev) { 701bcc1c2a1SAlex Deucher case 1: 702bcc1c2a1SAlex Deucher switch (crev) { 703bcc1c2a1SAlex Deucher case 5: 704bcc1c2a1SAlex Deucher /* if the default dcpll clock is specified, 705bcc1c2a1SAlex Deucher * SetPixelClock provides the dividers 706bcc1c2a1SAlex Deucher */ 707bcc1c2a1SAlex Deucher args.v5.ucCRTC = ATOM_CRTC_INVALID; 708bcc1c2a1SAlex Deucher args.v5.usPixelClock = rdev->clock.default_dispclk; 709bcc1c2a1SAlex Deucher args.v5.ucPpll = ATOM_DCPLL; 710bcc1c2a1SAlex Deucher break; 711bcc1c2a1SAlex Deucher default: 712bcc1c2a1SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 713bcc1c2a1SAlex Deucher return; 714bcc1c2a1SAlex Deucher } 715bcc1c2a1SAlex Deucher break; 716bcc1c2a1SAlex Deucher default: 717bcc1c2a1SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 718bcc1c2a1SAlex Deucher return; 719bcc1c2a1SAlex Deucher } 720bcc1c2a1SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 721bcc1c2a1SAlex Deucher } 722bcc1c2a1SAlex Deucher 72337f9003bSAlex Deucher static void atombios_crtc_program_pll(struct drm_crtc *crtc, 72437f9003bSAlex Deucher int crtc_id, 72537f9003bSAlex Deucher int pll_id, 72637f9003bSAlex Deucher u32 encoder_mode, 72737f9003bSAlex Deucher u32 encoder_id, 72837f9003bSAlex Deucher u32 clock, 72937f9003bSAlex Deucher u32 ref_div, 73037f9003bSAlex Deucher u32 fb_div, 73137f9003bSAlex Deucher u32 frac_fb_div, 73237f9003bSAlex Deucher u32 post_div) 73337f9003bSAlex Deucher { 73437f9003bSAlex Deucher struct drm_device *dev = crtc->dev; 73537f9003bSAlex Deucher struct radeon_device *rdev = dev->dev_private; 73637f9003bSAlex Deucher u8 frev, crev; 73737f9003bSAlex Deucher int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); 73837f9003bSAlex Deucher union set_pixel_clock args; 73937f9003bSAlex Deucher 74037f9003bSAlex Deucher memset(&args, 0, sizeof(args)); 74137f9003bSAlex Deucher 74237f9003bSAlex Deucher if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 74337f9003bSAlex Deucher &crev)) 74437f9003bSAlex Deucher return; 74537f9003bSAlex Deucher 74637f9003bSAlex Deucher switch (frev) { 74737f9003bSAlex Deucher case 1: 74837f9003bSAlex Deucher switch (crev) { 74937f9003bSAlex Deucher case 1: 75037f9003bSAlex Deucher if (clock == ATOM_DISABLE) 75137f9003bSAlex Deucher return; 75237f9003bSAlex Deucher args.v1.usPixelClock = cpu_to_le16(clock / 10); 75337f9003bSAlex Deucher args.v1.usRefDiv = cpu_to_le16(ref_div); 75437f9003bSAlex Deucher args.v1.usFbDiv = cpu_to_le16(fb_div); 75537f9003bSAlex Deucher args.v1.ucFracFbDiv = frac_fb_div; 75637f9003bSAlex Deucher args.v1.ucPostDiv = post_div; 75737f9003bSAlex Deucher args.v1.ucPpll = pll_id; 75837f9003bSAlex Deucher args.v1.ucCRTC = crtc_id; 75937f9003bSAlex Deucher args.v1.ucRefDivSrc = 1; 76037f9003bSAlex Deucher break; 76137f9003bSAlex Deucher case 2: 76237f9003bSAlex Deucher args.v2.usPixelClock = cpu_to_le16(clock / 10); 76337f9003bSAlex Deucher args.v2.usRefDiv = cpu_to_le16(ref_div); 76437f9003bSAlex Deucher args.v2.usFbDiv = cpu_to_le16(fb_div); 76537f9003bSAlex Deucher args.v2.ucFracFbDiv = frac_fb_div; 76637f9003bSAlex Deucher args.v2.ucPostDiv = post_div; 76737f9003bSAlex Deucher args.v2.ucPpll = pll_id; 76837f9003bSAlex Deucher args.v2.ucCRTC = crtc_id; 76937f9003bSAlex Deucher args.v2.ucRefDivSrc = 1; 77037f9003bSAlex Deucher break; 77137f9003bSAlex Deucher case 3: 77237f9003bSAlex Deucher args.v3.usPixelClock = cpu_to_le16(clock / 10); 77337f9003bSAlex Deucher args.v3.usRefDiv = cpu_to_le16(ref_div); 77437f9003bSAlex Deucher args.v3.usFbDiv = cpu_to_le16(fb_div); 77537f9003bSAlex Deucher args.v3.ucFracFbDiv = frac_fb_div; 77637f9003bSAlex Deucher args.v3.ucPostDiv = post_div; 77737f9003bSAlex Deucher args.v3.ucPpll = pll_id; 77837f9003bSAlex Deucher args.v3.ucMiscInfo = (pll_id << 2); 77937f9003bSAlex Deucher args.v3.ucTransmitterId = encoder_id; 78037f9003bSAlex Deucher args.v3.ucEncoderMode = encoder_mode; 78137f9003bSAlex Deucher break; 78237f9003bSAlex Deucher case 5: 78337f9003bSAlex Deucher args.v5.ucCRTC = crtc_id; 78437f9003bSAlex Deucher args.v5.usPixelClock = cpu_to_le16(clock / 10); 78537f9003bSAlex Deucher args.v5.ucRefDiv = ref_div; 78637f9003bSAlex Deucher args.v5.usFbDiv = cpu_to_le16(fb_div); 78737f9003bSAlex Deucher args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); 78837f9003bSAlex Deucher args.v5.ucPostDiv = post_div; 78937f9003bSAlex Deucher args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */ 79037f9003bSAlex Deucher args.v5.ucTransmitterID = encoder_id; 79137f9003bSAlex Deucher args.v5.ucEncoderMode = encoder_mode; 79237f9003bSAlex Deucher args.v5.ucPpll = pll_id; 79337f9003bSAlex Deucher break; 79437f9003bSAlex Deucher default: 79537f9003bSAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 79637f9003bSAlex Deucher return; 79737f9003bSAlex Deucher } 79837f9003bSAlex Deucher break; 79937f9003bSAlex Deucher default: 80037f9003bSAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 80137f9003bSAlex Deucher return; 80237f9003bSAlex Deucher } 80337f9003bSAlex Deucher 80437f9003bSAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 80537f9003bSAlex Deucher } 80637f9003bSAlex Deucher 807bcc1c2a1SAlex Deucher static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) 8084eaeca33SAlex Deucher { 8094eaeca33SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 8104eaeca33SAlex Deucher struct drm_device *dev = crtc->dev; 8114eaeca33SAlex Deucher struct radeon_device *rdev = dev->dev_private; 8124eaeca33SAlex Deucher struct drm_encoder *encoder = NULL; 8134eaeca33SAlex Deucher struct radeon_encoder *radeon_encoder = NULL; 8144eaeca33SAlex Deucher u32 pll_clock = mode->clock; 8154eaeca33SAlex Deucher u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; 8164eaeca33SAlex Deucher struct radeon_pll *pll; 8174eaeca33SAlex Deucher u32 adjusted_clock; 818bcc1c2a1SAlex Deucher int encoder_mode = 0; 8194eaeca33SAlex Deucher 8204eaeca33SAlex Deucher list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 8214eaeca33SAlex Deucher if (encoder->crtc == crtc) { 8224eaeca33SAlex Deucher radeon_encoder = to_radeon_encoder(encoder); 823bcc1c2a1SAlex Deucher encoder_mode = atombios_get_encoder_mode(encoder); 8244eaeca33SAlex Deucher break; 8254eaeca33SAlex Deucher } 8264eaeca33SAlex Deucher } 8274eaeca33SAlex Deucher 8284eaeca33SAlex Deucher if (!radeon_encoder) 8294eaeca33SAlex Deucher return; 8304eaeca33SAlex Deucher 831bcc1c2a1SAlex Deucher switch (radeon_crtc->pll_id) { 832bcc1c2a1SAlex Deucher case ATOM_PPLL1: 8334eaeca33SAlex Deucher pll = &rdev->clock.p1pll; 834bcc1c2a1SAlex Deucher break; 835bcc1c2a1SAlex Deucher case ATOM_PPLL2: 8364eaeca33SAlex Deucher pll = &rdev->clock.p2pll; 837bcc1c2a1SAlex Deucher break; 838bcc1c2a1SAlex Deucher case ATOM_DCPLL: 839bcc1c2a1SAlex Deucher case ATOM_PPLL_INVALID: 840921d98b5SStefan Richter default: 841bcc1c2a1SAlex Deucher pll = &rdev->clock.dcpll; 842bcc1c2a1SAlex Deucher break; 843bcc1c2a1SAlex Deucher } 8444eaeca33SAlex Deucher 8454eaeca33SAlex Deucher /* adjust pixel clock as needed */ 8464eaeca33SAlex Deucher adjusted_clock = atombios_adjust_pll(crtc, mode, pll); 8472606c886SAlex Deucher 8482606c886SAlex Deucher radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, 849fc10332bSAlex Deucher &ref_div, &post_div); 850771fe6b9SJerome Glisse 85137f9003bSAlex Deucher atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, 85237f9003bSAlex Deucher encoder_mode, radeon_encoder->encoder_id, mode->clock, 85337f9003bSAlex Deucher ref_div, fb_div, frac_fb_div, post_div); 854771fe6b9SJerome Glisse 855771fe6b9SJerome Glisse } 856771fe6b9SJerome Glisse 8574dd19b0dSChris Ball static int evergreen_crtc_do_set_base(struct drm_crtc *crtc, 8584dd19b0dSChris Ball struct drm_framebuffer *fb, 8594dd19b0dSChris Ball int x, int y, int atomic) 860bcc1c2a1SAlex Deucher { 861bcc1c2a1SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 862bcc1c2a1SAlex Deucher struct drm_device *dev = crtc->dev; 863bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 864bcc1c2a1SAlex Deucher struct radeon_framebuffer *radeon_fb; 8654dd19b0dSChris Ball struct drm_framebuffer *target_fb; 866bcc1c2a1SAlex Deucher struct drm_gem_object *obj; 867bcc1c2a1SAlex Deucher struct radeon_bo *rbo; 868bcc1c2a1SAlex Deucher uint64_t fb_location; 869bcc1c2a1SAlex Deucher uint32_t fb_format, fb_pitch_pixels, tiling_flags; 870bcc1c2a1SAlex Deucher int r; 871bcc1c2a1SAlex Deucher 872bcc1c2a1SAlex Deucher /* no fb bound */ 8734dd19b0dSChris Ball if (!atomic && !crtc->fb) { 874d9fdaafbSDave Airlie DRM_DEBUG_KMS("No FB bound\n"); 875bcc1c2a1SAlex Deucher return 0; 876bcc1c2a1SAlex Deucher } 877bcc1c2a1SAlex Deucher 8784dd19b0dSChris Ball if (atomic) { 8794dd19b0dSChris Ball radeon_fb = to_radeon_framebuffer(fb); 8804dd19b0dSChris Ball target_fb = fb; 8814dd19b0dSChris Ball } 8824dd19b0dSChris Ball else { 883bcc1c2a1SAlex Deucher radeon_fb = to_radeon_framebuffer(crtc->fb); 8844dd19b0dSChris Ball target_fb = crtc->fb; 8854dd19b0dSChris Ball } 886bcc1c2a1SAlex Deucher 8874dd19b0dSChris Ball /* If atomic, assume fb object is pinned & idle & fenced and 8884dd19b0dSChris Ball * just update base pointers 8894dd19b0dSChris Ball */ 890bcc1c2a1SAlex Deucher obj = radeon_fb->obj; 891bcc1c2a1SAlex Deucher rbo = obj->driver_private; 892bcc1c2a1SAlex Deucher r = radeon_bo_reserve(rbo, false); 893bcc1c2a1SAlex Deucher if (unlikely(r != 0)) 894bcc1c2a1SAlex Deucher return r; 8954dd19b0dSChris Ball 8964dd19b0dSChris Ball if (atomic) 8974dd19b0dSChris Ball fb_location = radeon_bo_gpu_offset(rbo); 8984dd19b0dSChris Ball else { 899bcc1c2a1SAlex Deucher r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); 900bcc1c2a1SAlex Deucher if (unlikely(r != 0)) { 901bcc1c2a1SAlex Deucher radeon_bo_unreserve(rbo); 902bcc1c2a1SAlex Deucher return -EINVAL; 903bcc1c2a1SAlex Deucher } 9044dd19b0dSChris Ball } 9054dd19b0dSChris Ball 906bcc1c2a1SAlex Deucher radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); 907bcc1c2a1SAlex Deucher radeon_bo_unreserve(rbo); 908bcc1c2a1SAlex Deucher 9094dd19b0dSChris Ball switch (target_fb->bits_per_pixel) { 910bcc1c2a1SAlex Deucher case 8: 911bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP) | 912bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED)); 913bcc1c2a1SAlex Deucher break; 914bcc1c2a1SAlex Deucher case 15: 915bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 916bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB1555)); 917bcc1c2a1SAlex Deucher break; 918bcc1c2a1SAlex Deucher case 16: 919bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 920bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565)); 921bcc1c2a1SAlex Deucher break; 922bcc1c2a1SAlex Deucher case 24: 923bcc1c2a1SAlex Deucher case 32: 924bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) | 925bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888)); 926bcc1c2a1SAlex Deucher break; 927bcc1c2a1SAlex Deucher default: 928bcc1c2a1SAlex Deucher DRM_ERROR("Unsupported screen depth %d\n", 9294dd19b0dSChris Ball target_fb->bits_per_pixel); 930bcc1c2a1SAlex Deucher return -EINVAL; 931bcc1c2a1SAlex Deucher } 932bcc1c2a1SAlex Deucher 93397d66328SAlex Deucher if (tiling_flags & RADEON_TILING_MACRO) 93497d66328SAlex Deucher fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1); 93597d66328SAlex Deucher else if (tiling_flags & RADEON_TILING_MICRO) 93697d66328SAlex Deucher fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1); 93797d66328SAlex Deucher 938bcc1c2a1SAlex Deucher switch (radeon_crtc->crtc_id) { 939bcc1c2a1SAlex Deucher case 0: 940bcc1c2a1SAlex Deucher WREG32(AVIVO_D1VGA_CONTROL, 0); 941bcc1c2a1SAlex Deucher break; 942bcc1c2a1SAlex Deucher case 1: 943bcc1c2a1SAlex Deucher WREG32(AVIVO_D2VGA_CONTROL, 0); 944bcc1c2a1SAlex Deucher break; 945bcc1c2a1SAlex Deucher case 2: 946bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D3VGA_CONTROL, 0); 947bcc1c2a1SAlex Deucher break; 948bcc1c2a1SAlex Deucher case 3: 949bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D4VGA_CONTROL, 0); 950bcc1c2a1SAlex Deucher break; 951bcc1c2a1SAlex Deucher case 4: 952bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D5VGA_CONTROL, 0); 953bcc1c2a1SAlex Deucher break; 954bcc1c2a1SAlex Deucher case 5: 955bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D6VGA_CONTROL, 0); 956bcc1c2a1SAlex Deucher break; 957bcc1c2a1SAlex Deucher default: 958bcc1c2a1SAlex Deucher break; 959bcc1c2a1SAlex Deucher } 960bcc1c2a1SAlex Deucher 961bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 962bcc1c2a1SAlex Deucher upper_32_bits(fb_location)); 963bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 964bcc1c2a1SAlex Deucher upper_32_bits(fb_location)); 965bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 966bcc1c2a1SAlex Deucher (u32)fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK); 967bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 968bcc1c2a1SAlex Deucher (u32) fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK); 969bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); 970bcc1c2a1SAlex Deucher 971bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); 972bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); 973bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_X_START + radeon_crtc->crtc_offset, 0); 974bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_Y_START + radeon_crtc->crtc_offset, 0); 9754dd19b0dSChris Ball WREG32(EVERGREEN_GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width); 9764dd19b0dSChris Ball WREG32(EVERGREEN_GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height); 977bcc1c2a1SAlex Deucher 9784dd19b0dSChris Ball fb_pitch_pixels = target_fb->pitch / (target_fb->bits_per_pixel / 8); 979bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); 980bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1); 981bcc1c2a1SAlex Deucher 982bcc1c2a1SAlex Deucher WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, 983bcc1c2a1SAlex Deucher crtc->mode.vdisplay); 984bcc1c2a1SAlex Deucher x &= ~3; 985bcc1c2a1SAlex Deucher y &= ~1; 986bcc1c2a1SAlex Deucher WREG32(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset, 987bcc1c2a1SAlex Deucher (x << 16) | y); 988bcc1c2a1SAlex Deucher WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset, 989bcc1c2a1SAlex Deucher (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay); 990bcc1c2a1SAlex Deucher 991bcc1c2a1SAlex Deucher if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) 992bcc1c2a1SAlex Deucher WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 993bcc1c2a1SAlex Deucher EVERGREEN_INTERLEAVE_EN); 994bcc1c2a1SAlex Deucher else 995bcc1c2a1SAlex Deucher WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 0); 996bcc1c2a1SAlex Deucher 9974dd19b0dSChris Ball if (!atomic && fb && fb != crtc->fb) { 9984dd19b0dSChris Ball radeon_fb = to_radeon_framebuffer(fb); 999bcc1c2a1SAlex Deucher rbo = radeon_fb->obj->driver_private; 1000bcc1c2a1SAlex Deucher r = radeon_bo_reserve(rbo, false); 1001bcc1c2a1SAlex Deucher if (unlikely(r != 0)) 1002bcc1c2a1SAlex Deucher return r; 1003bcc1c2a1SAlex Deucher radeon_bo_unpin(rbo); 1004bcc1c2a1SAlex Deucher radeon_bo_unreserve(rbo); 1005bcc1c2a1SAlex Deucher } 1006bcc1c2a1SAlex Deucher 1007bcc1c2a1SAlex Deucher /* Bytes per pixel may have changed */ 1008bcc1c2a1SAlex Deucher radeon_bandwidth_update(rdev); 1009bcc1c2a1SAlex Deucher 1010bcc1c2a1SAlex Deucher return 0; 1011bcc1c2a1SAlex Deucher } 1012bcc1c2a1SAlex Deucher 10134dd19b0dSChris Ball static int avivo_crtc_do_set_base(struct drm_crtc *crtc, 10144dd19b0dSChris Ball struct drm_framebuffer *fb, 10154dd19b0dSChris Ball int x, int y, int atomic) 1016771fe6b9SJerome Glisse { 1017771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1018771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 1019771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 1020771fe6b9SJerome Glisse struct radeon_framebuffer *radeon_fb; 1021771fe6b9SJerome Glisse struct drm_gem_object *obj; 10224c788679SJerome Glisse struct radeon_bo *rbo; 10234dd19b0dSChris Ball struct drm_framebuffer *target_fb; 1024771fe6b9SJerome Glisse uint64_t fb_location; 1025e024e110SDave Airlie uint32_t fb_format, fb_pitch_pixels, tiling_flags; 10264c788679SJerome Glisse int r; 1027771fe6b9SJerome Glisse 10282de3b484SJerome Glisse /* no fb bound */ 10294dd19b0dSChris Ball if (!atomic && !crtc->fb) { 1030d9fdaafbSDave Airlie DRM_DEBUG_KMS("No FB bound\n"); 10312de3b484SJerome Glisse return 0; 10322de3b484SJerome Glisse } 1033771fe6b9SJerome Glisse 10344dd19b0dSChris Ball if (atomic) { 10354dd19b0dSChris Ball radeon_fb = to_radeon_framebuffer(fb); 10364dd19b0dSChris Ball target_fb = fb; 10374dd19b0dSChris Ball } 10384dd19b0dSChris Ball else { 1039771fe6b9SJerome Glisse radeon_fb = to_radeon_framebuffer(crtc->fb); 10404dd19b0dSChris Ball target_fb = crtc->fb; 10414dd19b0dSChris Ball } 1042771fe6b9SJerome Glisse 1043771fe6b9SJerome Glisse obj = radeon_fb->obj; 10444c788679SJerome Glisse rbo = obj->driver_private; 10454c788679SJerome Glisse r = radeon_bo_reserve(rbo, false); 10464c788679SJerome Glisse if (unlikely(r != 0)) 10474c788679SJerome Glisse return r; 10484dd19b0dSChris Ball 10494dd19b0dSChris Ball /* If atomic, assume fb object is pinned & idle & fenced and 10504dd19b0dSChris Ball * just update base pointers 10514dd19b0dSChris Ball */ 10524dd19b0dSChris Ball if (atomic) 10534dd19b0dSChris Ball fb_location = radeon_bo_gpu_offset(rbo); 10544dd19b0dSChris Ball else { 10554c788679SJerome Glisse r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); 10564c788679SJerome Glisse if (unlikely(r != 0)) { 10574c788679SJerome Glisse radeon_bo_unreserve(rbo); 1058771fe6b9SJerome Glisse return -EINVAL; 1059771fe6b9SJerome Glisse } 10604dd19b0dSChris Ball } 10614c788679SJerome Glisse radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); 10624c788679SJerome Glisse radeon_bo_unreserve(rbo); 1063771fe6b9SJerome Glisse 10644dd19b0dSChris Ball switch (target_fb->bits_per_pixel) { 106541456df2SDave Airlie case 8: 106641456df2SDave Airlie fb_format = 106741456df2SDave Airlie AVIVO_D1GRPH_CONTROL_DEPTH_8BPP | 106841456df2SDave Airlie AVIVO_D1GRPH_CONTROL_8BPP_INDEXED; 106941456df2SDave Airlie break; 1070771fe6b9SJerome Glisse case 15: 1071771fe6b9SJerome Glisse fb_format = 1072771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | 1073771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555; 1074771fe6b9SJerome Glisse break; 1075771fe6b9SJerome Glisse case 16: 1076771fe6b9SJerome Glisse fb_format = 1077771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | 1078771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_16BPP_RGB565; 1079771fe6b9SJerome Glisse break; 1080771fe6b9SJerome Glisse case 24: 1081771fe6b9SJerome Glisse case 32: 1082771fe6b9SJerome Glisse fb_format = 1083771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_32BPP | 1084771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888; 1085771fe6b9SJerome Glisse break; 1086771fe6b9SJerome Glisse default: 1087771fe6b9SJerome Glisse DRM_ERROR("Unsupported screen depth %d\n", 10884dd19b0dSChris Ball target_fb->bits_per_pixel); 1089771fe6b9SJerome Glisse return -EINVAL; 1090771fe6b9SJerome Glisse } 1091771fe6b9SJerome Glisse 109240c4ac1cSAlex Deucher if (rdev->family >= CHIP_R600) { 109340c4ac1cSAlex Deucher if (tiling_flags & RADEON_TILING_MACRO) 109440c4ac1cSAlex Deucher fb_format |= R600_D1GRPH_ARRAY_MODE_2D_TILED_THIN1; 109540c4ac1cSAlex Deucher else if (tiling_flags & RADEON_TILING_MICRO) 109640c4ac1cSAlex Deucher fb_format |= R600_D1GRPH_ARRAY_MODE_1D_TILED_THIN1; 109740c4ac1cSAlex Deucher } else { 1098cf2f05d3SDave Airlie if (tiling_flags & RADEON_TILING_MACRO) 1099cf2f05d3SDave Airlie fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE; 1100cf2f05d3SDave Airlie 1101e024e110SDave Airlie if (tiling_flags & RADEON_TILING_MICRO) 1102e024e110SDave Airlie fb_format |= AVIVO_D1GRPH_TILED; 110340c4ac1cSAlex Deucher } 1104e024e110SDave Airlie 1105771fe6b9SJerome Glisse if (radeon_crtc->crtc_id == 0) 1106771fe6b9SJerome Glisse WREG32(AVIVO_D1VGA_CONTROL, 0); 1107771fe6b9SJerome Glisse else 1108771fe6b9SJerome Glisse WREG32(AVIVO_D2VGA_CONTROL, 0); 1109c290dadfSAlex Deucher 1110c290dadfSAlex Deucher if (rdev->family >= CHIP_RV770) { 1111c290dadfSAlex Deucher if (radeon_crtc->crtc_id) { 111295347871SAlex Deucher WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 111395347871SAlex Deucher WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 1114c290dadfSAlex Deucher } else { 111595347871SAlex Deucher WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 111695347871SAlex Deucher WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 1117c290dadfSAlex Deucher } 1118c290dadfSAlex Deucher } 1119771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 1120771fe6b9SJerome Glisse (u32) fb_location); 1121771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + 1122771fe6b9SJerome Glisse radeon_crtc->crtc_offset, (u32) fb_location); 1123771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); 1124771fe6b9SJerome Glisse 1125771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); 1126771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); 1127771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0); 1128771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, 0); 11294dd19b0dSChris Ball WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width); 11304dd19b0dSChris Ball WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height); 1131771fe6b9SJerome Glisse 11324dd19b0dSChris Ball fb_pitch_pixels = target_fb->pitch / (target_fb->bits_per_pixel / 8); 1133771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); 1134771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1); 1135771fe6b9SJerome Glisse 1136771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, 1137771fe6b9SJerome Glisse crtc->mode.vdisplay); 1138771fe6b9SJerome Glisse x &= ~3; 1139771fe6b9SJerome Glisse y &= ~1; 1140771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset, 1141771fe6b9SJerome Glisse (x << 16) | y); 1142771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset, 1143771fe6b9SJerome Glisse (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay); 1144771fe6b9SJerome Glisse 1145771fe6b9SJerome Glisse if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) 1146771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 1147771fe6b9SJerome Glisse AVIVO_D1MODE_INTERLEAVE_EN); 1148771fe6b9SJerome Glisse else 1149771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0); 1150771fe6b9SJerome Glisse 11514dd19b0dSChris Ball if (!atomic && fb && fb != crtc->fb) { 11524dd19b0dSChris Ball radeon_fb = to_radeon_framebuffer(fb); 11534c788679SJerome Glisse rbo = radeon_fb->obj->driver_private; 11544c788679SJerome Glisse r = radeon_bo_reserve(rbo, false); 11554c788679SJerome Glisse if (unlikely(r != 0)) 11564c788679SJerome Glisse return r; 11574c788679SJerome Glisse radeon_bo_unpin(rbo); 11584c788679SJerome Glisse radeon_bo_unreserve(rbo); 1159771fe6b9SJerome Glisse } 1160f30f37deSMichel Dänzer 1161f30f37deSMichel Dänzer /* Bytes per pixel may have changed */ 1162f30f37deSMichel Dänzer radeon_bandwidth_update(rdev); 1163f30f37deSMichel Dänzer 1164771fe6b9SJerome Glisse return 0; 1165771fe6b9SJerome Glisse } 1166771fe6b9SJerome Glisse 116754f088a9SAlex Deucher int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, 116854f088a9SAlex Deucher struct drm_framebuffer *old_fb) 116954f088a9SAlex Deucher { 117054f088a9SAlex Deucher struct drm_device *dev = crtc->dev; 117154f088a9SAlex Deucher struct radeon_device *rdev = dev->dev_private; 117254f088a9SAlex Deucher 1173bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) 11744dd19b0dSChris Ball return evergreen_crtc_do_set_base(crtc, old_fb, x, y, 0); 1175bcc1c2a1SAlex Deucher else if (ASIC_IS_AVIVO(rdev)) 11764dd19b0dSChris Ball return avivo_crtc_do_set_base(crtc, old_fb, x, y, 0); 117754f088a9SAlex Deucher else 11784dd19b0dSChris Ball return radeon_crtc_do_set_base(crtc, old_fb, x, y, 0); 11794dd19b0dSChris Ball } 11804dd19b0dSChris Ball 11814dd19b0dSChris Ball int atombios_crtc_set_base_atomic(struct drm_crtc *crtc, 11824dd19b0dSChris Ball struct drm_framebuffer *fb, 11834dd19b0dSChris Ball int x, int y) 11844dd19b0dSChris Ball { 11854dd19b0dSChris Ball struct drm_device *dev = crtc->dev; 11864dd19b0dSChris Ball struct radeon_device *rdev = dev->dev_private; 11874dd19b0dSChris Ball 11884dd19b0dSChris Ball if (ASIC_IS_DCE4(rdev)) 11894dd19b0dSChris Ball return evergreen_crtc_do_set_base(crtc, fb, x, y, 1); 11904dd19b0dSChris Ball else if (ASIC_IS_AVIVO(rdev)) 11914dd19b0dSChris Ball return avivo_crtc_do_set_base(crtc, fb, x, y, 1); 11924dd19b0dSChris Ball else 11934dd19b0dSChris Ball return radeon_crtc_do_set_base(crtc, fb, x, y, 1); 119454f088a9SAlex Deucher } 119554f088a9SAlex Deucher 1196615e0cb6SAlex Deucher /* properly set additional regs when using atombios */ 1197615e0cb6SAlex Deucher static void radeon_legacy_atom_fixup(struct drm_crtc *crtc) 1198615e0cb6SAlex Deucher { 1199615e0cb6SAlex Deucher struct drm_device *dev = crtc->dev; 1200615e0cb6SAlex Deucher struct radeon_device *rdev = dev->dev_private; 1201615e0cb6SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1202615e0cb6SAlex Deucher u32 disp_merge_cntl; 1203615e0cb6SAlex Deucher 1204615e0cb6SAlex Deucher switch (radeon_crtc->crtc_id) { 1205615e0cb6SAlex Deucher case 0: 1206615e0cb6SAlex Deucher disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL); 1207615e0cb6SAlex Deucher disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; 1208615e0cb6SAlex Deucher WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl); 1209615e0cb6SAlex Deucher break; 1210615e0cb6SAlex Deucher case 1: 1211615e0cb6SAlex Deucher disp_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL); 1212615e0cb6SAlex Deucher disp_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN; 1213615e0cb6SAlex Deucher WREG32(RADEON_DISP2_MERGE_CNTL, disp_merge_cntl); 1214615e0cb6SAlex Deucher WREG32(RADEON_FP_H2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_H_SYNC_STRT_WID)); 1215615e0cb6SAlex Deucher WREG32(RADEON_FP_V2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_V_SYNC_STRT_WID)); 1216615e0cb6SAlex Deucher break; 1217615e0cb6SAlex Deucher } 1218615e0cb6SAlex Deucher } 1219615e0cb6SAlex Deucher 1220bcc1c2a1SAlex Deucher static int radeon_atom_pick_pll(struct drm_crtc *crtc) 1221bcc1c2a1SAlex Deucher { 1222bcc1c2a1SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1223bcc1c2a1SAlex Deucher struct drm_device *dev = crtc->dev; 1224bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 1225bcc1c2a1SAlex Deucher struct drm_encoder *test_encoder; 1226bcc1c2a1SAlex Deucher struct drm_crtc *test_crtc; 1227bcc1c2a1SAlex Deucher uint32_t pll_in_use = 0; 1228bcc1c2a1SAlex Deucher 1229bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) { 1230bcc1c2a1SAlex Deucher /* if crtc is driving DP and we have an ext clock, use that */ 1231bcc1c2a1SAlex Deucher list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { 1232bcc1c2a1SAlex Deucher if (test_encoder->crtc && (test_encoder->crtc == crtc)) { 1233bcc1c2a1SAlex Deucher if (atombios_get_encoder_mode(test_encoder) == ATOM_ENCODER_MODE_DP) { 1234bcc1c2a1SAlex Deucher if (rdev->clock.dp_extclk) 1235bcc1c2a1SAlex Deucher return ATOM_PPLL_INVALID; 1236bcc1c2a1SAlex Deucher } 1237bcc1c2a1SAlex Deucher } 1238bcc1c2a1SAlex Deucher } 1239bcc1c2a1SAlex Deucher 1240bcc1c2a1SAlex Deucher /* otherwise, pick one of the plls */ 1241bcc1c2a1SAlex Deucher list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { 1242bcc1c2a1SAlex Deucher struct radeon_crtc *radeon_test_crtc; 1243bcc1c2a1SAlex Deucher 1244bcc1c2a1SAlex Deucher if (crtc == test_crtc) 1245bcc1c2a1SAlex Deucher continue; 1246bcc1c2a1SAlex Deucher 1247bcc1c2a1SAlex Deucher radeon_test_crtc = to_radeon_crtc(test_crtc); 1248bcc1c2a1SAlex Deucher if ((radeon_test_crtc->pll_id >= ATOM_PPLL1) && 1249bcc1c2a1SAlex Deucher (radeon_test_crtc->pll_id <= ATOM_PPLL2)) 1250bcc1c2a1SAlex Deucher pll_in_use |= (1 << radeon_test_crtc->pll_id); 1251bcc1c2a1SAlex Deucher } 1252bcc1c2a1SAlex Deucher if (!(pll_in_use & 1)) 1253bcc1c2a1SAlex Deucher return ATOM_PPLL1; 1254bcc1c2a1SAlex Deucher return ATOM_PPLL2; 1255bcc1c2a1SAlex Deucher } else 1256bcc1c2a1SAlex Deucher return radeon_crtc->crtc_id; 1257bcc1c2a1SAlex Deucher 1258bcc1c2a1SAlex Deucher } 1259bcc1c2a1SAlex Deucher 1260771fe6b9SJerome Glisse int atombios_crtc_mode_set(struct drm_crtc *crtc, 1261771fe6b9SJerome Glisse struct drm_display_mode *mode, 1262771fe6b9SJerome Glisse struct drm_display_mode *adjusted_mode, 1263771fe6b9SJerome Glisse int x, int y, struct drm_framebuffer *old_fb) 1264771fe6b9SJerome Glisse { 1265771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1266771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 1267771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 126854bfe496SAlex Deucher struct drm_encoder *encoder; 126954bfe496SAlex Deucher bool is_tvcv = false; 1270771fe6b9SJerome Glisse 127154bfe496SAlex Deucher list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 127254bfe496SAlex Deucher /* find tv std */ 127354bfe496SAlex Deucher if (encoder->crtc == crtc) { 127454bfe496SAlex Deucher struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 127554bfe496SAlex Deucher if (radeon_encoder->active_device & 127654bfe496SAlex Deucher (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) 127754bfe496SAlex Deucher is_tvcv = true; 127854bfe496SAlex Deucher } 127954bfe496SAlex Deucher } 1280771fe6b9SJerome Glisse 1281b792210eSAlex Deucher atombios_disable_ss(crtc); 1282bcc1c2a1SAlex Deucher /* always set DCPLL */ 1283bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) 1284bcc1c2a1SAlex Deucher atombios_crtc_set_dcpll(crtc); 1285771fe6b9SJerome Glisse atombios_crtc_set_pll(crtc, adjusted_mode); 1286b792210eSAlex Deucher atombios_enable_ss(crtc); 1287771fe6b9SJerome Glisse 128854bfe496SAlex Deucher if (ASIC_IS_DCE4(rdev)) 1289bcc1c2a1SAlex Deucher atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 129054bfe496SAlex Deucher else if (ASIC_IS_AVIVO(rdev)) { 129154bfe496SAlex Deucher if (is_tvcv) 129254bfe496SAlex Deucher atombios_crtc_set_timing(crtc, adjusted_mode); 129354bfe496SAlex Deucher else 129454bfe496SAlex Deucher atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 129554bfe496SAlex Deucher } else { 1296bcc1c2a1SAlex Deucher atombios_crtc_set_timing(crtc, adjusted_mode); 12975a9bcaccSAlex Deucher if (radeon_crtc->crtc_id == 0) 12985a9bcaccSAlex Deucher atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 1299615e0cb6SAlex Deucher radeon_legacy_atom_fixup(crtc); 1300771fe6b9SJerome Glisse } 1301bcc1c2a1SAlex Deucher atombios_crtc_set_base(crtc, x, y, old_fb); 1302c93bb85bSJerome Glisse atombios_overscan_setup(crtc, mode, adjusted_mode); 1303c93bb85bSJerome Glisse atombios_scaler_setup(crtc); 1304771fe6b9SJerome Glisse return 0; 1305771fe6b9SJerome Glisse } 1306771fe6b9SJerome Glisse 1307771fe6b9SJerome Glisse static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, 1308771fe6b9SJerome Glisse struct drm_display_mode *mode, 1309771fe6b9SJerome Glisse struct drm_display_mode *adjusted_mode) 1310771fe6b9SJerome Glisse { 131103214bd5SAlex Deucher struct drm_device *dev = crtc->dev; 131203214bd5SAlex Deucher struct radeon_device *rdev = dev->dev_private; 131303214bd5SAlex Deucher 131403214bd5SAlex Deucher /* adjust pm to upcoming mode change */ 131503214bd5SAlex Deucher radeon_pm_compute_clocks(rdev); 131603214bd5SAlex Deucher 1317c93bb85bSJerome Glisse if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) 1318c93bb85bSJerome Glisse return false; 1319771fe6b9SJerome Glisse return true; 1320771fe6b9SJerome Glisse } 1321771fe6b9SJerome Glisse 1322771fe6b9SJerome Glisse static void atombios_crtc_prepare(struct drm_crtc *crtc) 1323771fe6b9SJerome Glisse { 1324267364acSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1325267364acSAlex Deucher 1326267364acSAlex Deucher /* pick pll */ 1327267364acSAlex Deucher radeon_crtc->pll_id = radeon_atom_pick_pll(crtc); 1328267364acSAlex Deucher 132937b4390eSAlex Deucher atombios_lock_crtc(crtc, ATOM_ENABLE); 1330a348c84dSAlex Deucher atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 1331771fe6b9SJerome Glisse } 1332771fe6b9SJerome Glisse 1333771fe6b9SJerome Glisse static void atombios_crtc_commit(struct drm_crtc *crtc) 1334771fe6b9SJerome Glisse { 1335771fe6b9SJerome Glisse atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON); 133637b4390eSAlex Deucher atombios_lock_crtc(crtc, ATOM_DISABLE); 1337771fe6b9SJerome Glisse } 1338771fe6b9SJerome Glisse 133937f9003bSAlex Deucher static void atombios_crtc_disable(struct drm_crtc *crtc) 134037f9003bSAlex Deucher { 134137f9003bSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 134237f9003bSAlex Deucher atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 134337f9003bSAlex Deucher 134437f9003bSAlex Deucher switch (radeon_crtc->pll_id) { 134537f9003bSAlex Deucher case ATOM_PPLL1: 134637f9003bSAlex Deucher case ATOM_PPLL2: 134737f9003bSAlex Deucher /* disable the ppll */ 134837f9003bSAlex Deucher atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, 134937f9003bSAlex Deucher 0, 0, ATOM_DISABLE, 0, 0, 0, 0); 135037f9003bSAlex Deucher break; 135137f9003bSAlex Deucher default: 135237f9003bSAlex Deucher break; 135337f9003bSAlex Deucher } 135437f9003bSAlex Deucher radeon_crtc->pll_id = -1; 135537f9003bSAlex Deucher } 135637f9003bSAlex Deucher 1357771fe6b9SJerome Glisse static const struct drm_crtc_helper_funcs atombios_helper_funcs = { 1358771fe6b9SJerome Glisse .dpms = atombios_crtc_dpms, 1359771fe6b9SJerome Glisse .mode_fixup = atombios_crtc_mode_fixup, 1360771fe6b9SJerome Glisse .mode_set = atombios_crtc_mode_set, 1361771fe6b9SJerome Glisse .mode_set_base = atombios_crtc_set_base, 13624dd19b0dSChris Ball .mode_set_base_atomic = atombios_crtc_set_base_atomic, 1363771fe6b9SJerome Glisse .prepare = atombios_crtc_prepare, 1364771fe6b9SJerome Glisse .commit = atombios_crtc_commit, 1365068143d3SDave Airlie .load_lut = radeon_crtc_load_lut, 136637f9003bSAlex Deucher .disable = atombios_crtc_disable, 1367771fe6b9SJerome Glisse }; 1368771fe6b9SJerome Glisse 1369771fe6b9SJerome Glisse void radeon_atombios_init_crtc(struct drm_device *dev, 1370771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc) 1371771fe6b9SJerome Glisse { 1372bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 1373bcc1c2a1SAlex Deucher 1374bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) { 1375bcc1c2a1SAlex Deucher switch (radeon_crtc->crtc_id) { 1376bcc1c2a1SAlex Deucher case 0: 1377bcc1c2a1SAlex Deucher default: 137812d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC0_REGISTER_OFFSET; 1379bcc1c2a1SAlex Deucher break; 1380bcc1c2a1SAlex Deucher case 1: 138112d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC1_REGISTER_OFFSET; 1382bcc1c2a1SAlex Deucher break; 1383bcc1c2a1SAlex Deucher case 2: 138412d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC2_REGISTER_OFFSET; 1385bcc1c2a1SAlex Deucher break; 1386bcc1c2a1SAlex Deucher case 3: 138712d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC3_REGISTER_OFFSET; 1388bcc1c2a1SAlex Deucher break; 1389bcc1c2a1SAlex Deucher case 4: 139012d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC4_REGISTER_OFFSET; 1391bcc1c2a1SAlex Deucher break; 1392bcc1c2a1SAlex Deucher case 5: 139312d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC5_REGISTER_OFFSET; 1394bcc1c2a1SAlex Deucher break; 1395bcc1c2a1SAlex Deucher } 1396bcc1c2a1SAlex Deucher } else { 1397771fe6b9SJerome Glisse if (radeon_crtc->crtc_id == 1) 1398771fe6b9SJerome Glisse radeon_crtc->crtc_offset = 1399771fe6b9SJerome Glisse AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL; 1400bcc1c2a1SAlex Deucher else 1401bcc1c2a1SAlex Deucher radeon_crtc->crtc_offset = 0; 1402bcc1c2a1SAlex Deucher } 1403bcc1c2a1SAlex Deucher radeon_crtc->pll_id = -1; 1404771fe6b9SJerome Glisse drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); 1405771fe6b9SJerome Glisse } 1406