1771fe6b9SJerome Glisse /* 2771fe6b9SJerome Glisse * Copyright 2007-8 Advanced Micro Devices, Inc. 3771fe6b9SJerome Glisse * Copyright 2008 Red Hat Inc. 4771fe6b9SJerome Glisse * 5771fe6b9SJerome Glisse * Permission is hereby granted, free of charge, to any person obtaining a 6771fe6b9SJerome Glisse * copy of this software and associated documentation files (the "Software"), 7771fe6b9SJerome Glisse * to deal in the Software without restriction, including without limitation 8771fe6b9SJerome Glisse * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9771fe6b9SJerome Glisse * and/or sell copies of the Software, and to permit persons to whom the 10771fe6b9SJerome Glisse * Software is furnished to do so, subject to the following conditions: 11771fe6b9SJerome Glisse * 12771fe6b9SJerome Glisse * The above copyright notice and this permission notice shall be included in 13771fe6b9SJerome Glisse * all copies or substantial portions of the Software. 14771fe6b9SJerome Glisse * 15771fe6b9SJerome Glisse * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16771fe6b9SJerome Glisse * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17771fe6b9SJerome Glisse * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18771fe6b9SJerome Glisse * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 19771fe6b9SJerome Glisse * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20771fe6b9SJerome Glisse * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21771fe6b9SJerome Glisse * OTHER DEALINGS IN THE SOFTWARE. 22771fe6b9SJerome Glisse * 23771fe6b9SJerome Glisse * Authors: Dave Airlie 24771fe6b9SJerome Glisse * Alex Deucher 25771fe6b9SJerome Glisse */ 26771fe6b9SJerome Glisse #include <drm/drmP.h> 27771fe6b9SJerome Glisse #include <drm/drm_crtc_helper.h> 28771fe6b9SJerome Glisse #include <drm/radeon_drm.h> 29771fe6b9SJerome Glisse #include "radeon_fixed.h" 30771fe6b9SJerome Glisse #include "radeon.h" 31771fe6b9SJerome Glisse #include "atom.h" 32771fe6b9SJerome Glisse #include "atom-bits.h" 33771fe6b9SJerome Glisse 34c93bb85bSJerome Glisse static void atombios_overscan_setup(struct drm_crtc *crtc, 35c93bb85bSJerome Glisse struct drm_display_mode *mode, 36c93bb85bSJerome Glisse struct drm_display_mode *adjusted_mode) 37c93bb85bSJerome Glisse { 38c93bb85bSJerome Glisse struct drm_device *dev = crtc->dev; 39c93bb85bSJerome Glisse struct radeon_device *rdev = dev->dev_private; 40c93bb85bSJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 41c93bb85bSJerome Glisse SET_CRTC_OVERSCAN_PS_ALLOCATION args; 42c93bb85bSJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan); 43c93bb85bSJerome Glisse int a1, a2; 44c93bb85bSJerome Glisse 45c93bb85bSJerome Glisse memset(&args, 0, sizeof(args)); 46c93bb85bSJerome Glisse 47c93bb85bSJerome Glisse args.usOverscanRight = 0; 48c93bb85bSJerome Glisse args.usOverscanLeft = 0; 49c93bb85bSJerome Glisse args.usOverscanBottom = 0; 50c93bb85bSJerome Glisse args.usOverscanTop = 0; 51c93bb85bSJerome Glisse args.ucCRTC = radeon_crtc->crtc_id; 52c93bb85bSJerome Glisse 53c93bb85bSJerome Glisse switch (radeon_crtc->rmx_type) { 54c93bb85bSJerome Glisse case RMX_CENTER: 55c93bb85bSJerome Glisse args.usOverscanTop = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2; 56c93bb85bSJerome Glisse args.usOverscanBottom = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2; 57c93bb85bSJerome Glisse args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2; 58c93bb85bSJerome Glisse args.usOverscanRight = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2; 59c93bb85bSJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 60c93bb85bSJerome Glisse break; 61c93bb85bSJerome Glisse case RMX_ASPECT: 62c93bb85bSJerome Glisse a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay; 63c93bb85bSJerome Glisse a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay; 64c93bb85bSJerome Glisse 65c93bb85bSJerome Glisse if (a1 > a2) { 66c93bb85bSJerome Glisse args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2; 67c93bb85bSJerome Glisse args.usOverscanRight = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2; 68c93bb85bSJerome Glisse } else if (a2 > a1) { 69c93bb85bSJerome Glisse args.usOverscanLeft = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2; 70c93bb85bSJerome Glisse args.usOverscanRight = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2; 71c93bb85bSJerome Glisse } 72c93bb85bSJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 73c93bb85bSJerome Glisse break; 74c93bb85bSJerome Glisse case RMX_FULL: 75c93bb85bSJerome Glisse default: 76c93bb85bSJerome Glisse args.usOverscanRight = 0; 77c93bb85bSJerome Glisse args.usOverscanLeft = 0; 78c93bb85bSJerome Glisse args.usOverscanBottom = 0; 79c93bb85bSJerome Glisse args.usOverscanTop = 0; 80c93bb85bSJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 81c93bb85bSJerome Glisse break; 82c93bb85bSJerome Glisse } 83c93bb85bSJerome Glisse } 84c93bb85bSJerome Glisse 85c93bb85bSJerome Glisse static void atombios_scaler_setup(struct drm_crtc *crtc) 86c93bb85bSJerome Glisse { 87c93bb85bSJerome Glisse struct drm_device *dev = crtc->dev; 88c93bb85bSJerome Glisse struct radeon_device *rdev = dev->dev_private; 89c93bb85bSJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 90c93bb85bSJerome Glisse ENABLE_SCALER_PS_ALLOCATION args; 91c93bb85bSJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, EnableScaler); 924ce001abSDave Airlie 93c93bb85bSJerome Glisse /* fixme - fill in enc_priv for atom dac */ 94c93bb85bSJerome Glisse enum radeon_tv_std tv_std = TV_STD_NTSC; 954ce001abSDave Airlie bool is_tv = false, is_cv = false; 964ce001abSDave Airlie struct drm_encoder *encoder; 97c93bb85bSJerome Glisse 98c93bb85bSJerome Glisse if (!ASIC_IS_AVIVO(rdev) && radeon_crtc->crtc_id) 99c93bb85bSJerome Glisse return; 100c93bb85bSJerome Glisse 1014ce001abSDave Airlie list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 1024ce001abSDave Airlie /* find tv std */ 1034ce001abSDave Airlie if (encoder->crtc == crtc) { 1044ce001abSDave Airlie struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 1054ce001abSDave Airlie if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) { 1064ce001abSDave Airlie struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv; 1074ce001abSDave Airlie tv_std = tv_dac->tv_std; 1084ce001abSDave Airlie is_tv = true; 1094ce001abSDave Airlie } 1104ce001abSDave Airlie } 1114ce001abSDave Airlie } 1124ce001abSDave Airlie 113c93bb85bSJerome Glisse memset(&args, 0, sizeof(args)); 114c93bb85bSJerome Glisse 115c93bb85bSJerome Glisse args.ucScaler = radeon_crtc->crtc_id; 116c93bb85bSJerome Glisse 1174ce001abSDave Airlie if (is_tv) { 118c93bb85bSJerome Glisse switch (tv_std) { 119c93bb85bSJerome Glisse case TV_STD_NTSC: 120c93bb85bSJerome Glisse default: 121c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_NTSC; 122c93bb85bSJerome Glisse break; 123c93bb85bSJerome Glisse case TV_STD_PAL: 124c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_PAL; 125c93bb85bSJerome Glisse break; 126c93bb85bSJerome Glisse case TV_STD_PAL_M: 127c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_PALM; 128c93bb85bSJerome Glisse break; 129c93bb85bSJerome Glisse case TV_STD_PAL_60: 130c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_PAL60; 131c93bb85bSJerome Glisse break; 132c93bb85bSJerome Glisse case TV_STD_NTSC_J: 133c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_NTSCJ; 134c93bb85bSJerome Glisse break; 135c93bb85bSJerome Glisse case TV_STD_SCART_PAL: 136c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_PAL; /* ??? */ 137c93bb85bSJerome Glisse break; 138c93bb85bSJerome Glisse case TV_STD_SECAM: 139c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_SECAM; 140c93bb85bSJerome Glisse break; 141c93bb85bSJerome Glisse case TV_STD_PAL_CN: 142c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_PALCN; 143c93bb85bSJerome Glisse break; 144c93bb85bSJerome Glisse } 145c93bb85bSJerome Glisse args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; 1464ce001abSDave Airlie } else if (is_cv) { 147c93bb85bSJerome Glisse args.ucTVStandard = ATOM_TV_CV; 148c93bb85bSJerome Glisse args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; 149c93bb85bSJerome Glisse } else { 150c93bb85bSJerome Glisse switch (radeon_crtc->rmx_type) { 151c93bb85bSJerome Glisse case RMX_FULL: 152c93bb85bSJerome Glisse args.ucEnable = ATOM_SCALER_EXPANSION; 153c93bb85bSJerome Glisse break; 154c93bb85bSJerome Glisse case RMX_CENTER: 155c93bb85bSJerome Glisse args.ucEnable = ATOM_SCALER_CENTER; 156c93bb85bSJerome Glisse break; 157c93bb85bSJerome Glisse case RMX_ASPECT: 158c93bb85bSJerome Glisse args.ucEnable = ATOM_SCALER_EXPANSION; 159c93bb85bSJerome Glisse break; 160c93bb85bSJerome Glisse default: 161c93bb85bSJerome Glisse if (ASIC_IS_AVIVO(rdev)) 162c93bb85bSJerome Glisse args.ucEnable = ATOM_SCALER_DISABLE; 163c93bb85bSJerome Glisse else 164c93bb85bSJerome Glisse args.ucEnable = ATOM_SCALER_CENTER; 165c93bb85bSJerome Glisse break; 166c93bb85bSJerome Glisse } 167c93bb85bSJerome Glisse } 168c93bb85bSJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 1694ce001abSDave Airlie if ((is_tv || is_cv) 1704ce001abSDave Airlie && rdev->family >= CHIP_RV515 && rdev->family <= CHIP_R580) { 1714ce001abSDave Airlie atom_rv515_force_tv_scaler(rdev, radeon_crtc); 172c93bb85bSJerome Glisse } 173c93bb85bSJerome Glisse } 174c93bb85bSJerome Glisse 175771fe6b9SJerome Glisse static void atombios_lock_crtc(struct drm_crtc *crtc, int lock) 176771fe6b9SJerome Glisse { 177771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 178771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 179771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 180771fe6b9SJerome Glisse int index = 181771fe6b9SJerome Glisse GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters); 182771fe6b9SJerome Glisse ENABLE_CRTC_PS_ALLOCATION args; 183771fe6b9SJerome Glisse 184771fe6b9SJerome Glisse memset(&args, 0, sizeof(args)); 185771fe6b9SJerome Glisse 186771fe6b9SJerome Glisse args.ucCRTC = radeon_crtc->crtc_id; 187771fe6b9SJerome Glisse args.ucEnable = lock; 188771fe6b9SJerome Glisse 189771fe6b9SJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 190771fe6b9SJerome Glisse } 191771fe6b9SJerome Glisse 192771fe6b9SJerome Glisse static void atombios_enable_crtc(struct drm_crtc *crtc, int state) 193771fe6b9SJerome Glisse { 194771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 195771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 196771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 197771fe6b9SJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC); 198771fe6b9SJerome Glisse ENABLE_CRTC_PS_ALLOCATION args; 199771fe6b9SJerome Glisse 200771fe6b9SJerome Glisse memset(&args, 0, sizeof(args)); 201771fe6b9SJerome Glisse 202771fe6b9SJerome Glisse args.ucCRTC = radeon_crtc->crtc_id; 203771fe6b9SJerome Glisse args.ucEnable = state; 204771fe6b9SJerome Glisse 205771fe6b9SJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 206771fe6b9SJerome Glisse } 207771fe6b9SJerome Glisse 208771fe6b9SJerome Glisse static void atombios_enable_crtc_memreq(struct drm_crtc *crtc, int state) 209771fe6b9SJerome Glisse { 210771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 211771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 212771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 213771fe6b9SJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, EnableCRTCMemReq); 214771fe6b9SJerome Glisse ENABLE_CRTC_PS_ALLOCATION args; 215771fe6b9SJerome Glisse 216771fe6b9SJerome Glisse memset(&args, 0, sizeof(args)); 217771fe6b9SJerome Glisse 218771fe6b9SJerome Glisse args.ucCRTC = radeon_crtc->crtc_id; 219771fe6b9SJerome Glisse args.ucEnable = state; 220771fe6b9SJerome Glisse 221771fe6b9SJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 222771fe6b9SJerome Glisse } 223771fe6b9SJerome Glisse 224771fe6b9SJerome Glisse static void atombios_blank_crtc(struct drm_crtc *crtc, int state) 225771fe6b9SJerome Glisse { 226771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 227771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 228771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 229771fe6b9SJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC); 230771fe6b9SJerome Glisse BLANK_CRTC_PS_ALLOCATION args; 231771fe6b9SJerome Glisse 232771fe6b9SJerome Glisse memset(&args, 0, sizeof(args)); 233771fe6b9SJerome Glisse 234771fe6b9SJerome Glisse args.ucCRTC = radeon_crtc->crtc_id; 235771fe6b9SJerome Glisse args.ucBlanking = state; 236771fe6b9SJerome Glisse 237771fe6b9SJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 238771fe6b9SJerome Glisse } 239771fe6b9SJerome Glisse 240771fe6b9SJerome Glisse void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) 241771fe6b9SJerome Glisse { 242771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 243771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 244500b7587SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 245771fe6b9SJerome Glisse 246771fe6b9SJerome Glisse switch (mode) { 247771fe6b9SJerome Glisse case DRM_MODE_DPMS_ON: 2485f9a0eb5SAlex Deucher atombios_enable_crtc(crtc, 1); 249771fe6b9SJerome Glisse if (ASIC_IS_DCE3(rdev)) 250771fe6b9SJerome Glisse atombios_enable_crtc_memreq(crtc, 1); 251771fe6b9SJerome Glisse atombios_blank_crtc(crtc, 0); 252500b7587SAlex Deucher drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); 253500b7587SAlex Deucher radeon_crtc_load_lut(crtc); 254771fe6b9SJerome Glisse break; 255771fe6b9SJerome Glisse case DRM_MODE_DPMS_STANDBY: 256771fe6b9SJerome Glisse case DRM_MODE_DPMS_SUSPEND: 257771fe6b9SJerome Glisse case DRM_MODE_DPMS_OFF: 258500b7587SAlex Deucher drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id); 259771fe6b9SJerome Glisse atombios_blank_crtc(crtc, 1); 260771fe6b9SJerome Glisse if (ASIC_IS_DCE3(rdev)) 261771fe6b9SJerome Glisse atombios_enable_crtc_memreq(crtc, 0); 2625f9a0eb5SAlex Deucher atombios_enable_crtc(crtc, 0); 263771fe6b9SJerome Glisse break; 264771fe6b9SJerome Glisse } 265771fe6b9SJerome Glisse } 266771fe6b9SJerome Glisse 267771fe6b9SJerome Glisse static void 268771fe6b9SJerome Glisse atombios_set_crtc_dtd_timing(struct drm_crtc *crtc, 2695a9bcaccSAlex Deucher struct drm_display_mode *mode) 270771fe6b9SJerome Glisse { 2715a9bcaccSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 272771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 273771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 2745a9bcaccSAlex Deucher SET_CRTC_USING_DTD_TIMING_PARAMETERS args; 275771fe6b9SJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming); 2765a9bcaccSAlex Deucher u16 misc = 0; 277771fe6b9SJerome Glisse 2785a9bcaccSAlex Deucher memset(&args, 0, sizeof(args)); 2795a9bcaccSAlex Deucher args.usH_Size = cpu_to_le16(mode->crtc_hdisplay); 2805a9bcaccSAlex Deucher args.usH_Blanking_Time = 2815a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay); 2825a9bcaccSAlex Deucher args.usV_Size = cpu_to_le16(mode->crtc_vdisplay); 2835a9bcaccSAlex Deucher args.usV_Blanking_Time = 2845a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay); 2855a9bcaccSAlex Deucher args.usH_SyncOffset = 2865a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay); 2875a9bcaccSAlex Deucher args.usH_SyncWidth = 2885a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start); 2895a9bcaccSAlex Deucher args.usV_SyncOffset = 2905a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay); 2915a9bcaccSAlex Deucher args.usV_SyncWidth = 2925a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start); 2935a9bcaccSAlex Deucher /*args.ucH_Border = mode->hborder;*/ 2945a9bcaccSAlex Deucher /*args.ucV_Border = mode->vborder;*/ 2955a9bcaccSAlex Deucher 2965a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_NVSYNC) 2975a9bcaccSAlex Deucher misc |= ATOM_VSYNC_POLARITY; 2985a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_NHSYNC) 2995a9bcaccSAlex Deucher misc |= ATOM_HSYNC_POLARITY; 3005a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_CSYNC) 3015a9bcaccSAlex Deucher misc |= ATOM_COMPOSITESYNC; 3025a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_INTERLACE) 3035a9bcaccSAlex Deucher misc |= ATOM_INTERLACE; 3045a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 3055a9bcaccSAlex Deucher misc |= ATOM_DOUBLE_CLOCK_MODE; 3065a9bcaccSAlex Deucher 3075a9bcaccSAlex Deucher args.susModeMiscInfo.usAccess = cpu_to_le16(misc); 3085a9bcaccSAlex Deucher args.ucCRTC = radeon_crtc->crtc_id; 309771fe6b9SJerome Glisse 310771fe6b9SJerome Glisse printk("executing set crtc dtd timing\n"); 3115a9bcaccSAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 312771fe6b9SJerome Glisse } 313771fe6b9SJerome Glisse 3145a9bcaccSAlex Deucher static void atombios_crtc_set_timing(struct drm_crtc *crtc, 3155a9bcaccSAlex Deucher struct drm_display_mode *mode) 316771fe6b9SJerome Glisse { 3175a9bcaccSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 318771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 319771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 3205a9bcaccSAlex Deucher SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION args; 321771fe6b9SJerome Glisse int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing); 3225a9bcaccSAlex Deucher u16 misc = 0; 323771fe6b9SJerome Glisse 3245a9bcaccSAlex Deucher memset(&args, 0, sizeof(args)); 3255a9bcaccSAlex Deucher args.usH_Total = cpu_to_le16(mode->crtc_htotal); 3265a9bcaccSAlex Deucher args.usH_Disp = cpu_to_le16(mode->crtc_hdisplay); 3275a9bcaccSAlex Deucher args.usH_SyncStart = cpu_to_le16(mode->crtc_hsync_start); 3285a9bcaccSAlex Deucher args.usH_SyncWidth = 3295a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start); 3305a9bcaccSAlex Deucher args.usV_Total = cpu_to_le16(mode->crtc_vtotal); 3315a9bcaccSAlex Deucher args.usV_Disp = cpu_to_le16(mode->crtc_vdisplay); 3325a9bcaccSAlex Deucher args.usV_SyncStart = cpu_to_le16(mode->crtc_vsync_start); 3335a9bcaccSAlex Deucher args.usV_SyncWidth = 3345a9bcaccSAlex Deucher cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start); 3355a9bcaccSAlex Deucher 3365a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_NVSYNC) 3375a9bcaccSAlex Deucher misc |= ATOM_VSYNC_POLARITY; 3385a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_NHSYNC) 3395a9bcaccSAlex Deucher misc |= ATOM_HSYNC_POLARITY; 3405a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_CSYNC) 3415a9bcaccSAlex Deucher misc |= ATOM_COMPOSITESYNC; 3425a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_INTERLACE) 3435a9bcaccSAlex Deucher misc |= ATOM_INTERLACE; 3445a9bcaccSAlex Deucher if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 3455a9bcaccSAlex Deucher misc |= ATOM_DOUBLE_CLOCK_MODE; 3465a9bcaccSAlex Deucher 3475a9bcaccSAlex Deucher args.susModeMiscInfo.usAccess = cpu_to_le16(misc); 3485a9bcaccSAlex Deucher args.ucCRTC = radeon_crtc->crtc_id; 349771fe6b9SJerome Glisse 350771fe6b9SJerome Glisse printk("executing set crtc timing\n"); 3515a9bcaccSAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 352771fe6b9SJerome Glisse } 353771fe6b9SJerome Glisse 354ebbe1cb9SAlex Deucher static void atombios_set_ss(struct drm_crtc *crtc, int enable) 355ebbe1cb9SAlex Deucher { 356ebbe1cb9SAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 357ebbe1cb9SAlex Deucher struct drm_device *dev = crtc->dev; 358ebbe1cb9SAlex Deucher struct radeon_device *rdev = dev->dev_private; 359ebbe1cb9SAlex Deucher struct drm_encoder *encoder = NULL; 360ebbe1cb9SAlex Deucher struct radeon_encoder *radeon_encoder = NULL; 361ebbe1cb9SAlex Deucher struct radeon_encoder_atom_dig *dig = NULL; 362ebbe1cb9SAlex Deucher int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL); 363ebbe1cb9SAlex Deucher ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION args; 364ebbe1cb9SAlex Deucher ENABLE_LVDS_SS_PARAMETERS legacy_args; 365ebbe1cb9SAlex Deucher uint16_t percentage = 0; 366ebbe1cb9SAlex Deucher uint8_t type = 0, step = 0, delay = 0, range = 0; 367ebbe1cb9SAlex Deucher 368ebbe1cb9SAlex Deucher list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 369ebbe1cb9SAlex Deucher if (encoder->crtc == crtc) { 370ebbe1cb9SAlex Deucher radeon_encoder = to_radeon_encoder(encoder); 371ebbe1cb9SAlex Deucher /* only enable spread spectrum on LVDS */ 372d11aa88bSAlex Deucher if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 373d11aa88bSAlex Deucher dig = radeon_encoder->enc_priv; 374ebbe1cb9SAlex Deucher if (dig && dig->ss) { 375ebbe1cb9SAlex Deucher percentage = dig->ss->percentage; 376ebbe1cb9SAlex Deucher type = dig->ss->type; 377ebbe1cb9SAlex Deucher step = dig->ss->step; 378ebbe1cb9SAlex Deucher delay = dig->ss->delay; 379ebbe1cb9SAlex Deucher range = dig->ss->range; 380ebbe1cb9SAlex Deucher } else if (enable) 381ebbe1cb9SAlex Deucher return; 382d11aa88bSAlex Deucher } else if (enable) 383d11aa88bSAlex Deucher return; 384ebbe1cb9SAlex Deucher break; 385ebbe1cb9SAlex Deucher } 386ebbe1cb9SAlex Deucher } 387ebbe1cb9SAlex Deucher 388ebbe1cb9SAlex Deucher if (!radeon_encoder) 389ebbe1cb9SAlex Deucher return; 390ebbe1cb9SAlex Deucher 391ebbe1cb9SAlex Deucher if (ASIC_IS_AVIVO(rdev)) { 392ebbe1cb9SAlex Deucher memset(&args, 0, sizeof(args)); 393d11aa88bSAlex Deucher args.usSpreadSpectrumPercentage = cpu_to_le16(percentage); 394ebbe1cb9SAlex Deucher args.ucSpreadSpectrumType = type; 395ebbe1cb9SAlex Deucher args.ucSpreadSpectrumStep = step; 396ebbe1cb9SAlex Deucher args.ucSpreadSpectrumDelay = delay; 397ebbe1cb9SAlex Deucher args.ucSpreadSpectrumRange = range; 398ebbe1cb9SAlex Deucher args.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; 399ebbe1cb9SAlex Deucher args.ucEnable = enable; 400ebbe1cb9SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 401ebbe1cb9SAlex Deucher } else { 402ebbe1cb9SAlex Deucher memset(&legacy_args, 0, sizeof(legacy_args)); 403d11aa88bSAlex Deucher legacy_args.usSpreadSpectrumPercentage = cpu_to_le16(percentage); 404ebbe1cb9SAlex Deucher legacy_args.ucSpreadSpectrumType = type; 405ebbe1cb9SAlex Deucher legacy_args.ucSpreadSpectrumStepSize_Delay = (step & 3) << 2; 406ebbe1cb9SAlex Deucher legacy_args.ucSpreadSpectrumStepSize_Delay |= (delay & 7) << 4; 407ebbe1cb9SAlex Deucher legacy_args.ucEnable = enable; 408ebbe1cb9SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&legacy_args); 409ebbe1cb9SAlex Deucher } 410ebbe1cb9SAlex Deucher } 411ebbe1cb9SAlex Deucher 412771fe6b9SJerome Glisse void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) 413771fe6b9SJerome Glisse { 414771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 415771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 416771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 417771fe6b9SJerome Glisse struct drm_encoder *encoder = NULL; 418771fe6b9SJerome Glisse struct radeon_encoder *radeon_encoder = NULL; 419771fe6b9SJerome Glisse uint8_t frev, crev; 4202606c886SAlex Deucher int index; 421771fe6b9SJerome Glisse SET_PIXEL_CLOCK_PS_ALLOCATION args; 422771fe6b9SJerome Glisse PIXEL_CLOCK_PARAMETERS *spc1_ptr; 423771fe6b9SJerome Glisse PIXEL_CLOCK_PARAMETERS_V2 *spc2_ptr; 424771fe6b9SJerome Glisse PIXEL_CLOCK_PARAMETERS_V3 *spc3_ptr; 4252606c886SAlex Deucher uint32_t pll_clock = mode->clock; 4262606c886SAlex Deucher uint32_t adjusted_clock; 427771fe6b9SJerome Glisse uint32_t ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; 428771fe6b9SJerome Glisse struct radeon_pll *pll; 429771fe6b9SJerome Glisse int pll_flags = 0; 430771fe6b9SJerome Glisse 431771fe6b9SJerome Glisse memset(&args, 0, sizeof(args)); 432771fe6b9SJerome Glisse 433771fe6b9SJerome Glisse if (ASIC_IS_AVIVO(rdev)) { 434eb1300bcSAlex Deucher if ((rdev->family == CHIP_RS600) || 435eb1300bcSAlex Deucher (rdev->family == CHIP_RS690) || 436eb1300bcSAlex Deucher (rdev->family == CHIP_RS740)) 437eb1300bcSAlex Deucher pll_flags |= (RADEON_PLL_USE_FRAC_FB_DIV | 438eb1300bcSAlex Deucher RADEON_PLL_PREFER_CLOSEST_LOWER); 439eb1300bcSAlex Deucher 440771fe6b9SJerome Glisse if (ASIC_IS_DCE32(rdev) && mode->clock > 200000) /* range limits??? */ 441771fe6b9SJerome Glisse pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; 442771fe6b9SJerome Glisse else 443771fe6b9SJerome Glisse pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; 444771fe6b9SJerome Glisse } else { 445771fe6b9SJerome Glisse pll_flags |= RADEON_PLL_LEGACY; 446771fe6b9SJerome Glisse 447771fe6b9SJerome Glisse if (mode->clock > 200000) /* range limits??? */ 448771fe6b9SJerome Glisse pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; 449771fe6b9SJerome Glisse else 450771fe6b9SJerome Glisse pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; 451771fe6b9SJerome Glisse 452771fe6b9SJerome Glisse } 453771fe6b9SJerome Glisse 454771fe6b9SJerome Glisse list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 455771fe6b9SJerome Glisse if (encoder->crtc == crtc) { 456771fe6b9SJerome Glisse if (!ASIC_IS_AVIVO(rdev)) { 457771fe6b9SJerome Glisse if (encoder->encoder_type != 458771fe6b9SJerome Glisse DRM_MODE_ENCODER_DAC) 459771fe6b9SJerome Glisse pll_flags |= RADEON_PLL_NO_ODD_POST_DIV; 4602a008d0cSAlex Deucher if (encoder->encoder_type == 4612a008d0cSAlex Deucher DRM_MODE_ENCODER_LVDS) 462771fe6b9SJerome Glisse pll_flags |= RADEON_PLL_USE_REF_DIV; 463771fe6b9SJerome Glisse } 464771fe6b9SJerome Glisse radeon_encoder = to_radeon_encoder(encoder); 4653ce0a23dSJerome Glisse break; 466771fe6b9SJerome Glisse } 467771fe6b9SJerome Glisse } 468771fe6b9SJerome Glisse 4692606c886SAlex Deucher /* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock 4702606c886SAlex Deucher * accordingly based on the encoder/transmitter to work around 4712606c886SAlex Deucher * special hw requirements. 4722606c886SAlex Deucher */ 4732606c886SAlex Deucher if (ASIC_IS_DCE3(rdev)) { 4742606c886SAlex Deucher ADJUST_DISPLAY_PLL_PS_ALLOCATION adjust_pll_args; 4752606c886SAlex Deucher 4762606c886SAlex Deucher if (!encoder) 4772606c886SAlex Deucher return; 4782606c886SAlex Deucher 4792606c886SAlex Deucher memset(&adjust_pll_args, 0, sizeof(adjust_pll_args)); 4802606c886SAlex Deucher adjust_pll_args.usPixelClock = cpu_to_le16(mode->clock / 10); 4812606c886SAlex Deucher adjust_pll_args.ucTransmitterID = radeon_encoder->encoder_id; 4822606c886SAlex Deucher adjust_pll_args.ucEncodeMode = atombios_get_encoder_mode(encoder); 4832606c886SAlex Deucher 4842606c886SAlex Deucher index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll); 4852606c886SAlex Deucher atom_execute_table(rdev->mode_info.atom_context, 4862606c886SAlex Deucher index, (uint32_t *)&adjust_pll_args); 4872606c886SAlex Deucher adjusted_clock = le16_to_cpu(adjust_pll_args.usPixelClock) * 10; 488d56ef9c8SAlex Deucher } else { 489d56ef9c8SAlex Deucher /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ 490d56ef9c8SAlex Deucher if (ASIC_IS_AVIVO(rdev) && 491d56ef9c8SAlex Deucher (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)) 492d56ef9c8SAlex Deucher adjusted_clock = mode->clock * 2; 493d56ef9c8SAlex Deucher else 4942606c886SAlex Deucher adjusted_clock = mode->clock; 495d56ef9c8SAlex Deucher } 4962606c886SAlex Deucher 497771fe6b9SJerome Glisse if (radeon_crtc->crtc_id == 0) 498771fe6b9SJerome Glisse pll = &rdev->clock.p1pll; 499771fe6b9SJerome Glisse else 500771fe6b9SJerome Glisse pll = &rdev->clock.p2pll; 501771fe6b9SJerome Glisse 5022606c886SAlex Deucher radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, 503771fe6b9SJerome Glisse &ref_div, &post_div, pll_flags); 504771fe6b9SJerome Glisse 50539deb2d6SDave Airlie index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); 506771fe6b9SJerome Glisse atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 507771fe6b9SJerome Glisse &crev); 508771fe6b9SJerome Glisse 509771fe6b9SJerome Glisse switch (frev) { 510771fe6b9SJerome Glisse case 1: 511771fe6b9SJerome Glisse switch (crev) { 512771fe6b9SJerome Glisse case 1: 513771fe6b9SJerome Glisse spc1_ptr = (PIXEL_CLOCK_PARAMETERS *) & args.sPCLKInput; 5142606c886SAlex Deucher spc1_ptr->usPixelClock = cpu_to_le16(mode->clock / 10); 515771fe6b9SJerome Glisse spc1_ptr->usRefDiv = cpu_to_le16(ref_div); 516771fe6b9SJerome Glisse spc1_ptr->usFbDiv = cpu_to_le16(fb_div); 517771fe6b9SJerome Glisse spc1_ptr->ucFracFbDiv = frac_fb_div; 518771fe6b9SJerome Glisse spc1_ptr->ucPostDiv = post_div; 519771fe6b9SJerome Glisse spc1_ptr->ucPpll = 520771fe6b9SJerome Glisse radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; 521771fe6b9SJerome Glisse spc1_ptr->ucCRTC = radeon_crtc->crtc_id; 522771fe6b9SJerome Glisse spc1_ptr->ucRefDivSrc = 1; 523771fe6b9SJerome Glisse break; 524771fe6b9SJerome Glisse case 2: 525771fe6b9SJerome Glisse spc2_ptr = 526771fe6b9SJerome Glisse (PIXEL_CLOCK_PARAMETERS_V2 *) & args.sPCLKInput; 5272606c886SAlex Deucher spc2_ptr->usPixelClock = cpu_to_le16(mode->clock / 10); 528771fe6b9SJerome Glisse spc2_ptr->usRefDiv = cpu_to_le16(ref_div); 529771fe6b9SJerome Glisse spc2_ptr->usFbDiv = cpu_to_le16(fb_div); 530771fe6b9SJerome Glisse spc2_ptr->ucFracFbDiv = frac_fb_div; 531771fe6b9SJerome Glisse spc2_ptr->ucPostDiv = post_div; 532771fe6b9SJerome Glisse spc2_ptr->ucPpll = 533771fe6b9SJerome Glisse radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; 534771fe6b9SJerome Glisse spc2_ptr->ucCRTC = radeon_crtc->crtc_id; 535771fe6b9SJerome Glisse spc2_ptr->ucRefDivSrc = 1; 536771fe6b9SJerome Glisse break; 537771fe6b9SJerome Glisse case 3: 538771fe6b9SJerome Glisse if (!encoder) 539771fe6b9SJerome Glisse return; 540771fe6b9SJerome Glisse spc3_ptr = 541771fe6b9SJerome Glisse (PIXEL_CLOCK_PARAMETERS_V3 *) & args.sPCLKInput; 5422606c886SAlex Deucher spc3_ptr->usPixelClock = cpu_to_le16(mode->clock / 10); 543771fe6b9SJerome Glisse spc3_ptr->usRefDiv = cpu_to_le16(ref_div); 544771fe6b9SJerome Glisse spc3_ptr->usFbDiv = cpu_to_le16(fb_div); 545771fe6b9SJerome Glisse spc3_ptr->ucFracFbDiv = frac_fb_div; 546771fe6b9SJerome Glisse spc3_ptr->ucPostDiv = post_div; 547771fe6b9SJerome Glisse spc3_ptr->ucPpll = 548771fe6b9SJerome Glisse radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; 549771fe6b9SJerome Glisse spc3_ptr->ucMiscInfo = (radeon_crtc->crtc_id << 2); 550771fe6b9SJerome Glisse spc3_ptr->ucTransmitterId = radeon_encoder->encoder_id; 551771fe6b9SJerome Glisse spc3_ptr->ucEncoderMode = 552771fe6b9SJerome Glisse atombios_get_encoder_mode(encoder); 553771fe6b9SJerome Glisse break; 554771fe6b9SJerome Glisse default: 555771fe6b9SJerome Glisse DRM_ERROR("Unknown table version %d %d\n", frev, crev); 556771fe6b9SJerome Glisse return; 557771fe6b9SJerome Glisse } 558771fe6b9SJerome Glisse break; 559771fe6b9SJerome Glisse default: 560771fe6b9SJerome Glisse DRM_ERROR("Unknown table version %d %d\n", frev, crev); 561771fe6b9SJerome Glisse return; 562771fe6b9SJerome Glisse } 563771fe6b9SJerome Glisse 564771fe6b9SJerome Glisse printk("executing set pll\n"); 565771fe6b9SJerome Glisse atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 566771fe6b9SJerome Glisse } 567771fe6b9SJerome Glisse 568771fe6b9SJerome Glisse int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, 569771fe6b9SJerome Glisse struct drm_framebuffer *old_fb) 570771fe6b9SJerome Glisse { 571771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 572771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 573771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 574771fe6b9SJerome Glisse struct radeon_framebuffer *radeon_fb; 575771fe6b9SJerome Glisse struct drm_gem_object *obj; 5764c788679SJerome Glisse struct radeon_bo *rbo; 577771fe6b9SJerome Glisse uint64_t fb_location; 578e024e110SDave Airlie uint32_t fb_format, fb_pitch_pixels, tiling_flags; 5794c788679SJerome Glisse int r; 580771fe6b9SJerome Glisse 5812de3b484SJerome Glisse /* no fb bound */ 5822de3b484SJerome Glisse if (!crtc->fb) { 5832de3b484SJerome Glisse DRM_DEBUG("No FB bound\n"); 5842de3b484SJerome Glisse return 0; 5852de3b484SJerome Glisse } 586771fe6b9SJerome Glisse 587771fe6b9SJerome Glisse radeon_fb = to_radeon_framebuffer(crtc->fb); 588771fe6b9SJerome Glisse 5894c788679SJerome Glisse /* Pin framebuffer & get tilling informations */ 590771fe6b9SJerome Glisse obj = radeon_fb->obj; 5914c788679SJerome Glisse rbo = obj->driver_private; 5924c788679SJerome Glisse r = radeon_bo_reserve(rbo, false); 5934c788679SJerome Glisse if (unlikely(r != 0)) 5944c788679SJerome Glisse return r; 5954c788679SJerome Glisse r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); 5964c788679SJerome Glisse if (unlikely(r != 0)) { 5974c788679SJerome Glisse radeon_bo_unreserve(rbo); 598771fe6b9SJerome Glisse return -EINVAL; 599771fe6b9SJerome Glisse } 6004c788679SJerome Glisse radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); 6014c788679SJerome Glisse radeon_bo_unreserve(rbo); 6024c788679SJerome Glisse if (tiling_flags & RADEON_TILING_MACRO) 6034c788679SJerome Glisse fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE; 604771fe6b9SJerome Glisse 605771fe6b9SJerome Glisse switch (crtc->fb->bits_per_pixel) { 60641456df2SDave Airlie case 8: 60741456df2SDave Airlie fb_format = 60841456df2SDave Airlie AVIVO_D1GRPH_CONTROL_DEPTH_8BPP | 60941456df2SDave Airlie AVIVO_D1GRPH_CONTROL_8BPP_INDEXED; 61041456df2SDave Airlie break; 611771fe6b9SJerome Glisse case 15: 612771fe6b9SJerome Glisse fb_format = 613771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | 614771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555; 615771fe6b9SJerome Glisse break; 616771fe6b9SJerome Glisse case 16: 617771fe6b9SJerome Glisse fb_format = 618771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | 619771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_16BPP_RGB565; 620771fe6b9SJerome Glisse break; 621771fe6b9SJerome Glisse case 24: 622771fe6b9SJerome Glisse case 32: 623771fe6b9SJerome Glisse fb_format = 624771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_DEPTH_32BPP | 625771fe6b9SJerome Glisse AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888; 626771fe6b9SJerome Glisse break; 627771fe6b9SJerome Glisse default: 628771fe6b9SJerome Glisse DRM_ERROR("Unsupported screen depth %d\n", 629771fe6b9SJerome Glisse crtc->fb->bits_per_pixel); 630771fe6b9SJerome Glisse return -EINVAL; 631771fe6b9SJerome Glisse } 632771fe6b9SJerome Glisse 633e024e110SDave Airlie if (tiling_flags & RADEON_TILING_MICRO) 634e024e110SDave Airlie fb_format |= AVIVO_D1GRPH_TILED; 635e024e110SDave Airlie 636771fe6b9SJerome Glisse if (radeon_crtc->crtc_id == 0) 637771fe6b9SJerome Glisse WREG32(AVIVO_D1VGA_CONTROL, 0); 638771fe6b9SJerome Glisse else 639771fe6b9SJerome Glisse WREG32(AVIVO_D2VGA_CONTROL, 0); 640c290dadfSAlex Deucher 641c290dadfSAlex Deucher if (rdev->family >= CHIP_RV770) { 642c290dadfSAlex Deucher if (radeon_crtc->crtc_id) { 643c290dadfSAlex Deucher WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, 0); 644c290dadfSAlex Deucher WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, 0); 645c290dadfSAlex Deucher } else { 646c290dadfSAlex Deucher WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, 0); 647c290dadfSAlex Deucher WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, 0); 648c290dadfSAlex Deucher } 649c290dadfSAlex Deucher } 650771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 651771fe6b9SJerome Glisse (u32) fb_location); 652771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + 653771fe6b9SJerome Glisse radeon_crtc->crtc_offset, (u32) fb_location); 654771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); 655771fe6b9SJerome Glisse 656771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); 657771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); 658771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0); 659771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, 0); 660771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, crtc->fb->width); 661771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, crtc->fb->height); 662771fe6b9SJerome Glisse 663771fe6b9SJerome Glisse fb_pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8); 664771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); 665771fe6b9SJerome Glisse WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1); 666771fe6b9SJerome Glisse 667771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, 668771fe6b9SJerome Glisse crtc->mode.vdisplay); 669771fe6b9SJerome Glisse x &= ~3; 670771fe6b9SJerome Glisse y &= ~1; 671771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset, 672771fe6b9SJerome Glisse (x << 16) | y); 673771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset, 674771fe6b9SJerome Glisse (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay); 675771fe6b9SJerome Glisse 676771fe6b9SJerome Glisse if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) 677771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 678771fe6b9SJerome Glisse AVIVO_D1MODE_INTERLEAVE_EN); 679771fe6b9SJerome Glisse else 680771fe6b9SJerome Glisse WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0); 681771fe6b9SJerome Glisse 682771fe6b9SJerome Glisse if (old_fb && old_fb != crtc->fb) { 683771fe6b9SJerome Glisse radeon_fb = to_radeon_framebuffer(old_fb); 6844c788679SJerome Glisse rbo = radeon_fb->obj->driver_private; 6854c788679SJerome Glisse r = radeon_bo_reserve(rbo, false); 6864c788679SJerome Glisse if (unlikely(r != 0)) 6874c788679SJerome Glisse return r; 6884c788679SJerome Glisse radeon_bo_unpin(rbo); 6894c788679SJerome Glisse radeon_bo_unreserve(rbo); 690771fe6b9SJerome Glisse } 691f30f37deSMichel Dänzer 692f30f37deSMichel Dänzer /* Bytes per pixel may have changed */ 693f30f37deSMichel Dänzer radeon_bandwidth_update(rdev); 694f30f37deSMichel Dänzer 695771fe6b9SJerome Glisse return 0; 696771fe6b9SJerome Glisse } 697771fe6b9SJerome Glisse 698771fe6b9SJerome Glisse int atombios_crtc_mode_set(struct drm_crtc *crtc, 699771fe6b9SJerome Glisse struct drm_display_mode *mode, 700771fe6b9SJerome Glisse struct drm_display_mode *adjusted_mode, 701771fe6b9SJerome Glisse int x, int y, struct drm_framebuffer *old_fb) 702771fe6b9SJerome Glisse { 703771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 704771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev; 705771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private; 706771fe6b9SJerome Glisse 707771fe6b9SJerome Glisse /* TODO color tiling */ 708771fe6b9SJerome Glisse 709ebbe1cb9SAlex Deucher atombios_set_ss(crtc, 0); 710771fe6b9SJerome Glisse atombios_crtc_set_pll(crtc, adjusted_mode); 711ebbe1cb9SAlex Deucher atombios_set_ss(crtc, 1); 7125a9bcaccSAlex Deucher atombios_crtc_set_timing(crtc, adjusted_mode); 713771fe6b9SJerome Glisse 714771fe6b9SJerome Glisse if (ASIC_IS_AVIVO(rdev)) 715771fe6b9SJerome Glisse atombios_crtc_set_base(crtc, x, y, old_fb); 716771fe6b9SJerome Glisse else { 7175a9bcaccSAlex Deucher if (radeon_crtc->crtc_id == 0) 7185a9bcaccSAlex Deucher atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 719771fe6b9SJerome Glisse radeon_crtc_set_base(crtc, x, y, old_fb); 720771fe6b9SJerome Glisse radeon_legacy_atom_set_surface(crtc); 721771fe6b9SJerome Glisse } 722c93bb85bSJerome Glisse atombios_overscan_setup(crtc, mode, adjusted_mode); 723c93bb85bSJerome Glisse atombios_scaler_setup(crtc); 724771fe6b9SJerome Glisse return 0; 725771fe6b9SJerome Glisse } 726771fe6b9SJerome Glisse 727771fe6b9SJerome Glisse static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, 728771fe6b9SJerome Glisse struct drm_display_mode *mode, 729771fe6b9SJerome Glisse struct drm_display_mode *adjusted_mode) 730771fe6b9SJerome Glisse { 731c93bb85bSJerome Glisse if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) 732c93bb85bSJerome Glisse return false; 733771fe6b9SJerome Glisse return true; 734771fe6b9SJerome Glisse } 735771fe6b9SJerome Glisse 736771fe6b9SJerome Glisse static void atombios_crtc_prepare(struct drm_crtc *crtc) 737771fe6b9SJerome Glisse { 738771fe6b9SJerome Glisse atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 739771fe6b9SJerome Glisse atombios_lock_crtc(crtc, 1); 740771fe6b9SJerome Glisse } 741771fe6b9SJerome Glisse 742771fe6b9SJerome Glisse static void atombios_crtc_commit(struct drm_crtc *crtc) 743771fe6b9SJerome Glisse { 744771fe6b9SJerome Glisse atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON); 745771fe6b9SJerome Glisse atombios_lock_crtc(crtc, 0); 746771fe6b9SJerome Glisse } 747771fe6b9SJerome Glisse 748771fe6b9SJerome Glisse static const struct drm_crtc_helper_funcs atombios_helper_funcs = { 749771fe6b9SJerome Glisse .dpms = atombios_crtc_dpms, 750771fe6b9SJerome Glisse .mode_fixup = atombios_crtc_mode_fixup, 751771fe6b9SJerome Glisse .mode_set = atombios_crtc_mode_set, 752771fe6b9SJerome Glisse .mode_set_base = atombios_crtc_set_base, 753771fe6b9SJerome Glisse .prepare = atombios_crtc_prepare, 754771fe6b9SJerome Glisse .commit = atombios_crtc_commit, 755068143d3SDave Airlie .load_lut = radeon_crtc_load_lut, 756771fe6b9SJerome Glisse }; 757771fe6b9SJerome Glisse 758771fe6b9SJerome Glisse void radeon_atombios_init_crtc(struct drm_device *dev, 759771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc) 760771fe6b9SJerome Glisse { 761771fe6b9SJerome Glisse if (radeon_crtc->crtc_id == 1) 762771fe6b9SJerome Glisse radeon_crtc->crtc_offset = 763771fe6b9SJerome Glisse AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL; 764771fe6b9SJerome Glisse drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); 765771fe6b9SJerome Glisse } 766