18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2007-8 Advanced Micro Devices, Inc. 38c2ecf20Sopenharmony_ci * Copyright 2008 Red Hat Inc. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 68c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 78c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation 88c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 98c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 108c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 138c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 168c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 178c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 188c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 198c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 208c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 218c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * Authors: Dave Airlie 248c2ecf20Sopenharmony_ci * Alex Deucher 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include <drm/drm_crtc_helper.h> 288c2ecf20Sopenharmony_ci#include <drm/drm_fb_helper.h> 298c2ecf20Sopenharmony_ci#include <drm/drm_fixed.h> 308c2ecf20Sopenharmony_ci#include <drm/drm_fourcc.h> 318c2ecf20Sopenharmony_ci#include <drm/drm_vblank.h> 328c2ecf20Sopenharmony_ci#include <drm/radeon_drm.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include "radeon.h" 358c2ecf20Sopenharmony_ci#include "atom.h" 368c2ecf20Sopenharmony_ci#include "atom-bits.h" 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic void atombios_overscan_setup(struct drm_crtc *crtc, 398c2ecf20Sopenharmony_ci struct drm_display_mode *mode, 408c2ecf20Sopenharmony_ci struct drm_display_mode *adjusted_mode) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 438c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 448c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 458c2ecf20Sopenharmony_ci SET_CRTC_OVERSCAN_PS_ALLOCATION args; 468c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan); 478c2ecf20Sopenharmony_ci int a1, a2; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci args.ucCRTC = radeon_crtc->crtc_id; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci switch (radeon_crtc->rmx_type) { 548c2ecf20Sopenharmony_ci case RMX_CENTER: 558c2ecf20Sopenharmony_ci args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2); 568c2ecf20Sopenharmony_ci args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2); 578c2ecf20Sopenharmony_ci args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2); 588c2ecf20Sopenharmony_ci args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2); 598c2ecf20Sopenharmony_ci break; 608c2ecf20Sopenharmony_ci case RMX_ASPECT: 618c2ecf20Sopenharmony_ci a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay; 628c2ecf20Sopenharmony_ci a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (a1 > a2) { 658c2ecf20Sopenharmony_ci args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2); 668c2ecf20Sopenharmony_ci args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2); 678c2ecf20Sopenharmony_ci } else if (a2 > a1) { 688c2ecf20Sopenharmony_ci args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2); 698c2ecf20Sopenharmony_ci args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2); 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci break; 728c2ecf20Sopenharmony_ci case RMX_FULL: 738c2ecf20Sopenharmony_ci default: 748c2ecf20Sopenharmony_ci args.usOverscanRight = cpu_to_le16(radeon_crtc->h_border); 758c2ecf20Sopenharmony_ci args.usOverscanLeft = cpu_to_le16(radeon_crtc->h_border); 768c2ecf20Sopenharmony_ci args.usOverscanBottom = cpu_to_le16(radeon_crtc->v_border); 778c2ecf20Sopenharmony_ci args.usOverscanTop = cpu_to_le16(radeon_crtc->v_border); 788c2ecf20Sopenharmony_ci break; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic void atombios_scaler_setup(struct drm_crtc *crtc) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 868c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 878c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 888c2ecf20Sopenharmony_ci ENABLE_SCALER_PS_ALLOCATION args; 898c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, EnableScaler); 908c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = 918c2ecf20Sopenharmony_ci to_radeon_encoder(radeon_crtc->encoder); 928c2ecf20Sopenharmony_ci /* fixme - fill in enc_priv for atom dac */ 938c2ecf20Sopenharmony_ci enum radeon_tv_std tv_std = TV_STD_NTSC; 948c2ecf20Sopenharmony_ci bool is_tv = false, is_cv = false; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (!ASIC_IS_AVIVO(rdev) && radeon_crtc->crtc_id) 978c2ecf20Sopenharmony_ci return; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) { 1008c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv; 1018c2ecf20Sopenharmony_ci tv_std = tv_dac->tv_std; 1028c2ecf20Sopenharmony_ci is_tv = true; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci args.ucScaler = radeon_crtc->crtc_id; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (is_tv) { 1108c2ecf20Sopenharmony_ci switch (tv_std) { 1118c2ecf20Sopenharmony_ci case TV_STD_NTSC: 1128c2ecf20Sopenharmony_ci default: 1138c2ecf20Sopenharmony_ci args.ucTVStandard = ATOM_TV_NTSC; 1148c2ecf20Sopenharmony_ci break; 1158c2ecf20Sopenharmony_ci case TV_STD_PAL: 1168c2ecf20Sopenharmony_ci args.ucTVStandard = ATOM_TV_PAL; 1178c2ecf20Sopenharmony_ci break; 1188c2ecf20Sopenharmony_ci case TV_STD_PAL_M: 1198c2ecf20Sopenharmony_ci args.ucTVStandard = ATOM_TV_PALM; 1208c2ecf20Sopenharmony_ci break; 1218c2ecf20Sopenharmony_ci case TV_STD_PAL_60: 1228c2ecf20Sopenharmony_ci args.ucTVStandard = ATOM_TV_PAL60; 1238c2ecf20Sopenharmony_ci break; 1248c2ecf20Sopenharmony_ci case TV_STD_NTSC_J: 1258c2ecf20Sopenharmony_ci args.ucTVStandard = ATOM_TV_NTSCJ; 1268c2ecf20Sopenharmony_ci break; 1278c2ecf20Sopenharmony_ci case TV_STD_SCART_PAL: 1288c2ecf20Sopenharmony_ci args.ucTVStandard = ATOM_TV_PAL; /* ??? */ 1298c2ecf20Sopenharmony_ci break; 1308c2ecf20Sopenharmony_ci case TV_STD_SECAM: 1318c2ecf20Sopenharmony_ci args.ucTVStandard = ATOM_TV_SECAM; 1328c2ecf20Sopenharmony_ci break; 1338c2ecf20Sopenharmony_ci case TV_STD_PAL_CN: 1348c2ecf20Sopenharmony_ci args.ucTVStandard = ATOM_TV_PALCN; 1358c2ecf20Sopenharmony_ci break; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; 1388c2ecf20Sopenharmony_ci } else if (is_cv) { 1398c2ecf20Sopenharmony_ci args.ucTVStandard = ATOM_TV_CV; 1408c2ecf20Sopenharmony_ci args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; 1418c2ecf20Sopenharmony_ci } else { 1428c2ecf20Sopenharmony_ci switch (radeon_crtc->rmx_type) { 1438c2ecf20Sopenharmony_ci case RMX_FULL: 1448c2ecf20Sopenharmony_ci args.ucEnable = ATOM_SCALER_EXPANSION; 1458c2ecf20Sopenharmony_ci break; 1468c2ecf20Sopenharmony_ci case RMX_CENTER: 1478c2ecf20Sopenharmony_ci args.ucEnable = ATOM_SCALER_CENTER; 1488c2ecf20Sopenharmony_ci break; 1498c2ecf20Sopenharmony_ci case RMX_ASPECT: 1508c2ecf20Sopenharmony_ci args.ucEnable = ATOM_SCALER_EXPANSION; 1518c2ecf20Sopenharmony_ci break; 1528c2ecf20Sopenharmony_ci default: 1538c2ecf20Sopenharmony_ci if (ASIC_IS_AVIVO(rdev)) 1548c2ecf20Sopenharmony_ci args.ucEnable = ATOM_SCALER_DISABLE; 1558c2ecf20Sopenharmony_ci else 1568c2ecf20Sopenharmony_ci args.ucEnable = ATOM_SCALER_CENTER; 1578c2ecf20Sopenharmony_ci break; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 1618c2ecf20Sopenharmony_ci if ((is_tv || is_cv) 1628c2ecf20Sopenharmony_ci && rdev->family >= CHIP_RV515 && rdev->family <= CHIP_R580) { 1638c2ecf20Sopenharmony_ci atom_rv515_force_tv_scaler(rdev, radeon_crtc); 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic void atombios_lock_crtc(struct drm_crtc *crtc, int lock) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1708c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 1718c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 1728c2ecf20Sopenharmony_ci int index = 1738c2ecf20Sopenharmony_ci GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters); 1748c2ecf20Sopenharmony_ci ENABLE_CRTC_PS_ALLOCATION args; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci args.ucCRTC = radeon_crtc->crtc_id; 1798c2ecf20Sopenharmony_ci args.ucEnable = lock; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic void atombios_enable_crtc(struct drm_crtc *crtc, int state) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 1878c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 1888c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 1898c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC); 1908c2ecf20Sopenharmony_ci ENABLE_CRTC_PS_ALLOCATION args; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci args.ucCRTC = radeon_crtc->crtc_id; 1958c2ecf20Sopenharmony_ci args.ucEnable = state; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic void atombios_enable_crtc_memreq(struct drm_crtc *crtc, int state) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 2038c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 2048c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 2058c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, EnableCRTCMemReq); 2068c2ecf20Sopenharmony_ci ENABLE_CRTC_PS_ALLOCATION args; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci args.ucCRTC = radeon_crtc->crtc_id; 2118c2ecf20Sopenharmony_ci args.ucEnable = state; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic const u32 vga_control_regs[6] = 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci AVIVO_D1VGA_CONTROL, 2198c2ecf20Sopenharmony_ci AVIVO_D2VGA_CONTROL, 2208c2ecf20Sopenharmony_ci EVERGREEN_D3VGA_CONTROL, 2218c2ecf20Sopenharmony_ci EVERGREEN_D4VGA_CONTROL, 2228c2ecf20Sopenharmony_ci EVERGREEN_D5VGA_CONTROL, 2238c2ecf20Sopenharmony_ci EVERGREEN_D6VGA_CONTROL, 2248c2ecf20Sopenharmony_ci}; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic void atombios_blank_crtc(struct drm_crtc *crtc, int state) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 2298c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 2308c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 2318c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC); 2328c2ecf20Sopenharmony_ci BLANK_CRTC_PS_ALLOCATION args; 2338c2ecf20Sopenharmony_ci u32 vga_control = 0; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (ASIC_IS_DCE8(rdev)) { 2388c2ecf20Sopenharmony_ci vga_control = RREG32(vga_control_regs[radeon_crtc->crtc_id]); 2398c2ecf20Sopenharmony_ci WREG32(vga_control_regs[radeon_crtc->crtc_id], vga_control | 1); 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci args.ucCRTC = radeon_crtc->crtc_id; 2438c2ecf20Sopenharmony_ci args.ucBlanking = state; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (ASIC_IS_DCE8(rdev)) 2488c2ecf20Sopenharmony_ci WREG32(vga_control_regs[radeon_crtc->crtc_id], vga_control); 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic void atombios_powergate_crtc(struct drm_crtc *crtc, int state) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 2548c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 2558c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 2568c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating); 2578c2ecf20Sopenharmony_ci ENABLE_DISP_POWER_GATING_PARAMETERS_V2_1 args; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci args.ucDispPipeId = radeon_crtc->crtc_id; 2628c2ecf20Sopenharmony_ci args.ucEnable = state; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_civoid atombios_crtc_dpms(struct drm_crtc *crtc, int mode) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 2708c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 2718c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci switch (mode) { 2748c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_ON: 2758c2ecf20Sopenharmony_ci radeon_crtc->enabled = true; 2768c2ecf20Sopenharmony_ci atombios_enable_crtc(crtc, ATOM_ENABLE); 2778c2ecf20Sopenharmony_ci if (ASIC_IS_DCE3(rdev) && !ASIC_IS_DCE6(rdev)) 2788c2ecf20Sopenharmony_ci atombios_enable_crtc_memreq(crtc, ATOM_ENABLE); 2798c2ecf20Sopenharmony_ci atombios_blank_crtc(crtc, ATOM_DISABLE); 2808c2ecf20Sopenharmony_ci if (dev->num_crtcs > radeon_crtc->crtc_id) 2818c2ecf20Sopenharmony_ci drm_crtc_vblank_on(crtc); 2828c2ecf20Sopenharmony_ci radeon_crtc_load_lut(crtc); 2838c2ecf20Sopenharmony_ci break; 2848c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_STANDBY: 2858c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_SUSPEND: 2868c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_OFF: 2878c2ecf20Sopenharmony_ci if (dev->num_crtcs > radeon_crtc->crtc_id) 2888c2ecf20Sopenharmony_ci drm_crtc_vblank_off(crtc); 2898c2ecf20Sopenharmony_ci if (radeon_crtc->enabled) 2908c2ecf20Sopenharmony_ci atombios_blank_crtc(crtc, ATOM_ENABLE); 2918c2ecf20Sopenharmony_ci if (ASIC_IS_DCE3(rdev) && !ASIC_IS_DCE6(rdev)) 2928c2ecf20Sopenharmony_ci atombios_enable_crtc_memreq(crtc, ATOM_DISABLE); 2938c2ecf20Sopenharmony_ci atombios_enable_crtc(crtc, ATOM_DISABLE); 2948c2ecf20Sopenharmony_ci radeon_crtc->enabled = false; 2958c2ecf20Sopenharmony_ci break; 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci /* adjust pm to dpms */ 2988c2ecf20Sopenharmony_ci radeon_pm_compute_clocks(rdev); 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic void 3028c2ecf20Sopenharmony_ciatombios_set_crtc_dtd_timing(struct drm_crtc *crtc, 3038c2ecf20Sopenharmony_ci struct drm_display_mode *mode) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 3068c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 3078c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 3088c2ecf20Sopenharmony_ci SET_CRTC_USING_DTD_TIMING_PARAMETERS args; 3098c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming); 3108c2ecf20Sopenharmony_ci u16 misc = 0; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 3138c2ecf20Sopenharmony_ci args.usH_Size = cpu_to_le16(mode->crtc_hdisplay - (radeon_crtc->h_border * 2)); 3148c2ecf20Sopenharmony_ci args.usH_Blanking_Time = 3158c2ecf20Sopenharmony_ci cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay + (radeon_crtc->h_border * 2)); 3168c2ecf20Sopenharmony_ci args.usV_Size = cpu_to_le16(mode->crtc_vdisplay - (radeon_crtc->v_border * 2)); 3178c2ecf20Sopenharmony_ci args.usV_Blanking_Time = 3188c2ecf20Sopenharmony_ci cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay + (radeon_crtc->v_border * 2)); 3198c2ecf20Sopenharmony_ci args.usH_SyncOffset = 3208c2ecf20Sopenharmony_ci cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay + radeon_crtc->h_border); 3218c2ecf20Sopenharmony_ci args.usH_SyncWidth = 3228c2ecf20Sopenharmony_ci cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start); 3238c2ecf20Sopenharmony_ci args.usV_SyncOffset = 3248c2ecf20Sopenharmony_ci cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay + radeon_crtc->v_border); 3258c2ecf20Sopenharmony_ci args.usV_SyncWidth = 3268c2ecf20Sopenharmony_ci cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start); 3278c2ecf20Sopenharmony_ci args.ucH_Border = radeon_crtc->h_border; 3288c2ecf20Sopenharmony_ci args.ucV_Border = radeon_crtc->v_border; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_NVSYNC) 3318c2ecf20Sopenharmony_ci misc |= ATOM_VSYNC_POLARITY; 3328c2ecf20Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_NHSYNC) 3338c2ecf20Sopenharmony_ci misc |= ATOM_HSYNC_POLARITY; 3348c2ecf20Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_CSYNC) 3358c2ecf20Sopenharmony_ci misc |= ATOM_COMPOSITESYNC; 3368c2ecf20Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_INTERLACE) 3378c2ecf20Sopenharmony_ci misc |= ATOM_INTERLACE; 3388c2ecf20Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_DBLCLK) 3398c2ecf20Sopenharmony_ci misc |= ATOM_DOUBLE_CLOCK_MODE; 3408c2ecf20Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 3418c2ecf20Sopenharmony_ci misc |= ATOM_H_REPLICATIONBY2 | ATOM_V_REPLICATIONBY2; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci args.susModeMiscInfo.usAccess = cpu_to_le16(misc); 3448c2ecf20Sopenharmony_ci args.ucCRTC = radeon_crtc->crtc_id; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic void atombios_crtc_set_timing(struct drm_crtc *crtc, 3508c2ecf20Sopenharmony_ci struct drm_display_mode *mode) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 3538c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 3548c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 3558c2ecf20Sopenharmony_ci SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION args; 3568c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing); 3578c2ecf20Sopenharmony_ci u16 misc = 0; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 3608c2ecf20Sopenharmony_ci args.usH_Total = cpu_to_le16(mode->crtc_htotal); 3618c2ecf20Sopenharmony_ci args.usH_Disp = cpu_to_le16(mode->crtc_hdisplay); 3628c2ecf20Sopenharmony_ci args.usH_SyncStart = cpu_to_le16(mode->crtc_hsync_start); 3638c2ecf20Sopenharmony_ci args.usH_SyncWidth = 3648c2ecf20Sopenharmony_ci cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start); 3658c2ecf20Sopenharmony_ci args.usV_Total = cpu_to_le16(mode->crtc_vtotal); 3668c2ecf20Sopenharmony_ci args.usV_Disp = cpu_to_le16(mode->crtc_vdisplay); 3678c2ecf20Sopenharmony_ci args.usV_SyncStart = cpu_to_le16(mode->crtc_vsync_start); 3688c2ecf20Sopenharmony_ci args.usV_SyncWidth = 3698c2ecf20Sopenharmony_ci cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci args.ucOverscanRight = radeon_crtc->h_border; 3728c2ecf20Sopenharmony_ci args.ucOverscanLeft = radeon_crtc->h_border; 3738c2ecf20Sopenharmony_ci args.ucOverscanBottom = radeon_crtc->v_border; 3748c2ecf20Sopenharmony_ci args.ucOverscanTop = radeon_crtc->v_border; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_NVSYNC) 3778c2ecf20Sopenharmony_ci misc |= ATOM_VSYNC_POLARITY; 3788c2ecf20Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_NHSYNC) 3798c2ecf20Sopenharmony_ci misc |= ATOM_HSYNC_POLARITY; 3808c2ecf20Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_CSYNC) 3818c2ecf20Sopenharmony_ci misc |= ATOM_COMPOSITESYNC; 3828c2ecf20Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_INTERLACE) 3838c2ecf20Sopenharmony_ci misc |= ATOM_INTERLACE; 3848c2ecf20Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_DBLCLK) 3858c2ecf20Sopenharmony_ci misc |= ATOM_DOUBLE_CLOCK_MODE; 3868c2ecf20Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 3878c2ecf20Sopenharmony_ci misc |= ATOM_H_REPLICATIONBY2 | ATOM_V_REPLICATIONBY2; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci args.susModeMiscInfo.usAccess = cpu_to_le16(misc); 3908c2ecf20Sopenharmony_ci args.ucCRTC = radeon_crtc->crtc_id; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic void atombios_disable_ss(struct radeon_device *rdev, int pll_id) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci u32 ss_cntl; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) { 4008c2ecf20Sopenharmony_ci switch (pll_id) { 4018c2ecf20Sopenharmony_ci case ATOM_PPLL1: 4028c2ecf20Sopenharmony_ci ss_cntl = RREG32(EVERGREEN_P1PLL_SS_CNTL); 4038c2ecf20Sopenharmony_ci ss_cntl &= ~EVERGREEN_PxPLL_SS_EN; 4048c2ecf20Sopenharmony_ci WREG32(EVERGREEN_P1PLL_SS_CNTL, ss_cntl); 4058c2ecf20Sopenharmony_ci break; 4068c2ecf20Sopenharmony_ci case ATOM_PPLL2: 4078c2ecf20Sopenharmony_ci ss_cntl = RREG32(EVERGREEN_P2PLL_SS_CNTL); 4088c2ecf20Sopenharmony_ci ss_cntl &= ~EVERGREEN_PxPLL_SS_EN; 4098c2ecf20Sopenharmony_ci WREG32(EVERGREEN_P2PLL_SS_CNTL, ss_cntl); 4108c2ecf20Sopenharmony_ci break; 4118c2ecf20Sopenharmony_ci case ATOM_DCPLL: 4128c2ecf20Sopenharmony_ci case ATOM_PPLL_INVALID: 4138c2ecf20Sopenharmony_ci return; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci } else if (ASIC_IS_AVIVO(rdev)) { 4168c2ecf20Sopenharmony_ci switch (pll_id) { 4178c2ecf20Sopenharmony_ci case ATOM_PPLL1: 4188c2ecf20Sopenharmony_ci ss_cntl = RREG32(AVIVO_P1PLL_INT_SS_CNTL); 4198c2ecf20Sopenharmony_ci ss_cntl &= ~1; 4208c2ecf20Sopenharmony_ci WREG32(AVIVO_P1PLL_INT_SS_CNTL, ss_cntl); 4218c2ecf20Sopenharmony_ci break; 4228c2ecf20Sopenharmony_ci case ATOM_PPLL2: 4238c2ecf20Sopenharmony_ci ss_cntl = RREG32(AVIVO_P2PLL_INT_SS_CNTL); 4248c2ecf20Sopenharmony_ci ss_cntl &= ~1; 4258c2ecf20Sopenharmony_ci WREG32(AVIVO_P2PLL_INT_SS_CNTL, ss_cntl); 4268c2ecf20Sopenharmony_ci break; 4278c2ecf20Sopenharmony_ci case ATOM_DCPLL: 4288c2ecf20Sopenharmony_ci case ATOM_PPLL_INVALID: 4298c2ecf20Sopenharmony_ci return; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ciunion atom_enable_ss { 4368c2ecf20Sopenharmony_ci ENABLE_LVDS_SS_PARAMETERS lvds_ss; 4378c2ecf20Sopenharmony_ci ENABLE_LVDS_SS_PARAMETERS_V2 lvds_ss_2; 4388c2ecf20Sopenharmony_ci ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1; 4398c2ecf20Sopenharmony_ci ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 v2; 4408c2ecf20Sopenharmony_ci ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 v3; 4418c2ecf20Sopenharmony_ci}; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic void atombios_crtc_program_ss(struct radeon_device *rdev, 4448c2ecf20Sopenharmony_ci int enable, 4458c2ecf20Sopenharmony_ci int pll_id, 4468c2ecf20Sopenharmony_ci int crtc_id, 4478c2ecf20Sopenharmony_ci struct radeon_atom_ss *ss) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci unsigned i; 4508c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL); 4518c2ecf20Sopenharmony_ci union atom_enable_ss args; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (enable) { 4548c2ecf20Sopenharmony_ci /* Don't mess with SS if percentage is 0 or external ss. 4558c2ecf20Sopenharmony_ci * SS is already disabled previously, and disabling it 4568c2ecf20Sopenharmony_ci * again can cause display problems if the pll is already 4578c2ecf20Sopenharmony_ci * programmed. 4588c2ecf20Sopenharmony_ci */ 4598c2ecf20Sopenharmony_ci if (ss->percentage == 0) 4608c2ecf20Sopenharmony_ci return; 4618c2ecf20Sopenharmony_ci if (ss->type & ATOM_EXTERNAL_SS_MASK) 4628c2ecf20Sopenharmony_ci return; 4638c2ecf20Sopenharmony_ci } else { 4648c2ecf20Sopenharmony_ci for (i = 0; i < rdev->num_crtc; i++) { 4658c2ecf20Sopenharmony_ci if (rdev->mode_info.crtcs[i] && 4668c2ecf20Sopenharmony_ci rdev->mode_info.crtcs[i]->enabled && 4678c2ecf20Sopenharmony_ci i != crtc_id && 4688c2ecf20Sopenharmony_ci pll_id == rdev->mode_info.crtcs[i]->pll_id) { 4698c2ecf20Sopenharmony_ci /* one other crtc is using this pll don't turn 4708c2ecf20Sopenharmony_ci * off spread spectrum as it might turn off 4718c2ecf20Sopenharmony_ci * display on active crtc 4728c2ecf20Sopenharmony_ci */ 4738c2ecf20Sopenharmony_ci return; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci if (ASIC_IS_DCE5(rdev)) { 4818c2ecf20Sopenharmony_ci args.v3.usSpreadSpectrumAmountFrac = cpu_to_le16(0); 4828c2ecf20Sopenharmony_ci args.v3.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 4838c2ecf20Sopenharmony_ci switch (pll_id) { 4848c2ecf20Sopenharmony_ci case ATOM_PPLL1: 4858c2ecf20Sopenharmony_ci args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL; 4868c2ecf20Sopenharmony_ci break; 4878c2ecf20Sopenharmony_ci case ATOM_PPLL2: 4888c2ecf20Sopenharmony_ci args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL; 4898c2ecf20Sopenharmony_ci break; 4908c2ecf20Sopenharmony_ci case ATOM_DCPLL: 4918c2ecf20Sopenharmony_ci args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL; 4928c2ecf20Sopenharmony_ci break; 4938c2ecf20Sopenharmony_ci case ATOM_PPLL_INVALID: 4948c2ecf20Sopenharmony_ci return; 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci args.v3.usSpreadSpectrumAmount = cpu_to_le16(ss->amount); 4978c2ecf20Sopenharmony_ci args.v3.usSpreadSpectrumStep = cpu_to_le16(ss->step); 4988c2ecf20Sopenharmony_ci args.v3.ucEnable = enable; 4998c2ecf20Sopenharmony_ci } else if (ASIC_IS_DCE4(rdev)) { 5008c2ecf20Sopenharmony_ci args.v2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); 5018c2ecf20Sopenharmony_ci args.v2.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 5028c2ecf20Sopenharmony_ci switch (pll_id) { 5038c2ecf20Sopenharmony_ci case ATOM_PPLL1: 5048c2ecf20Sopenharmony_ci args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P1PLL; 5058c2ecf20Sopenharmony_ci break; 5068c2ecf20Sopenharmony_ci case ATOM_PPLL2: 5078c2ecf20Sopenharmony_ci args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P2PLL; 5088c2ecf20Sopenharmony_ci break; 5098c2ecf20Sopenharmony_ci case ATOM_DCPLL: 5108c2ecf20Sopenharmony_ci args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_DCPLL; 5118c2ecf20Sopenharmony_ci break; 5128c2ecf20Sopenharmony_ci case ATOM_PPLL_INVALID: 5138c2ecf20Sopenharmony_ci return; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci args.v2.usSpreadSpectrumAmount = cpu_to_le16(ss->amount); 5168c2ecf20Sopenharmony_ci args.v2.usSpreadSpectrumStep = cpu_to_le16(ss->step); 5178c2ecf20Sopenharmony_ci args.v2.ucEnable = enable; 5188c2ecf20Sopenharmony_ci } else if (ASIC_IS_DCE3(rdev)) { 5198c2ecf20Sopenharmony_ci args.v1.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); 5208c2ecf20Sopenharmony_ci args.v1.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 5218c2ecf20Sopenharmony_ci args.v1.ucSpreadSpectrumStep = ss->step; 5228c2ecf20Sopenharmony_ci args.v1.ucSpreadSpectrumDelay = ss->delay; 5238c2ecf20Sopenharmony_ci args.v1.ucSpreadSpectrumRange = ss->range; 5248c2ecf20Sopenharmony_ci args.v1.ucPpll = pll_id; 5258c2ecf20Sopenharmony_ci args.v1.ucEnable = enable; 5268c2ecf20Sopenharmony_ci } else if (ASIC_IS_AVIVO(rdev)) { 5278c2ecf20Sopenharmony_ci if ((enable == ATOM_DISABLE) || (ss->percentage == 0) || 5288c2ecf20Sopenharmony_ci (ss->type & ATOM_EXTERNAL_SS_MASK)) { 5298c2ecf20Sopenharmony_ci atombios_disable_ss(rdev, pll_id); 5308c2ecf20Sopenharmony_ci return; 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci args.lvds_ss_2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); 5338c2ecf20Sopenharmony_ci args.lvds_ss_2.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 5348c2ecf20Sopenharmony_ci args.lvds_ss_2.ucSpreadSpectrumStep = ss->step; 5358c2ecf20Sopenharmony_ci args.lvds_ss_2.ucSpreadSpectrumDelay = ss->delay; 5368c2ecf20Sopenharmony_ci args.lvds_ss_2.ucSpreadSpectrumRange = ss->range; 5378c2ecf20Sopenharmony_ci args.lvds_ss_2.ucEnable = enable; 5388c2ecf20Sopenharmony_ci } else { 5398c2ecf20Sopenharmony_ci if (enable == ATOM_DISABLE) { 5408c2ecf20Sopenharmony_ci atombios_disable_ss(rdev, pll_id); 5418c2ecf20Sopenharmony_ci return; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci args.lvds_ss.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); 5448c2ecf20Sopenharmony_ci args.lvds_ss.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 5458c2ecf20Sopenharmony_ci args.lvds_ss.ucSpreadSpectrumStepSize_Delay = (ss->step & 3) << 2; 5468c2ecf20Sopenharmony_ci args.lvds_ss.ucSpreadSpectrumStepSize_Delay |= (ss->delay & 7) << 4; 5478c2ecf20Sopenharmony_ci args.lvds_ss.ucEnable = enable; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ciunion adjust_pixel_clock { 5538c2ecf20Sopenharmony_ci ADJUST_DISPLAY_PLL_PS_ALLOCATION v1; 5548c2ecf20Sopenharmony_ci ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 v3; 5558c2ecf20Sopenharmony_ci}; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cistatic u32 atombios_adjust_pll(struct drm_crtc *crtc, 5588c2ecf20Sopenharmony_ci struct drm_display_mode *mode) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 5618c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 5628c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 5638c2ecf20Sopenharmony_ci struct drm_encoder *encoder = radeon_crtc->encoder; 5648c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 5658c2ecf20Sopenharmony_ci struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); 5668c2ecf20Sopenharmony_ci u32 adjusted_clock = mode->clock; 5678c2ecf20Sopenharmony_ci int encoder_mode = atombios_get_encoder_mode(encoder); 5688c2ecf20Sopenharmony_ci u32 dp_clock = mode->clock; 5698c2ecf20Sopenharmony_ci u32 clock = mode->clock; 5708c2ecf20Sopenharmony_ci int bpc = radeon_crtc->bpc; 5718c2ecf20Sopenharmony_ci bool is_duallink = radeon_dig_monitor_is_duallink(encoder, mode->clock); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci /* reset the pll flags */ 5748c2ecf20Sopenharmony_ci radeon_crtc->pll_flags = 0; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci if (ASIC_IS_AVIVO(rdev)) { 5778c2ecf20Sopenharmony_ci if ((rdev->family == CHIP_RS600) || 5788c2ecf20Sopenharmony_ci (rdev->family == CHIP_RS690) || 5798c2ecf20Sopenharmony_ci (rdev->family == CHIP_RS740)) 5808c2ecf20Sopenharmony_ci radeon_crtc->pll_flags |= (/*RADEON_PLL_USE_FRAC_FB_DIV |*/ 5818c2ecf20Sopenharmony_ci RADEON_PLL_PREFER_CLOSEST_LOWER); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (ASIC_IS_DCE32(rdev) && mode->clock > 200000) /* range limits??? */ 5848c2ecf20Sopenharmony_ci radeon_crtc->pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; 5858c2ecf20Sopenharmony_ci else 5868c2ecf20Sopenharmony_ci radeon_crtc->pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if (rdev->family < CHIP_RV770) 5898c2ecf20Sopenharmony_ci radeon_crtc->pll_flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP; 5908c2ecf20Sopenharmony_ci /* use frac fb div on APUs */ 5918c2ecf20Sopenharmony_ci if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev) || ASIC_IS_DCE8(rdev)) 5928c2ecf20Sopenharmony_ci radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; 5938c2ecf20Sopenharmony_ci /* use frac fb div on RS780/RS880 */ 5948c2ecf20Sopenharmony_ci if (((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880)) 5958c2ecf20Sopenharmony_ci && !radeon_crtc->ss_enabled) 5968c2ecf20Sopenharmony_ci radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; 5978c2ecf20Sopenharmony_ci if (ASIC_IS_DCE32(rdev) && mode->clock > 165000) 5988c2ecf20Sopenharmony_ci radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; 5998c2ecf20Sopenharmony_ci } else { 6008c2ecf20Sopenharmony_ci radeon_crtc->pll_flags |= RADEON_PLL_LEGACY; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci if (mode->clock > 200000) /* range limits??? */ 6038c2ecf20Sopenharmony_ci radeon_crtc->pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; 6048c2ecf20Sopenharmony_ci else 6058c2ecf20Sopenharmony_ci radeon_crtc->pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) || 6098c2ecf20Sopenharmony_ci (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)) { 6108c2ecf20Sopenharmony_ci if (connector) { 6118c2ecf20Sopenharmony_ci struct radeon_connector *radeon_connector = to_radeon_connector(connector); 6128c2ecf20Sopenharmony_ci struct radeon_connector_atom_dig *dig_connector = 6138c2ecf20Sopenharmony_ci radeon_connector->con_priv; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci dp_clock = dig_connector->dp_clock; 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci if (radeon_encoder->is_mst_encoder) { 6208c2ecf20Sopenharmony_ci struct radeon_encoder_mst *mst_enc = radeon_encoder->enc_priv; 6218c2ecf20Sopenharmony_ci struct radeon_connector_atom_dig *dig_connector = mst_enc->connector->con_priv; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci dp_clock = dig_connector->dp_clock; 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci /* use recommended ref_div for ss */ 6278c2ecf20Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 6288c2ecf20Sopenharmony_ci if (radeon_crtc->ss_enabled) { 6298c2ecf20Sopenharmony_ci if (radeon_crtc->ss.refdiv) { 6308c2ecf20Sopenharmony_ci radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV; 6318c2ecf20Sopenharmony_ci radeon_crtc->pll_reference_div = radeon_crtc->ss.refdiv; 6328c2ecf20Sopenharmony_ci if (ASIC_IS_AVIVO(rdev) && 6338c2ecf20Sopenharmony_ci rdev->family != CHIP_RS780 && 6348c2ecf20Sopenharmony_ci rdev->family != CHIP_RS880) 6358c2ecf20Sopenharmony_ci radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci if (ASIC_IS_AVIVO(rdev)) { 6418c2ecf20Sopenharmony_ci /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ 6428c2ecf20Sopenharmony_ci if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1) 6438c2ecf20Sopenharmony_ci adjusted_clock = mode->clock * 2; 6448c2ecf20Sopenharmony_ci if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 6458c2ecf20Sopenharmony_ci radeon_crtc->pll_flags |= RADEON_PLL_PREFER_CLOSEST_LOWER; 6468c2ecf20Sopenharmony_ci if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) 6478c2ecf20Sopenharmony_ci radeon_crtc->pll_flags |= RADEON_PLL_IS_LCD; 6488c2ecf20Sopenharmony_ci } else { 6498c2ecf20Sopenharmony_ci if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) 6508c2ecf20Sopenharmony_ci radeon_crtc->pll_flags |= RADEON_PLL_NO_ODD_POST_DIV; 6518c2ecf20Sopenharmony_ci if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) 6528c2ecf20Sopenharmony_ci radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV; 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci /* adjust pll for deep color modes */ 6568c2ecf20Sopenharmony_ci if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { 6578c2ecf20Sopenharmony_ci switch (bpc) { 6588c2ecf20Sopenharmony_ci case 8: 6598c2ecf20Sopenharmony_ci default: 6608c2ecf20Sopenharmony_ci break; 6618c2ecf20Sopenharmony_ci case 10: 6628c2ecf20Sopenharmony_ci clock = (clock * 5) / 4; 6638c2ecf20Sopenharmony_ci break; 6648c2ecf20Sopenharmony_ci case 12: 6658c2ecf20Sopenharmony_ci clock = (clock * 3) / 2; 6668c2ecf20Sopenharmony_ci break; 6678c2ecf20Sopenharmony_ci case 16: 6688c2ecf20Sopenharmony_ci clock = clock * 2; 6698c2ecf20Sopenharmony_ci break; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci /* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock 6748c2ecf20Sopenharmony_ci * accordingly based on the encoder/transmitter to work around 6758c2ecf20Sopenharmony_ci * special hw requirements. 6768c2ecf20Sopenharmony_ci */ 6778c2ecf20Sopenharmony_ci if (ASIC_IS_DCE3(rdev)) { 6788c2ecf20Sopenharmony_ci union adjust_pixel_clock args; 6798c2ecf20Sopenharmony_ci u8 frev, crev; 6808c2ecf20Sopenharmony_ci int index; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll); 6838c2ecf20Sopenharmony_ci if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 6848c2ecf20Sopenharmony_ci &crev)) 6858c2ecf20Sopenharmony_ci return adjusted_clock; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci switch (frev) { 6908c2ecf20Sopenharmony_ci case 1: 6918c2ecf20Sopenharmony_ci switch (crev) { 6928c2ecf20Sopenharmony_ci case 1: 6938c2ecf20Sopenharmony_ci case 2: 6948c2ecf20Sopenharmony_ci args.v1.usPixelClock = cpu_to_le16(clock / 10); 6958c2ecf20Sopenharmony_ci args.v1.ucTransmitterID = radeon_encoder->encoder_id; 6968c2ecf20Sopenharmony_ci args.v1.ucEncodeMode = encoder_mode; 6978c2ecf20Sopenharmony_ci if (radeon_crtc->ss_enabled && radeon_crtc->ss.percentage) 6988c2ecf20Sopenharmony_ci args.v1.ucConfig |= 6998c2ecf20Sopenharmony_ci ADJUST_DISPLAY_CONFIG_SS_ENABLE; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, 7028c2ecf20Sopenharmony_ci index, (uint32_t *)&args); 7038c2ecf20Sopenharmony_ci adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10; 7048c2ecf20Sopenharmony_ci break; 7058c2ecf20Sopenharmony_ci case 3: 7068c2ecf20Sopenharmony_ci args.v3.sInput.usPixelClock = cpu_to_le16(clock / 10); 7078c2ecf20Sopenharmony_ci args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id; 7088c2ecf20Sopenharmony_ci args.v3.sInput.ucEncodeMode = encoder_mode; 7098c2ecf20Sopenharmony_ci args.v3.sInput.ucDispPllConfig = 0; 7108c2ecf20Sopenharmony_ci if (radeon_crtc->ss_enabled && radeon_crtc->ss.percentage) 7118c2ecf20Sopenharmony_ci args.v3.sInput.ucDispPllConfig |= 7128c2ecf20Sopenharmony_ci DISPPLL_CONFIG_SS_ENABLE; 7138c2ecf20Sopenharmony_ci if (ENCODER_MODE_IS_DP(encoder_mode)) { 7148c2ecf20Sopenharmony_ci args.v3.sInput.ucDispPllConfig |= 7158c2ecf20Sopenharmony_ci DISPPLL_CONFIG_COHERENT_MODE; 7168c2ecf20Sopenharmony_ci /* 16200 or 27000 */ 7178c2ecf20Sopenharmony_ci args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); 7188c2ecf20Sopenharmony_ci } else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { 7198c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 7208c2ecf20Sopenharmony_ci if (dig->coherent_mode) 7218c2ecf20Sopenharmony_ci args.v3.sInput.ucDispPllConfig |= 7228c2ecf20Sopenharmony_ci DISPPLL_CONFIG_COHERENT_MODE; 7238c2ecf20Sopenharmony_ci if (is_duallink) 7248c2ecf20Sopenharmony_ci args.v3.sInput.ucDispPllConfig |= 7258c2ecf20Sopenharmony_ci DISPPLL_CONFIG_DUAL_LINK; 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci if (radeon_encoder_get_dp_bridge_encoder_id(encoder) != 7288c2ecf20Sopenharmony_ci ENCODER_OBJECT_ID_NONE) 7298c2ecf20Sopenharmony_ci args.v3.sInput.ucExtTransmitterID = 7308c2ecf20Sopenharmony_ci radeon_encoder_get_dp_bridge_encoder_id(encoder); 7318c2ecf20Sopenharmony_ci else 7328c2ecf20Sopenharmony_ci args.v3.sInput.ucExtTransmitterID = 0; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, 7358c2ecf20Sopenharmony_ci index, (uint32_t *)&args); 7368c2ecf20Sopenharmony_ci adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10; 7378c2ecf20Sopenharmony_ci if (args.v3.sOutput.ucRefDiv) { 7388c2ecf20Sopenharmony_ci radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; 7398c2ecf20Sopenharmony_ci radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV; 7408c2ecf20Sopenharmony_ci radeon_crtc->pll_reference_div = args.v3.sOutput.ucRefDiv; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci if (args.v3.sOutput.ucPostDiv) { 7438c2ecf20Sopenharmony_ci radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; 7448c2ecf20Sopenharmony_ci radeon_crtc->pll_flags |= RADEON_PLL_USE_POST_DIV; 7458c2ecf20Sopenharmony_ci radeon_crtc->pll_post_div = args.v3.sOutput.ucPostDiv; 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci break; 7488c2ecf20Sopenharmony_ci default: 7498c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version %d %d\n", frev, crev); 7508c2ecf20Sopenharmony_ci return adjusted_clock; 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci break; 7538c2ecf20Sopenharmony_ci default: 7548c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version %d %d\n", frev, crev); 7558c2ecf20Sopenharmony_ci return adjusted_clock; 7568c2ecf20Sopenharmony_ci } 7578c2ecf20Sopenharmony_ci } 7588c2ecf20Sopenharmony_ci return adjusted_clock; 7598c2ecf20Sopenharmony_ci} 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ciunion set_pixel_clock { 7628c2ecf20Sopenharmony_ci SET_PIXEL_CLOCK_PS_ALLOCATION base; 7638c2ecf20Sopenharmony_ci PIXEL_CLOCK_PARAMETERS v1; 7648c2ecf20Sopenharmony_ci PIXEL_CLOCK_PARAMETERS_V2 v2; 7658c2ecf20Sopenharmony_ci PIXEL_CLOCK_PARAMETERS_V3 v3; 7668c2ecf20Sopenharmony_ci PIXEL_CLOCK_PARAMETERS_V5 v5; 7678c2ecf20Sopenharmony_ci PIXEL_CLOCK_PARAMETERS_V6 v6; 7688c2ecf20Sopenharmony_ci}; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci/* on DCE5, make sure the voltage is high enough to support the 7718c2ecf20Sopenharmony_ci * required disp clk. 7728c2ecf20Sopenharmony_ci */ 7738c2ecf20Sopenharmony_cistatic void atombios_crtc_set_disp_eng_pll(struct radeon_device *rdev, 7748c2ecf20Sopenharmony_ci u32 dispclk) 7758c2ecf20Sopenharmony_ci{ 7768c2ecf20Sopenharmony_ci u8 frev, crev; 7778c2ecf20Sopenharmony_ci int index; 7788c2ecf20Sopenharmony_ci union set_pixel_clock args; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); 7838c2ecf20Sopenharmony_ci if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 7848c2ecf20Sopenharmony_ci &crev)) 7858c2ecf20Sopenharmony_ci return; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci switch (frev) { 7888c2ecf20Sopenharmony_ci case 1: 7898c2ecf20Sopenharmony_ci switch (crev) { 7908c2ecf20Sopenharmony_ci case 5: 7918c2ecf20Sopenharmony_ci /* if the default dcpll clock is specified, 7928c2ecf20Sopenharmony_ci * SetPixelClock provides the dividers 7938c2ecf20Sopenharmony_ci */ 7948c2ecf20Sopenharmony_ci args.v5.ucCRTC = ATOM_CRTC_INVALID; 7958c2ecf20Sopenharmony_ci args.v5.usPixelClock = cpu_to_le16(dispclk); 7968c2ecf20Sopenharmony_ci args.v5.ucPpll = ATOM_DCPLL; 7978c2ecf20Sopenharmony_ci break; 7988c2ecf20Sopenharmony_ci case 6: 7998c2ecf20Sopenharmony_ci /* if the default dcpll clock is specified, 8008c2ecf20Sopenharmony_ci * SetPixelClock provides the dividers 8018c2ecf20Sopenharmony_ci */ 8028c2ecf20Sopenharmony_ci args.v6.ulDispEngClkFreq = cpu_to_le32(dispclk); 8038c2ecf20Sopenharmony_ci if (ASIC_IS_DCE61(rdev) || ASIC_IS_DCE8(rdev)) 8048c2ecf20Sopenharmony_ci args.v6.ucPpll = ATOM_EXT_PLL1; 8058c2ecf20Sopenharmony_ci else if (ASIC_IS_DCE6(rdev)) 8068c2ecf20Sopenharmony_ci args.v6.ucPpll = ATOM_PPLL0; 8078c2ecf20Sopenharmony_ci else 8088c2ecf20Sopenharmony_ci args.v6.ucPpll = ATOM_DCPLL; 8098c2ecf20Sopenharmony_ci break; 8108c2ecf20Sopenharmony_ci default: 8118c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version %d %d\n", frev, crev); 8128c2ecf20Sopenharmony_ci return; 8138c2ecf20Sopenharmony_ci } 8148c2ecf20Sopenharmony_ci break; 8158c2ecf20Sopenharmony_ci default: 8168c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version %d %d\n", frev, crev); 8178c2ecf20Sopenharmony_ci return; 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 8208c2ecf20Sopenharmony_ci} 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_cistatic void atombios_crtc_program_pll(struct drm_crtc *crtc, 8238c2ecf20Sopenharmony_ci u32 crtc_id, 8248c2ecf20Sopenharmony_ci int pll_id, 8258c2ecf20Sopenharmony_ci u32 encoder_mode, 8268c2ecf20Sopenharmony_ci u32 encoder_id, 8278c2ecf20Sopenharmony_ci u32 clock, 8288c2ecf20Sopenharmony_ci u32 ref_div, 8298c2ecf20Sopenharmony_ci u32 fb_div, 8308c2ecf20Sopenharmony_ci u32 frac_fb_div, 8318c2ecf20Sopenharmony_ci u32 post_div, 8328c2ecf20Sopenharmony_ci int bpc, 8338c2ecf20Sopenharmony_ci bool ss_enabled, 8348c2ecf20Sopenharmony_ci struct radeon_atom_ss *ss) 8358c2ecf20Sopenharmony_ci{ 8368c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 8378c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 8388c2ecf20Sopenharmony_ci u8 frev, crev; 8398c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); 8408c2ecf20Sopenharmony_ci union set_pixel_clock args; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, 8458c2ecf20Sopenharmony_ci &crev)) 8468c2ecf20Sopenharmony_ci return; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci switch (frev) { 8498c2ecf20Sopenharmony_ci case 1: 8508c2ecf20Sopenharmony_ci switch (crev) { 8518c2ecf20Sopenharmony_ci case 1: 8528c2ecf20Sopenharmony_ci if (clock == ATOM_DISABLE) 8538c2ecf20Sopenharmony_ci return; 8548c2ecf20Sopenharmony_ci args.v1.usPixelClock = cpu_to_le16(clock / 10); 8558c2ecf20Sopenharmony_ci args.v1.usRefDiv = cpu_to_le16(ref_div); 8568c2ecf20Sopenharmony_ci args.v1.usFbDiv = cpu_to_le16(fb_div); 8578c2ecf20Sopenharmony_ci args.v1.ucFracFbDiv = frac_fb_div; 8588c2ecf20Sopenharmony_ci args.v1.ucPostDiv = post_div; 8598c2ecf20Sopenharmony_ci args.v1.ucPpll = pll_id; 8608c2ecf20Sopenharmony_ci args.v1.ucCRTC = crtc_id; 8618c2ecf20Sopenharmony_ci args.v1.ucRefDivSrc = 1; 8628c2ecf20Sopenharmony_ci break; 8638c2ecf20Sopenharmony_ci case 2: 8648c2ecf20Sopenharmony_ci args.v2.usPixelClock = cpu_to_le16(clock / 10); 8658c2ecf20Sopenharmony_ci args.v2.usRefDiv = cpu_to_le16(ref_div); 8668c2ecf20Sopenharmony_ci args.v2.usFbDiv = cpu_to_le16(fb_div); 8678c2ecf20Sopenharmony_ci args.v2.ucFracFbDiv = frac_fb_div; 8688c2ecf20Sopenharmony_ci args.v2.ucPostDiv = post_div; 8698c2ecf20Sopenharmony_ci args.v2.ucPpll = pll_id; 8708c2ecf20Sopenharmony_ci args.v2.ucCRTC = crtc_id; 8718c2ecf20Sopenharmony_ci args.v2.ucRefDivSrc = 1; 8728c2ecf20Sopenharmony_ci break; 8738c2ecf20Sopenharmony_ci case 3: 8748c2ecf20Sopenharmony_ci args.v3.usPixelClock = cpu_to_le16(clock / 10); 8758c2ecf20Sopenharmony_ci args.v3.usRefDiv = cpu_to_le16(ref_div); 8768c2ecf20Sopenharmony_ci args.v3.usFbDiv = cpu_to_le16(fb_div); 8778c2ecf20Sopenharmony_ci args.v3.ucFracFbDiv = frac_fb_div; 8788c2ecf20Sopenharmony_ci args.v3.ucPostDiv = post_div; 8798c2ecf20Sopenharmony_ci args.v3.ucPpll = pll_id; 8808c2ecf20Sopenharmony_ci if (crtc_id == ATOM_CRTC2) 8818c2ecf20Sopenharmony_ci args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC2; 8828c2ecf20Sopenharmony_ci else 8838c2ecf20Sopenharmony_ci args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC1; 8848c2ecf20Sopenharmony_ci if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) 8858c2ecf20Sopenharmony_ci args.v3.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC; 8868c2ecf20Sopenharmony_ci args.v3.ucTransmitterId = encoder_id; 8878c2ecf20Sopenharmony_ci args.v3.ucEncoderMode = encoder_mode; 8888c2ecf20Sopenharmony_ci break; 8898c2ecf20Sopenharmony_ci case 5: 8908c2ecf20Sopenharmony_ci args.v5.ucCRTC = crtc_id; 8918c2ecf20Sopenharmony_ci args.v5.usPixelClock = cpu_to_le16(clock / 10); 8928c2ecf20Sopenharmony_ci args.v5.ucRefDiv = ref_div; 8938c2ecf20Sopenharmony_ci args.v5.usFbDiv = cpu_to_le16(fb_div); 8948c2ecf20Sopenharmony_ci args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); 8958c2ecf20Sopenharmony_ci args.v5.ucPostDiv = post_div; 8968c2ecf20Sopenharmony_ci args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */ 8978c2ecf20Sopenharmony_ci if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) 8988c2ecf20Sopenharmony_ci args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_REF_DIV_SRC; 8998c2ecf20Sopenharmony_ci if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { 9008c2ecf20Sopenharmony_ci switch (bpc) { 9018c2ecf20Sopenharmony_ci case 8: 9028c2ecf20Sopenharmony_ci default: 9038c2ecf20Sopenharmony_ci args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP; 9048c2ecf20Sopenharmony_ci break; 9058c2ecf20Sopenharmony_ci case 10: 9068c2ecf20Sopenharmony_ci /* yes this is correct, the atom define is wrong */ 9078c2ecf20Sopenharmony_ci args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_32BPP; 9088c2ecf20Sopenharmony_ci break; 9098c2ecf20Sopenharmony_ci case 12: 9108c2ecf20Sopenharmony_ci /* yes this is correct, the atom define is wrong */ 9118c2ecf20Sopenharmony_ci args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP; 9128c2ecf20Sopenharmony_ci break; 9138c2ecf20Sopenharmony_ci } 9148c2ecf20Sopenharmony_ci } 9158c2ecf20Sopenharmony_ci args.v5.ucTransmitterID = encoder_id; 9168c2ecf20Sopenharmony_ci args.v5.ucEncoderMode = encoder_mode; 9178c2ecf20Sopenharmony_ci args.v5.ucPpll = pll_id; 9188c2ecf20Sopenharmony_ci break; 9198c2ecf20Sopenharmony_ci case 6: 9208c2ecf20Sopenharmony_ci args.v6.ulDispEngClkFreq = cpu_to_le32(crtc_id << 24 | clock / 10); 9218c2ecf20Sopenharmony_ci args.v6.ucRefDiv = ref_div; 9228c2ecf20Sopenharmony_ci args.v6.usFbDiv = cpu_to_le16(fb_div); 9238c2ecf20Sopenharmony_ci args.v6.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); 9248c2ecf20Sopenharmony_ci args.v6.ucPostDiv = post_div; 9258c2ecf20Sopenharmony_ci args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */ 9268c2ecf20Sopenharmony_ci if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) 9278c2ecf20Sopenharmony_ci args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_REF_DIV_SRC; 9288c2ecf20Sopenharmony_ci if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { 9298c2ecf20Sopenharmony_ci switch (bpc) { 9308c2ecf20Sopenharmony_ci case 8: 9318c2ecf20Sopenharmony_ci default: 9328c2ecf20Sopenharmony_ci args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP; 9338c2ecf20Sopenharmony_ci break; 9348c2ecf20Sopenharmony_ci case 10: 9358c2ecf20Sopenharmony_ci args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP_V6; 9368c2ecf20Sopenharmony_ci break; 9378c2ecf20Sopenharmony_ci case 12: 9388c2ecf20Sopenharmony_ci args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP_V6; 9398c2ecf20Sopenharmony_ci break; 9408c2ecf20Sopenharmony_ci case 16: 9418c2ecf20Sopenharmony_ci args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP; 9428c2ecf20Sopenharmony_ci break; 9438c2ecf20Sopenharmony_ci } 9448c2ecf20Sopenharmony_ci } 9458c2ecf20Sopenharmony_ci args.v6.ucTransmitterID = encoder_id; 9468c2ecf20Sopenharmony_ci args.v6.ucEncoderMode = encoder_mode; 9478c2ecf20Sopenharmony_ci args.v6.ucPpll = pll_id; 9488c2ecf20Sopenharmony_ci break; 9498c2ecf20Sopenharmony_ci default: 9508c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version %d %d\n", frev, crev); 9518c2ecf20Sopenharmony_ci return; 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci break; 9548c2ecf20Sopenharmony_ci default: 9558c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version %d %d\n", frev, crev); 9568c2ecf20Sopenharmony_ci return; 9578c2ecf20Sopenharmony_ci } 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 9608c2ecf20Sopenharmony_ci} 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_cistatic bool atombios_crtc_prepare_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) 9638c2ecf20Sopenharmony_ci{ 9648c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 9658c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 9668c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 9678c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = 9688c2ecf20Sopenharmony_ci to_radeon_encoder(radeon_crtc->encoder); 9698c2ecf20Sopenharmony_ci int encoder_mode = atombios_get_encoder_mode(radeon_crtc->encoder); 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci radeon_crtc->bpc = 8; 9728c2ecf20Sopenharmony_ci radeon_crtc->ss_enabled = false; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci if (radeon_encoder->is_mst_encoder) { 9758c2ecf20Sopenharmony_ci radeon_dp_mst_prepare_pll(crtc, mode); 9768c2ecf20Sopenharmony_ci } else if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) || 9778c2ecf20Sopenharmony_ci (radeon_encoder_get_dp_bridge_encoder_id(radeon_crtc->encoder) != ENCODER_OBJECT_ID_NONE)) { 9788c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 9798c2ecf20Sopenharmony_ci struct drm_connector *connector = 9808c2ecf20Sopenharmony_ci radeon_get_connector_for_encoder(radeon_crtc->encoder); 9818c2ecf20Sopenharmony_ci struct radeon_connector *radeon_connector = 9828c2ecf20Sopenharmony_ci to_radeon_connector(connector); 9838c2ecf20Sopenharmony_ci struct radeon_connector_atom_dig *dig_connector = 9848c2ecf20Sopenharmony_ci radeon_connector->con_priv; 9858c2ecf20Sopenharmony_ci int dp_clock; 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci /* Assign mode clock for hdmi deep color max clock limit check */ 9888c2ecf20Sopenharmony_ci radeon_connector->pixelclock_for_modeset = mode->clock; 9898c2ecf20Sopenharmony_ci radeon_crtc->bpc = radeon_get_monitor_bpc(connector); 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci switch (encoder_mode) { 9928c2ecf20Sopenharmony_ci case ATOM_ENCODER_MODE_DP_MST: 9938c2ecf20Sopenharmony_ci case ATOM_ENCODER_MODE_DP: 9948c2ecf20Sopenharmony_ci /* DP/eDP */ 9958c2ecf20Sopenharmony_ci dp_clock = dig_connector->dp_clock / 10; 9968c2ecf20Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) 9978c2ecf20Sopenharmony_ci radeon_crtc->ss_enabled = 9988c2ecf20Sopenharmony_ci radeon_atombios_get_asic_ss_info(rdev, &radeon_crtc->ss, 9998c2ecf20Sopenharmony_ci ASIC_INTERNAL_SS_ON_DP, 10008c2ecf20Sopenharmony_ci dp_clock); 10018c2ecf20Sopenharmony_ci else { 10028c2ecf20Sopenharmony_ci if (dp_clock == 16200) { 10038c2ecf20Sopenharmony_ci radeon_crtc->ss_enabled = 10048c2ecf20Sopenharmony_ci radeon_atombios_get_ppll_ss_info(rdev, 10058c2ecf20Sopenharmony_ci &radeon_crtc->ss, 10068c2ecf20Sopenharmony_ci ATOM_DP_SS_ID2); 10078c2ecf20Sopenharmony_ci if (!radeon_crtc->ss_enabled) 10088c2ecf20Sopenharmony_ci radeon_crtc->ss_enabled = 10098c2ecf20Sopenharmony_ci radeon_atombios_get_ppll_ss_info(rdev, 10108c2ecf20Sopenharmony_ci &radeon_crtc->ss, 10118c2ecf20Sopenharmony_ci ATOM_DP_SS_ID1); 10128c2ecf20Sopenharmony_ci } else { 10138c2ecf20Sopenharmony_ci radeon_crtc->ss_enabled = 10148c2ecf20Sopenharmony_ci radeon_atombios_get_ppll_ss_info(rdev, 10158c2ecf20Sopenharmony_ci &radeon_crtc->ss, 10168c2ecf20Sopenharmony_ci ATOM_DP_SS_ID1); 10178c2ecf20Sopenharmony_ci } 10188c2ecf20Sopenharmony_ci /* disable spread spectrum on DCE3 DP */ 10198c2ecf20Sopenharmony_ci radeon_crtc->ss_enabled = false; 10208c2ecf20Sopenharmony_ci } 10218c2ecf20Sopenharmony_ci break; 10228c2ecf20Sopenharmony_ci case ATOM_ENCODER_MODE_LVDS: 10238c2ecf20Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) 10248c2ecf20Sopenharmony_ci radeon_crtc->ss_enabled = 10258c2ecf20Sopenharmony_ci radeon_atombios_get_asic_ss_info(rdev, 10268c2ecf20Sopenharmony_ci &radeon_crtc->ss, 10278c2ecf20Sopenharmony_ci dig->lcd_ss_id, 10288c2ecf20Sopenharmony_ci mode->clock / 10); 10298c2ecf20Sopenharmony_ci else 10308c2ecf20Sopenharmony_ci radeon_crtc->ss_enabled = 10318c2ecf20Sopenharmony_ci radeon_atombios_get_ppll_ss_info(rdev, 10328c2ecf20Sopenharmony_ci &radeon_crtc->ss, 10338c2ecf20Sopenharmony_ci dig->lcd_ss_id); 10348c2ecf20Sopenharmony_ci break; 10358c2ecf20Sopenharmony_ci case ATOM_ENCODER_MODE_DVI: 10368c2ecf20Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) 10378c2ecf20Sopenharmony_ci radeon_crtc->ss_enabled = 10388c2ecf20Sopenharmony_ci radeon_atombios_get_asic_ss_info(rdev, 10398c2ecf20Sopenharmony_ci &radeon_crtc->ss, 10408c2ecf20Sopenharmony_ci ASIC_INTERNAL_SS_ON_TMDS, 10418c2ecf20Sopenharmony_ci mode->clock / 10); 10428c2ecf20Sopenharmony_ci break; 10438c2ecf20Sopenharmony_ci case ATOM_ENCODER_MODE_HDMI: 10448c2ecf20Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) 10458c2ecf20Sopenharmony_ci radeon_crtc->ss_enabled = 10468c2ecf20Sopenharmony_ci radeon_atombios_get_asic_ss_info(rdev, 10478c2ecf20Sopenharmony_ci &radeon_crtc->ss, 10488c2ecf20Sopenharmony_ci ASIC_INTERNAL_SS_ON_HDMI, 10498c2ecf20Sopenharmony_ci mode->clock / 10); 10508c2ecf20Sopenharmony_ci break; 10518c2ecf20Sopenharmony_ci default: 10528c2ecf20Sopenharmony_ci break; 10538c2ecf20Sopenharmony_ci } 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci /* adjust pixel clock as needed */ 10578c2ecf20Sopenharmony_ci radeon_crtc->adjusted_clock = atombios_adjust_pll(crtc, mode); 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci return true; 10608c2ecf20Sopenharmony_ci} 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_cistatic void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) 10638c2ecf20Sopenharmony_ci{ 10648c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 10658c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 10668c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 10678c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = 10688c2ecf20Sopenharmony_ci to_radeon_encoder(radeon_crtc->encoder); 10698c2ecf20Sopenharmony_ci u32 pll_clock = mode->clock; 10708c2ecf20Sopenharmony_ci u32 clock = mode->clock; 10718c2ecf20Sopenharmony_ci u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; 10728c2ecf20Sopenharmony_ci struct radeon_pll *pll; 10738c2ecf20Sopenharmony_ci int encoder_mode = atombios_get_encoder_mode(radeon_crtc->encoder); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci /* pass the actual clock to atombios_crtc_program_pll for DCE5,6 for HDMI */ 10768c2ecf20Sopenharmony_ci if (ASIC_IS_DCE5(rdev) && 10778c2ecf20Sopenharmony_ci (encoder_mode == ATOM_ENCODER_MODE_HDMI) && 10788c2ecf20Sopenharmony_ci (radeon_crtc->bpc > 8)) 10798c2ecf20Sopenharmony_ci clock = radeon_crtc->adjusted_clock; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci switch (radeon_crtc->pll_id) { 10828c2ecf20Sopenharmony_ci case ATOM_PPLL1: 10838c2ecf20Sopenharmony_ci pll = &rdev->clock.p1pll; 10848c2ecf20Sopenharmony_ci break; 10858c2ecf20Sopenharmony_ci case ATOM_PPLL2: 10868c2ecf20Sopenharmony_ci pll = &rdev->clock.p2pll; 10878c2ecf20Sopenharmony_ci break; 10888c2ecf20Sopenharmony_ci case ATOM_DCPLL: 10898c2ecf20Sopenharmony_ci case ATOM_PPLL_INVALID: 10908c2ecf20Sopenharmony_ci default: 10918c2ecf20Sopenharmony_ci pll = &rdev->clock.dcpll; 10928c2ecf20Sopenharmony_ci break; 10938c2ecf20Sopenharmony_ci } 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci /* update pll params */ 10968c2ecf20Sopenharmony_ci pll->flags = radeon_crtc->pll_flags; 10978c2ecf20Sopenharmony_ci pll->reference_div = radeon_crtc->pll_reference_div; 10988c2ecf20Sopenharmony_ci pll->post_div = radeon_crtc->pll_post_div; 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) 11018c2ecf20Sopenharmony_ci /* TV seems to prefer the legacy algo on some boards */ 11028c2ecf20Sopenharmony_ci radeon_compute_pll_legacy(pll, radeon_crtc->adjusted_clock, &pll_clock, 11038c2ecf20Sopenharmony_ci &fb_div, &frac_fb_div, &ref_div, &post_div); 11048c2ecf20Sopenharmony_ci else if (ASIC_IS_AVIVO(rdev)) 11058c2ecf20Sopenharmony_ci radeon_compute_pll_avivo(pll, radeon_crtc->adjusted_clock, &pll_clock, 11068c2ecf20Sopenharmony_ci &fb_div, &frac_fb_div, &ref_div, &post_div); 11078c2ecf20Sopenharmony_ci else 11088c2ecf20Sopenharmony_ci radeon_compute_pll_legacy(pll, radeon_crtc->adjusted_clock, &pll_clock, 11098c2ecf20Sopenharmony_ci &fb_div, &frac_fb_div, &ref_div, &post_div); 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci atombios_crtc_program_ss(rdev, ATOM_DISABLE, radeon_crtc->pll_id, 11128c2ecf20Sopenharmony_ci radeon_crtc->crtc_id, &radeon_crtc->ss); 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, 11158c2ecf20Sopenharmony_ci encoder_mode, radeon_encoder->encoder_id, clock, 11168c2ecf20Sopenharmony_ci ref_div, fb_div, frac_fb_div, post_div, 11178c2ecf20Sopenharmony_ci radeon_crtc->bpc, radeon_crtc->ss_enabled, &radeon_crtc->ss); 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci if (radeon_crtc->ss_enabled) { 11208c2ecf20Sopenharmony_ci /* calculate ss amount and step size */ 11218c2ecf20Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) { 11228c2ecf20Sopenharmony_ci u32 step_size; 11238c2ecf20Sopenharmony_ci u32 amount = (((fb_div * 10) + frac_fb_div) * 11248c2ecf20Sopenharmony_ci (u32)radeon_crtc->ss.percentage) / 11258c2ecf20Sopenharmony_ci (100 * (u32)radeon_crtc->ss.percentage_divider); 11268c2ecf20Sopenharmony_ci radeon_crtc->ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK; 11278c2ecf20Sopenharmony_ci radeon_crtc->ss.amount |= ((amount - (amount / 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) & 11288c2ecf20Sopenharmony_ci ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK; 11298c2ecf20Sopenharmony_ci if (radeon_crtc->ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD) 11308c2ecf20Sopenharmony_ci step_size = (4 * amount * ref_div * ((u32)radeon_crtc->ss.rate * 2048)) / 11318c2ecf20Sopenharmony_ci (125 * 25 * pll->reference_freq / 100); 11328c2ecf20Sopenharmony_ci else 11338c2ecf20Sopenharmony_ci step_size = (2 * amount * ref_div * ((u32)radeon_crtc->ss.rate * 2048)) / 11348c2ecf20Sopenharmony_ci (125 * 25 * pll->reference_freq / 100); 11358c2ecf20Sopenharmony_ci radeon_crtc->ss.step = step_size; 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci atombios_crtc_program_ss(rdev, ATOM_ENABLE, radeon_crtc->pll_id, 11398c2ecf20Sopenharmony_ci radeon_crtc->crtc_id, &radeon_crtc->ss); 11408c2ecf20Sopenharmony_ci } 11418c2ecf20Sopenharmony_ci} 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_cistatic int dce4_crtc_do_set_base(struct drm_crtc *crtc, 11448c2ecf20Sopenharmony_ci struct drm_framebuffer *fb, 11458c2ecf20Sopenharmony_ci int x, int y, int atomic) 11468c2ecf20Sopenharmony_ci{ 11478c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 11488c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 11498c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 11508c2ecf20Sopenharmony_ci struct drm_framebuffer *target_fb; 11518c2ecf20Sopenharmony_ci struct drm_gem_object *obj; 11528c2ecf20Sopenharmony_ci struct radeon_bo *rbo; 11538c2ecf20Sopenharmony_ci uint64_t fb_location; 11548c2ecf20Sopenharmony_ci uint32_t fb_format, fb_pitch_pixels, tiling_flags; 11558c2ecf20Sopenharmony_ci unsigned bankw, bankh, mtaspect, tile_split; 11568c2ecf20Sopenharmony_ci u32 fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE); 11578c2ecf20Sopenharmony_ci u32 tmp, viewport_w, viewport_h; 11588c2ecf20Sopenharmony_ci int r; 11598c2ecf20Sopenharmony_ci bool bypass_lut = false; 11608c2ecf20Sopenharmony_ci struct drm_format_name_buf format_name; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci /* no fb bound */ 11638c2ecf20Sopenharmony_ci if (!atomic && !crtc->primary->fb) { 11648c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("No FB bound\n"); 11658c2ecf20Sopenharmony_ci return 0; 11668c2ecf20Sopenharmony_ci } 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci if (atomic) 11698c2ecf20Sopenharmony_ci target_fb = fb; 11708c2ecf20Sopenharmony_ci else 11718c2ecf20Sopenharmony_ci target_fb = crtc->primary->fb; 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci /* If atomic, assume fb object is pinned & idle & fenced and 11748c2ecf20Sopenharmony_ci * just update base pointers 11758c2ecf20Sopenharmony_ci */ 11768c2ecf20Sopenharmony_ci obj = target_fb->obj[0]; 11778c2ecf20Sopenharmony_ci rbo = gem_to_radeon_bo(obj); 11788c2ecf20Sopenharmony_ci r = radeon_bo_reserve(rbo, false); 11798c2ecf20Sopenharmony_ci if (unlikely(r != 0)) 11808c2ecf20Sopenharmony_ci return r; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci if (atomic) 11838c2ecf20Sopenharmony_ci fb_location = radeon_bo_gpu_offset(rbo); 11848c2ecf20Sopenharmony_ci else { 11858c2ecf20Sopenharmony_ci r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); 11868c2ecf20Sopenharmony_ci if (unlikely(r != 0)) { 11878c2ecf20Sopenharmony_ci radeon_bo_unreserve(rbo); 11888c2ecf20Sopenharmony_ci return -EINVAL; 11898c2ecf20Sopenharmony_ci } 11908c2ecf20Sopenharmony_ci } 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); 11938c2ecf20Sopenharmony_ci radeon_bo_unreserve(rbo); 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci switch (target_fb->format->format) { 11968c2ecf20Sopenharmony_ci case DRM_FORMAT_C8: 11978c2ecf20Sopenharmony_ci fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP) | 11988c2ecf20Sopenharmony_ci EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED)); 11998c2ecf20Sopenharmony_ci break; 12008c2ecf20Sopenharmony_ci case DRM_FORMAT_XRGB4444: 12018c2ecf20Sopenharmony_ci case DRM_FORMAT_ARGB4444: 12028c2ecf20Sopenharmony_ci fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 12038c2ecf20Sopenharmony_ci EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB4444)); 12048c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 12058c2ecf20Sopenharmony_ci fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16); 12068c2ecf20Sopenharmony_ci#endif 12078c2ecf20Sopenharmony_ci break; 12088c2ecf20Sopenharmony_ci case DRM_FORMAT_XRGB1555: 12098c2ecf20Sopenharmony_ci case DRM_FORMAT_ARGB1555: 12108c2ecf20Sopenharmony_ci fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 12118c2ecf20Sopenharmony_ci EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB1555)); 12128c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 12138c2ecf20Sopenharmony_ci fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16); 12148c2ecf20Sopenharmony_ci#endif 12158c2ecf20Sopenharmony_ci break; 12168c2ecf20Sopenharmony_ci case DRM_FORMAT_BGRX5551: 12178c2ecf20Sopenharmony_ci case DRM_FORMAT_BGRA5551: 12188c2ecf20Sopenharmony_ci fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 12198c2ecf20Sopenharmony_ci EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_BGRA5551)); 12208c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 12218c2ecf20Sopenharmony_ci fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16); 12228c2ecf20Sopenharmony_ci#endif 12238c2ecf20Sopenharmony_ci break; 12248c2ecf20Sopenharmony_ci case DRM_FORMAT_RGB565: 12258c2ecf20Sopenharmony_ci fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | 12268c2ecf20Sopenharmony_ci EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565)); 12278c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 12288c2ecf20Sopenharmony_ci fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16); 12298c2ecf20Sopenharmony_ci#endif 12308c2ecf20Sopenharmony_ci break; 12318c2ecf20Sopenharmony_ci case DRM_FORMAT_XRGB8888: 12328c2ecf20Sopenharmony_ci case DRM_FORMAT_ARGB8888: 12338c2ecf20Sopenharmony_ci fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) | 12348c2ecf20Sopenharmony_ci EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888)); 12358c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 12368c2ecf20Sopenharmony_ci fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32); 12378c2ecf20Sopenharmony_ci#endif 12388c2ecf20Sopenharmony_ci break; 12398c2ecf20Sopenharmony_ci case DRM_FORMAT_XRGB2101010: 12408c2ecf20Sopenharmony_ci case DRM_FORMAT_ARGB2101010: 12418c2ecf20Sopenharmony_ci fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) | 12428c2ecf20Sopenharmony_ci EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB2101010)); 12438c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 12448c2ecf20Sopenharmony_ci fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32); 12458c2ecf20Sopenharmony_ci#endif 12468c2ecf20Sopenharmony_ci /* Greater 8 bpc fb needs to bypass hw-lut to retain precision */ 12478c2ecf20Sopenharmony_ci bypass_lut = true; 12488c2ecf20Sopenharmony_ci break; 12498c2ecf20Sopenharmony_ci case DRM_FORMAT_BGRX1010102: 12508c2ecf20Sopenharmony_ci case DRM_FORMAT_BGRA1010102: 12518c2ecf20Sopenharmony_ci fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) | 12528c2ecf20Sopenharmony_ci EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_BGRA1010102)); 12538c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 12548c2ecf20Sopenharmony_ci fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32); 12558c2ecf20Sopenharmony_ci#endif 12568c2ecf20Sopenharmony_ci /* Greater 8 bpc fb needs to bypass hw-lut to retain precision */ 12578c2ecf20Sopenharmony_ci bypass_lut = true; 12588c2ecf20Sopenharmony_ci break; 12598c2ecf20Sopenharmony_ci case DRM_FORMAT_XBGR8888: 12608c2ecf20Sopenharmony_ci case DRM_FORMAT_ABGR8888: 12618c2ecf20Sopenharmony_ci fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) | 12628c2ecf20Sopenharmony_ci EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888)); 12638c2ecf20Sopenharmony_ci fb_swap = (EVERGREEN_GRPH_RED_CROSSBAR(EVERGREEN_GRPH_RED_SEL_B) | 12648c2ecf20Sopenharmony_ci EVERGREEN_GRPH_BLUE_CROSSBAR(EVERGREEN_GRPH_BLUE_SEL_R)); 12658c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 12668c2ecf20Sopenharmony_ci fb_swap |= EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32); 12678c2ecf20Sopenharmony_ci#endif 12688c2ecf20Sopenharmony_ci break; 12698c2ecf20Sopenharmony_ci default: 12708c2ecf20Sopenharmony_ci DRM_ERROR("Unsupported screen format %s\n", 12718c2ecf20Sopenharmony_ci drm_get_format_name(target_fb->format->format, &format_name)); 12728c2ecf20Sopenharmony_ci return -EINVAL; 12738c2ecf20Sopenharmony_ci } 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci if (tiling_flags & RADEON_TILING_MACRO) { 12768c2ecf20Sopenharmony_ci evergreen_tiling_fields(tiling_flags, &bankw, &bankh, &mtaspect, &tile_split); 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci /* Set NUM_BANKS. */ 12798c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_TAHITI) { 12808c2ecf20Sopenharmony_ci unsigned index, num_banks; 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_BONAIRE) { 12838c2ecf20Sopenharmony_ci unsigned tileb, tile_split_bytes; 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci /* Calculate the macrotile mode index. */ 12868c2ecf20Sopenharmony_ci tile_split_bytes = 64 << tile_split; 12878c2ecf20Sopenharmony_ci tileb = 8 * 8 * target_fb->format->cpp[0]; 12888c2ecf20Sopenharmony_ci tileb = min(tile_split_bytes, tileb); 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci for (index = 0; tileb > 64; index++) 12918c2ecf20Sopenharmony_ci tileb >>= 1; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci if (index >= 16) { 12948c2ecf20Sopenharmony_ci DRM_ERROR("Wrong screen bpp (%u) or tile split (%u)\n", 12958c2ecf20Sopenharmony_ci target_fb->format->cpp[0] * 8, 12968c2ecf20Sopenharmony_ci tile_split); 12978c2ecf20Sopenharmony_ci return -EINVAL; 12988c2ecf20Sopenharmony_ci } 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci num_banks = (rdev->config.cik.macrotile_mode_array[index] >> 6) & 0x3; 13018c2ecf20Sopenharmony_ci } else { 13028c2ecf20Sopenharmony_ci switch (target_fb->format->cpp[0] * 8) { 13038c2ecf20Sopenharmony_ci case 8: 13048c2ecf20Sopenharmony_ci index = 10; 13058c2ecf20Sopenharmony_ci break; 13068c2ecf20Sopenharmony_ci case 16: 13078c2ecf20Sopenharmony_ci index = SI_TILE_MODE_COLOR_2D_SCANOUT_16BPP; 13088c2ecf20Sopenharmony_ci break; 13098c2ecf20Sopenharmony_ci default: 13108c2ecf20Sopenharmony_ci case 32: 13118c2ecf20Sopenharmony_ci index = SI_TILE_MODE_COLOR_2D_SCANOUT_32BPP; 13128c2ecf20Sopenharmony_ci break; 13138c2ecf20Sopenharmony_ci } 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci num_banks = (rdev->config.si.tile_mode_array[index] >> 20) & 0x3; 13168c2ecf20Sopenharmony_ci } 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci fb_format |= EVERGREEN_GRPH_NUM_BANKS(num_banks); 13198c2ecf20Sopenharmony_ci } else { 13208c2ecf20Sopenharmony_ci /* NI and older. */ 13218c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_CAYMAN) 13228c2ecf20Sopenharmony_ci tmp = rdev->config.cayman.tile_config; 13238c2ecf20Sopenharmony_ci else 13248c2ecf20Sopenharmony_ci tmp = rdev->config.evergreen.tile_config; 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci switch ((tmp & 0xf0) >> 4) { 13278c2ecf20Sopenharmony_ci case 0: /* 4 banks */ 13288c2ecf20Sopenharmony_ci fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_4_BANK); 13298c2ecf20Sopenharmony_ci break; 13308c2ecf20Sopenharmony_ci case 1: /* 8 banks */ 13318c2ecf20Sopenharmony_ci default: 13328c2ecf20Sopenharmony_ci fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_8_BANK); 13338c2ecf20Sopenharmony_ci break; 13348c2ecf20Sopenharmony_ci case 2: /* 16 banks */ 13358c2ecf20Sopenharmony_ci fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_16_BANK); 13368c2ecf20Sopenharmony_ci break; 13378c2ecf20Sopenharmony_ci } 13388c2ecf20Sopenharmony_ci } 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1); 13418c2ecf20Sopenharmony_ci fb_format |= EVERGREEN_GRPH_TILE_SPLIT(tile_split); 13428c2ecf20Sopenharmony_ci fb_format |= EVERGREEN_GRPH_BANK_WIDTH(bankw); 13438c2ecf20Sopenharmony_ci fb_format |= EVERGREEN_GRPH_BANK_HEIGHT(bankh); 13448c2ecf20Sopenharmony_ci fb_format |= EVERGREEN_GRPH_MACRO_TILE_ASPECT(mtaspect); 13458c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_BONAIRE) { 13468c2ecf20Sopenharmony_ci /* XXX need to know more about the surface tiling mode */ 13478c2ecf20Sopenharmony_ci fb_format |= CIK_GRPH_MICRO_TILE_MODE(CIK_DISPLAY_MICRO_TILING); 13488c2ecf20Sopenharmony_ci } 13498c2ecf20Sopenharmony_ci } else if (tiling_flags & RADEON_TILING_MICRO) 13508c2ecf20Sopenharmony_ci fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1); 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_BONAIRE) { 13538c2ecf20Sopenharmony_ci /* Read the pipe config from the 2D TILED SCANOUT mode. 13548c2ecf20Sopenharmony_ci * It should be the same for the other modes too, but not all 13558c2ecf20Sopenharmony_ci * modes set the pipe config field. */ 13568c2ecf20Sopenharmony_ci u32 pipe_config = (rdev->config.cik.tile_mode_array[10] >> 6) & 0x1f; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci fb_format |= CIK_GRPH_PIPE_CONFIG(pipe_config); 13598c2ecf20Sopenharmony_ci } else if ((rdev->family == CHIP_TAHITI) || 13608c2ecf20Sopenharmony_ci (rdev->family == CHIP_PITCAIRN)) 13618c2ecf20Sopenharmony_ci fb_format |= SI_GRPH_PIPE_CONFIG(SI_ADDR_SURF_P8_32x32_8x16); 13628c2ecf20Sopenharmony_ci else if ((rdev->family == CHIP_VERDE) || 13638c2ecf20Sopenharmony_ci (rdev->family == CHIP_OLAND) || 13648c2ecf20Sopenharmony_ci (rdev->family == CHIP_HAINAN)) /* for completeness. HAINAN has no display hw */ 13658c2ecf20Sopenharmony_ci fb_format |= SI_GRPH_PIPE_CONFIG(SI_ADDR_SURF_P4_8x16); 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci switch (radeon_crtc->crtc_id) { 13688c2ecf20Sopenharmony_ci case 0: 13698c2ecf20Sopenharmony_ci WREG32(AVIVO_D1VGA_CONTROL, 0); 13708c2ecf20Sopenharmony_ci break; 13718c2ecf20Sopenharmony_ci case 1: 13728c2ecf20Sopenharmony_ci WREG32(AVIVO_D2VGA_CONTROL, 0); 13738c2ecf20Sopenharmony_ci break; 13748c2ecf20Sopenharmony_ci case 2: 13758c2ecf20Sopenharmony_ci WREG32(EVERGREEN_D3VGA_CONTROL, 0); 13768c2ecf20Sopenharmony_ci break; 13778c2ecf20Sopenharmony_ci case 3: 13788c2ecf20Sopenharmony_ci WREG32(EVERGREEN_D4VGA_CONTROL, 0); 13798c2ecf20Sopenharmony_ci break; 13808c2ecf20Sopenharmony_ci case 4: 13818c2ecf20Sopenharmony_ci WREG32(EVERGREEN_D5VGA_CONTROL, 0); 13828c2ecf20Sopenharmony_ci break; 13838c2ecf20Sopenharmony_ci case 5: 13848c2ecf20Sopenharmony_ci WREG32(EVERGREEN_D6VGA_CONTROL, 0); 13858c2ecf20Sopenharmony_ci break; 13868c2ecf20Sopenharmony_ci default: 13878c2ecf20Sopenharmony_ci break; 13888c2ecf20Sopenharmony_ci } 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci /* Make sure surface address is updated at vertical blank rather than 13918c2ecf20Sopenharmony_ci * horizontal blank 13928c2ecf20Sopenharmony_ci */ 13938c2ecf20Sopenharmony_ci WREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, 0); 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 13968c2ecf20Sopenharmony_ci upper_32_bits(fb_location)); 13978c2ecf20Sopenharmony_ci WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 13988c2ecf20Sopenharmony_ci upper_32_bits(fb_location)); 13998c2ecf20Sopenharmony_ci WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 14008c2ecf20Sopenharmony_ci (u32)fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK); 14018c2ecf20Sopenharmony_ci WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 14028c2ecf20Sopenharmony_ci (u32) fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK); 14038c2ecf20Sopenharmony_ci WREG32(EVERGREEN_GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); 14048c2ecf20Sopenharmony_ci WREG32(EVERGREEN_GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap); 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci /* 14078c2ecf20Sopenharmony_ci * The LUT only has 256 slots for indexing by a 8 bpc fb. Bypass the LUT 14088c2ecf20Sopenharmony_ci * for > 8 bpc scanout to avoid truncation of fb indices to 8 msb's, to 14098c2ecf20Sopenharmony_ci * retain the full precision throughout the pipeline. 14108c2ecf20Sopenharmony_ci */ 14118c2ecf20Sopenharmony_ci WREG32_P(EVERGREEN_GRPH_LUT_10BIT_BYPASS_CONTROL + radeon_crtc->crtc_offset, 14128c2ecf20Sopenharmony_ci (bypass_lut ? EVERGREEN_LUT_10BIT_BYPASS_EN : 0), 14138c2ecf20Sopenharmony_ci ~EVERGREEN_LUT_10BIT_BYPASS_EN); 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci if (bypass_lut) 14168c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("Bypassing hardware LUT due to 10 bit fb scanout.\n"); 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); 14198c2ecf20Sopenharmony_ci WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); 14208c2ecf20Sopenharmony_ci WREG32(EVERGREEN_GRPH_X_START + radeon_crtc->crtc_offset, 0); 14218c2ecf20Sopenharmony_ci WREG32(EVERGREEN_GRPH_Y_START + radeon_crtc->crtc_offset, 0); 14228c2ecf20Sopenharmony_ci WREG32(EVERGREEN_GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width); 14238c2ecf20Sopenharmony_ci WREG32(EVERGREEN_GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height); 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci fb_pitch_pixels = target_fb->pitches[0] / target_fb->format->cpp[0]; 14268c2ecf20Sopenharmony_ci WREG32(EVERGREEN_GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); 14278c2ecf20Sopenharmony_ci WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1); 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_BONAIRE) 14308c2ecf20Sopenharmony_ci WREG32(CIK_LB_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, 14318c2ecf20Sopenharmony_ci target_fb->height); 14328c2ecf20Sopenharmony_ci else 14338c2ecf20Sopenharmony_ci WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, 14348c2ecf20Sopenharmony_ci target_fb->height); 14358c2ecf20Sopenharmony_ci x &= ~3; 14368c2ecf20Sopenharmony_ci y &= ~1; 14378c2ecf20Sopenharmony_ci WREG32(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset, 14388c2ecf20Sopenharmony_ci (x << 16) | y); 14398c2ecf20Sopenharmony_ci viewport_w = crtc->mode.hdisplay; 14408c2ecf20Sopenharmony_ci viewport_h = (crtc->mode.vdisplay + 1) & ~1; 14418c2ecf20Sopenharmony_ci if ((rdev->family >= CHIP_BONAIRE) && 14428c2ecf20Sopenharmony_ci (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)) 14438c2ecf20Sopenharmony_ci viewport_h *= 2; 14448c2ecf20Sopenharmony_ci WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset, 14458c2ecf20Sopenharmony_ci (viewport_w << 16) | viewport_h); 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci /* set pageflip to happen anywhere in vblank interval */ 14488c2ecf20Sopenharmony_ci WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci if (!atomic && fb && fb != crtc->primary->fb) { 14518c2ecf20Sopenharmony_ci rbo = gem_to_radeon_bo(fb->obj[0]); 14528c2ecf20Sopenharmony_ci r = radeon_bo_reserve(rbo, false); 14538c2ecf20Sopenharmony_ci if (unlikely(r != 0)) 14548c2ecf20Sopenharmony_ci return r; 14558c2ecf20Sopenharmony_ci radeon_bo_unpin(rbo); 14568c2ecf20Sopenharmony_ci radeon_bo_unreserve(rbo); 14578c2ecf20Sopenharmony_ci } 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci /* Bytes per pixel may have changed */ 14608c2ecf20Sopenharmony_ci radeon_bandwidth_update(rdev); 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci return 0; 14638c2ecf20Sopenharmony_ci} 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_cistatic int avivo_crtc_do_set_base(struct drm_crtc *crtc, 14668c2ecf20Sopenharmony_ci struct drm_framebuffer *fb, 14678c2ecf20Sopenharmony_ci int x, int y, int atomic) 14688c2ecf20Sopenharmony_ci{ 14698c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 14708c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 14718c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 14728c2ecf20Sopenharmony_ci struct drm_gem_object *obj; 14738c2ecf20Sopenharmony_ci struct radeon_bo *rbo; 14748c2ecf20Sopenharmony_ci struct drm_framebuffer *target_fb; 14758c2ecf20Sopenharmony_ci uint64_t fb_location; 14768c2ecf20Sopenharmony_ci uint32_t fb_format, fb_pitch_pixels, tiling_flags; 14778c2ecf20Sopenharmony_ci u32 fb_swap = R600_D1GRPH_SWAP_ENDIAN_NONE; 14788c2ecf20Sopenharmony_ci u32 viewport_w, viewport_h; 14798c2ecf20Sopenharmony_ci int r; 14808c2ecf20Sopenharmony_ci bool bypass_lut = false; 14818c2ecf20Sopenharmony_ci struct drm_format_name_buf format_name; 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci /* no fb bound */ 14848c2ecf20Sopenharmony_ci if (!atomic && !crtc->primary->fb) { 14858c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("No FB bound\n"); 14868c2ecf20Sopenharmony_ci return 0; 14878c2ecf20Sopenharmony_ci } 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci if (atomic) 14908c2ecf20Sopenharmony_ci target_fb = fb; 14918c2ecf20Sopenharmony_ci else 14928c2ecf20Sopenharmony_ci target_fb = crtc->primary->fb; 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci obj = target_fb->obj[0]; 14958c2ecf20Sopenharmony_ci rbo = gem_to_radeon_bo(obj); 14968c2ecf20Sopenharmony_ci r = radeon_bo_reserve(rbo, false); 14978c2ecf20Sopenharmony_ci if (unlikely(r != 0)) 14988c2ecf20Sopenharmony_ci return r; 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci /* If atomic, assume fb object is pinned & idle & fenced and 15018c2ecf20Sopenharmony_ci * just update base pointers 15028c2ecf20Sopenharmony_ci */ 15038c2ecf20Sopenharmony_ci if (atomic) 15048c2ecf20Sopenharmony_ci fb_location = radeon_bo_gpu_offset(rbo); 15058c2ecf20Sopenharmony_ci else { 15068c2ecf20Sopenharmony_ci r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location); 15078c2ecf20Sopenharmony_ci if (unlikely(r != 0)) { 15088c2ecf20Sopenharmony_ci radeon_bo_unreserve(rbo); 15098c2ecf20Sopenharmony_ci return -EINVAL; 15108c2ecf20Sopenharmony_ci } 15118c2ecf20Sopenharmony_ci } 15128c2ecf20Sopenharmony_ci radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); 15138c2ecf20Sopenharmony_ci radeon_bo_unreserve(rbo); 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci switch (target_fb->format->format) { 15168c2ecf20Sopenharmony_ci case DRM_FORMAT_C8: 15178c2ecf20Sopenharmony_ci fb_format = 15188c2ecf20Sopenharmony_ci AVIVO_D1GRPH_CONTROL_DEPTH_8BPP | 15198c2ecf20Sopenharmony_ci AVIVO_D1GRPH_CONTROL_8BPP_INDEXED; 15208c2ecf20Sopenharmony_ci break; 15218c2ecf20Sopenharmony_ci case DRM_FORMAT_XRGB4444: 15228c2ecf20Sopenharmony_ci case DRM_FORMAT_ARGB4444: 15238c2ecf20Sopenharmony_ci fb_format = 15248c2ecf20Sopenharmony_ci AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | 15258c2ecf20Sopenharmony_ci AVIVO_D1GRPH_CONTROL_16BPP_ARGB4444; 15268c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 15278c2ecf20Sopenharmony_ci fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT; 15288c2ecf20Sopenharmony_ci#endif 15298c2ecf20Sopenharmony_ci break; 15308c2ecf20Sopenharmony_ci case DRM_FORMAT_XRGB1555: 15318c2ecf20Sopenharmony_ci fb_format = 15328c2ecf20Sopenharmony_ci AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | 15338c2ecf20Sopenharmony_ci AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555; 15348c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 15358c2ecf20Sopenharmony_ci fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT; 15368c2ecf20Sopenharmony_ci#endif 15378c2ecf20Sopenharmony_ci break; 15388c2ecf20Sopenharmony_ci case DRM_FORMAT_RGB565: 15398c2ecf20Sopenharmony_ci fb_format = 15408c2ecf20Sopenharmony_ci AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | 15418c2ecf20Sopenharmony_ci AVIVO_D1GRPH_CONTROL_16BPP_RGB565; 15428c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 15438c2ecf20Sopenharmony_ci fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT; 15448c2ecf20Sopenharmony_ci#endif 15458c2ecf20Sopenharmony_ci break; 15468c2ecf20Sopenharmony_ci case DRM_FORMAT_XRGB8888: 15478c2ecf20Sopenharmony_ci case DRM_FORMAT_ARGB8888: 15488c2ecf20Sopenharmony_ci fb_format = 15498c2ecf20Sopenharmony_ci AVIVO_D1GRPH_CONTROL_DEPTH_32BPP | 15508c2ecf20Sopenharmony_ci AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888; 15518c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 15528c2ecf20Sopenharmony_ci fb_swap = R600_D1GRPH_SWAP_ENDIAN_32BIT; 15538c2ecf20Sopenharmony_ci#endif 15548c2ecf20Sopenharmony_ci break; 15558c2ecf20Sopenharmony_ci case DRM_FORMAT_XRGB2101010: 15568c2ecf20Sopenharmony_ci case DRM_FORMAT_ARGB2101010: 15578c2ecf20Sopenharmony_ci fb_format = 15588c2ecf20Sopenharmony_ci AVIVO_D1GRPH_CONTROL_DEPTH_32BPP | 15598c2ecf20Sopenharmony_ci AVIVO_D1GRPH_CONTROL_32BPP_ARGB2101010; 15608c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 15618c2ecf20Sopenharmony_ci fb_swap = R600_D1GRPH_SWAP_ENDIAN_32BIT; 15628c2ecf20Sopenharmony_ci#endif 15638c2ecf20Sopenharmony_ci /* Greater 8 bpc fb needs to bypass hw-lut to retain precision */ 15648c2ecf20Sopenharmony_ci bypass_lut = true; 15658c2ecf20Sopenharmony_ci break; 15668c2ecf20Sopenharmony_ci case DRM_FORMAT_XBGR8888: 15678c2ecf20Sopenharmony_ci case DRM_FORMAT_ABGR8888: 15688c2ecf20Sopenharmony_ci fb_format = 15698c2ecf20Sopenharmony_ci AVIVO_D1GRPH_CONTROL_DEPTH_32BPP | 15708c2ecf20Sopenharmony_ci AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888; 15718c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_R600) 15728c2ecf20Sopenharmony_ci fb_swap = 15738c2ecf20Sopenharmony_ci (R600_D1GRPH_RED_CROSSBAR(R600_D1GRPH_RED_SEL_B) | 15748c2ecf20Sopenharmony_ci R600_D1GRPH_BLUE_CROSSBAR(R600_D1GRPH_BLUE_SEL_R)); 15758c2ecf20Sopenharmony_ci else /* DCE1 (R5xx) */ 15768c2ecf20Sopenharmony_ci fb_format |= AVIVO_D1GRPH_SWAP_RB; 15778c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 15788c2ecf20Sopenharmony_ci fb_swap |= R600_D1GRPH_SWAP_ENDIAN_32BIT; 15798c2ecf20Sopenharmony_ci#endif 15808c2ecf20Sopenharmony_ci break; 15818c2ecf20Sopenharmony_ci default: 15828c2ecf20Sopenharmony_ci DRM_ERROR("Unsupported screen format %s\n", 15838c2ecf20Sopenharmony_ci drm_get_format_name(target_fb->format->format, &format_name)); 15848c2ecf20Sopenharmony_ci return -EINVAL; 15858c2ecf20Sopenharmony_ci } 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_R600) { 15888c2ecf20Sopenharmony_ci if (tiling_flags & RADEON_TILING_MACRO) 15898c2ecf20Sopenharmony_ci fb_format |= R600_D1GRPH_ARRAY_MODE_2D_TILED_THIN1; 15908c2ecf20Sopenharmony_ci else if (tiling_flags & RADEON_TILING_MICRO) 15918c2ecf20Sopenharmony_ci fb_format |= R600_D1GRPH_ARRAY_MODE_1D_TILED_THIN1; 15928c2ecf20Sopenharmony_ci } else { 15938c2ecf20Sopenharmony_ci if (tiling_flags & RADEON_TILING_MACRO) 15948c2ecf20Sopenharmony_ci fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE; 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci if (tiling_flags & RADEON_TILING_MICRO) 15978c2ecf20Sopenharmony_ci fb_format |= AVIVO_D1GRPH_TILED; 15988c2ecf20Sopenharmony_ci } 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci if (radeon_crtc->crtc_id == 0) 16018c2ecf20Sopenharmony_ci WREG32(AVIVO_D1VGA_CONTROL, 0); 16028c2ecf20Sopenharmony_ci else 16038c2ecf20Sopenharmony_ci WREG32(AVIVO_D2VGA_CONTROL, 0); 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci /* Make sure surface address is update at vertical blank rather than 16068c2ecf20Sopenharmony_ci * horizontal blank 16078c2ecf20Sopenharmony_ci */ 16088c2ecf20Sopenharmony_ci WREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, 0); 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_RV770) { 16118c2ecf20Sopenharmony_ci if (radeon_crtc->crtc_id) { 16128c2ecf20Sopenharmony_ci WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 16138c2ecf20Sopenharmony_ci WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 16148c2ecf20Sopenharmony_ci } else { 16158c2ecf20Sopenharmony_ci WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 16168c2ecf20Sopenharmony_ci WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); 16178c2ecf20Sopenharmony_ci } 16188c2ecf20Sopenharmony_ci } 16198c2ecf20Sopenharmony_ci WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 16208c2ecf20Sopenharmony_ci (u32) fb_location); 16218c2ecf20Sopenharmony_ci WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + 16228c2ecf20Sopenharmony_ci radeon_crtc->crtc_offset, (u32) fb_location); 16238c2ecf20Sopenharmony_ci WREG32(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); 16248c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_R600) 16258c2ecf20Sopenharmony_ci WREG32(R600_D1GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap); 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci /* LUT only has 256 slots for 8 bpc fb. Bypass for > 8 bpc scanout for precision */ 16288c2ecf20Sopenharmony_ci WREG32_P(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, 16298c2ecf20Sopenharmony_ci (bypass_lut ? AVIVO_LUT_10BIT_BYPASS_EN : 0), ~AVIVO_LUT_10BIT_BYPASS_EN); 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci if (bypass_lut) 16328c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("Bypassing hardware LUT due to 10 bit fb scanout.\n"); 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); 16358c2ecf20Sopenharmony_ci WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); 16368c2ecf20Sopenharmony_ci WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0); 16378c2ecf20Sopenharmony_ci WREG32(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, 0); 16388c2ecf20Sopenharmony_ci WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width); 16398c2ecf20Sopenharmony_ci WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height); 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci fb_pitch_pixels = target_fb->pitches[0] / target_fb->format->cpp[0]; 16428c2ecf20Sopenharmony_ci WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); 16438c2ecf20Sopenharmony_ci WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1); 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, 16468c2ecf20Sopenharmony_ci target_fb->height); 16478c2ecf20Sopenharmony_ci x &= ~3; 16488c2ecf20Sopenharmony_ci y &= ~1; 16498c2ecf20Sopenharmony_ci WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset, 16508c2ecf20Sopenharmony_ci (x << 16) | y); 16518c2ecf20Sopenharmony_ci viewport_w = crtc->mode.hdisplay; 16528c2ecf20Sopenharmony_ci viewport_h = (crtc->mode.vdisplay + 1) & ~1; 16538c2ecf20Sopenharmony_ci WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset, 16548c2ecf20Sopenharmony_ci (viewport_w << 16) | viewport_h); 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci /* set pageflip to happen only at start of vblank interval (front porch) */ 16578c2ecf20Sopenharmony_ci WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 3); 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci if (!atomic && fb && fb != crtc->primary->fb) { 16608c2ecf20Sopenharmony_ci rbo = gem_to_radeon_bo(fb->obj[0]); 16618c2ecf20Sopenharmony_ci r = radeon_bo_reserve(rbo, false); 16628c2ecf20Sopenharmony_ci if (unlikely(r != 0)) 16638c2ecf20Sopenharmony_ci return r; 16648c2ecf20Sopenharmony_ci radeon_bo_unpin(rbo); 16658c2ecf20Sopenharmony_ci radeon_bo_unreserve(rbo); 16668c2ecf20Sopenharmony_ci } 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci /* Bytes per pixel may have changed */ 16698c2ecf20Sopenharmony_ci radeon_bandwidth_update(rdev); 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci return 0; 16728c2ecf20Sopenharmony_ci} 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ciint atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, 16758c2ecf20Sopenharmony_ci struct drm_framebuffer *old_fb) 16768c2ecf20Sopenharmony_ci{ 16778c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 16788c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) 16818c2ecf20Sopenharmony_ci return dce4_crtc_do_set_base(crtc, old_fb, x, y, 0); 16828c2ecf20Sopenharmony_ci else if (ASIC_IS_AVIVO(rdev)) 16838c2ecf20Sopenharmony_ci return avivo_crtc_do_set_base(crtc, old_fb, x, y, 0); 16848c2ecf20Sopenharmony_ci else 16858c2ecf20Sopenharmony_ci return radeon_crtc_do_set_base(crtc, old_fb, x, y, 0); 16868c2ecf20Sopenharmony_ci} 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_ciint atombios_crtc_set_base_atomic(struct drm_crtc *crtc, 16898c2ecf20Sopenharmony_ci struct drm_framebuffer *fb, 16908c2ecf20Sopenharmony_ci int x, int y, enum mode_set_atomic state) 16918c2ecf20Sopenharmony_ci{ 16928c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 16938c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) 16968c2ecf20Sopenharmony_ci return dce4_crtc_do_set_base(crtc, fb, x, y, 1); 16978c2ecf20Sopenharmony_ci else if (ASIC_IS_AVIVO(rdev)) 16988c2ecf20Sopenharmony_ci return avivo_crtc_do_set_base(crtc, fb, x, y, 1); 16998c2ecf20Sopenharmony_ci else 17008c2ecf20Sopenharmony_ci return radeon_crtc_do_set_base(crtc, fb, x, y, 1); 17018c2ecf20Sopenharmony_ci} 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci/* properly set additional regs when using atombios */ 17048c2ecf20Sopenharmony_cistatic void radeon_legacy_atom_fixup(struct drm_crtc *crtc) 17058c2ecf20Sopenharmony_ci{ 17068c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 17078c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 17088c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 17098c2ecf20Sopenharmony_ci u32 disp_merge_cntl; 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci switch (radeon_crtc->crtc_id) { 17128c2ecf20Sopenharmony_ci case 0: 17138c2ecf20Sopenharmony_ci disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL); 17148c2ecf20Sopenharmony_ci disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; 17158c2ecf20Sopenharmony_ci WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl); 17168c2ecf20Sopenharmony_ci break; 17178c2ecf20Sopenharmony_ci case 1: 17188c2ecf20Sopenharmony_ci disp_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL); 17198c2ecf20Sopenharmony_ci disp_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN; 17208c2ecf20Sopenharmony_ci WREG32(RADEON_DISP2_MERGE_CNTL, disp_merge_cntl); 17218c2ecf20Sopenharmony_ci WREG32(RADEON_FP_H2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_H_SYNC_STRT_WID)); 17228c2ecf20Sopenharmony_ci WREG32(RADEON_FP_V2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_V_SYNC_STRT_WID)); 17238c2ecf20Sopenharmony_ci break; 17248c2ecf20Sopenharmony_ci } 17258c2ecf20Sopenharmony_ci} 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci/** 17288c2ecf20Sopenharmony_ci * radeon_get_pll_use_mask - look up a mask of which pplls are in use 17298c2ecf20Sopenharmony_ci * 17308c2ecf20Sopenharmony_ci * @crtc: drm crtc 17318c2ecf20Sopenharmony_ci * 17328c2ecf20Sopenharmony_ci * Returns the mask of which PPLLs (Pixel PLLs) are in use. 17338c2ecf20Sopenharmony_ci */ 17348c2ecf20Sopenharmony_cistatic u32 radeon_get_pll_use_mask(struct drm_crtc *crtc) 17358c2ecf20Sopenharmony_ci{ 17368c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 17378c2ecf20Sopenharmony_ci struct drm_crtc *test_crtc; 17388c2ecf20Sopenharmony_ci struct radeon_crtc *test_radeon_crtc; 17398c2ecf20Sopenharmony_ci u32 pll_in_use = 0; 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { 17428c2ecf20Sopenharmony_ci if (crtc == test_crtc) 17438c2ecf20Sopenharmony_ci continue; 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci test_radeon_crtc = to_radeon_crtc(test_crtc); 17468c2ecf20Sopenharmony_ci if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID) 17478c2ecf20Sopenharmony_ci pll_in_use |= (1 << test_radeon_crtc->pll_id); 17488c2ecf20Sopenharmony_ci } 17498c2ecf20Sopenharmony_ci return pll_in_use; 17508c2ecf20Sopenharmony_ci} 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci/** 17538c2ecf20Sopenharmony_ci * radeon_get_shared_dp_ppll - return the PPLL used by another crtc for DP 17548c2ecf20Sopenharmony_ci * 17558c2ecf20Sopenharmony_ci * @crtc: drm crtc 17568c2ecf20Sopenharmony_ci * 17578c2ecf20Sopenharmony_ci * Returns the PPLL (Pixel PLL) used by another crtc/encoder which is 17588c2ecf20Sopenharmony_ci * also in DP mode. For DP, a single PPLL can be used for all DP 17598c2ecf20Sopenharmony_ci * crtcs/encoders. 17608c2ecf20Sopenharmony_ci */ 17618c2ecf20Sopenharmony_cistatic int radeon_get_shared_dp_ppll(struct drm_crtc *crtc) 17628c2ecf20Sopenharmony_ci{ 17638c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 17648c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 17658c2ecf20Sopenharmony_ci struct drm_crtc *test_crtc; 17668c2ecf20Sopenharmony_ci struct radeon_crtc *test_radeon_crtc; 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { 17698c2ecf20Sopenharmony_ci if (crtc == test_crtc) 17708c2ecf20Sopenharmony_ci continue; 17718c2ecf20Sopenharmony_ci test_radeon_crtc = to_radeon_crtc(test_crtc); 17728c2ecf20Sopenharmony_ci if (test_radeon_crtc->encoder && 17738c2ecf20Sopenharmony_ci ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_radeon_crtc->encoder))) { 17748c2ecf20Sopenharmony_ci /* PPLL2 is exclusive to UNIPHYA on DCE61 */ 17758c2ecf20Sopenharmony_ci if (ASIC_IS_DCE61(rdev) && !ASIC_IS_DCE8(rdev) && 17768c2ecf20Sopenharmony_ci test_radeon_crtc->pll_id == ATOM_PPLL2) 17778c2ecf20Sopenharmony_ci continue; 17788c2ecf20Sopenharmony_ci /* for DP use the same PLL for all */ 17798c2ecf20Sopenharmony_ci if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID) 17808c2ecf20Sopenharmony_ci return test_radeon_crtc->pll_id; 17818c2ecf20Sopenharmony_ci } 17828c2ecf20Sopenharmony_ci } 17838c2ecf20Sopenharmony_ci return ATOM_PPLL_INVALID; 17848c2ecf20Sopenharmony_ci} 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci/** 17878c2ecf20Sopenharmony_ci * radeon_get_shared_nondp_ppll - return the PPLL used by another non-DP crtc 17888c2ecf20Sopenharmony_ci * 17898c2ecf20Sopenharmony_ci * @crtc: drm crtc 17908c2ecf20Sopenharmony_ci * @encoder: drm encoder 17918c2ecf20Sopenharmony_ci * 17928c2ecf20Sopenharmony_ci * Returns the PPLL (Pixel PLL) used by another non-DP crtc/encoder which can 17938c2ecf20Sopenharmony_ci * be shared (i.e., same clock). 17948c2ecf20Sopenharmony_ci */ 17958c2ecf20Sopenharmony_cistatic int radeon_get_shared_nondp_ppll(struct drm_crtc *crtc) 17968c2ecf20Sopenharmony_ci{ 17978c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 17988c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 17998c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 18008c2ecf20Sopenharmony_ci struct drm_crtc *test_crtc; 18018c2ecf20Sopenharmony_ci struct radeon_crtc *test_radeon_crtc; 18028c2ecf20Sopenharmony_ci u32 adjusted_clock, test_adjusted_clock; 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci adjusted_clock = radeon_crtc->adjusted_clock; 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci if (adjusted_clock == 0) 18078c2ecf20Sopenharmony_ci return ATOM_PPLL_INVALID; 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { 18108c2ecf20Sopenharmony_ci if (crtc == test_crtc) 18118c2ecf20Sopenharmony_ci continue; 18128c2ecf20Sopenharmony_ci test_radeon_crtc = to_radeon_crtc(test_crtc); 18138c2ecf20Sopenharmony_ci if (test_radeon_crtc->encoder && 18148c2ecf20Sopenharmony_ci !ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_radeon_crtc->encoder))) { 18158c2ecf20Sopenharmony_ci /* PPLL2 is exclusive to UNIPHYA on DCE61 */ 18168c2ecf20Sopenharmony_ci if (ASIC_IS_DCE61(rdev) && !ASIC_IS_DCE8(rdev) && 18178c2ecf20Sopenharmony_ci test_radeon_crtc->pll_id == ATOM_PPLL2) 18188c2ecf20Sopenharmony_ci continue; 18198c2ecf20Sopenharmony_ci /* check if we are already driving this connector with another crtc */ 18208c2ecf20Sopenharmony_ci if (test_radeon_crtc->connector == radeon_crtc->connector) { 18218c2ecf20Sopenharmony_ci /* if we are, return that pll */ 18228c2ecf20Sopenharmony_ci if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID) 18238c2ecf20Sopenharmony_ci return test_radeon_crtc->pll_id; 18248c2ecf20Sopenharmony_ci } 18258c2ecf20Sopenharmony_ci /* for non-DP check the clock */ 18268c2ecf20Sopenharmony_ci test_adjusted_clock = test_radeon_crtc->adjusted_clock; 18278c2ecf20Sopenharmony_ci if ((crtc->mode.clock == test_crtc->mode.clock) && 18288c2ecf20Sopenharmony_ci (adjusted_clock == test_adjusted_clock) && 18298c2ecf20Sopenharmony_ci (radeon_crtc->ss_enabled == test_radeon_crtc->ss_enabled) && 18308c2ecf20Sopenharmony_ci (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID)) 18318c2ecf20Sopenharmony_ci return test_radeon_crtc->pll_id; 18328c2ecf20Sopenharmony_ci } 18338c2ecf20Sopenharmony_ci } 18348c2ecf20Sopenharmony_ci return ATOM_PPLL_INVALID; 18358c2ecf20Sopenharmony_ci} 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci/** 18388c2ecf20Sopenharmony_ci * radeon_atom_pick_pll - Allocate a PPLL for use by the crtc. 18398c2ecf20Sopenharmony_ci * 18408c2ecf20Sopenharmony_ci * @crtc: drm crtc 18418c2ecf20Sopenharmony_ci * 18428c2ecf20Sopenharmony_ci * Returns the PPLL (Pixel PLL) to be used by the crtc. For DP monitors 18438c2ecf20Sopenharmony_ci * a single PPLL can be used for all DP crtcs/encoders. For non-DP 18448c2ecf20Sopenharmony_ci * monitors a dedicated PPLL must be used. If a particular board has 18458c2ecf20Sopenharmony_ci * an external DP PLL, return ATOM_PPLL_INVALID to skip PLL programming 18468c2ecf20Sopenharmony_ci * as there is no need to program the PLL itself. If we are not able to 18478c2ecf20Sopenharmony_ci * allocate a PLL, return ATOM_PPLL_INVALID to skip PLL programming to 18488c2ecf20Sopenharmony_ci * avoid messing up an existing monitor. 18498c2ecf20Sopenharmony_ci * 18508c2ecf20Sopenharmony_ci * Asic specific PLL information 18518c2ecf20Sopenharmony_ci * 18528c2ecf20Sopenharmony_ci * DCE 8.x 18538c2ecf20Sopenharmony_ci * KB/KV 18548c2ecf20Sopenharmony_ci * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) 18558c2ecf20Sopenharmony_ci * CI 18568c2ecf20Sopenharmony_ci * - PPLL0, PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC 18578c2ecf20Sopenharmony_ci * 18588c2ecf20Sopenharmony_ci * DCE 6.1 18598c2ecf20Sopenharmony_ci * - PPLL2 is only available to UNIPHYA (both DP and non-DP) 18608c2ecf20Sopenharmony_ci * - PPLL0, PPLL1 are available for UNIPHYB/C/D/E/F (both DP and non-DP) 18618c2ecf20Sopenharmony_ci * 18628c2ecf20Sopenharmony_ci * DCE 6.0 18638c2ecf20Sopenharmony_ci * - PPLL0 is available to all UNIPHY (DP only) 18648c2ecf20Sopenharmony_ci * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC 18658c2ecf20Sopenharmony_ci * 18668c2ecf20Sopenharmony_ci * DCE 5.0 18678c2ecf20Sopenharmony_ci * - DCPLL is available to all UNIPHY (DP only) 18688c2ecf20Sopenharmony_ci * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC 18698c2ecf20Sopenharmony_ci * 18708c2ecf20Sopenharmony_ci * DCE 3.0/4.0/4.1 18718c2ecf20Sopenharmony_ci * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC 18728c2ecf20Sopenharmony_ci * 18738c2ecf20Sopenharmony_ci */ 18748c2ecf20Sopenharmony_cistatic int radeon_atom_pick_pll(struct drm_crtc *crtc) 18758c2ecf20Sopenharmony_ci{ 18768c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 18778c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 18788c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 18798c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = 18808c2ecf20Sopenharmony_ci to_radeon_encoder(radeon_crtc->encoder); 18818c2ecf20Sopenharmony_ci u32 pll_in_use; 18828c2ecf20Sopenharmony_ci int pll; 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci if (ASIC_IS_DCE8(rdev)) { 18858c2ecf20Sopenharmony_ci if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { 18868c2ecf20Sopenharmony_ci if (rdev->clock.dp_extclk) 18878c2ecf20Sopenharmony_ci /* skip PPLL programming if using ext clock */ 18888c2ecf20Sopenharmony_ci return ATOM_PPLL_INVALID; 18898c2ecf20Sopenharmony_ci else { 18908c2ecf20Sopenharmony_ci /* use the same PPLL for all DP monitors */ 18918c2ecf20Sopenharmony_ci pll = radeon_get_shared_dp_ppll(crtc); 18928c2ecf20Sopenharmony_ci if (pll != ATOM_PPLL_INVALID) 18938c2ecf20Sopenharmony_ci return pll; 18948c2ecf20Sopenharmony_ci } 18958c2ecf20Sopenharmony_ci } else { 18968c2ecf20Sopenharmony_ci /* use the same PPLL for all monitors with the same clock */ 18978c2ecf20Sopenharmony_ci pll = radeon_get_shared_nondp_ppll(crtc); 18988c2ecf20Sopenharmony_ci if (pll != ATOM_PPLL_INVALID) 18998c2ecf20Sopenharmony_ci return pll; 19008c2ecf20Sopenharmony_ci } 19018c2ecf20Sopenharmony_ci /* otherwise, pick one of the plls */ 19028c2ecf20Sopenharmony_ci if ((rdev->family == CHIP_KABINI) || 19038c2ecf20Sopenharmony_ci (rdev->family == CHIP_MULLINS)) { 19048c2ecf20Sopenharmony_ci /* KB/ML has PPLL1 and PPLL2 */ 19058c2ecf20Sopenharmony_ci pll_in_use = radeon_get_pll_use_mask(crtc); 19068c2ecf20Sopenharmony_ci if (!(pll_in_use & (1 << ATOM_PPLL2))) 19078c2ecf20Sopenharmony_ci return ATOM_PPLL2; 19088c2ecf20Sopenharmony_ci if (!(pll_in_use & (1 << ATOM_PPLL1))) 19098c2ecf20Sopenharmony_ci return ATOM_PPLL1; 19108c2ecf20Sopenharmony_ci DRM_ERROR("unable to allocate a PPLL\n"); 19118c2ecf20Sopenharmony_ci return ATOM_PPLL_INVALID; 19128c2ecf20Sopenharmony_ci } else { 19138c2ecf20Sopenharmony_ci /* CI/KV has PPLL0, PPLL1, and PPLL2 */ 19148c2ecf20Sopenharmony_ci pll_in_use = radeon_get_pll_use_mask(crtc); 19158c2ecf20Sopenharmony_ci if (!(pll_in_use & (1 << ATOM_PPLL2))) 19168c2ecf20Sopenharmony_ci return ATOM_PPLL2; 19178c2ecf20Sopenharmony_ci if (!(pll_in_use & (1 << ATOM_PPLL1))) 19188c2ecf20Sopenharmony_ci return ATOM_PPLL1; 19198c2ecf20Sopenharmony_ci if (!(pll_in_use & (1 << ATOM_PPLL0))) 19208c2ecf20Sopenharmony_ci return ATOM_PPLL0; 19218c2ecf20Sopenharmony_ci DRM_ERROR("unable to allocate a PPLL\n"); 19228c2ecf20Sopenharmony_ci return ATOM_PPLL_INVALID; 19238c2ecf20Sopenharmony_ci } 19248c2ecf20Sopenharmony_ci } else if (ASIC_IS_DCE61(rdev)) { 19258c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dig *dig = 19268c2ecf20Sopenharmony_ci radeon_encoder->enc_priv; 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY) && 19298c2ecf20Sopenharmony_ci (dig->linkb == false)) 19308c2ecf20Sopenharmony_ci /* UNIPHY A uses PPLL2 */ 19318c2ecf20Sopenharmony_ci return ATOM_PPLL2; 19328c2ecf20Sopenharmony_ci else if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { 19338c2ecf20Sopenharmony_ci /* UNIPHY B/C/D/E/F */ 19348c2ecf20Sopenharmony_ci if (rdev->clock.dp_extclk) 19358c2ecf20Sopenharmony_ci /* skip PPLL programming if using ext clock */ 19368c2ecf20Sopenharmony_ci return ATOM_PPLL_INVALID; 19378c2ecf20Sopenharmony_ci else { 19388c2ecf20Sopenharmony_ci /* use the same PPLL for all DP monitors */ 19398c2ecf20Sopenharmony_ci pll = radeon_get_shared_dp_ppll(crtc); 19408c2ecf20Sopenharmony_ci if (pll != ATOM_PPLL_INVALID) 19418c2ecf20Sopenharmony_ci return pll; 19428c2ecf20Sopenharmony_ci } 19438c2ecf20Sopenharmony_ci } else { 19448c2ecf20Sopenharmony_ci /* use the same PPLL for all monitors with the same clock */ 19458c2ecf20Sopenharmony_ci pll = radeon_get_shared_nondp_ppll(crtc); 19468c2ecf20Sopenharmony_ci if (pll != ATOM_PPLL_INVALID) 19478c2ecf20Sopenharmony_ci return pll; 19488c2ecf20Sopenharmony_ci } 19498c2ecf20Sopenharmony_ci /* UNIPHY B/C/D/E/F */ 19508c2ecf20Sopenharmony_ci pll_in_use = radeon_get_pll_use_mask(crtc); 19518c2ecf20Sopenharmony_ci if (!(pll_in_use & (1 << ATOM_PPLL0))) 19528c2ecf20Sopenharmony_ci return ATOM_PPLL0; 19538c2ecf20Sopenharmony_ci if (!(pll_in_use & (1 << ATOM_PPLL1))) 19548c2ecf20Sopenharmony_ci return ATOM_PPLL1; 19558c2ecf20Sopenharmony_ci DRM_ERROR("unable to allocate a PPLL\n"); 19568c2ecf20Sopenharmony_ci return ATOM_PPLL_INVALID; 19578c2ecf20Sopenharmony_ci } else if (ASIC_IS_DCE41(rdev)) { 19588c2ecf20Sopenharmony_ci /* Don't share PLLs on DCE4.1 chips */ 19598c2ecf20Sopenharmony_ci if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { 19608c2ecf20Sopenharmony_ci if (rdev->clock.dp_extclk) 19618c2ecf20Sopenharmony_ci /* skip PPLL programming if using ext clock */ 19628c2ecf20Sopenharmony_ci return ATOM_PPLL_INVALID; 19638c2ecf20Sopenharmony_ci } 19648c2ecf20Sopenharmony_ci pll_in_use = radeon_get_pll_use_mask(crtc); 19658c2ecf20Sopenharmony_ci if (!(pll_in_use & (1 << ATOM_PPLL1))) 19668c2ecf20Sopenharmony_ci return ATOM_PPLL1; 19678c2ecf20Sopenharmony_ci if (!(pll_in_use & (1 << ATOM_PPLL2))) 19688c2ecf20Sopenharmony_ci return ATOM_PPLL2; 19698c2ecf20Sopenharmony_ci DRM_ERROR("unable to allocate a PPLL\n"); 19708c2ecf20Sopenharmony_ci return ATOM_PPLL_INVALID; 19718c2ecf20Sopenharmony_ci } else if (ASIC_IS_DCE4(rdev)) { 19728c2ecf20Sopenharmony_ci /* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock, 19738c2ecf20Sopenharmony_ci * depending on the asic: 19748c2ecf20Sopenharmony_ci * DCE4: PPLL or ext clock 19758c2ecf20Sopenharmony_ci * DCE5: PPLL, DCPLL, or ext clock 19768c2ecf20Sopenharmony_ci * DCE6: PPLL, PPLL0, or ext clock 19778c2ecf20Sopenharmony_ci * 19788c2ecf20Sopenharmony_ci * Setting ATOM_PPLL_INVALID will cause SetPixelClock to skip 19798c2ecf20Sopenharmony_ci * PPLL/DCPLL programming and only program the DP DTO for the 19808c2ecf20Sopenharmony_ci * crtc virtual pixel clock. 19818c2ecf20Sopenharmony_ci */ 19828c2ecf20Sopenharmony_ci if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { 19838c2ecf20Sopenharmony_ci if (rdev->clock.dp_extclk) 19848c2ecf20Sopenharmony_ci /* skip PPLL programming if using ext clock */ 19858c2ecf20Sopenharmony_ci return ATOM_PPLL_INVALID; 19868c2ecf20Sopenharmony_ci else if (ASIC_IS_DCE6(rdev)) 19878c2ecf20Sopenharmony_ci /* use PPLL0 for all DP */ 19888c2ecf20Sopenharmony_ci return ATOM_PPLL0; 19898c2ecf20Sopenharmony_ci else if (ASIC_IS_DCE5(rdev)) 19908c2ecf20Sopenharmony_ci /* use DCPLL for all DP */ 19918c2ecf20Sopenharmony_ci return ATOM_DCPLL; 19928c2ecf20Sopenharmony_ci else { 19938c2ecf20Sopenharmony_ci /* use the same PPLL for all DP monitors */ 19948c2ecf20Sopenharmony_ci pll = radeon_get_shared_dp_ppll(crtc); 19958c2ecf20Sopenharmony_ci if (pll != ATOM_PPLL_INVALID) 19968c2ecf20Sopenharmony_ci return pll; 19978c2ecf20Sopenharmony_ci } 19988c2ecf20Sopenharmony_ci } else { 19998c2ecf20Sopenharmony_ci /* use the same PPLL for all monitors with the same clock */ 20008c2ecf20Sopenharmony_ci pll = radeon_get_shared_nondp_ppll(crtc); 20018c2ecf20Sopenharmony_ci if (pll != ATOM_PPLL_INVALID) 20028c2ecf20Sopenharmony_ci return pll; 20038c2ecf20Sopenharmony_ci } 20048c2ecf20Sopenharmony_ci /* all other cases */ 20058c2ecf20Sopenharmony_ci pll_in_use = radeon_get_pll_use_mask(crtc); 20068c2ecf20Sopenharmony_ci if (!(pll_in_use & (1 << ATOM_PPLL1))) 20078c2ecf20Sopenharmony_ci return ATOM_PPLL1; 20088c2ecf20Sopenharmony_ci if (!(pll_in_use & (1 << ATOM_PPLL2))) 20098c2ecf20Sopenharmony_ci return ATOM_PPLL2; 20108c2ecf20Sopenharmony_ci DRM_ERROR("unable to allocate a PPLL\n"); 20118c2ecf20Sopenharmony_ci return ATOM_PPLL_INVALID; 20128c2ecf20Sopenharmony_ci } else { 20138c2ecf20Sopenharmony_ci /* on pre-R5xx asics, the crtc to pll mapping is hardcoded */ 20148c2ecf20Sopenharmony_ci /* some atombios (observed in some DCE2/DCE3) code have a bug, 20158c2ecf20Sopenharmony_ci * the matching btw pll and crtc is done through 20168c2ecf20Sopenharmony_ci * PCLK_CRTC[1|2]_CNTL (0x480/0x484) but atombios code use the 20178c2ecf20Sopenharmony_ci * pll (1 or 2) to select which register to write. ie if using 20188c2ecf20Sopenharmony_ci * pll1 it will use PCLK_CRTC1_CNTL (0x480) and if using pll2 20198c2ecf20Sopenharmony_ci * it will use PCLK_CRTC2_CNTL (0x484), it then use crtc id to 20208c2ecf20Sopenharmony_ci * choose which value to write. Which is reverse order from 20218c2ecf20Sopenharmony_ci * register logic. So only case that works is when pllid is 20228c2ecf20Sopenharmony_ci * same as crtcid or when both pll and crtc are enabled and 20238c2ecf20Sopenharmony_ci * both use same clock. 20248c2ecf20Sopenharmony_ci * 20258c2ecf20Sopenharmony_ci * So just return crtc id as if crtc and pll were hard linked 20268c2ecf20Sopenharmony_ci * together even if they aren't 20278c2ecf20Sopenharmony_ci */ 20288c2ecf20Sopenharmony_ci return radeon_crtc->crtc_id; 20298c2ecf20Sopenharmony_ci } 20308c2ecf20Sopenharmony_ci} 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_civoid radeon_atom_disp_eng_pll_init(struct radeon_device *rdev) 20338c2ecf20Sopenharmony_ci{ 20348c2ecf20Sopenharmony_ci /* always set DCPLL */ 20358c2ecf20Sopenharmony_ci if (ASIC_IS_DCE6(rdev)) 20368c2ecf20Sopenharmony_ci atombios_crtc_set_disp_eng_pll(rdev, rdev->clock.default_dispclk); 20378c2ecf20Sopenharmony_ci else if (ASIC_IS_DCE4(rdev)) { 20388c2ecf20Sopenharmony_ci struct radeon_atom_ss ss; 20398c2ecf20Sopenharmony_ci bool ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &ss, 20408c2ecf20Sopenharmony_ci ASIC_INTERNAL_SS_ON_DCPLL, 20418c2ecf20Sopenharmony_ci rdev->clock.default_dispclk); 20428c2ecf20Sopenharmony_ci if (ss_enabled) 20438c2ecf20Sopenharmony_ci atombios_crtc_program_ss(rdev, ATOM_DISABLE, ATOM_DCPLL, -1, &ss); 20448c2ecf20Sopenharmony_ci /* XXX: DCE5, make sure voltage, dispclk is high enough */ 20458c2ecf20Sopenharmony_ci atombios_crtc_set_disp_eng_pll(rdev, rdev->clock.default_dispclk); 20468c2ecf20Sopenharmony_ci if (ss_enabled) 20478c2ecf20Sopenharmony_ci atombios_crtc_program_ss(rdev, ATOM_ENABLE, ATOM_DCPLL, -1, &ss); 20488c2ecf20Sopenharmony_ci } 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci} 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ciint atombios_crtc_mode_set(struct drm_crtc *crtc, 20538c2ecf20Sopenharmony_ci struct drm_display_mode *mode, 20548c2ecf20Sopenharmony_ci struct drm_display_mode *adjusted_mode, 20558c2ecf20Sopenharmony_ci int x, int y, struct drm_framebuffer *old_fb) 20568c2ecf20Sopenharmony_ci{ 20578c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 20588c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 20598c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 20608c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = 20618c2ecf20Sopenharmony_ci to_radeon_encoder(radeon_crtc->encoder); 20628c2ecf20Sopenharmony_ci bool is_tvcv = false; 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_ci if (radeon_encoder->active_device & 20658c2ecf20Sopenharmony_ci (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) 20668c2ecf20Sopenharmony_ci is_tvcv = true; 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_ci if (!radeon_crtc->adjusted_clock) 20698c2ecf20Sopenharmony_ci return -EINVAL; 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci atombios_crtc_set_pll(crtc, adjusted_mode); 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) 20748c2ecf20Sopenharmony_ci atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 20758c2ecf20Sopenharmony_ci else if (ASIC_IS_AVIVO(rdev)) { 20768c2ecf20Sopenharmony_ci if (is_tvcv) 20778c2ecf20Sopenharmony_ci atombios_crtc_set_timing(crtc, adjusted_mode); 20788c2ecf20Sopenharmony_ci else 20798c2ecf20Sopenharmony_ci atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 20808c2ecf20Sopenharmony_ci } else { 20818c2ecf20Sopenharmony_ci atombios_crtc_set_timing(crtc, adjusted_mode); 20828c2ecf20Sopenharmony_ci if (radeon_crtc->crtc_id == 0) 20838c2ecf20Sopenharmony_ci atombios_set_crtc_dtd_timing(crtc, adjusted_mode); 20848c2ecf20Sopenharmony_ci radeon_legacy_atom_fixup(crtc); 20858c2ecf20Sopenharmony_ci } 20868c2ecf20Sopenharmony_ci atombios_crtc_set_base(crtc, x, y, old_fb); 20878c2ecf20Sopenharmony_ci atombios_overscan_setup(crtc, mode, adjusted_mode); 20888c2ecf20Sopenharmony_ci atombios_scaler_setup(crtc); 20898c2ecf20Sopenharmony_ci radeon_cursor_reset(crtc); 20908c2ecf20Sopenharmony_ci /* update the hw version fpr dpm */ 20918c2ecf20Sopenharmony_ci radeon_crtc->hw_mode = *adjusted_mode; 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_ci return 0; 20948c2ecf20Sopenharmony_ci} 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_cistatic bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, 20978c2ecf20Sopenharmony_ci const struct drm_display_mode *mode, 20988c2ecf20Sopenharmony_ci struct drm_display_mode *adjusted_mode) 20998c2ecf20Sopenharmony_ci{ 21008c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 21018c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 21028c2ecf20Sopenharmony_ci struct drm_encoder *encoder; 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_ci /* assign the encoder to the radeon crtc to avoid repeated lookups later */ 21058c2ecf20Sopenharmony_ci list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 21068c2ecf20Sopenharmony_ci if (encoder->crtc == crtc) { 21078c2ecf20Sopenharmony_ci radeon_crtc->encoder = encoder; 21088c2ecf20Sopenharmony_ci radeon_crtc->connector = radeon_get_connector_for_encoder(encoder); 21098c2ecf20Sopenharmony_ci break; 21108c2ecf20Sopenharmony_ci } 21118c2ecf20Sopenharmony_ci } 21128c2ecf20Sopenharmony_ci if ((radeon_crtc->encoder == NULL) || (radeon_crtc->connector == NULL)) { 21138c2ecf20Sopenharmony_ci radeon_crtc->encoder = NULL; 21148c2ecf20Sopenharmony_ci radeon_crtc->connector = NULL; 21158c2ecf20Sopenharmony_ci return false; 21168c2ecf20Sopenharmony_ci } 21178c2ecf20Sopenharmony_ci if (radeon_crtc->encoder) { 21188c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = 21198c2ecf20Sopenharmony_ci to_radeon_encoder(radeon_crtc->encoder); 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci radeon_crtc->output_csc = radeon_encoder->output_csc; 21228c2ecf20Sopenharmony_ci } 21238c2ecf20Sopenharmony_ci if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) 21248c2ecf20Sopenharmony_ci return false; 21258c2ecf20Sopenharmony_ci if (!atombios_crtc_prepare_pll(crtc, adjusted_mode)) 21268c2ecf20Sopenharmony_ci return false; 21278c2ecf20Sopenharmony_ci /* pick pll */ 21288c2ecf20Sopenharmony_ci radeon_crtc->pll_id = radeon_atom_pick_pll(crtc); 21298c2ecf20Sopenharmony_ci /* if we can't get a PPLL for a non-DP encoder, fail */ 21308c2ecf20Sopenharmony_ci if ((radeon_crtc->pll_id == ATOM_PPLL_INVALID) && 21318c2ecf20Sopenharmony_ci !ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) 21328c2ecf20Sopenharmony_ci return false; 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci return true; 21358c2ecf20Sopenharmony_ci} 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_cistatic void atombios_crtc_prepare(struct drm_crtc *crtc) 21388c2ecf20Sopenharmony_ci{ 21398c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 21408c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_ci /* disable crtc pair power gating before programming */ 21438c2ecf20Sopenharmony_ci if (ASIC_IS_DCE6(rdev)) 21448c2ecf20Sopenharmony_ci atombios_powergate_crtc(crtc, ATOM_DISABLE); 21458c2ecf20Sopenharmony_ci 21468c2ecf20Sopenharmony_ci atombios_lock_crtc(crtc, ATOM_ENABLE); 21478c2ecf20Sopenharmony_ci atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 21488c2ecf20Sopenharmony_ci} 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_cistatic void atombios_crtc_commit(struct drm_crtc *crtc) 21518c2ecf20Sopenharmony_ci{ 21528c2ecf20Sopenharmony_ci atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON); 21538c2ecf20Sopenharmony_ci atombios_lock_crtc(crtc, ATOM_DISABLE); 21548c2ecf20Sopenharmony_ci} 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_cistatic void atombios_crtc_disable(struct drm_crtc *crtc) 21578c2ecf20Sopenharmony_ci{ 21588c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 21598c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 21608c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 21618c2ecf20Sopenharmony_ci struct radeon_atom_ss ss; 21628c2ecf20Sopenharmony_ci int i; 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 21658c2ecf20Sopenharmony_ci if (crtc->primary->fb) { 21668c2ecf20Sopenharmony_ci int r; 21678c2ecf20Sopenharmony_ci struct radeon_bo *rbo; 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci rbo = gem_to_radeon_bo(crtc->primary->fb->obj[0]); 21708c2ecf20Sopenharmony_ci r = radeon_bo_reserve(rbo, false); 21718c2ecf20Sopenharmony_ci if (unlikely(r)) 21728c2ecf20Sopenharmony_ci DRM_ERROR("failed to reserve rbo before unpin\n"); 21738c2ecf20Sopenharmony_ci else { 21748c2ecf20Sopenharmony_ci radeon_bo_unpin(rbo); 21758c2ecf20Sopenharmony_ci radeon_bo_unreserve(rbo); 21768c2ecf20Sopenharmony_ci } 21778c2ecf20Sopenharmony_ci } 21788c2ecf20Sopenharmony_ci /* disable the GRPH */ 21798c2ecf20Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) 21808c2ecf20Sopenharmony_ci WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 0); 21818c2ecf20Sopenharmony_ci else if (ASIC_IS_AVIVO(rdev)) 21828c2ecf20Sopenharmony_ci WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 0); 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci if (ASIC_IS_DCE6(rdev)) 21858c2ecf20Sopenharmony_ci atombios_powergate_crtc(crtc, ATOM_ENABLE); 21868c2ecf20Sopenharmony_ci 21878c2ecf20Sopenharmony_ci for (i = 0; i < rdev->num_crtc; i++) { 21888c2ecf20Sopenharmony_ci if (rdev->mode_info.crtcs[i] && 21898c2ecf20Sopenharmony_ci rdev->mode_info.crtcs[i]->enabled && 21908c2ecf20Sopenharmony_ci i != radeon_crtc->crtc_id && 21918c2ecf20Sopenharmony_ci radeon_crtc->pll_id == rdev->mode_info.crtcs[i]->pll_id) { 21928c2ecf20Sopenharmony_ci /* one other crtc is using this pll don't turn 21938c2ecf20Sopenharmony_ci * off the pll 21948c2ecf20Sopenharmony_ci */ 21958c2ecf20Sopenharmony_ci goto done; 21968c2ecf20Sopenharmony_ci } 21978c2ecf20Sopenharmony_ci } 21988c2ecf20Sopenharmony_ci 21998c2ecf20Sopenharmony_ci switch (radeon_crtc->pll_id) { 22008c2ecf20Sopenharmony_ci case ATOM_PPLL1: 22018c2ecf20Sopenharmony_ci case ATOM_PPLL2: 22028c2ecf20Sopenharmony_ci /* disable the ppll */ 22038c2ecf20Sopenharmony_ci atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, 22048c2ecf20Sopenharmony_ci 0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss); 22058c2ecf20Sopenharmony_ci break; 22068c2ecf20Sopenharmony_ci case ATOM_PPLL0: 22078c2ecf20Sopenharmony_ci /* disable the ppll */ 22088c2ecf20Sopenharmony_ci if ((rdev->family == CHIP_ARUBA) || 22098c2ecf20Sopenharmony_ci (rdev->family == CHIP_KAVERI) || 22108c2ecf20Sopenharmony_ci (rdev->family == CHIP_BONAIRE) || 22118c2ecf20Sopenharmony_ci (rdev->family == CHIP_HAWAII)) 22128c2ecf20Sopenharmony_ci atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, 22138c2ecf20Sopenharmony_ci 0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss); 22148c2ecf20Sopenharmony_ci break; 22158c2ecf20Sopenharmony_ci default: 22168c2ecf20Sopenharmony_ci break; 22178c2ecf20Sopenharmony_ci } 22188c2ecf20Sopenharmony_cidone: 22198c2ecf20Sopenharmony_ci radeon_crtc->pll_id = ATOM_PPLL_INVALID; 22208c2ecf20Sopenharmony_ci radeon_crtc->adjusted_clock = 0; 22218c2ecf20Sopenharmony_ci radeon_crtc->encoder = NULL; 22228c2ecf20Sopenharmony_ci radeon_crtc->connector = NULL; 22238c2ecf20Sopenharmony_ci} 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_cistatic const struct drm_crtc_helper_funcs atombios_helper_funcs = { 22268c2ecf20Sopenharmony_ci .dpms = atombios_crtc_dpms, 22278c2ecf20Sopenharmony_ci .mode_fixup = atombios_crtc_mode_fixup, 22288c2ecf20Sopenharmony_ci .mode_set = atombios_crtc_mode_set, 22298c2ecf20Sopenharmony_ci .mode_set_base = atombios_crtc_set_base, 22308c2ecf20Sopenharmony_ci .mode_set_base_atomic = atombios_crtc_set_base_atomic, 22318c2ecf20Sopenharmony_ci .prepare = atombios_crtc_prepare, 22328c2ecf20Sopenharmony_ci .commit = atombios_crtc_commit, 22338c2ecf20Sopenharmony_ci .disable = atombios_crtc_disable, 22348c2ecf20Sopenharmony_ci .get_scanout_position = radeon_get_crtc_scanout_position, 22358c2ecf20Sopenharmony_ci}; 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_civoid radeon_atombios_init_crtc(struct drm_device *dev, 22388c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc) 22398c2ecf20Sopenharmony_ci{ 22408c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) { 22438c2ecf20Sopenharmony_ci switch (radeon_crtc->crtc_id) { 22448c2ecf20Sopenharmony_ci case 0: 22458c2ecf20Sopenharmony_ci default: 22468c2ecf20Sopenharmony_ci radeon_crtc->crtc_offset = EVERGREEN_CRTC0_REGISTER_OFFSET; 22478c2ecf20Sopenharmony_ci break; 22488c2ecf20Sopenharmony_ci case 1: 22498c2ecf20Sopenharmony_ci radeon_crtc->crtc_offset = EVERGREEN_CRTC1_REGISTER_OFFSET; 22508c2ecf20Sopenharmony_ci break; 22518c2ecf20Sopenharmony_ci case 2: 22528c2ecf20Sopenharmony_ci radeon_crtc->crtc_offset = EVERGREEN_CRTC2_REGISTER_OFFSET; 22538c2ecf20Sopenharmony_ci break; 22548c2ecf20Sopenharmony_ci case 3: 22558c2ecf20Sopenharmony_ci radeon_crtc->crtc_offset = EVERGREEN_CRTC3_REGISTER_OFFSET; 22568c2ecf20Sopenharmony_ci break; 22578c2ecf20Sopenharmony_ci case 4: 22588c2ecf20Sopenharmony_ci radeon_crtc->crtc_offset = EVERGREEN_CRTC4_REGISTER_OFFSET; 22598c2ecf20Sopenharmony_ci break; 22608c2ecf20Sopenharmony_ci case 5: 22618c2ecf20Sopenharmony_ci radeon_crtc->crtc_offset = EVERGREEN_CRTC5_REGISTER_OFFSET; 22628c2ecf20Sopenharmony_ci break; 22638c2ecf20Sopenharmony_ci } 22648c2ecf20Sopenharmony_ci } else { 22658c2ecf20Sopenharmony_ci if (radeon_crtc->crtc_id == 1) 22668c2ecf20Sopenharmony_ci radeon_crtc->crtc_offset = 22678c2ecf20Sopenharmony_ci AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL; 22688c2ecf20Sopenharmony_ci else 22698c2ecf20Sopenharmony_ci radeon_crtc->crtc_offset = 0; 22708c2ecf20Sopenharmony_ci } 22718c2ecf20Sopenharmony_ci radeon_crtc->pll_id = ATOM_PPLL_INVALID; 22728c2ecf20Sopenharmony_ci radeon_crtc->adjusted_clock = 0; 22738c2ecf20Sopenharmony_ci radeon_crtc->encoder = NULL; 22748c2ecf20Sopenharmony_ci radeon_crtc->connector = NULL; 22758c2ecf20Sopenharmony_ci drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); 22768c2ecf20Sopenharmony_ci} 2277