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