162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright 2007-8 Advanced Micro Devices, Inc.
362306a36Sopenharmony_ci * Copyright 2008 Red Hat Inc.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
662306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
762306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation
862306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
962306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
1062306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
1362306a36Sopenharmony_ci * all copies or substantial portions of the Software.
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1662306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1762306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1862306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1962306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2062306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2162306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * Authors: Dave Airlie
2462306a36Sopenharmony_ci *          Alex Deucher
2562306a36Sopenharmony_ci */
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include <drm/drm_fixed.h>
2862306a36Sopenharmony_ci#include <drm/drm_fourcc.h>
2962306a36Sopenharmony_ci#include <drm/drm_framebuffer.h>
3062306a36Sopenharmony_ci#include <drm/drm_modeset_helper_vtables.h>
3162306a36Sopenharmony_ci#include <drm/drm_vblank.h>
3262306a36Sopenharmony_ci#include <drm/radeon_drm.h>
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#include "radeon.h"
3562306a36Sopenharmony_ci#include "atom.h"
3662306a36Sopenharmony_ci#include "atom-bits.h"
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic void atombios_overscan_setup(struct drm_crtc *crtc,
3962306a36Sopenharmony_ci				    struct drm_display_mode *mode,
4062306a36Sopenharmony_ci				    struct drm_display_mode *adjusted_mode)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
4362306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
4462306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
4562306a36Sopenharmony_ci	SET_CRTC_OVERSCAN_PS_ALLOCATION args;
4662306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan);
4762306a36Sopenharmony_ci	int a1, a2;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	memset(&args, 0, sizeof(args));
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	args.ucCRTC = radeon_crtc->crtc_id;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	switch (radeon_crtc->rmx_type) {
5462306a36Sopenharmony_ci	case RMX_CENTER:
5562306a36Sopenharmony_ci		args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2);
5662306a36Sopenharmony_ci		args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2);
5762306a36Sopenharmony_ci		args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2);
5862306a36Sopenharmony_ci		args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2);
5962306a36Sopenharmony_ci		break;
6062306a36Sopenharmony_ci	case RMX_ASPECT:
6162306a36Sopenharmony_ci		a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay;
6262306a36Sopenharmony_ci		a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci		if (a1 > a2) {
6562306a36Sopenharmony_ci			args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2);
6662306a36Sopenharmony_ci			args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2);
6762306a36Sopenharmony_ci		} else if (a2 > a1) {
6862306a36Sopenharmony_ci			args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2);
6962306a36Sopenharmony_ci			args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2);
7062306a36Sopenharmony_ci		}
7162306a36Sopenharmony_ci		break;
7262306a36Sopenharmony_ci	case RMX_FULL:
7362306a36Sopenharmony_ci	default:
7462306a36Sopenharmony_ci		args.usOverscanRight = cpu_to_le16(radeon_crtc->h_border);
7562306a36Sopenharmony_ci		args.usOverscanLeft = cpu_to_le16(radeon_crtc->h_border);
7662306a36Sopenharmony_ci		args.usOverscanBottom = cpu_to_le16(radeon_crtc->v_border);
7762306a36Sopenharmony_ci		args.usOverscanTop = cpu_to_le16(radeon_crtc->v_border);
7862306a36Sopenharmony_ci		break;
7962306a36Sopenharmony_ci	}
8062306a36Sopenharmony_ci	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic void atombios_scaler_setup(struct drm_crtc *crtc)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
8662306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
8762306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
8862306a36Sopenharmony_ci	ENABLE_SCALER_PS_ALLOCATION args;
8962306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(COMMAND, EnableScaler);
9062306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder =
9162306a36Sopenharmony_ci		to_radeon_encoder(radeon_crtc->encoder);
9262306a36Sopenharmony_ci	/* fixme - fill in enc_priv for atom dac */
9362306a36Sopenharmony_ci	enum radeon_tv_std tv_std = TV_STD_NTSC;
9462306a36Sopenharmony_ci	bool is_tv = false, is_cv = false;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	if (!ASIC_IS_AVIVO(rdev) && radeon_crtc->crtc_id)
9762306a36Sopenharmony_ci		return;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) {
10062306a36Sopenharmony_ci		struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv;
10162306a36Sopenharmony_ci		tv_std = tv_dac->tv_std;
10262306a36Sopenharmony_ci		is_tv = true;
10362306a36Sopenharmony_ci	}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	memset(&args, 0, sizeof(args));
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	args.ucScaler = radeon_crtc->crtc_id;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	if (is_tv) {
11062306a36Sopenharmony_ci		switch (tv_std) {
11162306a36Sopenharmony_ci		case TV_STD_NTSC:
11262306a36Sopenharmony_ci		default:
11362306a36Sopenharmony_ci			args.ucTVStandard = ATOM_TV_NTSC;
11462306a36Sopenharmony_ci			break;
11562306a36Sopenharmony_ci		case TV_STD_PAL:
11662306a36Sopenharmony_ci			args.ucTVStandard = ATOM_TV_PAL;
11762306a36Sopenharmony_ci			break;
11862306a36Sopenharmony_ci		case TV_STD_PAL_M:
11962306a36Sopenharmony_ci			args.ucTVStandard = ATOM_TV_PALM;
12062306a36Sopenharmony_ci			break;
12162306a36Sopenharmony_ci		case TV_STD_PAL_60:
12262306a36Sopenharmony_ci			args.ucTVStandard = ATOM_TV_PAL60;
12362306a36Sopenharmony_ci			break;
12462306a36Sopenharmony_ci		case TV_STD_NTSC_J:
12562306a36Sopenharmony_ci			args.ucTVStandard = ATOM_TV_NTSCJ;
12662306a36Sopenharmony_ci			break;
12762306a36Sopenharmony_ci		case TV_STD_SCART_PAL:
12862306a36Sopenharmony_ci			args.ucTVStandard = ATOM_TV_PAL; /* ??? */
12962306a36Sopenharmony_ci			break;
13062306a36Sopenharmony_ci		case TV_STD_SECAM:
13162306a36Sopenharmony_ci			args.ucTVStandard = ATOM_TV_SECAM;
13262306a36Sopenharmony_ci			break;
13362306a36Sopenharmony_ci		case TV_STD_PAL_CN:
13462306a36Sopenharmony_ci			args.ucTVStandard = ATOM_TV_PALCN;
13562306a36Sopenharmony_ci			break;
13662306a36Sopenharmony_ci		}
13762306a36Sopenharmony_ci		args.ucEnable = SCALER_ENABLE_MULTITAP_MODE;
13862306a36Sopenharmony_ci	} else if (is_cv) {
13962306a36Sopenharmony_ci		args.ucTVStandard = ATOM_TV_CV;
14062306a36Sopenharmony_ci		args.ucEnable = SCALER_ENABLE_MULTITAP_MODE;
14162306a36Sopenharmony_ci	} else {
14262306a36Sopenharmony_ci		switch (radeon_crtc->rmx_type) {
14362306a36Sopenharmony_ci		case RMX_FULL:
14462306a36Sopenharmony_ci			args.ucEnable = ATOM_SCALER_EXPANSION;
14562306a36Sopenharmony_ci			break;
14662306a36Sopenharmony_ci		case RMX_CENTER:
14762306a36Sopenharmony_ci			args.ucEnable = ATOM_SCALER_CENTER;
14862306a36Sopenharmony_ci			break;
14962306a36Sopenharmony_ci		case RMX_ASPECT:
15062306a36Sopenharmony_ci			args.ucEnable = ATOM_SCALER_EXPANSION;
15162306a36Sopenharmony_ci			break;
15262306a36Sopenharmony_ci		default:
15362306a36Sopenharmony_ci			if (ASIC_IS_AVIVO(rdev))
15462306a36Sopenharmony_ci				args.ucEnable = ATOM_SCALER_DISABLE;
15562306a36Sopenharmony_ci			else
15662306a36Sopenharmony_ci				args.ucEnable = ATOM_SCALER_CENTER;
15762306a36Sopenharmony_ci			break;
15862306a36Sopenharmony_ci		}
15962306a36Sopenharmony_ci	}
16062306a36Sopenharmony_ci	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
16162306a36Sopenharmony_ci	if ((is_tv || is_cv)
16262306a36Sopenharmony_ci	    && rdev->family >= CHIP_RV515 && rdev->family <= CHIP_R580) {
16362306a36Sopenharmony_ci		atom_rv515_force_tv_scaler(rdev, radeon_crtc);
16462306a36Sopenharmony_ci	}
16562306a36Sopenharmony_ci}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cistatic void atombios_lock_crtc(struct drm_crtc *crtc, int lock)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
17062306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
17162306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
17262306a36Sopenharmony_ci	int index =
17362306a36Sopenharmony_ci	    GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters);
17462306a36Sopenharmony_ci	ENABLE_CRTC_PS_ALLOCATION args;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	memset(&args, 0, sizeof(args));
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	args.ucCRTC = radeon_crtc->crtc_id;
17962306a36Sopenharmony_ci	args.ucEnable = lock;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic void atombios_enable_crtc(struct drm_crtc *crtc, int state)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
18762306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
18862306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
18962306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC);
19062306a36Sopenharmony_ci	ENABLE_CRTC_PS_ALLOCATION args;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	memset(&args, 0, sizeof(args));
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	args.ucCRTC = radeon_crtc->crtc_id;
19562306a36Sopenharmony_ci	args.ucEnable = state;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic void atombios_enable_crtc_memreq(struct drm_crtc *crtc, int state)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
20362306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
20462306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
20562306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(COMMAND, EnableCRTCMemReq);
20662306a36Sopenharmony_ci	ENABLE_CRTC_PS_ALLOCATION args;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	memset(&args, 0, sizeof(args));
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	args.ucCRTC = radeon_crtc->crtc_id;
21162306a36Sopenharmony_ci	args.ucEnable = state;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic const u32 vga_control_regs[6] =
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	AVIVO_D1VGA_CONTROL,
21962306a36Sopenharmony_ci	AVIVO_D2VGA_CONTROL,
22062306a36Sopenharmony_ci	EVERGREEN_D3VGA_CONTROL,
22162306a36Sopenharmony_ci	EVERGREEN_D4VGA_CONTROL,
22262306a36Sopenharmony_ci	EVERGREEN_D5VGA_CONTROL,
22362306a36Sopenharmony_ci	EVERGREEN_D6VGA_CONTROL,
22462306a36Sopenharmony_ci};
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cistatic void atombios_blank_crtc(struct drm_crtc *crtc, int state)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
22962306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
23062306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
23162306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC);
23262306a36Sopenharmony_ci	BLANK_CRTC_PS_ALLOCATION args;
23362306a36Sopenharmony_ci	u32 vga_control = 0;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	memset(&args, 0, sizeof(args));
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	if (ASIC_IS_DCE8(rdev)) {
23862306a36Sopenharmony_ci		vga_control = RREG32(vga_control_regs[radeon_crtc->crtc_id]);
23962306a36Sopenharmony_ci		WREG32(vga_control_regs[radeon_crtc->crtc_id], vga_control | 1);
24062306a36Sopenharmony_ci	}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	args.ucCRTC = radeon_crtc->crtc_id;
24362306a36Sopenharmony_ci	args.ucBlanking = state;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	if (ASIC_IS_DCE8(rdev))
24862306a36Sopenharmony_ci		WREG32(vga_control_regs[radeon_crtc->crtc_id], vga_control);
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic void atombios_powergate_crtc(struct drm_crtc *crtc, int state)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
25462306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
25562306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
25662306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating);
25762306a36Sopenharmony_ci	ENABLE_DISP_POWER_GATING_PARAMETERS_V2_1 args;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	memset(&args, 0, sizeof(args));
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	args.ucDispPipeId = radeon_crtc->crtc_id;
26262306a36Sopenharmony_ci	args.ucEnable = state;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_civoid atombios_crtc_dpms(struct drm_crtc *crtc, int mode)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
27062306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
27162306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	switch (mode) {
27462306a36Sopenharmony_ci	case DRM_MODE_DPMS_ON:
27562306a36Sopenharmony_ci		radeon_crtc->enabled = true;
27662306a36Sopenharmony_ci		atombios_enable_crtc(crtc, ATOM_ENABLE);
27762306a36Sopenharmony_ci		if (ASIC_IS_DCE3(rdev) && !ASIC_IS_DCE6(rdev))
27862306a36Sopenharmony_ci			atombios_enable_crtc_memreq(crtc, ATOM_ENABLE);
27962306a36Sopenharmony_ci		atombios_blank_crtc(crtc, ATOM_DISABLE);
28062306a36Sopenharmony_ci		if (dev->num_crtcs > radeon_crtc->crtc_id)
28162306a36Sopenharmony_ci			drm_crtc_vblank_on(crtc);
28262306a36Sopenharmony_ci		radeon_crtc_load_lut(crtc);
28362306a36Sopenharmony_ci		break;
28462306a36Sopenharmony_ci	case DRM_MODE_DPMS_STANDBY:
28562306a36Sopenharmony_ci	case DRM_MODE_DPMS_SUSPEND:
28662306a36Sopenharmony_ci	case DRM_MODE_DPMS_OFF:
28762306a36Sopenharmony_ci		if (dev->num_crtcs > radeon_crtc->crtc_id)
28862306a36Sopenharmony_ci			drm_crtc_vblank_off(crtc);
28962306a36Sopenharmony_ci		if (radeon_crtc->enabled)
29062306a36Sopenharmony_ci			atombios_blank_crtc(crtc, ATOM_ENABLE);
29162306a36Sopenharmony_ci		if (ASIC_IS_DCE3(rdev) && !ASIC_IS_DCE6(rdev))
29262306a36Sopenharmony_ci			atombios_enable_crtc_memreq(crtc, ATOM_DISABLE);
29362306a36Sopenharmony_ci		atombios_enable_crtc(crtc, ATOM_DISABLE);
29462306a36Sopenharmony_ci		radeon_crtc->enabled = false;
29562306a36Sopenharmony_ci		break;
29662306a36Sopenharmony_ci	}
29762306a36Sopenharmony_ci	/* adjust pm to dpms */
29862306a36Sopenharmony_ci	radeon_pm_compute_clocks(rdev);
29962306a36Sopenharmony_ci}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_cistatic void
30262306a36Sopenharmony_ciatombios_set_crtc_dtd_timing(struct drm_crtc *crtc,
30362306a36Sopenharmony_ci			     struct drm_display_mode *mode)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
30662306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
30762306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
30862306a36Sopenharmony_ci	SET_CRTC_USING_DTD_TIMING_PARAMETERS args;
30962306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming);
31062306a36Sopenharmony_ci	u16 misc = 0;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	memset(&args, 0, sizeof(args));
31362306a36Sopenharmony_ci	args.usH_Size = cpu_to_le16(mode->crtc_hdisplay - (radeon_crtc->h_border * 2));
31462306a36Sopenharmony_ci	args.usH_Blanking_Time =
31562306a36Sopenharmony_ci		cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay + (radeon_crtc->h_border * 2));
31662306a36Sopenharmony_ci	args.usV_Size = cpu_to_le16(mode->crtc_vdisplay - (radeon_crtc->v_border * 2));
31762306a36Sopenharmony_ci	args.usV_Blanking_Time =
31862306a36Sopenharmony_ci		cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay + (radeon_crtc->v_border * 2));
31962306a36Sopenharmony_ci	args.usH_SyncOffset =
32062306a36Sopenharmony_ci		cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay + radeon_crtc->h_border);
32162306a36Sopenharmony_ci	args.usH_SyncWidth =
32262306a36Sopenharmony_ci		cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start);
32362306a36Sopenharmony_ci	args.usV_SyncOffset =
32462306a36Sopenharmony_ci		cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay + radeon_crtc->v_border);
32562306a36Sopenharmony_ci	args.usV_SyncWidth =
32662306a36Sopenharmony_ci		cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start);
32762306a36Sopenharmony_ci	args.ucH_Border = radeon_crtc->h_border;
32862306a36Sopenharmony_ci	args.ucV_Border = radeon_crtc->v_border;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
33162306a36Sopenharmony_ci		misc |= ATOM_VSYNC_POLARITY;
33262306a36Sopenharmony_ci	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
33362306a36Sopenharmony_ci		misc |= ATOM_HSYNC_POLARITY;
33462306a36Sopenharmony_ci	if (mode->flags & DRM_MODE_FLAG_CSYNC)
33562306a36Sopenharmony_ci		misc |= ATOM_COMPOSITESYNC;
33662306a36Sopenharmony_ci	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
33762306a36Sopenharmony_ci		misc |= ATOM_INTERLACE;
33862306a36Sopenharmony_ci	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
33962306a36Sopenharmony_ci		misc |= ATOM_DOUBLE_CLOCK_MODE;
34062306a36Sopenharmony_ci	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
34162306a36Sopenharmony_ci		misc |= ATOM_H_REPLICATIONBY2 | ATOM_V_REPLICATIONBY2;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
34462306a36Sopenharmony_ci	args.ucCRTC = radeon_crtc->crtc_id;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_cistatic void atombios_crtc_set_timing(struct drm_crtc *crtc,
35062306a36Sopenharmony_ci				     struct drm_display_mode *mode)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
35362306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
35462306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
35562306a36Sopenharmony_ci	SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION args;
35662306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing);
35762306a36Sopenharmony_ci	u16 misc = 0;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	memset(&args, 0, sizeof(args));
36062306a36Sopenharmony_ci	args.usH_Total = cpu_to_le16(mode->crtc_htotal);
36162306a36Sopenharmony_ci	args.usH_Disp = cpu_to_le16(mode->crtc_hdisplay);
36262306a36Sopenharmony_ci	args.usH_SyncStart = cpu_to_le16(mode->crtc_hsync_start);
36362306a36Sopenharmony_ci	args.usH_SyncWidth =
36462306a36Sopenharmony_ci		cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start);
36562306a36Sopenharmony_ci	args.usV_Total = cpu_to_le16(mode->crtc_vtotal);
36662306a36Sopenharmony_ci	args.usV_Disp = cpu_to_le16(mode->crtc_vdisplay);
36762306a36Sopenharmony_ci	args.usV_SyncStart = cpu_to_le16(mode->crtc_vsync_start);
36862306a36Sopenharmony_ci	args.usV_SyncWidth =
36962306a36Sopenharmony_ci		cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	args.ucOverscanRight = radeon_crtc->h_border;
37262306a36Sopenharmony_ci	args.ucOverscanLeft = radeon_crtc->h_border;
37362306a36Sopenharmony_ci	args.ucOverscanBottom = radeon_crtc->v_border;
37462306a36Sopenharmony_ci	args.ucOverscanTop = radeon_crtc->v_border;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
37762306a36Sopenharmony_ci		misc |= ATOM_VSYNC_POLARITY;
37862306a36Sopenharmony_ci	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
37962306a36Sopenharmony_ci		misc |= ATOM_HSYNC_POLARITY;
38062306a36Sopenharmony_ci	if (mode->flags & DRM_MODE_FLAG_CSYNC)
38162306a36Sopenharmony_ci		misc |= ATOM_COMPOSITESYNC;
38262306a36Sopenharmony_ci	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
38362306a36Sopenharmony_ci		misc |= ATOM_INTERLACE;
38462306a36Sopenharmony_ci	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
38562306a36Sopenharmony_ci		misc |= ATOM_DOUBLE_CLOCK_MODE;
38662306a36Sopenharmony_ci	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
38762306a36Sopenharmony_ci		misc |= ATOM_H_REPLICATIONBY2 | ATOM_V_REPLICATIONBY2;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
39062306a36Sopenharmony_ci	args.ucCRTC = radeon_crtc->crtc_id;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
39362306a36Sopenharmony_ci}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_cistatic void atombios_disable_ss(struct radeon_device *rdev, int pll_id)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	u32 ss_cntl;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	if (ASIC_IS_DCE4(rdev)) {
40062306a36Sopenharmony_ci		switch (pll_id) {
40162306a36Sopenharmony_ci		case ATOM_PPLL1:
40262306a36Sopenharmony_ci			ss_cntl = RREG32(EVERGREEN_P1PLL_SS_CNTL);
40362306a36Sopenharmony_ci			ss_cntl &= ~EVERGREEN_PxPLL_SS_EN;
40462306a36Sopenharmony_ci			WREG32(EVERGREEN_P1PLL_SS_CNTL, ss_cntl);
40562306a36Sopenharmony_ci			break;
40662306a36Sopenharmony_ci		case ATOM_PPLL2:
40762306a36Sopenharmony_ci			ss_cntl = RREG32(EVERGREEN_P2PLL_SS_CNTL);
40862306a36Sopenharmony_ci			ss_cntl &= ~EVERGREEN_PxPLL_SS_EN;
40962306a36Sopenharmony_ci			WREG32(EVERGREEN_P2PLL_SS_CNTL, ss_cntl);
41062306a36Sopenharmony_ci			break;
41162306a36Sopenharmony_ci		case ATOM_DCPLL:
41262306a36Sopenharmony_ci		case ATOM_PPLL_INVALID:
41362306a36Sopenharmony_ci			return;
41462306a36Sopenharmony_ci		}
41562306a36Sopenharmony_ci	} else if (ASIC_IS_AVIVO(rdev)) {
41662306a36Sopenharmony_ci		switch (pll_id) {
41762306a36Sopenharmony_ci		case ATOM_PPLL1:
41862306a36Sopenharmony_ci			ss_cntl = RREG32(AVIVO_P1PLL_INT_SS_CNTL);
41962306a36Sopenharmony_ci			ss_cntl &= ~1;
42062306a36Sopenharmony_ci			WREG32(AVIVO_P1PLL_INT_SS_CNTL, ss_cntl);
42162306a36Sopenharmony_ci			break;
42262306a36Sopenharmony_ci		case ATOM_PPLL2:
42362306a36Sopenharmony_ci			ss_cntl = RREG32(AVIVO_P2PLL_INT_SS_CNTL);
42462306a36Sopenharmony_ci			ss_cntl &= ~1;
42562306a36Sopenharmony_ci			WREG32(AVIVO_P2PLL_INT_SS_CNTL, ss_cntl);
42662306a36Sopenharmony_ci			break;
42762306a36Sopenharmony_ci		case ATOM_DCPLL:
42862306a36Sopenharmony_ci		case ATOM_PPLL_INVALID:
42962306a36Sopenharmony_ci			return;
43062306a36Sopenharmony_ci		}
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ciunion atom_enable_ss {
43662306a36Sopenharmony_ci	ENABLE_LVDS_SS_PARAMETERS lvds_ss;
43762306a36Sopenharmony_ci	ENABLE_LVDS_SS_PARAMETERS_V2 lvds_ss_2;
43862306a36Sopenharmony_ci	ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1;
43962306a36Sopenharmony_ci	ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 v2;
44062306a36Sopenharmony_ci	ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 v3;
44162306a36Sopenharmony_ci};
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_cistatic void atombios_crtc_program_ss(struct radeon_device *rdev,
44462306a36Sopenharmony_ci				     int enable,
44562306a36Sopenharmony_ci				     int pll_id,
44662306a36Sopenharmony_ci				     int crtc_id,
44762306a36Sopenharmony_ci				     struct radeon_atom_ss *ss)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci	unsigned i;
45062306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL);
45162306a36Sopenharmony_ci	union atom_enable_ss args;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	if (enable) {
45462306a36Sopenharmony_ci		/* Don't mess with SS if percentage is 0 or external ss.
45562306a36Sopenharmony_ci		 * SS is already disabled previously, and disabling it
45662306a36Sopenharmony_ci		 * again can cause display problems if the pll is already
45762306a36Sopenharmony_ci		 * programmed.
45862306a36Sopenharmony_ci		 */
45962306a36Sopenharmony_ci		if (ss->percentage == 0)
46062306a36Sopenharmony_ci			return;
46162306a36Sopenharmony_ci		if (ss->type & ATOM_EXTERNAL_SS_MASK)
46262306a36Sopenharmony_ci			return;
46362306a36Sopenharmony_ci	} else {
46462306a36Sopenharmony_ci		for (i = 0; i < rdev->num_crtc; i++) {
46562306a36Sopenharmony_ci			if (rdev->mode_info.crtcs[i] &&
46662306a36Sopenharmony_ci			    rdev->mode_info.crtcs[i]->enabled &&
46762306a36Sopenharmony_ci			    i != crtc_id &&
46862306a36Sopenharmony_ci			    pll_id == rdev->mode_info.crtcs[i]->pll_id) {
46962306a36Sopenharmony_ci				/* one other crtc is using this pll don't turn
47062306a36Sopenharmony_ci				 * off spread spectrum as it might turn off
47162306a36Sopenharmony_ci				 * display on active crtc
47262306a36Sopenharmony_ci				 */
47362306a36Sopenharmony_ci				return;
47462306a36Sopenharmony_ci			}
47562306a36Sopenharmony_ci		}
47662306a36Sopenharmony_ci	}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	memset(&args, 0, sizeof(args));
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	if (ASIC_IS_DCE5(rdev)) {
48162306a36Sopenharmony_ci		args.v3.usSpreadSpectrumAmountFrac = cpu_to_le16(0);
48262306a36Sopenharmony_ci		args.v3.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
48362306a36Sopenharmony_ci		switch (pll_id) {
48462306a36Sopenharmony_ci		case ATOM_PPLL1:
48562306a36Sopenharmony_ci			args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL;
48662306a36Sopenharmony_ci			break;
48762306a36Sopenharmony_ci		case ATOM_PPLL2:
48862306a36Sopenharmony_ci			args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL;
48962306a36Sopenharmony_ci			break;
49062306a36Sopenharmony_ci		case ATOM_DCPLL:
49162306a36Sopenharmony_ci			args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL;
49262306a36Sopenharmony_ci			break;
49362306a36Sopenharmony_ci		case ATOM_PPLL_INVALID:
49462306a36Sopenharmony_ci			return;
49562306a36Sopenharmony_ci		}
49662306a36Sopenharmony_ci		args.v3.usSpreadSpectrumAmount = cpu_to_le16(ss->amount);
49762306a36Sopenharmony_ci		args.v3.usSpreadSpectrumStep = cpu_to_le16(ss->step);
49862306a36Sopenharmony_ci		args.v3.ucEnable = enable;
49962306a36Sopenharmony_ci	} else if (ASIC_IS_DCE4(rdev)) {
50062306a36Sopenharmony_ci		args.v2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
50162306a36Sopenharmony_ci		args.v2.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
50262306a36Sopenharmony_ci		switch (pll_id) {
50362306a36Sopenharmony_ci		case ATOM_PPLL1:
50462306a36Sopenharmony_ci			args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P1PLL;
50562306a36Sopenharmony_ci			break;
50662306a36Sopenharmony_ci		case ATOM_PPLL2:
50762306a36Sopenharmony_ci			args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P2PLL;
50862306a36Sopenharmony_ci			break;
50962306a36Sopenharmony_ci		case ATOM_DCPLL:
51062306a36Sopenharmony_ci			args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_DCPLL;
51162306a36Sopenharmony_ci			break;
51262306a36Sopenharmony_ci		case ATOM_PPLL_INVALID:
51362306a36Sopenharmony_ci			return;
51462306a36Sopenharmony_ci		}
51562306a36Sopenharmony_ci		args.v2.usSpreadSpectrumAmount = cpu_to_le16(ss->amount);
51662306a36Sopenharmony_ci		args.v2.usSpreadSpectrumStep = cpu_to_le16(ss->step);
51762306a36Sopenharmony_ci		args.v2.ucEnable = enable;
51862306a36Sopenharmony_ci	} else if (ASIC_IS_DCE3(rdev)) {
51962306a36Sopenharmony_ci		args.v1.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
52062306a36Sopenharmony_ci		args.v1.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
52162306a36Sopenharmony_ci		args.v1.ucSpreadSpectrumStep = ss->step;
52262306a36Sopenharmony_ci		args.v1.ucSpreadSpectrumDelay = ss->delay;
52362306a36Sopenharmony_ci		args.v1.ucSpreadSpectrumRange = ss->range;
52462306a36Sopenharmony_ci		args.v1.ucPpll = pll_id;
52562306a36Sopenharmony_ci		args.v1.ucEnable = enable;
52662306a36Sopenharmony_ci	} else if (ASIC_IS_AVIVO(rdev)) {
52762306a36Sopenharmony_ci		if ((enable == ATOM_DISABLE) || (ss->percentage == 0) ||
52862306a36Sopenharmony_ci		    (ss->type & ATOM_EXTERNAL_SS_MASK)) {
52962306a36Sopenharmony_ci			atombios_disable_ss(rdev, pll_id);
53062306a36Sopenharmony_ci			return;
53162306a36Sopenharmony_ci		}
53262306a36Sopenharmony_ci		args.lvds_ss_2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
53362306a36Sopenharmony_ci		args.lvds_ss_2.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
53462306a36Sopenharmony_ci		args.lvds_ss_2.ucSpreadSpectrumStep = ss->step;
53562306a36Sopenharmony_ci		args.lvds_ss_2.ucSpreadSpectrumDelay = ss->delay;
53662306a36Sopenharmony_ci		args.lvds_ss_2.ucSpreadSpectrumRange = ss->range;
53762306a36Sopenharmony_ci		args.lvds_ss_2.ucEnable = enable;
53862306a36Sopenharmony_ci	} else {
53962306a36Sopenharmony_ci		if (enable == ATOM_DISABLE) {
54062306a36Sopenharmony_ci			atombios_disable_ss(rdev, pll_id);
54162306a36Sopenharmony_ci			return;
54262306a36Sopenharmony_ci		}
54362306a36Sopenharmony_ci		args.lvds_ss.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
54462306a36Sopenharmony_ci		args.lvds_ss.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
54562306a36Sopenharmony_ci		args.lvds_ss.ucSpreadSpectrumStepSize_Delay = (ss->step & 3) << 2;
54662306a36Sopenharmony_ci		args.lvds_ss.ucSpreadSpectrumStepSize_Delay |= (ss->delay & 7) << 4;
54762306a36Sopenharmony_ci		args.lvds_ss.ucEnable = enable;
54862306a36Sopenharmony_ci	}
54962306a36Sopenharmony_ci	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
55062306a36Sopenharmony_ci}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ciunion adjust_pixel_clock {
55362306a36Sopenharmony_ci	ADJUST_DISPLAY_PLL_PS_ALLOCATION v1;
55462306a36Sopenharmony_ci	ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 v3;
55562306a36Sopenharmony_ci};
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_cistatic u32 atombios_adjust_pll(struct drm_crtc *crtc,
55862306a36Sopenharmony_ci			       struct drm_display_mode *mode)
55962306a36Sopenharmony_ci{
56062306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
56162306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
56262306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
56362306a36Sopenharmony_ci	struct drm_encoder *encoder = radeon_crtc->encoder;
56462306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
56562306a36Sopenharmony_ci	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
56662306a36Sopenharmony_ci	u32 adjusted_clock = mode->clock;
56762306a36Sopenharmony_ci	int encoder_mode = atombios_get_encoder_mode(encoder);
56862306a36Sopenharmony_ci	u32 dp_clock = mode->clock;
56962306a36Sopenharmony_ci	u32 clock = mode->clock;
57062306a36Sopenharmony_ci	int bpc = radeon_crtc->bpc;
57162306a36Sopenharmony_ci	bool is_duallink = radeon_dig_monitor_is_duallink(encoder, mode->clock);
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	/* reset the pll flags */
57462306a36Sopenharmony_ci	radeon_crtc->pll_flags = 0;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	if (ASIC_IS_AVIVO(rdev)) {
57762306a36Sopenharmony_ci		if ((rdev->family == CHIP_RS600) ||
57862306a36Sopenharmony_ci		    (rdev->family == CHIP_RS690) ||
57962306a36Sopenharmony_ci		    (rdev->family == CHIP_RS740))
58062306a36Sopenharmony_ci			radeon_crtc->pll_flags |= (/*RADEON_PLL_USE_FRAC_FB_DIV |*/
58162306a36Sopenharmony_ci				RADEON_PLL_PREFER_CLOSEST_LOWER);
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci		if (ASIC_IS_DCE32(rdev) && mode->clock > 200000)	/* range limits??? */
58462306a36Sopenharmony_ci			radeon_crtc->pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
58562306a36Sopenharmony_ci		else
58662306a36Sopenharmony_ci			radeon_crtc->pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci		if (rdev->family < CHIP_RV770)
58962306a36Sopenharmony_ci			radeon_crtc->pll_flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP;
59062306a36Sopenharmony_ci		/* use frac fb div on APUs */
59162306a36Sopenharmony_ci		if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev) || ASIC_IS_DCE8(rdev))
59262306a36Sopenharmony_ci			radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV;
59362306a36Sopenharmony_ci		/* use frac fb div on RS780/RS880 */
59462306a36Sopenharmony_ci		if (((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880))
59562306a36Sopenharmony_ci		    && !radeon_crtc->ss_enabled)
59662306a36Sopenharmony_ci			radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV;
59762306a36Sopenharmony_ci		if (ASIC_IS_DCE32(rdev) && mode->clock > 165000)
59862306a36Sopenharmony_ci			radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV;
59962306a36Sopenharmony_ci	} else {
60062306a36Sopenharmony_ci		radeon_crtc->pll_flags |= RADEON_PLL_LEGACY;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci		if (mode->clock > 200000)	/* range limits??? */
60362306a36Sopenharmony_ci			radeon_crtc->pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
60462306a36Sopenharmony_ci		else
60562306a36Sopenharmony_ci			radeon_crtc->pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
60662306a36Sopenharmony_ci	}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
60962306a36Sopenharmony_ci	    (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)) {
61062306a36Sopenharmony_ci		if (connector) {
61162306a36Sopenharmony_ci			struct radeon_connector *radeon_connector = to_radeon_connector(connector);
61262306a36Sopenharmony_ci			struct radeon_connector_atom_dig *dig_connector =
61362306a36Sopenharmony_ci				radeon_connector->con_priv;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci			dp_clock = dig_connector->dp_clock;
61662306a36Sopenharmony_ci		}
61762306a36Sopenharmony_ci	}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	/* use recommended ref_div for ss */
62062306a36Sopenharmony_ci	if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
62162306a36Sopenharmony_ci		if (radeon_crtc->ss_enabled) {
62262306a36Sopenharmony_ci			if (radeon_crtc->ss.refdiv) {
62362306a36Sopenharmony_ci				radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV;
62462306a36Sopenharmony_ci				radeon_crtc->pll_reference_div = radeon_crtc->ss.refdiv;
62562306a36Sopenharmony_ci				if (ASIC_IS_AVIVO(rdev) &&
62662306a36Sopenharmony_ci				    rdev->family != CHIP_RS780 &&
62762306a36Sopenharmony_ci				    rdev->family != CHIP_RS880)
62862306a36Sopenharmony_ci					radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV;
62962306a36Sopenharmony_ci			}
63062306a36Sopenharmony_ci		}
63162306a36Sopenharmony_ci	}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	if (ASIC_IS_AVIVO(rdev)) {
63462306a36Sopenharmony_ci		/* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */
63562306a36Sopenharmony_ci		if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)
63662306a36Sopenharmony_ci			adjusted_clock = mode->clock * 2;
63762306a36Sopenharmony_ci		if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
63862306a36Sopenharmony_ci			radeon_crtc->pll_flags |= RADEON_PLL_PREFER_CLOSEST_LOWER;
63962306a36Sopenharmony_ci		if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
64062306a36Sopenharmony_ci			radeon_crtc->pll_flags |= RADEON_PLL_IS_LCD;
64162306a36Sopenharmony_ci	} else {
64262306a36Sopenharmony_ci		if (encoder->encoder_type != DRM_MODE_ENCODER_DAC)
64362306a36Sopenharmony_ci			radeon_crtc->pll_flags |= RADEON_PLL_NO_ODD_POST_DIV;
64462306a36Sopenharmony_ci		if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS)
64562306a36Sopenharmony_ci			radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV;
64662306a36Sopenharmony_ci	}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	/* adjust pll for deep color modes */
64962306a36Sopenharmony_ci	if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
65062306a36Sopenharmony_ci		switch (bpc) {
65162306a36Sopenharmony_ci		case 8:
65262306a36Sopenharmony_ci		default:
65362306a36Sopenharmony_ci			break;
65462306a36Sopenharmony_ci		case 10:
65562306a36Sopenharmony_ci			clock = (clock * 5) / 4;
65662306a36Sopenharmony_ci			break;
65762306a36Sopenharmony_ci		case 12:
65862306a36Sopenharmony_ci			clock = (clock * 3) / 2;
65962306a36Sopenharmony_ci			break;
66062306a36Sopenharmony_ci		case 16:
66162306a36Sopenharmony_ci			clock = clock * 2;
66262306a36Sopenharmony_ci			break;
66362306a36Sopenharmony_ci		}
66462306a36Sopenharmony_ci	}
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	/* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock
66762306a36Sopenharmony_ci	 * accordingly based on the encoder/transmitter to work around
66862306a36Sopenharmony_ci	 * special hw requirements.
66962306a36Sopenharmony_ci	 */
67062306a36Sopenharmony_ci	if (ASIC_IS_DCE3(rdev)) {
67162306a36Sopenharmony_ci		union adjust_pixel_clock args;
67262306a36Sopenharmony_ci		u8 frev, crev;
67362306a36Sopenharmony_ci		int index;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci		index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll);
67662306a36Sopenharmony_ci		if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
67762306a36Sopenharmony_ci					   &crev))
67862306a36Sopenharmony_ci			return adjusted_clock;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci		memset(&args, 0, sizeof(args));
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci		switch (frev) {
68362306a36Sopenharmony_ci		case 1:
68462306a36Sopenharmony_ci			switch (crev) {
68562306a36Sopenharmony_ci			case 1:
68662306a36Sopenharmony_ci			case 2:
68762306a36Sopenharmony_ci				args.v1.usPixelClock = cpu_to_le16(clock / 10);
68862306a36Sopenharmony_ci				args.v1.ucTransmitterID = radeon_encoder->encoder_id;
68962306a36Sopenharmony_ci				args.v1.ucEncodeMode = encoder_mode;
69062306a36Sopenharmony_ci				if (radeon_crtc->ss_enabled && radeon_crtc->ss.percentage)
69162306a36Sopenharmony_ci					args.v1.ucConfig |=
69262306a36Sopenharmony_ci						ADJUST_DISPLAY_CONFIG_SS_ENABLE;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci				atom_execute_table(rdev->mode_info.atom_context,
69562306a36Sopenharmony_ci						   index, (uint32_t *)&args);
69662306a36Sopenharmony_ci				adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10;
69762306a36Sopenharmony_ci				break;
69862306a36Sopenharmony_ci			case 3:
69962306a36Sopenharmony_ci				args.v3.sInput.usPixelClock = cpu_to_le16(clock / 10);
70062306a36Sopenharmony_ci				args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id;
70162306a36Sopenharmony_ci				args.v3.sInput.ucEncodeMode = encoder_mode;
70262306a36Sopenharmony_ci				args.v3.sInput.ucDispPllConfig = 0;
70362306a36Sopenharmony_ci				if (radeon_crtc->ss_enabled && radeon_crtc->ss.percentage)
70462306a36Sopenharmony_ci					args.v3.sInput.ucDispPllConfig |=
70562306a36Sopenharmony_ci						DISPPLL_CONFIG_SS_ENABLE;
70662306a36Sopenharmony_ci				if (ENCODER_MODE_IS_DP(encoder_mode)) {
70762306a36Sopenharmony_ci					args.v3.sInput.ucDispPllConfig |=
70862306a36Sopenharmony_ci						DISPPLL_CONFIG_COHERENT_MODE;
70962306a36Sopenharmony_ci					/* 16200 or 27000 */
71062306a36Sopenharmony_ci					args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10);
71162306a36Sopenharmony_ci				} else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
71262306a36Sopenharmony_ci					struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
71362306a36Sopenharmony_ci					if (dig->coherent_mode)
71462306a36Sopenharmony_ci						args.v3.sInput.ucDispPllConfig |=
71562306a36Sopenharmony_ci							DISPPLL_CONFIG_COHERENT_MODE;
71662306a36Sopenharmony_ci					if (is_duallink)
71762306a36Sopenharmony_ci						args.v3.sInput.ucDispPllConfig |=
71862306a36Sopenharmony_ci							DISPPLL_CONFIG_DUAL_LINK;
71962306a36Sopenharmony_ci				}
72062306a36Sopenharmony_ci				if (radeon_encoder_get_dp_bridge_encoder_id(encoder) !=
72162306a36Sopenharmony_ci				    ENCODER_OBJECT_ID_NONE)
72262306a36Sopenharmony_ci					args.v3.sInput.ucExtTransmitterID =
72362306a36Sopenharmony_ci						radeon_encoder_get_dp_bridge_encoder_id(encoder);
72462306a36Sopenharmony_ci				else
72562306a36Sopenharmony_ci					args.v3.sInput.ucExtTransmitterID = 0;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci				atom_execute_table(rdev->mode_info.atom_context,
72862306a36Sopenharmony_ci						   index, (uint32_t *)&args);
72962306a36Sopenharmony_ci				adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10;
73062306a36Sopenharmony_ci				if (args.v3.sOutput.ucRefDiv) {
73162306a36Sopenharmony_ci					radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV;
73262306a36Sopenharmony_ci					radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV;
73362306a36Sopenharmony_ci					radeon_crtc->pll_reference_div = args.v3.sOutput.ucRefDiv;
73462306a36Sopenharmony_ci				}
73562306a36Sopenharmony_ci				if (args.v3.sOutput.ucPostDiv) {
73662306a36Sopenharmony_ci					radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV;
73762306a36Sopenharmony_ci					radeon_crtc->pll_flags |= RADEON_PLL_USE_POST_DIV;
73862306a36Sopenharmony_ci					radeon_crtc->pll_post_div = args.v3.sOutput.ucPostDiv;
73962306a36Sopenharmony_ci				}
74062306a36Sopenharmony_ci				break;
74162306a36Sopenharmony_ci			default:
74262306a36Sopenharmony_ci				DRM_ERROR("Unknown table version %d %d\n", frev, crev);
74362306a36Sopenharmony_ci				return adjusted_clock;
74462306a36Sopenharmony_ci			}
74562306a36Sopenharmony_ci			break;
74662306a36Sopenharmony_ci		default:
74762306a36Sopenharmony_ci			DRM_ERROR("Unknown table version %d %d\n", frev, crev);
74862306a36Sopenharmony_ci			return adjusted_clock;
74962306a36Sopenharmony_ci		}
75062306a36Sopenharmony_ci	}
75162306a36Sopenharmony_ci	return adjusted_clock;
75262306a36Sopenharmony_ci}
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ciunion set_pixel_clock {
75562306a36Sopenharmony_ci	SET_PIXEL_CLOCK_PS_ALLOCATION base;
75662306a36Sopenharmony_ci	PIXEL_CLOCK_PARAMETERS v1;
75762306a36Sopenharmony_ci	PIXEL_CLOCK_PARAMETERS_V2 v2;
75862306a36Sopenharmony_ci	PIXEL_CLOCK_PARAMETERS_V3 v3;
75962306a36Sopenharmony_ci	PIXEL_CLOCK_PARAMETERS_V5 v5;
76062306a36Sopenharmony_ci	PIXEL_CLOCK_PARAMETERS_V6 v6;
76162306a36Sopenharmony_ci};
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci/* on DCE5, make sure the voltage is high enough to support the
76462306a36Sopenharmony_ci * required disp clk.
76562306a36Sopenharmony_ci */
76662306a36Sopenharmony_cistatic void atombios_crtc_set_disp_eng_pll(struct radeon_device *rdev,
76762306a36Sopenharmony_ci				    u32 dispclk)
76862306a36Sopenharmony_ci{
76962306a36Sopenharmony_ci	u8 frev, crev;
77062306a36Sopenharmony_ci	int index;
77162306a36Sopenharmony_ci	union set_pixel_clock args;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	memset(&args, 0, sizeof(args));
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
77662306a36Sopenharmony_ci	if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
77762306a36Sopenharmony_ci				   &crev))
77862306a36Sopenharmony_ci		return;
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	switch (frev) {
78162306a36Sopenharmony_ci	case 1:
78262306a36Sopenharmony_ci		switch (crev) {
78362306a36Sopenharmony_ci		case 5:
78462306a36Sopenharmony_ci			/* if the default dcpll clock is specified,
78562306a36Sopenharmony_ci			 * SetPixelClock provides the dividers
78662306a36Sopenharmony_ci			 */
78762306a36Sopenharmony_ci			args.v5.ucCRTC = ATOM_CRTC_INVALID;
78862306a36Sopenharmony_ci			args.v5.usPixelClock = cpu_to_le16(dispclk);
78962306a36Sopenharmony_ci			args.v5.ucPpll = ATOM_DCPLL;
79062306a36Sopenharmony_ci			break;
79162306a36Sopenharmony_ci		case 6:
79262306a36Sopenharmony_ci			/* if the default dcpll clock is specified,
79362306a36Sopenharmony_ci			 * SetPixelClock provides the dividers
79462306a36Sopenharmony_ci			 */
79562306a36Sopenharmony_ci			args.v6.ulDispEngClkFreq = cpu_to_le32(dispclk);
79662306a36Sopenharmony_ci			if (ASIC_IS_DCE61(rdev) || ASIC_IS_DCE8(rdev))
79762306a36Sopenharmony_ci				args.v6.ucPpll = ATOM_EXT_PLL1;
79862306a36Sopenharmony_ci			else if (ASIC_IS_DCE6(rdev))
79962306a36Sopenharmony_ci				args.v6.ucPpll = ATOM_PPLL0;
80062306a36Sopenharmony_ci			else
80162306a36Sopenharmony_ci				args.v6.ucPpll = ATOM_DCPLL;
80262306a36Sopenharmony_ci			break;
80362306a36Sopenharmony_ci		default:
80462306a36Sopenharmony_ci			DRM_ERROR("Unknown table version %d %d\n", frev, crev);
80562306a36Sopenharmony_ci			return;
80662306a36Sopenharmony_ci		}
80762306a36Sopenharmony_ci		break;
80862306a36Sopenharmony_ci	default:
80962306a36Sopenharmony_ci		DRM_ERROR("Unknown table version %d %d\n", frev, crev);
81062306a36Sopenharmony_ci		return;
81162306a36Sopenharmony_ci	}
81262306a36Sopenharmony_ci	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
81362306a36Sopenharmony_ci}
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_cistatic void atombios_crtc_program_pll(struct drm_crtc *crtc,
81662306a36Sopenharmony_ci				      u32 crtc_id,
81762306a36Sopenharmony_ci				      int pll_id,
81862306a36Sopenharmony_ci				      u32 encoder_mode,
81962306a36Sopenharmony_ci				      u32 encoder_id,
82062306a36Sopenharmony_ci				      u32 clock,
82162306a36Sopenharmony_ci				      u32 ref_div,
82262306a36Sopenharmony_ci				      u32 fb_div,
82362306a36Sopenharmony_ci				      u32 frac_fb_div,
82462306a36Sopenharmony_ci				      u32 post_div,
82562306a36Sopenharmony_ci				      int bpc,
82662306a36Sopenharmony_ci				      bool ss_enabled,
82762306a36Sopenharmony_ci				      struct radeon_atom_ss *ss)
82862306a36Sopenharmony_ci{
82962306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
83062306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
83162306a36Sopenharmony_ci	u8 frev, crev;
83262306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
83362306a36Sopenharmony_ci	union set_pixel_clock args;
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	memset(&args, 0, sizeof(args));
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
83862306a36Sopenharmony_ci				   &crev))
83962306a36Sopenharmony_ci		return;
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	switch (frev) {
84262306a36Sopenharmony_ci	case 1:
84362306a36Sopenharmony_ci		switch (crev) {
84462306a36Sopenharmony_ci		case 1:
84562306a36Sopenharmony_ci			if (clock == ATOM_DISABLE)
84662306a36Sopenharmony_ci				return;
84762306a36Sopenharmony_ci			args.v1.usPixelClock = cpu_to_le16(clock / 10);
84862306a36Sopenharmony_ci			args.v1.usRefDiv = cpu_to_le16(ref_div);
84962306a36Sopenharmony_ci			args.v1.usFbDiv = cpu_to_le16(fb_div);
85062306a36Sopenharmony_ci			args.v1.ucFracFbDiv = frac_fb_div;
85162306a36Sopenharmony_ci			args.v1.ucPostDiv = post_div;
85262306a36Sopenharmony_ci			args.v1.ucPpll = pll_id;
85362306a36Sopenharmony_ci			args.v1.ucCRTC = crtc_id;
85462306a36Sopenharmony_ci			args.v1.ucRefDivSrc = 1;
85562306a36Sopenharmony_ci			break;
85662306a36Sopenharmony_ci		case 2:
85762306a36Sopenharmony_ci			args.v2.usPixelClock = cpu_to_le16(clock / 10);
85862306a36Sopenharmony_ci			args.v2.usRefDiv = cpu_to_le16(ref_div);
85962306a36Sopenharmony_ci			args.v2.usFbDiv = cpu_to_le16(fb_div);
86062306a36Sopenharmony_ci			args.v2.ucFracFbDiv = frac_fb_div;
86162306a36Sopenharmony_ci			args.v2.ucPostDiv = post_div;
86262306a36Sopenharmony_ci			args.v2.ucPpll = pll_id;
86362306a36Sopenharmony_ci			args.v2.ucCRTC = crtc_id;
86462306a36Sopenharmony_ci			args.v2.ucRefDivSrc = 1;
86562306a36Sopenharmony_ci			break;
86662306a36Sopenharmony_ci		case 3:
86762306a36Sopenharmony_ci			args.v3.usPixelClock = cpu_to_le16(clock / 10);
86862306a36Sopenharmony_ci			args.v3.usRefDiv = cpu_to_le16(ref_div);
86962306a36Sopenharmony_ci			args.v3.usFbDiv = cpu_to_le16(fb_div);
87062306a36Sopenharmony_ci			args.v3.ucFracFbDiv = frac_fb_div;
87162306a36Sopenharmony_ci			args.v3.ucPostDiv = post_div;
87262306a36Sopenharmony_ci			args.v3.ucPpll = pll_id;
87362306a36Sopenharmony_ci			if (crtc_id == ATOM_CRTC2)
87462306a36Sopenharmony_ci				args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC2;
87562306a36Sopenharmony_ci			else
87662306a36Sopenharmony_ci				args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC1;
87762306a36Sopenharmony_ci			if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
87862306a36Sopenharmony_ci				args.v3.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC;
87962306a36Sopenharmony_ci			args.v3.ucTransmitterId = encoder_id;
88062306a36Sopenharmony_ci			args.v3.ucEncoderMode = encoder_mode;
88162306a36Sopenharmony_ci			break;
88262306a36Sopenharmony_ci		case 5:
88362306a36Sopenharmony_ci			args.v5.ucCRTC = crtc_id;
88462306a36Sopenharmony_ci			args.v5.usPixelClock = cpu_to_le16(clock / 10);
88562306a36Sopenharmony_ci			args.v5.ucRefDiv = ref_div;
88662306a36Sopenharmony_ci			args.v5.usFbDiv = cpu_to_le16(fb_div);
88762306a36Sopenharmony_ci			args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
88862306a36Sopenharmony_ci			args.v5.ucPostDiv = post_div;
88962306a36Sopenharmony_ci			args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */
89062306a36Sopenharmony_ci			if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
89162306a36Sopenharmony_ci				args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_REF_DIV_SRC;
89262306a36Sopenharmony_ci			if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
89362306a36Sopenharmony_ci				switch (bpc) {
89462306a36Sopenharmony_ci				case 8:
89562306a36Sopenharmony_ci				default:
89662306a36Sopenharmony_ci					args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP;
89762306a36Sopenharmony_ci					break;
89862306a36Sopenharmony_ci				case 10:
89962306a36Sopenharmony_ci					/* yes this is correct, the atom define is wrong */
90062306a36Sopenharmony_ci					args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_32BPP;
90162306a36Sopenharmony_ci					break;
90262306a36Sopenharmony_ci				case 12:
90362306a36Sopenharmony_ci					/* yes this is correct, the atom define is wrong */
90462306a36Sopenharmony_ci					args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP;
90562306a36Sopenharmony_ci					break;
90662306a36Sopenharmony_ci				}
90762306a36Sopenharmony_ci			}
90862306a36Sopenharmony_ci			args.v5.ucTransmitterID = encoder_id;
90962306a36Sopenharmony_ci			args.v5.ucEncoderMode = encoder_mode;
91062306a36Sopenharmony_ci			args.v5.ucPpll = pll_id;
91162306a36Sopenharmony_ci			break;
91262306a36Sopenharmony_ci		case 6:
91362306a36Sopenharmony_ci			args.v6.ulDispEngClkFreq = cpu_to_le32(crtc_id << 24 | clock / 10);
91462306a36Sopenharmony_ci			args.v6.ucRefDiv = ref_div;
91562306a36Sopenharmony_ci			args.v6.usFbDiv = cpu_to_le16(fb_div);
91662306a36Sopenharmony_ci			args.v6.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
91762306a36Sopenharmony_ci			args.v6.ucPostDiv = post_div;
91862306a36Sopenharmony_ci			args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */
91962306a36Sopenharmony_ci			if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
92062306a36Sopenharmony_ci				args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_REF_DIV_SRC;
92162306a36Sopenharmony_ci			if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
92262306a36Sopenharmony_ci				switch (bpc) {
92362306a36Sopenharmony_ci				case 8:
92462306a36Sopenharmony_ci				default:
92562306a36Sopenharmony_ci					args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP;
92662306a36Sopenharmony_ci					break;
92762306a36Sopenharmony_ci				case 10:
92862306a36Sopenharmony_ci					args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP_V6;
92962306a36Sopenharmony_ci					break;
93062306a36Sopenharmony_ci				case 12:
93162306a36Sopenharmony_ci					args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP_V6;
93262306a36Sopenharmony_ci					break;
93362306a36Sopenharmony_ci				case 16:
93462306a36Sopenharmony_ci					args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP;
93562306a36Sopenharmony_ci					break;
93662306a36Sopenharmony_ci				}
93762306a36Sopenharmony_ci			}
93862306a36Sopenharmony_ci			args.v6.ucTransmitterID = encoder_id;
93962306a36Sopenharmony_ci			args.v6.ucEncoderMode = encoder_mode;
94062306a36Sopenharmony_ci			args.v6.ucPpll = pll_id;
94162306a36Sopenharmony_ci			break;
94262306a36Sopenharmony_ci		default:
94362306a36Sopenharmony_ci			DRM_ERROR("Unknown table version %d %d\n", frev, crev);
94462306a36Sopenharmony_ci			return;
94562306a36Sopenharmony_ci		}
94662306a36Sopenharmony_ci		break;
94762306a36Sopenharmony_ci	default:
94862306a36Sopenharmony_ci		DRM_ERROR("Unknown table version %d %d\n", frev, crev);
94962306a36Sopenharmony_ci		return;
95062306a36Sopenharmony_ci	}
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
95362306a36Sopenharmony_ci}
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_cistatic bool atombios_crtc_prepare_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
95662306a36Sopenharmony_ci{
95762306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
95862306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
95962306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
96062306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder =
96162306a36Sopenharmony_ci		to_radeon_encoder(radeon_crtc->encoder);
96262306a36Sopenharmony_ci	int encoder_mode = atombios_get_encoder_mode(radeon_crtc->encoder);
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	radeon_crtc->bpc = 8;
96562306a36Sopenharmony_ci	radeon_crtc->ss_enabled = false;
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
96862306a36Sopenharmony_ci	    (radeon_encoder_get_dp_bridge_encoder_id(radeon_crtc->encoder) != ENCODER_OBJECT_ID_NONE)) {
96962306a36Sopenharmony_ci		struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
97062306a36Sopenharmony_ci		struct drm_connector *connector =
97162306a36Sopenharmony_ci			radeon_get_connector_for_encoder(radeon_crtc->encoder);
97262306a36Sopenharmony_ci		struct radeon_connector *radeon_connector =
97362306a36Sopenharmony_ci			to_radeon_connector(connector);
97462306a36Sopenharmony_ci		struct radeon_connector_atom_dig *dig_connector =
97562306a36Sopenharmony_ci			radeon_connector->con_priv;
97662306a36Sopenharmony_ci		int dp_clock;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci		/* Assign mode clock for hdmi deep color max clock limit check */
97962306a36Sopenharmony_ci		radeon_connector->pixelclock_for_modeset = mode->clock;
98062306a36Sopenharmony_ci		radeon_crtc->bpc = radeon_get_monitor_bpc(connector);
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci		switch (encoder_mode) {
98362306a36Sopenharmony_ci		case ATOM_ENCODER_MODE_DP_MST:
98462306a36Sopenharmony_ci		case ATOM_ENCODER_MODE_DP:
98562306a36Sopenharmony_ci			/* DP/eDP */
98662306a36Sopenharmony_ci			dp_clock = dig_connector->dp_clock / 10;
98762306a36Sopenharmony_ci			if (ASIC_IS_DCE4(rdev))
98862306a36Sopenharmony_ci				radeon_crtc->ss_enabled =
98962306a36Sopenharmony_ci					radeon_atombios_get_asic_ss_info(rdev, &radeon_crtc->ss,
99062306a36Sopenharmony_ci									 ASIC_INTERNAL_SS_ON_DP,
99162306a36Sopenharmony_ci									 dp_clock);
99262306a36Sopenharmony_ci			else {
99362306a36Sopenharmony_ci				if (dp_clock == 16200) {
99462306a36Sopenharmony_ci					radeon_crtc->ss_enabled =
99562306a36Sopenharmony_ci						radeon_atombios_get_ppll_ss_info(rdev,
99662306a36Sopenharmony_ci										 &radeon_crtc->ss,
99762306a36Sopenharmony_ci										 ATOM_DP_SS_ID2);
99862306a36Sopenharmony_ci					if (!radeon_crtc->ss_enabled)
99962306a36Sopenharmony_ci						radeon_crtc->ss_enabled =
100062306a36Sopenharmony_ci							radeon_atombios_get_ppll_ss_info(rdev,
100162306a36Sopenharmony_ci											 &radeon_crtc->ss,
100262306a36Sopenharmony_ci											 ATOM_DP_SS_ID1);
100362306a36Sopenharmony_ci				} else {
100462306a36Sopenharmony_ci					radeon_crtc->ss_enabled =
100562306a36Sopenharmony_ci						radeon_atombios_get_ppll_ss_info(rdev,
100662306a36Sopenharmony_ci										 &radeon_crtc->ss,
100762306a36Sopenharmony_ci										 ATOM_DP_SS_ID1);
100862306a36Sopenharmony_ci				}
100962306a36Sopenharmony_ci				/* disable spread spectrum on DCE3 DP */
101062306a36Sopenharmony_ci				radeon_crtc->ss_enabled = false;
101162306a36Sopenharmony_ci			}
101262306a36Sopenharmony_ci			break;
101362306a36Sopenharmony_ci		case ATOM_ENCODER_MODE_LVDS:
101462306a36Sopenharmony_ci			if (ASIC_IS_DCE4(rdev))
101562306a36Sopenharmony_ci				radeon_crtc->ss_enabled =
101662306a36Sopenharmony_ci					radeon_atombios_get_asic_ss_info(rdev,
101762306a36Sopenharmony_ci									 &radeon_crtc->ss,
101862306a36Sopenharmony_ci									 dig->lcd_ss_id,
101962306a36Sopenharmony_ci									 mode->clock / 10);
102062306a36Sopenharmony_ci			else
102162306a36Sopenharmony_ci				radeon_crtc->ss_enabled =
102262306a36Sopenharmony_ci					radeon_atombios_get_ppll_ss_info(rdev,
102362306a36Sopenharmony_ci									 &radeon_crtc->ss,
102462306a36Sopenharmony_ci									 dig->lcd_ss_id);
102562306a36Sopenharmony_ci			break;
102662306a36Sopenharmony_ci		case ATOM_ENCODER_MODE_DVI:
102762306a36Sopenharmony_ci			if (ASIC_IS_DCE4(rdev))
102862306a36Sopenharmony_ci				radeon_crtc->ss_enabled =
102962306a36Sopenharmony_ci					radeon_atombios_get_asic_ss_info(rdev,
103062306a36Sopenharmony_ci									 &radeon_crtc->ss,
103162306a36Sopenharmony_ci									 ASIC_INTERNAL_SS_ON_TMDS,
103262306a36Sopenharmony_ci									 mode->clock / 10);
103362306a36Sopenharmony_ci			break;
103462306a36Sopenharmony_ci		case ATOM_ENCODER_MODE_HDMI:
103562306a36Sopenharmony_ci			if (ASIC_IS_DCE4(rdev))
103662306a36Sopenharmony_ci				radeon_crtc->ss_enabled =
103762306a36Sopenharmony_ci					radeon_atombios_get_asic_ss_info(rdev,
103862306a36Sopenharmony_ci									 &radeon_crtc->ss,
103962306a36Sopenharmony_ci									 ASIC_INTERNAL_SS_ON_HDMI,
104062306a36Sopenharmony_ci									 mode->clock / 10);
104162306a36Sopenharmony_ci			break;
104262306a36Sopenharmony_ci		default:
104362306a36Sopenharmony_ci			break;
104462306a36Sopenharmony_ci		}
104562306a36Sopenharmony_ci	}
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci	/* adjust pixel clock as needed */
104862306a36Sopenharmony_ci	radeon_crtc->adjusted_clock = atombios_adjust_pll(crtc, mode);
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	return true;
105162306a36Sopenharmony_ci}
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_cistatic void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
105462306a36Sopenharmony_ci{
105562306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
105662306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
105762306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
105862306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder =
105962306a36Sopenharmony_ci		to_radeon_encoder(radeon_crtc->encoder);
106062306a36Sopenharmony_ci	u32 pll_clock = mode->clock;
106162306a36Sopenharmony_ci	u32 clock = mode->clock;
106262306a36Sopenharmony_ci	u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0;
106362306a36Sopenharmony_ci	struct radeon_pll *pll;
106462306a36Sopenharmony_ci	int encoder_mode = atombios_get_encoder_mode(radeon_crtc->encoder);
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	/* pass the actual clock to atombios_crtc_program_pll for DCE5,6 for HDMI */
106762306a36Sopenharmony_ci	if (ASIC_IS_DCE5(rdev) &&
106862306a36Sopenharmony_ci	    (encoder_mode == ATOM_ENCODER_MODE_HDMI) &&
106962306a36Sopenharmony_ci	    (radeon_crtc->bpc > 8))
107062306a36Sopenharmony_ci		clock = radeon_crtc->adjusted_clock;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	switch (radeon_crtc->pll_id) {
107362306a36Sopenharmony_ci	case ATOM_PPLL1:
107462306a36Sopenharmony_ci		pll = &rdev->clock.p1pll;
107562306a36Sopenharmony_ci		break;
107662306a36Sopenharmony_ci	case ATOM_PPLL2:
107762306a36Sopenharmony_ci		pll = &rdev->clock.p2pll;
107862306a36Sopenharmony_ci		break;
107962306a36Sopenharmony_ci	case ATOM_DCPLL:
108062306a36Sopenharmony_ci	case ATOM_PPLL_INVALID:
108162306a36Sopenharmony_ci	default:
108262306a36Sopenharmony_ci		pll = &rdev->clock.dcpll;
108362306a36Sopenharmony_ci		break;
108462306a36Sopenharmony_ci	}
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	/* update pll params */
108762306a36Sopenharmony_ci	pll->flags = radeon_crtc->pll_flags;
108862306a36Sopenharmony_ci	pll->reference_div = radeon_crtc->pll_reference_div;
108962306a36Sopenharmony_ci	pll->post_div = radeon_crtc->pll_post_div;
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
109262306a36Sopenharmony_ci		/* TV seems to prefer the legacy algo on some boards */
109362306a36Sopenharmony_ci		radeon_compute_pll_legacy(pll, radeon_crtc->adjusted_clock, &pll_clock,
109462306a36Sopenharmony_ci					  &fb_div, &frac_fb_div, &ref_div, &post_div);
109562306a36Sopenharmony_ci	else if (ASIC_IS_AVIVO(rdev))
109662306a36Sopenharmony_ci		radeon_compute_pll_avivo(pll, radeon_crtc->adjusted_clock, &pll_clock,
109762306a36Sopenharmony_ci					 &fb_div, &frac_fb_div, &ref_div, &post_div);
109862306a36Sopenharmony_ci	else
109962306a36Sopenharmony_ci		radeon_compute_pll_legacy(pll, radeon_crtc->adjusted_clock, &pll_clock,
110062306a36Sopenharmony_ci					  &fb_div, &frac_fb_div, &ref_div, &post_div);
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	atombios_crtc_program_ss(rdev, ATOM_DISABLE, radeon_crtc->pll_id,
110362306a36Sopenharmony_ci				 radeon_crtc->crtc_id, &radeon_crtc->ss);
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
110662306a36Sopenharmony_ci				  encoder_mode, radeon_encoder->encoder_id, clock,
110762306a36Sopenharmony_ci				  ref_div, fb_div, frac_fb_div, post_div,
110862306a36Sopenharmony_ci				  radeon_crtc->bpc, radeon_crtc->ss_enabled, &radeon_crtc->ss);
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	if (radeon_crtc->ss_enabled) {
111162306a36Sopenharmony_ci		/* calculate ss amount and step size */
111262306a36Sopenharmony_ci		if (ASIC_IS_DCE4(rdev)) {
111362306a36Sopenharmony_ci			u32 step_size;
111462306a36Sopenharmony_ci			u32 amount = (((fb_div * 10) + frac_fb_div) *
111562306a36Sopenharmony_ci				      (u32)radeon_crtc->ss.percentage) /
111662306a36Sopenharmony_ci				(100 * (u32)radeon_crtc->ss.percentage_divider);
111762306a36Sopenharmony_ci			radeon_crtc->ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK;
111862306a36Sopenharmony_ci			radeon_crtc->ss.amount |= ((amount - (amount / 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) &
111962306a36Sopenharmony_ci				ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK;
112062306a36Sopenharmony_ci			if (radeon_crtc->ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD)
112162306a36Sopenharmony_ci				step_size = (4 * amount * ref_div * ((u32)radeon_crtc->ss.rate * 2048)) /
112262306a36Sopenharmony_ci					(125 * 25 * pll->reference_freq / 100);
112362306a36Sopenharmony_ci			else
112462306a36Sopenharmony_ci				step_size = (2 * amount * ref_div * ((u32)radeon_crtc->ss.rate * 2048)) /
112562306a36Sopenharmony_ci					(125 * 25 * pll->reference_freq / 100);
112662306a36Sopenharmony_ci			radeon_crtc->ss.step = step_size;
112762306a36Sopenharmony_ci		}
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci		atombios_crtc_program_ss(rdev, ATOM_ENABLE, radeon_crtc->pll_id,
113062306a36Sopenharmony_ci					 radeon_crtc->crtc_id, &radeon_crtc->ss);
113162306a36Sopenharmony_ci	}
113262306a36Sopenharmony_ci}
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_cistatic int dce4_crtc_do_set_base(struct drm_crtc *crtc,
113562306a36Sopenharmony_ci				 struct drm_framebuffer *fb,
113662306a36Sopenharmony_ci				 int x, int y, int atomic)
113762306a36Sopenharmony_ci{
113862306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
113962306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
114062306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
114162306a36Sopenharmony_ci	struct drm_framebuffer *target_fb;
114262306a36Sopenharmony_ci	struct drm_gem_object *obj;
114362306a36Sopenharmony_ci	struct radeon_bo *rbo;
114462306a36Sopenharmony_ci	uint64_t fb_location;
114562306a36Sopenharmony_ci	uint32_t fb_format, fb_pitch_pixels, tiling_flags;
114662306a36Sopenharmony_ci	unsigned bankw, bankh, mtaspect, tile_split;
114762306a36Sopenharmony_ci	u32 fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE);
114862306a36Sopenharmony_ci	u32 tmp, viewport_w, viewport_h;
114962306a36Sopenharmony_ci	int r;
115062306a36Sopenharmony_ci	bool bypass_lut = false;
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	/* no fb bound */
115362306a36Sopenharmony_ci	if (!atomic && !crtc->primary->fb) {
115462306a36Sopenharmony_ci		DRM_DEBUG_KMS("No FB bound\n");
115562306a36Sopenharmony_ci		return 0;
115662306a36Sopenharmony_ci	}
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	if (atomic)
115962306a36Sopenharmony_ci		target_fb = fb;
116062306a36Sopenharmony_ci	else
116162306a36Sopenharmony_ci		target_fb = crtc->primary->fb;
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	/* If atomic, assume fb object is pinned & idle & fenced and
116462306a36Sopenharmony_ci	 * just update base pointers
116562306a36Sopenharmony_ci	 */
116662306a36Sopenharmony_ci	obj = target_fb->obj[0];
116762306a36Sopenharmony_ci	rbo = gem_to_radeon_bo(obj);
116862306a36Sopenharmony_ci	r = radeon_bo_reserve(rbo, false);
116962306a36Sopenharmony_ci	if (unlikely(r != 0))
117062306a36Sopenharmony_ci		return r;
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci	if (atomic)
117362306a36Sopenharmony_ci		fb_location = radeon_bo_gpu_offset(rbo);
117462306a36Sopenharmony_ci	else {
117562306a36Sopenharmony_ci		r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
117662306a36Sopenharmony_ci		if (unlikely(r != 0)) {
117762306a36Sopenharmony_ci			radeon_bo_unreserve(rbo);
117862306a36Sopenharmony_ci			return -EINVAL;
117962306a36Sopenharmony_ci		}
118062306a36Sopenharmony_ci	}
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
118362306a36Sopenharmony_ci	radeon_bo_unreserve(rbo);
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	switch (target_fb->format->format) {
118662306a36Sopenharmony_ci	case DRM_FORMAT_C8:
118762306a36Sopenharmony_ci		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP) |
118862306a36Sopenharmony_ci			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED));
118962306a36Sopenharmony_ci		break;
119062306a36Sopenharmony_ci	case DRM_FORMAT_XRGB4444:
119162306a36Sopenharmony_ci	case DRM_FORMAT_ARGB4444:
119262306a36Sopenharmony_ci		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) |
119362306a36Sopenharmony_ci			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB4444));
119462306a36Sopenharmony_ci#ifdef __BIG_ENDIAN
119562306a36Sopenharmony_ci		fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16);
119662306a36Sopenharmony_ci#endif
119762306a36Sopenharmony_ci		break;
119862306a36Sopenharmony_ci	case DRM_FORMAT_XRGB1555:
119962306a36Sopenharmony_ci	case DRM_FORMAT_ARGB1555:
120062306a36Sopenharmony_ci		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) |
120162306a36Sopenharmony_ci			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB1555));
120262306a36Sopenharmony_ci#ifdef __BIG_ENDIAN
120362306a36Sopenharmony_ci		fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16);
120462306a36Sopenharmony_ci#endif
120562306a36Sopenharmony_ci		break;
120662306a36Sopenharmony_ci	case DRM_FORMAT_BGRX5551:
120762306a36Sopenharmony_ci	case DRM_FORMAT_BGRA5551:
120862306a36Sopenharmony_ci		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) |
120962306a36Sopenharmony_ci			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_BGRA5551));
121062306a36Sopenharmony_ci#ifdef __BIG_ENDIAN
121162306a36Sopenharmony_ci		fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16);
121262306a36Sopenharmony_ci#endif
121362306a36Sopenharmony_ci		break;
121462306a36Sopenharmony_ci	case DRM_FORMAT_RGB565:
121562306a36Sopenharmony_ci		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) |
121662306a36Sopenharmony_ci			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565));
121762306a36Sopenharmony_ci#ifdef __BIG_ENDIAN
121862306a36Sopenharmony_ci		fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16);
121962306a36Sopenharmony_ci#endif
122062306a36Sopenharmony_ci		break;
122162306a36Sopenharmony_ci	case DRM_FORMAT_XRGB8888:
122262306a36Sopenharmony_ci	case DRM_FORMAT_ARGB8888:
122362306a36Sopenharmony_ci		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) |
122462306a36Sopenharmony_ci			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888));
122562306a36Sopenharmony_ci#ifdef __BIG_ENDIAN
122662306a36Sopenharmony_ci		fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32);
122762306a36Sopenharmony_ci#endif
122862306a36Sopenharmony_ci		break;
122962306a36Sopenharmony_ci	case DRM_FORMAT_XRGB2101010:
123062306a36Sopenharmony_ci	case DRM_FORMAT_ARGB2101010:
123162306a36Sopenharmony_ci		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) |
123262306a36Sopenharmony_ci			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB2101010));
123362306a36Sopenharmony_ci#ifdef __BIG_ENDIAN
123462306a36Sopenharmony_ci		fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32);
123562306a36Sopenharmony_ci#endif
123662306a36Sopenharmony_ci		/* Greater 8 bpc fb needs to bypass hw-lut to retain precision */
123762306a36Sopenharmony_ci		bypass_lut = true;
123862306a36Sopenharmony_ci		break;
123962306a36Sopenharmony_ci	case DRM_FORMAT_BGRX1010102:
124062306a36Sopenharmony_ci	case DRM_FORMAT_BGRA1010102:
124162306a36Sopenharmony_ci		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) |
124262306a36Sopenharmony_ci			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_BGRA1010102));
124362306a36Sopenharmony_ci#ifdef __BIG_ENDIAN
124462306a36Sopenharmony_ci		fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32);
124562306a36Sopenharmony_ci#endif
124662306a36Sopenharmony_ci		/* Greater 8 bpc fb needs to bypass hw-lut to retain precision */
124762306a36Sopenharmony_ci		bypass_lut = true;
124862306a36Sopenharmony_ci		break;
124962306a36Sopenharmony_ci	case DRM_FORMAT_XBGR8888:
125062306a36Sopenharmony_ci	case DRM_FORMAT_ABGR8888:
125162306a36Sopenharmony_ci		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) |
125262306a36Sopenharmony_ci			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888));
125362306a36Sopenharmony_ci		fb_swap = (EVERGREEN_GRPH_RED_CROSSBAR(EVERGREEN_GRPH_RED_SEL_B) |
125462306a36Sopenharmony_ci			   EVERGREEN_GRPH_BLUE_CROSSBAR(EVERGREEN_GRPH_BLUE_SEL_R));
125562306a36Sopenharmony_ci#ifdef __BIG_ENDIAN
125662306a36Sopenharmony_ci		fb_swap |= EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32);
125762306a36Sopenharmony_ci#endif
125862306a36Sopenharmony_ci		break;
125962306a36Sopenharmony_ci	default:
126062306a36Sopenharmony_ci		DRM_ERROR("Unsupported screen format %p4cc\n",
126162306a36Sopenharmony_ci			  &target_fb->format->format);
126262306a36Sopenharmony_ci		return -EINVAL;
126362306a36Sopenharmony_ci	}
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	if (tiling_flags & RADEON_TILING_MACRO) {
126662306a36Sopenharmony_ci		evergreen_tiling_fields(tiling_flags, &bankw, &bankh, &mtaspect, &tile_split);
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci		/* Set NUM_BANKS. */
126962306a36Sopenharmony_ci		if (rdev->family >= CHIP_TAHITI) {
127062306a36Sopenharmony_ci			unsigned index, num_banks;
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci			if (rdev->family >= CHIP_BONAIRE) {
127362306a36Sopenharmony_ci				unsigned tileb, tile_split_bytes;
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci				/* Calculate the macrotile mode index. */
127662306a36Sopenharmony_ci				tile_split_bytes = 64 << tile_split;
127762306a36Sopenharmony_ci				tileb = 8 * 8 * target_fb->format->cpp[0];
127862306a36Sopenharmony_ci				tileb = min(tile_split_bytes, tileb);
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci				for (index = 0; tileb > 64; index++)
128162306a36Sopenharmony_ci					tileb >>= 1;
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci				if (index >= 16) {
128462306a36Sopenharmony_ci					DRM_ERROR("Wrong screen bpp (%u) or tile split (%u)\n",
128562306a36Sopenharmony_ci						  target_fb->format->cpp[0] * 8,
128662306a36Sopenharmony_ci						  tile_split);
128762306a36Sopenharmony_ci					return -EINVAL;
128862306a36Sopenharmony_ci				}
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci				num_banks = (rdev->config.cik.macrotile_mode_array[index] >> 6) & 0x3;
129162306a36Sopenharmony_ci			} else {
129262306a36Sopenharmony_ci				switch (target_fb->format->cpp[0] * 8) {
129362306a36Sopenharmony_ci				case 8:
129462306a36Sopenharmony_ci					index = 10;
129562306a36Sopenharmony_ci					break;
129662306a36Sopenharmony_ci				case 16:
129762306a36Sopenharmony_ci					index = SI_TILE_MODE_COLOR_2D_SCANOUT_16BPP;
129862306a36Sopenharmony_ci					break;
129962306a36Sopenharmony_ci				default:
130062306a36Sopenharmony_ci				case 32:
130162306a36Sopenharmony_ci					index = SI_TILE_MODE_COLOR_2D_SCANOUT_32BPP;
130262306a36Sopenharmony_ci					break;
130362306a36Sopenharmony_ci				}
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci				num_banks = (rdev->config.si.tile_mode_array[index] >> 20) & 0x3;
130662306a36Sopenharmony_ci			}
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci			fb_format |= EVERGREEN_GRPH_NUM_BANKS(num_banks);
130962306a36Sopenharmony_ci		} else {
131062306a36Sopenharmony_ci			/* NI and older. */
131162306a36Sopenharmony_ci			if (rdev->family >= CHIP_CAYMAN)
131262306a36Sopenharmony_ci				tmp = rdev->config.cayman.tile_config;
131362306a36Sopenharmony_ci			else
131462306a36Sopenharmony_ci				tmp = rdev->config.evergreen.tile_config;
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci			switch ((tmp & 0xf0) >> 4) {
131762306a36Sopenharmony_ci			case 0: /* 4 banks */
131862306a36Sopenharmony_ci				fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_4_BANK);
131962306a36Sopenharmony_ci				break;
132062306a36Sopenharmony_ci			case 1: /* 8 banks */
132162306a36Sopenharmony_ci			default:
132262306a36Sopenharmony_ci				fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_8_BANK);
132362306a36Sopenharmony_ci				break;
132462306a36Sopenharmony_ci			case 2: /* 16 banks */
132562306a36Sopenharmony_ci				fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_16_BANK);
132662306a36Sopenharmony_ci				break;
132762306a36Sopenharmony_ci			}
132862306a36Sopenharmony_ci		}
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci		fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1);
133162306a36Sopenharmony_ci		fb_format |= EVERGREEN_GRPH_TILE_SPLIT(tile_split);
133262306a36Sopenharmony_ci		fb_format |= EVERGREEN_GRPH_BANK_WIDTH(bankw);
133362306a36Sopenharmony_ci		fb_format |= EVERGREEN_GRPH_BANK_HEIGHT(bankh);
133462306a36Sopenharmony_ci		fb_format |= EVERGREEN_GRPH_MACRO_TILE_ASPECT(mtaspect);
133562306a36Sopenharmony_ci		if (rdev->family >= CHIP_BONAIRE) {
133662306a36Sopenharmony_ci			/* XXX need to know more about the surface tiling mode */
133762306a36Sopenharmony_ci			fb_format |= CIK_GRPH_MICRO_TILE_MODE(CIK_DISPLAY_MICRO_TILING);
133862306a36Sopenharmony_ci		}
133962306a36Sopenharmony_ci	} else if (tiling_flags & RADEON_TILING_MICRO)
134062306a36Sopenharmony_ci		fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1);
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	if (rdev->family >= CHIP_BONAIRE) {
134362306a36Sopenharmony_ci		/* Read the pipe config from the 2D TILED SCANOUT mode.
134462306a36Sopenharmony_ci		 * It should be the same for the other modes too, but not all
134562306a36Sopenharmony_ci		 * modes set the pipe config field. */
134662306a36Sopenharmony_ci		u32 pipe_config = (rdev->config.cik.tile_mode_array[10] >> 6) & 0x1f;
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci		fb_format |= CIK_GRPH_PIPE_CONFIG(pipe_config);
134962306a36Sopenharmony_ci	} else if ((rdev->family == CHIP_TAHITI) ||
135062306a36Sopenharmony_ci		   (rdev->family == CHIP_PITCAIRN))
135162306a36Sopenharmony_ci		fb_format |= SI_GRPH_PIPE_CONFIG(SI_ADDR_SURF_P8_32x32_8x16);
135262306a36Sopenharmony_ci	else if ((rdev->family == CHIP_VERDE) ||
135362306a36Sopenharmony_ci		 (rdev->family == CHIP_OLAND) ||
135462306a36Sopenharmony_ci		 (rdev->family == CHIP_HAINAN)) /* for completeness.  HAINAN has no display hw */
135562306a36Sopenharmony_ci		fb_format |= SI_GRPH_PIPE_CONFIG(SI_ADDR_SURF_P4_8x16);
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	switch (radeon_crtc->crtc_id) {
135862306a36Sopenharmony_ci	case 0:
135962306a36Sopenharmony_ci		WREG32(AVIVO_D1VGA_CONTROL, 0);
136062306a36Sopenharmony_ci		break;
136162306a36Sopenharmony_ci	case 1:
136262306a36Sopenharmony_ci		WREG32(AVIVO_D2VGA_CONTROL, 0);
136362306a36Sopenharmony_ci		break;
136462306a36Sopenharmony_ci	case 2:
136562306a36Sopenharmony_ci		WREG32(EVERGREEN_D3VGA_CONTROL, 0);
136662306a36Sopenharmony_ci		break;
136762306a36Sopenharmony_ci	case 3:
136862306a36Sopenharmony_ci		WREG32(EVERGREEN_D4VGA_CONTROL, 0);
136962306a36Sopenharmony_ci		break;
137062306a36Sopenharmony_ci	case 4:
137162306a36Sopenharmony_ci		WREG32(EVERGREEN_D5VGA_CONTROL, 0);
137262306a36Sopenharmony_ci		break;
137362306a36Sopenharmony_ci	case 5:
137462306a36Sopenharmony_ci		WREG32(EVERGREEN_D6VGA_CONTROL, 0);
137562306a36Sopenharmony_ci		break;
137662306a36Sopenharmony_ci	default:
137762306a36Sopenharmony_ci		break;
137862306a36Sopenharmony_ci	}
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci	/* Make sure surface address is updated at vertical blank rather than
138162306a36Sopenharmony_ci	 * horizontal blank
138262306a36Sopenharmony_ci	 */
138362306a36Sopenharmony_ci	WREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, 0);
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
138662306a36Sopenharmony_ci	       upper_32_bits(fb_location));
138762306a36Sopenharmony_ci	WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
138862306a36Sopenharmony_ci	       upper_32_bits(fb_location));
138962306a36Sopenharmony_ci	WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
139062306a36Sopenharmony_ci	       (u32)fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK);
139162306a36Sopenharmony_ci	WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
139262306a36Sopenharmony_ci	       (u32) fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK);
139362306a36Sopenharmony_ci	WREG32(EVERGREEN_GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format);
139462306a36Sopenharmony_ci	WREG32(EVERGREEN_GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap);
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	/*
139762306a36Sopenharmony_ci	 * The LUT only has 256 slots for indexing by a 8 bpc fb. Bypass the LUT
139862306a36Sopenharmony_ci	 * for > 8 bpc scanout to avoid truncation of fb indices to 8 msb's, to
139962306a36Sopenharmony_ci	 * retain the full precision throughout the pipeline.
140062306a36Sopenharmony_ci	 */
140162306a36Sopenharmony_ci	WREG32_P(EVERGREEN_GRPH_LUT_10BIT_BYPASS_CONTROL + radeon_crtc->crtc_offset,
140262306a36Sopenharmony_ci		 (bypass_lut ? EVERGREEN_LUT_10BIT_BYPASS_EN : 0),
140362306a36Sopenharmony_ci		 ~EVERGREEN_LUT_10BIT_BYPASS_EN);
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	if (bypass_lut)
140662306a36Sopenharmony_ci		DRM_DEBUG_KMS("Bypassing hardware LUT due to 10 bit fb scanout.\n");
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci	WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0);
140962306a36Sopenharmony_ci	WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);
141062306a36Sopenharmony_ci	WREG32(EVERGREEN_GRPH_X_START + radeon_crtc->crtc_offset, 0);
141162306a36Sopenharmony_ci	WREG32(EVERGREEN_GRPH_Y_START + radeon_crtc->crtc_offset, 0);
141262306a36Sopenharmony_ci	WREG32(EVERGREEN_GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width);
141362306a36Sopenharmony_ci	WREG32(EVERGREEN_GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height);
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	fb_pitch_pixels = target_fb->pitches[0] / target_fb->format->cpp[0];
141662306a36Sopenharmony_ci	WREG32(EVERGREEN_GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels);
141762306a36Sopenharmony_ci	WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1);
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci	if (rdev->family >= CHIP_BONAIRE)
142062306a36Sopenharmony_ci		WREG32(CIK_LB_DESKTOP_HEIGHT + radeon_crtc->crtc_offset,
142162306a36Sopenharmony_ci		       target_fb->height);
142262306a36Sopenharmony_ci	else
142362306a36Sopenharmony_ci		WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset,
142462306a36Sopenharmony_ci		       target_fb->height);
142562306a36Sopenharmony_ci	x &= ~3;
142662306a36Sopenharmony_ci	y &= ~1;
142762306a36Sopenharmony_ci	WREG32(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset,
142862306a36Sopenharmony_ci	       (x << 16) | y);
142962306a36Sopenharmony_ci	viewport_w = crtc->mode.hdisplay;
143062306a36Sopenharmony_ci	viewport_h = (crtc->mode.vdisplay + 1) & ~1;
143162306a36Sopenharmony_ci	if ((rdev->family >= CHIP_BONAIRE) &&
143262306a36Sopenharmony_ci	    (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE))
143362306a36Sopenharmony_ci		viewport_h *= 2;
143462306a36Sopenharmony_ci	WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset,
143562306a36Sopenharmony_ci	       (viewport_w << 16) | viewport_h);
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	/* set pageflip to happen anywhere in vblank interval */
143862306a36Sopenharmony_ci	WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0);
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	if (!atomic && fb && fb != crtc->primary->fb) {
144162306a36Sopenharmony_ci		rbo = gem_to_radeon_bo(fb->obj[0]);
144262306a36Sopenharmony_ci		r = radeon_bo_reserve(rbo, false);
144362306a36Sopenharmony_ci		if (unlikely(r != 0))
144462306a36Sopenharmony_ci			return r;
144562306a36Sopenharmony_ci		radeon_bo_unpin(rbo);
144662306a36Sopenharmony_ci		radeon_bo_unreserve(rbo);
144762306a36Sopenharmony_ci	}
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	/* Bytes per pixel may have changed */
145062306a36Sopenharmony_ci	radeon_bandwidth_update(rdev);
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	return 0;
145362306a36Sopenharmony_ci}
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_cistatic int avivo_crtc_do_set_base(struct drm_crtc *crtc,
145662306a36Sopenharmony_ci				  struct drm_framebuffer *fb,
145762306a36Sopenharmony_ci				  int x, int y, int atomic)
145862306a36Sopenharmony_ci{
145962306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
146062306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
146162306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
146262306a36Sopenharmony_ci	struct drm_gem_object *obj;
146362306a36Sopenharmony_ci	struct radeon_bo *rbo;
146462306a36Sopenharmony_ci	struct drm_framebuffer *target_fb;
146562306a36Sopenharmony_ci	uint64_t fb_location;
146662306a36Sopenharmony_ci	uint32_t fb_format, fb_pitch_pixels, tiling_flags;
146762306a36Sopenharmony_ci	u32 fb_swap = R600_D1GRPH_SWAP_ENDIAN_NONE;
146862306a36Sopenharmony_ci	u32 viewport_w, viewport_h;
146962306a36Sopenharmony_ci	int r;
147062306a36Sopenharmony_ci	bool bypass_lut = false;
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	/* no fb bound */
147362306a36Sopenharmony_ci	if (!atomic && !crtc->primary->fb) {
147462306a36Sopenharmony_ci		DRM_DEBUG_KMS("No FB bound\n");
147562306a36Sopenharmony_ci		return 0;
147662306a36Sopenharmony_ci	}
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci	if (atomic)
147962306a36Sopenharmony_ci		target_fb = fb;
148062306a36Sopenharmony_ci	else
148162306a36Sopenharmony_ci		target_fb = crtc->primary->fb;
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	obj = target_fb->obj[0];
148462306a36Sopenharmony_ci	rbo = gem_to_radeon_bo(obj);
148562306a36Sopenharmony_ci	r = radeon_bo_reserve(rbo, false);
148662306a36Sopenharmony_ci	if (unlikely(r != 0))
148762306a36Sopenharmony_ci		return r;
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci	/* If atomic, assume fb object is pinned & idle & fenced and
149062306a36Sopenharmony_ci	 * just update base pointers
149162306a36Sopenharmony_ci	 */
149262306a36Sopenharmony_ci	if (atomic)
149362306a36Sopenharmony_ci		fb_location = radeon_bo_gpu_offset(rbo);
149462306a36Sopenharmony_ci	else {
149562306a36Sopenharmony_ci		r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
149662306a36Sopenharmony_ci		if (unlikely(r != 0)) {
149762306a36Sopenharmony_ci			radeon_bo_unreserve(rbo);
149862306a36Sopenharmony_ci			return -EINVAL;
149962306a36Sopenharmony_ci		}
150062306a36Sopenharmony_ci	}
150162306a36Sopenharmony_ci	radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
150262306a36Sopenharmony_ci	radeon_bo_unreserve(rbo);
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci	switch (target_fb->format->format) {
150562306a36Sopenharmony_ci	case DRM_FORMAT_C8:
150662306a36Sopenharmony_ci		fb_format =
150762306a36Sopenharmony_ci		    AVIVO_D1GRPH_CONTROL_DEPTH_8BPP |
150862306a36Sopenharmony_ci		    AVIVO_D1GRPH_CONTROL_8BPP_INDEXED;
150962306a36Sopenharmony_ci		break;
151062306a36Sopenharmony_ci	case DRM_FORMAT_XRGB4444:
151162306a36Sopenharmony_ci	case DRM_FORMAT_ARGB4444:
151262306a36Sopenharmony_ci		fb_format =
151362306a36Sopenharmony_ci		    AVIVO_D1GRPH_CONTROL_DEPTH_16BPP |
151462306a36Sopenharmony_ci		    AVIVO_D1GRPH_CONTROL_16BPP_ARGB4444;
151562306a36Sopenharmony_ci#ifdef __BIG_ENDIAN
151662306a36Sopenharmony_ci		fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT;
151762306a36Sopenharmony_ci#endif
151862306a36Sopenharmony_ci		break;
151962306a36Sopenharmony_ci	case DRM_FORMAT_XRGB1555:
152062306a36Sopenharmony_ci		fb_format =
152162306a36Sopenharmony_ci		    AVIVO_D1GRPH_CONTROL_DEPTH_16BPP |
152262306a36Sopenharmony_ci		    AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555;
152362306a36Sopenharmony_ci#ifdef __BIG_ENDIAN
152462306a36Sopenharmony_ci		fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT;
152562306a36Sopenharmony_ci#endif
152662306a36Sopenharmony_ci		break;
152762306a36Sopenharmony_ci	case DRM_FORMAT_RGB565:
152862306a36Sopenharmony_ci		fb_format =
152962306a36Sopenharmony_ci		    AVIVO_D1GRPH_CONTROL_DEPTH_16BPP |
153062306a36Sopenharmony_ci		    AVIVO_D1GRPH_CONTROL_16BPP_RGB565;
153162306a36Sopenharmony_ci#ifdef __BIG_ENDIAN
153262306a36Sopenharmony_ci		fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT;
153362306a36Sopenharmony_ci#endif
153462306a36Sopenharmony_ci		break;
153562306a36Sopenharmony_ci	case DRM_FORMAT_XRGB8888:
153662306a36Sopenharmony_ci	case DRM_FORMAT_ARGB8888:
153762306a36Sopenharmony_ci		fb_format =
153862306a36Sopenharmony_ci		    AVIVO_D1GRPH_CONTROL_DEPTH_32BPP |
153962306a36Sopenharmony_ci		    AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888;
154062306a36Sopenharmony_ci#ifdef __BIG_ENDIAN
154162306a36Sopenharmony_ci		fb_swap = R600_D1GRPH_SWAP_ENDIAN_32BIT;
154262306a36Sopenharmony_ci#endif
154362306a36Sopenharmony_ci		break;
154462306a36Sopenharmony_ci	case DRM_FORMAT_XRGB2101010:
154562306a36Sopenharmony_ci	case DRM_FORMAT_ARGB2101010:
154662306a36Sopenharmony_ci		fb_format =
154762306a36Sopenharmony_ci		    AVIVO_D1GRPH_CONTROL_DEPTH_32BPP |
154862306a36Sopenharmony_ci		    AVIVO_D1GRPH_CONTROL_32BPP_ARGB2101010;
154962306a36Sopenharmony_ci#ifdef __BIG_ENDIAN
155062306a36Sopenharmony_ci		fb_swap = R600_D1GRPH_SWAP_ENDIAN_32BIT;
155162306a36Sopenharmony_ci#endif
155262306a36Sopenharmony_ci		/* Greater 8 bpc fb needs to bypass hw-lut to retain precision */
155362306a36Sopenharmony_ci		bypass_lut = true;
155462306a36Sopenharmony_ci		break;
155562306a36Sopenharmony_ci	case DRM_FORMAT_XBGR8888:
155662306a36Sopenharmony_ci	case DRM_FORMAT_ABGR8888:
155762306a36Sopenharmony_ci		fb_format =
155862306a36Sopenharmony_ci		    AVIVO_D1GRPH_CONTROL_DEPTH_32BPP |
155962306a36Sopenharmony_ci		    AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888;
156062306a36Sopenharmony_ci		if (rdev->family >= CHIP_R600)
156162306a36Sopenharmony_ci			fb_swap =
156262306a36Sopenharmony_ci			    (R600_D1GRPH_RED_CROSSBAR(R600_D1GRPH_RED_SEL_B) |
156362306a36Sopenharmony_ci			     R600_D1GRPH_BLUE_CROSSBAR(R600_D1GRPH_BLUE_SEL_R));
156462306a36Sopenharmony_ci		else /* DCE1 (R5xx) */
156562306a36Sopenharmony_ci			fb_format |= AVIVO_D1GRPH_SWAP_RB;
156662306a36Sopenharmony_ci#ifdef __BIG_ENDIAN
156762306a36Sopenharmony_ci		fb_swap |= R600_D1GRPH_SWAP_ENDIAN_32BIT;
156862306a36Sopenharmony_ci#endif
156962306a36Sopenharmony_ci		break;
157062306a36Sopenharmony_ci	default:
157162306a36Sopenharmony_ci		DRM_ERROR("Unsupported screen format %p4cc\n",
157262306a36Sopenharmony_ci			  &target_fb->format->format);
157362306a36Sopenharmony_ci		return -EINVAL;
157462306a36Sopenharmony_ci	}
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	if (rdev->family >= CHIP_R600) {
157762306a36Sopenharmony_ci		if (tiling_flags & RADEON_TILING_MACRO)
157862306a36Sopenharmony_ci			fb_format |= R600_D1GRPH_ARRAY_MODE_2D_TILED_THIN1;
157962306a36Sopenharmony_ci		else if (tiling_flags & RADEON_TILING_MICRO)
158062306a36Sopenharmony_ci			fb_format |= R600_D1GRPH_ARRAY_MODE_1D_TILED_THIN1;
158162306a36Sopenharmony_ci	} else {
158262306a36Sopenharmony_ci		if (tiling_flags & RADEON_TILING_MACRO)
158362306a36Sopenharmony_ci			fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE;
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci		if (tiling_flags & RADEON_TILING_MICRO)
158662306a36Sopenharmony_ci			fb_format |= AVIVO_D1GRPH_TILED;
158762306a36Sopenharmony_ci	}
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	if (radeon_crtc->crtc_id == 0)
159062306a36Sopenharmony_ci		WREG32(AVIVO_D1VGA_CONTROL, 0);
159162306a36Sopenharmony_ci	else
159262306a36Sopenharmony_ci		WREG32(AVIVO_D2VGA_CONTROL, 0);
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	/* Make sure surface address is update at vertical blank rather than
159562306a36Sopenharmony_ci	 * horizontal blank
159662306a36Sopenharmony_ci	 */
159762306a36Sopenharmony_ci	WREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, 0);
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci	if (rdev->family >= CHIP_RV770) {
160062306a36Sopenharmony_ci		if (radeon_crtc->crtc_id) {
160162306a36Sopenharmony_ci			WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location));
160262306a36Sopenharmony_ci			WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location));
160362306a36Sopenharmony_ci		} else {
160462306a36Sopenharmony_ci			WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location));
160562306a36Sopenharmony_ci			WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location));
160662306a36Sopenharmony_ci		}
160762306a36Sopenharmony_ci	}
160862306a36Sopenharmony_ci	WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
160962306a36Sopenharmony_ci	       (u32) fb_location);
161062306a36Sopenharmony_ci	WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS +
161162306a36Sopenharmony_ci	       radeon_crtc->crtc_offset, (u32) fb_location);
161262306a36Sopenharmony_ci	WREG32(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format);
161362306a36Sopenharmony_ci	if (rdev->family >= CHIP_R600)
161462306a36Sopenharmony_ci		WREG32(R600_D1GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap);
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci	/* LUT only has 256 slots for 8 bpc fb. Bypass for > 8 bpc scanout for precision */
161762306a36Sopenharmony_ci	WREG32_P(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset,
161862306a36Sopenharmony_ci		 (bypass_lut ? AVIVO_LUT_10BIT_BYPASS_EN : 0), ~AVIVO_LUT_10BIT_BYPASS_EN);
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	if (bypass_lut)
162162306a36Sopenharmony_ci		DRM_DEBUG_KMS("Bypassing hardware LUT due to 10 bit fb scanout.\n");
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0);
162462306a36Sopenharmony_ci	WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);
162562306a36Sopenharmony_ci	WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0);
162662306a36Sopenharmony_ci	WREG32(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, 0);
162762306a36Sopenharmony_ci	WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width);
162862306a36Sopenharmony_ci	WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height);
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci	fb_pitch_pixels = target_fb->pitches[0] / target_fb->format->cpp[0];
163162306a36Sopenharmony_ci	WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels);
163262306a36Sopenharmony_ci	WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1);
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset,
163562306a36Sopenharmony_ci	       target_fb->height);
163662306a36Sopenharmony_ci	x &= ~3;
163762306a36Sopenharmony_ci	y &= ~1;
163862306a36Sopenharmony_ci	WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset,
163962306a36Sopenharmony_ci	       (x << 16) | y);
164062306a36Sopenharmony_ci	viewport_w = crtc->mode.hdisplay;
164162306a36Sopenharmony_ci	viewport_h = (crtc->mode.vdisplay + 1) & ~1;
164262306a36Sopenharmony_ci	WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset,
164362306a36Sopenharmony_ci	       (viewport_w << 16) | viewport_h);
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci	/* set pageflip to happen only at start of vblank interval (front porch) */
164662306a36Sopenharmony_ci	WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 3);
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	if (!atomic && fb && fb != crtc->primary->fb) {
164962306a36Sopenharmony_ci		rbo = gem_to_radeon_bo(fb->obj[0]);
165062306a36Sopenharmony_ci		r = radeon_bo_reserve(rbo, false);
165162306a36Sopenharmony_ci		if (unlikely(r != 0))
165262306a36Sopenharmony_ci			return r;
165362306a36Sopenharmony_ci		radeon_bo_unpin(rbo);
165462306a36Sopenharmony_ci		radeon_bo_unreserve(rbo);
165562306a36Sopenharmony_ci	}
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci	/* Bytes per pixel may have changed */
165862306a36Sopenharmony_ci	radeon_bandwidth_update(rdev);
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci	return 0;
166162306a36Sopenharmony_ci}
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ciint atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
166462306a36Sopenharmony_ci			   struct drm_framebuffer *old_fb)
166562306a36Sopenharmony_ci{
166662306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
166762306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci	if (ASIC_IS_DCE4(rdev))
167062306a36Sopenharmony_ci		return dce4_crtc_do_set_base(crtc, old_fb, x, y, 0);
167162306a36Sopenharmony_ci	else if (ASIC_IS_AVIVO(rdev))
167262306a36Sopenharmony_ci		return avivo_crtc_do_set_base(crtc, old_fb, x, y, 0);
167362306a36Sopenharmony_ci	else
167462306a36Sopenharmony_ci		return radeon_crtc_do_set_base(crtc, old_fb, x, y, 0);
167562306a36Sopenharmony_ci}
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ciint atombios_crtc_set_base_atomic(struct drm_crtc *crtc,
167862306a36Sopenharmony_ci				  struct drm_framebuffer *fb,
167962306a36Sopenharmony_ci				  int x, int y, enum mode_set_atomic state)
168062306a36Sopenharmony_ci{
168162306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
168262306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	if (ASIC_IS_DCE4(rdev))
168562306a36Sopenharmony_ci		return dce4_crtc_do_set_base(crtc, fb, x, y, 1);
168662306a36Sopenharmony_ci	else if (ASIC_IS_AVIVO(rdev))
168762306a36Sopenharmony_ci		return avivo_crtc_do_set_base(crtc, fb, x, y, 1);
168862306a36Sopenharmony_ci	else
168962306a36Sopenharmony_ci		return radeon_crtc_do_set_base(crtc, fb, x, y, 1);
169062306a36Sopenharmony_ci}
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci/* properly set additional regs when using atombios */
169362306a36Sopenharmony_cistatic void radeon_legacy_atom_fixup(struct drm_crtc *crtc)
169462306a36Sopenharmony_ci{
169562306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
169662306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
169762306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
169862306a36Sopenharmony_ci	u32 disp_merge_cntl;
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	switch (radeon_crtc->crtc_id) {
170162306a36Sopenharmony_ci	case 0:
170262306a36Sopenharmony_ci		disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL);
170362306a36Sopenharmony_ci		disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN;
170462306a36Sopenharmony_ci		WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl);
170562306a36Sopenharmony_ci		break;
170662306a36Sopenharmony_ci	case 1:
170762306a36Sopenharmony_ci		disp_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL);
170862306a36Sopenharmony_ci		disp_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN;
170962306a36Sopenharmony_ci		WREG32(RADEON_DISP2_MERGE_CNTL, disp_merge_cntl);
171062306a36Sopenharmony_ci		WREG32(RADEON_FP_H2_SYNC_STRT_WID,   RREG32(RADEON_CRTC2_H_SYNC_STRT_WID));
171162306a36Sopenharmony_ci		WREG32(RADEON_FP_V2_SYNC_STRT_WID,   RREG32(RADEON_CRTC2_V_SYNC_STRT_WID));
171262306a36Sopenharmony_ci		break;
171362306a36Sopenharmony_ci	}
171462306a36Sopenharmony_ci}
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci/**
171762306a36Sopenharmony_ci * radeon_get_pll_use_mask - look up a mask of which pplls are in use
171862306a36Sopenharmony_ci *
171962306a36Sopenharmony_ci * @crtc: drm crtc
172062306a36Sopenharmony_ci *
172162306a36Sopenharmony_ci * Returns the mask of which PPLLs (Pixel PLLs) are in use.
172262306a36Sopenharmony_ci */
172362306a36Sopenharmony_cistatic u32 radeon_get_pll_use_mask(struct drm_crtc *crtc)
172462306a36Sopenharmony_ci{
172562306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
172662306a36Sopenharmony_ci	struct drm_crtc *test_crtc;
172762306a36Sopenharmony_ci	struct radeon_crtc *test_radeon_crtc;
172862306a36Sopenharmony_ci	u32 pll_in_use = 0;
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci	list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
173162306a36Sopenharmony_ci		if (crtc == test_crtc)
173262306a36Sopenharmony_ci			continue;
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci		test_radeon_crtc = to_radeon_crtc(test_crtc);
173562306a36Sopenharmony_ci		if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID)
173662306a36Sopenharmony_ci			pll_in_use |= (1 << test_radeon_crtc->pll_id);
173762306a36Sopenharmony_ci	}
173862306a36Sopenharmony_ci	return pll_in_use;
173962306a36Sopenharmony_ci}
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci/**
174262306a36Sopenharmony_ci * radeon_get_shared_dp_ppll - return the PPLL used by another crtc for DP
174362306a36Sopenharmony_ci *
174462306a36Sopenharmony_ci * @crtc: drm crtc
174562306a36Sopenharmony_ci *
174662306a36Sopenharmony_ci * Returns the PPLL (Pixel PLL) used by another crtc/encoder which is
174762306a36Sopenharmony_ci * also in DP mode.  For DP, a single PPLL can be used for all DP
174862306a36Sopenharmony_ci * crtcs/encoders.
174962306a36Sopenharmony_ci */
175062306a36Sopenharmony_cistatic int radeon_get_shared_dp_ppll(struct drm_crtc *crtc)
175162306a36Sopenharmony_ci{
175262306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
175362306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
175462306a36Sopenharmony_ci	struct drm_crtc *test_crtc;
175562306a36Sopenharmony_ci	struct radeon_crtc *test_radeon_crtc;
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
175862306a36Sopenharmony_ci		if (crtc == test_crtc)
175962306a36Sopenharmony_ci			continue;
176062306a36Sopenharmony_ci		test_radeon_crtc = to_radeon_crtc(test_crtc);
176162306a36Sopenharmony_ci		if (test_radeon_crtc->encoder &&
176262306a36Sopenharmony_ci		    ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_radeon_crtc->encoder))) {
176362306a36Sopenharmony_ci			/* PPLL2 is exclusive to UNIPHYA on DCE61 */
176462306a36Sopenharmony_ci			if (ASIC_IS_DCE61(rdev) && !ASIC_IS_DCE8(rdev) &&
176562306a36Sopenharmony_ci			    test_radeon_crtc->pll_id == ATOM_PPLL2)
176662306a36Sopenharmony_ci				continue;
176762306a36Sopenharmony_ci			/* for DP use the same PLL for all */
176862306a36Sopenharmony_ci			if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID)
176962306a36Sopenharmony_ci				return test_radeon_crtc->pll_id;
177062306a36Sopenharmony_ci		}
177162306a36Sopenharmony_ci	}
177262306a36Sopenharmony_ci	return ATOM_PPLL_INVALID;
177362306a36Sopenharmony_ci}
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci/**
177662306a36Sopenharmony_ci * radeon_get_shared_nondp_ppll - return the PPLL used by another non-DP crtc
177762306a36Sopenharmony_ci *
177862306a36Sopenharmony_ci * @crtc: drm crtc
177962306a36Sopenharmony_ci *
178062306a36Sopenharmony_ci * Returns the PPLL (Pixel PLL) used by another non-DP crtc/encoder which can
178162306a36Sopenharmony_ci * be shared (i.e., same clock).
178262306a36Sopenharmony_ci */
178362306a36Sopenharmony_cistatic int radeon_get_shared_nondp_ppll(struct drm_crtc *crtc)
178462306a36Sopenharmony_ci{
178562306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
178662306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
178762306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
178862306a36Sopenharmony_ci	struct drm_crtc *test_crtc;
178962306a36Sopenharmony_ci	struct radeon_crtc *test_radeon_crtc;
179062306a36Sopenharmony_ci	u32 adjusted_clock, test_adjusted_clock;
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	adjusted_clock = radeon_crtc->adjusted_clock;
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci	if (adjusted_clock == 0)
179562306a36Sopenharmony_ci		return ATOM_PPLL_INVALID;
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
179862306a36Sopenharmony_ci		if (crtc == test_crtc)
179962306a36Sopenharmony_ci			continue;
180062306a36Sopenharmony_ci		test_radeon_crtc = to_radeon_crtc(test_crtc);
180162306a36Sopenharmony_ci		if (test_radeon_crtc->encoder &&
180262306a36Sopenharmony_ci		    !ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_radeon_crtc->encoder))) {
180362306a36Sopenharmony_ci			/* PPLL2 is exclusive to UNIPHYA on DCE61 */
180462306a36Sopenharmony_ci			if (ASIC_IS_DCE61(rdev) && !ASIC_IS_DCE8(rdev) &&
180562306a36Sopenharmony_ci			    test_radeon_crtc->pll_id == ATOM_PPLL2)
180662306a36Sopenharmony_ci				continue;
180762306a36Sopenharmony_ci			/* check if we are already driving this connector with another crtc */
180862306a36Sopenharmony_ci			if (test_radeon_crtc->connector == radeon_crtc->connector) {
180962306a36Sopenharmony_ci				/* if we are, return that pll */
181062306a36Sopenharmony_ci				if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID)
181162306a36Sopenharmony_ci					return test_radeon_crtc->pll_id;
181262306a36Sopenharmony_ci			}
181362306a36Sopenharmony_ci			/* for non-DP check the clock */
181462306a36Sopenharmony_ci			test_adjusted_clock = test_radeon_crtc->adjusted_clock;
181562306a36Sopenharmony_ci			if ((crtc->mode.clock == test_crtc->mode.clock) &&
181662306a36Sopenharmony_ci			    (adjusted_clock == test_adjusted_clock) &&
181762306a36Sopenharmony_ci			    (radeon_crtc->ss_enabled == test_radeon_crtc->ss_enabled) &&
181862306a36Sopenharmony_ci			    (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID))
181962306a36Sopenharmony_ci				return test_radeon_crtc->pll_id;
182062306a36Sopenharmony_ci		}
182162306a36Sopenharmony_ci	}
182262306a36Sopenharmony_ci	return ATOM_PPLL_INVALID;
182362306a36Sopenharmony_ci}
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci/**
182662306a36Sopenharmony_ci * radeon_atom_pick_pll - Allocate a PPLL for use by the crtc.
182762306a36Sopenharmony_ci *
182862306a36Sopenharmony_ci * @crtc: drm crtc
182962306a36Sopenharmony_ci *
183062306a36Sopenharmony_ci * Returns the PPLL (Pixel PLL) to be used by the crtc.  For DP monitors
183162306a36Sopenharmony_ci * a single PPLL can be used for all DP crtcs/encoders.  For non-DP
183262306a36Sopenharmony_ci * monitors a dedicated PPLL must be used.  If a particular board has
183362306a36Sopenharmony_ci * an external DP PLL, return ATOM_PPLL_INVALID to skip PLL programming
183462306a36Sopenharmony_ci * as there is no need to program the PLL itself.  If we are not able to
183562306a36Sopenharmony_ci * allocate a PLL, return ATOM_PPLL_INVALID to skip PLL programming to
183662306a36Sopenharmony_ci * avoid messing up an existing monitor.
183762306a36Sopenharmony_ci *
183862306a36Sopenharmony_ci * Asic specific PLL information
183962306a36Sopenharmony_ci *
184062306a36Sopenharmony_ci * DCE 8.x
184162306a36Sopenharmony_ci * KB/KV
184262306a36Sopenharmony_ci * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP)
184362306a36Sopenharmony_ci * CI
184462306a36Sopenharmony_ci * - PPLL0, PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC
184562306a36Sopenharmony_ci *
184662306a36Sopenharmony_ci * DCE 6.1
184762306a36Sopenharmony_ci * - PPLL2 is only available to UNIPHYA (both DP and non-DP)
184862306a36Sopenharmony_ci * - PPLL0, PPLL1 are available for UNIPHYB/C/D/E/F (both DP and non-DP)
184962306a36Sopenharmony_ci *
185062306a36Sopenharmony_ci * DCE 6.0
185162306a36Sopenharmony_ci * - PPLL0 is available to all UNIPHY (DP only)
185262306a36Sopenharmony_ci * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC
185362306a36Sopenharmony_ci *
185462306a36Sopenharmony_ci * DCE 5.0
185562306a36Sopenharmony_ci * - DCPLL is available to all UNIPHY (DP only)
185662306a36Sopenharmony_ci * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC
185762306a36Sopenharmony_ci *
185862306a36Sopenharmony_ci * DCE 3.0/4.0/4.1
185962306a36Sopenharmony_ci * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC
186062306a36Sopenharmony_ci *
186162306a36Sopenharmony_ci */
186262306a36Sopenharmony_cistatic int radeon_atom_pick_pll(struct drm_crtc *crtc)
186362306a36Sopenharmony_ci{
186462306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
186562306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
186662306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
186762306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder =
186862306a36Sopenharmony_ci		to_radeon_encoder(radeon_crtc->encoder);
186962306a36Sopenharmony_ci	u32 pll_in_use;
187062306a36Sopenharmony_ci	int pll;
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_ci	if (ASIC_IS_DCE8(rdev)) {
187362306a36Sopenharmony_ci		if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) {
187462306a36Sopenharmony_ci			if (rdev->clock.dp_extclk)
187562306a36Sopenharmony_ci				/* skip PPLL programming if using ext clock */
187662306a36Sopenharmony_ci				return ATOM_PPLL_INVALID;
187762306a36Sopenharmony_ci			else {
187862306a36Sopenharmony_ci				/* use the same PPLL for all DP monitors */
187962306a36Sopenharmony_ci				pll = radeon_get_shared_dp_ppll(crtc);
188062306a36Sopenharmony_ci				if (pll != ATOM_PPLL_INVALID)
188162306a36Sopenharmony_ci					return pll;
188262306a36Sopenharmony_ci			}
188362306a36Sopenharmony_ci		} else {
188462306a36Sopenharmony_ci			/* use the same PPLL for all monitors with the same clock */
188562306a36Sopenharmony_ci			pll = radeon_get_shared_nondp_ppll(crtc);
188662306a36Sopenharmony_ci			if (pll != ATOM_PPLL_INVALID)
188762306a36Sopenharmony_ci				return pll;
188862306a36Sopenharmony_ci		}
188962306a36Sopenharmony_ci		/* otherwise, pick one of the plls */
189062306a36Sopenharmony_ci		if ((rdev->family == CHIP_KABINI) ||
189162306a36Sopenharmony_ci		    (rdev->family == CHIP_MULLINS)) {
189262306a36Sopenharmony_ci			/* KB/ML has PPLL1 and PPLL2 */
189362306a36Sopenharmony_ci			pll_in_use = radeon_get_pll_use_mask(crtc);
189462306a36Sopenharmony_ci			if (!(pll_in_use & (1 << ATOM_PPLL2)))
189562306a36Sopenharmony_ci				return ATOM_PPLL2;
189662306a36Sopenharmony_ci			if (!(pll_in_use & (1 << ATOM_PPLL1)))
189762306a36Sopenharmony_ci				return ATOM_PPLL1;
189862306a36Sopenharmony_ci			DRM_ERROR("unable to allocate a PPLL\n");
189962306a36Sopenharmony_ci			return ATOM_PPLL_INVALID;
190062306a36Sopenharmony_ci		} else {
190162306a36Sopenharmony_ci			/* CI/KV has PPLL0, PPLL1, and PPLL2 */
190262306a36Sopenharmony_ci			pll_in_use = radeon_get_pll_use_mask(crtc);
190362306a36Sopenharmony_ci			if (!(pll_in_use & (1 << ATOM_PPLL2)))
190462306a36Sopenharmony_ci				return ATOM_PPLL2;
190562306a36Sopenharmony_ci			if (!(pll_in_use & (1 << ATOM_PPLL1)))
190662306a36Sopenharmony_ci				return ATOM_PPLL1;
190762306a36Sopenharmony_ci			if (!(pll_in_use & (1 << ATOM_PPLL0)))
190862306a36Sopenharmony_ci				return ATOM_PPLL0;
190962306a36Sopenharmony_ci			DRM_ERROR("unable to allocate a PPLL\n");
191062306a36Sopenharmony_ci			return ATOM_PPLL_INVALID;
191162306a36Sopenharmony_ci		}
191262306a36Sopenharmony_ci	} else if (ASIC_IS_DCE61(rdev)) {
191362306a36Sopenharmony_ci		struct radeon_encoder_atom_dig *dig =
191462306a36Sopenharmony_ci			radeon_encoder->enc_priv;
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci		if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY) &&
191762306a36Sopenharmony_ci		    (dig->linkb == false))
191862306a36Sopenharmony_ci			/* UNIPHY A uses PPLL2 */
191962306a36Sopenharmony_ci			return ATOM_PPLL2;
192062306a36Sopenharmony_ci		else if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) {
192162306a36Sopenharmony_ci			/* UNIPHY B/C/D/E/F */
192262306a36Sopenharmony_ci			if (rdev->clock.dp_extclk)
192362306a36Sopenharmony_ci				/* skip PPLL programming if using ext clock */
192462306a36Sopenharmony_ci				return ATOM_PPLL_INVALID;
192562306a36Sopenharmony_ci			else {
192662306a36Sopenharmony_ci				/* use the same PPLL for all DP monitors */
192762306a36Sopenharmony_ci				pll = radeon_get_shared_dp_ppll(crtc);
192862306a36Sopenharmony_ci				if (pll != ATOM_PPLL_INVALID)
192962306a36Sopenharmony_ci					return pll;
193062306a36Sopenharmony_ci			}
193162306a36Sopenharmony_ci		} else {
193262306a36Sopenharmony_ci			/* use the same PPLL for all monitors with the same clock */
193362306a36Sopenharmony_ci			pll = radeon_get_shared_nondp_ppll(crtc);
193462306a36Sopenharmony_ci			if (pll != ATOM_PPLL_INVALID)
193562306a36Sopenharmony_ci				return pll;
193662306a36Sopenharmony_ci		}
193762306a36Sopenharmony_ci		/* UNIPHY B/C/D/E/F */
193862306a36Sopenharmony_ci		pll_in_use = radeon_get_pll_use_mask(crtc);
193962306a36Sopenharmony_ci		if (!(pll_in_use & (1 << ATOM_PPLL0)))
194062306a36Sopenharmony_ci			return ATOM_PPLL0;
194162306a36Sopenharmony_ci		if (!(pll_in_use & (1 << ATOM_PPLL1)))
194262306a36Sopenharmony_ci			return ATOM_PPLL1;
194362306a36Sopenharmony_ci		DRM_ERROR("unable to allocate a PPLL\n");
194462306a36Sopenharmony_ci		return ATOM_PPLL_INVALID;
194562306a36Sopenharmony_ci	} else if (ASIC_IS_DCE41(rdev)) {
194662306a36Sopenharmony_ci		/* Don't share PLLs on DCE4.1 chips */
194762306a36Sopenharmony_ci		if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) {
194862306a36Sopenharmony_ci			if (rdev->clock.dp_extclk)
194962306a36Sopenharmony_ci				/* skip PPLL programming if using ext clock */
195062306a36Sopenharmony_ci				return ATOM_PPLL_INVALID;
195162306a36Sopenharmony_ci		}
195262306a36Sopenharmony_ci		pll_in_use = radeon_get_pll_use_mask(crtc);
195362306a36Sopenharmony_ci		if (!(pll_in_use & (1 << ATOM_PPLL1)))
195462306a36Sopenharmony_ci			return ATOM_PPLL1;
195562306a36Sopenharmony_ci		if (!(pll_in_use & (1 << ATOM_PPLL2)))
195662306a36Sopenharmony_ci			return ATOM_PPLL2;
195762306a36Sopenharmony_ci		DRM_ERROR("unable to allocate a PPLL\n");
195862306a36Sopenharmony_ci		return ATOM_PPLL_INVALID;
195962306a36Sopenharmony_ci	} else if (ASIC_IS_DCE4(rdev)) {
196062306a36Sopenharmony_ci		/* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock,
196162306a36Sopenharmony_ci		 * depending on the asic:
196262306a36Sopenharmony_ci		 * DCE4: PPLL or ext clock
196362306a36Sopenharmony_ci		 * DCE5: PPLL, DCPLL, or ext clock
196462306a36Sopenharmony_ci		 * DCE6: PPLL, PPLL0, or ext clock
196562306a36Sopenharmony_ci		 *
196662306a36Sopenharmony_ci		 * Setting ATOM_PPLL_INVALID will cause SetPixelClock to skip
196762306a36Sopenharmony_ci		 * PPLL/DCPLL programming and only program the DP DTO for the
196862306a36Sopenharmony_ci		 * crtc virtual pixel clock.
196962306a36Sopenharmony_ci		 */
197062306a36Sopenharmony_ci		if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) {
197162306a36Sopenharmony_ci			if (rdev->clock.dp_extclk)
197262306a36Sopenharmony_ci				/* skip PPLL programming if using ext clock */
197362306a36Sopenharmony_ci				return ATOM_PPLL_INVALID;
197462306a36Sopenharmony_ci			else if (ASIC_IS_DCE6(rdev))
197562306a36Sopenharmony_ci				/* use PPLL0 for all DP */
197662306a36Sopenharmony_ci				return ATOM_PPLL0;
197762306a36Sopenharmony_ci			else if (ASIC_IS_DCE5(rdev))
197862306a36Sopenharmony_ci				/* use DCPLL for all DP */
197962306a36Sopenharmony_ci				return ATOM_DCPLL;
198062306a36Sopenharmony_ci			else {
198162306a36Sopenharmony_ci				/* use the same PPLL for all DP monitors */
198262306a36Sopenharmony_ci				pll = radeon_get_shared_dp_ppll(crtc);
198362306a36Sopenharmony_ci				if (pll != ATOM_PPLL_INVALID)
198462306a36Sopenharmony_ci					return pll;
198562306a36Sopenharmony_ci			}
198662306a36Sopenharmony_ci		} else {
198762306a36Sopenharmony_ci			/* use the same PPLL for all monitors with the same clock */
198862306a36Sopenharmony_ci			pll = radeon_get_shared_nondp_ppll(crtc);
198962306a36Sopenharmony_ci			if (pll != ATOM_PPLL_INVALID)
199062306a36Sopenharmony_ci				return pll;
199162306a36Sopenharmony_ci		}
199262306a36Sopenharmony_ci		/* all other cases */
199362306a36Sopenharmony_ci		pll_in_use = radeon_get_pll_use_mask(crtc);
199462306a36Sopenharmony_ci		if (!(pll_in_use & (1 << ATOM_PPLL1)))
199562306a36Sopenharmony_ci			return ATOM_PPLL1;
199662306a36Sopenharmony_ci		if (!(pll_in_use & (1 << ATOM_PPLL2)))
199762306a36Sopenharmony_ci			return ATOM_PPLL2;
199862306a36Sopenharmony_ci		DRM_ERROR("unable to allocate a PPLL\n");
199962306a36Sopenharmony_ci		return ATOM_PPLL_INVALID;
200062306a36Sopenharmony_ci	} else {
200162306a36Sopenharmony_ci		/* on pre-R5xx asics, the crtc to pll mapping is hardcoded */
200262306a36Sopenharmony_ci		/* some atombios (observed in some DCE2/DCE3) code have a bug,
200362306a36Sopenharmony_ci		 * the matching btw pll and crtc is done through
200462306a36Sopenharmony_ci		 * PCLK_CRTC[1|2]_CNTL (0x480/0x484) but atombios code use the
200562306a36Sopenharmony_ci		 * pll (1 or 2) to select which register to write. ie if using
200662306a36Sopenharmony_ci		 * pll1 it will use PCLK_CRTC1_CNTL (0x480) and if using pll2
200762306a36Sopenharmony_ci		 * it will use PCLK_CRTC2_CNTL (0x484), it then use crtc id to
200862306a36Sopenharmony_ci		 * choose which value to write. Which is reverse order from
200962306a36Sopenharmony_ci		 * register logic. So only case that works is when pllid is
201062306a36Sopenharmony_ci		 * same as crtcid or when both pll and crtc are enabled and
201162306a36Sopenharmony_ci		 * both use same clock.
201262306a36Sopenharmony_ci		 *
201362306a36Sopenharmony_ci		 * So just return crtc id as if crtc and pll were hard linked
201462306a36Sopenharmony_ci		 * together even if they aren't
201562306a36Sopenharmony_ci		 */
201662306a36Sopenharmony_ci		return radeon_crtc->crtc_id;
201762306a36Sopenharmony_ci	}
201862306a36Sopenharmony_ci}
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_civoid radeon_atom_disp_eng_pll_init(struct radeon_device *rdev)
202162306a36Sopenharmony_ci{
202262306a36Sopenharmony_ci	/* always set DCPLL */
202362306a36Sopenharmony_ci	if (ASIC_IS_DCE6(rdev))
202462306a36Sopenharmony_ci		atombios_crtc_set_disp_eng_pll(rdev, rdev->clock.default_dispclk);
202562306a36Sopenharmony_ci	else if (ASIC_IS_DCE4(rdev)) {
202662306a36Sopenharmony_ci		struct radeon_atom_ss ss;
202762306a36Sopenharmony_ci		bool ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &ss,
202862306a36Sopenharmony_ci								   ASIC_INTERNAL_SS_ON_DCPLL,
202962306a36Sopenharmony_ci								   rdev->clock.default_dispclk);
203062306a36Sopenharmony_ci		if (ss_enabled)
203162306a36Sopenharmony_ci			atombios_crtc_program_ss(rdev, ATOM_DISABLE, ATOM_DCPLL, -1, &ss);
203262306a36Sopenharmony_ci		/* XXX: DCE5, make sure voltage, dispclk is high enough */
203362306a36Sopenharmony_ci		atombios_crtc_set_disp_eng_pll(rdev, rdev->clock.default_dispclk);
203462306a36Sopenharmony_ci		if (ss_enabled)
203562306a36Sopenharmony_ci			atombios_crtc_program_ss(rdev, ATOM_ENABLE, ATOM_DCPLL, -1, &ss);
203662306a36Sopenharmony_ci	}
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci}
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ciint atombios_crtc_mode_set(struct drm_crtc *crtc,
204162306a36Sopenharmony_ci			   struct drm_display_mode *mode,
204262306a36Sopenharmony_ci			   struct drm_display_mode *adjusted_mode,
204362306a36Sopenharmony_ci			   int x, int y, struct drm_framebuffer *old_fb)
204462306a36Sopenharmony_ci{
204562306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
204662306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
204762306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
204862306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder =
204962306a36Sopenharmony_ci		to_radeon_encoder(radeon_crtc->encoder);
205062306a36Sopenharmony_ci	bool is_tvcv = false;
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci	if (radeon_encoder->active_device &
205362306a36Sopenharmony_ci	    (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT))
205462306a36Sopenharmony_ci		is_tvcv = true;
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	if (!radeon_crtc->adjusted_clock)
205762306a36Sopenharmony_ci		return -EINVAL;
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci	atombios_crtc_set_pll(crtc, adjusted_mode);
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci	if (ASIC_IS_DCE4(rdev))
206262306a36Sopenharmony_ci		atombios_set_crtc_dtd_timing(crtc, adjusted_mode);
206362306a36Sopenharmony_ci	else if (ASIC_IS_AVIVO(rdev)) {
206462306a36Sopenharmony_ci		if (is_tvcv)
206562306a36Sopenharmony_ci			atombios_crtc_set_timing(crtc, adjusted_mode);
206662306a36Sopenharmony_ci		else
206762306a36Sopenharmony_ci			atombios_set_crtc_dtd_timing(crtc, adjusted_mode);
206862306a36Sopenharmony_ci	} else {
206962306a36Sopenharmony_ci		atombios_crtc_set_timing(crtc, adjusted_mode);
207062306a36Sopenharmony_ci		if (radeon_crtc->crtc_id == 0)
207162306a36Sopenharmony_ci			atombios_set_crtc_dtd_timing(crtc, adjusted_mode);
207262306a36Sopenharmony_ci		radeon_legacy_atom_fixup(crtc);
207362306a36Sopenharmony_ci	}
207462306a36Sopenharmony_ci	atombios_crtc_set_base(crtc, x, y, old_fb);
207562306a36Sopenharmony_ci	atombios_overscan_setup(crtc, mode, adjusted_mode);
207662306a36Sopenharmony_ci	atombios_scaler_setup(crtc);
207762306a36Sopenharmony_ci	radeon_cursor_reset(crtc);
207862306a36Sopenharmony_ci	/* update the hw version fpr dpm */
207962306a36Sopenharmony_ci	radeon_crtc->hw_mode = *adjusted_mode;
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_ci	return 0;
208262306a36Sopenharmony_ci}
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_cistatic bool atombios_crtc_mode_fixup(struct drm_crtc *crtc,
208562306a36Sopenharmony_ci				     const struct drm_display_mode *mode,
208662306a36Sopenharmony_ci				     struct drm_display_mode *adjusted_mode)
208762306a36Sopenharmony_ci{
208862306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
208962306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
209062306a36Sopenharmony_ci	struct drm_encoder *encoder;
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ci	/* assign the encoder to the radeon crtc to avoid repeated lookups later */
209362306a36Sopenharmony_ci	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
209462306a36Sopenharmony_ci		if (encoder->crtc == crtc) {
209562306a36Sopenharmony_ci			radeon_crtc->encoder = encoder;
209662306a36Sopenharmony_ci			radeon_crtc->connector = radeon_get_connector_for_encoder(encoder);
209762306a36Sopenharmony_ci			break;
209862306a36Sopenharmony_ci		}
209962306a36Sopenharmony_ci	}
210062306a36Sopenharmony_ci	if ((radeon_crtc->encoder == NULL) || (radeon_crtc->connector == NULL)) {
210162306a36Sopenharmony_ci		radeon_crtc->encoder = NULL;
210262306a36Sopenharmony_ci		radeon_crtc->connector = NULL;
210362306a36Sopenharmony_ci		return false;
210462306a36Sopenharmony_ci	}
210562306a36Sopenharmony_ci	if (radeon_crtc->encoder) {
210662306a36Sopenharmony_ci		struct radeon_encoder *radeon_encoder =
210762306a36Sopenharmony_ci			to_radeon_encoder(radeon_crtc->encoder);
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_ci		radeon_crtc->output_csc = radeon_encoder->output_csc;
211062306a36Sopenharmony_ci	}
211162306a36Sopenharmony_ci	if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode))
211262306a36Sopenharmony_ci		return false;
211362306a36Sopenharmony_ci	if (!atombios_crtc_prepare_pll(crtc, adjusted_mode))
211462306a36Sopenharmony_ci		return false;
211562306a36Sopenharmony_ci	/* pick pll */
211662306a36Sopenharmony_ci	radeon_crtc->pll_id = radeon_atom_pick_pll(crtc);
211762306a36Sopenharmony_ci	/* if we can't get a PPLL for a non-DP encoder, fail */
211862306a36Sopenharmony_ci	if ((radeon_crtc->pll_id == ATOM_PPLL_INVALID) &&
211962306a36Sopenharmony_ci	    !ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder)))
212062306a36Sopenharmony_ci		return false;
212162306a36Sopenharmony_ci
212262306a36Sopenharmony_ci	return true;
212362306a36Sopenharmony_ci}
212462306a36Sopenharmony_ci
212562306a36Sopenharmony_cistatic void atombios_crtc_prepare(struct drm_crtc *crtc)
212662306a36Sopenharmony_ci{
212762306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
212862306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci	/* disable crtc pair power gating before programming */
213162306a36Sopenharmony_ci	if (ASIC_IS_DCE6(rdev))
213262306a36Sopenharmony_ci		atombios_powergate_crtc(crtc, ATOM_DISABLE);
213362306a36Sopenharmony_ci
213462306a36Sopenharmony_ci	atombios_lock_crtc(crtc, ATOM_ENABLE);
213562306a36Sopenharmony_ci	atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
213662306a36Sopenharmony_ci}
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_cistatic void atombios_crtc_commit(struct drm_crtc *crtc)
213962306a36Sopenharmony_ci{
214062306a36Sopenharmony_ci	atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
214162306a36Sopenharmony_ci	atombios_lock_crtc(crtc, ATOM_DISABLE);
214262306a36Sopenharmony_ci}
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_cistatic void atombios_crtc_disable(struct drm_crtc *crtc)
214562306a36Sopenharmony_ci{
214662306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
214762306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
214862306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
214962306a36Sopenharmony_ci	struct radeon_atom_ss ss;
215062306a36Sopenharmony_ci	int i;
215162306a36Sopenharmony_ci
215262306a36Sopenharmony_ci	atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
215362306a36Sopenharmony_ci	if (crtc->primary->fb) {
215462306a36Sopenharmony_ci		int r;
215562306a36Sopenharmony_ci		struct radeon_bo *rbo;
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci		rbo = gem_to_radeon_bo(crtc->primary->fb->obj[0]);
215862306a36Sopenharmony_ci		r = radeon_bo_reserve(rbo, false);
215962306a36Sopenharmony_ci		if (unlikely(r))
216062306a36Sopenharmony_ci			DRM_ERROR("failed to reserve rbo before unpin\n");
216162306a36Sopenharmony_ci		else {
216262306a36Sopenharmony_ci			radeon_bo_unpin(rbo);
216362306a36Sopenharmony_ci			radeon_bo_unreserve(rbo);
216462306a36Sopenharmony_ci		}
216562306a36Sopenharmony_ci	}
216662306a36Sopenharmony_ci	/* disable the GRPH */
216762306a36Sopenharmony_ci	if (ASIC_IS_DCE4(rdev))
216862306a36Sopenharmony_ci		WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 0);
216962306a36Sopenharmony_ci	else if (ASIC_IS_AVIVO(rdev))
217062306a36Sopenharmony_ci		WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 0);
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_ci	if (ASIC_IS_DCE6(rdev))
217362306a36Sopenharmony_ci		atombios_powergate_crtc(crtc, ATOM_ENABLE);
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ci	for (i = 0; i < rdev->num_crtc; i++) {
217662306a36Sopenharmony_ci		if (rdev->mode_info.crtcs[i] &&
217762306a36Sopenharmony_ci		    rdev->mode_info.crtcs[i]->enabled &&
217862306a36Sopenharmony_ci		    i != radeon_crtc->crtc_id &&
217962306a36Sopenharmony_ci		    radeon_crtc->pll_id == rdev->mode_info.crtcs[i]->pll_id) {
218062306a36Sopenharmony_ci			/* one other crtc is using this pll don't turn
218162306a36Sopenharmony_ci			 * off the pll
218262306a36Sopenharmony_ci			 */
218362306a36Sopenharmony_ci			goto done;
218462306a36Sopenharmony_ci		}
218562306a36Sopenharmony_ci	}
218662306a36Sopenharmony_ci
218762306a36Sopenharmony_ci	switch (radeon_crtc->pll_id) {
218862306a36Sopenharmony_ci	case ATOM_PPLL1:
218962306a36Sopenharmony_ci	case ATOM_PPLL2:
219062306a36Sopenharmony_ci		/* disable the ppll */
219162306a36Sopenharmony_ci		atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
219262306a36Sopenharmony_ci					  0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss);
219362306a36Sopenharmony_ci		break;
219462306a36Sopenharmony_ci	case ATOM_PPLL0:
219562306a36Sopenharmony_ci		/* disable the ppll */
219662306a36Sopenharmony_ci		if ((rdev->family == CHIP_ARUBA) ||
219762306a36Sopenharmony_ci		    (rdev->family == CHIP_KAVERI) ||
219862306a36Sopenharmony_ci		    (rdev->family == CHIP_BONAIRE) ||
219962306a36Sopenharmony_ci		    (rdev->family == CHIP_HAWAII))
220062306a36Sopenharmony_ci			atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
220162306a36Sopenharmony_ci						  0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss);
220262306a36Sopenharmony_ci		break;
220362306a36Sopenharmony_ci	default:
220462306a36Sopenharmony_ci		break;
220562306a36Sopenharmony_ci	}
220662306a36Sopenharmony_cidone:
220762306a36Sopenharmony_ci	radeon_crtc->pll_id = ATOM_PPLL_INVALID;
220862306a36Sopenharmony_ci	radeon_crtc->adjusted_clock = 0;
220962306a36Sopenharmony_ci	radeon_crtc->encoder = NULL;
221062306a36Sopenharmony_ci	radeon_crtc->connector = NULL;
221162306a36Sopenharmony_ci}
221262306a36Sopenharmony_ci
221362306a36Sopenharmony_cistatic const struct drm_crtc_helper_funcs atombios_helper_funcs = {
221462306a36Sopenharmony_ci	.dpms = atombios_crtc_dpms,
221562306a36Sopenharmony_ci	.mode_fixup = atombios_crtc_mode_fixup,
221662306a36Sopenharmony_ci	.mode_set = atombios_crtc_mode_set,
221762306a36Sopenharmony_ci	.mode_set_base = atombios_crtc_set_base,
221862306a36Sopenharmony_ci	.mode_set_base_atomic = atombios_crtc_set_base_atomic,
221962306a36Sopenharmony_ci	.prepare = atombios_crtc_prepare,
222062306a36Sopenharmony_ci	.commit = atombios_crtc_commit,
222162306a36Sopenharmony_ci	.disable = atombios_crtc_disable,
222262306a36Sopenharmony_ci	.get_scanout_position = radeon_get_crtc_scanout_position,
222362306a36Sopenharmony_ci};
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_civoid radeon_atombios_init_crtc(struct drm_device *dev,
222662306a36Sopenharmony_ci			       struct radeon_crtc *radeon_crtc)
222762306a36Sopenharmony_ci{
222862306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_ci	if (ASIC_IS_DCE4(rdev)) {
223162306a36Sopenharmony_ci		switch (radeon_crtc->crtc_id) {
223262306a36Sopenharmony_ci		case 0:
223362306a36Sopenharmony_ci		default:
223462306a36Sopenharmony_ci			radeon_crtc->crtc_offset = EVERGREEN_CRTC0_REGISTER_OFFSET;
223562306a36Sopenharmony_ci			break;
223662306a36Sopenharmony_ci		case 1:
223762306a36Sopenharmony_ci			radeon_crtc->crtc_offset = EVERGREEN_CRTC1_REGISTER_OFFSET;
223862306a36Sopenharmony_ci			break;
223962306a36Sopenharmony_ci		case 2:
224062306a36Sopenharmony_ci			radeon_crtc->crtc_offset = EVERGREEN_CRTC2_REGISTER_OFFSET;
224162306a36Sopenharmony_ci			break;
224262306a36Sopenharmony_ci		case 3:
224362306a36Sopenharmony_ci			radeon_crtc->crtc_offset = EVERGREEN_CRTC3_REGISTER_OFFSET;
224462306a36Sopenharmony_ci			break;
224562306a36Sopenharmony_ci		case 4:
224662306a36Sopenharmony_ci			radeon_crtc->crtc_offset = EVERGREEN_CRTC4_REGISTER_OFFSET;
224762306a36Sopenharmony_ci			break;
224862306a36Sopenharmony_ci		case 5:
224962306a36Sopenharmony_ci			radeon_crtc->crtc_offset = EVERGREEN_CRTC5_REGISTER_OFFSET;
225062306a36Sopenharmony_ci			break;
225162306a36Sopenharmony_ci		}
225262306a36Sopenharmony_ci	} else {
225362306a36Sopenharmony_ci		if (radeon_crtc->crtc_id == 1)
225462306a36Sopenharmony_ci			radeon_crtc->crtc_offset =
225562306a36Sopenharmony_ci				AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL;
225662306a36Sopenharmony_ci		else
225762306a36Sopenharmony_ci			radeon_crtc->crtc_offset = 0;
225862306a36Sopenharmony_ci	}
225962306a36Sopenharmony_ci	radeon_crtc->pll_id = ATOM_PPLL_INVALID;
226062306a36Sopenharmony_ci	radeon_crtc->adjusted_clock = 0;
226162306a36Sopenharmony_ci	radeon_crtc->encoder = NULL;
226262306a36Sopenharmony_ci	radeon_crtc->connector = NULL;
226362306a36Sopenharmony_ci	drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs);
226462306a36Sopenharmony_ci}
2265