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> 31720cf96dSVille Syrjälä #include <drm/drm_framebuffer.h> 32c182615fSSam Ravnborg #include <drm/drm_vblank.h> 33c182615fSSam Ravnborg #include <drm/radeon_drm.h> 34c182615fSSam Ravnborg 35771fe6b9SJerome Glisse #include "radeon.h" 36771fe6b9SJerome Glisse #include "atom.h" 37771fe6b9SJerome Glisse #include "atom-bits.h" 38771fe6b9SJerome Glisse 39c93bb85bSJerome Glisse static void atombios_overscan_setup(struct drm_crtc *crtc, 40c93bb85bSJerome Glisse struct drm_display_mode *mode, 41c93bb85bSJerome Glisse struct drm_display_mode *adjusted_mode) 42c93bb85bSJerome Glisse { 43c93bb85bSJerome Glisse struct drm_device *dev = crtc->dev; 44c93bb85bSJerome Glisse struct radeon_device *rdev = dev->dev_private; 45c93bb85bSJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 46c93bb85bSJerome Glisse SET_CRTC_OVERSCAN_PS_ALLOCATION args; 47c93bb85bSJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan); 48c93bb85bSJerome Glisse int a1, a2; 49c93bb85bSJerome Glisse 50c93bb85bSJerome Glisse memset(&args, 0, sizeof(args)); 51c93bb85bSJerome Glisse 52c93bb85bSJerome Glisse args.ucCRTC = radeon_crtc->crtc_id; 53c93bb85bSJerome Glisse 54c93bb85bSJerome Glisse switch (radeon_crtc->rmx_type) { 55c93bb85bSJerome Glisse case RMX_CENTER: 564589433cSCédric Cano args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2); 574589433cSCédric Cano args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2); 584589433cSCédric Cano args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2); 594589433cSCédric Cano args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2); 60c93bb85bSJerome Glisse break; 61c93bb85bSJerome Glisse case RMX_ASPECT: 62c93bb85bSJerome Glisse a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay; 63c93bb85bSJerome Glisse a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay; 64c93bb85bSJerome Glisse 65c93bb85bSJerome Glisse if (a1 > a2) { 664589433cSCédric Cano args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2); 674589433cSCédric Cano args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2); 68c93bb85bSJerome Glisse } else if (a2 > a1) { 69942b0e95SAlex Deucher args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2); 70942b0e95SAlex Deucher args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2); 71c93bb85bSJerome Glisse } 72c93bb85bSJerome Glisse break; 73c93bb85bSJerome Glisse case RMX_FULL: 74c93bb85bSJerome Glisse default: 754589433cSCédric Cano args.usOverscanRight = cpu_to_le16(radeon_crtc->h_border); 764589433cSCédric Cano args.usOverscanLeft = cpu_to_le16(radeon_crtc->h_border); 774589433cSCédric Cano args.usOverscanBottom = cpu_to_le16(radeon_crtc->v_border); 784589433cSCédric Cano args.usOverscanTop = cpu_to_le16(radeon_crtc->v_border); 79c93bb85bSJerome Glisse break; 80c93bb85bSJerome Glisse } 815b1714d3SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 82c93bb85bSJerome Glisse } 83c93bb85bSJerome Glisse 84c93bb85bSJerome Glisse static void atombios_scaler_setup(struct drm_crtc *crtc) 85c93bb85bSJerome Glisse { 86c93bb85bSJerome Glisse struct drm_device *dev = crtc->dev; 87c93bb85bSJerome Glisse struct radeon_device *rdev = dev->dev_private; 88c93bb85bSJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 89c93bb85bSJerome Glisse ENABLE_SCALER_PS_ALLOCATION args; 90c93bb85bSJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, EnableScaler); 915df3196bSAlex Deucher struct radeon_encoder *radeon_encoder = 925df3196bSAlex Deucher to_radeon_encoder(radeon_crtc->encoder); 93c93bb85bSJerome Glisse /* fixme - fill in enc_priv for atom dac */ 94c93bb85bSJerome Glisse enum radeon_tv_std tv_std = TV_STD_NTSC; 954ce001abSDave Airlie bool is_tv = false, is_cv = false; 96c93bb85bSJerome Glisse 97c93bb85bSJerome Glisse if (!ASIC_IS_AVIVO(rdev) && radeon_crtc->crtc_id) 98c93bb85bSJerome Glisse return; 99c93bb85bSJerome Glisse 1004ce001abSDave Airlie if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) { 1014ce001abSDave Airlie struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv; 1024ce001abSDave Airlie tv_std = tv_dac->tv_std; 1034ce001abSDave Airlie is_tv = true; 1044ce001abSDave Airlie } 1054ce001abSDave Airlie 106c93bb85bSJerome Glisse memset(&args, 0, sizeof(args)); 107c93bb85bSJerome Glisse 108c93bb85bSJerome Glisse args.ucScaler = radeon_crtc->crtc_id; 109c93bb85bSJerome Glisse 1104ce001abSDave Airlie if (is_tv) { 111c93bb85bSJerome Glisse switch (tv_std) { 112c93bb85bSJerome Glisse case TV_STD_NTSC: 113c93bb85bSJerome Glisse default: 114c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_NTSC; 115c93bb85bSJerome Glisse break; 116c93bb85bSJerome Glisse case TV_STD_PAL: 117c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_PAL; 118c93bb85bSJerome Glisse break; 119c93bb85bSJerome Glisse case TV_STD_PAL_M: 120c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_PALM; 121c93bb85bSJerome Glisse break; 122c93bb85bSJerome Glisse case TV_STD_PAL_60: 123c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_PAL60; 124c93bb85bSJerome Glisse break; 125c93bb85bSJerome Glisse case TV_STD_NTSC_J: 126c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_NTSCJ; 127c93bb85bSJerome Glisse break; 128c93bb85bSJerome Glisse case TV_STD_SCART_PAL: 129c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_PAL; /* ??? */ 130c93bb85bSJerome Glisse break; 131c93bb85bSJerome Glisse case TV_STD_SECAM: 132c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_SECAM; 133c93bb85bSJerome Glisse break; 134c93bb85bSJerome Glisse case TV_STD_PAL_CN: 135c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_PALCN; 136c93bb85bSJerome Glisse break; 137c93bb85bSJerome Glisse } 138c93bb85bSJerome Glisse args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; 1394ce001abSDave Airlie } else if (is_cv) { 140c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_CV; 141c93bb85bSJerome Glisse args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; 142c93bb85bSJerome Glisse } else { 143c93bb85bSJerome Glisse switch (radeon_crtc->rmx_type) { 144c93bb85bSJerome Glisse case RMX_FULL: 145c93bb85bSJerome Glisse args.ucEnable = ATOM_SCALER_EXPANSION; 146c93bb85bSJerome Glisse break; 147c93bb85bSJerome Glisse case RMX_CENTER: 148c93bb85bSJerome Glisse args.ucEnable = ATOM_SCALER_CENTER; 149c93bb85bSJerome Glisse break; 150c93bb85bSJerome Glisse case RMX_ASPECT: 151c93bb85bSJerome Glisse args.ucEnable = ATOM_SCALER_EXPANSION; 152c93bb85bSJerome Glisse break; 153c93bb85bSJerome Glisse default: 154c93bb85bSJerome Glisse if (ASIC_IS_AVIVO(rdev)) 155c93bb85bSJerome Glisse args.ucEnable = ATOM_SCALER_DISABLE; 156c93bb85bSJerome Glisse else 157c93bb85bSJerome Glisse args.ucEnable = ATOM_SCALER_CENTER; 158c93bb85bSJerome Glisse break; 159c93bb85bSJerome Glisse } 160c93bb85bSJerome Glisse } 161c93bb85bSJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 1624ce001abSDave Airlie if ((is_tv || is_cv) 1634ce001abSDave Airlie && rdev->family >= CHIP_RV515 && rdev->family <= CHIP_R580) { 1644ce001abSDave Airlie atom_rv515_force_tv_scaler(rdev, radeon_crtc); 165c93bb85bSJerome Glisse } 166c93bb85bSJerome Glisse } 167c93bb85bSJerome Glisse 168771fe6b9SJerome Glisse static void atombios_lock_crtc(struct drm_crtc *crtc, int lock) 169771fe6b9SJerome Glisse { 170771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 171771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 172771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 173771fe6b9SJerome Glisse int index = 174771fe6b9SJerome Glisse GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters); 175771fe6b9SJerome Glisse ENABLE_CRTC_PS_ALLOCATION args; 176771fe6b9SJerome Glisse 177771fe6b9SJerome Glisse memset(&args, 0, sizeof(args)); 178771fe6b9SJerome Glisse 179771fe6b9SJerome Glisse args.ucCRTC = radeon_crtc->crtc_id; 180771fe6b9SJerome Glisse args.ucEnable = lock; 181771fe6b9SJerome Glisse 182771fe6b9SJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 183771fe6b9SJerome Glisse } 184771fe6b9SJerome Glisse 185771fe6b9SJerome Glisse static void atombios_enable_crtc(struct drm_crtc *crtc, int state) 186771fe6b9SJerome Glisse { 187771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 188771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 189771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 190771fe6b9SJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC); 191771fe6b9SJerome Glisse ENABLE_CRTC_PS_ALLOCATION args; 192771fe6b9SJerome Glisse 193771fe6b9SJerome Glisse memset(&args, 0, sizeof(args)); 194771fe6b9SJerome Glisse 195771fe6b9SJerome Glisse args.ucCRTC = radeon_crtc->crtc_id; 196771fe6b9SJerome Glisse args.ucEnable = state; 197771fe6b9SJerome Glisse 198771fe6b9SJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 199771fe6b9SJerome Glisse } 200771fe6b9SJerome Glisse 201771fe6b9SJerome Glisse static void atombios_enable_crtc_memreq(struct drm_crtc *crtc, int state) 202771fe6b9SJerome Glisse { 203771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 204771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 205771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 206771fe6b9SJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, EnableCRTCMemReq); 207771fe6b9SJerome Glisse ENABLE_CRTC_PS_ALLOCATION args; 208771fe6b9SJerome Glisse 209771fe6b9SJerome Glisse memset(&args, 0, sizeof(args)); 210771fe6b9SJerome Glisse 211771fe6b9SJerome Glisse args.ucCRTC = radeon_crtc->crtc_id; 212771fe6b9SJerome Glisse args.ucEnable = state; 213771fe6b9SJerome Glisse 214771fe6b9SJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 215771fe6b9SJerome Glisse } 216771fe6b9SJerome Glisse 21778fe9e54SAlex Deucher static const u32 vga_control_regs[6] = 21878fe9e54SAlex Deucher { 21978fe9e54SAlex Deucher AVIVO_D1VGA_CONTROL, 22078fe9e54SAlex Deucher AVIVO_D2VGA_CONTROL, 22178fe9e54SAlex Deucher EVERGREEN_D3VGA_CONTROL, 22278fe9e54SAlex Deucher EVERGREEN_D4VGA_CONTROL, 22378fe9e54SAlex Deucher EVERGREEN_D5VGA_CONTROL, 22478fe9e54SAlex Deucher EVERGREEN_D6VGA_CONTROL, 22578fe9e54SAlex Deucher }; 22678fe9e54SAlex Deucher 227771fe6b9SJerome Glisse static void atombios_blank_crtc(struct drm_crtc *crtc, int state) 228771fe6b9SJerome Glisse { 229771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 230771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 231771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 232771fe6b9SJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC); 233771fe6b9SJerome Glisse BLANK_CRTC_PS_ALLOCATION args; 23478fe9e54SAlex Deucher u32 vga_control = 0; 235771fe6b9SJerome Glisse 236771fe6b9SJerome Glisse memset(&args, 0, sizeof(args)); 237771fe6b9SJerome Glisse 23878fe9e54SAlex Deucher if (ASIC_IS_DCE8(rdev)) { 23978fe9e54SAlex Deucher vga_control = RREG32(vga_control_regs[radeon_crtc->crtc_id]); 24078fe9e54SAlex Deucher WREG32(vga_control_regs[radeon_crtc->crtc_id], vga_control | 1); 24178fe9e54SAlex Deucher } 24278fe9e54SAlex Deucher 243771fe6b9SJerome Glisse args.ucCRTC = radeon_crtc->crtc_id; 244771fe6b9SJerome Glisse args.ucBlanking = state; 245771fe6b9SJerome Glisse 246771fe6b9SJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 24778fe9e54SAlex Deucher 2483c20d544SWambui Karuga if (ASIC_IS_DCE8(rdev)) 24978fe9e54SAlex Deucher WREG32(vga_control_regs[radeon_crtc->crtc_id], vga_control); 25078fe9e54SAlex Deucher } 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 620ba032a58SAlex Deucher /* use recommended ref_div for ss */ 621ba032a58SAlex Deucher if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 62219eca43eSAlex Deucher if (radeon_crtc->ss_enabled) { 62319eca43eSAlex Deucher if (radeon_crtc->ss.refdiv) { 62419eca43eSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV; 62519eca43eSAlex Deucher radeon_crtc->pll_reference_div = radeon_crtc->ss.refdiv; 626ae5b80d2SChristian König if (ASIC_IS_AVIVO(rdev) && 627ae5b80d2SChristian König rdev->family != CHIP_RS780 && 628ae5b80d2SChristian König rdev->family != CHIP_RS880) 62919eca43eSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; 630ba032a58SAlex Deucher } 631ba032a58SAlex Deucher } 632ba032a58SAlex Deucher } 6335b40ddf8SAlex Deucher 6344eaeca33SAlex Deucher if (ASIC_IS_AVIVO(rdev)) { 6354eaeca33SAlex Deucher /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ 6364eaeca33SAlex Deucher if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1) 6374eaeca33SAlex Deucher adjusted_clock = mode->clock * 2; 63848dfaaebSAlex Deucher if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 63919eca43eSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_PREFER_CLOSEST_LOWER; 640619efb10SAlex Deucher if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) 64119eca43eSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_IS_LCD; 6424eaeca33SAlex Deucher } else { 6434eaeca33SAlex Deucher if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) 64419eca43eSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_NO_ODD_POST_DIV; 6454eaeca33SAlex Deucher if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) 64619eca43eSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV; 647771fe6b9SJerome Glisse } 648771fe6b9SJerome Glisse 649f71d9ebdSAlex Deucher /* adjust pll for deep color modes */ 650f71d9ebdSAlex Deucher if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { 651f71d9ebdSAlex Deucher switch (bpc) { 652f71d9ebdSAlex Deucher case 8: 653f71d9ebdSAlex Deucher default: 654f71d9ebdSAlex Deucher break; 655f71d9ebdSAlex Deucher case 10: 656f71d9ebdSAlex Deucher clock = (clock * 5) / 4; 657f71d9ebdSAlex Deucher break; 658f71d9ebdSAlex Deucher case 12: 659f71d9ebdSAlex Deucher clock = (clock * 3) / 2; 660f71d9ebdSAlex Deucher break; 661f71d9ebdSAlex Deucher case 16: 662f71d9ebdSAlex Deucher clock = clock * 2; 663f71d9ebdSAlex Deucher break; 664f71d9ebdSAlex Deucher } 665f71d9ebdSAlex Deucher } 666f71d9ebdSAlex Deucher 6672606c886SAlex Deucher /* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock 6682606c886SAlex Deucher * accordingly based on the encoder/transmitter to work around 6692606c886SAlex Deucher * special hw requirements. 6702606c886SAlex Deucher */ 6712606c886SAlex Deucher if (ASIC_IS_DCE3(rdev)) { 6724eaeca33SAlex Deucher union adjust_pixel_clock args; 6734eaeca33SAlex Deucher u8 frev, crev; 6744eaeca33SAlex Deucher int index; 6752606c886SAlex Deucher 6762606c886SAlex Deucher index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll); 677a084e6eeSAlex Deucher if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 678a084e6eeSAlex Deucher &crev)) 679a084e6eeSAlex Deucher return adjusted_clock; 6804eaeca33SAlex Deucher 6814eaeca33SAlex Deucher memset(&args, 0, sizeof(args)); 6824eaeca33SAlex Deucher 6834eaeca33SAlex Deucher switch (frev) { 6844eaeca33SAlex Deucher case 1: 6854eaeca33SAlex Deucher switch (crev) { 6864eaeca33SAlex Deucher case 1: 6874eaeca33SAlex Deucher case 2: 688f71d9ebdSAlex Deucher args.v1.usPixelClock = cpu_to_le16(clock / 10); 6894eaeca33SAlex Deucher args.v1.ucTransmitterID = radeon_encoder->encoder_id; 690bcc1c2a1SAlex Deucher args.v1.ucEncodeMode = encoder_mode; 69119eca43eSAlex Deucher if (radeon_crtc->ss_enabled && radeon_crtc->ss.percentage) 692ba032a58SAlex Deucher args.v1.ucConfig |= 693ba032a58SAlex Deucher ADJUST_DISPLAY_CONFIG_SS_ENABLE; 6944eaeca33SAlex Deucher 6952606c886SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, 6964eaeca33SAlex Deucher index, (uint32_t *)&args); 6974eaeca33SAlex Deucher adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10; 6984eaeca33SAlex Deucher break; 699bcc1c2a1SAlex Deucher case 3: 700f71d9ebdSAlex Deucher args.v3.sInput.usPixelClock = cpu_to_le16(clock / 10); 701bcc1c2a1SAlex Deucher args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id; 702bcc1c2a1SAlex Deucher args.v3.sInput.ucEncodeMode = encoder_mode; 703bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig = 0; 70419eca43eSAlex Deucher if (radeon_crtc->ss_enabled && radeon_crtc->ss.percentage) 705ba032a58SAlex Deucher args.v3.sInput.ucDispPllConfig |= 706ba032a58SAlex Deucher DISPPLL_CONFIG_SS_ENABLE; 707996d5c59SAlex Deucher if (ENCODER_MODE_IS_DP(encoder_mode)) { 708bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 709bcc1c2a1SAlex Deucher DISPPLL_CONFIG_COHERENT_MODE; 710fbee67a6SAlex Deucher /* 16200 or 27000 */ 711fbee67a6SAlex Deucher args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); 712b4f15f80SAlex Deucher } else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { 713b4f15f80SAlex Deucher struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 714bcc1c2a1SAlex Deucher if (dig->coherent_mode) 715bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 716bcc1c2a1SAlex Deucher DISPPLL_CONFIG_COHERENT_MODE; 7179aa59993SAlex Deucher if (is_duallink) 718bcc1c2a1SAlex Deucher args.v3.sInput.ucDispPllConfig |= 719bcc1c2a1SAlex Deucher DISPPLL_CONFIG_DUAL_LINK; 720bcc1c2a1SAlex Deucher } 7211d33e1fcSAlex Deucher if (radeon_encoder_get_dp_bridge_encoder_id(encoder) != 7221d33e1fcSAlex Deucher ENCODER_OBJECT_ID_NONE) 7231d33e1fcSAlex Deucher args.v3.sInput.ucExtTransmitterID = 7241d33e1fcSAlex Deucher radeon_encoder_get_dp_bridge_encoder_id(encoder); 7251d33e1fcSAlex Deucher else 726cc9f67a0SAlex Deucher args.v3.sInput.ucExtTransmitterID = 0; 727cc9f67a0SAlex Deucher 728bcc1c2a1SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, 729bcc1c2a1SAlex Deucher index, (uint32_t *)&args); 730bcc1c2a1SAlex Deucher adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10; 731bcc1c2a1SAlex Deucher if (args.v3.sOutput.ucRefDiv) { 73219eca43eSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; 73319eca43eSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV; 73419eca43eSAlex Deucher radeon_crtc->pll_reference_div = args.v3.sOutput.ucRefDiv; 735bcc1c2a1SAlex Deucher } 736bcc1c2a1SAlex Deucher if (args.v3.sOutput.ucPostDiv) { 73719eca43eSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; 73819eca43eSAlex Deucher radeon_crtc->pll_flags |= RADEON_PLL_USE_POST_DIV; 73919eca43eSAlex Deucher radeon_crtc->pll_post_div = args.v3.sOutput.ucPostDiv; 740bcc1c2a1SAlex Deucher } 741bcc1c2a1SAlex Deucher break; 7424eaeca33SAlex Deucher default: 7434eaeca33SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 7444eaeca33SAlex Deucher return adjusted_clock; 745d56ef9c8SAlex Deucher } 7464eaeca33SAlex Deucher break; 7474eaeca33SAlex Deucher default: 7484eaeca33SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 7494eaeca33SAlex Deucher return adjusted_clock; 7504eaeca33SAlex Deucher } 7514eaeca33SAlex Deucher } 7524eaeca33SAlex Deucher return adjusted_clock; 7534eaeca33SAlex Deucher } 7544eaeca33SAlex Deucher 7554eaeca33SAlex Deucher union set_pixel_clock { 7564eaeca33SAlex Deucher SET_PIXEL_CLOCK_PS_ALLOCATION base; 7574eaeca33SAlex Deucher PIXEL_CLOCK_PARAMETERS v1; 7584eaeca33SAlex Deucher PIXEL_CLOCK_PARAMETERS_V2 v2; 7594eaeca33SAlex Deucher PIXEL_CLOCK_PARAMETERS_V3 v3; 760bcc1c2a1SAlex Deucher PIXEL_CLOCK_PARAMETERS_V5 v5; 761f82b3ddcSAlex Deucher PIXEL_CLOCK_PARAMETERS_V6 v6; 7624eaeca33SAlex Deucher }; 7634eaeca33SAlex Deucher 764f82b3ddcSAlex Deucher /* on DCE5, make sure the voltage is high enough to support the 765f82b3ddcSAlex Deucher * required disp clk. 766f82b3ddcSAlex Deucher */ 767f3f1f03eSAlex Deucher static void atombios_crtc_set_disp_eng_pll(struct radeon_device *rdev, 768f82b3ddcSAlex Deucher u32 dispclk) 769bcc1c2a1SAlex Deucher { 770bcc1c2a1SAlex Deucher u8 frev, crev; 771bcc1c2a1SAlex Deucher int index; 772bcc1c2a1SAlex Deucher union set_pixel_clock args; 773bcc1c2a1SAlex Deucher 774bcc1c2a1SAlex Deucher memset(&args, 0, sizeof(args)); 775bcc1c2a1SAlex Deucher 776bcc1c2a1SAlex Deucher index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); 777a084e6eeSAlex Deucher if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 778a084e6eeSAlex Deucher &crev)) 779a084e6eeSAlex Deucher return; 780bcc1c2a1SAlex Deucher 781bcc1c2a1SAlex Deucher switch (frev) { 782bcc1c2a1SAlex Deucher case 1: 783bcc1c2a1SAlex Deucher switch (crev) { 784bcc1c2a1SAlex Deucher case 5: 785bcc1c2a1SAlex Deucher /* if the default dcpll clock is specified, 786bcc1c2a1SAlex Deucher * SetPixelClock provides the dividers 787bcc1c2a1SAlex Deucher */ 788bcc1c2a1SAlex Deucher args.v5.ucCRTC = ATOM_CRTC_INVALID; 7894589433cSCédric Cano args.v5.usPixelClock = cpu_to_le16(dispclk); 790bcc1c2a1SAlex Deucher args.v5.ucPpll = ATOM_DCPLL; 791bcc1c2a1SAlex Deucher break; 792f82b3ddcSAlex Deucher case 6: 793f82b3ddcSAlex Deucher /* if the default dcpll clock is specified, 794f82b3ddcSAlex Deucher * SetPixelClock provides the dividers 795f82b3ddcSAlex Deucher */ 796265aa6c8SAlex Deucher args.v6.ulDispEngClkFreq = cpu_to_le32(dispclk); 7978542c12bSAlex Deucher if (ASIC_IS_DCE61(rdev) || ASIC_IS_DCE8(rdev)) 798729b95efSAlex Deucher args.v6.ucPpll = ATOM_EXT_PLL1; 799729b95efSAlex Deucher else if (ASIC_IS_DCE6(rdev)) 800f3f1f03eSAlex Deucher args.v6.ucPpll = ATOM_PPLL0; 801f3f1f03eSAlex Deucher else 802f82b3ddcSAlex Deucher args.v6.ucPpll = ATOM_DCPLL; 803f82b3ddcSAlex Deucher break; 804bcc1c2a1SAlex Deucher default: 805bcc1c2a1SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 806bcc1c2a1SAlex Deucher return; 807bcc1c2a1SAlex Deucher } 808bcc1c2a1SAlex Deucher break; 809bcc1c2a1SAlex Deucher default: 810bcc1c2a1SAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 811bcc1c2a1SAlex Deucher return; 812bcc1c2a1SAlex Deucher } 813bcc1c2a1SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 814bcc1c2a1SAlex Deucher } 815bcc1c2a1SAlex Deucher 81637f9003bSAlex Deucher static void atombios_crtc_program_pll(struct drm_crtc *crtc, 817f1bece7fSBenjamin Herrenschmidt u32 crtc_id, 81837f9003bSAlex Deucher int pll_id, 81937f9003bSAlex Deucher u32 encoder_mode, 82037f9003bSAlex Deucher u32 encoder_id, 82137f9003bSAlex Deucher u32 clock, 82237f9003bSAlex Deucher u32 ref_div, 82337f9003bSAlex Deucher u32 fb_div, 82437f9003bSAlex Deucher u32 frac_fb_div, 825df271becSAlex Deucher u32 post_div, 8268e8e523dSAlex Deucher int bpc, 8278e8e523dSAlex Deucher bool ss_enabled, 8288e8e523dSAlex Deucher struct radeon_atom_ss *ss) 82937f9003bSAlex Deucher { 83037f9003bSAlex Deucher struct drm_device *dev = crtc->dev; 83137f9003bSAlex Deucher struct radeon_device *rdev = dev->dev_private; 83237f9003bSAlex Deucher u8 frev, crev; 83337f9003bSAlex Deucher int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); 83437f9003bSAlex Deucher union set_pixel_clock args; 83537f9003bSAlex Deucher 83637f9003bSAlex Deucher memset(&args, 0, sizeof(args)); 83737f9003bSAlex Deucher 83837f9003bSAlex Deucher if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 83937f9003bSAlex Deucher &crev)) 84037f9003bSAlex Deucher return; 84137f9003bSAlex Deucher 84237f9003bSAlex Deucher switch (frev) { 84337f9003bSAlex Deucher case 1: 84437f9003bSAlex Deucher switch (crev) { 84537f9003bSAlex Deucher case 1: 84637f9003bSAlex Deucher if (clock == ATOM_DISABLE) 84737f9003bSAlex Deucher return; 84837f9003bSAlex Deucher args.v1.usPixelClock = cpu_to_le16(clock / 10); 84937f9003bSAlex Deucher args.v1.usRefDiv = cpu_to_le16(ref_div); 85037f9003bSAlex Deucher args.v1.usFbDiv = cpu_to_le16(fb_div); 85137f9003bSAlex Deucher args.v1.ucFracFbDiv = frac_fb_div; 85237f9003bSAlex Deucher args.v1.ucPostDiv = post_div; 85337f9003bSAlex Deucher args.v1.ucPpll = pll_id; 85437f9003bSAlex Deucher args.v1.ucCRTC = crtc_id; 85537f9003bSAlex Deucher args.v1.ucRefDivSrc = 1; 85637f9003bSAlex Deucher break; 85737f9003bSAlex Deucher case 2: 85837f9003bSAlex Deucher args.v2.usPixelClock = cpu_to_le16(clock / 10); 85937f9003bSAlex Deucher args.v2.usRefDiv = cpu_to_le16(ref_div); 86037f9003bSAlex Deucher args.v2.usFbDiv = cpu_to_le16(fb_div); 86137f9003bSAlex Deucher args.v2.ucFracFbDiv = frac_fb_div; 86237f9003bSAlex Deucher args.v2.ucPostDiv = post_div; 86337f9003bSAlex Deucher args.v2.ucPpll = pll_id; 86437f9003bSAlex Deucher args.v2.ucCRTC = crtc_id; 86537f9003bSAlex Deucher args.v2.ucRefDivSrc = 1; 86637f9003bSAlex Deucher break; 86737f9003bSAlex Deucher case 3: 86837f9003bSAlex Deucher args.v3.usPixelClock = cpu_to_le16(clock / 10); 86937f9003bSAlex Deucher args.v3.usRefDiv = cpu_to_le16(ref_div); 87037f9003bSAlex Deucher args.v3.usFbDiv = cpu_to_le16(fb_div); 87137f9003bSAlex Deucher args.v3.ucFracFbDiv = frac_fb_div; 87237f9003bSAlex Deucher args.v3.ucPostDiv = post_div; 87337f9003bSAlex Deucher args.v3.ucPpll = pll_id; 874e729586eSAlex Deucher if (crtc_id == ATOM_CRTC2) 875e729586eSAlex Deucher args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC2; 876e729586eSAlex Deucher else 877e729586eSAlex Deucher args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC1; 8786f15c506SAlex Deucher if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) 8796f15c506SAlex Deucher args.v3.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC; 88037f9003bSAlex Deucher args.v3.ucTransmitterId = encoder_id; 88137f9003bSAlex Deucher args.v3.ucEncoderMode = encoder_mode; 88237f9003bSAlex Deucher break; 88337f9003bSAlex Deucher case 5: 88437f9003bSAlex Deucher args.v5.ucCRTC = crtc_id; 88537f9003bSAlex Deucher args.v5.usPixelClock = cpu_to_le16(clock / 10); 88637f9003bSAlex Deucher args.v5.ucRefDiv = ref_div; 88737f9003bSAlex Deucher args.v5.usFbDiv = cpu_to_le16(fb_div); 88837f9003bSAlex Deucher args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); 88937f9003bSAlex Deucher args.v5.ucPostDiv = post_div; 89037f9003bSAlex Deucher args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */ 8918e8e523dSAlex Deucher if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) 8928e8e523dSAlex Deucher args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_REF_DIV_SRC; 8937d5ab300SAlex Deucher if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { 894df271becSAlex Deucher switch (bpc) { 895df271becSAlex Deucher case 8: 896df271becSAlex Deucher default: 897df271becSAlex Deucher args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP; 898df271becSAlex Deucher break; 899df271becSAlex Deucher case 10: 900f71d9ebdSAlex Deucher /* yes this is correct, the atom define is wrong */ 901f71d9ebdSAlex Deucher args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_32BPP; 902f71d9ebdSAlex Deucher break; 903f71d9ebdSAlex Deucher case 12: 904f71d9ebdSAlex Deucher /* yes this is correct, the atom define is wrong */ 905df271becSAlex Deucher args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP; 906df271becSAlex Deucher break; 907df271becSAlex Deucher } 9087d5ab300SAlex Deucher } 90937f9003bSAlex Deucher args.v5.ucTransmitterID = encoder_id; 91037f9003bSAlex Deucher args.v5.ucEncoderMode = encoder_mode; 91137f9003bSAlex Deucher args.v5.ucPpll = pll_id; 91237f9003bSAlex Deucher break; 913f82b3ddcSAlex Deucher case 6: 914f1bece7fSBenjamin Herrenschmidt args.v6.ulDispEngClkFreq = cpu_to_le32(crtc_id << 24 | clock / 10); 915f82b3ddcSAlex Deucher args.v6.ucRefDiv = ref_div; 916f82b3ddcSAlex Deucher args.v6.usFbDiv = cpu_to_le16(fb_div); 917f82b3ddcSAlex Deucher args.v6.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); 918f82b3ddcSAlex Deucher args.v6.ucPostDiv = post_div; 919f82b3ddcSAlex Deucher args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */ 9208e8e523dSAlex Deucher if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) 9218e8e523dSAlex Deucher args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_REF_DIV_SRC; 9227d5ab300SAlex Deucher if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { 923df271becSAlex Deucher switch (bpc) { 924df271becSAlex Deucher case 8: 925df271becSAlex Deucher default: 926df271becSAlex Deucher args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP; 927df271becSAlex Deucher break; 928df271becSAlex Deucher case 10: 929f71d9ebdSAlex Deucher args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP_V6; 930df271becSAlex Deucher break; 931df271becSAlex Deucher case 12: 932f71d9ebdSAlex Deucher args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP_V6; 933df271becSAlex Deucher break; 934df271becSAlex Deucher case 16: 935df271becSAlex Deucher args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP; 936df271becSAlex Deucher break; 937df271becSAlex Deucher } 9387d5ab300SAlex Deucher } 939f82b3ddcSAlex Deucher args.v6.ucTransmitterID = encoder_id; 940f82b3ddcSAlex Deucher args.v6.ucEncoderMode = encoder_mode; 941f82b3ddcSAlex Deucher args.v6.ucPpll = pll_id; 942f82b3ddcSAlex Deucher break; 94337f9003bSAlex Deucher default: 94437f9003bSAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 94537f9003bSAlex Deucher return; 94637f9003bSAlex Deucher } 94737f9003bSAlex Deucher break; 94837f9003bSAlex Deucher default: 94937f9003bSAlex Deucher DRM_ERROR("Unknown table version %d %d\n", frev, crev); 95037f9003bSAlex Deucher return; 95137f9003bSAlex Deucher } 95237f9003bSAlex Deucher 95337f9003bSAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 95437f9003bSAlex Deucher } 95537f9003bSAlex Deucher 95619eca43eSAlex Deucher static bool atombios_crtc_prepare_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) 95719eca43eSAlex Deucher { 95819eca43eSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 95919eca43eSAlex Deucher struct drm_device *dev = crtc->dev; 96019eca43eSAlex Deucher struct radeon_device *rdev = dev->dev_private; 9615df3196bSAlex Deucher struct radeon_encoder *radeon_encoder = 9625df3196bSAlex Deucher to_radeon_encoder(radeon_crtc->encoder); 9635df3196bSAlex Deucher int encoder_mode = atombios_get_encoder_mode(radeon_crtc->encoder); 96419eca43eSAlex Deucher 96519eca43eSAlex Deucher radeon_crtc->bpc = 8; 96619eca43eSAlex Deucher radeon_crtc->ss_enabled = false; 96719eca43eSAlex Deucher 968*01ad1d9cSLyude Paul if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) || 9695df3196bSAlex Deucher (radeon_encoder_get_dp_bridge_encoder_id(radeon_crtc->encoder) != ENCODER_OBJECT_ID_NONE)) { 97019eca43eSAlex Deucher struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 97119eca43eSAlex Deucher struct drm_connector *connector = 9725df3196bSAlex Deucher radeon_get_connector_for_encoder(radeon_crtc->encoder); 97319eca43eSAlex Deucher struct radeon_connector *radeon_connector = 97419eca43eSAlex Deucher to_radeon_connector(connector); 97519eca43eSAlex Deucher struct radeon_connector_atom_dig *dig_connector = 97619eca43eSAlex Deucher radeon_connector->con_priv; 97719eca43eSAlex Deucher int dp_clock; 978ea292861SMario Kleiner 979ea292861SMario Kleiner /* Assign mode clock for hdmi deep color max clock limit check */ 980ea292861SMario Kleiner radeon_connector->pixelclock_for_modeset = mode->clock; 98119eca43eSAlex Deucher radeon_crtc->bpc = radeon_get_monitor_bpc(connector); 98219eca43eSAlex Deucher 98319eca43eSAlex Deucher switch (encoder_mode) { 98419eca43eSAlex Deucher case ATOM_ENCODER_MODE_DP_MST: 98519eca43eSAlex Deucher case ATOM_ENCODER_MODE_DP: 98619eca43eSAlex Deucher /* DP/eDP */ 98719eca43eSAlex Deucher dp_clock = dig_connector->dp_clock / 10; 98819eca43eSAlex Deucher if (ASIC_IS_DCE4(rdev)) 98919eca43eSAlex Deucher radeon_crtc->ss_enabled = 99019eca43eSAlex Deucher radeon_atombios_get_asic_ss_info(rdev, &radeon_crtc->ss, 99119eca43eSAlex Deucher ASIC_INTERNAL_SS_ON_DP, 99219eca43eSAlex Deucher dp_clock); 99319eca43eSAlex Deucher else { 99419eca43eSAlex Deucher if (dp_clock == 16200) { 99519eca43eSAlex Deucher radeon_crtc->ss_enabled = 99619eca43eSAlex Deucher radeon_atombios_get_ppll_ss_info(rdev, 99719eca43eSAlex Deucher &radeon_crtc->ss, 99819eca43eSAlex Deucher ATOM_DP_SS_ID2); 99919eca43eSAlex Deucher if (!radeon_crtc->ss_enabled) 100019eca43eSAlex Deucher radeon_crtc->ss_enabled = 100119eca43eSAlex Deucher radeon_atombios_get_ppll_ss_info(rdev, 100219eca43eSAlex Deucher &radeon_crtc->ss, 100319eca43eSAlex Deucher ATOM_DP_SS_ID1); 1004d8e24525SAlex Deucher } else { 100519eca43eSAlex Deucher radeon_crtc->ss_enabled = 100619eca43eSAlex Deucher radeon_atombios_get_ppll_ss_info(rdev, 100719eca43eSAlex Deucher &radeon_crtc->ss, 100819eca43eSAlex Deucher ATOM_DP_SS_ID1); 100919eca43eSAlex Deucher } 1010d8e24525SAlex Deucher /* disable spread spectrum on DCE3 DP */ 1011d8e24525SAlex Deucher radeon_crtc->ss_enabled = false; 1012d8e24525SAlex Deucher } 101319eca43eSAlex Deucher break; 101419eca43eSAlex Deucher case ATOM_ENCODER_MODE_LVDS: 101519eca43eSAlex Deucher if (ASIC_IS_DCE4(rdev)) 101619eca43eSAlex Deucher radeon_crtc->ss_enabled = 101719eca43eSAlex Deucher radeon_atombios_get_asic_ss_info(rdev, 101819eca43eSAlex Deucher &radeon_crtc->ss, 101919eca43eSAlex Deucher dig->lcd_ss_id, 102019eca43eSAlex Deucher mode->clock / 10); 102119eca43eSAlex Deucher else 102219eca43eSAlex Deucher radeon_crtc->ss_enabled = 102319eca43eSAlex Deucher radeon_atombios_get_ppll_ss_info(rdev, 102419eca43eSAlex Deucher &radeon_crtc->ss, 102519eca43eSAlex Deucher dig->lcd_ss_id); 102619eca43eSAlex Deucher break; 102719eca43eSAlex Deucher case ATOM_ENCODER_MODE_DVI: 102819eca43eSAlex Deucher if (ASIC_IS_DCE4(rdev)) 102919eca43eSAlex Deucher radeon_crtc->ss_enabled = 103019eca43eSAlex Deucher radeon_atombios_get_asic_ss_info(rdev, 103119eca43eSAlex Deucher &radeon_crtc->ss, 103219eca43eSAlex Deucher ASIC_INTERNAL_SS_ON_TMDS, 103319eca43eSAlex Deucher mode->clock / 10); 103419eca43eSAlex Deucher break; 103519eca43eSAlex Deucher case ATOM_ENCODER_MODE_HDMI: 103619eca43eSAlex Deucher if (ASIC_IS_DCE4(rdev)) 103719eca43eSAlex Deucher radeon_crtc->ss_enabled = 103819eca43eSAlex Deucher radeon_atombios_get_asic_ss_info(rdev, 103919eca43eSAlex Deucher &radeon_crtc->ss, 104019eca43eSAlex Deucher ASIC_INTERNAL_SS_ON_HDMI, 104119eca43eSAlex Deucher mode->clock / 10); 104219eca43eSAlex Deucher break; 104319eca43eSAlex Deucher default: 104419eca43eSAlex Deucher break; 104519eca43eSAlex Deucher } 104619eca43eSAlex Deucher } 104719eca43eSAlex Deucher 104819eca43eSAlex Deucher /* adjust pixel clock as needed */ 104919eca43eSAlex Deucher radeon_crtc->adjusted_clock = atombios_adjust_pll(crtc, mode); 105019eca43eSAlex Deucher 105119eca43eSAlex Deucher return true; 105219eca43eSAlex Deucher } 105319eca43eSAlex Deucher 1054bcc1c2a1SAlex Deucher static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) 10554eaeca33SAlex Deucher { 10564eaeca33SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 10574eaeca33SAlex Deucher struct drm_device *dev = crtc->dev; 10584eaeca33SAlex Deucher struct radeon_device *rdev = dev->dev_private; 10595df3196bSAlex Deucher struct radeon_encoder *radeon_encoder = 10605df3196bSAlex Deucher to_radeon_encoder(radeon_crtc->encoder); 10614eaeca33SAlex Deucher u32 pll_clock = mode->clock; 1062f71d9ebdSAlex Deucher u32 clock = mode->clock; 10634eaeca33SAlex Deucher u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; 10644eaeca33SAlex Deucher struct radeon_pll *pll; 10655df3196bSAlex Deucher int encoder_mode = atombios_get_encoder_mode(radeon_crtc->encoder); 10664eaeca33SAlex Deucher 1067f71d9ebdSAlex Deucher /* pass the actual clock to atombios_crtc_program_pll for DCE5,6 for HDMI */ 10685c868229SMario Kleiner if (ASIC_IS_DCE5(rdev) && 1069f71d9ebdSAlex Deucher (encoder_mode == ATOM_ENCODER_MODE_HDMI) && 1070f71d9ebdSAlex Deucher (radeon_crtc->bpc > 8)) 1071f71d9ebdSAlex Deucher clock = radeon_crtc->adjusted_clock; 1072f71d9ebdSAlex Deucher 1073bcc1c2a1SAlex Deucher switch (radeon_crtc->pll_id) { 1074bcc1c2a1SAlex Deucher case ATOM_PPLL1: 10754eaeca33SAlex Deucher pll = &rdev->clock.p1pll; 1076bcc1c2a1SAlex Deucher break; 1077bcc1c2a1SAlex Deucher case ATOM_PPLL2: 10784eaeca33SAlex Deucher pll = &rdev->clock.p2pll; 1079bcc1c2a1SAlex Deucher break; 1080bcc1c2a1SAlex Deucher case ATOM_DCPLL: 1081bcc1c2a1SAlex Deucher case ATOM_PPLL_INVALID: 1082921d98b5SStefan Richter default: 1083bcc1c2a1SAlex Deucher pll = &rdev->clock.dcpll; 1084bcc1c2a1SAlex Deucher break; 1085bcc1c2a1SAlex Deucher } 10864eaeca33SAlex Deucher 108719eca43eSAlex Deucher /* update pll params */ 108819eca43eSAlex Deucher pll->flags = radeon_crtc->pll_flags; 108919eca43eSAlex Deucher pll->reference_div = radeon_crtc->pll_reference_div; 109019eca43eSAlex Deucher pll->post_div = radeon_crtc->pll_post_div; 10912606c886SAlex Deucher 109264146f8bSAlex Deucher if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 109364146f8bSAlex Deucher /* TV seems to prefer the legacy algo on some boards */ 109419eca43eSAlex Deucher radeon_compute_pll_legacy(pll, radeon_crtc->adjusted_clock, &pll_clock, 109519eca43eSAlex Deucher &fb_div, &frac_fb_div, &ref_div, &post_div); 109664146f8bSAlex Deucher else if (ASIC_IS_AVIVO(rdev)) 109719eca43eSAlex Deucher radeon_compute_pll_avivo(pll, radeon_crtc->adjusted_clock, &pll_clock, 109819eca43eSAlex Deucher &fb_div, &frac_fb_div, &ref_div, &post_div); 1099619efb10SAlex Deucher else 110019eca43eSAlex Deucher radeon_compute_pll_legacy(pll, radeon_crtc->adjusted_clock, &pll_clock, 110119eca43eSAlex Deucher &fb_div, &frac_fb_div, &ref_div, &post_div); 1102771fe6b9SJerome Glisse 110319eca43eSAlex Deucher atombios_crtc_program_ss(rdev, ATOM_DISABLE, radeon_crtc->pll_id, 110419eca43eSAlex Deucher radeon_crtc->crtc_id, &radeon_crtc->ss); 1105ba032a58SAlex Deucher 110637f9003bSAlex Deucher atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, 1107f71d9ebdSAlex Deucher encoder_mode, radeon_encoder->encoder_id, clock, 110819eca43eSAlex Deucher ref_div, fb_div, frac_fb_div, post_div, 110919eca43eSAlex Deucher radeon_crtc->bpc, radeon_crtc->ss_enabled, &radeon_crtc->ss); 1110771fe6b9SJerome Glisse 111119eca43eSAlex Deucher if (radeon_crtc->ss_enabled) { 1112ba032a58SAlex Deucher /* calculate ss amount and step size */ 1113ba032a58SAlex Deucher if (ASIC_IS_DCE4(rdev)) { 1114ba032a58SAlex Deucher u32 step_size; 111518f8f52bSAlex Deucher u32 amount = (((fb_div * 10) + frac_fb_div) * 111618f8f52bSAlex Deucher (u32)radeon_crtc->ss.percentage) / 111718f8f52bSAlex Deucher (100 * (u32)radeon_crtc->ss.percentage_divider); 111819eca43eSAlex Deucher radeon_crtc->ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK; 111919eca43eSAlex Deucher radeon_crtc->ss.amount |= ((amount - (amount / 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) & 1120ba032a58SAlex Deucher ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK; 112119eca43eSAlex Deucher if (radeon_crtc->ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD) 112218f8f52bSAlex Deucher step_size = (4 * amount * ref_div * ((u32)radeon_crtc->ss.rate * 2048)) / 1123ba032a58SAlex Deucher (125 * 25 * pll->reference_freq / 100); 1124ba032a58SAlex Deucher else 112518f8f52bSAlex Deucher step_size = (2 * amount * ref_div * ((u32)radeon_crtc->ss.rate * 2048)) / 1126ba032a58SAlex Deucher (125 * 25 * pll->reference_freq / 100); 112719eca43eSAlex Deucher radeon_crtc->ss.step = step_size; 1128ba032a58SAlex Deucher } 1129ba032a58SAlex Deucher 113019eca43eSAlex Deucher atombios_crtc_program_ss(rdev, ATOM_ENABLE, radeon_crtc->pll_id, 113119eca43eSAlex Deucher radeon_crtc->crtc_id, &radeon_crtc->ss); 1132ba032a58SAlex Deucher } 1133771fe6b9SJerome Glisse } 1134771fe6b9SJerome Glisse 1135c9417bddSAlex Deucher static int dce4_crtc_do_set_base(struct drm_crtc *crtc, 11364dd19b0dSChris Ball struct drm_framebuffer *fb, 11374dd19b0dSChris Ball int x, int y, int atomic) 1138bcc1c2a1SAlex Deucher { 1139bcc1c2a1SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1140bcc1c2a1SAlex Deucher struct drm_device *dev = crtc->dev; 1141bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 11424dd19b0dSChris Ball struct drm_framebuffer *target_fb; 1143bcc1c2a1SAlex Deucher struct drm_gem_object *obj; 1144bcc1c2a1SAlex Deucher struct radeon_bo *rbo; 1145bcc1c2a1SAlex Deucher uint64_t fb_location; 1146bcc1c2a1SAlex Deucher uint32_t fb_format, fb_pitch_pixels, tiling_flags; 1147285484e2SJerome Glisse unsigned bankw, bankh, mtaspect, tile_split; 1148fa6bee46SAlex Deucher u32 fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE); 1149adcfde51SAlex Deucher u32 tmp, viewport_w, viewport_h; 1150bcc1c2a1SAlex Deucher int r; 11514366f3b5SMario Kleiner bool bypass_lut = false; 1152bcc1c2a1SAlex Deucher 1153bcc1c2a1SAlex Deucher /* no fb bound */ 1154f4510a27SMatt Roper if (!atomic && !crtc->primary->fb) { 1155d9fdaafbSDave Airlie DRM_DEBUG_KMS("No FB bound\n"); 1156bcc1c2a1SAlex Deucher return 0; 1157bcc1c2a1SAlex Deucher } 1158bcc1c2a1SAlex Deucher 11599a0f0c9dSDaniel Stone if (atomic) 11604dd19b0dSChris Ball target_fb = fb; 11619a0f0c9dSDaniel Stone else 1162f4510a27SMatt Roper target_fb = crtc->primary->fb; 1163bcc1c2a1SAlex Deucher 11644dd19b0dSChris Ball /* If atomic, assume fb object is pinned & idle & fenced and 11654dd19b0dSChris Ball * just update base pointers 11664dd19b0dSChris Ball */ 11679a0f0c9dSDaniel Stone obj = target_fb->obj[0]; 11687e4d15d9SDaniel Vetter rbo = gem_to_radeon_bo(obj); 1169bcc1c2a1SAlex Deucher r = radeon_bo_reserve(rbo, false); 1170bcc1c2a1SAlex Deucher if (unlikely(r != 0)) 1171bcc1c2a1SAlex Deucher return r; 11724dd19b0dSChris Ball 11734dd19b0dSChris Ball if (atomic) 11744dd19b0dSChris Ball fb_location = radeon_bo_gpu_offset(rbo); 11754dd19b0dSChris Ball else { 1176bcc1c2a1SAlex Deucher r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); 1177bcc1c2a1SAlex Deucher if (unlikely(r != 0)) { 1178bcc1c2a1SAlex Deucher radeon_bo_unreserve(rbo); 1179bcc1c2a1SAlex Deucher return -EINVAL; 1180bcc1c2a1SAlex Deucher } 11814dd19b0dSChris Ball } 11824dd19b0dSChris Ball 1183bcc1c2a1SAlex Deucher radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); 1184bcc1c2a1SAlex Deucher radeon_bo_unreserve(rbo); 1185bcc1c2a1SAlex Deucher 1186438b74a5SVille Syrjälä switch (target_fb->format->format) { 11878bae4276SFredrik Höglund case DRM_FORMAT_C8: 1188bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP) | 1189bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED)); 1190bcc1c2a1SAlex Deucher break; 11918bae4276SFredrik Höglund case DRM_FORMAT_XRGB4444: 11928bae4276SFredrik Höglund case DRM_FORMAT_ARGB4444: 11938bae4276SFredrik Höglund fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 11948bae4276SFredrik Höglund EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB4444)); 11958bae4276SFredrik Höglund #ifdef __BIG_ENDIAN 11968bae4276SFredrik Höglund fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16); 11978bae4276SFredrik Höglund #endif 11988bae4276SFredrik Höglund break; 11998bae4276SFredrik Höglund case DRM_FORMAT_XRGB1555: 12008bae4276SFredrik Höglund case DRM_FORMAT_ARGB1555: 1201bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 1202bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB1555)); 12038bae4276SFredrik Höglund #ifdef __BIG_ENDIAN 12048bae4276SFredrik Höglund fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16); 12058bae4276SFredrik Höglund #endif 1206bcc1c2a1SAlex Deucher break; 12078bae4276SFredrik Höglund case DRM_FORMAT_BGRX5551: 12088bae4276SFredrik Höglund case DRM_FORMAT_BGRA5551: 12098bae4276SFredrik Höglund fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 12108bae4276SFredrik Höglund EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_BGRA5551)); 12118bae4276SFredrik Höglund #ifdef __BIG_ENDIAN 12128bae4276SFredrik Höglund fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16); 12138bae4276SFredrik Höglund #endif 12148bae4276SFredrik Höglund break; 12158bae4276SFredrik Höglund case DRM_FORMAT_RGB565: 1216bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 1217bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565)); 1218fa6bee46SAlex Deucher #ifdef __BIG_ENDIAN 1219fa6bee46SAlex Deucher fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16); 1220fa6bee46SAlex Deucher #endif 1221bcc1c2a1SAlex Deucher break; 12228bae4276SFredrik Höglund case DRM_FORMAT_XRGB8888: 12238bae4276SFredrik Höglund case DRM_FORMAT_ARGB8888: 1224bcc1c2a1SAlex Deucher fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) | 1225bcc1c2a1SAlex Deucher EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888)); 1226fa6bee46SAlex Deucher #ifdef __BIG_ENDIAN 1227fa6bee46SAlex Deucher fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32); 1228fa6bee46SAlex Deucher #endif 1229bcc1c2a1SAlex Deucher break; 12308bae4276SFredrik Höglund case DRM_FORMAT_XRGB2101010: 12318bae4276SFredrik Höglund case DRM_FORMAT_ARGB2101010: 12328bae4276SFredrik Höglund fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) | 12338bae4276SFredrik Höglund EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB2101010)); 12348bae4276SFredrik Höglund #ifdef __BIG_ENDIAN 12358bae4276SFredrik Höglund fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32); 12368bae4276SFredrik Höglund #endif 12374366f3b5SMario Kleiner /* Greater 8 bpc fb needs to bypass hw-lut to retain precision */ 12384366f3b5SMario Kleiner bypass_lut = true; 12398bae4276SFredrik Höglund break; 12408bae4276SFredrik Höglund case DRM_FORMAT_BGRX1010102: 12418bae4276SFredrik Höglund case DRM_FORMAT_BGRA1010102: 12428bae4276SFredrik Höglund fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) | 12438bae4276SFredrik Höglund EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_BGRA1010102)); 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; 1250a69e40fdSMauro Rossi case DRM_FORMAT_XBGR8888: 1251a69e40fdSMauro Rossi case DRM_FORMAT_ABGR8888: 1252a69e40fdSMauro Rossi fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) | 1253a69e40fdSMauro Rossi EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888)); 1254a69e40fdSMauro Rossi fb_swap = (EVERGREEN_GRPH_RED_CROSSBAR(EVERGREEN_GRPH_RED_SEL_B) | 1255a69e40fdSMauro Rossi EVERGREEN_GRPH_BLUE_CROSSBAR(EVERGREEN_GRPH_BLUE_SEL_R)); 1256a69e40fdSMauro Rossi #ifdef __BIG_ENDIAN 1257a69e40fdSMauro Rossi fb_swap |= EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32); 1258a69e40fdSMauro Rossi #endif 1259a69e40fdSMauro Rossi break; 1260bcc1c2a1SAlex Deucher default: 126192f1d09cSSakari Ailus DRM_ERROR("Unsupported screen format %p4cc\n", 126292f1d09cSSakari Ailus &target_fb->format->format); 1263bcc1c2a1SAlex Deucher return -EINVAL; 1264bcc1c2a1SAlex Deucher } 1265bcc1c2a1SAlex Deucher 1266392e3722SAlex Deucher if (tiling_flags & RADEON_TILING_MACRO) { 1267e3ea94a6SMarek Olšák evergreen_tiling_fields(tiling_flags, &bankw, &bankh, &mtaspect, &tile_split); 1268e3ea94a6SMarek Olšák 1269e3ea94a6SMarek Olšák /* Set NUM_BANKS. */ 12706d8ea7deSAlex Deucher if (rdev->family >= CHIP_TAHITI) { 1271e9d14aebSMichel Dänzer unsigned index, num_banks; 1272e9d14aebSMichel Dänzer 1273e9d14aebSMichel Dänzer if (rdev->family >= CHIP_BONAIRE) { 1274e9d14aebSMichel Dänzer unsigned tileb, tile_split_bytes; 1275e3ea94a6SMarek Olšák 1276e3ea94a6SMarek Olšák /* Calculate the macrotile mode index. */ 1277e3ea94a6SMarek Olšák tile_split_bytes = 64 << tile_split; 1278272725c7SVille Syrjälä tileb = 8 * 8 * target_fb->format->cpp[0]; 1279e3ea94a6SMarek Olšák tileb = min(tile_split_bytes, tileb); 1280e3ea94a6SMarek Olšák 1281e9d14aebSMichel Dänzer for (index = 0; tileb > 64; index++) 1282e3ea94a6SMarek Olšák tileb >>= 1; 1283e3ea94a6SMarek Olšák 1284e3ea94a6SMarek Olšák if (index >= 16) { 1285e3ea94a6SMarek Olšák DRM_ERROR("Wrong screen bpp (%u) or tile split (%u)\n", 1286272725c7SVille Syrjälä target_fb->format->cpp[0] * 8, 1287272725c7SVille Syrjälä tile_split); 1288e3ea94a6SMarek Olšák return -EINVAL; 1289e3ea94a6SMarek Olšák } 1290e3ea94a6SMarek Olšák 1291e3ea94a6SMarek Olšák num_banks = (rdev->config.cik.macrotile_mode_array[index] >> 6) & 0x3; 1292e9d14aebSMichel Dänzer } else { 1293272725c7SVille Syrjälä switch (target_fb->format->cpp[0] * 8) { 1294e9d14aebSMichel Dänzer case 8: 1295e9d14aebSMichel Dänzer index = 10; 1296e9d14aebSMichel Dänzer break; 1297e9d14aebSMichel Dänzer case 16: 1298e9d14aebSMichel Dänzer index = SI_TILE_MODE_COLOR_2D_SCANOUT_16BPP; 1299e9d14aebSMichel Dänzer break; 1300e9d14aebSMichel Dänzer default: 1301e9d14aebSMichel Dänzer case 32: 1302e9d14aebSMichel Dänzer index = SI_TILE_MODE_COLOR_2D_SCANOUT_32BPP; 1303e9d14aebSMichel Dänzer break; 1304e9d14aebSMichel Dänzer } 1305e9d14aebSMichel Dänzer 13066d8ea7deSAlex Deucher num_banks = (rdev->config.si.tile_mode_array[index] >> 20) & 0x3; 1307e9d14aebSMichel Dänzer } 1308e9d14aebSMichel Dänzer 1309e3ea94a6SMarek Olšák fb_format |= EVERGREEN_GRPH_NUM_BANKS(num_banks); 1310e3ea94a6SMarek Olšák } else { 13116d8ea7deSAlex Deucher /* NI and older. */ 13126d8ea7deSAlex Deucher if (rdev->family >= CHIP_CAYMAN) 1313392e3722SAlex Deucher tmp = rdev->config.cayman.tile_config; 1314392e3722SAlex Deucher else 1315392e3722SAlex Deucher tmp = rdev->config.evergreen.tile_config; 1316392e3722SAlex Deucher 1317392e3722SAlex Deucher switch ((tmp & 0xf0) >> 4) { 1318392e3722SAlex Deucher case 0: /* 4 banks */ 1319392e3722SAlex Deucher fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_4_BANK); 1320392e3722SAlex Deucher break; 1321392e3722SAlex Deucher case 1: /* 8 banks */ 1322392e3722SAlex Deucher default: 1323392e3722SAlex Deucher fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_8_BANK); 1324392e3722SAlex Deucher break; 1325392e3722SAlex Deucher case 2: /* 16 banks */ 1326392e3722SAlex Deucher fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_16_BANK); 1327392e3722SAlex Deucher break; 1328392e3722SAlex Deucher } 1329e3ea94a6SMarek Olšák } 1330392e3722SAlex Deucher 133197d66328SAlex Deucher fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1); 1332285484e2SJerome Glisse fb_format |= EVERGREEN_GRPH_TILE_SPLIT(tile_split); 1333285484e2SJerome Glisse fb_format |= EVERGREEN_GRPH_BANK_WIDTH(bankw); 1334285484e2SJerome Glisse fb_format |= EVERGREEN_GRPH_BANK_HEIGHT(bankh); 1335285484e2SJerome Glisse fb_format |= EVERGREEN_GRPH_MACRO_TILE_ASPECT(mtaspect); 13368da0e500SAlex Deucher if (rdev->family >= CHIP_BONAIRE) { 13378da0e500SAlex Deucher /* XXX need to know more about the surface tiling mode */ 13388da0e500SAlex Deucher fb_format |= CIK_GRPH_MICRO_TILE_MODE(CIK_DISPLAY_MICRO_TILING); 13398da0e500SAlex Deucher } 1340392e3722SAlex Deucher } else if (tiling_flags & RADEON_TILING_MICRO) 134197d66328SAlex Deucher fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1); 134297d66328SAlex Deucher 13438da0e500SAlex Deucher if (rdev->family >= CHIP_BONAIRE) { 134435a90528SMarek Olšák /* Read the pipe config from the 2D TILED SCANOUT mode. 134535a90528SMarek Olšák * It should be the same for the other modes too, but not all 134635a90528SMarek Olšák * modes set the pipe config field. */ 134735a90528SMarek Olšák u32 pipe_config = (rdev->config.cik.tile_mode_array[10] >> 6) & 0x1f; 134835a90528SMarek Olšák 134935a90528SMarek Olšák fb_format |= CIK_GRPH_PIPE_CONFIG(pipe_config); 13508da0e500SAlex Deucher } else if ((rdev->family == CHIP_TAHITI) || 1351b7019b2fSAlex Deucher (rdev->family == CHIP_PITCAIRN)) 1352b7019b2fSAlex Deucher fb_format |= SI_GRPH_PIPE_CONFIG(SI_ADDR_SURF_P8_32x32_8x16); 1353227ae10fSAlex Deucher else if ((rdev->family == CHIP_VERDE) || 1354227ae10fSAlex Deucher (rdev->family == CHIP_OLAND) || 1355227ae10fSAlex Deucher (rdev->family == CHIP_HAINAN)) /* for completeness. HAINAN has no display hw */ 1356b7019b2fSAlex Deucher fb_format |= SI_GRPH_PIPE_CONFIG(SI_ADDR_SURF_P4_8x16); 1357b7019b2fSAlex Deucher 1358bcc1c2a1SAlex Deucher switch (radeon_crtc->crtc_id) { 1359bcc1c2a1SAlex Deucher case 0: 1360bcc1c2a1SAlex Deucher WREG32(AVIVO_D1VGA_CONTROL, 0); 1361bcc1c2a1SAlex Deucher break; 1362bcc1c2a1SAlex Deucher case 1: 1363bcc1c2a1SAlex Deucher WREG32(AVIVO_D2VGA_CONTROL, 0); 1364bcc1c2a1SAlex Deucher break; 1365bcc1c2a1SAlex Deucher case 2: 1366bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D3VGA_CONTROL, 0); 1367bcc1c2a1SAlex Deucher break; 1368bcc1c2a1SAlex Deucher case 3: 1369bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D4VGA_CONTROL, 0); 1370bcc1c2a1SAlex Deucher break; 1371bcc1c2a1SAlex Deucher case 4: 1372bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D5VGA_CONTROL, 0); 1373bcc1c2a1SAlex Deucher break; 1374bcc1c2a1SAlex Deucher case 5: 1375bcc1c2a1SAlex Deucher WREG32(EVERGREEN_D6VGA_CONTROL, 0); 1376bcc1c2a1SAlex Deucher break; 1377bcc1c2a1SAlex Deucher default: 1378bcc1c2a1SAlex Deucher break; 1379bcc1c2a1SAlex Deucher } 1380bcc1c2a1SAlex Deucher 1381c63dd758SMichel Dänzer /* Make sure surface address is updated at vertical blank rather than 1382c63dd758SMichel Dänzer * horizontal blank 1383c63dd758SMichel Dänzer */ 1384c63dd758SMichel Dänzer WREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, 0); 1385c63dd758SMichel Dänzer 1386bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 1387bcc1c2a1SAlex Deucher upper_32_bits(fb_location)); 1388bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 1389bcc1c2a1SAlex Deucher upper_32_bits(fb_location)); 1390bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 1391bcc1c2a1SAlex Deucher (u32)fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK); 1392bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 1393bcc1c2a1SAlex Deucher (u32) fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK); 1394bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); 1395fa6bee46SAlex Deucher WREG32(EVERGREEN_GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap); 1396bcc1c2a1SAlex Deucher 13974366f3b5SMario Kleiner /* 13984366f3b5SMario Kleiner * The LUT only has 256 slots for indexing by a 8 bpc fb. Bypass the LUT 13994366f3b5SMario Kleiner * for > 8 bpc scanout to avoid truncation of fb indices to 8 msb's, to 14004366f3b5SMario Kleiner * retain the full precision throughout the pipeline. 14014366f3b5SMario Kleiner */ 14024366f3b5SMario Kleiner WREG32_P(EVERGREEN_GRPH_LUT_10BIT_BYPASS_CONTROL + radeon_crtc->crtc_offset, 14034366f3b5SMario Kleiner (bypass_lut ? EVERGREEN_LUT_10BIT_BYPASS_EN : 0), 14044366f3b5SMario Kleiner ~EVERGREEN_LUT_10BIT_BYPASS_EN); 14054366f3b5SMario Kleiner 14064366f3b5SMario Kleiner if (bypass_lut) 14074366f3b5SMario Kleiner DRM_DEBUG_KMS("Bypassing hardware LUT due to 10 bit fb scanout.\n"); 14084366f3b5SMario Kleiner 1409bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); 1410bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); 1411bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_X_START + radeon_crtc->crtc_offset, 0); 1412bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_Y_START + radeon_crtc->crtc_offset, 0); 14134dd19b0dSChris Ball WREG32(EVERGREEN_GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width); 14144dd19b0dSChris Ball WREG32(EVERGREEN_GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height); 1415bcc1c2a1SAlex Deucher 1416272725c7SVille Syrjälä fb_pitch_pixels = target_fb->pitches[0] / target_fb->format->cpp[0]; 1417bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); 1418bcc1c2a1SAlex Deucher WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1); 1419bcc1c2a1SAlex Deucher 14208da0e500SAlex Deucher if (rdev->family >= CHIP_BONAIRE) 14218da0e500SAlex Deucher WREG32(CIK_LB_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, 14228da0e500SAlex Deucher target_fb->height); 14238da0e500SAlex Deucher else 1424bcc1c2a1SAlex Deucher WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, 14251b619250SMichel Dänzer target_fb->height); 1426bcc1c2a1SAlex Deucher x &= ~3; 1427bcc1c2a1SAlex Deucher y &= ~1; 1428bcc1c2a1SAlex Deucher WREG32(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset, 1429bcc1c2a1SAlex Deucher (x << 16) | y); 1430adcfde51SAlex Deucher viewport_w = crtc->mode.hdisplay; 1431adcfde51SAlex Deucher viewport_h = (crtc->mode.vdisplay + 1) & ~1; 143277ae5f4bSAlex Deucher if ((rdev->family >= CHIP_BONAIRE) && 143377ae5f4bSAlex Deucher (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)) 143477ae5f4bSAlex Deucher viewport_h *= 2; 1435bcc1c2a1SAlex Deucher WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset, 1436adcfde51SAlex Deucher (viewport_w << 16) | viewport_h); 1437bcc1c2a1SAlex Deucher 14385dd20bbaSMichel Dänzer /* set pageflip to happen anywhere in vblank interval */ 14395dd20bbaSMichel Dänzer WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); 1440fb9674bdSAlex Deucher 1441f4510a27SMatt Roper if (!atomic && fb && fb != crtc->primary->fb) { 14429a0f0c9dSDaniel Stone rbo = gem_to_radeon_bo(fb->obj[0]); 1443bcc1c2a1SAlex Deucher r = radeon_bo_reserve(rbo, false); 1444bcc1c2a1SAlex Deucher if (unlikely(r != 0)) 1445bcc1c2a1SAlex Deucher return r; 1446bcc1c2a1SAlex Deucher radeon_bo_unpin(rbo); 1447bcc1c2a1SAlex Deucher radeon_bo_unreserve(rbo); 1448bcc1c2a1SAlex Deucher } 1449bcc1c2a1SAlex Deucher 1450bcc1c2a1SAlex Deucher /* Bytes per pixel may have changed */ 1451bcc1c2a1SAlex Deucher radeon_bandwidth_update(rdev); 1452bcc1c2a1SAlex Deucher 1453bcc1c2a1SAlex Deucher return 0; 1454bcc1c2a1SAlex Deucher } 1455bcc1c2a1SAlex Deucher 14564dd19b0dSChris Ball static int avivo_crtc_do_set_base(struct drm_crtc *crtc, 14574dd19b0dSChris Ball struct drm_framebuffer *fb, 14584dd19b0dSChris Ball int x, int y, int atomic) 1459771fe6b9SJerome Glisse { 1460771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1461771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 1462771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 1463771fe6b9SJerome Glisse struct drm_gem_object *obj; 14644c788679SJerome Glisse struct radeon_bo *rbo; 14654dd19b0dSChris Ball struct drm_framebuffer *target_fb; 1466771fe6b9SJerome Glisse uint64_t fb_location; 1467e024e110SDave Airlie uint32_t fb_format, fb_pitch_pixels, tiling_flags; 1468fa6bee46SAlex Deucher u32 fb_swap = R600_D1GRPH_SWAP_ENDIAN_NONE; 1469c63dd758SMichel Dänzer u32 viewport_w, viewport_h; 14704c788679SJerome Glisse int r; 14714366f3b5SMario Kleiner bool bypass_lut = false; 1472771fe6b9SJerome Glisse 14732de3b484SJerome Glisse /* no fb bound */ 1474f4510a27SMatt Roper if (!atomic && !crtc->primary->fb) { 1475d9fdaafbSDave Airlie DRM_DEBUG_KMS("No FB bound\n"); 14762de3b484SJerome Glisse return 0; 14772de3b484SJerome Glisse } 1478771fe6b9SJerome Glisse 14799a0f0c9dSDaniel Stone if (atomic) 14804dd19b0dSChris Ball target_fb = fb; 14819a0f0c9dSDaniel Stone else 1482f4510a27SMatt Roper target_fb = crtc->primary->fb; 1483771fe6b9SJerome Glisse 14849a0f0c9dSDaniel Stone obj = target_fb->obj[0]; 14857e4d15d9SDaniel Vetter rbo = gem_to_radeon_bo(obj); 14864c788679SJerome Glisse r = radeon_bo_reserve(rbo, false); 14874c788679SJerome Glisse if (unlikely(r != 0)) 14884c788679SJerome Glisse return r; 14894dd19b0dSChris Ball 14904dd19b0dSChris Ball /* If atomic, assume fb object is pinned & idle & fenced and 14914dd19b0dSChris Ball * just update base pointers 14924dd19b0dSChris Ball */ 14934dd19b0dSChris Ball if (atomic) 14944dd19b0dSChris Ball fb_location = radeon_bo_gpu_offset(rbo); 14954dd19b0dSChris Ball else { 14964c788679SJerome Glisse r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); 14974c788679SJerome Glisse if (unlikely(r != 0)) { 14984c788679SJerome Glisse radeon_bo_unreserve(rbo); 1499771fe6b9SJerome Glisse return -EINVAL; 1500771fe6b9SJerome Glisse } 15014dd19b0dSChris Ball } 15024c788679SJerome Glisse radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); 15034c788679SJerome Glisse radeon_bo_unreserve(rbo); 1504771fe6b9SJerome Glisse 1505438b74a5SVille Syrjälä switch (target_fb->format->format) { 15068bae4276SFredrik Höglund case DRM_FORMAT_C8: 150741456df2SDave Airlie fb_format = 150841456df2SDave Airlie AVIVO_D1GRPH_CONTROL_DEPTH_8BPP | 150941456df2SDave Airlie AVIVO_D1GRPH_CONTROL_8BPP_INDEXED; 151041456df2SDave Airlie break; 15118bae4276SFredrik Höglund case DRM_FORMAT_XRGB4444: 15128bae4276SFredrik Höglund case DRM_FORMAT_ARGB4444: 15138bae4276SFredrik Höglund fb_format = 15148bae4276SFredrik Höglund AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | 15158bae4276SFredrik Höglund AVIVO_D1GRPH_CONTROL_16BPP_ARGB4444; 15168bae4276SFredrik Höglund #ifdef __BIG_ENDIAN 15178bae4276SFredrik Höglund fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT; 15188bae4276SFredrik Höglund #endif 15198bae4276SFredrik Höglund break; 15208bae4276SFredrik Höglund case DRM_FORMAT_XRGB1555: 1521771fe6b9SJerome Glisse fb_format = 1522771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | 1523771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555; 15248bae4276SFredrik Höglund #ifdef __BIG_ENDIAN 15258bae4276SFredrik Höglund fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT; 15268bae4276SFredrik Höglund #endif 1527771fe6b9SJerome Glisse break; 15288bae4276SFredrik Höglund case DRM_FORMAT_RGB565: 1529771fe6b9SJerome Glisse fb_format = 1530771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | 1531771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_16BPP_RGB565; 1532fa6bee46SAlex Deucher #ifdef __BIG_ENDIAN 1533fa6bee46SAlex Deucher fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT; 1534fa6bee46SAlex Deucher #endif 1535771fe6b9SJerome Glisse break; 15368bae4276SFredrik Höglund case DRM_FORMAT_XRGB8888: 15378bae4276SFredrik Höglund case DRM_FORMAT_ARGB8888: 1538771fe6b9SJerome Glisse fb_format = 1539771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_32BPP | 1540771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888; 1541fa6bee46SAlex Deucher #ifdef __BIG_ENDIAN 1542fa6bee46SAlex Deucher fb_swap = R600_D1GRPH_SWAP_ENDIAN_32BIT; 1543fa6bee46SAlex Deucher #endif 1544771fe6b9SJerome Glisse break; 15458bae4276SFredrik Höglund case DRM_FORMAT_XRGB2101010: 15468bae4276SFredrik Höglund case DRM_FORMAT_ARGB2101010: 15478bae4276SFredrik Höglund fb_format = 15488bae4276SFredrik Höglund AVIVO_D1GRPH_CONTROL_DEPTH_32BPP | 15498bae4276SFredrik Höglund AVIVO_D1GRPH_CONTROL_32BPP_ARGB2101010; 15508bae4276SFredrik Höglund #ifdef __BIG_ENDIAN 15518bae4276SFredrik Höglund fb_swap = R600_D1GRPH_SWAP_ENDIAN_32BIT; 15528bae4276SFredrik Höglund #endif 15534366f3b5SMario Kleiner /* Greater 8 bpc fb needs to bypass hw-lut to retain precision */ 15544366f3b5SMario Kleiner bypass_lut = true; 15558bae4276SFredrik Höglund break; 1556a69e40fdSMauro Rossi case DRM_FORMAT_XBGR8888: 1557a69e40fdSMauro Rossi case DRM_FORMAT_ABGR8888: 1558a69e40fdSMauro Rossi fb_format = 1559a69e40fdSMauro Rossi AVIVO_D1GRPH_CONTROL_DEPTH_32BPP | 1560a69e40fdSMauro Rossi AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888; 1561a69e40fdSMauro Rossi if (rdev->family >= CHIP_R600) 1562a69e40fdSMauro Rossi fb_swap = 1563a69e40fdSMauro Rossi (R600_D1GRPH_RED_CROSSBAR(R600_D1GRPH_RED_SEL_B) | 1564a69e40fdSMauro Rossi R600_D1GRPH_BLUE_CROSSBAR(R600_D1GRPH_BLUE_SEL_R)); 1565a69e40fdSMauro Rossi else /* DCE1 (R5xx) */ 1566a69e40fdSMauro Rossi fb_format |= AVIVO_D1GRPH_SWAP_RB; 1567a69e40fdSMauro Rossi #ifdef __BIG_ENDIAN 1568a69e40fdSMauro Rossi fb_swap |= R600_D1GRPH_SWAP_ENDIAN_32BIT; 1569a69e40fdSMauro Rossi #endif 1570a69e40fdSMauro Rossi break; 1571771fe6b9SJerome Glisse default: 157292f1d09cSSakari Ailus DRM_ERROR("Unsupported screen format %p4cc\n", 157392f1d09cSSakari Ailus &target_fb->format->format); 1574771fe6b9SJerome Glisse return -EINVAL; 1575771fe6b9SJerome Glisse } 1576771fe6b9SJerome Glisse 157740c4ac1cSAlex Deucher if (rdev->family >= CHIP_R600) { 157840c4ac1cSAlex Deucher if (tiling_flags & RADEON_TILING_MACRO) 157940c4ac1cSAlex Deucher fb_format |= R600_D1GRPH_ARRAY_MODE_2D_TILED_THIN1; 158040c4ac1cSAlex Deucher else if (tiling_flags & RADEON_TILING_MICRO) 158140c4ac1cSAlex Deucher fb_format |= R600_D1GRPH_ARRAY_MODE_1D_TILED_THIN1; 158240c4ac1cSAlex Deucher } else { 1583cf2f05d3SDave Airlie if (tiling_flags & RADEON_TILING_MACRO) 1584cf2f05d3SDave Airlie fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE; 1585cf2f05d3SDave Airlie 1586e024e110SDave Airlie if (tiling_flags & RADEON_TILING_MICRO) 1587e024e110SDave Airlie fb_format |= AVIVO_D1GRPH_TILED; 158840c4ac1cSAlex Deucher } 1589e024e110SDave Airlie 1590771fe6b9SJerome Glisse if (radeon_crtc->crtc_id == 0) 1591771fe6b9SJerome Glisse WREG32(AVIVO_D1VGA_CONTROL, 0); 1592771fe6b9SJerome Glisse else 1593771fe6b9SJerome Glisse WREG32(AVIVO_D2VGA_CONTROL, 0); 1594c290dadfSAlex Deucher 1595c63dd758SMichel Dänzer /* Make sure surface address is update at vertical blank rather than 1596c63dd758SMichel Dänzer * horizontal blank 1597c63dd758SMichel Dänzer */ 1598c63dd758SMichel Dänzer WREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, 0); 1599c63dd758SMichel Dänzer 1600c290dadfSAlex Deucher if (rdev->family >= CHIP_RV770) { 1601c290dadfSAlex Deucher if (radeon_crtc->crtc_id) { 160295347871SAlex Deucher WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 160395347871SAlex Deucher WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 1604c290dadfSAlex Deucher } else { 160595347871SAlex Deucher WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 160695347871SAlex Deucher WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 1607c290dadfSAlex Deucher } 1608c290dadfSAlex Deucher } 1609771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 1610771fe6b9SJerome Glisse (u32) fb_location); 1611771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + 1612771fe6b9SJerome Glisse radeon_crtc->crtc_offset, (u32) fb_location); 1613771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); 1614fa6bee46SAlex Deucher if (rdev->family >= CHIP_R600) 1615fa6bee46SAlex Deucher WREG32(R600_D1GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap); 1616771fe6b9SJerome Glisse 16174366f3b5SMario Kleiner /* LUT only has 256 slots for 8 bpc fb. Bypass for > 8 bpc scanout for precision */ 16184366f3b5SMario Kleiner WREG32_P(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, 16194366f3b5SMario Kleiner (bypass_lut ? AVIVO_LUT_10BIT_BYPASS_EN : 0), ~AVIVO_LUT_10BIT_BYPASS_EN); 16204366f3b5SMario Kleiner 16214366f3b5SMario Kleiner if (bypass_lut) 16224366f3b5SMario Kleiner DRM_DEBUG_KMS("Bypassing hardware LUT due to 10 bit fb scanout.\n"); 16234366f3b5SMario Kleiner 1624771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); 1625771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); 1626771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0); 1627771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, 0); 16284dd19b0dSChris Ball WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width); 16294dd19b0dSChris Ball WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height); 1630771fe6b9SJerome Glisse 1631272725c7SVille Syrjälä fb_pitch_pixels = target_fb->pitches[0] / target_fb->format->cpp[0]; 1632771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); 1633771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1); 1634771fe6b9SJerome Glisse 1635771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, 16361b619250SMichel Dänzer target_fb->height); 1637771fe6b9SJerome Glisse x &= ~3; 1638771fe6b9SJerome Glisse y &= ~1; 1639771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset, 1640771fe6b9SJerome Glisse (x << 16) | y); 1641adcfde51SAlex Deucher viewport_w = crtc->mode.hdisplay; 1642adcfde51SAlex Deucher viewport_h = (crtc->mode.vdisplay + 1) & ~1; 1643771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset, 1644adcfde51SAlex Deucher (viewport_w << 16) | viewport_h); 1645771fe6b9SJerome Glisse 1646363926dcSMario Kleiner /* set pageflip to happen only at start of vblank interval (front porch) */ 1647363926dcSMario Kleiner WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 3); 1648fb9674bdSAlex Deucher 1649f4510a27SMatt Roper if (!atomic && fb && fb != crtc->primary->fb) { 16509a0f0c9dSDaniel Stone rbo = gem_to_radeon_bo(fb->obj[0]); 16514c788679SJerome Glisse r = radeon_bo_reserve(rbo, false); 16524c788679SJerome Glisse if (unlikely(r != 0)) 16534c788679SJerome Glisse return r; 16544c788679SJerome Glisse radeon_bo_unpin(rbo); 16554c788679SJerome Glisse radeon_bo_unreserve(rbo); 1656771fe6b9SJerome Glisse } 1657f30f37deSMichel Dänzer 1658f30f37deSMichel Dänzer /* Bytes per pixel may have changed */ 1659f30f37deSMichel Dänzer radeon_bandwidth_update(rdev); 1660f30f37deSMichel Dänzer 1661771fe6b9SJerome Glisse return 0; 1662771fe6b9SJerome Glisse } 1663771fe6b9SJerome Glisse 166454f088a9SAlex Deucher int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, 166554f088a9SAlex Deucher struct drm_framebuffer *old_fb) 166654f088a9SAlex Deucher { 166754f088a9SAlex Deucher struct drm_device *dev = crtc->dev; 166854f088a9SAlex Deucher struct radeon_device *rdev = dev->dev_private; 166954f088a9SAlex Deucher 1670bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) 1671c9417bddSAlex Deucher return dce4_crtc_do_set_base(crtc, old_fb, x, y, 0); 1672bcc1c2a1SAlex Deucher else if (ASIC_IS_AVIVO(rdev)) 16734dd19b0dSChris Ball return avivo_crtc_do_set_base(crtc, old_fb, x, y, 0); 167454f088a9SAlex Deucher else 16754dd19b0dSChris Ball return radeon_crtc_do_set_base(crtc, old_fb, x, y, 0); 16764dd19b0dSChris Ball } 16774dd19b0dSChris Ball 16784dd19b0dSChris Ball int atombios_crtc_set_base_atomic(struct drm_crtc *crtc, 16794dd19b0dSChris Ball struct drm_framebuffer *fb, 168021c74a8eSJason Wessel int x, int y, enum mode_set_atomic state) 16814dd19b0dSChris Ball { 16824dd19b0dSChris Ball struct drm_device *dev = crtc->dev; 16834dd19b0dSChris Ball struct radeon_device *rdev = dev->dev_private; 16844dd19b0dSChris Ball 16854dd19b0dSChris Ball if (ASIC_IS_DCE4(rdev)) 1686c9417bddSAlex Deucher return dce4_crtc_do_set_base(crtc, fb, x, y, 1); 16874dd19b0dSChris Ball else if (ASIC_IS_AVIVO(rdev)) 16884dd19b0dSChris Ball return avivo_crtc_do_set_base(crtc, fb, x, y, 1); 16894dd19b0dSChris Ball else 16904dd19b0dSChris Ball return radeon_crtc_do_set_base(crtc, fb, x, y, 1); 169154f088a9SAlex Deucher } 169254f088a9SAlex Deucher 1693615e0cb6SAlex Deucher /* properly set additional regs when using atombios */ 1694615e0cb6SAlex Deucher static void radeon_legacy_atom_fixup(struct drm_crtc *crtc) 1695615e0cb6SAlex Deucher { 1696615e0cb6SAlex Deucher struct drm_device *dev = crtc->dev; 1697615e0cb6SAlex Deucher struct radeon_device *rdev = dev->dev_private; 1698615e0cb6SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1699615e0cb6SAlex Deucher u32 disp_merge_cntl; 1700615e0cb6SAlex Deucher 1701615e0cb6SAlex Deucher switch (radeon_crtc->crtc_id) { 1702615e0cb6SAlex Deucher case 0: 1703615e0cb6SAlex Deucher disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL); 1704615e0cb6SAlex Deucher disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; 1705615e0cb6SAlex Deucher WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl); 1706615e0cb6SAlex Deucher break; 1707615e0cb6SAlex Deucher case 1: 1708615e0cb6SAlex Deucher disp_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL); 1709615e0cb6SAlex Deucher disp_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN; 1710615e0cb6SAlex Deucher WREG32(RADEON_DISP2_MERGE_CNTL, disp_merge_cntl); 1711615e0cb6SAlex Deucher WREG32(RADEON_FP_H2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_H_SYNC_STRT_WID)); 1712615e0cb6SAlex Deucher WREG32(RADEON_FP_V2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_V_SYNC_STRT_WID)); 1713615e0cb6SAlex Deucher break; 1714615e0cb6SAlex Deucher } 1715615e0cb6SAlex Deucher } 1716615e0cb6SAlex Deucher 1717f3dd8508SAlex Deucher /** 1718f3dd8508SAlex Deucher * radeon_get_pll_use_mask - look up a mask of which pplls are in use 1719f3dd8508SAlex Deucher * 1720f3dd8508SAlex Deucher * @crtc: drm crtc 1721f3dd8508SAlex Deucher * 1722f3dd8508SAlex Deucher * Returns the mask of which PPLLs (Pixel PLLs) are in use. 1723f3dd8508SAlex Deucher */ 1724f3dd8508SAlex Deucher static u32 radeon_get_pll_use_mask(struct drm_crtc *crtc) 1725f3dd8508SAlex Deucher { 1726f3dd8508SAlex Deucher struct drm_device *dev = crtc->dev; 1727f3dd8508SAlex Deucher struct drm_crtc *test_crtc; 172857b35e29SAlex Deucher struct radeon_crtc *test_radeon_crtc; 1729f3dd8508SAlex Deucher u32 pll_in_use = 0; 1730f3dd8508SAlex Deucher 1731f3dd8508SAlex Deucher list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { 1732f3dd8508SAlex Deucher if (crtc == test_crtc) 1733f3dd8508SAlex Deucher continue; 1734f3dd8508SAlex Deucher 173557b35e29SAlex Deucher test_radeon_crtc = to_radeon_crtc(test_crtc); 173657b35e29SAlex Deucher if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID) 173757b35e29SAlex Deucher pll_in_use |= (1 << test_radeon_crtc->pll_id); 1738f3dd8508SAlex Deucher } 1739f3dd8508SAlex Deucher return pll_in_use; 1740f3dd8508SAlex Deucher } 1741f3dd8508SAlex Deucher 1742f3dd8508SAlex Deucher /** 1743f3dd8508SAlex Deucher * radeon_get_shared_dp_ppll - return the PPLL used by another crtc for DP 1744f3dd8508SAlex Deucher * 1745f3dd8508SAlex Deucher * @crtc: drm crtc 1746f3dd8508SAlex Deucher * 1747f3dd8508SAlex Deucher * Returns the PPLL (Pixel PLL) used by another crtc/encoder which is 1748f3dd8508SAlex Deucher * also in DP mode. For DP, a single PPLL can be used for all DP 1749f3dd8508SAlex Deucher * crtcs/encoders. 1750f3dd8508SAlex Deucher */ 1751f3dd8508SAlex Deucher static int radeon_get_shared_dp_ppll(struct drm_crtc *crtc) 1752f3dd8508SAlex Deucher { 1753f3dd8508SAlex Deucher struct drm_device *dev = crtc->dev; 1754e3c00d87SLucas Stach struct radeon_device *rdev = dev->dev_private; 175557b35e29SAlex Deucher struct drm_crtc *test_crtc; 17565df3196bSAlex Deucher struct radeon_crtc *test_radeon_crtc; 1757f3dd8508SAlex Deucher 175857b35e29SAlex Deucher list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { 175957b35e29SAlex Deucher if (crtc == test_crtc) 176057b35e29SAlex Deucher continue; 176157b35e29SAlex Deucher test_radeon_crtc = to_radeon_crtc(test_crtc); 176257b35e29SAlex Deucher if (test_radeon_crtc->encoder && 176357b35e29SAlex Deucher ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_radeon_crtc->encoder))) { 1764e3c00d87SLucas Stach /* PPLL2 is exclusive to UNIPHYA on DCE61 */ 1765e3c00d87SLucas Stach if (ASIC_IS_DCE61(rdev) && !ASIC_IS_DCE8(rdev) && 1766e3c00d87SLucas Stach test_radeon_crtc->pll_id == ATOM_PPLL2) 1767e3c00d87SLucas Stach continue; 1768f3dd8508SAlex Deucher /* for DP use the same PLL for all */ 17695df3196bSAlex Deucher if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID) 17705df3196bSAlex Deucher return test_radeon_crtc->pll_id; 1771f3dd8508SAlex Deucher } 1772f3dd8508SAlex Deucher } 1773f3dd8508SAlex Deucher return ATOM_PPLL_INVALID; 1774f3dd8508SAlex Deucher } 1775f3dd8508SAlex Deucher 1776f3dd8508SAlex Deucher /** 17772f454cf1SAlex Deucher * radeon_get_shared_nondp_ppll - return the PPLL used by another non-DP crtc 17782f454cf1SAlex Deucher * 17792f454cf1SAlex Deucher * @crtc: drm crtc 17802f454cf1SAlex Deucher * 17812f454cf1SAlex Deucher * Returns the PPLL (Pixel PLL) used by another non-DP crtc/encoder which can 17822f454cf1SAlex Deucher * be shared (i.e., same clock). 17832f454cf1SAlex Deucher */ 17845df3196bSAlex Deucher static int radeon_get_shared_nondp_ppll(struct drm_crtc *crtc) 17852f454cf1SAlex Deucher { 17865df3196bSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 17872f454cf1SAlex Deucher struct drm_device *dev = crtc->dev; 1788e3c00d87SLucas Stach struct radeon_device *rdev = dev->dev_private; 17899642ac0eSAlex Deucher struct drm_crtc *test_crtc; 17905df3196bSAlex Deucher struct radeon_crtc *test_radeon_crtc; 17919642ac0eSAlex Deucher u32 adjusted_clock, test_adjusted_clock; 17922f454cf1SAlex Deucher 17939642ac0eSAlex Deucher adjusted_clock = radeon_crtc->adjusted_clock; 17949642ac0eSAlex Deucher 17959642ac0eSAlex Deucher if (adjusted_clock == 0) 17969642ac0eSAlex Deucher return ATOM_PPLL_INVALID; 17972f454cf1SAlex Deucher 179857b35e29SAlex Deucher list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { 179957b35e29SAlex Deucher if (crtc == test_crtc) 180057b35e29SAlex Deucher continue; 18019642ac0eSAlex Deucher test_radeon_crtc = to_radeon_crtc(test_crtc); 180257b35e29SAlex Deucher if (test_radeon_crtc->encoder && 180357b35e29SAlex Deucher !ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_radeon_crtc->encoder))) { 1804e3c00d87SLucas Stach /* PPLL2 is exclusive to UNIPHYA on DCE61 */ 1805e3c00d87SLucas Stach if (ASIC_IS_DCE61(rdev) && !ASIC_IS_DCE8(rdev) && 1806e3c00d87SLucas Stach test_radeon_crtc->pll_id == ATOM_PPLL2) 1807e3c00d87SLucas Stach continue; 180857b35e29SAlex Deucher /* check if we are already driving this connector with another crtc */ 180957b35e29SAlex Deucher if (test_radeon_crtc->connector == radeon_crtc->connector) { 181057b35e29SAlex Deucher /* if we are, return that pll */ 181157b35e29SAlex Deucher if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID) 181257b35e29SAlex Deucher return test_radeon_crtc->pll_id; 181357b35e29SAlex Deucher } 18142f454cf1SAlex Deucher /* for non-DP check the clock */ 18159642ac0eSAlex Deucher test_adjusted_clock = test_radeon_crtc->adjusted_clock; 18169642ac0eSAlex Deucher if ((crtc->mode.clock == test_crtc->mode.clock) && 18179642ac0eSAlex Deucher (adjusted_clock == test_adjusted_clock) && 18189642ac0eSAlex Deucher (radeon_crtc->ss_enabled == test_radeon_crtc->ss_enabled) && 18196fb3c025SAlex Deucher (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID)) 18205df3196bSAlex Deucher return test_radeon_crtc->pll_id; 18212f454cf1SAlex Deucher } 18222f454cf1SAlex Deucher } 18232f454cf1SAlex Deucher return ATOM_PPLL_INVALID; 18242f454cf1SAlex Deucher } 18252f454cf1SAlex Deucher 18262f454cf1SAlex Deucher /** 1827f3dd8508SAlex Deucher * radeon_atom_pick_pll - Allocate a PPLL for use by the crtc. 1828f3dd8508SAlex Deucher * 1829f3dd8508SAlex Deucher * @crtc: drm crtc 1830f3dd8508SAlex Deucher * 1831f3dd8508SAlex Deucher * Returns the PPLL (Pixel PLL) to be used by the crtc. For DP monitors 1832f3dd8508SAlex Deucher * a single PPLL can be used for all DP crtcs/encoders. For non-DP 1833f3dd8508SAlex Deucher * monitors a dedicated PPLL must be used. If a particular board has 1834f3dd8508SAlex Deucher * an external DP PLL, return ATOM_PPLL_INVALID to skip PLL programming 1835f3dd8508SAlex Deucher * as there is no need to program the PLL itself. If we are not able to 1836f3dd8508SAlex Deucher * allocate a PLL, return ATOM_PPLL_INVALID to skip PLL programming to 1837f3dd8508SAlex Deucher * avoid messing up an existing monitor. 1838f3dd8508SAlex Deucher * 1839f3dd8508SAlex Deucher * Asic specific PLL information 1840f3dd8508SAlex Deucher * 18410331f674SAlex Deucher * DCE 8.x 18420331f674SAlex Deucher * KB/KV 18430331f674SAlex Deucher * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) 18440331f674SAlex Deucher * CI 18450331f674SAlex Deucher * - PPLL0, PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC 18460331f674SAlex Deucher * 1847f3dd8508SAlex Deucher * DCE 6.1 1848f3dd8508SAlex Deucher * - PPLL2 is only available to UNIPHYA (both DP and non-DP) 1849f3dd8508SAlex Deucher * - PPLL0, PPLL1 are available for UNIPHYB/C/D/E/F (both DP and non-DP) 1850f3dd8508SAlex Deucher * 1851f3dd8508SAlex Deucher * DCE 6.0 1852f3dd8508SAlex Deucher * - PPLL0 is available to all UNIPHY (DP only) 1853f3dd8508SAlex Deucher * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC 1854f3dd8508SAlex Deucher * 1855f3dd8508SAlex Deucher * DCE 5.0 1856f3dd8508SAlex Deucher * - DCPLL is available to all UNIPHY (DP only) 1857f3dd8508SAlex Deucher * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC 1858f3dd8508SAlex Deucher * 1859f3dd8508SAlex Deucher * DCE 3.0/4.0/4.1 1860f3dd8508SAlex Deucher * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC 1861f3dd8508SAlex Deucher * 1862f3dd8508SAlex Deucher */ 1863bcc1c2a1SAlex Deucher static int radeon_atom_pick_pll(struct drm_crtc *crtc) 1864bcc1c2a1SAlex Deucher { 18655df3196bSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1866bcc1c2a1SAlex Deucher struct drm_device *dev = crtc->dev; 1867bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 18685df3196bSAlex Deucher struct radeon_encoder *radeon_encoder = 18695df3196bSAlex Deucher to_radeon_encoder(radeon_crtc->encoder); 1870f3dd8508SAlex Deucher u32 pll_in_use; 1871f3dd8508SAlex Deucher int pll; 1872bcc1c2a1SAlex Deucher 18730331f674SAlex Deucher if (ASIC_IS_DCE8(rdev)) { 18740331f674SAlex Deucher if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { 18750331f674SAlex Deucher if (rdev->clock.dp_extclk) 18760331f674SAlex Deucher /* skip PPLL programming if using ext clock */ 18770331f674SAlex Deucher return ATOM_PPLL_INVALID; 18780331f674SAlex Deucher else { 18790331f674SAlex Deucher /* use the same PPLL for all DP monitors */ 18800331f674SAlex Deucher pll = radeon_get_shared_dp_ppll(crtc); 18810331f674SAlex Deucher if (pll != ATOM_PPLL_INVALID) 18820331f674SAlex Deucher return pll; 18830331f674SAlex Deucher } 18840331f674SAlex Deucher } else { 18850331f674SAlex Deucher /* use the same PPLL for all monitors with the same clock */ 18860331f674SAlex Deucher pll = radeon_get_shared_nondp_ppll(crtc); 18870331f674SAlex Deucher if (pll != ATOM_PPLL_INVALID) 18880331f674SAlex Deucher return pll; 18890331f674SAlex Deucher } 18900331f674SAlex Deucher /* otherwise, pick one of the plls */ 1891fbedf1c3SAlex Deucher if ((rdev->family == CHIP_KABINI) || 1892b214f2a4SSamuel Li (rdev->family == CHIP_MULLINS)) { 1893fbedf1c3SAlex Deucher /* KB/ML has PPLL1 and PPLL2 */ 18940331f674SAlex Deucher pll_in_use = radeon_get_pll_use_mask(crtc); 18950331f674SAlex Deucher if (!(pll_in_use & (1 << ATOM_PPLL2))) 18960331f674SAlex Deucher return ATOM_PPLL2; 18970331f674SAlex Deucher if (!(pll_in_use & (1 << ATOM_PPLL1))) 18980331f674SAlex Deucher return ATOM_PPLL1; 18990331f674SAlex Deucher DRM_ERROR("unable to allocate a PPLL\n"); 19000331f674SAlex Deucher return ATOM_PPLL_INVALID; 19010331f674SAlex Deucher } else { 1902fbedf1c3SAlex Deucher /* CI/KV has PPLL0, PPLL1, and PPLL2 */ 19030331f674SAlex Deucher pll_in_use = radeon_get_pll_use_mask(crtc); 19040331f674SAlex Deucher if (!(pll_in_use & (1 << ATOM_PPLL2))) 19050331f674SAlex Deucher return ATOM_PPLL2; 19060331f674SAlex Deucher if (!(pll_in_use & (1 << ATOM_PPLL1))) 19070331f674SAlex Deucher return ATOM_PPLL1; 19080331f674SAlex Deucher if (!(pll_in_use & (1 << ATOM_PPLL0))) 19090331f674SAlex Deucher return ATOM_PPLL0; 19100331f674SAlex Deucher DRM_ERROR("unable to allocate a PPLL\n"); 19110331f674SAlex Deucher return ATOM_PPLL_INVALID; 19120331f674SAlex Deucher } 19130331f674SAlex Deucher } else if (ASIC_IS_DCE61(rdev)) { 191424e1f794SAlex Deucher struct radeon_encoder_atom_dig *dig = 19155df3196bSAlex Deucher radeon_encoder->enc_priv; 191624e1f794SAlex Deucher 19175df3196bSAlex Deucher if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY) && 1918f3dd8508SAlex Deucher (dig->linkb == false)) 1919f3dd8508SAlex Deucher /* UNIPHY A uses PPLL2 */ 192024e1f794SAlex Deucher return ATOM_PPLL2; 19215df3196bSAlex Deucher else if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { 1922f3dd8508SAlex Deucher /* UNIPHY B/C/D/E/F */ 1923f3dd8508SAlex Deucher if (rdev->clock.dp_extclk) 1924f3dd8508SAlex Deucher /* skip PPLL programming if using ext clock */ 1925f3dd8508SAlex Deucher return ATOM_PPLL_INVALID; 1926f3dd8508SAlex Deucher else { 1927f3dd8508SAlex Deucher /* use the same PPLL for all DP monitors */ 1928f3dd8508SAlex Deucher pll = radeon_get_shared_dp_ppll(crtc); 1929f3dd8508SAlex Deucher if (pll != ATOM_PPLL_INVALID) 1930f3dd8508SAlex Deucher return pll; 1931f3dd8508SAlex Deucher } 19322f454cf1SAlex Deucher } else { 19332f454cf1SAlex Deucher /* use the same PPLL for all monitors with the same clock */ 19345df3196bSAlex Deucher pll = radeon_get_shared_nondp_ppll(crtc); 19352f454cf1SAlex Deucher if (pll != ATOM_PPLL_INVALID) 19362f454cf1SAlex Deucher return pll; 1937f3dd8508SAlex Deucher } 193824e1f794SAlex Deucher /* UNIPHY B/C/D/E/F */ 1939f3dd8508SAlex Deucher pll_in_use = radeon_get_pll_use_mask(crtc); 1940f3dd8508SAlex Deucher if (!(pll_in_use & (1 << ATOM_PPLL0))) 194124e1f794SAlex Deucher return ATOM_PPLL0; 1942f3dd8508SAlex Deucher if (!(pll_in_use & (1 << ATOM_PPLL1))) 194324e1f794SAlex Deucher return ATOM_PPLL1; 1944f3dd8508SAlex Deucher DRM_ERROR("unable to allocate a PPLL\n"); 1945f3dd8508SAlex Deucher return ATOM_PPLL_INVALID; 19469ef4e1d0SAlex Deucher } else if (ASIC_IS_DCE41(rdev)) { 19479ef4e1d0SAlex Deucher /* Don't share PLLs on DCE4.1 chips */ 19489ef4e1d0SAlex Deucher if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { 19499ef4e1d0SAlex Deucher if (rdev->clock.dp_extclk) 19509ef4e1d0SAlex Deucher /* skip PPLL programming if using ext clock */ 19519ef4e1d0SAlex Deucher return ATOM_PPLL_INVALID; 19529ef4e1d0SAlex Deucher } 19539ef4e1d0SAlex Deucher pll_in_use = radeon_get_pll_use_mask(crtc); 19549ef4e1d0SAlex Deucher if (!(pll_in_use & (1 << ATOM_PPLL1))) 19559ef4e1d0SAlex Deucher return ATOM_PPLL1; 19569ef4e1d0SAlex Deucher if (!(pll_in_use & (1 << ATOM_PPLL2))) 19579ef4e1d0SAlex Deucher return ATOM_PPLL2; 19589ef4e1d0SAlex Deucher DRM_ERROR("unable to allocate a PPLL\n"); 19599ef4e1d0SAlex Deucher return ATOM_PPLL_INVALID; 196024e1f794SAlex Deucher } else if (ASIC_IS_DCE4(rdev)) { 196186a94defSAlex Deucher /* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock, 196286a94defSAlex Deucher * depending on the asic: 196386a94defSAlex Deucher * DCE4: PPLL or ext clock 1964f3dd8508SAlex Deucher * DCE5: PPLL, DCPLL, or ext clock 1965f3dd8508SAlex Deucher * DCE6: PPLL, PPLL0, or ext clock 196686a94defSAlex Deucher * 196786a94defSAlex Deucher * Setting ATOM_PPLL_INVALID will cause SetPixelClock to skip 196886a94defSAlex Deucher * PPLL/DCPLL programming and only program the DP DTO for the 196986a94defSAlex Deucher * crtc virtual pixel clock. 197086a94defSAlex Deucher */ 19715df3196bSAlex Deucher if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { 1972ecd67955SAlex Deucher if (rdev->clock.dp_extclk) 1973f3dd8508SAlex Deucher /* skip PPLL programming if using ext clock */ 1974ecd67955SAlex Deucher return ATOM_PPLL_INVALID; 197526fe45a0SAlex Deucher else if (ASIC_IS_DCE6(rdev)) 1976f3dd8508SAlex Deucher /* use PPLL0 for all DP */ 197726fe45a0SAlex Deucher return ATOM_PPLL0; 1978ecd67955SAlex Deucher else if (ASIC_IS_DCE5(rdev)) 1979f3dd8508SAlex Deucher /* use DCPLL for all DP */ 1980ecd67955SAlex Deucher return ATOM_DCPLL; 1981f3dd8508SAlex Deucher else { 1982f3dd8508SAlex Deucher /* use the same PPLL for all DP monitors */ 1983f3dd8508SAlex Deucher pll = radeon_get_shared_dp_ppll(crtc); 1984f3dd8508SAlex Deucher if (pll != ATOM_PPLL_INVALID) 1985f3dd8508SAlex Deucher return pll; 1986bcc1c2a1SAlex Deucher } 19879ef4e1d0SAlex Deucher } else { 19882f454cf1SAlex Deucher /* use the same PPLL for all monitors with the same clock */ 19895df3196bSAlex Deucher pll = radeon_get_shared_nondp_ppll(crtc); 19909dbbcfc6SAlex Deucher if (pll != ATOM_PPLL_INVALID) 19919dbbcfc6SAlex Deucher return pll; 19929dbbcfc6SAlex Deucher } 19935df3196bSAlex Deucher /* all other cases */ 19945df3196bSAlex Deucher pll_in_use = radeon_get_pll_use_mask(crtc); 19955df3196bSAlex Deucher if (!(pll_in_use & (1 << ATOM_PPLL1))) 19965df3196bSAlex Deucher return ATOM_PPLL1; 199729dbe3bcSAlex Deucher if (!(pll_in_use & (1 << ATOM_PPLL2))) 199829dbe3bcSAlex Deucher return ATOM_PPLL2; 19995df3196bSAlex Deucher DRM_ERROR("unable to allocate a PPLL\n"); 20005df3196bSAlex Deucher return ATOM_PPLL_INVALID; 20012f454cf1SAlex Deucher } else { 20022f454cf1SAlex Deucher /* on pre-R5xx asics, the crtc to pll mapping is hardcoded */ 2003fc58acdbSJerome Glisse /* some atombios (observed in some DCE2/DCE3) code have a bug, 2004fc58acdbSJerome Glisse * the matching btw pll and crtc is done through 2005fc58acdbSJerome Glisse * PCLK_CRTC[1|2]_CNTL (0x480/0x484) but atombios code use the 2006fc58acdbSJerome Glisse * pll (1 or 2) to select which register to write. ie if using 2007fc58acdbSJerome Glisse * pll1 it will use PCLK_CRTC1_CNTL (0x480) and if using pll2 2008fc58acdbSJerome Glisse * it will use PCLK_CRTC2_CNTL (0x484), it then use crtc id to 2009fc58acdbSJerome Glisse * choose which value to write. Which is reverse order from 2010fc58acdbSJerome Glisse * register logic. So only case that works is when pllid is 2011fc58acdbSJerome Glisse * same as crtcid or when both pll and crtc are enabled and 2012fc58acdbSJerome Glisse * both use same clock. 2013fc58acdbSJerome Glisse * 2014fc58acdbSJerome Glisse * So just return crtc id as if crtc and pll were hard linked 2015fc58acdbSJerome Glisse * together even if they aren't 2016fc58acdbSJerome Glisse */ 2017bcc1c2a1SAlex Deucher return radeon_crtc->crtc_id; 20182f454cf1SAlex Deucher } 20192f454cf1SAlex Deucher } 2020bcc1c2a1SAlex Deucher 2021f3f1f03eSAlex Deucher void radeon_atom_disp_eng_pll_init(struct radeon_device *rdev) 20223fa47d9eSAlex Deucher { 20233fa47d9eSAlex Deucher /* always set DCPLL */ 2024f3f1f03eSAlex Deucher if (ASIC_IS_DCE6(rdev)) 2025f3f1f03eSAlex Deucher atombios_crtc_set_disp_eng_pll(rdev, rdev->clock.default_dispclk); 2026f3f1f03eSAlex Deucher else if (ASIC_IS_DCE4(rdev)) { 20273fa47d9eSAlex Deucher struct radeon_atom_ss ss; 20283fa47d9eSAlex Deucher bool ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &ss, 20293fa47d9eSAlex Deucher ASIC_INTERNAL_SS_ON_DCPLL, 20303fa47d9eSAlex Deucher rdev->clock.default_dispclk); 20313fa47d9eSAlex Deucher if (ss_enabled) 20325efcc76cSJerome Glisse atombios_crtc_program_ss(rdev, ATOM_DISABLE, ATOM_DCPLL, -1, &ss); 20333fa47d9eSAlex Deucher /* XXX: DCE5, make sure voltage, dispclk is high enough */ 2034f3f1f03eSAlex Deucher atombios_crtc_set_disp_eng_pll(rdev, rdev->clock.default_dispclk); 20353fa47d9eSAlex Deucher if (ss_enabled) 20365efcc76cSJerome Glisse atombios_crtc_program_ss(rdev, ATOM_ENABLE, ATOM_DCPLL, -1, &ss); 20373fa47d9eSAlex Deucher } 20383fa47d9eSAlex Deucher 20393fa47d9eSAlex Deucher } 20403fa47d9eSAlex Deucher 2041771fe6b9SJerome Glisse int atombios_crtc_mode_set(struct drm_crtc *crtc, 2042771fe6b9SJerome Glisse struct drm_display_mode *mode, 2043771fe6b9SJerome Glisse struct drm_display_mode *adjusted_mode, 2044771fe6b9SJerome Glisse int x, int y, struct drm_framebuffer *old_fb) 2045771fe6b9SJerome Glisse { 2046771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 2047771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 2048771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 20495df3196bSAlex Deucher struct radeon_encoder *radeon_encoder = 20505df3196bSAlex Deucher to_radeon_encoder(radeon_crtc->encoder); 205154bfe496SAlex Deucher bool is_tvcv = false; 2052771fe6b9SJerome Glisse 205354bfe496SAlex Deucher if (radeon_encoder->active_device & 205454bfe496SAlex Deucher (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) 205554bfe496SAlex Deucher is_tvcv = true; 2056771fe6b9SJerome Glisse 2057cde10122SChristian König if (!radeon_crtc->adjusted_clock) 2058cde10122SChristian König return -EINVAL; 2059cde10122SChristian König 2060771fe6b9SJerome Glisse atombios_crtc_set_pll(crtc, adjusted_mode); 2061771fe6b9SJerome Glisse 206254bfe496SAlex Deucher if (ASIC_IS_DCE4(rdev)) 2063bcc1c2a1SAlex Deucher atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 206454bfe496SAlex Deucher else if (ASIC_IS_AVIVO(rdev)) { 206554bfe496SAlex Deucher if (is_tvcv) 206654bfe496SAlex Deucher atombios_crtc_set_timing(crtc, adjusted_mode); 206754bfe496SAlex Deucher else 206854bfe496SAlex Deucher atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 206954bfe496SAlex Deucher } else { 2070bcc1c2a1SAlex Deucher atombios_crtc_set_timing(crtc, adjusted_mode); 20715a9bcaccSAlex Deucher if (radeon_crtc->crtc_id == 0) 20725a9bcaccSAlex Deucher atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 2073615e0cb6SAlex Deucher radeon_legacy_atom_fixup(crtc); 2074771fe6b9SJerome Glisse } 2075bcc1c2a1SAlex Deucher atombios_crtc_set_base(crtc, x, y, old_fb); 2076c93bb85bSJerome Glisse atombios_overscan_setup(crtc, mode, adjusted_mode); 2077c93bb85bSJerome Glisse atombios_scaler_setup(crtc); 20786d3759faSMichel Dänzer radeon_cursor_reset(crtc); 207966edc1c9SAlex Deucher /* update the hw version fpr dpm */ 208066edc1c9SAlex Deucher radeon_crtc->hw_mode = *adjusted_mode; 208166edc1c9SAlex Deucher 2082771fe6b9SJerome Glisse return 0; 2083771fe6b9SJerome Glisse } 2084771fe6b9SJerome Glisse 2085771fe6b9SJerome Glisse static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, 2086e811f5aeSLaurent Pinchart const struct drm_display_mode *mode, 2087771fe6b9SJerome Glisse struct drm_display_mode *adjusted_mode) 2088771fe6b9SJerome Glisse { 20895df3196bSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 20905df3196bSAlex Deucher struct drm_device *dev = crtc->dev; 20915df3196bSAlex Deucher struct drm_encoder *encoder; 20925df3196bSAlex Deucher 20935df3196bSAlex Deucher /* assign the encoder to the radeon crtc to avoid repeated lookups later */ 20945df3196bSAlex Deucher list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 20955df3196bSAlex Deucher if (encoder->crtc == crtc) { 20965df3196bSAlex Deucher radeon_crtc->encoder = encoder; 209757b35e29SAlex Deucher radeon_crtc->connector = radeon_get_connector_for_encoder(encoder); 20985df3196bSAlex Deucher break; 20995df3196bSAlex Deucher } 21005df3196bSAlex Deucher } 210157b35e29SAlex Deucher if ((radeon_crtc->encoder == NULL) || (radeon_crtc->connector == NULL)) { 210257b35e29SAlex Deucher radeon_crtc->encoder = NULL; 210357b35e29SAlex Deucher radeon_crtc->connector = NULL; 21045df3196bSAlex Deucher return false; 210557b35e29SAlex Deucher } 2106643b1f56SAlex Deucher if (radeon_crtc->encoder) { 2107643b1f56SAlex Deucher struct radeon_encoder *radeon_encoder = 2108643b1f56SAlex Deucher to_radeon_encoder(radeon_crtc->encoder); 2109643b1f56SAlex Deucher 2110643b1f56SAlex Deucher radeon_crtc->output_csc = radeon_encoder->output_csc; 2111643b1f56SAlex Deucher } 2112c93bb85bSJerome Glisse if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) 2113c93bb85bSJerome Glisse return false; 211419eca43eSAlex Deucher if (!atombios_crtc_prepare_pll(crtc, adjusted_mode)) 211519eca43eSAlex Deucher return false; 2116c0fd0834SAlex Deucher /* pick pll */ 2117c0fd0834SAlex Deucher radeon_crtc->pll_id = radeon_atom_pick_pll(crtc); 2118c0fd0834SAlex Deucher /* if we can't get a PPLL for a non-DP encoder, fail */ 2119c0fd0834SAlex Deucher if ((radeon_crtc->pll_id == ATOM_PPLL_INVALID) && 2120c0fd0834SAlex Deucher !ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) 2121c0fd0834SAlex Deucher return false; 2122c0fd0834SAlex Deucher 2123771fe6b9SJerome Glisse return true; 2124771fe6b9SJerome Glisse } 2125771fe6b9SJerome Glisse 2126771fe6b9SJerome Glisse static void atombios_crtc_prepare(struct drm_crtc *crtc) 2127771fe6b9SJerome Glisse { 21286c0ae2abSAlex Deucher struct drm_device *dev = crtc->dev; 21296c0ae2abSAlex Deucher struct radeon_device *rdev = dev->dev_private; 2130267364acSAlex Deucher 21316c0ae2abSAlex Deucher /* disable crtc pair power gating before programming */ 21326c0ae2abSAlex Deucher if (ASIC_IS_DCE6(rdev)) 21336c0ae2abSAlex Deucher atombios_powergate_crtc(crtc, ATOM_DISABLE); 21346c0ae2abSAlex Deucher 213537b4390eSAlex Deucher atombios_lock_crtc(crtc, ATOM_ENABLE); 2136a348c84dSAlex Deucher atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 2137771fe6b9SJerome Glisse } 2138771fe6b9SJerome Glisse 2139771fe6b9SJerome Glisse static void atombios_crtc_commit(struct drm_crtc *crtc) 2140771fe6b9SJerome Glisse { 2141771fe6b9SJerome Glisse atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON); 214237b4390eSAlex Deucher atombios_lock_crtc(crtc, ATOM_DISABLE); 2143771fe6b9SJerome Glisse } 2144771fe6b9SJerome Glisse 214537f9003bSAlex Deucher static void atombios_crtc_disable(struct drm_crtc *crtc) 214637f9003bSAlex Deucher { 214737f9003bSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 214864199870SAlex Deucher struct drm_device *dev = crtc->dev; 214964199870SAlex Deucher struct radeon_device *rdev = dev->dev_private; 21508e8e523dSAlex Deucher struct radeon_atom_ss ss; 21514e58591cSAlex Deucher int i; 21528e8e523dSAlex Deucher 215337f9003bSAlex Deucher atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 2154f4510a27SMatt Roper if (crtc->primary->fb) { 215575b871e2SIlija Hadzic int r; 215675b871e2SIlija Hadzic struct radeon_bo *rbo; 215775b871e2SIlija Hadzic 21589a0f0c9dSDaniel Stone rbo = gem_to_radeon_bo(crtc->primary->fb->obj[0]); 215975b871e2SIlija Hadzic r = radeon_bo_reserve(rbo, false); 216075b871e2SIlija Hadzic if (unlikely(r)) 216175b871e2SIlija Hadzic DRM_ERROR("failed to reserve rbo before unpin\n"); 216275b871e2SIlija Hadzic else { 216375b871e2SIlija Hadzic radeon_bo_unpin(rbo); 216475b871e2SIlija Hadzic radeon_bo_unreserve(rbo); 216575b871e2SIlija Hadzic } 216675b871e2SIlija Hadzic } 2167ac4d04d4SAlex Deucher /* disable the GRPH */ 2168ac4d04d4SAlex Deucher if (ASIC_IS_DCE4(rdev)) 2169ac4d04d4SAlex Deucher WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 0); 2170ac4d04d4SAlex Deucher else if (ASIC_IS_AVIVO(rdev)) 2171ac4d04d4SAlex Deucher WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 0); 2172ac4d04d4SAlex Deucher 21730e3d50bfSAlex Deucher if (ASIC_IS_DCE6(rdev)) 21740e3d50bfSAlex Deucher atombios_powergate_crtc(crtc, ATOM_ENABLE); 217537f9003bSAlex Deucher 21764e58591cSAlex Deucher for (i = 0; i < rdev->num_crtc; i++) { 21774e58591cSAlex Deucher if (rdev->mode_info.crtcs[i] && 21784e58591cSAlex Deucher rdev->mode_info.crtcs[i]->enabled && 21794e58591cSAlex Deucher i != radeon_crtc->crtc_id && 21804e58591cSAlex Deucher radeon_crtc->pll_id == rdev->mode_info.crtcs[i]->pll_id) { 21814e58591cSAlex Deucher /* one other crtc is using this pll don't turn 21824e58591cSAlex Deucher * off the pll 21834e58591cSAlex Deucher */ 21844e58591cSAlex Deucher goto done; 21854e58591cSAlex Deucher } 21864e58591cSAlex Deucher } 21874e58591cSAlex Deucher 218837f9003bSAlex Deucher switch (radeon_crtc->pll_id) { 218937f9003bSAlex Deucher case ATOM_PPLL1: 219037f9003bSAlex Deucher case ATOM_PPLL2: 219137f9003bSAlex Deucher /* disable the ppll */ 219237f9003bSAlex Deucher atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, 21938e8e523dSAlex Deucher 0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss); 219437f9003bSAlex Deucher break; 219564199870SAlex Deucher case ATOM_PPLL0: 219664199870SAlex Deucher /* disable the ppll */ 21977eeeabfcSAlex Deucher if ((rdev->family == CHIP_ARUBA) || 2198fbedf1c3SAlex Deucher (rdev->family == CHIP_KAVERI) || 21997eeeabfcSAlex Deucher (rdev->family == CHIP_BONAIRE) || 22007eeeabfcSAlex Deucher (rdev->family == CHIP_HAWAII)) 220164199870SAlex Deucher atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, 220264199870SAlex Deucher 0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss); 220364199870SAlex Deucher break; 220437f9003bSAlex Deucher default: 220537f9003bSAlex Deucher break; 220637f9003bSAlex Deucher } 22074e58591cSAlex Deucher done: 2208f3dd8508SAlex Deucher radeon_crtc->pll_id = ATOM_PPLL_INVALID; 22099642ac0eSAlex Deucher radeon_crtc->adjusted_clock = 0; 22105df3196bSAlex Deucher radeon_crtc->encoder = NULL; 221157b35e29SAlex Deucher radeon_crtc->connector = NULL; 221237f9003bSAlex Deucher } 221337f9003bSAlex Deucher 2214771fe6b9SJerome Glisse static const struct drm_crtc_helper_funcs atombios_helper_funcs = { 2215771fe6b9SJerome Glisse .dpms = atombios_crtc_dpms, 2216771fe6b9SJerome Glisse .mode_fixup = atombios_crtc_mode_fixup, 2217771fe6b9SJerome Glisse .mode_set = atombios_crtc_mode_set, 2218771fe6b9SJerome Glisse .mode_set_base = atombios_crtc_set_base, 22194dd19b0dSChris Ball .mode_set_base_atomic = atombios_crtc_set_base_atomic, 2220771fe6b9SJerome Glisse .prepare = atombios_crtc_prepare, 2221771fe6b9SJerome Glisse .commit = atombios_crtc_commit, 222237f9003bSAlex Deucher .disable = atombios_crtc_disable, 222327b4118dSThomas Zimmermann .get_scanout_position = radeon_get_crtc_scanout_position, 2224771fe6b9SJerome Glisse }; 2225771fe6b9SJerome Glisse 2226771fe6b9SJerome Glisse void radeon_atombios_init_crtc(struct drm_device *dev, 2227771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc) 2228771fe6b9SJerome Glisse { 2229bcc1c2a1SAlex Deucher struct radeon_device *rdev = dev->dev_private; 2230bcc1c2a1SAlex Deucher 2231bcc1c2a1SAlex Deucher if (ASIC_IS_DCE4(rdev)) { 2232bcc1c2a1SAlex Deucher switch (radeon_crtc->crtc_id) { 2233bcc1c2a1SAlex Deucher case 0: 2234bcc1c2a1SAlex Deucher default: 223512d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC0_REGISTER_OFFSET; 2236bcc1c2a1SAlex Deucher break; 2237bcc1c2a1SAlex Deucher case 1: 223812d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC1_REGISTER_OFFSET; 2239bcc1c2a1SAlex Deucher break; 2240bcc1c2a1SAlex Deucher case 2: 224112d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC2_REGISTER_OFFSET; 2242bcc1c2a1SAlex Deucher break; 2243bcc1c2a1SAlex Deucher case 3: 224412d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC3_REGISTER_OFFSET; 2245bcc1c2a1SAlex Deucher break; 2246bcc1c2a1SAlex Deucher case 4: 224712d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC4_REGISTER_OFFSET; 2248bcc1c2a1SAlex Deucher break; 2249bcc1c2a1SAlex Deucher case 5: 225012d7798fSAlex Deucher radeon_crtc->crtc_offset = EVERGREEN_CRTC5_REGISTER_OFFSET; 2251bcc1c2a1SAlex Deucher break; 2252bcc1c2a1SAlex Deucher } 2253bcc1c2a1SAlex Deucher } else { 2254771fe6b9SJerome Glisse if (radeon_crtc->crtc_id == 1) 2255771fe6b9SJerome Glisse radeon_crtc->crtc_offset = 2256771fe6b9SJerome Glisse AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL; 2257bcc1c2a1SAlex Deucher else 2258bcc1c2a1SAlex Deucher radeon_crtc->crtc_offset = 0; 2259bcc1c2a1SAlex Deucher } 2260f3dd8508SAlex Deucher radeon_crtc->pll_id = ATOM_PPLL_INVALID; 22619642ac0eSAlex Deucher radeon_crtc->adjusted_clock = 0; 22625df3196bSAlex Deucher radeon_crtc->encoder = NULL; 226357b35e29SAlex Deucher radeon_crtc->connector = NULL; 2264771fe6b9SJerome Glisse drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); 2265771fe6b9SJerome Glisse } 2266