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 */ 26c182615fSSam Ravnborg 27771fe6b9SJerome Glisse #include <drm/drm_crtc_helper.h> 28b516a9efSDaniel Vetter #include <drm/drm_fb_helper.h> 2968adac5eSBen Skeggs #include <drm/drm_fixed.h> 30c182615fSSam Ravnborg #include <drm/drm_fourcc.h> 31c182615fSSam Ravnborg #include <drm/drm_vblank.h> 32c182615fSSam Ravnborg #include <drm/radeon_drm.h> 33c182615fSSam Ravnborg 34771fe6b9SJerome Glisse #include "radeon.h" 35771fe6b9SJerome Glisse #include "atom.h" 36771fe6b9SJerome Glisse #include "atom-bits.h" 37771fe6b9SJerome Glisse 38c93bb85bSJerome Glisse static void atombios_overscan_setup(struct drm_crtc *crtc, 39c93bb85bSJerome Glisse struct drm_display_mode *mode, 40c93bb85bSJerome Glisse struct drm_display_mode *adjusted_mode) 41c93bb85bSJerome Glisse { 42c93bb85bSJerome Glisse struct drm_device *dev = crtc->dev; 43c93bb85bSJerome Glisse struct radeon_device *rdev = dev->dev_private; 44c93bb85bSJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 45c93bb85bSJerome Glisse SET_CRTC_OVERSCAN_PS_ALLOCATION args; 46c93bb85bSJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan); 47c93bb85bSJerome Glisse int a1, a2; 48c93bb85bSJerome Glisse 49c93bb85bSJerome Glisse memset(&args, 0, sizeof(args)); 50c93bb85bSJerome Glisse 51c93bb85bSJerome Glisse args.ucCRTC = radeon_crtc->crtc_id; 52c93bb85bSJerome Glisse 53c93bb85bSJerome Glisse switch (radeon_crtc->rmx_type) { 54c93bb85bSJerome Glisse case RMX_CENTER: 554589433cSCédric Cano args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2); 564589433cSCédric Cano args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2); 574589433cSCédric Cano args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2); 584589433cSCédric Cano args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2); 59c93bb85bSJerome Glisse break; 60c93bb85bSJerome Glisse case RMX_ASPECT: 61c93bb85bSJerome Glisse a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay; 62c93bb85bSJerome Glisse a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay; 63c93bb85bSJerome Glisse 64c93bb85bSJerome Glisse if (a1 > a2) { 654589433cSCédric Cano args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2); 664589433cSCédric Cano args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2); 67c93bb85bSJerome Glisse } else if (a2 > a1) { 68942b0e95SAlex Deucher args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2); 69942b0e95SAlex Deucher args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2); 70c93bb85bSJerome Glisse } 71c93bb85bSJerome Glisse break; 72c93bb85bSJerome Glisse case RMX_FULL: 73c93bb85bSJerome Glisse default: 744589433cSCédric Cano args.usOverscanRight = cpu_to_le16(radeon_crtc->h_border); 754589433cSCédric Cano args.usOverscanLeft = cpu_to_le16(radeon_crtc->h_border); 764589433cSCédric Cano args.usOverscanBottom = cpu_to_le16(radeon_crtc->v_border); 774589433cSCédric Cano args.usOverscanTop = cpu_to_le16(radeon_crtc->v_border); 78c93bb85bSJerome Glisse break; 79c93bb85bSJerome Glisse } 805b1714d3SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 81c93bb85bSJerome Glisse } 82c93bb85bSJerome Glisse 83c93bb85bSJerome Glisse static void atombios_scaler_setup(struct drm_crtc *crtc) 84c93bb85bSJerome Glisse { 85c93bb85bSJerome Glisse struct drm_device *dev = crtc->dev; 86c93bb85bSJerome Glisse struct radeon_device *rdev = dev->dev_private; 87c93bb85bSJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 88c93bb85bSJerome Glisse ENABLE_SCALER_PS_ALLOCATION args; 89c93bb85bSJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, EnableScaler); 905df3196bSAlex Deucher struct radeon_encoder *radeon_encoder = 915df3196bSAlex Deucher to_radeon_encoder(radeon_crtc->encoder); 92c93bb85bSJerome Glisse /* fixme - fill in enc_priv for atom dac */ 93c93bb85bSJerome Glisse enum radeon_tv_std tv_std = TV_STD_NTSC; 944ce001abSDave Airlie bool is_tv = false, is_cv = false; 95c93bb85bSJerome Glisse 96c93bb85bSJerome Glisse if (!ASIC_IS_AVIVO(rdev) && radeon_crtc->crtc_id) 97c93bb85bSJerome Glisse return; 98c93bb85bSJerome Glisse 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 105c93bb85bSJerome Glisse memset(&args, 0, sizeof(args)); 106c93bb85bSJerome Glisse 107c93bb85bSJerome Glisse args.ucScaler = radeon_crtc->crtc_id; 108c93bb85bSJerome Glisse 1094ce001abSDave Airlie if (is_tv) { 110c93bb85bSJerome Glisse switch (tv_std) { 111c93bb85bSJerome Glisse case TV_STD_NTSC: 112c93bb85bSJerome Glisse default: 113c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_NTSC; 114c93bb85bSJerome Glisse break; 115c93bb85bSJerome Glisse case TV_STD_PAL: 116c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_PAL; 117c93bb85bSJerome Glisse break; 118c93bb85bSJerome Glisse case TV_STD_PAL_M: 119c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_PALM; 120c93bb85bSJerome Glisse break; 121c93bb85bSJerome Glisse case TV_STD_PAL_60: 122c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_PAL60; 123c93bb85bSJerome Glisse break; 124c93bb85bSJerome Glisse case TV_STD_NTSC_J: 125c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_NTSCJ; 126c93bb85bSJerome Glisse break; 127c93bb85bSJerome Glisse case TV_STD_SCART_PAL: 128c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_PAL; /* ??? */ 129c93bb85bSJerome Glisse break; 130c93bb85bSJerome Glisse case TV_STD_SECAM: 131c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_SECAM; 132c93bb85bSJerome Glisse break; 133c93bb85bSJerome Glisse case TV_STD_PAL_CN: 134c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_PALCN; 135c93bb85bSJerome Glisse break; 136c93bb85bSJerome Glisse } 137c93bb85bSJerome Glisse args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; 1384ce001abSDave Airlie } else if (is_cv) { 139c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_CV; 140c93bb85bSJerome Glisse args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; 141c93bb85bSJerome Glisse } else { 142c93bb85bSJerome Glisse switch (radeon_crtc->rmx_type) { 143c93bb85bSJerome Glisse case RMX_FULL: 144c93bb85bSJerome Glisse args.ucEnable = ATOM_SCALER_EXPANSION; 145c93bb85bSJerome Glisse break; 146c93bb85bSJerome Glisse case RMX_CENTER: 147c93bb85bSJerome Glisse args.ucEnable = ATOM_SCALER_CENTER; 148c93bb85bSJerome Glisse break; 149c93bb85bSJerome Glisse case RMX_ASPECT: 150c93bb85bSJerome Glisse args.ucEnable = ATOM_SCALER_EXPANSION; 151c93bb85bSJerome Glisse break; 152c93bb85bSJerome Glisse default: 153c93bb85bSJerome Glisse if (ASIC_IS_AVIVO(rdev)) 154c93bb85bSJerome Glisse args.ucEnable = ATOM_SCALER_DISABLE; 155c93bb85bSJerome Glisse else 156c93bb85bSJerome Glisse args.ucEnable = ATOM_SCALER_CENTER; 157c93bb85bSJerome Glisse break; 158c93bb85bSJerome Glisse } 159c93bb85bSJerome Glisse } 160c93bb85bSJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 1614ce001abSDave Airlie if ((is_tv || is_cv) 1624ce001abSDave Airlie && rdev->family >= CHIP_RV515 && rdev->family <= CHIP_R580) { 1634ce001abSDave Airlie atom_rv515_force_tv_scaler(rdev, radeon_crtc); 164c93bb85bSJerome Glisse } 165c93bb85bSJerome Glisse } 166c93bb85bSJerome Glisse 167771fe6b9SJerome Glisse static void atombios_lock_crtc(struct drm_crtc *crtc, int lock) 168771fe6b9SJerome Glisse { 169771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 170771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 171771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 172771fe6b9SJerome Glisse int index = 173771fe6b9SJerome Glisse GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters); 174771fe6b9SJerome Glisse ENABLE_CRTC_PS_ALLOCATION args; 175771fe6b9SJerome Glisse 176771fe6b9SJerome Glisse memset(&args, 0, sizeof(args)); 177771fe6b9SJerome Glisse 178771fe6b9SJerome Glisse args.ucCRTC = radeon_crtc->crtc_id; 179771fe6b9SJerome Glisse args.ucEnable = lock; 180771fe6b9SJerome Glisse 181771fe6b9SJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 182771fe6b9SJerome Glisse } 183771fe6b9SJerome Glisse 184771fe6b9SJerome Glisse static void atombios_enable_crtc(struct drm_crtc *crtc, int state) 185771fe6b9SJerome Glisse { 186771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 187771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 188771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 189771fe6b9SJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC); 190771fe6b9SJerome Glisse ENABLE_CRTC_PS_ALLOCATION args; 191771fe6b9SJerome Glisse 192771fe6b9SJerome Glisse memset(&args, 0, sizeof(args)); 193771fe6b9SJerome Glisse 194771fe6b9SJerome Glisse args.ucCRTC = radeon_crtc->crtc_id; 195771fe6b9SJerome Glisse args.ucEnable = state; 196771fe6b9SJerome Glisse 197771fe6b9SJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 198771fe6b9SJerome Glisse } 199771fe6b9SJerome Glisse 200771fe6b9SJerome Glisse static void atombios_enable_crtc_memreq(struct drm_crtc *crtc, int state) 201771fe6b9SJerome Glisse { 202771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 203771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 204771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 205771fe6b9SJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, EnableCRTCMemReq); 206771fe6b9SJerome Glisse ENABLE_CRTC_PS_ALLOCATION args; 207771fe6b9SJerome Glisse 208771fe6b9SJerome Glisse memset(&args, 0, sizeof(args)); 209771fe6b9SJerome Glisse 210771fe6b9SJerome Glisse args.ucCRTC = radeon_crtc->crtc_id; 211771fe6b9SJerome Glisse args.ucEnable = state; 212771fe6b9SJerome Glisse 213771fe6b9SJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 214771fe6b9SJerome Glisse } 215771fe6b9SJerome Glisse 21678fe9e54SAlex Deucher static const u32 vga_control_regs[6] = 21778fe9e54SAlex Deucher { 21878fe9e54SAlex Deucher AVIVO_D1VGA_CONTROL, 21978fe9e54SAlex Deucher AVIVO_D2VGA_CONTROL, 22078fe9e54SAlex Deucher EVERGREEN_D3VGA_CONTROL, 22178fe9e54SAlex Deucher EVERGREEN_D4VGA_CONTROL, 22278fe9e54SAlex Deucher EVERGREEN_D5VGA_CONTROL, 22378fe9e54SAlex Deucher EVERGREEN_D6VGA_CONTROL, 22478fe9e54SAlex Deucher }; 22578fe9e54SAlex Deucher 226771fe6b9SJerome Glisse static void atombios_blank_crtc(struct drm_crtc *crtc, int state) 227771fe6b9SJerome Glisse { 228771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 229771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 230771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 231771fe6b9SJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC); 232771fe6b9SJerome Glisse BLANK_CRTC_PS_ALLOCATION args; 23378fe9e54SAlex Deucher u32 vga_control = 0; 234771fe6b9SJerome Glisse 235771fe6b9SJerome Glisse memset(&args, 0, sizeof(args)); 236771fe6b9SJerome Glisse 23778fe9e54SAlex Deucher if (ASIC_IS_DCE8(rdev)) { 23878fe9e54SAlex Deucher vga_control = RREG32(vga_control_regs[radeon_crtc->crtc_id]); 23978fe9e54SAlex Deucher WREG32(vga_control_regs[radeon_crtc->crtc_id], vga_control | 1); 24078fe9e54SAlex Deucher } 24178fe9e54SAlex Deucher 242771fe6b9SJerome Glisse args.ucCRTC = radeon_crtc->crtc_id; 243771fe6b9SJerome Glisse args.ucBlanking = state; 244771fe6b9SJerome Glisse 245771fe6b9SJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 24678fe9e54SAlex Deucher 24778fe9e54SAlex Deucher if (ASIC_IS_DCE8(rdev)) { 24878fe9e54SAlex Deucher WREG32(vga_control_regs[radeon_crtc->crtc_id], vga_control); 24978fe9e54SAlex Deucher } 250771fe6b9SJerome Glisse } 251771fe6b9SJerome Glisse 252fef9f91fSAlex Deucher static void atombios_powergate_crtc(struct drm_crtc *crtc, int state) 253fef9f91fSAlex Deucher { 254fef9f91fSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 255fef9f91fSAlex Deucher struct drm_device *dev = crtc->dev; 256fef9f91fSAlex Deucher struct radeon_device *rdev = dev->dev_private; 257fef9f91fSAlex Deucher int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating); 258fef9f91fSAlex Deucher ENABLE_DISP_POWER_GATING_PARAMETERS_V2_1 args; 259fef9f91fSAlex Deucher 260fef9f91fSAlex Deucher memset(&args, 0, sizeof(args)); 261fef9f91fSAlex Deucher 262fef9f91fSAlex Deucher args.ucDispPipeId = radeon_crtc->crtc_id; 263fef9f91fSAlex Deucher args.ucEnable = state; 264fef9f91fSAlex Deucher 265fef9f91fSAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 266fef9f91fSAlex Deucher } 267fef9f91fSAlex Deucher 268771fe6b9SJerome Glisse void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) 269771fe6b9SJerome Glisse { 270771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 271771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 272500b7587SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 273771fe6b9SJerome Glisse 274771fe6b9SJerome Glisse switch (mode) { 275771fe6b9SJerome Glisse case DRM_MODE_DPMS_ON: 276d7311171SAlex Deucher radeon_crtc->enabled = true; 27737b4390eSAlex Deucher atombios_enable_crtc(crtc, ATOM_ENABLE); 27879f17c64SAlex Deucher if (ASIC_IS_DCE3(rdev) && !ASIC_IS_DCE6(rdev)) 27937b4390eSAlex Deucher atombios_enable_crtc_memreq(crtc, ATOM_ENABLE); 28037b4390eSAlex Deucher atombios_blank_crtc(crtc, ATOM_DISABLE); 2815e916a3aSMichel Dänzer if (dev->num_crtcs > radeon_crtc->crtc_id) 2825c9ac115SGustavo Padovan drm_crtc_vblank_on(crtc); 283500b7587SAlex Deucher radeon_crtc_load_lut(crtc); 284771fe6b9SJerome Glisse break; 285771fe6b9SJerome Glisse case DRM_MODE_DPMS_STANDBY: 286771fe6b9SJerome Glisse case DRM_MODE_DPMS_SUSPEND: 287771fe6b9SJerome Glisse case DRM_MODE_DPMS_OFF: 2885e916a3aSMichel Dänzer if (dev->num_crtcs > radeon_crtc->crtc_id) 2895c9ac115SGustavo Padovan drm_crtc_vblank_off(crtc); 290a93f344dSAlex Deucher if (radeon_crtc->enabled) 29137b4390eSAlex Deucher atombios_blank_crtc(crtc, ATOM_ENABLE); 29279f17c64SAlex Deucher if (ASIC_IS_DCE3(rdev) && !ASIC_IS_DCE6(rdev)) 29337b4390eSAlex Deucher atombios_enable_crtc_memreq(crtc, ATOM_DISABLE); 29437b4390eSAlex Deucher atombios_enable_crtc(crtc, ATOM_DISABLE); 295a48b9b4eSAlex Deucher radeon_crtc->enabled = false; 296771fe6b9SJerome Glisse break; 297771fe6b9SJerome Glisse } 2983640da2fSAlex Deucher /* adjust pm to dpms */ 2993640da2fSAlex Deucher radeon_pm_compute_clocks(rdev); 300771fe6b9SJerome Glisse } 301771fe6b9SJerome Glisse 302771fe6b9SJerome Glisse static void 303771fe6b9SJerome Glisse atombios_set_crtc_dtd_timing(struct drm_crtc *crtc, 3045a9bcaccSAlex Deucher struct drm_display_mode *mode) 305771fe6b9SJerome Glisse { 3065a9bcaccSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 307771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 308771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 3095a9bcaccSAlex Deucher SET_CRTC_USING_DTD_TIMING_PARAMETERS args; 310771fe6b9SJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming); 3115a9bcaccSAlex Deucher u16 misc = 0; 312771fe6b9SJerome Glisse 3135a9bcaccSAlex Deucher memset(&args, 0, sizeof(args)); 3145b1714d3SAlex Deucher args.usH_Size = cpu_to_le16(mode->crtc_hdisplay - (radeon_crtc->h_border * 2)); 3155a9bcaccSAlex Deucher args.usH_Blanking_Time = 3165b1714d3SAlex Deucher cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay + (radeon_crtc->h_border * 2)); 3175b1714d3SAlex Deucher args.usV_Size = cpu_to_le16(mode->crtc_vdisplay - (radeon_crtc->v_border * 2)); 3185a9bcaccSAlex Deucher args.usV_Blanking_Time = 3195b1714d3SAlex Deucher cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay + (radeon_crtc->v_border * 2)); 3205a9bcaccSAlex Deucher args.usH_SyncOffset = 3215b1714d3SAlex Deucher cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay + radeon_crtc->h_border); 3225a9bcaccSAlex Deucher args.usH_SyncWidth = 3235a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start); 3245a9bcaccSAlex Deucher args.usV_SyncOffset = 3255b1714d3SAlex Deucher cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay + radeon_crtc->v_border); 3265a9bcaccSAlex Deucher args.usV_SyncWidth = 3275a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start); 3285b1714d3SAlex Deucher args.ucH_Border = radeon_crtc->h_border; 3295b1714d3SAlex Deucher args.ucV_Border = radeon_crtc->v_border; 3305a9bcaccSAlex Deucher 3315a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_NVSYNC) 3325a9bcaccSAlex Deucher misc |= ATOM_VSYNC_POLARITY; 3335a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_NHSYNC) 3345a9bcaccSAlex Deucher misc |= ATOM_HSYNC_POLARITY; 3355a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_CSYNC) 3365a9bcaccSAlex Deucher misc |= ATOM_COMPOSITESYNC; 3375a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_INTERLACE) 3385a9bcaccSAlex Deucher misc |= ATOM_INTERLACE; 339fd99a094SAlex Deucher if (mode->flags & DRM_MODE_FLAG_DBLCLK) 3405a9bcaccSAlex Deucher misc |= ATOM_DOUBLE_CLOCK_MODE; 341fd99a094SAlex Deucher if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 342fd99a094SAlex Deucher misc |= ATOM_H_REPLICATIONBY2 | ATOM_V_REPLICATIONBY2; 3435a9bcaccSAlex Deucher 3445a9bcaccSAlex Deucher args.susModeMiscInfo.usAccess = cpu_to_le16(misc); 3455a9bcaccSAlex Deucher args.ucCRTC = radeon_crtc->crtc_id; 346771fe6b9SJerome Glisse 3475a9bcaccSAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 348771fe6b9SJerome Glisse } 349771fe6b9SJerome Glisse 3505a9bcaccSAlex Deucher static void atombios_crtc_set_timing(struct drm_crtc *crtc, 3515a9bcaccSAlex Deucher struct drm_display_mode *mode) 352771fe6b9SJerome Glisse { 3535a9bcaccSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 354771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 355771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 3565a9bcaccSAlex Deucher SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION args; 357771fe6b9SJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing); 3585a9bcaccSAlex Deucher u16 misc = 0; 359771fe6b9SJerome Glisse 3605a9bcaccSAlex Deucher memset(&args, 0, sizeof(args)); 3615a9bcaccSAlex Deucher args.usH_Total = cpu_to_le16(mode->crtc_htotal); 3625a9bcaccSAlex Deucher args.usH_Disp = cpu_to_le16(mode->crtc_hdisplay); 3635a9bcaccSAlex Deucher args.usH_SyncStart = cpu_to_le16(mode->crtc_hsync_start); 3645a9bcaccSAlex Deucher args.usH_SyncWidth = 3655a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start); 3665a9bcaccSAlex Deucher args.usV_Total = cpu_to_le16(mode->crtc_vtotal); 3675a9bcaccSAlex Deucher args.usV_Disp = cpu_to_le16(mode->crtc_vdisplay); 3685a9bcaccSAlex Deucher args.usV_SyncStart = cpu_to_le16(mode->crtc_vsync_start); 3695a9bcaccSAlex Deucher args.usV_SyncWidth = 3705a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start); 3715a9bcaccSAlex Deucher 37254bfe496SAlex Deucher args.ucOverscanRight = radeon_crtc->h_border; 37354bfe496SAlex Deucher args.ucOverscanLeft = radeon_crtc->h_border; 37454bfe496SAlex Deucher args.ucOverscanBottom = radeon_crtc->v_border; 37554bfe496SAlex Deucher args.ucOverscanTop = radeon_crtc->v_border; 37654bfe496SAlex Deucher 3775a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_NVSYNC) 3785a9bcaccSAlex Deucher misc |= ATOM_VSYNC_POLARITY; 3795a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_NHSYNC) 3805a9bcaccSAlex Deucher misc |= ATOM_HSYNC_POLARITY; 3815a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_CSYNC) 3825a9bcaccSAlex Deucher misc |= ATOM_COMPOSITESYNC; 3835a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_INTERLACE) 3845a9bcaccSAlex Deucher misc |= ATOM_INTERLACE; 385fd99a094SAlex Deucher if (mode->flags & DRM_MODE_FLAG_DBLCLK) 3865a9bcaccSAlex Deucher misc |= ATOM_DOUBLE_CLOCK_MODE; 387fd99a094SAlex Deucher if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 388fd99a094SAlex Deucher misc |= ATOM_H_REPLICATIONBY2 | ATOM_V_REPLICATIONBY2; 3895a9bcaccSAlex Deucher 3905a9bcaccSAlex Deucher args.susModeMiscInfo.usAccess = cpu_to_le16(misc); 3915a9bcaccSAlex Deucher args.ucCRTC = radeon_crtc->crtc_id; 392771fe6b9SJerome Glisse 3935a9bcaccSAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 394771fe6b9SJerome Glisse } 395771fe6b9SJerome Glisse 3963fa47d9eSAlex Deucher static void atombios_disable_ss(struct radeon_device *rdev, int pll_id) 397b792210eSAlex Deucher { 398b792210eSAlex Deucher u32 ss_cntl; 399b792210eSAlex Deucher 400b792210eSAlex Deucher if (ASIC_IS_DCE4(rdev)) { 4013fa47d9eSAlex Deucher switch (pll_id) { 402b792210eSAlex Deucher case ATOM_PPLL1: 403b792210eSAlex Deucher ss_cntl = RREG32(EVERGREEN_P1PLL_SS_CNTL); 404b792210eSAlex Deucher ss_cntl &= ~EVERGREEN_PxPLL_SS_EN; 405b792210eSAlex Deucher WREG32(EVERGREEN_P1PLL_SS_CNTL, ss_cntl); 406b792210eSAlex Deucher break; 407b792210eSAlex Deucher case ATOM_PPLL2: 408b792210eSAlex Deucher ss_cntl = RREG32(EVERGREEN_P2PLL_SS_CNTL); 409b792210eSAlex Deucher ss_cntl &= ~EVERGREEN_PxPLL_SS_EN; 410b792210eSAlex Deucher WREG32(EVERGREEN_P2PLL_SS_CNTL, ss_cntl); 411b792210eSAlex Deucher break; 412b792210eSAlex Deucher case ATOM_DCPLL: 413b792210eSAlex Deucher case ATOM_PPLL_INVALID: 414b792210eSAlex Deucher return; 415b792210eSAlex Deucher } 416b792210eSAlex Deucher } else if (ASIC_IS_AVIVO(rdev)) { 4173fa47d9eSAlex Deucher switch (pll_id) { 418b792210eSAlex Deucher case ATOM_PPLL1: 419b792210eSAlex Deucher ss_cntl = RREG32(AVIVO_P1PLL_INT_SS_CNTL); 420b792210eSAlex Deucher ss_cntl &= ~1; 421b792210eSAlex Deucher WREG32(AVIVO_P1PLL_INT_SS_CNTL, ss_cntl); 422b792210eSAlex Deucher break; 423b792210eSAlex Deucher case ATOM_PPLL2: 424b792210eSAlex Deucher ss_cntl = RREG32(AVIVO_P2PLL_INT_SS_CNTL); 425b792210eSAlex Deucher ss_cntl &= ~1; 426b792210eSAlex Deucher WREG32(AVIVO_P2PLL_INT_SS_CNTL, ss_cntl); 427b792210eSAlex Deucher break; 428b792210eSAlex Deucher case ATOM_DCPLL: 429b792210eSAlex Deucher case ATOM_PPLL_INVALID: 430b792210eSAlex Deucher return; 431b792210eSAlex Deucher } 432b792210eSAlex Deucher } 433b792210eSAlex Deucher } 434b792210eSAlex Deucher 435b792210eSAlex Deucher 43626b9fc3aSAlex Deucher union atom_enable_ss { 437ba032a58SAlex Deucher ENABLE_LVDS_SS_PARAMETERS lvds_ss; 438ba032a58SAlex Deucher ENABLE_LVDS_SS_PARAMETERS_V2 lvds_ss_2; 43926b9fc3aSAlex Deucher ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1; 440ba032a58SAlex Deucher ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 v2; 441a572eaa3SAlex Deucher ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 v3; 44226b9fc3aSAlex Deucher }; 44326b9fc3aSAlex Deucher 4443fa47d9eSAlex Deucher static void atombios_crtc_program_ss(struct radeon_device *rdev, 445ba032a58SAlex Deucher int enable, 446ba032a58SAlex Deucher int pll_id, 4475efcc76cSJerome Glisse int crtc_id, 448ba032a58SAlex Deucher struct radeon_atom_ss *ss) 449ebbe1cb9SAlex Deucher { 4505efcc76cSJerome Glisse unsigned i; 451ebbe1cb9SAlex Deucher int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL); 45226b9fc3aSAlex Deucher union atom_enable_ss args; 453ebbe1cb9SAlex Deucher 454c4756baaSAlex Deucher if (enable) { 455c4756baaSAlex Deucher /* Don't mess with SS if percentage is 0 or external ss. 456c4756baaSAlex Deucher * SS is already disabled previously, and disabling it 457c4756baaSAlex Deucher * again can cause display problems if the pll is already 458c4756baaSAlex Deucher * programmed. 459c4756baaSAlex Deucher */ 460c4756baaSAlex Deucher if (ss->percentage == 0) 461c4756baaSAlex Deucher return; 462c4756baaSAlex Deucher if (ss->type & ATOM_EXTERNAL_SS_MASK) 463c4756baaSAlex Deucher return; 464c4756baaSAlex Deucher } else { 46553176706SAlex Deucher for (i = 0; i < rdev->num_crtc; i++) { 4665efcc76cSJerome Glisse if (rdev->mode_info.crtcs[i] && 4675efcc76cSJerome Glisse rdev->mode_info.crtcs[i]->enabled && 4685efcc76cSJerome Glisse i != crtc_id && 4695efcc76cSJerome Glisse pll_id == rdev->mode_info.crtcs[i]->pll_id) { 4705efcc76cSJerome Glisse /* one other crtc is using this pll don't turn 4715efcc76cSJerome Glisse * off spread spectrum as it might turn off 4725efcc76cSJerome Glisse * display on active crtc 4735efcc76cSJerome Glisse */ 4745efcc76cSJerome Glisse return; 4755efcc76cSJerome Glisse } 4765efcc76cSJerome Glisse } 4775efcc76cSJerome Glisse } 4785efcc76cSJerome Glisse 479ebbe1cb9SAlex Deucher memset(&args, 0, sizeof(args)); 480ba032a58SAlex Deucher 481a572eaa3SAlex Deucher if (ASIC_IS_DCE5(rdev)) { 4824589433cSCédric Cano args.v3.usSpreadSpectrumAmountFrac = cpu_to_le16(0); 4838e8e523dSAlex Deucher args.v3.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 484a572eaa3SAlex Deucher switch (pll_id) { 485a572eaa3SAlex Deucher case ATOM_PPLL1: 486a572eaa3SAlex Deucher args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL; 487a572eaa3SAlex Deucher break; 488a572eaa3SAlex Deucher case ATOM_PPLL2: 489a572eaa3SAlex Deucher args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL; 490a572eaa3SAlex Deucher break; 491a572eaa3SAlex Deucher case ATOM_DCPLL: 492a572eaa3SAlex Deucher args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL; 493a572eaa3SAlex Deucher break; 494a572eaa3SAlex Deucher case ATOM_PPLL_INVALID: 495a572eaa3SAlex Deucher return; 496a572eaa3SAlex Deucher } 497f312f093SAlex Deucher args.v3.usSpreadSpectrumAmount = cpu_to_le16(ss->amount); 498f312f093SAlex Deucher args.v3.usSpreadSpectrumStep = cpu_to_le16(ss->step); 499d0ae3e89SAlex Deucher args.v3.ucEnable = enable; 500a572eaa3SAlex Deucher } else if (ASIC_IS_DCE4(rdev)) { 501ba032a58SAlex Deucher args.v2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); 5028e8e523dSAlex Deucher args.v2.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 503ba032a58SAlex Deucher switch (pll_id) { 504ba032a58SAlex Deucher case ATOM_PPLL1: 505ba032a58SAlex Deucher args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P1PLL; 506ba032a58SAlex Deucher break; 507ba032a58SAlex Deucher case ATOM_PPLL2: 508ba032a58SAlex Deucher args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P2PLL; 509ba032a58SAlex Deucher break; 510ba032a58SAlex Deucher case ATOM_DCPLL: 511ba032a58SAlex Deucher args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_DCPLL; 512ba032a58SAlex Deucher break; 513ba032a58SAlex Deucher case ATOM_PPLL_INVALID: 514ba032a58SAlex Deucher return; 515ba032a58SAlex Deucher } 516f312f093SAlex Deucher args.v2.usSpreadSpectrumAmount = cpu_to_le16(ss->amount); 517f312f093SAlex Deucher args.v2.usSpreadSpectrumStep = cpu_to_le16(ss->step); 518ba032a58SAlex Deucher args.v2.ucEnable = enable; 519ba032a58SAlex Deucher } else if (ASIC_IS_DCE3(rdev)) { 520ba032a58SAlex Deucher args.v1.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); 5218e8e523dSAlex Deucher args.v1.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 522ba032a58SAlex Deucher args.v1.ucSpreadSpectrumStep = ss->step; 523ba032a58SAlex Deucher args.v1.ucSpreadSpectrumDelay = ss->delay; 524ba032a58SAlex Deucher args.v1.ucSpreadSpectrumRange = ss->range; 525ba032a58SAlex Deucher args.v1.ucPpll = pll_id; 526ba032a58SAlex Deucher args.v1.ucEnable = enable; 527ba032a58SAlex Deucher } else if (ASIC_IS_AVIVO(rdev)) { 5288e8e523dSAlex Deucher if ((enable == ATOM_DISABLE) || (ss->percentage == 0) || 5298e8e523dSAlex Deucher (ss->type & ATOM_EXTERNAL_SS_MASK)) { 5303fa47d9eSAlex Deucher atombios_disable_ss(rdev, pll_id); 531ba032a58SAlex Deucher return; 532ba032a58SAlex Deucher } 533ba032a58SAlex Deucher args.lvds_ss_2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); 5348e8e523dSAlex Deucher args.lvds_ss_2.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 535ba032a58SAlex Deucher args.lvds_ss_2.ucSpreadSpectrumStep = ss->step; 536ba032a58SAlex Deucher args.lvds_ss_2.ucSpreadSpectrumDelay = ss->delay; 537ba032a58SAlex Deucher args.lvds_ss_2.ucSpreadSpectrumRange = ss->range; 538ba032a58SAlex Deucher args.lvds_ss_2.ucEnable = enable; 539ebbe1cb9SAlex Deucher } else { 540c4756baaSAlex Deucher if (enable == ATOM_DISABLE) { 5413fa47d9eSAlex Deucher atombios_disable_ss(rdev, pll_id); 542ba032a58SAlex Deucher return; 543ba032a58SAlex Deucher } 544ba032a58SAlex Deucher args.lvds_ss.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); 5458e8e523dSAlex Deucher args.lvds_ss.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 546ba032a58SAlex Deucher args.lvds_ss.ucSpreadSpectrumStepSize_Delay = (ss->step & 3) << 2; 547ba032a58SAlex Deucher args.lvds_ss.ucSpreadSpectrumStepSize_Delay |= (ss->delay & 7) << 4; 548ba032a58SAlex Deucher args.lvds_ss.ucEnable = enable; 549ebbe1cb9SAlex Deucher } 55026b9fc3aSAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 551ebbe1cb9SAlex Deucher } 552ebbe1cb9SAlex Deucher 5534eaeca33SAlex Deucher union adjust_pixel_clock { 5544eaeca33SAlex Deucher ADJUST_DISPLAY_PLL_PS_ALLOCATION v1; 555bcc1c2a1SAlex Deucher ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 v3; 5564eaeca33SAlex Deucher }; 5574eaeca33SAlex Deucher 5584eaeca33SAlex Deucher static u32 atombios_adjust_pll(struct drm_crtc *crtc, 55919eca43eSAlex Deucher struct drm_display_mode *mode) 560771fe6b9SJerome Glisse { 56119eca43eSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 562771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 563771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 5645df3196bSAlex Deucher struct drm_encoder *encoder = radeon_crtc->encoder; 5655df3196bSAlex Deucher struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 5665df3196bSAlex Deucher struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); 5674eaeca33SAlex Deucher u32 adjusted_clock = mode->clock; 5685df3196bSAlex Deucher int encoder_mode = atombios_get_encoder_mode(encoder); 569fbee67a6SAlex Deucher u32 dp_clock = mode->clock; 570f71d9ebdSAlex Deucher u32 clock = mode->clock; 5717d5a33b0SAlex Deucher int bpc = radeon_crtc->bpc; 5725df3196bSAlex Deucher bool is_duallink = radeon_dig_monitor_is_duallink(encoder, mode->clock); 573fc10332bSAlex Deucher 5744eaeca33SAlex Deucher /* reset the pll flags */ 57519eca43eSAlex Deucher radeon_crtc->pll_flags = 0; 576771fe6b9SJerome Glisse 577771fe6b9SJerome Glisse if (ASIC_IS_AVIVO(rdev)) { 578eb1300bcSAlex Deucher if ((rdev->family == CHIP_RS600) || 579eb1300bcSAlex Deucher (rdev->family == CHIP_RS690) || 580eb1300bcSAlex Deucher (rdev->family == CHIP_RS740)) 58119eca43eSAlex Deucher radeon_crtc->pll_flags |= (/*RADEON_PLL_USE_FRAC_FB_DIV |*/ 582eb1300bcSAlex Deucher RADEON_PLL_PREFER_CLOSEST_LOWER); 5835480f727SDave Airlie 5845480f727SDave Airlie if (ASIC_IS_DCE32(rdev) && mode->clock > 200000) /* range limits??? */ 58519eca43eSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; 5865480f727SDave Airlie else 58719eca43eSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; 5889bb09fa1SAlex Deucher 5895785e53fSAlex Deucher if (rdev->family < CHIP_RV770) 59019eca43eSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP; 59137d4174dSAlex Deucher /* use frac fb div on APUs */ 592c7d2f227SAlex Deucher if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev) || ASIC_IS_DCE8(rdev)) 59319eca43eSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; 59441167828SAlex Deucher /* use frac fb div on RS780/RS880 */ 5959ef8537eSChristian König if (((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880)) 5969ef8537eSChristian König && !radeon_crtc->ss_enabled) 59741167828SAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; 598a02dc74bSAlex Deucher if (ASIC_IS_DCE32(rdev) && mode->clock > 165000) 599a02dc74bSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; 6005480f727SDave Airlie } else { 60119eca43eSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_LEGACY; 602771fe6b9SJerome Glisse 6035480f727SDave Airlie if (mode->clock > 200000) /* range limits??? */ 60419eca43eSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; 6055480f727SDave Airlie else 60619eca43eSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; 6075480f727SDave Airlie } 6085480f727SDave Airlie 609eac4dff6SAlex Deucher if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) || 6101d33e1fcSAlex Deucher (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)) { 611fbee67a6SAlex Deucher if (connector) { 612fbee67a6SAlex Deucher struct radeon_connector *radeon_connector = to_radeon_connector(connector); 613fbee67a6SAlex Deucher struct radeon_connector_atom_dig *dig_connector = 614fbee67a6SAlex Deucher radeon_connector->con_priv; 615fbee67a6SAlex Deucher 616fbee67a6SAlex Deucher dp_clock = dig_connector->dp_clock; 617fbee67a6SAlex Deucher } 618fbee67a6SAlex Deucher } 6195b40ddf8SAlex Deucher 6209843ead0SDave Airlie if (radeon_encoder->is_mst_encoder) { 6219843ead0SDave Airlie struct radeon_encoder_mst *mst_enc = radeon_encoder->enc_priv; 6229843ead0SDave Airlie struct radeon_connector_atom_dig *dig_connector = mst_enc->connector->con_priv; 6239843ead0SDave Airlie 6249843ead0SDave Airlie dp_clock = dig_connector->dp_clock; 6259843ead0SDave Airlie } 6269843ead0SDave Airlie 627ba032a58SAlex Deucher /* use recommended ref_div for ss */ 628ba032a58SAlex Deucher if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 62919eca43eSAlex Deucher if (radeon_crtc->ss_enabled) { 63019eca43eSAlex Deucher if (radeon_crtc->ss.refdiv) { 63119eca43eSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV; 63219eca43eSAlex Deucher radeon_crtc->pll_reference_div = radeon_crtc->ss.refdiv; 633ae5b80d2SChristian König if (ASIC_IS_AVIVO(rdev) && 634ae5b80d2SChristian König rdev->family != CHIP_RS780 && 635ae5b80d2SChristian König rdev->family != CHIP_RS880) 63619eca43eSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; 637ba032a58SAlex Deucher } 638ba032a58SAlex Deucher } 639ba032a58SAlex Deucher } 6405b40ddf8SAlex Deucher 6414eaeca33SAlex Deucher if (ASIC_IS_AVIVO(rdev)) { 6424eaeca33SAlex Deucher /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ 6434eaeca33SAlex Deucher if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1) 6444eaeca33SAlex Deucher adjusted_clock = mode->clock * 2; 64548dfaaebSAlex Deucher if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 64619eca43eSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_PREFER_CLOSEST_LOWER; 647619efb10SAlex Deucher if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) 64819eca43eSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_IS_LCD; 6494eaeca33SAlex Deucher } else { 6504eaeca33SAlex Deucher if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) 65119eca43eSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_NO_ODD_POST_DIV; 6524eaeca33SAlex Deucher if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) 65319eca43eSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV; 654771fe6b9SJerome Glisse } 655771fe6b9SJerome Glisse 656f71d9ebdSAlex Deucher /* adjust pll for deep color modes */ 657f71d9ebdSAlex Deucher if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { 658f71d9ebdSAlex Deucher switch (bpc) { 659f71d9ebdSAlex Deucher case 8: 660f71d9ebdSAlex Deucher default: 661f71d9ebdSAlex Deucher break; 662f71d9ebdSAlex Deucher case 10: 663f71d9ebdSAlex Deucher clock = (clock * 5) / 4; 664f71d9ebdSAlex Deucher break; 665f71d9ebdSAlex Deucher case 12: 666f71d9ebdSAlex Deucher clock = (clock * 3) / 2; 667f71d9ebdSAlex Deucher break; 668f71d9ebdSAlex Deucher case 16: 669f71d9ebdSAlex Deucher clock = clock * 2; 670f71d9ebdSAlex Deucher break; 671f71d9ebdSAlex Deucher } 672f71d9ebdSAlex Deucher } 673f71d9ebdSAlex Deucher 6742606c886SAlex Deucher /* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock 6752606c886SAlex Deucher * accordingly based on the encoder/transmitter to work around 6762606c886SAlex Deucher * special hw requirements. 6772606c886SAlex Deucher */ 6782606c886SAlex Deucher if (ASIC_IS_DCE3(rdev)) { 6794eaeca33SAlex Deucher union adjust_pixel_clock args; 6804eaeca33SAlex Deucher u8 frev, crev; 6814eaeca33SAlex Deucher int index; 6822606c886SAlex Deucher 6832606c886SAlex Deucher index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll); 684a084e6eeSAlex Deucher if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 685a084e6eeSAlex Deucher &crev)) 686a084e6eeSAlex Deucher return adjusted_clock; 6874eaeca33SAlex Deucher 6884eaeca33SAlex Deucher memset(&args, 0, sizeof(args)); 6894eaeca33SAlex Deucher 6904eaeca33SAlex Deucher switch (frev) { 6914eaeca33SAlex Deucher case 1: 6924eaeca33SAlex Deucher switch (crev) { 6934eaeca33SAlex Deucher case 1: 6944eaeca33SAlex Deucher case 2: 695f71d9ebdSAlex Deucher args.v1.usPixelClock = cpu_to_le16(clock / 10); 6964eaeca33SAlex Deucher args.v1.ucTransmitterID = radeon_encoder->encoder_id; 697bcc1c2a1SAlex Deucher args.v1.ucEncodeMode = encoder_mode; 69819eca43eSAlex Deucher if (radeon_crtc->ss_enabled && radeon_crtc->ss.percentage) 699ba032a58SAlex Deucher args.v1.ucConfig |= 700ba032a58SAlex Deucher ADJUST_DISPLAY_CONFIG_SS_ENABLE; 7014eaeca33SAlex Deucher 7022606c886SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, 7034eaeca33SAlex Deucher index, (uint32_t *)&args); 7044eaeca33SAlex Deucher adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10; 7054eaeca33SAlex Deucher break; 706bcc1c2a1SAlex Deucher case 3: 707f71d9ebdSAlex Deucher args.v3.sInput.usPixelClock = cpu_to_le16(clock / 10); 708bcc1c2a1SAlex Deucher args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id; 709bcc1c2a1SAlex Deucher args.v3.sInput.ucEncodeMode = encoder_mode; 710bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig = 0; 71119eca43eSAlex Deucher if (radeon_crtc->ss_enabled && radeon_crtc->ss.percentage) 712ba032a58SAlex Deucher args.v3.sInput.ucDispPllConfig |= 713ba032a58SAlex Deucher DISPPLL_CONFIG_SS_ENABLE; 714996d5c59SAlex Deucher if (ENCODER_MODE_IS_DP(encoder_mode)) { 715bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 716bcc1c2a1SAlex Deucher DISPPLL_CONFIG_COHERENT_MODE; 717fbee67a6SAlex Deucher /* 16200 or 27000 */ 718fbee67a6SAlex Deucher args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); 719b4f15f80SAlex Deucher } else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { 720b4f15f80SAlex Deucher struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 721bcc1c2a1SAlex Deucher if (dig->coherent_mode) 722bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 723bcc1c2a1SAlex Deucher DISPPLL_CONFIG_COHERENT_MODE; 7249aa59993SAlex Deucher if (is_duallink) 725bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 726bcc1c2a1SAlex Deucher DISPPLL_CONFIG_DUAL_LINK; 727bcc1c2a1SAlex Deucher } 7281d33e1fcSAlex Deucher if (radeon_encoder_get_dp_bridge_encoder_id(encoder) != 7291d33e1fcSAlex Deucher ENCODER_OBJECT_ID_NONE) 7301d33e1fcSAlex Deucher args.v3.sInput.ucExtTransmitterID = 7311d33e1fcSAlex Deucher radeon_encoder_get_dp_bridge_encoder_id(encoder); 7321d33e1fcSAlex Deucher else 733cc9f67a0SAlex Deucher args.v3.sInput.ucExtTransmitterID = 0; 734cc9f67a0SAlex Deucher 735bcc1c2a1SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, 736bcc1c2a1SAlex Deucher index, (uint32_t *)&args); 737bcc1c2a1SAlex Deucher adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10; 738bcc1c2a1SAlex Deucher if (args.v3.sOutput.ucRefDiv) { 73919eca43eSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; 74019eca43eSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV; 74119eca43eSAlex Deucher radeon_crtc->pll_reference_div = args.v3.sOutput.ucRefDiv; 742bcc1c2a1SAlex Deucher } 743bcc1c2a1SAlex Deucher if (args.v3.sOutput.ucPostDiv) { 74419eca43eSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; 74519eca43eSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_USE_POST_DIV; 74619eca43eSAlex Deucher radeon_crtc->pll_post_div = args.v3.sOutput.ucPostDiv; 747bcc1c2a1SAlex Deucher } 748bcc1c2a1SAlex Deucher break; 7494eaeca33SAlex Deucher default: 7504eaeca33SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 7514eaeca33SAlex Deucher return adjusted_clock; 752d56ef9c8SAlex Deucher } 7534eaeca33SAlex Deucher break; 7544eaeca33SAlex Deucher default: 7554eaeca33SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 7564eaeca33SAlex Deucher return adjusted_clock; 7574eaeca33SAlex Deucher } 7584eaeca33SAlex Deucher } 7594eaeca33SAlex Deucher return adjusted_clock; 7604eaeca33SAlex Deucher } 7614eaeca33SAlex Deucher 7624eaeca33SAlex Deucher union set_pixel_clock { 7634eaeca33SAlex Deucher SET_PIXEL_CLOCK_PS_ALLOCATION base; 7644eaeca33SAlex Deucher PIXEL_CLOCK_PARAMETERS v1; 7654eaeca33SAlex Deucher PIXEL_CLOCK_PARAMETERS_V2 v2; 7664eaeca33SAlex Deucher PIXEL_CLOCK_PARAMETERS_V3 v3; 767bcc1c2a1SAlex Deucher PIXEL_CLOCK_PARAMETERS_V5 v5; 768f82b3ddcSAlex Deucher PIXEL_CLOCK_PARAMETERS_V6 v6; 7694eaeca33SAlex Deucher }; 7704eaeca33SAlex Deucher 771f82b3ddcSAlex Deucher /* on DCE5, make sure the voltage is high enough to support the 772f82b3ddcSAlex Deucher * required disp clk. 773f82b3ddcSAlex Deucher */ 774f3f1f03eSAlex Deucher static void atombios_crtc_set_disp_eng_pll(struct radeon_device *rdev, 775f82b3ddcSAlex Deucher u32 dispclk) 776bcc1c2a1SAlex Deucher { 777bcc1c2a1SAlex Deucher u8 frev, crev; 778bcc1c2a1SAlex Deucher int index; 779bcc1c2a1SAlex Deucher union set_pixel_clock args; 780bcc1c2a1SAlex Deucher 781bcc1c2a1SAlex Deucher memset(&args, 0, sizeof(args)); 782bcc1c2a1SAlex Deucher 783bcc1c2a1SAlex Deucher index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); 784a084e6eeSAlex Deucher if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 785a084e6eeSAlex Deucher &crev)) 786a084e6eeSAlex Deucher return; 787bcc1c2a1SAlex Deucher 788bcc1c2a1SAlex Deucher switch (frev) { 789bcc1c2a1SAlex Deucher case 1: 790bcc1c2a1SAlex Deucher switch (crev) { 791bcc1c2a1SAlex Deucher case 5: 792bcc1c2a1SAlex Deucher /* if the default dcpll clock is specified, 793bcc1c2a1SAlex Deucher * SetPixelClock provides the dividers 794bcc1c2a1SAlex Deucher */ 795bcc1c2a1SAlex Deucher args.v5.ucCRTC = ATOM_CRTC_INVALID; 7964589433cSCédric Cano args.v5.usPixelClock = cpu_to_le16(dispclk); 797bcc1c2a1SAlex Deucher args.v5.ucPpll = ATOM_DCPLL; 798bcc1c2a1SAlex Deucher break; 799f82b3ddcSAlex Deucher case 6: 800f82b3ddcSAlex Deucher /* if the default dcpll clock is specified, 801f82b3ddcSAlex Deucher * SetPixelClock provides the dividers 802f82b3ddcSAlex Deucher */ 803265aa6c8SAlex Deucher args.v6.ulDispEngClkFreq = cpu_to_le32(dispclk); 8048542c12bSAlex Deucher if (ASIC_IS_DCE61(rdev) || ASIC_IS_DCE8(rdev)) 805729b95efSAlex Deucher args.v6.ucPpll = ATOM_EXT_PLL1; 806729b95efSAlex Deucher else if (ASIC_IS_DCE6(rdev)) 807f3f1f03eSAlex Deucher args.v6.ucPpll = ATOM_PPLL0; 808f3f1f03eSAlex Deucher else 809f82b3ddcSAlex Deucher args.v6.ucPpll = ATOM_DCPLL; 810f82b3ddcSAlex Deucher break; 811bcc1c2a1SAlex Deucher default: 812bcc1c2a1SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 813bcc1c2a1SAlex Deucher return; 814bcc1c2a1SAlex Deucher } 815bcc1c2a1SAlex Deucher break; 816bcc1c2a1SAlex Deucher default: 817bcc1c2a1SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 818bcc1c2a1SAlex Deucher return; 819bcc1c2a1SAlex Deucher } 820bcc1c2a1SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 821bcc1c2a1SAlex Deucher } 822bcc1c2a1SAlex Deucher 82337f9003bSAlex Deucher static void atombios_crtc_program_pll(struct drm_crtc *crtc, 824f1bece7fSBenjamin Herrenschmidt u32 crtc_id, 82537f9003bSAlex Deucher int pll_id, 82637f9003bSAlex Deucher u32 encoder_mode, 82737f9003bSAlex Deucher u32 encoder_id, 82837f9003bSAlex Deucher u32 clock, 82937f9003bSAlex Deucher u32 ref_div, 83037f9003bSAlex Deucher u32 fb_div, 83137f9003bSAlex Deucher u32 frac_fb_div, 832df271becSAlex Deucher u32 post_div, 8338e8e523dSAlex Deucher int bpc, 8348e8e523dSAlex Deucher bool ss_enabled, 8358e8e523dSAlex Deucher struct radeon_atom_ss *ss) 83637f9003bSAlex Deucher { 83737f9003bSAlex Deucher struct drm_device *dev = crtc->dev; 83837f9003bSAlex Deucher struct radeon_device *rdev = dev->dev_private; 83937f9003bSAlex Deucher u8 frev, crev; 84037f9003bSAlex Deucher int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); 84137f9003bSAlex Deucher union set_pixel_clock args; 84237f9003bSAlex Deucher 84337f9003bSAlex Deucher memset(&args, 0, sizeof(args)); 84437f9003bSAlex Deucher 84537f9003bSAlex Deucher if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 84637f9003bSAlex Deucher &crev)) 84737f9003bSAlex Deucher return; 84837f9003bSAlex Deucher 84937f9003bSAlex Deucher switch (frev) { 85037f9003bSAlex Deucher case 1: 85137f9003bSAlex Deucher switch (crev) { 85237f9003bSAlex Deucher case 1: 85337f9003bSAlex Deucher if (clock == ATOM_DISABLE) 85437f9003bSAlex Deucher return; 85537f9003bSAlex Deucher args.v1.usPixelClock = cpu_to_le16(clock / 10); 85637f9003bSAlex Deucher args.v1.usRefDiv = cpu_to_le16(ref_div); 85737f9003bSAlex Deucher args.v1.usFbDiv = cpu_to_le16(fb_div); 85837f9003bSAlex Deucher args.v1.ucFracFbDiv = frac_fb_div; 85937f9003bSAlex Deucher args.v1.ucPostDiv = post_div; 86037f9003bSAlex Deucher args.v1.ucPpll = pll_id; 86137f9003bSAlex Deucher args.v1.ucCRTC = crtc_id; 86237f9003bSAlex Deucher args.v1.ucRefDivSrc = 1; 86337f9003bSAlex Deucher break; 86437f9003bSAlex Deucher case 2: 86537f9003bSAlex Deucher args.v2.usPixelClock = cpu_to_le16(clock / 10); 86637f9003bSAlex Deucher args.v2.usRefDiv = cpu_to_le16(ref_div); 86737f9003bSAlex Deucher args.v2.usFbDiv = cpu_to_le16(fb_div); 86837f9003bSAlex Deucher args.v2.ucFracFbDiv = frac_fb_div; 86937f9003bSAlex Deucher args.v2.ucPostDiv = post_div; 87037f9003bSAlex Deucher args.v2.ucPpll = pll_id; 87137f9003bSAlex Deucher args.v2.ucCRTC = crtc_id; 87237f9003bSAlex Deucher args.v2.ucRefDivSrc = 1; 87337f9003bSAlex Deucher break; 87437f9003bSAlex Deucher case 3: 87537f9003bSAlex Deucher args.v3.usPixelClock = cpu_to_le16(clock / 10); 87637f9003bSAlex Deucher args.v3.usRefDiv = cpu_to_le16(ref_div); 87737f9003bSAlex Deucher args.v3.usFbDiv = cpu_to_le16(fb_div); 87837f9003bSAlex Deucher args.v3.ucFracFbDiv = frac_fb_div; 87937f9003bSAlex Deucher args.v3.ucPostDiv = post_div; 88037f9003bSAlex Deucher args.v3.ucPpll = pll_id; 881e729586eSAlex Deucher if (crtc_id == ATOM_CRTC2) 882e729586eSAlex Deucher args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC2; 883e729586eSAlex Deucher else 884e729586eSAlex Deucher args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC1; 8856f15c506SAlex Deucher if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) 8866f15c506SAlex Deucher args.v3.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC; 88737f9003bSAlex Deucher args.v3.ucTransmitterId = encoder_id; 88837f9003bSAlex Deucher args.v3.ucEncoderMode = encoder_mode; 88937f9003bSAlex Deucher break; 89037f9003bSAlex Deucher case 5: 89137f9003bSAlex Deucher args.v5.ucCRTC = crtc_id; 89237f9003bSAlex Deucher args.v5.usPixelClock = cpu_to_le16(clock / 10); 89337f9003bSAlex Deucher args.v5.ucRefDiv = ref_div; 89437f9003bSAlex Deucher args.v5.usFbDiv = cpu_to_le16(fb_div); 89537f9003bSAlex Deucher args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); 89637f9003bSAlex Deucher args.v5.ucPostDiv = post_div; 89737f9003bSAlex Deucher args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */ 8988e8e523dSAlex Deucher if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) 8998e8e523dSAlex Deucher args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_REF_DIV_SRC; 9007d5ab300SAlex Deucher if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { 901df271becSAlex Deucher switch (bpc) { 902df271becSAlex Deucher case 8: 903df271becSAlex Deucher default: 904df271becSAlex Deucher args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP; 905df271becSAlex Deucher break; 906df271becSAlex Deucher case 10: 907f71d9ebdSAlex Deucher /* yes this is correct, the atom define is wrong */ 908f71d9ebdSAlex Deucher args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_32BPP; 909f71d9ebdSAlex Deucher break; 910f71d9ebdSAlex Deucher case 12: 911f71d9ebdSAlex Deucher /* yes this is correct, the atom define is wrong */ 912df271becSAlex Deucher args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP; 913df271becSAlex Deucher break; 914df271becSAlex Deucher } 9157d5ab300SAlex Deucher } 91637f9003bSAlex Deucher args.v5.ucTransmitterID = encoder_id; 91737f9003bSAlex Deucher args.v5.ucEncoderMode = encoder_mode; 91837f9003bSAlex Deucher args.v5.ucPpll = pll_id; 91937f9003bSAlex Deucher break; 920f82b3ddcSAlex Deucher case 6: 921f1bece7fSBenjamin Herrenschmidt args.v6.ulDispEngClkFreq = cpu_to_le32(crtc_id << 24 | clock / 10); 922f82b3ddcSAlex Deucher args.v6.ucRefDiv = ref_div; 923f82b3ddcSAlex Deucher args.v6.usFbDiv = cpu_to_le16(fb_div); 924f82b3ddcSAlex Deucher args.v6.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); 925f82b3ddcSAlex Deucher args.v6.ucPostDiv = post_div; 926f82b3ddcSAlex Deucher args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */ 9278e8e523dSAlex Deucher if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) 9288e8e523dSAlex Deucher args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_REF_DIV_SRC; 9297d5ab300SAlex Deucher if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { 930df271becSAlex Deucher switch (bpc) { 931df271becSAlex Deucher case 8: 932df271becSAlex Deucher default: 933df271becSAlex Deucher args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP; 934df271becSAlex Deucher break; 935df271becSAlex Deucher case 10: 936f71d9ebdSAlex Deucher args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP_V6; 937df271becSAlex Deucher break; 938df271becSAlex Deucher case 12: 939f71d9ebdSAlex Deucher args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP_V6; 940df271becSAlex Deucher break; 941df271becSAlex Deucher case 16: 942df271becSAlex Deucher args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP; 943df271becSAlex Deucher break; 944df271becSAlex Deucher } 9457d5ab300SAlex Deucher } 946f82b3ddcSAlex Deucher args.v6.ucTransmitterID = encoder_id; 947f82b3ddcSAlex Deucher args.v6.ucEncoderMode = encoder_mode; 948f82b3ddcSAlex Deucher args.v6.ucPpll = pll_id; 949f82b3ddcSAlex Deucher break; 95037f9003bSAlex Deucher default: 95137f9003bSAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 95237f9003bSAlex Deucher return; 95337f9003bSAlex Deucher } 95437f9003bSAlex Deucher break; 95537f9003bSAlex Deucher default: 95637f9003bSAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 95737f9003bSAlex Deucher return; 95837f9003bSAlex Deucher } 95937f9003bSAlex Deucher 96037f9003bSAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 96137f9003bSAlex Deucher } 96237f9003bSAlex Deucher 96319eca43eSAlex Deucher static bool atombios_crtc_prepare_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) 96419eca43eSAlex Deucher { 96519eca43eSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 96619eca43eSAlex Deucher struct drm_device *dev = crtc->dev; 96719eca43eSAlex Deucher struct radeon_device *rdev = dev->dev_private; 9685df3196bSAlex Deucher struct radeon_encoder *radeon_encoder = 9695df3196bSAlex Deucher to_radeon_encoder(radeon_crtc->encoder); 9705df3196bSAlex Deucher int encoder_mode = atombios_get_encoder_mode(radeon_crtc->encoder); 97119eca43eSAlex Deucher 97219eca43eSAlex Deucher radeon_crtc->bpc = 8; 97319eca43eSAlex Deucher radeon_crtc->ss_enabled = false; 97419eca43eSAlex Deucher 9759843ead0SDave Airlie if (radeon_encoder->is_mst_encoder) { 9769843ead0SDave Airlie radeon_dp_mst_prepare_pll(crtc, mode); 9779843ead0SDave Airlie } else if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) || 9785df3196bSAlex Deucher (radeon_encoder_get_dp_bridge_encoder_id(radeon_crtc->encoder) != ENCODER_OBJECT_ID_NONE)) { 97919eca43eSAlex Deucher struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 98019eca43eSAlex Deucher struct drm_connector *connector = 9815df3196bSAlex Deucher radeon_get_connector_for_encoder(radeon_crtc->encoder); 98219eca43eSAlex Deucher struct radeon_connector *radeon_connector = 98319eca43eSAlex Deucher to_radeon_connector(connector); 98419eca43eSAlex Deucher struct radeon_connector_atom_dig *dig_connector = 98519eca43eSAlex Deucher radeon_connector->con_priv; 98619eca43eSAlex Deucher int dp_clock; 987ea292861SMario Kleiner 988ea292861SMario Kleiner /* Assign mode clock for hdmi deep color max clock limit check */ 989ea292861SMario Kleiner radeon_connector->pixelclock_for_modeset = mode->clock; 99019eca43eSAlex Deucher radeon_crtc->bpc = radeon_get_monitor_bpc(connector); 99119eca43eSAlex Deucher 99219eca43eSAlex Deucher switch (encoder_mode) { 99319eca43eSAlex Deucher case ATOM_ENCODER_MODE_DP_MST: 99419eca43eSAlex Deucher case ATOM_ENCODER_MODE_DP: 99519eca43eSAlex Deucher /* DP/eDP */ 99619eca43eSAlex Deucher dp_clock = dig_connector->dp_clock / 10; 99719eca43eSAlex Deucher if (ASIC_IS_DCE4(rdev)) 99819eca43eSAlex Deucher radeon_crtc->ss_enabled = 99919eca43eSAlex Deucher radeon_atombios_get_asic_ss_info(rdev, &radeon_crtc->ss, 100019eca43eSAlex Deucher ASIC_INTERNAL_SS_ON_DP, 100119eca43eSAlex Deucher dp_clock); 100219eca43eSAlex Deucher else { 100319eca43eSAlex Deucher if (dp_clock == 16200) { 100419eca43eSAlex Deucher radeon_crtc->ss_enabled = 100519eca43eSAlex Deucher radeon_atombios_get_ppll_ss_info(rdev, 100619eca43eSAlex Deucher &radeon_crtc->ss, 100719eca43eSAlex Deucher ATOM_DP_SS_ID2); 100819eca43eSAlex Deucher if (!radeon_crtc->ss_enabled) 100919eca43eSAlex Deucher radeon_crtc->ss_enabled = 101019eca43eSAlex Deucher radeon_atombios_get_ppll_ss_info(rdev, 101119eca43eSAlex Deucher &radeon_crtc->ss, 101219eca43eSAlex Deucher ATOM_DP_SS_ID1); 1013d8e24525SAlex Deucher } else { 101419eca43eSAlex Deucher radeon_crtc->ss_enabled = 101519eca43eSAlex Deucher radeon_atombios_get_ppll_ss_info(rdev, 101619eca43eSAlex Deucher &radeon_crtc->ss, 101719eca43eSAlex Deucher ATOM_DP_SS_ID1); 101819eca43eSAlex Deucher } 1019d8e24525SAlex Deucher /* disable spread spectrum on DCE3 DP */ 1020d8e24525SAlex Deucher radeon_crtc->ss_enabled = false; 1021d8e24525SAlex Deucher } 102219eca43eSAlex Deucher break; 102319eca43eSAlex Deucher case ATOM_ENCODER_MODE_LVDS: 102419eca43eSAlex Deucher if (ASIC_IS_DCE4(rdev)) 102519eca43eSAlex Deucher radeon_crtc->ss_enabled = 102619eca43eSAlex Deucher radeon_atombios_get_asic_ss_info(rdev, 102719eca43eSAlex Deucher &radeon_crtc->ss, 102819eca43eSAlex Deucher dig->lcd_ss_id, 102919eca43eSAlex Deucher mode->clock / 10); 103019eca43eSAlex Deucher else 103119eca43eSAlex Deucher radeon_crtc->ss_enabled = 103219eca43eSAlex Deucher radeon_atombios_get_ppll_ss_info(rdev, 103319eca43eSAlex Deucher &radeon_crtc->ss, 103419eca43eSAlex Deucher dig->lcd_ss_id); 103519eca43eSAlex Deucher break; 103619eca43eSAlex Deucher case ATOM_ENCODER_MODE_DVI: 103719eca43eSAlex Deucher if (ASIC_IS_DCE4(rdev)) 103819eca43eSAlex Deucher radeon_crtc->ss_enabled = 103919eca43eSAlex Deucher radeon_atombios_get_asic_ss_info(rdev, 104019eca43eSAlex Deucher &radeon_crtc->ss, 104119eca43eSAlex Deucher ASIC_INTERNAL_SS_ON_TMDS, 104219eca43eSAlex Deucher mode->clock / 10); 104319eca43eSAlex Deucher break; 104419eca43eSAlex Deucher case ATOM_ENCODER_MODE_HDMI: 104519eca43eSAlex Deucher if (ASIC_IS_DCE4(rdev)) 104619eca43eSAlex Deucher radeon_crtc->ss_enabled = 104719eca43eSAlex Deucher radeon_atombios_get_asic_ss_info(rdev, 104819eca43eSAlex Deucher &radeon_crtc->ss, 104919eca43eSAlex Deucher ASIC_INTERNAL_SS_ON_HDMI, 105019eca43eSAlex Deucher mode->clock / 10); 105119eca43eSAlex Deucher break; 105219eca43eSAlex Deucher default: 105319eca43eSAlex Deucher break; 105419eca43eSAlex Deucher } 105519eca43eSAlex Deucher } 105619eca43eSAlex Deucher 105719eca43eSAlex Deucher /* adjust pixel clock as needed */ 105819eca43eSAlex Deucher radeon_crtc->adjusted_clock = atombios_adjust_pll(crtc, mode); 105919eca43eSAlex Deucher 106019eca43eSAlex Deucher return true; 106119eca43eSAlex Deucher } 106219eca43eSAlex Deucher 1063bcc1c2a1SAlex Deucher static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) 10644eaeca33SAlex Deucher { 10654eaeca33SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 10664eaeca33SAlex Deucher struct drm_device *dev = crtc->dev; 10674eaeca33SAlex Deucher struct radeon_device *rdev = dev->dev_private; 10685df3196bSAlex Deucher struct radeon_encoder *radeon_encoder = 10695df3196bSAlex Deucher to_radeon_encoder(radeon_crtc->encoder); 10704eaeca33SAlex Deucher u32 pll_clock = mode->clock; 1071f71d9ebdSAlex Deucher u32 clock = mode->clock; 10724eaeca33SAlex Deucher u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; 10734eaeca33SAlex Deucher struct radeon_pll *pll; 10745df3196bSAlex Deucher int encoder_mode = atombios_get_encoder_mode(radeon_crtc->encoder); 10754eaeca33SAlex Deucher 1076f71d9ebdSAlex Deucher /* pass the actual clock to atombios_crtc_program_pll for DCE5,6 for HDMI */ 10775c868229SMario Kleiner if (ASIC_IS_DCE5(rdev) && 1078f71d9ebdSAlex Deucher (encoder_mode == ATOM_ENCODER_MODE_HDMI) && 1079f71d9ebdSAlex Deucher (radeon_crtc->bpc > 8)) 1080f71d9ebdSAlex Deucher clock = radeon_crtc->adjusted_clock; 1081f71d9ebdSAlex Deucher 1082bcc1c2a1SAlex Deucher switch (radeon_crtc->pll_id) { 1083bcc1c2a1SAlex Deucher case ATOM_PPLL1: 10844eaeca33SAlex Deucher pll = &rdev->clock.p1pll; 1085bcc1c2a1SAlex Deucher break; 1086bcc1c2a1SAlex Deucher case ATOM_PPLL2: 10874eaeca33SAlex Deucher pll = &rdev->clock.p2pll; 1088bcc1c2a1SAlex Deucher break; 1089bcc1c2a1SAlex Deucher case ATOM_DCPLL: 1090bcc1c2a1SAlex Deucher case ATOM_PPLL_INVALID: 1091921d98b5SStefan Richter default: 1092bcc1c2a1SAlex Deucher pll = &rdev->clock.dcpll; 1093bcc1c2a1SAlex Deucher break; 1094bcc1c2a1SAlex Deucher } 10954eaeca33SAlex Deucher 109619eca43eSAlex Deucher /* update pll params */ 109719eca43eSAlex Deucher pll->flags = radeon_crtc->pll_flags; 109819eca43eSAlex Deucher pll->reference_div = radeon_crtc->pll_reference_div; 109919eca43eSAlex Deucher pll->post_div = radeon_crtc->pll_post_div; 11002606c886SAlex Deucher 110164146f8bSAlex Deucher if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 110264146f8bSAlex Deucher /* TV seems to prefer the legacy algo on some boards */ 110319eca43eSAlex Deucher radeon_compute_pll_legacy(pll, radeon_crtc->adjusted_clock, &pll_clock, 110419eca43eSAlex Deucher &fb_div, &frac_fb_div, &ref_div, &post_div); 110564146f8bSAlex Deucher else if (ASIC_IS_AVIVO(rdev)) 110619eca43eSAlex Deucher radeon_compute_pll_avivo(pll, radeon_crtc->adjusted_clock, &pll_clock, 110719eca43eSAlex Deucher &fb_div, &frac_fb_div, &ref_div, &post_div); 1108619efb10SAlex Deucher else 110919eca43eSAlex Deucher radeon_compute_pll_legacy(pll, radeon_crtc->adjusted_clock, &pll_clock, 111019eca43eSAlex Deucher &fb_div, &frac_fb_div, &ref_div, &post_div); 1111771fe6b9SJerome Glisse 111219eca43eSAlex Deucher atombios_crtc_program_ss(rdev, ATOM_DISABLE, radeon_crtc->pll_id, 111319eca43eSAlex Deucher radeon_crtc->crtc_id, &radeon_crtc->ss); 1114ba032a58SAlex Deucher 111537f9003bSAlex Deucher atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, 1116f71d9ebdSAlex Deucher encoder_mode, radeon_encoder->encoder_id, clock, 111719eca43eSAlex Deucher ref_div, fb_div, frac_fb_div, post_div, 111819eca43eSAlex Deucher radeon_crtc->bpc, radeon_crtc->ss_enabled, &radeon_crtc->ss); 1119771fe6b9SJerome Glisse 112019eca43eSAlex Deucher if (radeon_crtc->ss_enabled) { 1121ba032a58SAlex Deucher /* calculate ss amount and step size */ 1122ba032a58SAlex Deucher if (ASIC_IS_DCE4(rdev)) { 1123ba032a58SAlex Deucher u32 step_size; 112418f8f52bSAlex Deucher u32 amount = (((fb_div * 10) + frac_fb_div) * 112518f8f52bSAlex Deucher (u32)radeon_crtc->ss.percentage) / 112618f8f52bSAlex Deucher (100 * (u32)radeon_crtc->ss.percentage_divider); 112719eca43eSAlex Deucher radeon_crtc->ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK; 112819eca43eSAlex Deucher radeon_crtc->ss.amount |= ((amount - (amount / 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) & 1129ba032a58SAlex Deucher ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK; 113019eca43eSAlex Deucher if (radeon_crtc->ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD) 113118f8f52bSAlex Deucher step_size = (4 * amount * ref_div * ((u32)radeon_crtc->ss.rate * 2048)) / 1132ba032a58SAlex Deucher (125 * 25 * pll->reference_freq / 100); 1133ba032a58SAlex Deucher else 113418f8f52bSAlex Deucher step_size = (2 * amount * ref_div * ((u32)radeon_crtc->ss.rate * 2048)) / 1135ba032a58SAlex Deucher (125 * 25 * pll->reference_freq / 100); 113619eca43eSAlex Deucher radeon_crtc->ss.step = step_size; 1137ba032a58SAlex Deucher } 1138ba032a58SAlex Deucher 113919eca43eSAlex Deucher atombios_crtc_program_ss(rdev, ATOM_ENABLE, radeon_crtc->pll_id, 114019eca43eSAlex Deucher radeon_crtc->crtc_id, &radeon_crtc->ss); 1141ba032a58SAlex Deucher } 1142771fe6b9SJerome Glisse } 1143771fe6b9SJerome Glisse 1144c9417bddSAlex Deucher static int dce4_crtc_do_set_base(struct drm_crtc *crtc, 11454dd19b0dSChris Ball struct drm_framebuffer *fb, 11464dd19b0dSChris Ball int x, int y, int atomic) 1147bcc1c2a1SAlex Deucher { 1148bcc1c2a1SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1149bcc1c2a1SAlex Deucher struct drm_device *dev = crtc->dev; 1150bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 11514dd19b0dSChris Ball struct drm_framebuffer *target_fb; 1152bcc1c2a1SAlex Deucher struct drm_gem_object *obj; 1153bcc1c2a1SAlex Deucher struct radeon_bo *rbo; 1154bcc1c2a1SAlex Deucher uint64_t fb_location; 1155bcc1c2a1SAlex Deucher uint32_t fb_format, fb_pitch_pixels, tiling_flags; 1156285484e2SJerome Glisse unsigned bankw, bankh, mtaspect, tile_split; 1157fa6bee46SAlex Deucher u32 fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE); 1158adcfde51SAlex Deucher u32 tmp, viewport_w, viewport_h; 1159bcc1c2a1SAlex Deucher int r; 11604366f3b5SMario Kleiner bool bypass_lut = false; 1161b3c11ac2SEric Engestrom struct drm_format_name_buf format_name; 1162bcc1c2a1SAlex Deucher 1163bcc1c2a1SAlex Deucher /* no fb bound */ 1164f4510a27SMatt Roper if (!atomic && !crtc->primary->fb) { 1165d9fdaafbSDave Airlie DRM_DEBUG_KMS("No FB bound\n"); 1166bcc1c2a1SAlex Deucher return 0; 1167bcc1c2a1SAlex Deucher } 1168bcc1c2a1SAlex Deucher 11699a0f0c9dSDaniel Stone if (atomic) 11704dd19b0dSChris Ball target_fb = fb; 11719a0f0c9dSDaniel Stone else 1172f4510a27SMatt Roper target_fb = crtc->primary->fb; 1173bcc1c2a1SAlex Deucher 11744dd19b0dSChris Ball /* If atomic, assume fb object is pinned & idle & fenced and 11754dd19b0dSChris Ball * just update base pointers 11764dd19b0dSChris Ball */ 11779a0f0c9dSDaniel Stone obj = target_fb->obj[0]; 11787e4d15d9SDaniel Vetter rbo = gem_to_radeon_bo(obj); 1179bcc1c2a1SAlex Deucher r = radeon_bo_reserve(rbo, false); 1180bcc1c2a1SAlex Deucher if (unlikely(r != 0)) 1181bcc1c2a1SAlex Deucher return r; 11824dd19b0dSChris Ball 11834dd19b0dSChris Ball if (atomic) 11844dd19b0dSChris Ball fb_location = radeon_bo_gpu_offset(rbo); 11854dd19b0dSChris Ball else { 1186bcc1c2a1SAlex Deucher r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); 1187bcc1c2a1SAlex Deucher if (unlikely(r != 0)) { 1188bcc1c2a1SAlex Deucher radeon_bo_unreserve(rbo); 1189bcc1c2a1SAlex Deucher return -EINVAL; 1190bcc1c2a1SAlex Deucher } 11914dd19b0dSChris Ball } 11924dd19b0dSChris Ball 1193bcc1c2a1SAlex Deucher radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); 1194bcc1c2a1SAlex Deucher radeon_bo_unreserve(rbo); 1195bcc1c2a1SAlex Deucher 1196438b74a5SVille Syrjälä switch (target_fb->format->format) { 11978bae4276SFredrik Höglund case DRM_FORMAT_C8: 1198bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP) | 1199bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED)); 1200bcc1c2a1SAlex Deucher break; 12018bae4276SFredrik Höglund case DRM_FORMAT_XRGB4444: 12028bae4276SFredrik Höglund case DRM_FORMAT_ARGB4444: 12038bae4276SFredrik Höglund fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 12048bae4276SFredrik Höglund EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB4444)); 12058bae4276SFredrik Höglund #ifdef __BIG_ENDIAN 12068bae4276SFredrik Höglund fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16); 12078bae4276SFredrik Höglund #endif 12088bae4276SFredrik Höglund break; 12098bae4276SFredrik Höglund case DRM_FORMAT_XRGB1555: 12108bae4276SFredrik Höglund case DRM_FORMAT_ARGB1555: 1211bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 1212bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB1555)); 12138bae4276SFredrik Höglund #ifdef __BIG_ENDIAN 12148bae4276SFredrik Höglund fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16); 12158bae4276SFredrik Höglund #endif 1216bcc1c2a1SAlex Deucher break; 12178bae4276SFredrik Höglund case DRM_FORMAT_BGRX5551: 12188bae4276SFredrik Höglund case DRM_FORMAT_BGRA5551: 12198bae4276SFredrik Höglund fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 12208bae4276SFredrik Höglund EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_BGRA5551)); 12218bae4276SFredrik Höglund #ifdef __BIG_ENDIAN 12228bae4276SFredrik Höglund fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16); 12238bae4276SFredrik Höglund #endif 12248bae4276SFredrik Höglund break; 12258bae4276SFredrik Höglund case DRM_FORMAT_RGB565: 1226bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 1227bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565)); 1228fa6bee46SAlex Deucher #ifdef __BIG_ENDIAN 1229fa6bee46SAlex Deucher fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16); 1230fa6bee46SAlex Deucher #endif 1231bcc1c2a1SAlex Deucher break; 12328bae4276SFredrik Höglund case DRM_FORMAT_XRGB8888: 12338bae4276SFredrik Höglund case DRM_FORMAT_ARGB8888: 1234bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) | 1235bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888)); 1236fa6bee46SAlex Deucher #ifdef __BIG_ENDIAN 1237fa6bee46SAlex Deucher fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32); 1238fa6bee46SAlex Deucher #endif 1239bcc1c2a1SAlex Deucher break; 12408bae4276SFredrik Höglund case DRM_FORMAT_XRGB2101010: 12418bae4276SFredrik Höglund case DRM_FORMAT_ARGB2101010: 12428bae4276SFredrik Höglund fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) | 12438bae4276SFredrik Höglund EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB2101010)); 12448bae4276SFredrik Höglund #ifdef __BIG_ENDIAN 12458bae4276SFredrik Höglund fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32); 12468bae4276SFredrik Höglund #endif 12474366f3b5SMario Kleiner /* Greater 8 bpc fb needs to bypass hw-lut to retain precision */ 12484366f3b5SMario Kleiner bypass_lut = true; 12498bae4276SFredrik Höglund break; 12508bae4276SFredrik Höglund case DRM_FORMAT_BGRX1010102: 12518bae4276SFredrik Höglund case DRM_FORMAT_BGRA1010102: 12528bae4276SFredrik Höglund fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) | 12538bae4276SFredrik Höglund EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_BGRA1010102)); 12548bae4276SFredrik Höglund #ifdef __BIG_ENDIAN 12558bae4276SFredrik Höglund fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32); 12568bae4276SFredrik Höglund #endif 12574366f3b5SMario Kleiner /* Greater 8 bpc fb needs to bypass hw-lut to retain precision */ 12584366f3b5SMario Kleiner bypass_lut = true; 12598bae4276SFredrik Höglund break; 1260a69e40fdSMauro Rossi case DRM_FORMAT_XBGR8888: 1261a69e40fdSMauro Rossi case DRM_FORMAT_ABGR8888: 1262a69e40fdSMauro Rossi fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) | 1263a69e40fdSMauro Rossi EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888)); 1264a69e40fdSMauro Rossi fb_swap = (EVERGREEN_GRPH_RED_CROSSBAR(EVERGREEN_GRPH_RED_SEL_B) | 1265a69e40fdSMauro Rossi EVERGREEN_GRPH_BLUE_CROSSBAR(EVERGREEN_GRPH_BLUE_SEL_R)); 1266a69e40fdSMauro Rossi #ifdef __BIG_ENDIAN 1267a69e40fdSMauro Rossi fb_swap |= EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32); 1268a69e40fdSMauro Rossi #endif 1269a69e40fdSMauro Rossi break; 1270bcc1c2a1SAlex Deucher default: 1271b3c11ac2SEric Engestrom DRM_ERROR("Unsupported screen format %s\n", 1272438b74a5SVille Syrjälä drm_get_format_name(target_fb->format->format, &format_name)); 1273bcc1c2a1SAlex Deucher return -EINVAL; 1274bcc1c2a1SAlex Deucher } 1275bcc1c2a1SAlex Deucher 1276392e3722SAlex Deucher if (tiling_flags & RADEON_TILING_MACRO) { 1277e3ea94a6SMarek Olšák evergreen_tiling_fields(tiling_flags, &bankw, &bankh, &mtaspect, &tile_split); 1278e3ea94a6SMarek Olšák 1279e3ea94a6SMarek Olšák /* Set NUM_BANKS. */ 12806d8ea7deSAlex Deucher if (rdev->family >= CHIP_TAHITI) { 1281e9d14aebSMichel Dänzer unsigned index, num_banks; 1282e9d14aebSMichel Dänzer 1283e9d14aebSMichel Dänzer if (rdev->family >= CHIP_BONAIRE) { 1284e9d14aebSMichel Dänzer unsigned tileb, tile_split_bytes; 1285e3ea94a6SMarek Olšák 1286e3ea94a6SMarek Olšák /* Calculate the macrotile mode index. */ 1287e3ea94a6SMarek Olšák tile_split_bytes = 64 << tile_split; 1288272725c7SVille Syrjälä tileb = 8 * 8 * target_fb->format->cpp[0]; 1289e3ea94a6SMarek Olšák tileb = min(tile_split_bytes, tileb); 1290e3ea94a6SMarek Olšák 1291e9d14aebSMichel Dänzer for (index = 0; tileb > 64; index++) 1292e3ea94a6SMarek Olšák tileb >>= 1; 1293e3ea94a6SMarek Olšák 1294e3ea94a6SMarek Olšák if (index >= 16) { 1295e3ea94a6SMarek Olšák DRM_ERROR("Wrong screen bpp (%u) or tile split (%u)\n", 1296272725c7SVille Syrjälä target_fb->format->cpp[0] * 8, 1297272725c7SVille Syrjälä tile_split); 1298e3ea94a6SMarek Olšák return -EINVAL; 1299e3ea94a6SMarek Olšák } 1300e3ea94a6SMarek Olšák 1301e3ea94a6SMarek Olšák num_banks = (rdev->config.cik.macrotile_mode_array[index] >> 6) & 0x3; 1302e9d14aebSMichel Dänzer } else { 1303272725c7SVille Syrjälä switch (target_fb->format->cpp[0] * 8) { 1304e9d14aebSMichel Dänzer case 8: 1305e9d14aebSMichel Dänzer index = 10; 1306e9d14aebSMichel Dänzer break; 1307e9d14aebSMichel Dänzer case 16: 1308e9d14aebSMichel Dänzer index = SI_TILE_MODE_COLOR_2D_SCANOUT_16BPP; 1309e9d14aebSMichel Dänzer break; 1310e9d14aebSMichel Dänzer default: 1311e9d14aebSMichel Dänzer case 32: 1312e9d14aebSMichel Dänzer index = SI_TILE_MODE_COLOR_2D_SCANOUT_32BPP; 1313e9d14aebSMichel Dänzer break; 1314e9d14aebSMichel Dänzer } 1315e9d14aebSMichel Dänzer 13166d8ea7deSAlex Deucher num_banks = (rdev->config.si.tile_mode_array[index] >> 20) & 0x3; 1317e9d14aebSMichel Dänzer } 1318e9d14aebSMichel Dänzer 1319e3ea94a6SMarek Olšák fb_format |= EVERGREEN_GRPH_NUM_BANKS(num_banks); 1320e3ea94a6SMarek Olšák } else { 13216d8ea7deSAlex Deucher /* NI and older. */ 13226d8ea7deSAlex Deucher if (rdev->family >= CHIP_CAYMAN) 1323392e3722SAlex Deucher tmp = rdev->config.cayman.tile_config; 1324392e3722SAlex Deucher else 1325392e3722SAlex Deucher tmp = rdev->config.evergreen.tile_config; 1326392e3722SAlex Deucher 1327392e3722SAlex Deucher switch ((tmp & 0xf0) >> 4) { 1328392e3722SAlex Deucher case 0: /* 4 banks */ 1329392e3722SAlex Deucher fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_4_BANK); 1330392e3722SAlex Deucher break; 1331392e3722SAlex Deucher case 1: /* 8 banks */ 1332392e3722SAlex Deucher default: 1333392e3722SAlex Deucher fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_8_BANK); 1334392e3722SAlex Deucher break; 1335392e3722SAlex Deucher case 2: /* 16 banks */ 1336392e3722SAlex Deucher fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_16_BANK); 1337392e3722SAlex Deucher break; 1338392e3722SAlex Deucher } 1339e3ea94a6SMarek Olšák } 1340392e3722SAlex Deucher 134197d66328SAlex Deucher fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1); 1342285484e2SJerome Glisse fb_format |= EVERGREEN_GRPH_TILE_SPLIT(tile_split); 1343285484e2SJerome Glisse fb_format |= EVERGREEN_GRPH_BANK_WIDTH(bankw); 1344285484e2SJerome Glisse fb_format |= EVERGREEN_GRPH_BANK_HEIGHT(bankh); 1345285484e2SJerome Glisse fb_format |= EVERGREEN_GRPH_MACRO_TILE_ASPECT(mtaspect); 13468da0e500SAlex Deucher if (rdev->family >= CHIP_BONAIRE) { 13478da0e500SAlex Deucher /* XXX need to know more about the surface tiling mode */ 13488da0e500SAlex Deucher fb_format |= CIK_GRPH_MICRO_TILE_MODE(CIK_DISPLAY_MICRO_TILING); 13498da0e500SAlex Deucher } 1350392e3722SAlex Deucher } else if (tiling_flags & RADEON_TILING_MICRO) 135197d66328SAlex Deucher fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1); 135297d66328SAlex Deucher 13538da0e500SAlex Deucher if (rdev->family >= CHIP_BONAIRE) { 135435a90528SMarek Olšák /* Read the pipe config from the 2D TILED SCANOUT mode. 135535a90528SMarek Olšák * It should be the same for the other modes too, but not all 135635a90528SMarek Olšák * modes set the pipe config field. */ 135735a90528SMarek Olšák u32 pipe_config = (rdev->config.cik.tile_mode_array[10] >> 6) & 0x1f; 135835a90528SMarek Olšák 135935a90528SMarek Olšák fb_format |= CIK_GRPH_PIPE_CONFIG(pipe_config); 13608da0e500SAlex Deucher } else if ((rdev->family == CHIP_TAHITI) || 1361b7019b2fSAlex Deucher (rdev->family == CHIP_PITCAIRN)) 1362b7019b2fSAlex Deucher fb_format |= SI_GRPH_PIPE_CONFIG(SI_ADDR_SURF_P8_32x32_8x16); 1363227ae10fSAlex Deucher else if ((rdev->family == CHIP_VERDE) || 1364227ae10fSAlex Deucher (rdev->family == CHIP_OLAND) || 1365227ae10fSAlex Deucher (rdev->family == CHIP_HAINAN)) /* for completeness. HAINAN has no display hw */ 1366b7019b2fSAlex Deucher fb_format |= SI_GRPH_PIPE_CONFIG(SI_ADDR_SURF_P4_8x16); 1367b7019b2fSAlex Deucher 1368bcc1c2a1SAlex Deucher switch (radeon_crtc->crtc_id) { 1369bcc1c2a1SAlex Deucher case 0: 1370bcc1c2a1SAlex Deucher WREG32(AVIVO_D1VGA_CONTROL, 0); 1371bcc1c2a1SAlex Deucher break; 1372bcc1c2a1SAlex Deucher case 1: 1373bcc1c2a1SAlex Deucher WREG32(AVIVO_D2VGA_CONTROL, 0); 1374bcc1c2a1SAlex Deucher break; 1375bcc1c2a1SAlex Deucher case 2: 1376bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D3VGA_CONTROL, 0); 1377bcc1c2a1SAlex Deucher break; 1378bcc1c2a1SAlex Deucher case 3: 1379bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D4VGA_CONTROL, 0); 1380bcc1c2a1SAlex Deucher break; 1381bcc1c2a1SAlex Deucher case 4: 1382bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D5VGA_CONTROL, 0); 1383bcc1c2a1SAlex Deucher break; 1384bcc1c2a1SAlex Deucher case 5: 1385bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D6VGA_CONTROL, 0); 1386bcc1c2a1SAlex Deucher break; 1387bcc1c2a1SAlex Deucher default: 1388bcc1c2a1SAlex Deucher break; 1389bcc1c2a1SAlex Deucher } 1390bcc1c2a1SAlex Deucher 1391c63dd758SMichel Dänzer /* Make sure surface address is updated at vertical blank rather than 1392c63dd758SMichel Dänzer * horizontal blank 1393c63dd758SMichel Dänzer */ 1394c63dd758SMichel Dänzer WREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, 0); 1395c63dd758SMichel Dänzer 1396bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 1397bcc1c2a1SAlex Deucher upper_32_bits(fb_location)); 1398bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 1399bcc1c2a1SAlex Deucher upper_32_bits(fb_location)); 1400bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 1401bcc1c2a1SAlex Deucher (u32)fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK); 1402bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 1403bcc1c2a1SAlex Deucher (u32) fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK); 1404bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); 1405fa6bee46SAlex Deucher WREG32(EVERGREEN_GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap); 1406bcc1c2a1SAlex Deucher 14074366f3b5SMario Kleiner /* 14084366f3b5SMario Kleiner * The LUT only has 256 slots for indexing by a 8 bpc fb. Bypass the LUT 14094366f3b5SMario Kleiner * for > 8 bpc scanout to avoid truncation of fb indices to 8 msb's, to 14104366f3b5SMario Kleiner * retain the full precision throughout the pipeline. 14114366f3b5SMario Kleiner */ 14124366f3b5SMario Kleiner WREG32_P(EVERGREEN_GRPH_LUT_10BIT_BYPASS_CONTROL + radeon_crtc->crtc_offset, 14134366f3b5SMario Kleiner (bypass_lut ? EVERGREEN_LUT_10BIT_BYPASS_EN : 0), 14144366f3b5SMario Kleiner ~EVERGREEN_LUT_10BIT_BYPASS_EN); 14154366f3b5SMario Kleiner 14164366f3b5SMario Kleiner if (bypass_lut) 14174366f3b5SMario Kleiner DRM_DEBUG_KMS("Bypassing hardware LUT due to 10 bit fb scanout.\n"); 14184366f3b5SMario Kleiner 1419bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); 1420bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); 1421bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_X_START + radeon_crtc->crtc_offset, 0); 1422bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_Y_START + radeon_crtc->crtc_offset, 0); 14234dd19b0dSChris Ball WREG32(EVERGREEN_GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width); 14244dd19b0dSChris Ball WREG32(EVERGREEN_GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height); 1425bcc1c2a1SAlex Deucher 1426272725c7SVille Syrjälä fb_pitch_pixels = target_fb->pitches[0] / target_fb->format->cpp[0]; 1427bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); 1428bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1); 1429bcc1c2a1SAlex Deucher 14308da0e500SAlex Deucher if (rdev->family >= CHIP_BONAIRE) 14318da0e500SAlex Deucher WREG32(CIK_LB_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, 14328da0e500SAlex Deucher target_fb->height); 14338da0e500SAlex Deucher else 1434bcc1c2a1SAlex Deucher WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, 14351b619250SMichel Dänzer target_fb->height); 1436bcc1c2a1SAlex Deucher x &= ~3; 1437bcc1c2a1SAlex Deucher y &= ~1; 1438bcc1c2a1SAlex Deucher WREG32(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset, 1439bcc1c2a1SAlex Deucher (x << 16) | y); 1440adcfde51SAlex Deucher viewport_w = crtc->mode.hdisplay; 1441adcfde51SAlex Deucher viewport_h = (crtc->mode.vdisplay + 1) & ~1; 144277ae5f4bSAlex Deucher if ((rdev->family >= CHIP_BONAIRE) && 144377ae5f4bSAlex Deucher (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)) 144477ae5f4bSAlex Deucher viewport_h *= 2; 1445bcc1c2a1SAlex Deucher WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset, 1446adcfde51SAlex Deucher (viewport_w << 16) | viewport_h); 1447bcc1c2a1SAlex Deucher 14485dd20bbaSMichel Dänzer /* set pageflip to happen anywhere in vblank interval */ 14495dd20bbaSMichel Dänzer WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); 1450fb9674bdSAlex Deucher 1451f4510a27SMatt Roper if (!atomic && fb && fb != crtc->primary->fb) { 14529a0f0c9dSDaniel Stone rbo = gem_to_radeon_bo(fb->obj[0]); 1453bcc1c2a1SAlex Deucher r = radeon_bo_reserve(rbo, false); 1454bcc1c2a1SAlex Deucher if (unlikely(r != 0)) 1455bcc1c2a1SAlex Deucher return r; 1456bcc1c2a1SAlex Deucher radeon_bo_unpin(rbo); 1457bcc1c2a1SAlex Deucher radeon_bo_unreserve(rbo); 1458bcc1c2a1SAlex Deucher } 1459bcc1c2a1SAlex Deucher 1460bcc1c2a1SAlex Deucher /* Bytes per pixel may have changed */ 1461bcc1c2a1SAlex Deucher radeon_bandwidth_update(rdev); 1462bcc1c2a1SAlex Deucher 1463bcc1c2a1SAlex Deucher return 0; 1464bcc1c2a1SAlex Deucher } 1465bcc1c2a1SAlex Deucher 14664dd19b0dSChris Ball static int avivo_crtc_do_set_base(struct drm_crtc *crtc, 14674dd19b0dSChris Ball struct drm_framebuffer *fb, 14684dd19b0dSChris Ball int x, int y, int atomic) 1469771fe6b9SJerome Glisse { 1470771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1471771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 1472771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 1473771fe6b9SJerome Glisse struct drm_gem_object *obj; 14744c788679SJerome Glisse struct radeon_bo *rbo; 14754dd19b0dSChris Ball struct drm_framebuffer *target_fb; 1476771fe6b9SJerome Glisse uint64_t fb_location; 1477e024e110SDave Airlie uint32_t fb_format, fb_pitch_pixels, tiling_flags; 1478fa6bee46SAlex Deucher u32 fb_swap = R600_D1GRPH_SWAP_ENDIAN_NONE; 1479c63dd758SMichel Dänzer u32 viewport_w, viewport_h; 14804c788679SJerome Glisse int r; 14814366f3b5SMario Kleiner bool bypass_lut = false; 1482b3c11ac2SEric Engestrom struct drm_format_name_buf format_name; 1483771fe6b9SJerome Glisse 14842de3b484SJerome Glisse /* no fb bound */ 1485f4510a27SMatt Roper if (!atomic && !crtc->primary->fb) { 1486d9fdaafbSDave Airlie DRM_DEBUG_KMS("No FB bound\n"); 14872de3b484SJerome Glisse return 0; 14882de3b484SJerome Glisse } 1489771fe6b9SJerome Glisse 14909a0f0c9dSDaniel Stone if (atomic) 14914dd19b0dSChris Ball target_fb = fb; 14929a0f0c9dSDaniel Stone else 1493f4510a27SMatt Roper target_fb = crtc->primary->fb; 1494771fe6b9SJerome Glisse 14959a0f0c9dSDaniel Stone obj = target_fb->obj[0]; 14967e4d15d9SDaniel Vetter rbo = gem_to_radeon_bo(obj); 14974c788679SJerome Glisse r = radeon_bo_reserve(rbo, false); 14984c788679SJerome Glisse if (unlikely(r != 0)) 14994c788679SJerome Glisse return r; 15004dd19b0dSChris Ball 15014dd19b0dSChris Ball /* If atomic, assume fb object is pinned & idle & fenced and 15024dd19b0dSChris Ball * just update base pointers 15034dd19b0dSChris Ball */ 15044dd19b0dSChris Ball if (atomic) 15054dd19b0dSChris Ball fb_location = radeon_bo_gpu_offset(rbo); 15064dd19b0dSChris Ball else { 15074c788679SJerome Glisse r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); 15084c788679SJerome Glisse if (unlikely(r != 0)) { 15094c788679SJerome Glisse radeon_bo_unreserve(rbo); 1510771fe6b9SJerome Glisse return -EINVAL; 1511771fe6b9SJerome Glisse } 15124dd19b0dSChris Ball } 15134c788679SJerome Glisse radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); 15144c788679SJerome Glisse radeon_bo_unreserve(rbo); 1515771fe6b9SJerome Glisse 1516438b74a5SVille Syrjälä switch (target_fb->format->format) { 15178bae4276SFredrik Höglund case DRM_FORMAT_C8: 151841456df2SDave Airlie fb_format = 151941456df2SDave Airlie AVIVO_D1GRPH_CONTROL_DEPTH_8BPP | 152041456df2SDave Airlie AVIVO_D1GRPH_CONTROL_8BPP_INDEXED; 152141456df2SDave Airlie break; 15228bae4276SFredrik Höglund case DRM_FORMAT_XRGB4444: 15238bae4276SFredrik Höglund case DRM_FORMAT_ARGB4444: 15248bae4276SFredrik Höglund fb_format = 15258bae4276SFredrik Höglund AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | 15268bae4276SFredrik Höglund AVIVO_D1GRPH_CONTROL_16BPP_ARGB4444; 15278bae4276SFredrik Höglund #ifdef __BIG_ENDIAN 15288bae4276SFredrik Höglund fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT; 15298bae4276SFredrik Höglund #endif 15308bae4276SFredrik Höglund break; 15318bae4276SFredrik Höglund case DRM_FORMAT_XRGB1555: 1532771fe6b9SJerome Glisse fb_format = 1533771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | 1534771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555; 15358bae4276SFredrik Höglund #ifdef __BIG_ENDIAN 15368bae4276SFredrik Höglund fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT; 15378bae4276SFredrik Höglund #endif 1538771fe6b9SJerome Glisse break; 15398bae4276SFredrik Höglund case DRM_FORMAT_RGB565: 1540771fe6b9SJerome Glisse fb_format = 1541771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | 1542771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_16BPP_RGB565; 1543fa6bee46SAlex Deucher #ifdef __BIG_ENDIAN 1544fa6bee46SAlex Deucher fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT; 1545fa6bee46SAlex Deucher #endif 1546771fe6b9SJerome Glisse break; 15478bae4276SFredrik Höglund case DRM_FORMAT_XRGB8888: 15488bae4276SFredrik Höglund case DRM_FORMAT_ARGB8888: 1549771fe6b9SJerome Glisse fb_format = 1550771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_32BPP | 1551771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888; 1552fa6bee46SAlex Deucher #ifdef __BIG_ENDIAN 1553fa6bee46SAlex Deucher fb_swap = R600_D1GRPH_SWAP_ENDIAN_32BIT; 1554fa6bee46SAlex Deucher #endif 1555771fe6b9SJerome Glisse break; 15568bae4276SFredrik Höglund case DRM_FORMAT_XRGB2101010: 15578bae4276SFredrik Höglund case DRM_FORMAT_ARGB2101010: 15588bae4276SFredrik Höglund fb_format = 15598bae4276SFredrik Höglund AVIVO_D1GRPH_CONTROL_DEPTH_32BPP | 15608bae4276SFredrik Höglund AVIVO_D1GRPH_CONTROL_32BPP_ARGB2101010; 15618bae4276SFredrik Höglund #ifdef __BIG_ENDIAN 15628bae4276SFredrik Höglund fb_swap = R600_D1GRPH_SWAP_ENDIAN_32BIT; 15638bae4276SFredrik Höglund #endif 15644366f3b5SMario Kleiner /* Greater 8 bpc fb needs to bypass hw-lut to retain precision */ 15654366f3b5SMario Kleiner bypass_lut = true; 15668bae4276SFredrik Höglund break; 1567a69e40fdSMauro Rossi case DRM_FORMAT_XBGR8888: 1568a69e40fdSMauro Rossi case DRM_FORMAT_ABGR8888: 1569a69e40fdSMauro Rossi fb_format = 1570a69e40fdSMauro Rossi AVIVO_D1GRPH_CONTROL_DEPTH_32BPP | 1571a69e40fdSMauro Rossi AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888; 1572a69e40fdSMauro Rossi if (rdev->family >= CHIP_R600) 1573a69e40fdSMauro Rossi fb_swap = 1574a69e40fdSMauro Rossi (R600_D1GRPH_RED_CROSSBAR(R600_D1GRPH_RED_SEL_B) | 1575a69e40fdSMauro Rossi R600_D1GRPH_BLUE_CROSSBAR(R600_D1GRPH_BLUE_SEL_R)); 1576a69e40fdSMauro Rossi else /* DCE1 (R5xx) */ 1577a69e40fdSMauro Rossi fb_format |= AVIVO_D1GRPH_SWAP_RB; 1578a69e40fdSMauro Rossi #ifdef __BIG_ENDIAN 1579a69e40fdSMauro Rossi fb_swap |= R600_D1GRPH_SWAP_ENDIAN_32BIT; 1580a69e40fdSMauro Rossi #endif 1581a69e40fdSMauro Rossi break; 1582771fe6b9SJerome Glisse default: 1583b3c11ac2SEric Engestrom DRM_ERROR("Unsupported screen format %s\n", 1584438b74a5SVille Syrjälä drm_get_format_name(target_fb->format->format, &format_name)); 1585771fe6b9SJerome Glisse return -EINVAL; 1586771fe6b9SJerome Glisse } 1587771fe6b9SJerome Glisse 158840c4ac1cSAlex Deucher if (rdev->family >= CHIP_R600) { 158940c4ac1cSAlex Deucher if (tiling_flags & RADEON_TILING_MACRO) 159040c4ac1cSAlex Deucher fb_format |= R600_D1GRPH_ARRAY_MODE_2D_TILED_THIN1; 159140c4ac1cSAlex Deucher else if (tiling_flags & RADEON_TILING_MICRO) 159240c4ac1cSAlex Deucher fb_format |= R600_D1GRPH_ARRAY_MODE_1D_TILED_THIN1; 159340c4ac1cSAlex Deucher } else { 1594cf2f05d3SDave Airlie if (tiling_flags & RADEON_TILING_MACRO) 1595cf2f05d3SDave Airlie fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE; 1596cf2f05d3SDave Airlie 1597e024e110SDave Airlie if (tiling_flags & RADEON_TILING_MICRO) 1598e024e110SDave Airlie fb_format |= AVIVO_D1GRPH_TILED; 159940c4ac1cSAlex Deucher } 1600e024e110SDave Airlie 1601771fe6b9SJerome Glisse if (radeon_crtc->crtc_id == 0) 1602771fe6b9SJerome Glisse WREG32(AVIVO_D1VGA_CONTROL, 0); 1603771fe6b9SJerome Glisse else 1604771fe6b9SJerome Glisse WREG32(AVIVO_D2VGA_CONTROL, 0); 1605c290dadfSAlex Deucher 1606c63dd758SMichel Dänzer /* Make sure surface address is update at vertical blank rather than 1607c63dd758SMichel Dänzer * horizontal blank 1608c63dd758SMichel Dänzer */ 1609c63dd758SMichel Dänzer WREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, 0); 1610c63dd758SMichel Dänzer 1611c290dadfSAlex Deucher if (rdev->family >= CHIP_RV770) { 1612c290dadfSAlex Deucher if (radeon_crtc->crtc_id) { 161395347871SAlex Deucher WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 161495347871SAlex Deucher WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 1615c290dadfSAlex Deucher } else { 161695347871SAlex Deucher WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 161795347871SAlex Deucher WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 1618c290dadfSAlex Deucher } 1619c290dadfSAlex Deucher } 1620771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 1621771fe6b9SJerome Glisse (u32) fb_location); 1622771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + 1623771fe6b9SJerome Glisse radeon_crtc->crtc_offset, (u32) fb_location); 1624771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); 1625fa6bee46SAlex Deucher if (rdev->family >= CHIP_R600) 1626fa6bee46SAlex Deucher WREG32(R600_D1GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap); 1627771fe6b9SJerome Glisse 16284366f3b5SMario Kleiner /* LUT only has 256 slots for 8 bpc fb. Bypass for > 8 bpc scanout for precision */ 16294366f3b5SMario Kleiner WREG32_P(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, 16304366f3b5SMario Kleiner (bypass_lut ? AVIVO_LUT_10BIT_BYPASS_EN : 0), ~AVIVO_LUT_10BIT_BYPASS_EN); 16314366f3b5SMario Kleiner 16324366f3b5SMario Kleiner if (bypass_lut) 16334366f3b5SMario Kleiner DRM_DEBUG_KMS("Bypassing hardware LUT due to 10 bit fb scanout.\n"); 16344366f3b5SMario Kleiner 1635771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); 1636771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); 1637771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0); 1638771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, 0); 16394dd19b0dSChris Ball WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width); 16404dd19b0dSChris Ball WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height); 1641771fe6b9SJerome Glisse 1642272725c7SVille Syrjälä fb_pitch_pixels = target_fb->pitches[0] / target_fb->format->cpp[0]; 1643771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); 1644771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1); 1645771fe6b9SJerome Glisse 1646771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, 16471b619250SMichel Dänzer target_fb->height); 1648771fe6b9SJerome Glisse x &= ~3; 1649771fe6b9SJerome Glisse y &= ~1; 1650771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset, 1651771fe6b9SJerome Glisse (x << 16) | y); 1652adcfde51SAlex Deucher viewport_w = crtc->mode.hdisplay; 1653adcfde51SAlex Deucher viewport_h = (crtc->mode.vdisplay + 1) & ~1; 1654771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset, 1655adcfde51SAlex Deucher (viewport_w << 16) | viewport_h); 1656771fe6b9SJerome Glisse 1657363926dcSMario Kleiner /* set pageflip to happen only at start of vblank interval (front porch) */ 1658363926dcSMario Kleiner WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 3); 1659fb9674bdSAlex Deucher 1660f4510a27SMatt Roper if (!atomic && fb && fb != crtc->primary->fb) { 16619a0f0c9dSDaniel Stone rbo = gem_to_radeon_bo(fb->obj[0]); 16624c788679SJerome Glisse r = radeon_bo_reserve(rbo, false); 16634c788679SJerome Glisse if (unlikely(r != 0)) 16644c788679SJerome Glisse return r; 16654c788679SJerome Glisse radeon_bo_unpin(rbo); 16664c788679SJerome Glisse radeon_bo_unreserve(rbo); 1667771fe6b9SJerome Glisse } 1668f30f37deSMichel Dänzer 1669f30f37deSMichel Dänzer /* Bytes per pixel may have changed */ 1670f30f37deSMichel Dänzer radeon_bandwidth_update(rdev); 1671f30f37deSMichel Dänzer 1672771fe6b9SJerome Glisse return 0; 1673771fe6b9SJerome Glisse } 1674771fe6b9SJerome Glisse 167554f088a9SAlex Deucher int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, 167654f088a9SAlex Deucher struct drm_framebuffer *old_fb) 167754f088a9SAlex Deucher { 167854f088a9SAlex Deucher struct drm_device *dev = crtc->dev; 167954f088a9SAlex Deucher struct radeon_device *rdev = dev->dev_private; 168054f088a9SAlex Deucher 1681bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) 1682c9417bddSAlex Deucher return dce4_crtc_do_set_base(crtc, old_fb, x, y, 0); 1683bcc1c2a1SAlex Deucher else if (ASIC_IS_AVIVO(rdev)) 16844dd19b0dSChris Ball return avivo_crtc_do_set_base(crtc, old_fb, x, y, 0); 168554f088a9SAlex Deucher else 16864dd19b0dSChris Ball return radeon_crtc_do_set_base(crtc, old_fb, x, y, 0); 16874dd19b0dSChris Ball } 16884dd19b0dSChris Ball 16894dd19b0dSChris Ball int atombios_crtc_set_base_atomic(struct drm_crtc *crtc, 16904dd19b0dSChris Ball struct drm_framebuffer *fb, 169121c74a8eSJason Wessel int x, int y, enum mode_set_atomic state) 16924dd19b0dSChris Ball { 16934dd19b0dSChris Ball struct drm_device *dev = crtc->dev; 16944dd19b0dSChris Ball struct radeon_device *rdev = dev->dev_private; 16954dd19b0dSChris Ball 16964dd19b0dSChris Ball if (ASIC_IS_DCE4(rdev)) 1697c9417bddSAlex Deucher return dce4_crtc_do_set_base(crtc, fb, x, y, 1); 16984dd19b0dSChris Ball else if (ASIC_IS_AVIVO(rdev)) 16994dd19b0dSChris Ball return avivo_crtc_do_set_base(crtc, fb, x, y, 1); 17004dd19b0dSChris Ball else 17014dd19b0dSChris Ball return radeon_crtc_do_set_base(crtc, fb, x, y, 1); 170254f088a9SAlex Deucher } 170354f088a9SAlex Deucher 1704615e0cb6SAlex Deucher /* properly set additional regs when using atombios */ 1705615e0cb6SAlex Deucher static void radeon_legacy_atom_fixup(struct drm_crtc *crtc) 1706615e0cb6SAlex Deucher { 1707615e0cb6SAlex Deucher struct drm_device *dev = crtc->dev; 1708615e0cb6SAlex Deucher struct radeon_device *rdev = dev->dev_private; 1709615e0cb6SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1710615e0cb6SAlex Deucher u32 disp_merge_cntl; 1711615e0cb6SAlex Deucher 1712615e0cb6SAlex Deucher switch (radeon_crtc->crtc_id) { 1713615e0cb6SAlex Deucher case 0: 1714615e0cb6SAlex Deucher disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL); 1715615e0cb6SAlex Deucher disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; 1716615e0cb6SAlex Deucher WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl); 1717615e0cb6SAlex Deucher break; 1718615e0cb6SAlex Deucher case 1: 1719615e0cb6SAlex Deucher disp_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL); 1720615e0cb6SAlex Deucher disp_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN; 1721615e0cb6SAlex Deucher WREG32(RADEON_DISP2_MERGE_CNTL, disp_merge_cntl); 1722615e0cb6SAlex Deucher WREG32(RADEON_FP_H2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_H_SYNC_STRT_WID)); 1723615e0cb6SAlex Deucher WREG32(RADEON_FP_V2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_V_SYNC_STRT_WID)); 1724615e0cb6SAlex Deucher break; 1725615e0cb6SAlex Deucher } 1726615e0cb6SAlex Deucher } 1727615e0cb6SAlex Deucher 1728f3dd8508SAlex Deucher /** 1729f3dd8508SAlex Deucher * radeon_get_pll_use_mask - look up a mask of which pplls are in use 1730f3dd8508SAlex Deucher * 1731f3dd8508SAlex Deucher * @crtc: drm crtc 1732f3dd8508SAlex Deucher * 1733f3dd8508SAlex Deucher * Returns the mask of which PPLLs (Pixel PLLs) are in use. 1734f3dd8508SAlex Deucher */ 1735f3dd8508SAlex Deucher static u32 radeon_get_pll_use_mask(struct drm_crtc *crtc) 1736f3dd8508SAlex Deucher { 1737f3dd8508SAlex Deucher struct drm_device *dev = crtc->dev; 1738f3dd8508SAlex Deucher struct drm_crtc *test_crtc; 173957b35e29SAlex Deucher struct radeon_crtc *test_radeon_crtc; 1740f3dd8508SAlex Deucher u32 pll_in_use = 0; 1741f3dd8508SAlex Deucher 1742f3dd8508SAlex Deucher list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { 1743f3dd8508SAlex Deucher if (crtc == test_crtc) 1744f3dd8508SAlex Deucher continue; 1745f3dd8508SAlex Deucher 174657b35e29SAlex Deucher test_radeon_crtc = to_radeon_crtc(test_crtc); 174757b35e29SAlex Deucher if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID) 174857b35e29SAlex Deucher pll_in_use |= (1 << test_radeon_crtc->pll_id); 1749f3dd8508SAlex Deucher } 1750f3dd8508SAlex Deucher return pll_in_use; 1751f3dd8508SAlex Deucher } 1752f3dd8508SAlex Deucher 1753f3dd8508SAlex Deucher /** 1754f3dd8508SAlex Deucher * radeon_get_shared_dp_ppll - return the PPLL used by another crtc for DP 1755f3dd8508SAlex Deucher * 1756f3dd8508SAlex Deucher * @crtc: drm crtc 1757f3dd8508SAlex Deucher * 1758f3dd8508SAlex Deucher * Returns the PPLL (Pixel PLL) used by another crtc/encoder which is 1759f3dd8508SAlex Deucher * also in DP mode. For DP, a single PPLL can be used for all DP 1760f3dd8508SAlex Deucher * crtcs/encoders. 1761f3dd8508SAlex Deucher */ 1762f3dd8508SAlex Deucher static int radeon_get_shared_dp_ppll(struct drm_crtc *crtc) 1763f3dd8508SAlex Deucher { 1764f3dd8508SAlex Deucher struct drm_device *dev = crtc->dev; 1765e3c00d87SLucas Stach struct radeon_device *rdev = dev->dev_private; 176657b35e29SAlex Deucher struct drm_crtc *test_crtc; 17675df3196bSAlex Deucher struct radeon_crtc *test_radeon_crtc; 1768f3dd8508SAlex Deucher 176957b35e29SAlex Deucher list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { 177057b35e29SAlex Deucher if (crtc == test_crtc) 177157b35e29SAlex Deucher continue; 177257b35e29SAlex Deucher test_radeon_crtc = to_radeon_crtc(test_crtc); 177357b35e29SAlex Deucher if (test_radeon_crtc->encoder && 177457b35e29SAlex Deucher ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_radeon_crtc->encoder))) { 1775e3c00d87SLucas Stach /* PPLL2 is exclusive to UNIPHYA on DCE61 */ 1776e3c00d87SLucas Stach if (ASIC_IS_DCE61(rdev) && !ASIC_IS_DCE8(rdev) && 1777e3c00d87SLucas Stach test_radeon_crtc->pll_id == ATOM_PPLL2) 1778e3c00d87SLucas Stach continue; 1779f3dd8508SAlex Deucher /* for DP use the same PLL for all */ 17805df3196bSAlex Deucher if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID) 17815df3196bSAlex Deucher return test_radeon_crtc->pll_id; 1782f3dd8508SAlex Deucher } 1783f3dd8508SAlex Deucher } 1784f3dd8508SAlex Deucher return ATOM_PPLL_INVALID; 1785f3dd8508SAlex Deucher } 1786f3dd8508SAlex Deucher 1787f3dd8508SAlex Deucher /** 17882f454cf1SAlex Deucher * radeon_get_shared_nondp_ppll - return the PPLL used by another non-DP crtc 17892f454cf1SAlex Deucher * 17902f454cf1SAlex Deucher * @crtc: drm crtc 17912f454cf1SAlex Deucher * @encoder: drm encoder 17922f454cf1SAlex Deucher * 17932f454cf1SAlex Deucher * Returns the PPLL (Pixel PLL) used by another non-DP crtc/encoder which can 17942f454cf1SAlex Deucher * be shared (i.e., same clock). 17952f454cf1SAlex Deucher */ 17965df3196bSAlex Deucher static int radeon_get_shared_nondp_ppll(struct drm_crtc *crtc) 17972f454cf1SAlex Deucher { 17985df3196bSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 17992f454cf1SAlex Deucher struct drm_device *dev = crtc->dev; 1800e3c00d87SLucas Stach struct radeon_device *rdev = dev->dev_private; 18019642ac0eSAlex Deucher struct drm_crtc *test_crtc; 18025df3196bSAlex Deucher struct radeon_crtc *test_radeon_crtc; 18039642ac0eSAlex Deucher u32 adjusted_clock, test_adjusted_clock; 18042f454cf1SAlex Deucher 18059642ac0eSAlex Deucher adjusted_clock = radeon_crtc->adjusted_clock; 18069642ac0eSAlex Deucher 18079642ac0eSAlex Deucher if (adjusted_clock == 0) 18089642ac0eSAlex Deucher return ATOM_PPLL_INVALID; 18092f454cf1SAlex Deucher 181057b35e29SAlex Deucher list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { 181157b35e29SAlex Deucher if (crtc == test_crtc) 181257b35e29SAlex Deucher continue; 18139642ac0eSAlex Deucher test_radeon_crtc = to_radeon_crtc(test_crtc); 181457b35e29SAlex Deucher if (test_radeon_crtc->encoder && 181557b35e29SAlex Deucher !ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_radeon_crtc->encoder))) { 1816e3c00d87SLucas Stach /* PPLL2 is exclusive to UNIPHYA on DCE61 */ 1817e3c00d87SLucas Stach if (ASIC_IS_DCE61(rdev) && !ASIC_IS_DCE8(rdev) && 1818e3c00d87SLucas Stach test_radeon_crtc->pll_id == ATOM_PPLL2) 1819e3c00d87SLucas Stach continue; 182057b35e29SAlex Deucher /* check if we are already driving this connector with another crtc */ 182157b35e29SAlex Deucher if (test_radeon_crtc->connector == radeon_crtc->connector) { 182257b35e29SAlex Deucher /* if we are, return that pll */ 182357b35e29SAlex Deucher if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID) 182457b35e29SAlex Deucher return test_radeon_crtc->pll_id; 182557b35e29SAlex Deucher } 18262f454cf1SAlex Deucher /* for non-DP check the clock */ 18279642ac0eSAlex Deucher test_adjusted_clock = test_radeon_crtc->adjusted_clock; 18289642ac0eSAlex Deucher if ((crtc->mode.clock == test_crtc->mode.clock) && 18299642ac0eSAlex Deucher (adjusted_clock == test_adjusted_clock) && 18309642ac0eSAlex Deucher (radeon_crtc->ss_enabled == test_radeon_crtc->ss_enabled) && 18316fb3c025SAlex Deucher (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID)) 18325df3196bSAlex Deucher return test_radeon_crtc->pll_id; 18332f454cf1SAlex Deucher } 18342f454cf1SAlex Deucher } 18352f454cf1SAlex Deucher return ATOM_PPLL_INVALID; 18362f454cf1SAlex Deucher } 18372f454cf1SAlex Deucher 18382f454cf1SAlex Deucher /** 1839f3dd8508SAlex Deucher * radeon_atom_pick_pll - Allocate a PPLL for use by the crtc. 1840f3dd8508SAlex Deucher * 1841f3dd8508SAlex Deucher * @crtc: drm crtc 1842f3dd8508SAlex Deucher * 1843f3dd8508SAlex Deucher * Returns the PPLL (Pixel PLL) to be used by the crtc. For DP monitors 1844f3dd8508SAlex Deucher * a single PPLL can be used for all DP crtcs/encoders. For non-DP 1845f3dd8508SAlex Deucher * monitors a dedicated PPLL must be used. If a particular board has 1846f3dd8508SAlex Deucher * an external DP PLL, return ATOM_PPLL_INVALID to skip PLL programming 1847f3dd8508SAlex Deucher * as there is no need to program the PLL itself. If we are not able to 1848f3dd8508SAlex Deucher * allocate a PLL, return ATOM_PPLL_INVALID to skip PLL programming to 1849f3dd8508SAlex Deucher * avoid messing up an existing monitor. 1850f3dd8508SAlex Deucher * 1851f3dd8508SAlex Deucher * Asic specific PLL information 1852f3dd8508SAlex Deucher * 18530331f674SAlex Deucher * DCE 8.x 18540331f674SAlex Deucher * KB/KV 18550331f674SAlex Deucher * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) 18560331f674SAlex Deucher * CI 18570331f674SAlex Deucher * - PPLL0, PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC 18580331f674SAlex Deucher * 1859f3dd8508SAlex Deucher * DCE 6.1 1860f3dd8508SAlex Deucher * - PPLL2 is only available to UNIPHYA (both DP and non-DP) 1861f3dd8508SAlex Deucher * - PPLL0, PPLL1 are available for UNIPHYB/C/D/E/F (both DP and non-DP) 1862f3dd8508SAlex Deucher * 1863f3dd8508SAlex Deucher * DCE 6.0 1864f3dd8508SAlex Deucher * - PPLL0 is available to all UNIPHY (DP only) 1865f3dd8508SAlex Deucher * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC 1866f3dd8508SAlex Deucher * 1867f3dd8508SAlex Deucher * DCE 5.0 1868f3dd8508SAlex Deucher * - DCPLL is available to all UNIPHY (DP only) 1869f3dd8508SAlex Deucher * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC 1870f3dd8508SAlex Deucher * 1871f3dd8508SAlex Deucher * DCE 3.0/4.0/4.1 1872f3dd8508SAlex Deucher * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC 1873f3dd8508SAlex Deucher * 1874f3dd8508SAlex Deucher */ 1875bcc1c2a1SAlex Deucher static int radeon_atom_pick_pll(struct drm_crtc *crtc) 1876bcc1c2a1SAlex Deucher { 18775df3196bSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1878bcc1c2a1SAlex Deucher struct drm_device *dev = crtc->dev; 1879bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 18805df3196bSAlex Deucher struct radeon_encoder *radeon_encoder = 18815df3196bSAlex Deucher to_radeon_encoder(radeon_crtc->encoder); 1882f3dd8508SAlex Deucher u32 pll_in_use; 1883f3dd8508SAlex Deucher int pll; 1884bcc1c2a1SAlex Deucher 18850331f674SAlex Deucher if (ASIC_IS_DCE8(rdev)) { 18860331f674SAlex Deucher if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { 18870331f674SAlex Deucher if (rdev->clock.dp_extclk) 18880331f674SAlex Deucher /* skip PPLL programming if using ext clock */ 18890331f674SAlex Deucher return ATOM_PPLL_INVALID; 18900331f674SAlex Deucher else { 18910331f674SAlex Deucher /* use the same PPLL for all DP monitors */ 18920331f674SAlex Deucher pll = radeon_get_shared_dp_ppll(crtc); 18930331f674SAlex Deucher if (pll != ATOM_PPLL_INVALID) 18940331f674SAlex Deucher return pll; 18950331f674SAlex Deucher } 18960331f674SAlex Deucher } else { 18970331f674SAlex Deucher /* use the same PPLL for all monitors with the same clock */ 18980331f674SAlex Deucher pll = radeon_get_shared_nondp_ppll(crtc); 18990331f674SAlex Deucher if (pll != ATOM_PPLL_INVALID) 19000331f674SAlex Deucher return pll; 19010331f674SAlex Deucher } 19020331f674SAlex Deucher /* otherwise, pick one of the plls */ 1903fbedf1c3SAlex Deucher if ((rdev->family == CHIP_KABINI) || 1904b214f2a4SSamuel Li (rdev->family == CHIP_MULLINS)) { 1905fbedf1c3SAlex Deucher /* KB/ML has PPLL1 and PPLL2 */ 19060331f674SAlex Deucher pll_in_use = radeon_get_pll_use_mask(crtc); 19070331f674SAlex Deucher if (!(pll_in_use & (1 << ATOM_PPLL2))) 19080331f674SAlex Deucher return ATOM_PPLL2; 19090331f674SAlex Deucher if (!(pll_in_use & (1 << ATOM_PPLL1))) 19100331f674SAlex Deucher return ATOM_PPLL1; 19110331f674SAlex Deucher DRM_ERROR("unable to allocate a PPLL\n"); 19120331f674SAlex Deucher return ATOM_PPLL_INVALID; 19130331f674SAlex Deucher } else { 1914fbedf1c3SAlex Deucher /* CI/KV has PPLL0, PPLL1, and PPLL2 */ 19150331f674SAlex Deucher pll_in_use = radeon_get_pll_use_mask(crtc); 19160331f674SAlex Deucher if (!(pll_in_use & (1 << ATOM_PPLL2))) 19170331f674SAlex Deucher return ATOM_PPLL2; 19180331f674SAlex Deucher if (!(pll_in_use & (1 << ATOM_PPLL1))) 19190331f674SAlex Deucher return ATOM_PPLL1; 19200331f674SAlex Deucher if (!(pll_in_use & (1 << ATOM_PPLL0))) 19210331f674SAlex Deucher return ATOM_PPLL0; 19220331f674SAlex Deucher DRM_ERROR("unable to allocate a PPLL\n"); 19230331f674SAlex Deucher return ATOM_PPLL_INVALID; 19240331f674SAlex Deucher } 19250331f674SAlex Deucher } else if (ASIC_IS_DCE61(rdev)) { 192624e1f794SAlex Deucher struct radeon_encoder_atom_dig *dig = 19275df3196bSAlex Deucher radeon_encoder->enc_priv; 192824e1f794SAlex Deucher 19295df3196bSAlex Deucher if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY) && 1930f3dd8508SAlex Deucher (dig->linkb == false)) 1931f3dd8508SAlex Deucher /* UNIPHY A uses PPLL2 */ 193224e1f794SAlex Deucher return ATOM_PPLL2; 19335df3196bSAlex Deucher else if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { 1934f3dd8508SAlex Deucher /* UNIPHY B/C/D/E/F */ 1935f3dd8508SAlex Deucher if (rdev->clock.dp_extclk) 1936f3dd8508SAlex Deucher /* skip PPLL programming if using ext clock */ 1937f3dd8508SAlex Deucher return ATOM_PPLL_INVALID; 1938f3dd8508SAlex Deucher else { 1939f3dd8508SAlex Deucher /* use the same PPLL for all DP monitors */ 1940f3dd8508SAlex Deucher pll = radeon_get_shared_dp_ppll(crtc); 1941f3dd8508SAlex Deucher if (pll != ATOM_PPLL_INVALID) 1942f3dd8508SAlex Deucher return pll; 1943f3dd8508SAlex Deucher } 19442f454cf1SAlex Deucher } else { 19452f454cf1SAlex Deucher /* use the same PPLL for all monitors with the same clock */ 19465df3196bSAlex Deucher pll = radeon_get_shared_nondp_ppll(crtc); 19472f454cf1SAlex Deucher if (pll != ATOM_PPLL_INVALID) 19482f454cf1SAlex Deucher return pll; 1949f3dd8508SAlex Deucher } 195024e1f794SAlex Deucher /* UNIPHY B/C/D/E/F */ 1951f3dd8508SAlex Deucher pll_in_use = radeon_get_pll_use_mask(crtc); 1952f3dd8508SAlex Deucher if (!(pll_in_use & (1 << ATOM_PPLL0))) 195324e1f794SAlex Deucher return ATOM_PPLL0; 1954f3dd8508SAlex Deucher if (!(pll_in_use & (1 << ATOM_PPLL1))) 195524e1f794SAlex Deucher return ATOM_PPLL1; 1956f3dd8508SAlex Deucher DRM_ERROR("unable to allocate a PPLL\n"); 1957f3dd8508SAlex Deucher return ATOM_PPLL_INVALID; 19589ef4e1d0SAlex Deucher } else if (ASIC_IS_DCE41(rdev)) { 19599ef4e1d0SAlex Deucher /* Don't share PLLs on DCE4.1 chips */ 19609ef4e1d0SAlex Deucher if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { 19619ef4e1d0SAlex Deucher if (rdev->clock.dp_extclk) 19629ef4e1d0SAlex Deucher /* skip PPLL programming if using ext clock */ 19639ef4e1d0SAlex Deucher return ATOM_PPLL_INVALID; 19649ef4e1d0SAlex Deucher } 19659ef4e1d0SAlex Deucher pll_in_use = radeon_get_pll_use_mask(crtc); 19669ef4e1d0SAlex Deucher if (!(pll_in_use & (1 << ATOM_PPLL1))) 19679ef4e1d0SAlex Deucher return ATOM_PPLL1; 19689ef4e1d0SAlex Deucher if (!(pll_in_use & (1 << ATOM_PPLL2))) 19699ef4e1d0SAlex Deucher return ATOM_PPLL2; 19709ef4e1d0SAlex Deucher DRM_ERROR("unable to allocate a PPLL\n"); 19719ef4e1d0SAlex Deucher return ATOM_PPLL_INVALID; 197224e1f794SAlex Deucher } else if (ASIC_IS_DCE4(rdev)) { 197386a94defSAlex Deucher /* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock, 197486a94defSAlex Deucher * depending on the asic: 197586a94defSAlex Deucher * DCE4: PPLL or ext clock 1976f3dd8508SAlex Deucher * DCE5: PPLL, DCPLL, or ext clock 1977f3dd8508SAlex Deucher * DCE6: PPLL, PPLL0, or ext clock 197886a94defSAlex Deucher * 197986a94defSAlex Deucher * Setting ATOM_PPLL_INVALID will cause SetPixelClock to skip 198086a94defSAlex Deucher * PPLL/DCPLL programming and only program the DP DTO for the 198186a94defSAlex Deucher * crtc virtual pixel clock. 198286a94defSAlex Deucher */ 19835df3196bSAlex Deucher if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { 1984ecd67955SAlex Deucher if (rdev->clock.dp_extclk) 1985f3dd8508SAlex Deucher /* skip PPLL programming if using ext clock */ 1986ecd67955SAlex Deucher return ATOM_PPLL_INVALID; 198726fe45a0SAlex Deucher else if (ASIC_IS_DCE6(rdev)) 1988f3dd8508SAlex Deucher /* use PPLL0 for all DP */ 198926fe45a0SAlex Deucher return ATOM_PPLL0; 1990ecd67955SAlex Deucher else if (ASIC_IS_DCE5(rdev)) 1991f3dd8508SAlex Deucher /* use DCPLL for all DP */ 1992ecd67955SAlex Deucher return ATOM_DCPLL; 1993f3dd8508SAlex Deucher else { 1994f3dd8508SAlex Deucher /* use the same PPLL for all DP monitors */ 1995f3dd8508SAlex Deucher pll = radeon_get_shared_dp_ppll(crtc); 1996f3dd8508SAlex Deucher if (pll != ATOM_PPLL_INVALID) 1997f3dd8508SAlex Deucher return pll; 1998bcc1c2a1SAlex Deucher } 19999ef4e1d0SAlex Deucher } else { 20002f454cf1SAlex Deucher /* use the same PPLL for all monitors with the same clock */ 20015df3196bSAlex Deucher pll = radeon_get_shared_nondp_ppll(crtc); 20029dbbcfc6SAlex Deucher if (pll != ATOM_PPLL_INVALID) 20039dbbcfc6SAlex Deucher return pll; 20049dbbcfc6SAlex Deucher } 20055df3196bSAlex Deucher /* all other cases */ 20065df3196bSAlex Deucher pll_in_use = radeon_get_pll_use_mask(crtc); 20075df3196bSAlex Deucher if (!(pll_in_use & (1 << ATOM_PPLL1))) 20085df3196bSAlex Deucher return ATOM_PPLL1; 200929dbe3bcSAlex Deucher if (!(pll_in_use & (1 << ATOM_PPLL2))) 201029dbe3bcSAlex Deucher return ATOM_PPLL2; 20115df3196bSAlex Deucher DRM_ERROR("unable to allocate a PPLL\n"); 20125df3196bSAlex Deucher return ATOM_PPLL_INVALID; 20132f454cf1SAlex Deucher } else { 20142f454cf1SAlex Deucher /* on pre-R5xx asics, the crtc to pll mapping is hardcoded */ 2015fc58acdbSJerome Glisse /* some atombios (observed in some DCE2/DCE3) code have a bug, 2016fc58acdbSJerome Glisse * the matching btw pll and crtc is done through 2017fc58acdbSJerome Glisse * PCLK_CRTC[1|2]_CNTL (0x480/0x484) but atombios code use the 2018fc58acdbSJerome Glisse * pll (1 or 2) to select which register to write. ie if using 2019fc58acdbSJerome Glisse * pll1 it will use PCLK_CRTC1_CNTL (0x480) and if using pll2 2020fc58acdbSJerome Glisse * it will use PCLK_CRTC2_CNTL (0x484), it then use crtc id to 2021fc58acdbSJerome Glisse * choose which value to write. Which is reverse order from 2022fc58acdbSJerome Glisse * register logic. So only case that works is when pllid is 2023fc58acdbSJerome Glisse * same as crtcid or when both pll and crtc are enabled and 2024fc58acdbSJerome Glisse * both use same clock. 2025fc58acdbSJerome Glisse * 2026fc58acdbSJerome Glisse * So just return crtc id as if crtc and pll were hard linked 2027fc58acdbSJerome Glisse * together even if they aren't 2028fc58acdbSJerome Glisse */ 2029bcc1c2a1SAlex Deucher return radeon_crtc->crtc_id; 20302f454cf1SAlex Deucher } 20312f454cf1SAlex Deucher } 2032bcc1c2a1SAlex Deucher 2033f3f1f03eSAlex Deucher void radeon_atom_disp_eng_pll_init(struct radeon_device *rdev) 20343fa47d9eSAlex Deucher { 20353fa47d9eSAlex Deucher /* always set DCPLL */ 2036f3f1f03eSAlex Deucher if (ASIC_IS_DCE6(rdev)) 2037f3f1f03eSAlex Deucher atombios_crtc_set_disp_eng_pll(rdev, rdev->clock.default_dispclk); 2038f3f1f03eSAlex Deucher else if (ASIC_IS_DCE4(rdev)) { 20393fa47d9eSAlex Deucher struct radeon_atom_ss ss; 20403fa47d9eSAlex Deucher bool ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &ss, 20413fa47d9eSAlex Deucher ASIC_INTERNAL_SS_ON_DCPLL, 20423fa47d9eSAlex Deucher rdev->clock.default_dispclk); 20433fa47d9eSAlex Deucher if (ss_enabled) 20445efcc76cSJerome Glisse atombios_crtc_program_ss(rdev, ATOM_DISABLE, ATOM_DCPLL, -1, &ss); 20453fa47d9eSAlex Deucher /* XXX: DCE5, make sure voltage, dispclk is high enough */ 2046f3f1f03eSAlex Deucher atombios_crtc_set_disp_eng_pll(rdev, rdev->clock.default_dispclk); 20473fa47d9eSAlex Deucher if (ss_enabled) 20485efcc76cSJerome Glisse atombios_crtc_program_ss(rdev, ATOM_ENABLE, ATOM_DCPLL, -1, &ss); 20493fa47d9eSAlex Deucher } 20503fa47d9eSAlex Deucher 20513fa47d9eSAlex Deucher } 20523fa47d9eSAlex Deucher 2053771fe6b9SJerome Glisse int atombios_crtc_mode_set(struct drm_crtc *crtc, 2054771fe6b9SJerome Glisse struct drm_display_mode *mode, 2055771fe6b9SJerome Glisse struct drm_display_mode *adjusted_mode, 2056771fe6b9SJerome Glisse int x, int y, struct drm_framebuffer *old_fb) 2057771fe6b9SJerome Glisse { 2058771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 2059771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 2060771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 20615df3196bSAlex Deucher struct radeon_encoder *radeon_encoder = 20625df3196bSAlex Deucher to_radeon_encoder(radeon_crtc->encoder); 206354bfe496SAlex Deucher bool is_tvcv = false; 2064771fe6b9SJerome Glisse 206554bfe496SAlex Deucher if (radeon_encoder->active_device & 206654bfe496SAlex Deucher (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) 206754bfe496SAlex Deucher is_tvcv = true; 2068771fe6b9SJerome Glisse 2069cde10122SChristian König if (!radeon_crtc->adjusted_clock) 2070cde10122SChristian König return -EINVAL; 2071cde10122SChristian König 2072771fe6b9SJerome Glisse atombios_crtc_set_pll(crtc, adjusted_mode); 2073771fe6b9SJerome Glisse 207454bfe496SAlex Deucher if (ASIC_IS_DCE4(rdev)) 2075bcc1c2a1SAlex Deucher atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 207654bfe496SAlex Deucher else if (ASIC_IS_AVIVO(rdev)) { 207754bfe496SAlex Deucher if (is_tvcv) 207854bfe496SAlex Deucher atombios_crtc_set_timing(crtc, adjusted_mode); 207954bfe496SAlex Deucher else 208054bfe496SAlex Deucher atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 208154bfe496SAlex Deucher } else { 2082bcc1c2a1SAlex Deucher atombios_crtc_set_timing(crtc, adjusted_mode); 20835a9bcaccSAlex Deucher if (radeon_crtc->crtc_id == 0) 20845a9bcaccSAlex Deucher atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 2085615e0cb6SAlex Deucher radeon_legacy_atom_fixup(crtc); 2086771fe6b9SJerome Glisse } 2087bcc1c2a1SAlex Deucher atombios_crtc_set_base(crtc, x, y, old_fb); 2088c93bb85bSJerome Glisse atombios_overscan_setup(crtc, mode, adjusted_mode); 2089c93bb85bSJerome Glisse atombios_scaler_setup(crtc); 20906d3759faSMichel Dänzer radeon_cursor_reset(crtc); 209166edc1c9SAlex Deucher /* update the hw version fpr dpm */ 209266edc1c9SAlex Deucher radeon_crtc->hw_mode = *adjusted_mode; 209366edc1c9SAlex Deucher 2094771fe6b9SJerome Glisse return 0; 2095771fe6b9SJerome Glisse } 2096771fe6b9SJerome Glisse 2097771fe6b9SJerome Glisse static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, 2098e811f5aeSLaurent Pinchart const struct drm_display_mode *mode, 2099771fe6b9SJerome Glisse struct drm_display_mode *adjusted_mode) 2100771fe6b9SJerome Glisse { 21015df3196bSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 21025df3196bSAlex Deucher struct drm_device *dev = crtc->dev; 21035df3196bSAlex Deucher struct drm_encoder *encoder; 21045df3196bSAlex Deucher 21055df3196bSAlex Deucher /* assign the encoder to the radeon crtc to avoid repeated lookups later */ 21065df3196bSAlex Deucher list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 21075df3196bSAlex Deucher if (encoder->crtc == crtc) { 21085df3196bSAlex Deucher radeon_crtc->encoder = encoder; 210957b35e29SAlex Deucher radeon_crtc->connector = radeon_get_connector_for_encoder(encoder); 21105df3196bSAlex Deucher break; 21115df3196bSAlex Deucher } 21125df3196bSAlex Deucher } 211357b35e29SAlex Deucher if ((radeon_crtc->encoder == NULL) || (radeon_crtc->connector == NULL)) { 211457b35e29SAlex Deucher radeon_crtc->encoder = NULL; 211557b35e29SAlex Deucher radeon_crtc->connector = NULL; 21165df3196bSAlex Deucher return false; 211757b35e29SAlex Deucher } 2118643b1f56SAlex Deucher if (radeon_crtc->encoder) { 2119643b1f56SAlex Deucher struct radeon_encoder *radeon_encoder = 2120643b1f56SAlex Deucher to_radeon_encoder(radeon_crtc->encoder); 2121643b1f56SAlex Deucher 2122643b1f56SAlex Deucher radeon_crtc->output_csc = radeon_encoder->output_csc; 2123643b1f56SAlex Deucher } 2124c93bb85bSJerome Glisse if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) 2125c93bb85bSJerome Glisse return false; 212619eca43eSAlex Deucher if (!atombios_crtc_prepare_pll(crtc, adjusted_mode)) 212719eca43eSAlex Deucher return false; 2128c0fd0834SAlex Deucher /* pick pll */ 2129c0fd0834SAlex Deucher radeon_crtc->pll_id = radeon_atom_pick_pll(crtc); 2130c0fd0834SAlex Deucher /* if we can't get a PPLL for a non-DP encoder, fail */ 2131c0fd0834SAlex Deucher if ((radeon_crtc->pll_id == ATOM_PPLL_INVALID) && 2132c0fd0834SAlex Deucher !ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) 2133c0fd0834SAlex Deucher return false; 2134c0fd0834SAlex Deucher 2135771fe6b9SJerome Glisse return true; 2136771fe6b9SJerome Glisse } 2137771fe6b9SJerome Glisse 2138771fe6b9SJerome Glisse static void atombios_crtc_prepare(struct drm_crtc *crtc) 2139771fe6b9SJerome Glisse { 21406c0ae2abSAlex Deucher struct drm_device *dev = crtc->dev; 21416c0ae2abSAlex Deucher struct radeon_device *rdev = dev->dev_private; 2142267364acSAlex Deucher 21436c0ae2abSAlex Deucher /* disable crtc pair power gating before programming */ 21446c0ae2abSAlex Deucher if (ASIC_IS_DCE6(rdev)) 21456c0ae2abSAlex Deucher atombios_powergate_crtc(crtc, ATOM_DISABLE); 21466c0ae2abSAlex Deucher 214737b4390eSAlex Deucher atombios_lock_crtc(crtc, ATOM_ENABLE); 2148a348c84dSAlex Deucher atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 2149771fe6b9SJerome Glisse } 2150771fe6b9SJerome Glisse 2151771fe6b9SJerome Glisse static void atombios_crtc_commit(struct drm_crtc *crtc) 2152771fe6b9SJerome Glisse { 2153771fe6b9SJerome Glisse atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON); 215437b4390eSAlex Deucher atombios_lock_crtc(crtc, ATOM_DISABLE); 2155771fe6b9SJerome Glisse } 2156771fe6b9SJerome Glisse 215737f9003bSAlex Deucher static void atombios_crtc_disable(struct drm_crtc *crtc) 215837f9003bSAlex Deucher { 215937f9003bSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 216064199870SAlex Deucher struct drm_device *dev = crtc->dev; 216164199870SAlex Deucher struct radeon_device *rdev = dev->dev_private; 21628e8e523dSAlex Deucher struct radeon_atom_ss ss; 21634e58591cSAlex Deucher int i; 21648e8e523dSAlex Deucher 216537f9003bSAlex Deucher atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 2166f4510a27SMatt Roper if (crtc->primary->fb) { 216775b871e2SIlija Hadzic int r; 216875b871e2SIlija Hadzic struct radeon_bo *rbo; 216975b871e2SIlija Hadzic 21709a0f0c9dSDaniel Stone rbo = gem_to_radeon_bo(crtc->primary->fb->obj[0]); 217175b871e2SIlija Hadzic r = radeon_bo_reserve(rbo, false); 217275b871e2SIlija Hadzic if (unlikely(r)) 217375b871e2SIlija Hadzic DRM_ERROR("failed to reserve rbo before unpin\n"); 217475b871e2SIlija Hadzic else { 217575b871e2SIlija Hadzic radeon_bo_unpin(rbo); 217675b871e2SIlija Hadzic radeon_bo_unreserve(rbo); 217775b871e2SIlija Hadzic } 217875b871e2SIlija Hadzic } 2179ac4d04d4SAlex Deucher /* disable the GRPH */ 2180ac4d04d4SAlex Deucher if (ASIC_IS_DCE4(rdev)) 2181ac4d04d4SAlex Deucher WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 0); 2182ac4d04d4SAlex Deucher else if (ASIC_IS_AVIVO(rdev)) 2183ac4d04d4SAlex Deucher WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 0); 2184ac4d04d4SAlex Deucher 21850e3d50bfSAlex Deucher if (ASIC_IS_DCE6(rdev)) 21860e3d50bfSAlex Deucher atombios_powergate_crtc(crtc, ATOM_ENABLE); 218737f9003bSAlex Deucher 21884e58591cSAlex Deucher for (i = 0; i < rdev->num_crtc; i++) { 21894e58591cSAlex Deucher if (rdev->mode_info.crtcs[i] && 21904e58591cSAlex Deucher rdev->mode_info.crtcs[i]->enabled && 21914e58591cSAlex Deucher i != radeon_crtc->crtc_id && 21924e58591cSAlex Deucher radeon_crtc->pll_id == rdev->mode_info.crtcs[i]->pll_id) { 21934e58591cSAlex Deucher /* one other crtc is using this pll don't turn 21944e58591cSAlex Deucher * off the pll 21954e58591cSAlex Deucher */ 21964e58591cSAlex Deucher goto done; 21974e58591cSAlex Deucher } 21984e58591cSAlex Deucher } 21994e58591cSAlex Deucher 220037f9003bSAlex Deucher switch (radeon_crtc->pll_id) { 220137f9003bSAlex Deucher case ATOM_PPLL1: 220237f9003bSAlex Deucher case ATOM_PPLL2: 220337f9003bSAlex Deucher /* disable the ppll */ 220437f9003bSAlex Deucher atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, 22058e8e523dSAlex Deucher 0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss); 220637f9003bSAlex Deucher break; 220764199870SAlex Deucher case ATOM_PPLL0: 220864199870SAlex Deucher /* disable the ppll */ 22097eeeabfcSAlex Deucher if ((rdev->family == CHIP_ARUBA) || 2210fbedf1c3SAlex Deucher (rdev->family == CHIP_KAVERI) || 22117eeeabfcSAlex Deucher (rdev->family == CHIP_BONAIRE) || 22127eeeabfcSAlex Deucher (rdev->family == CHIP_HAWAII)) 221364199870SAlex Deucher atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, 221464199870SAlex Deucher 0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss); 221564199870SAlex Deucher break; 221637f9003bSAlex Deucher default: 221737f9003bSAlex Deucher break; 221837f9003bSAlex Deucher } 22194e58591cSAlex Deucher done: 2220f3dd8508SAlex Deucher radeon_crtc->pll_id = ATOM_PPLL_INVALID; 22219642ac0eSAlex Deucher radeon_crtc->adjusted_clock = 0; 22225df3196bSAlex Deucher radeon_crtc->encoder = NULL; 222357b35e29SAlex Deucher radeon_crtc->connector = NULL; 222437f9003bSAlex Deucher } 222537f9003bSAlex Deucher 2226771fe6b9SJerome Glisse static const struct drm_crtc_helper_funcs atombios_helper_funcs = { 2227771fe6b9SJerome Glisse .dpms = atombios_crtc_dpms, 2228771fe6b9SJerome Glisse .mode_fixup = atombios_crtc_mode_fixup, 2229771fe6b9SJerome Glisse .mode_set = atombios_crtc_mode_set, 2230771fe6b9SJerome Glisse .mode_set_base = atombios_crtc_set_base, 22314dd19b0dSChris Ball .mode_set_base_atomic = atombios_crtc_set_base_atomic, 2232771fe6b9SJerome Glisse .prepare = atombios_crtc_prepare, 2233771fe6b9SJerome Glisse .commit = atombios_crtc_commit, 223437f9003bSAlex Deucher .disable = atombios_crtc_disable, 223527b4118dSThomas Zimmermann .get_scanout_position = radeon_get_crtc_scanout_position, 2236771fe6b9SJerome Glisse }; 2237771fe6b9SJerome Glisse 2238771fe6b9SJerome Glisse void radeon_atombios_init_crtc(struct drm_device *dev, 2239771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc) 2240771fe6b9SJerome Glisse { 2241bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 2242bcc1c2a1SAlex Deucher 2243bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) { 2244bcc1c2a1SAlex Deucher switch (radeon_crtc->crtc_id) { 2245bcc1c2a1SAlex Deucher case 0: 2246bcc1c2a1SAlex Deucher default: 224712d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC0_REGISTER_OFFSET; 2248bcc1c2a1SAlex Deucher break; 2249bcc1c2a1SAlex Deucher case 1: 225012d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC1_REGISTER_OFFSET; 2251bcc1c2a1SAlex Deucher break; 2252bcc1c2a1SAlex Deucher case 2: 225312d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC2_REGISTER_OFFSET; 2254bcc1c2a1SAlex Deucher break; 2255bcc1c2a1SAlex Deucher case 3: 225612d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC3_REGISTER_OFFSET; 2257bcc1c2a1SAlex Deucher break; 2258bcc1c2a1SAlex Deucher case 4: 225912d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC4_REGISTER_OFFSET; 2260bcc1c2a1SAlex Deucher break; 2261bcc1c2a1SAlex Deucher case 5: 226212d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC5_REGISTER_OFFSET; 2263bcc1c2a1SAlex Deucher break; 2264bcc1c2a1SAlex Deucher } 2265bcc1c2a1SAlex Deucher } else { 2266771fe6b9SJerome Glisse if (radeon_crtc->crtc_id == 1) 2267771fe6b9SJerome Glisse radeon_crtc->crtc_offset = 2268771fe6b9SJerome Glisse AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL; 2269bcc1c2a1SAlex Deucher else 2270bcc1c2a1SAlex Deucher radeon_crtc->crtc_offset = 0; 2271bcc1c2a1SAlex Deucher } 2272f3dd8508SAlex Deucher radeon_crtc->pll_id = ATOM_PPLL_INVALID; 22739642ac0eSAlex Deucher radeon_crtc->adjusted_clock = 0; 22745df3196bSAlex Deucher radeon_crtc->encoder = NULL; 227557b35e29SAlex Deucher radeon_crtc->connector = NULL; 2276771fe6b9SJerome Glisse drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); 2277771fe6b9SJerome Glisse } 2278