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> 29771fe6b9SJerome Glisse #include "radeon_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.usOverscanRight = 0; 48c93bb85bSJerome Glisse args.usOverscanLeft = 0; 49c93bb85bSJerome Glisse args.usOverscanBottom = 0; 50c93bb85bSJerome Glisse args.usOverscanTop = 0; 51c93bb85bSJerome Glisse args.ucCRTC = radeon_crtc->crtc_id; 52c93bb85bSJerome Glisse 53c93bb85bSJerome Glisse switch (radeon_crtc->rmx_type) { 54c93bb85bSJerome Glisse case RMX_CENTER: 55c93bb85bSJerome Glisse args.usOverscanTop = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2; 56c93bb85bSJerome Glisse args.usOverscanBottom = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2; 57c93bb85bSJerome Glisse args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2; 58c93bb85bSJerome Glisse args.usOverscanRight = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2; 59c93bb85bSJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 60c93bb85bSJerome Glisse break; 61c93bb85bSJerome Glisse case RMX_ASPECT: 62c93bb85bSJerome Glisse a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay; 63c93bb85bSJerome Glisse a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay; 64c93bb85bSJerome Glisse 65c93bb85bSJerome Glisse if (a1 > a2) { 66c93bb85bSJerome Glisse args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2; 67c93bb85bSJerome Glisse args.usOverscanRight = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2; 68c93bb85bSJerome Glisse } else if (a2 > a1) { 69c93bb85bSJerome Glisse args.usOverscanLeft = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2; 70c93bb85bSJerome Glisse args.usOverscanRight = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2; 71c93bb85bSJerome Glisse } 72c93bb85bSJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 73c93bb85bSJerome Glisse break; 74c93bb85bSJerome Glisse case RMX_FULL: 75c93bb85bSJerome Glisse default: 76c93bb85bSJerome Glisse args.usOverscanRight = 0; 77c93bb85bSJerome Glisse args.usOverscanLeft = 0; 78c93bb85bSJerome Glisse args.usOverscanBottom = 0; 79c93bb85bSJerome Glisse args.usOverscanTop = 0; 80c93bb85bSJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 81c93bb85bSJerome Glisse break; 82c93bb85bSJerome Glisse } 83c93bb85bSJerome Glisse } 84c93bb85bSJerome Glisse 85c93bb85bSJerome Glisse static void atombios_scaler_setup(struct drm_crtc *crtc) 86c93bb85bSJerome Glisse { 87c93bb85bSJerome Glisse struct drm_device *dev = crtc->dev; 88c93bb85bSJerome Glisse struct radeon_device *rdev = dev->dev_private; 89c93bb85bSJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 90c93bb85bSJerome Glisse ENABLE_SCALER_PS_ALLOCATION args; 91c93bb85bSJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, EnableScaler); 924ce001abSDave Airlie 93c93bb85bSJerome Glisse /* fixme - fill in enc_priv for atom dac */ 94c93bb85bSJerome Glisse enum radeon_tv_std tv_std = TV_STD_NTSC; 954ce001abSDave Airlie bool is_tv = false, is_cv = false; 964ce001abSDave Airlie struct drm_encoder *encoder; 97c93bb85bSJerome Glisse 98c93bb85bSJerome Glisse if (!ASIC_IS_AVIVO(rdev) && radeon_crtc->crtc_id) 99c93bb85bSJerome Glisse return; 100c93bb85bSJerome Glisse 1014ce001abSDave Airlie list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 1024ce001abSDave Airlie /* find tv std */ 1034ce001abSDave Airlie if (encoder->crtc == crtc) { 1044ce001abSDave Airlie struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 1054ce001abSDave Airlie if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) { 1064ce001abSDave Airlie struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv; 1074ce001abSDave Airlie tv_std = tv_dac->tv_std; 1084ce001abSDave Airlie is_tv = true; 1094ce001abSDave Airlie } 1104ce001abSDave Airlie } 1114ce001abSDave Airlie } 1124ce001abSDave Airlie 113c93bb85bSJerome Glisse memset(&args, 0, sizeof(args)); 114c93bb85bSJerome Glisse 115c93bb85bSJerome Glisse args.ucScaler = radeon_crtc->crtc_id; 116c93bb85bSJerome Glisse 1174ce001abSDave Airlie if (is_tv) { 118c93bb85bSJerome Glisse switch (tv_std) { 119c93bb85bSJerome Glisse case TV_STD_NTSC: 120c93bb85bSJerome Glisse default: 121c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_NTSC; 122c93bb85bSJerome Glisse break; 123c93bb85bSJerome Glisse case TV_STD_PAL: 124c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_PAL; 125c93bb85bSJerome Glisse break; 126c93bb85bSJerome Glisse case TV_STD_PAL_M: 127c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_PALM; 128c93bb85bSJerome Glisse break; 129c93bb85bSJerome Glisse case TV_STD_PAL_60: 130c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_PAL60; 131c93bb85bSJerome Glisse break; 132c93bb85bSJerome Glisse case TV_STD_NTSC_J: 133c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_NTSCJ; 134c93bb85bSJerome Glisse break; 135c93bb85bSJerome Glisse case TV_STD_SCART_PAL: 136c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_PAL; /* ??? */ 137c93bb85bSJerome Glisse break; 138c93bb85bSJerome Glisse case TV_STD_SECAM: 139c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_SECAM; 140c93bb85bSJerome Glisse break; 141c93bb85bSJerome Glisse case TV_STD_PAL_CN: 142c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_PALCN; 143c93bb85bSJerome Glisse break; 144c93bb85bSJerome Glisse } 145c93bb85bSJerome Glisse args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; 1464ce001abSDave Airlie } else if (is_cv) { 147c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_CV; 148c93bb85bSJerome Glisse args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; 149c93bb85bSJerome Glisse } else { 150c93bb85bSJerome Glisse switch (radeon_crtc->rmx_type) { 151c93bb85bSJerome Glisse case RMX_FULL: 152c93bb85bSJerome Glisse args.ucEnable = ATOM_SCALER_EXPANSION; 153c93bb85bSJerome Glisse break; 154c93bb85bSJerome Glisse case RMX_CENTER: 155c93bb85bSJerome Glisse args.ucEnable = ATOM_SCALER_CENTER; 156c93bb85bSJerome Glisse break; 157c93bb85bSJerome Glisse case RMX_ASPECT: 158c93bb85bSJerome Glisse args.ucEnable = ATOM_SCALER_EXPANSION; 159c93bb85bSJerome Glisse break; 160c93bb85bSJerome Glisse default: 161c93bb85bSJerome Glisse if (ASIC_IS_AVIVO(rdev)) 162c93bb85bSJerome Glisse args.ucEnable = ATOM_SCALER_DISABLE; 163c93bb85bSJerome Glisse else 164c93bb85bSJerome Glisse args.ucEnable = ATOM_SCALER_CENTER; 165c93bb85bSJerome Glisse break; 166c93bb85bSJerome Glisse } 167c93bb85bSJerome Glisse } 168c93bb85bSJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 1694ce001abSDave Airlie if ((is_tv || is_cv) 1704ce001abSDave Airlie && rdev->family >= CHIP_RV515 && rdev->family <= CHIP_R580) { 1714ce001abSDave Airlie atom_rv515_force_tv_scaler(rdev, radeon_crtc); 172c93bb85bSJerome Glisse } 173c93bb85bSJerome Glisse } 174c93bb85bSJerome Glisse 175771fe6b9SJerome Glisse static void atombios_lock_crtc(struct drm_crtc *crtc, int lock) 176771fe6b9SJerome Glisse { 177771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 178771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 179771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 180771fe6b9SJerome Glisse int index = 181771fe6b9SJerome Glisse GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters); 182771fe6b9SJerome Glisse ENABLE_CRTC_PS_ALLOCATION args; 183771fe6b9SJerome Glisse 184771fe6b9SJerome Glisse memset(&args, 0, sizeof(args)); 185771fe6b9SJerome Glisse 186771fe6b9SJerome Glisse args.ucCRTC = radeon_crtc->crtc_id; 187771fe6b9SJerome Glisse args.ucEnable = lock; 188771fe6b9SJerome Glisse 189771fe6b9SJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 190771fe6b9SJerome Glisse } 191771fe6b9SJerome Glisse 192771fe6b9SJerome Glisse static void atombios_enable_crtc(struct drm_crtc *crtc, int state) 193771fe6b9SJerome Glisse { 194771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 195771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 196771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 197771fe6b9SJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC); 198771fe6b9SJerome Glisse ENABLE_CRTC_PS_ALLOCATION args; 199771fe6b9SJerome Glisse 200771fe6b9SJerome Glisse memset(&args, 0, sizeof(args)); 201771fe6b9SJerome Glisse 202771fe6b9SJerome Glisse args.ucCRTC = radeon_crtc->crtc_id; 203771fe6b9SJerome Glisse args.ucEnable = state; 204771fe6b9SJerome Glisse 205771fe6b9SJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 206771fe6b9SJerome Glisse } 207771fe6b9SJerome Glisse 208771fe6b9SJerome Glisse static void atombios_enable_crtc_memreq(struct drm_crtc *crtc, int state) 209771fe6b9SJerome Glisse { 210771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 211771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 212771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 213771fe6b9SJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, EnableCRTCMemReq); 214771fe6b9SJerome Glisse ENABLE_CRTC_PS_ALLOCATION args; 215771fe6b9SJerome Glisse 216771fe6b9SJerome Glisse memset(&args, 0, sizeof(args)); 217771fe6b9SJerome Glisse 218771fe6b9SJerome Glisse args.ucCRTC = radeon_crtc->crtc_id; 219771fe6b9SJerome Glisse args.ucEnable = state; 220771fe6b9SJerome Glisse 221771fe6b9SJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 222771fe6b9SJerome Glisse } 223771fe6b9SJerome Glisse 224771fe6b9SJerome Glisse static void atombios_blank_crtc(struct drm_crtc *crtc, int state) 225771fe6b9SJerome Glisse { 226771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 227771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 228771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 229771fe6b9SJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC); 230771fe6b9SJerome Glisse BLANK_CRTC_PS_ALLOCATION args; 231771fe6b9SJerome Glisse 232771fe6b9SJerome Glisse memset(&args, 0, sizeof(args)); 233771fe6b9SJerome Glisse 234771fe6b9SJerome Glisse args.ucCRTC = radeon_crtc->crtc_id; 235771fe6b9SJerome Glisse args.ucBlanking = state; 236771fe6b9SJerome Glisse 237771fe6b9SJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 238771fe6b9SJerome Glisse } 239771fe6b9SJerome Glisse 240771fe6b9SJerome Glisse void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) 241771fe6b9SJerome Glisse { 242771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 243771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 244500b7587SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 245771fe6b9SJerome Glisse 246771fe6b9SJerome Glisse switch (mode) { 247771fe6b9SJerome Glisse case DRM_MODE_DPMS_ON: 24837b4390eSAlex Deucher atombios_enable_crtc(crtc, ATOM_ENABLE); 249771fe6b9SJerome Glisse if (ASIC_IS_DCE3(rdev)) 25037b4390eSAlex Deucher atombios_enable_crtc_memreq(crtc, ATOM_ENABLE); 25137b4390eSAlex Deucher atombios_blank_crtc(crtc, ATOM_DISABLE); 252500b7587SAlex Deucher drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); 253500b7587SAlex Deucher radeon_crtc_load_lut(crtc); 254a48b9b4eSAlex Deucher radeon_crtc->enabled = true; 255771fe6b9SJerome Glisse break; 256771fe6b9SJerome Glisse case DRM_MODE_DPMS_STANDBY: 257771fe6b9SJerome Glisse case DRM_MODE_DPMS_SUSPEND: 258771fe6b9SJerome Glisse case DRM_MODE_DPMS_OFF: 259500b7587SAlex Deucher drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id); 26037b4390eSAlex Deucher atombios_blank_crtc(crtc, ATOM_ENABLE); 261771fe6b9SJerome Glisse if (ASIC_IS_DCE3(rdev)) 26237b4390eSAlex Deucher atombios_enable_crtc_memreq(crtc, ATOM_DISABLE); 26337b4390eSAlex Deucher atombios_enable_crtc(crtc, ATOM_DISABLE); 264a48b9b4eSAlex Deucher radeon_crtc->enabled = false; 265771fe6b9SJerome Glisse break; 266771fe6b9SJerome Glisse } 26703214bd5SAlex Deucher 26803214bd5SAlex Deucher /* adjust pm to dpms change */ 26903214bd5SAlex Deucher radeon_pm_compute_clocks(rdev); 270771fe6b9SJerome Glisse } 271771fe6b9SJerome Glisse 272771fe6b9SJerome Glisse static void 273771fe6b9SJerome Glisse atombios_set_crtc_dtd_timing(struct drm_crtc *crtc, 2745a9bcaccSAlex Deucher struct drm_display_mode *mode) 275771fe6b9SJerome Glisse { 2765a9bcaccSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 277771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 278771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 2795a9bcaccSAlex Deucher SET_CRTC_USING_DTD_TIMING_PARAMETERS args; 280771fe6b9SJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming); 2815a9bcaccSAlex Deucher u16 misc = 0; 282771fe6b9SJerome Glisse 2835a9bcaccSAlex Deucher memset(&args, 0, sizeof(args)); 2845a9bcaccSAlex Deucher args.usH_Size = cpu_to_le16(mode->crtc_hdisplay); 2855a9bcaccSAlex Deucher args.usH_Blanking_Time = 2865a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay); 2875a9bcaccSAlex Deucher args.usV_Size = cpu_to_le16(mode->crtc_vdisplay); 2885a9bcaccSAlex Deucher args.usV_Blanking_Time = 2895a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay); 2905a9bcaccSAlex Deucher args.usH_SyncOffset = 2915a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay); 2925a9bcaccSAlex Deucher args.usH_SyncWidth = 2935a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start); 2945a9bcaccSAlex Deucher args.usV_SyncOffset = 2955a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay); 2965a9bcaccSAlex Deucher args.usV_SyncWidth = 2975a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start); 2985a9bcaccSAlex Deucher /*args.ucH_Border = mode->hborder;*/ 2995a9bcaccSAlex Deucher /*args.ucV_Border = mode->vborder;*/ 3005a9bcaccSAlex Deucher 3015a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_NVSYNC) 3025a9bcaccSAlex Deucher misc |= ATOM_VSYNC_POLARITY; 3035a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_NHSYNC) 3045a9bcaccSAlex Deucher misc |= ATOM_HSYNC_POLARITY; 3055a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_CSYNC) 3065a9bcaccSAlex Deucher misc |= ATOM_COMPOSITESYNC; 3075a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_INTERLACE) 3085a9bcaccSAlex Deucher misc |= ATOM_INTERLACE; 3095a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 3105a9bcaccSAlex Deucher misc |= ATOM_DOUBLE_CLOCK_MODE; 3115a9bcaccSAlex Deucher 3125a9bcaccSAlex Deucher args.susModeMiscInfo.usAccess = cpu_to_le16(misc); 3135a9bcaccSAlex Deucher args.ucCRTC = radeon_crtc->crtc_id; 314771fe6b9SJerome Glisse 3155a9bcaccSAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 316771fe6b9SJerome Glisse } 317771fe6b9SJerome Glisse 3185a9bcaccSAlex Deucher static void atombios_crtc_set_timing(struct drm_crtc *crtc, 3195a9bcaccSAlex Deucher struct drm_display_mode *mode) 320771fe6b9SJerome Glisse { 3215a9bcaccSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 322771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 323771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 3245a9bcaccSAlex Deucher SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION args; 325771fe6b9SJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing); 3265a9bcaccSAlex Deucher u16 misc = 0; 327771fe6b9SJerome Glisse 3285a9bcaccSAlex Deucher memset(&args, 0, sizeof(args)); 3295a9bcaccSAlex Deucher args.usH_Total = cpu_to_le16(mode->crtc_htotal); 3305a9bcaccSAlex Deucher args.usH_Disp = cpu_to_le16(mode->crtc_hdisplay); 3315a9bcaccSAlex Deucher args.usH_SyncStart = cpu_to_le16(mode->crtc_hsync_start); 3325a9bcaccSAlex Deucher args.usH_SyncWidth = 3335a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start); 3345a9bcaccSAlex Deucher args.usV_Total = cpu_to_le16(mode->crtc_vtotal); 3355a9bcaccSAlex Deucher args.usV_Disp = cpu_to_le16(mode->crtc_vdisplay); 3365a9bcaccSAlex Deucher args.usV_SyncStart = cpu_to_le16(mode->crtc_vsync_start); 3375a9bcaccSAlex Deucher args.usV_SyncWidth = 3385a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start); 3395a9bcaccSAlex 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; 479fc10332bSAlex Deucher 4804eaeca33SAlex Deucher /* reset the pll flags */ 4814eaeca33SAlex Deucher pll->flags = 0; 482771fe6b9SJerome Glisse 4837c27f87dSAlex Deucher /* select the PLL algo */ 4847c27f87dSAlex Deucher if (ASIC_IS_AVIVO(rdev)) { 485383be5d1SAlex Deucher if (radeon_new_pll == 0) 486383be5d1SAlex Deucher pll->algo = PLL_ALGO_LEGACY; 487383be5d1SAlex Deucher else 488383be5d1SAlex Deucher pll->algo = PLL_ALGO_NEW; 489383be5d1SAlex Deucher } else { 490383be5d1SAlex Deucher if (radeon_new_pll == 1) 491383be5d1SAlex Deucher pll->algo = PLL_ALGO_NEW; 4927c27f87dSAlex Deucher else 4937c27f87dSAlex Deucher pll->algo = PLL_ALGO_LEGACY; 494383be5d1SAlex Deucher } 4957c27f87dSAlex Deucher 496771fe6b9SJerome Glisse if (ASIC_IS_AVIVO(rdev)) { 497eb1300bcSAlex Deucher if ((rdev->family == CHIP_RS600) || 498eb1300bcSAlex Deucher (rdev->family == CHIP_RS690) || 499eb1300bcSAlex Deucher (rdev->family == CHIP_RS740)) 500fc10332bSAlex Deucher pll->flags |= (RADEON_PLL_USE_FRAC_FB_DIV | 501eb1300bcSAlex Deucher RADEON_PLL_PREFER_CLOSEST_LOWER); 502eb1300bcSAlex Deucher 503771fe6b9SJerome Glisse if (ASIC_IS_DCE32(rdev) && mode->clock > 200000) /* range limits??? */ 504fc10332bSAlex Deucher pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; 505771fe6b9SJerome Glisse else 506fc10332bSAlex Deucher pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; 507771fe6b9SJerome Glisse } else { 508fc10332bSAlex Deucher pll->flags |= RADEON_PLL_LEGACY; 509771fe6b9SJerome Glisse 510771fe6b9SJerome Glisse if (mode->clock > 200000) /* range limits??? */ 511fc10332bSAlex Deucher pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; 512771fe6b9SJerome Glisse else 513fc10332bSAlex Deucher pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; 514771fe6b9SJerome Glisse 515771fe6b9SJerome Glisse } 516771fe6b9SJerome Glisse 517771fe6b9SJerome Glisse list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 518771fe6b9SJerome Glisse if (encoder->crtc == crtc) { 5194eaeca33SAlex Deucher radeon_encoder = to_radeon_encoder(encoder); 520bcc1c2a1SAlex Deucher encoder_mode = atombios_get_encoder_mode(encoder); 5214eaeca33SAlex Deucher if (ASIC_IS_AVIVO(rdev)) { 5224eaeca33SAlex Deucher /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ 5234eaeca33SAlex Deucher if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1) 5244eaeca33SAlex Deucher adjusted_clock = mode->clock * 2; 525a1a4b23bSAlex Deucher if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) { 526a1a4b23bSAlex Deucher pll->algo = PLL_ALGO_LEGACY; 527a1a4b23bSAlex Deucher pll->flags |= RADEON_PLL_PREFER_CLOSEST_LOWER; 528a1a4b23bSAlex Deucher } 5294eaeca33SAlex Deucher } else { 5304eaeca33SAlex Deucher if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) 531fc10332bSAlex Deucher pll->flags |= RADEON_PLL_NO_ODD_POST_DIV; 5324eaeca33SAlex Deucher if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) 533fc10332bSAlex Deucher pll->flags |= RADEON_PLL_USE_REF_DIV; 534771fe6b9SJerome Glisse } 5353ce0a23dSJerome Glisse break; 536771fe6b9SJerome Glisse } 537771fe6b9SJerome Glisse } 538771fe6b9SJerome Glisse 5392606c886SAlex Deucher /* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock 5402606c886SAlex Deucher * accordingly based on the encoder/transmitter to work around 5412606c886SAlex Deucher * special hw requirements. 5422606c886SAlex Deucher */ 5432606c886SAlex Deucher if (ASIC_IS_DCE3(rdev)) { 5444eaeca33SAlex Deucher union adjust_pixel_clock args; 5454eaeca33SAlex Deucher u8 frev, crev; 5464eaeca33SAlex Deucher int index; 5472606c886SAlex Deucher 5482606c886SAlex Deucher index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll); 549a084e6eeSAlex Deucher if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 550a084e6eeSAlex Deucher &crev)) 551a084e6eeSAlex Deucher return adjusted_clock; 5524eaeca33SAlex Deucher 5534eaeca33SAlex Deucher memset(&args, 0, sizeof(args)); 5544eaeca33SAlex Deucher 5554eaeca33SAlex Deucher switch (frev) { 5564eaeca33SAlex Deucher case 1: 5574eaeca33SAlex Deucher switch (crev) { 5584eaeca33SAlex Deucher case 1: 5594eaeca33SAlex Deucher case 2: 5604eaeca33SAlex Deucher args.v1.usPixelClock = cpu_to_le16(mode->clock / 10); 5614eaeca33SAlex Deucher args.v1.ucTransmitterID = radeon_encoder->encoder_id; 562bcc1c2a1SAlex Deucher args.v1.ucEncodeMode = encoder_mode; 5634eaeca33SAlex Deucher 5642606c886SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, 5654eaeca33SAlex Deucher index, (uint32_t *)&args); 5664eaeca33SAlex Deucher adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10; 5674eaeca33SAlex Deucher break; 568bcc1c2a1SAlex Deucher case 3: 569bcc1c2a1SAlex Deucher args.v3.sInput.usPixelClock = cpu_to_le16(mode->clock / 10); 570bcc1c2a1SAlex Deucher args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id; 571bcc1c2a1SAlex Deucher args.v3.sInput.ucEncodeMode = encoder_mode; 572bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig = 0; 573bcc1c2a1SAlex Deucher if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { 574bcc1c2a1SAlex Deucher struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 575bcc1c2a1SAlex Deucher 576bcc1c2a1SAlex Deucher if (encoder_mode == ATOM_ENCODER_MODE_DP) 577bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 578bcc1c2a1SAlex Deucher DISPPLL_CONFIG_COHERENT_MODE; 579bcc1c2a1SAlex Deucher else { 580bcc1c2a1SAlex Deucher if (dig->coherent_mode) 581bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 582bcc1c2a1SAlex Deucher DISPPLL_CONFIG_COHERENT_MODE; 583bcc1c2a1SAlex Deucher if (mode->clock > 165000) 584bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 585bcc1c2a1SAlex Deucher DISPPLL_CONFIG_DUAL_LINK; 586bcc1c2a1SAlex Deucher } 587bcc1c2a1SAlex Deucher } else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 588bcc1c2a1SAlex Deucher /* may want to enable SS on DP/eDP eventually */ 5899f998ad7SAlex Deucher /*args.v3.sInput.ucDispPllConfig |= 5909f998ad7SAlex Deucher DISPPLL_CONFIG_SS_ENABLE;*/ 5919f998ad7SAlex Deucher if (encoder_mode == ATOM_ENCODER_MODE_DP) 592bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 5939f998ad7SAlex Deucher DISPPLL_CONFIG_COHERENT_MODE; 5949f998ad7SAlex Deucher else { 595bcc1c2a1SAlex Deucher if (mode->clock > 165000) 596bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 597bcc1c2a1SAlex Deucher DISPPLL_CONFIG_DUAL_LINK; 598bcc1c2a1SAlex Deucher } 5999f998ad7SAlex Deucher } 600bcc1c2a1SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, 601bcc1c2a1SAlex Deucher index, (uint32_t *)&args); 602bcc1c2a1SAlex Deucher adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10; 603bcc1c2a1SAlex Deucher if (args.v3.sOutput.ucRefDiv) { 604bcc1c2a1SAlex Deucher pll->flags |= RADEON_PLL_USE_REF_DIV; 605bcc1c2a1SAlex Deucher pll->reference_div = args.v3.sOutput.ucRefDiv; 606bcc1c2a1SAlex Deucher } 607bcc1c2a1SAlex Deucher if (args.v3.sOutput.ucPostDiv) { 608bcc1c2a1SAlex Deucher pll->flags |= RADEON_PLL_USE_POST_DIV; 609bcc1c2a1SAlex Deucher pll->post_div = args.v3.sOutput.ucPostDiv; 610bcc1c2a1SAlex Deucher } 611bcc1c2a1SAlex Deucher break; 6124eaeca33SAlex Deucher default: 6134eaeca33SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 6144eaeca33SAlex Deucher return adjusted_clock; 615d56ef9c8SAlex Deucher } 6164eaeca33SAlex Deucher break; 6174eaeca33SAlex Deucher default: 6184eaeca33SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 6194eaeca33SAlex Deucher return adjusted_clock; 6204eaeca33SAlex Deucher } 6214eaeca33SAlex Deucher } 6224eaeca33SAlex Deucher return adjusted_clock; 6234eaeca33SAlex Deucher } 6244eaeca33SAlex Deucher 6254eaeca33SAlex Deucher union set_pixel_clock { 6264eaeca33SAlex Deucher SET_PIXEL_CLOCK_PS_ALLOCATION base; 6274eaeca33SAlex Deucher PIXEL_CLOCK_PARAMETERS v1; 6284eaeca33SAlex Deucher PIXEL_CLOCK_PARAMETERS_V2 v2; 6294eaeca33SAlex Deucher PIXEL_CLOCK_PARAMETERS_V3 v3; 630bcc1c2a1SAlex Deucher PIXEL_CLOCK_PARAMETERS_V5 v5; 6314eaeca33SAlex Deucher }; 6324eaeca33SAlex Deucher 633bcc1c2a1SAlex Deucher static void atombios_crtc_set_dcpll(struct drm_crtc *crtc) 634bcc1c2a1SAlex Deucher { 635bcc1c2a1SAlex Deucher struct drm_device *dev = crtc->dev; 636bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 637bcc1c2a1SAlex Deucher u8 frev, crev; 638bcc1c2a1SAlex Deucher int index; 639bcc1c2a1SAlex Deucher union set_pixel_clock args; 640bcc1c2a1SAlex Deucher 641bcc1c2a1SAlex Deucher memset(&args, 0, sizeof(args)); 642bcc1c2a1SAlex Deucher 643bcc1c2a1SAlex Deucher index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); 644a084e6eeSAlex Deucher if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 645a084e6eeSAlex Deucher &crev)) 646a084e6eeSAlex Deucher return; 647bcc1c2a1SAlex Deucher 648bcc1c2a1SAlex Deucher switch (frev) { 649bcc1c2a1SAlex Deucher case 1: 650bcc1c2a1SAlex Deucher switch (crev) { 651bcc1c2a1SAlex Deucher case 5: 652bcc1c2a1SAlex Deucher /* if the default dcpll clock is specified, 653bcc1c2a1SAlex Deucher * SetPixelClock provides the dividers 654bcc1c2a1SAlex Deucher */ 655bcc1c2a1SAlex Deucher args.v5.ucCRTC = ATOM_CRTC_INVALID; 656bcc1c2a1SAlex Deucher args.v5.usPixelClock = rdev->clock.default_dispclk; 657bcc1c2a1SAlex Deucher args.v5.ucPpll = ATOM_DCPLL; 658bcc1c2a1SAlex Deucher break; 659bcc1c2a1SAlex Deucher default: 660bcc1c2a1SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 661bcc1c2a1SAlex Deucher return; 662bcc1c2a1SAlex Deucher } 663bcc1c2a1SAlex Deucher break; 664bcc1c2a1SAlex Deucher default: 665bcc1c2a1SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 666bcc1c2a1SAlex Deucher return; 667bcc1c2a1SAlex Deucher } 668bcc1c2a1SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 669bcc1c2a1SAlex Deucher } 670bcc1c2a1SAlex Deucher 671bcc1c2a1SAlex Deucher static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) 6724eaeca33SAlex Deucher { 6734eaeca33SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 6744eaeca33SAlex Deucher struct drm_device *dev = crtc->dev; 6754eaeca33SAlex Deucher struct radeon_device *rdev = dev->dev_private; 6764eaeca33SAlex Deucher struct drm_encoder *encoder = NULL; 6774eaeca33SAlex Deucher struct radeon_encoder *radeon_encoder = NULL; 6784eaeca33SAlex Deucher u8 frev, crev; 6794eaeca33SAlex Deucher int index; 6804eaeca33SAlex Deucher union set_pixel_clock args; 6814eaeca33SAlex Deucher u32 pll_clock = mode->clock; 6824eaeca33SAlex Deucher u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; 6834eaeca33SAlex Deucher struct radeon_pll *pll; 6844eaeca33SAlex Deucher u32 adjusted_clock; 685bcc1c2a1SAlex Deucher int encoder_mode = 0; 6864eaeca33SAlex Deucher 6874eaeca33SAlex Deucher memset(&args, 0, sizeof(args)); 6884eaeca33SAlex Deucher 6894eaeca33SAlex Deucher list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 6904eaeca33SAlex Deucher if (encoder->crtc == crtc) { 6914eaeca33SAlex Deucher radeon_encoder = to_radeon_encoder(encoder); 692bcc1c2a1SAlex Deucher encoder_mode = atombios_get_encoder_mode(encoder); 6934eaeca33SAlex Deucher break; 6944eaeca33SAlex Deucher } 6954eaeca33SAlex Deucher } 6964eaeca33SAlex Deucher 6974eaeca33SAlex Deucher if (!radeon_encoder) 6984eaeca33SAlex Deucher return; 6994eaeca33SAlex Deucher 700bcc1c2a1SAlex Deucher switch (radeon_crtc->pll_id) { 701bcc1c2a1SAlex Deucher case ATOM_PPLL1: 7024eaeca33SAlex Deucher pll = &rdev->clock.p1pll; 703bcc1c2a1SAlex Deucher break; 704bcc1c2a1SAlex Deucher case ATOM_PPLL2: 7054eaeca33SAlex Deucher pll = &rdev->clock.p2pll; 706bcc1c2a1SAlex Deucher break; 707bcc1c2a1SAlex Deucher case ATOM_DCPLL: 708bcc1c2a1SAlex Deucher case ATOM_PPLL_INVALID: 709bcc1c2a1SAlex Deucher pll = &rdev->clock.dcpll; 710bcc1c2a1SAlex Deucher break; 711bcc1c2a1SAlex Deucher } 7124eaeca33SAlex Deucher 7134eaeca33SAlex Deucher /* adjust pixel clock as needed */ 7144eaeca33SAlex Deucher adjusted_clock = atombios_adjust_pll(crtc, mode, pll); 7152606c886SAlex Deucher 7162606c886SAlex Deucher radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, 717fc10332bSAlex Deucher &ref_div, &post_div); 718771fe6b9SJerome Glisse 71939deb2d6SDave Airlie index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); 720a084e6eeSAlex Deucher if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 721a084e6eeSAlex Deucher &crev)) 722a084e6eeSAlex Deucher return; 723771fe6b9SJerome Glisse 724771fe6b9SJerome Glisse switch (frev) { 725771fe6b9SJerome Glisse case 1: 726771fe6b9SJerome Glisse switch (crev) { 727771fe6b9SJerome Glisse case 1: 7284eaeca33SAlex Deucher args.v1.usPixelClock = cpu_to_le16(mode->clock / 10); 7294eaeca33SAlex Deucher args.v1.usRefDiv = cpu_to_le16(ref_div); 7304eaeca33SAlex Deucher args.v1.usFbDiv = cpu_to_le16(fb_div); 7314eaeca33SAlex Deucher args.v1.ucFracFbDiv = frac_fb_div; 7324eaeca33SAlex Deucher args.v1.ucPostDiv = post_div; 733bcc1c2a1SAlex Deucher args.v1.ucPpll = radeon_crtc->pll_id; 7344eaeca33SAlex Deucher args.v1.ucCRTC = radeon_crtc->crtc_id; 7354eaeca33SAlex Deucher args.v1.ucRefDivSrc = 1; 736771fe6b9SJerome Glisse break; 737771fe6b9SJerome Glisse case 2: 7384eaeca33SAlex Deucher args.v2.usPixelClock = cpu_to_le16(mode->clock / 10); 7394eaeca33SAlex Deucher args.v2.usRefDiv = cpu_to_le16(ref_div); 7404eaeca33SAlex Deucher args.v2.usFbDiv = cpu_to_le16(fb_div); 7414eaeca33SAlex Deucher args.v2.ucFracFbDiv = frac_fb_div; 7424eaeca33SAlex Deucher args.v2.ucPostDiv = post_div; 743bcc1c2a1SAlex Deucher args.v2.ucPpll = radeon_crtc->pll_id; 7444eaeca33SAlex Deucher args.v2.ucCRTC = radeon_crtc->crtc_id; 7454eaeca33SAlex Deucher args.v2.ucRefDivSrc = 1; 746771fe6b9SJerome Glisse break; 747771fe6b9SJerome Glisse case 3: 7484eaeca33SAlex Deucher args.v3.usPixelClock = cpu_to_le16(mode->clock / 10); 7494eaeca33SAlex Deucher args.v3.usRefDiv = cpu_to_le16(ref_div); 7504eaeca33SAlex Deucher args.v3.usFbDiv = cpu_to_le16(fb_div); 7514eaeca33SAlex Deucher args.v3.ucFracFbDiv = frac_fb_div; 7524eaeca33SAlex Deucher args.v3.ucPostDiv = post_div; 753bcc1c2a1SAlex Deucher args.v3.ucPpll = radeon_crtc->pll_id; 754bcc1c2a1SAlex Deucher args.v3.ucMiscInfo = (radeon_crtc->pll_id << 2); 7554eaeca33SAlex Deucher args.v3.ucTransmitterId = radeon_encoder->encoder_id; 756bcc1c2a1SAlex Deucher args.v3.ucEncoderMode = encoder_mode; 757bcc1c2a1SAlex Deucher break; 758bcc1c2a1SAlex Deucher case 5: 759bcc1c2a1SAlex Deucher args.v5.ucCRTC = radeon_crtc->crtc_id; 760bcc1c2a1SAlex Deucher args.v5.usPixelClock = cpu_to_le16(mode->clock / 10); 761bcc1c2a1SAlex Deucher args.v5.ucRefDiv = ref_div; 762bcc1c2a1SAlex Deucher args.v5.usFbDiv = cpu_to_le16(fb_div); 763bcc1c2a1SAlex Deucher args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); 764bcc1c2a1SAlex Deucher args.v5.ucPostDiv = post_div; 765bcc1c2a1SAlex Deucher args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */ 766bcc1c2a1SAlex Deucher args.v5.ucTransmitterID = radeon_encoder->encoder_id; 767bcc1c2a1SAlex Deucher args.v5.ucEncoderMode = encoder_mode; 768bcc1c2a1SAlex Deucher args.v5.ucPpll = radeon_crtc->pll_id; 769771fe6b9SJerome Glisse break; 770771fe6b9SJerome Glisse default: 771771fe6b9SJerome Glisse DRM_ERROR("Unknown table version %d %d\n", frev, crev); 772771fe6b9SJerome Glisse return; 773771fe6b9SJerome Glisse } 774771fe6b9SJerome Glisse break; 775771fe6b9SJerome Glisse default: 776771fe6b9SJerome Glisse DRM_ERROR("Unknown table version %d %d\n", frev, crev); 777771fe6b9SJerome Glisse return; 778771fe6b9SJerome Glisse } 779771fe6b9SJerome Glisse 780771fe6b9SJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 781771fe6b9SJerome Glisse } 782771fe6b9SJerome Glisse 783bcc1c2a1SAlex Deucher static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y, 784bcc1c2a1SAlex Deucher struct drm_framebuffer *old_fb) 785bcc1c2a1SAlex Deucher { 786bcc1c2a1SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 787bcc1c2a1SAlex Deucher struct drm_device *dev = crtc->dev; 788bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 789bcc1c2a1SAlex Deucher struct radeon_framebuffer *radeon_fb; 790bcc1c2a1SAlex Deucher struct drm_gem_object *obj; 791bcc1c2a1SAlex Deucher struct radeon_bo *rbo; 792bcc1c2a1SAlex Deucher uint64_t fb_location; 793bcc1c2a1SAlex Deucher uint32_t fb_format, fb_pitch_pixels, tiling_flags; 794bcc1c2a1SAlex Deucher int r; 795bcc1c2a1SAlex Deucher 796bcc1c2a1SAlex Deucher /* no fb bound */ 797bcc1c2a1SAlex Deucher if (!crtc->fb) { 798bcc1c2a1SAlex Deucher DRM_DEBUG("No FB bound\n"); 799bcc1c2a1SAlex Deucher return 0; 800bcc1c2a1SAlex Deucher } 801bcc1c2a1SAlex Deucher 802bcc1c2a1SAlex Deucher radeon_fb = to_radeon_framebuffer(crtc->fb); 803bcc1c2a1SAlex Deucher 804bcc1c2a1SAlex Deucher /* Pin framebuffer & get tilling informations */ 805bcc1c2a1SAlex Deucher obj = radeon_fb->obj; 806bcc1c2a1SAlex Deucher rbo = obj->driver_private; 807bcc1c2a1SAlex Deucher r = radeon_bo_reserve(rbo, false); 808bcc1c2a1SAlex Deucher if (unlikely(r != 0)) 809bcc1c2a1SAlex Deucher return r; 810bcc1c2a1SAlex Deucher r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); 811bcc1c2a1SAlex Deucher if (unlikely(r != 0)) { 812bcc1c2a1SAlex Deucher radeon_bo_unreserve(rbo); 813bcc1c2a1SAlex Deucher return -EINVAL; 814bcc1c2a1SAlex Deucher } 815bcc1c2a1SAlex Deucher radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); 816bcc1c2a1SAlex Deucher radeon_bo_unreserve(rbo); 817bcc1c2a1SAlex Deucher 818bcc1c2a1SAlex Deucher switch (crtc->fb->bits_per_pixel) { 819bcc1c2a1SAlex Deucher case 8: 820bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP) | 821bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED)); 822bcc1c2a1SAlex Deucher break; 823bcc1c2a1SAlex Deucher case 15: 824bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 825bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB1555)); 826bcc1c2a1SAlex Deucher break; 827bcc1c2a1SAlex Deucher case 16: 828bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 829bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565)); 830bcc1c2a1SAlex Deucher break; 831bcc1c2a1SAlex Deucher case 24: 832bcc1c2a1SAlex Deucher case 32: 833bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) | 834bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888)); 835bcc1c2a1SAlex Deucher break; 836bcc1c2a1SAlex Deucher default: 837bcc1c2a1SAlex Deucher DRM_ERROR("Unsupported screen depth %d\n", 838bcc1c2a1SAlex Deucher crtc->fb->bits_per_pixel); 839bcc1c2a1SAlex Deucher return -EINVAL; 840bcc1c2a1SAlex Deucher } 841bcc1c2a1SAlex Deucher 842bcc1c2a1SAlex Deucher switch (radeon_crtc->crtc_id) { 843bcc1c2a1SAlex Deucher case 0: 844bcc1c2a1SAlex Deucher WREG32(AVIVO_D1VGA_CONTROL, 0); 845bcc1c2a1SAlex Deucher break; 846bcc1c2a1SAlex Deucher case 1: 847bcc1c2a1SAlex Deucher WREG32(AVIVO_D2VGA_CONTROL, 0); 848bcc1c2a1SAlex Deucher break; 849bcc1c2a1SAlex Deucher case 2: 850bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D3VGA_CONTROL, 0); 851bcc1c2a1SAlex Deucher break; 852bcc1c2a1SAlex Deucher case 3: 853bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D4VGA_CONTROL, 0); 854bcc1c2a1SAlex Deucher break; 855bcc1c2a1SAlex Deucher case 4: 856bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D5VGA_CONTROL, 0); 857bcc1c2a1SAlex Deucher break; 858bcc1c2a1SAlex Deucher case 5: 859bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D6VGA_CONTROL, 0); 860bcc1c2a1SAlex Deucher break; 861bcc1c2a1SAlex Deucher default: 862bcc1c2a1SAlex Deucher break; 863bcc1c2a1SAlex Deucher } 864bcc1c2a1SAlex Deucher 865bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 866bcc1c2a1SAlex Deucher upper_32_bits(fb_location)); 867bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 868bcc1c2a1SAlex Deucher upper_32_bits(fb_location)); 869bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 870bcc1c2a1SAlex Deucher (u32)fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK); 871bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 872bcc1c2a1SAlex Deucher (u32) fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK); 873bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); 874bcc1c2a1SAlex Deucher 875bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); 876bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); 877bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_X_START + radeon_crtc->crtc_offset, 0); 878bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_Y_START + radeon_crtc->crtc_offset, 0); 879bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_X_END + radeon_crtc->crtc_offset, crtc->fb->width); 880bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_Y_END + radeon_crtc->crtc_offset, crtc->fb->height); 881bcc1c2a1SAlex Deucher 882bcc1c2a1SAlex Deucher fb_pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8); 883bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); 884bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1); 885bcc1c2a1SAlex Deucher 886bcc1c2a1SAlex Deucher WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, 887bcc1c2a1SAlex Deucher crtc->mode.vdisplay); 888bcc1c2a1SAlex Deucher x &= ~3; 889bcc1c2a1SAlex Deucher y &= ~1; 890bcc1c2a1SAlex Deucher WREG32(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset, 891bcc1c2a1SAlex Deucher (x << 16) | y); 892bcc1c2a1SAlex Deucher WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset, 893bcc1c2a1SAlex Deucher (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay); 894bcc1c2a1SAlex Deucher 895bcc1c2a1SAlex Deucher if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) 896bcc1c2a1SAlex Deucher WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 897bcc1c2a1SAlex Deucher EVERGREEN_INTERLEAVE_EN); 898bcc1c2a1SAlex Deucher else 899bcc1c2a1SAlex Deucher WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 0); 900bcc1c2a1SAlex Deucher 901bcc1c2a1SAlex Deucher if (old_fb && old_fb != crtc->fb) { 902bcc1c2a1SAlex Deucher radeon_fb = to_radeon_framebuffer(old_fb); 903bcc1c2a1SAlex Deucher rbo = radeon_fb->obj->driver_private; 904bcc1c2a1SAlex Deucher r = radeon_bo_reserve(rbo, false); 905bcc1c2a1SAlex Deucher if (unlikely(r != 0)) 906bcc1c2a1SAlex Deucher return r; 907bcc1c2a1SAlex Deucher radeon_bo_unpin(rbo); 908bcc1c2a1SAlex Deucher radeon_bo_unreserve(rbo); 909bcc1c2a1SAlex Deucher } 910bcc1c2a1SAlex Deucher 911bcc1c2a1SAlex Deucher /* Bytes per pixel may have changed */ 912bcc1c2a1SAlex Deucher radeon_bandwidth_update(rdev); 913bcc1c2a1SAlex Deucher 914bcc1c2a1SAlex Deucher return 0; 915bcc1c2a1SAlex Deucher } 916bcc1c2a1SAlex Deucher 91754f088a9SAlex Deucher static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y, 918771fe6b9SJerome Glisse struct drm_framebuffer *old_fb) 919771fe6b9SJerome Glisse { 920771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 921771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 922771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 923771fe6b9SJerome Glisse struct radeon_framebuffer *radeon_fb; 924771fe6b9SJerome Glisse struct drm_gem_object *obj; 9254c788679SJerome Glisse struct radeon_bo *rbo; 926771fe6b9SJerome Glisse uint64_t fb_location; 927e024e110SDave Airlie uint32_t fb_format, fb_pitch_pixels, tiling_flags; 9284c788679SJerome Glisse int r; 929771fe6b9SJerome Glisse 9302de3b484SJerome Glisse /* no fb bound */ 9312de3b484SJerome Glisse if (!crtc->fb) { 9322de3b484SJerome Glisse DRM_DEBUG("No FB bound\n"); 9332de3b484SJerome Glisse return 0; 9342de3b484SJerome Glisse } 935771fe6b9SJerome Glisse 936771fe6b9SJerome Glisse radeon_fb = to_radeon_framebuffer(crtc->fb); 937771fe6b9SJerome Glisse 9384c788679SJerome Glisse /* Pin framebuffer & get tilling informations */ 939771fe6b9SJerome Glisse obj = radeon_fb->obj; 9404c788679SJerome Glisse rbo = obj->driver_private; 9414c788679SJerome Glisse r = radeon_bo_reserve(rbo, false); 9424c788679SJerome Glisse if (unlikely(r != 0)) 9434c788679SJerome Glisse return r; 9444c788679SJerome Glisse r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); 9454c788679SJerome Glisse if (unlikely(r != 0)) { 9464c788679SJerome Glisse radeon_bo_unreserve(rbo); 947771fe6b9SJerome Glisse return -EINVAL; 948771fe6b9SJerome Glisse } 9494c788679SJerome Glisse radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); 9504c788679SJerome Glisse radeon_bo_unreserve(rbo); 951771fe6b9SJerome Glisse 952771fe6b9SJerome Glisse switch (crtc->fb->bits_per_pixel) { 95341456df2SDave Airlie case 8: 95441456df2SDave Airlie fb_format = 95541456df2SDave Airlie AVIVO_D1GRPH_CONTROL_DEPTH_8BPP | 95641456df2SDave Airlie AVIVO_D1GRPH_CONTROL_8BPP_INDEXED; 95741456df2SDave Airlie break; 958771fe6b9SJerome Glisse case 15: 959771fe6b9SJerome Glisse fb_format = 960771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | 961771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555; 962771fe6b9SJerome Glisse break; 963771fe6b9SJerome Glisse case 16: 964771fe6b9SJerome Glisse fb_format = 965771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | 966771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_16BPP_RGB565; 967771fe6b9SJerome Glisse break; 968771fe6b9SJerome Glisse case 24: 969771fe6b9SJerome Glisse case 32: 970771fe6b9SJerome Glisse fb_format = 971771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_32BPP | 972771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888; 973771fe6b9SJerome Glisse break; 974771fe6b9SJerome Glisse default: 975771fe6b9SJerome Glisse DRM_ERROR("Unsupported screen depth %d\n", 976771fe6b9SJerome Glisse crtc->fb->bits_per_pixel); 977771fe6b9SJerome Glisse return -EINVAL; 978771fe6b9SJerome Glisse } 979771fe6b9SJerome Glisse 980cf2f05d3SDave Airlie if (tiling_flags & RADEON_TILING_MACRO) 981cf2f05d3SDave Airlie fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE; 982cf2f05d3SDave Airlie 983e024e110SDave Airlie if (tiling_flags & RADEON_TILING_MICRO) 984e024e110SDave Airlie fb_format |= AVIVO_D1GRPH_TILED; 985e024e110SDave Airlie 986771fe6b9SJerome Glisse if (radeon_crtc->crtc_id == 0) 987771fe6b9SJerome Glisse WREG32(AVIVO_D1VGA_CONTROL, 0); 988771fe6b9SJerome Glisse else 989771fe6b9SJerome Glisse WREG32(AVIVO_D2VGA_CONTROL, 0); 990c290dadfSAlex Deucher 991c290dadfSAlex Deucher if (rdev->family >= CHIP_RV770) { 992c290dadfSAlex Deucher if (radeon_crtc->crtc_id) { 993c290dadfSAlex Deucher WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, 0); 994c290dadfSAlex Deucher WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, 0); 995c290dadfSAlex Deucher } else { 996c290dadfSAlex Deucher WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, 0); 997c290dadfSAlex Deucher WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, 0); 998c290dadfSAlex Deucher } 999c290dadfSAlex Deucher } 1000771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 1001771fe6b9SJerome Glisse (u32) fb_location); 1002771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + 1003771fe6b9SJerome Glisse radeon_crtc->crtc_offset, (u32) fb_location); 1004771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); 1005771fe6b9SJerome Glisse 1006771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); 1007771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); 1008771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0); 1009771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, 0); 1010771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, crtc->fb->width); 1011771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, crtc->fb->height); 1012771fe6b9SJerome Glisse 1013771fe6b9SJerome Glisse fb_pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8); 1014771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); 1015771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1); 1016771fe6b9SJerome Glisse 1017771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, 1018771fe6b9SJerome Glisse crtc->mode.vdisplay); 1019771fe6b9SJerome Glisse x &= ~3; 1020771fe6b9SJerome Glisse y &= ~1; 1021771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset, 1022771fe6b9SJerome Glisse (x << 16) | y); 1023771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset, 1024771fe6b9SJerome Glisse (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay); 1025771fe6b9SJerome Glisse 1026771fe6b9SJerome Glisse if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) 1027771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 1028771fe6b9SJerome Glisse AVIVO_D1MODE_INTERLEAVE_EN); 1029771fe6b9SJerome Glisse else 1030771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0); 1031771fe6b9SJerome Glisse 1032771fe6b9SJerome Glisse if (old_fb && old_fb != crtc->fb) { 1033771fe6b9SJerome Glisse radeon_fb = to_radeon_framebuffer(old_fb); 10344c788679SJerome Glisse rbo = radeon_fb->obj->driver_private; 10354c788679SJerome Glisse r = radeon_bo_reserve(rbo, false); 10364c788679SJerome Glisse if (unlikely(r != 0)) 10374c788679SJerome Glisse return r; 10384c788679SJerome Glisse radeon_bo_unpin(rbo); 10394c788679SJerome Glisse radeon_bo_unreserve(rbo); 1040771fe6b9SJerome Glisse } 1041f30f37deSMichel Dänzer 1042f30f37deSMichel Dänzer /* Bytes per pixel may have changed */ 1043f30f37deSMichel Dänzer radeon_bandwidth_update(rdev); 1044f30f37deSMichel Dänzer 1045771fe6b9SJerome Glisse return 0; 1046771fe6b9SJerome Glisse } 1047771fe6b9SJerome Glisse 104854f088a9SAlex Deucher int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, 104954f088a9SAlex Deucher struct drm_framebuffer *old_fb) 105054f088a9SAlex Deucher { 105154f088a9SAlex Deucher struct drm_device *dev = crtc->dev; 105254f088a9SAlex Deucher struct radeon_device *rdev = dev->dev_private; 105354f088a9SAlex Deucher 1054bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) 1055bcc1c2a1SAlex Deucher return evergreen_crtc_set_base(crtc, x, y, old_fb); 1056bcc1c2a1SAlex Deucher else if (ASIC_IS_AVIVO(rdev)) 105754f088a9SAlex Deucher return avivo_crtc_set_base(crtc, x, y, old_fb); 105854f088a9SAlex Deucher else 105954f088a9SAlex Deucher return radeon_crtc_set_base(crtc, x, y, old_fb); 106054f088a9SAlex Deucher } 106154f088a9SAlex Deucher 1062615e0cb6SAlex Deucher /* properly set additional regs when using atombios */ 1063615e0cb6SAlex Deucher static void radeon_legacy_atom_fixup(struct drm_crtc *crtc) 1064615e0cb6SAlex Deucher { 1065615e0cb6SAlex Deucher struct drm_device *dev = crtc->dev; 1066615e0cb6SAlex Deucher struct radeon_device *rdev = dev->dev_private; 1067615e0cb6SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1068615e0cb6SAlex Deucher u32 disp_merge_cntl; 1069615e0cb6SAlex Deucher 1070615e0cb6SAlex Deucher switch (radeon_crtc->crtc_id) { 1071615e0cb6SAlex Deucher case 0: 1072615e0cb6SAlex Deucher disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL); 1073615e0cb6SAlex Deucher disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; 1074615e0cb6SAlex Deucher WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl); 1075615e0cb6SAlex Deucher break; 1076615e0cb6SAlex Deucher case 1: 1077615e0cb6SAlex Deucher disp_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL); 1078615e0cb6SAlex Deucher disp_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN; 1079615e0cb6SAlex Deucher WREG32(RADEON_DISP2_MERGE_CNTL, disp_merge_cntl); 1080615e0cb6SAlex Deucher WREG32(RADEON_FP_H2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_H_SYNC_STRT_WID)); 1081615e0cb6SAlex Deucher WREG32(RADEON_FP_V2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_V_SYNC_STRT_WID)); 1082615e0cb6SAlex Deucher break; 1083615e0cb6SAlex Deucher } 1084615e0cb6SAlex Deucher } 1085615e0cb6SAlex Deucher 1086bcc1c2a1SAlex Deucher static int radeon_atom_pick_pll(struct drm_crtc *crtc) 1087bcc1c2a1SAlex Deucher { 1088bcc1c2a1SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1089bcc1c2a1SAlex Deucher struct drm_device *dev = crtc->dev; 1090bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 1091bcc1c2a1SAlex Deucher struct drm_encoder *test_encoder; 1092bcc1c2a1SAlex Deucher struct drm_crtc *test_crtc; 1093bcc1c2a1SAlex Deucher uint32_t pll_in_use = 0; 1094bcc1c2a1SAlex Deucher 1095bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) { 1096bcc1c2a1SAlex Deucher /* if crtc is driving DP and we have an ext clock, use that */ 1097bcc1c2a1SAlex Deucher list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { 1098bcc1c2a1SAlex Deucher if (test_encoder->crtc && (test_encoder->crtc == crtc)) { 1099bcc1c2a1SAlex Deucher if (atombios_get_encoder_mode(test_encoder) == ATOM_ENCODER_MODE_DP) { 1100bcc1c2a1SAlex Deucher if (rdev->clock.dp_extclk) 1101bcc1c2a1SAlex Deucher return ATOM_PPLL_INVALID; 1102bcc1c2a1SAlex Deucher } 1103bcc1c2a1SAlex Deucher } 1104bcc1c2a1SAlex Deucher } 1105bcc1c2a1SAlex Deucher 1106bcc1c2a1SAlex Deucher /* otherwise, pick one of the plls */ 1107bcc1c2a1SAlex Deucher list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { 1108bcc1c2a1SAlex Deucher struct radeon_crtc *radeon_test_crtc; 1109bcc1c2a1SAlex Deucher 1110bcc1c2a1SAlex Deucher if (crtc == test_crtc) 1111bcc1c2a1SAlex Deucher continue; 1112bcc1c2a1SAlex Deucher 1113bcc1c2a1SAlex Deucher radeon_test_crtc = to_radeon_crtc(test_crtc); 1114bcc1c2a1SAlex Deucher if ((radeon_test_crtc->pll_id >= ATOM_PPLL1) && 1115bcc1c2a1SAlex Deucher (radeon_test_crtc->pll_id <= ATOM_PPLL2)) 1116bcc1c2a1SAlex Deucher pll_in_use |= (1 << radeon_test_crtc->pll_id); 1117bcc1c2a1SAlex Deucher } 1118bcc1c2a1SAlex Deucher if (!(pll_in_use & 1)) 1119bcc1c2a1SAlex Deucher return ATOM_PPLL1; 1120bcc1c2a1SAlex Deucher return ATOM_PPLL2; 1121bcc1c2a1SAlex Deucher } else 1122bcc1c2a1SAlex Deucher return radeon_crtc->crtc_id; 1123bcc1c2a1SAlex Deucher 1124bcc1c2a1SAlex Deucher } 1125bcc1c2a1SAlex Deucher 1126771fe6b9SJerome Glisse int atombios_crtc_mode_set(struct drm_crtc *crtc, 1127771fe6b9SJerome Glisse struct drm_display_mode *mode, 1128771fe6b9SJerome Glisse struct drm_display_mode *adjusted_mode, 1129771fe6b9SJerome Glisse int x, int y, struct drm_framebuffer *old_fb) 1130771fe6b9SJerome Glisse { 1131771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1132771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 1133771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 1134771fe6b9SJerome Glisse 1135771fe6b9SJerome Glisse /* TODO color tiling */ 1136771fe6b9SJerome Glisse 1137b792210eSAlex Deucher atombios_disable_ss(crtc); 1138bcc1c2a1SAlex Deucher /* always set DCPLL */ 1139bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) 1140bcc1c2a1SAlex Deucher atombios_crtc_set_dcpll(crtc); 1141771fe6b9SJerome Glisse atombios_crtc_set_pll(crtc, adjusted_mode); 1142b792210eSAlex Deucher atombios_enable_ss(crtc); 1143771fe6b9SJerome Glisse 1144bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) 1145bcc1c2a1SAlex Deucher atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 1146bcc1c2a1SAlex Deucher else if (ASIC_IS_AVIVO(rdev)) 1147bcc1c2a1SAlex Deucher atombios_crtc_set_timing(crtc, adjusted_mode); 1148771fe6b9SJerome Glisse else { 1149bcc1c2a1SAlex Deucher atombios_crtc_set_timing(crtc, adjusted_mode); 11505a9bcaccSAlex Deucher if (radeon_crtc->crtc_id == 0) 11515a9bcaccSAlex Deucher atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 1152615e0cb6SAlex Deucher radeon_legacy_atom_fixup(crtc); 1153771fe6b9SJerome Glisse } 1154bcc1c2a1SAlex Deucher atombios_crtc_set_base(crtc, x, y, old_fb); 1155c93bb85bSJerome Glisse atombios_overscan_setup(crtc, mode, adjusted_mode); 1156c93bb85bSJerome Glisse atombios_scaler_setup(crtc); 1157771fe6b9SJerome Glisse return 0; 1158771fe6b9SJerome Glisse } 1159771fe6b9SJerome Glisse 1160771fe6b9SJerome Glisse static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, 1161771fe6b9SJerome Glisse struct drm_display_mode *mode, 1162771fe6b9SJerome Glisse struct drm_display_mode *adjusted_mode) 1163771fe6b9SJerome Glisse { 116403214bd5SAlex Deucher struct drm_device *dev = crtc->dev; 116503214bd5SAlex Deucher struct radeon_device *rdev = dev->dev_private; 116603214bd5SAlex Deucher 116703214bd5SAlex Deucher /* adjust pm to upcoming mode change */ 116803214bd5SAlex Deucher radeon_pm_compute_clocks(rdev); 116903214bd5SAlex Deucher 1170c93bb85bSJerome Glisse if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) 1171c93bb85bSJerome Glisse return false; 1172771fe6b9SJerome Glisse return true; 1173771fe6b9SJerome Glisse } 1174771fe6b9SJerome Glisse 1175771fe6b9SJerome Glisse static void atombios_crtc_prepare(struct drm_crtc *crtc) 1176771fe6b9SJerome Glisse { 1177267364acSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1178267364acSAlex Deucher 1179267364acSAlex Deucher /* pick pll */ 1180267364acSAlex Deucher radeon_crtc->pll_id = radeon_atom_pick_pll(crtc); 1181267364acSAlex Deucher 118237b4390eSAlex Deucher atombios_lock_crtc(crtc, ATOM_ENABLE); 1183a348c84dSAlex Deucher atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 1184771fe6b9SJerome Glisse } 1185771fe6b9SJerome Glisse 1186771fe6b9SJerome Glisse static void atombios_crtc_commit(struct drm_crtc *crtc) 1187771fe6b9SJerome Glisse { 1188771fe6b9SJerome Glisse atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON); 118937b4390eSAlex Deucher atombios_lock_crtc(crtc, ATOM_DISABLE); 1190771fe6b9SJerome Glisse } 1191771fe6b9SJerome Glisse 1192771fe6b9SJerome Glisse static const struct drm_crtc_helper_funcs atombios_helper_funcs = { 1193771fe6b9SJerome Glisse .dpms = atombios_crtc_dpms, 1194771fe6b9SJerome Glisse .mode_fixup = atombios_crtc_mode_fixup, 1195771fe6b9SJerome Glisse .mode_set = atombios_crtc_mode_set, 1196771fe6b9SJerome Glisse .mode_set_base = atombios_crtc_set_base, 1197771fe6b9SJerome Glisse .prepare = atombios_crtc_prepare, 1198771fe6b9SJerome Glisse .commit = atombios_crtc_commit, 1199068143d3SDave Airlie .load_lut = radeon_crtc_load_lut, 1200771fe6b9SJerome Glisse }; 1201771fe6b9SJerome Glisse 1202771fe6b9SJerome Glisse void radeon_atombios_init_crtc(struct drm_device *dev, 1203771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc) 1204771fe6b9SJerome Glisse { 1205bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 1206bcc1c2a1SAlex Deucher 1207bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) { 1208bcc1c2a1SAlex Deucher switch (radeon_crtc->crtc_id) { 1209bcc1c2a1SAlex Deucher case 0: 1210bcc1c2a1SAlex Deucher default: 121112d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC0_REGISTER_OFFSET; 1212bcc1c2a1SAlex Deucher break; 1213bcc1c2a1SAlex Deucher case 1: 121412d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC1_REGISTER_OFFSET; 1215bcc1c2a1SAlex Deucher break; 1216bcc1c2a1SAlex Deucher case 2: 121712d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC2_REGISTER_OFFSET; 1218bcc1c2a1SAlex Deucher break; 1219bcc1c2a1SAlex Deucher case 3: 122012d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC3_REGISTER_OFFSET; 1221bcc1c2a1SAlex Deucher break; 1222bcc1c2a1SAlex Deucher case 4: 122312d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC4_REGISTER_OFFSET; 1224bcc1c2a1SAlex Deucher break; 1225bcc1c2a1SAlex Deucher case 5: 122612d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC5_REGISTER_OFFSET; 1227bcc1c2a1SAlex Deucher break; 1228bcc1c2a1SAlex Deucher } 1229bcc1c2a1SAlex Deucher } else { 1230771fe6b9SJerome Glisse if (radeon_crtc->crtc_id == 1) 1231771fe6b9SJerome Glisse radeon_crtc->crtc_offset = 1232771fe6b9SJerome Glisse AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL; 1233bcc1c2a1SAlex Deucher else 1234bcc1c2a1SAlex Deucher radeon_crtc->crtc_offset = 0; 1235bcc1c2a1SAlex Deucher } 1236bcc1c2a1SAlex Deucher radeon_crtc->pll_id = -1; 1237771fe6b9SJerome Glisse drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); 1238771fe6b9SJerome Glisse } 1239