1254885Sdumbbell/*
2254885Sdumbbell * Copyright 2007-8 Advanced Micro Devices, Inc.
3254885Sdumbbell * Copyright 2008 Red Hat Inc.
4254885Sdumbbell *
5254885Sdumbbell * Permission is hereby granted, free of charge, to any person obtaining a
6254885Sdumbbell * copy of this software and associated documentation files (the "Software"),
7254885Sdumbbell * to deal in the Software without restriction, including without limitation
8254885Sdumbbell * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9254885Sdumbbell * and/or sell copies of the Software, and to permit persons to whom the
10254885Sdumbbell * Software is furnished to do so, subject to the following conditions:
11254885Sdumbbell *
12254885Sdumbbell * The above copyright notice and this permission notice shall be included in
13254885Sdumbbell * all copies or substantial portions of the Software.
14254885Sdumbbell *
15254885Sdumbbell * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16254885Sdumbbell * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17254885Sdumbbell * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18254885Sdumbbell * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19254885Sdumbbell * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20254885Sdumbbell * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21254885Sdumbbell * OTHER DEALINGS IN THE SOFTWARE.
22254885Sdumbbell *
23254885Sdumbbell * Authors: Dave Airlie
24254885Sdumbbell *          Alex Deucher
25254885Sdumbbell */
26254885Sdumbbell
27254885Sdumbbell#include <sys/cdefs.h>
28254885Sdumbbell__FBSDID("$FreeBSD$");
29254885Sdumbbell
30254885Sdumbbell#include <dev/drm2/drmP.h>
31254885Sdumbbell#include <dev/drm2/drm_crtc_helper.h>
32254885Sdumbbell#include <dev/drm2/radeon/radeon_drm.h>
33254885Sdumbbell#include <dev/drm2/drm_fixed.h>
34254885Sdumbbell#include "radeon.h"
35254885Sdumbbell#include "atom.h"
36254885Sdumbbell#include "atom-bits.h"
37254885Sdumbbell
38254885Sdumbbellstatic void atombios_overscan_setup(struct drm_crtc *crtc,
39254885Sdumbbell				    struct drm_display_mode *mode,
40254885Sdumbbell				    struct drm_display_mode *adjusted_mode)
41254885Sdumbbell{
42254885Sdumbbell	struct drm_device *dev = crtc->dev;
43254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
44254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
45254885Sdumbbell	SET_CRTC_OVERSCAN_PS_ALLOCATION args;
46254885Sdumbbell	int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan);
47254885Sdumbbell	int a1, a2;
48254885Sdumbbell
49254885Sdumbbell	memset(&args, 0, sizeof(args));
50254885Sdumbbell
51254885Sdumbbell	args.ucCRTC = radeon_crtc->crtc_id;
52254885Sdumbbell
53254885Sdumbbell	switch (radeon_crtc->rmx_type) {
54254885Sdumbbell	case RMX_CENTER:
55254885Sdumbbell		args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2);
56254885Sdumbbell		args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2);
57254885Sdumbbell		args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2);
58254885Sdumbbell		args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2);
59254885Sdumbbell		break;
60254885Sdumbbell	case RMX_ASPECT:
61254885Sdumbbell		a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay;
62254885Sdumbbell		a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay;
63254885Sdumbbell
64254885Sdumbbell		if (a1 > a2) {
65254885Sdumbbell			args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2);
66254885Sdumbbell			args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2);
67254885Sdumbbell		} else if (a2 > a1) {
68254885Sdumbbell			args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2);
69254885Sdumbbell			args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2);
70254885Sdumbbell		}
71254885Sdumbbell		break;
72254885Sdumbbell	case RMX_FULL:
73254885Sdumbbell	default:
74254885Sdumbbell		args.usOverscanRight = cpu_to_le16(radeon_crtc->h_border);
75254885Sdumbbell		args.usOverscanLeft = cpu_to_le16(radeon_crtc->h_border);
76254885Sdumbbell		args.usOverscanBottom = cpu_to_le16(radeon_crtc->v_border);
77254885Sdumbbell		args.usOverscanTop = cpu_to_le16(radeon_crtc->v_border);
78254885Sdumbbell		break;
79254885Sdumbbell	}
80254885Sdumbbell	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
81254885Sdumbbell}
82254885Sdumbbell
83254885Sdumbbellstatic void atombios_scaler_setup(struct drm_crtc *crtc)
84254885Sdumbbell{
85254885Sdumbbell	struct drm_device *dev = crtc->dev;
86254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
87254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
88254885Sdumbbell	ENABLE_SCALER_PS_ALLOCATION args;
89254885Sdumbbell	int index = GetIndexIntoMasterTable(COMMAND, EnableScaler);
90254885Sdumbbell	struct radeon_encoder *radeon_encoder =
91254885Sdumbbell		to_radeon_encoder(radeon_crtc->encoder);
92254885Sdumbbell	/* fixme - fill in enc_priv for atom dac */
93254885Sdumbbell	enum radeon_tv_std tv_std = TV_STD_NTSC;
94254885Sdumbbell	bool is_tv = false, is_cv = false;
95254885Sdumbbell
96254885Sdumbbell	if (!ASIC_IS_AVIVO(rdev) && radeon_crtc->crtc_id)
97254885Sdumbbell		return;
98254885Sdumbbell
99254885Sdumbbell	if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) {
100254885Sdumbbell		struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv;
101254885Sdumbbell		tv_std = tv_dac->tv_std;
102254885Sdumbbell		is_tv = true;
103254885Sdumbbell	}
104254885Sdumbbell
105254885Sdumbbell	memset(&args, 0, sizeof(args));
106254885Sdumbbell
107254885Sdumbbell	args.ucScaler = radeon_crtc->crtc_id;
108254885Sdumbbell
109254885Sdumbbell	if (is_tv) {
110254885Sdumbbell		switch (tv_std) {
111254885Sdumbbell		case TV_STD_NTSC:
112254885Sdumbbell		default:
113254885Sdumbbell			args.ucTVStandard = ATOM_TV_NTSC;
114254885Sdumbbell			break;
115254885Sdumbbell		case TV_STD_PAL:
116254885Sdumbbell			args.ucTVStandard = ATOM_TV_PAL;
117254885Sdumbbell			break;
118254885Sdumbbell		case TV_STD_PAL_M:
119254885Sdumbbell			args.ucTVStandard = ATOM_TV_PALM;
120254885Sdumbbell			break;
121254885Sdumbbell		case TV_STD_PAL_60:
122254885Sdumbbell			args.ucTVStandard = ATOM_TV_PAL60;
123254885Sdumbbell			break;
124254885Sdumbbell		case TV_STD_NTSC_J:
125254885Sdumbbell			args.ucTVStandard = ATOM_TV_NTSCJ;
126254885Sdumbbell			break;
127254885Sdumbbell		case TV_STD_SCART_PAL:
128254885Sdumbbell			args.ucTVStandard = ATOM_TV_PAL; /* ??? */
129254885Sdumbbell			break;
130254885Sdumbbell		case TV_STD_SECAM:
131254885Sdumbbell			args.ucTVStandard = ATOM_TV_SECAM;
132254885Sdumbbell			break;
133254885Sdumbbell		case TV_STD_PAL_CN:
134254885Sdumbbell			args.ucTVStandard = ATOM_TV_PALCN;
135254885Sdumbbell			break;
136254885Sdumbbell		}
137254885Sdumbbell		args.ucEnable = SCALER_ENABLE_MULTITAP_MODE;
138254885Sdumbbell	} else if (is_cv) {
139254885Sdumbbell		args.ucTVStandard = ATOM_TV_CV;
140254885Sdumbbell		args.ucEnable = SCALER_ENABLE_MULTITAP_MODE;
141254885Sdumbbell	} else {
142254885Sdumbbell		switch (radeon_crtc->rmx_type) {
143254885Sdumbbell		case RMX_FULL:
144254885Sdumbbell			args.ucEnable = ATOM_SCALER_EXPANSION;
145254885Sdumbbell			break;
146254885Sdumbbell		case RMX_CENTER:
147254885Sdumbbell			args.ucEnable = ATOM_SCALER_CENTER;
148254885Sdumbbell			break;
149254885Sdumbbell		case RMX_ASPECT:
150254885Sdumbbell			args.ucEnable = ATOM_SCALER_EXPANSION;
151254885Sdumbbell			break;
152254885Sdumbbell		default:
153254885Sdumbbell			if (ASIC_IS_AVIVO(rdev))
154254885Sdumbbell				args.ucEnable = ATOM_SCALER_DISABLE;
155254885Sdumbbell			else
156254885Sdumbbell				args.ucEnable = ATOM_SCALER_CENTER;
157254885Sdumbbell			break;
158254885Sdumbbell		}
159254885Sdumbbell	}
160254885Sdumbbell	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
161254885Sdumbbell	if ((is_tv || is_cv)
162254885Sdumbbell	    && rdev->family >= CHIP_RV515 && rdev->family <= CHIP_R580) {
163254885Sdumbbell		atom_rv515_force_tv_scaler(rdev, radeon_crtc);
164254885Sdumbbell	}
165254885Sdumbbell}
166254885Sdumbbell
167254885Sdumbbellstatic void atombios_lock_crtc(struct drm_crtc *crtc, int lock)
168254885Sdumbbell{
169254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
170254885Sdumbbell	struct drm_device *dev = crtc->dev;
171254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
172254885Sdumbbell	int index =
173254885Sdumbbell	    GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters);
174254885Sdumbbell	ENABLE_CRTC_PS_ALLOCATION args;
175254885Sdumbbell
176254885Sdumbbell	memset(&args, 0, sizeof(args));
177254885Sdumbbell
178254885Sdumbbell	args.ucCRTC = radeon_crtc->crtc_id;
179254885Sdumbbell	args.ucEnable = lock;
180254885Sdumbbell
181254885Sdumbbell	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
182254885Sdumbbell}
183254885Sdumbbell
184254885Sdumbbellstatic void atombios_enable_crtc(struct drm_crtc *crtc, int state)
185254885Sdumbbell{
186254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
187254885Sdumbbell	struct drm_device *dev = crtc->dev;
188254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
189254885Sdumbbell	int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC);
190254885Sdumbbell	ENABLE_CRTC_PS_ALLOCATION args;
191254885Sdumbbell
192254885Sdumbbell	memset(&args, 0, sizeof(args));
193254885Sdumbbell
194254885Sdumbbell	args.ucCRTC = radeon_crtc->crtc_id;
195254885Sdumbbell	args.ucEnable = state;
196254885Sdumbbell
197254885Sdumbbell	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
198254885Sdumbbell}
199254885Sdumbbell
200254885Sdumbbellstatic void atombios_enable_crtc_memreq(struct drm_crtc *crtc, int state)
201254885Sdumbbell{
202254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
203254885Sdumbbell	struct drm_device *dev = crtc->dev;
204254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
205254885Sdumbbell	int index = GetIndexIntoMasterTable(COMMAND, EnableCRTCMemReq);
206254885Sdumbbell	ENABLE_CRTC_PS_ALLOCATION args;
207254885Sdumbbell
208254885Sdumbbell	memset(&args, 0, sizeof(args));
209254885Sdumbbell
210254885Sdumbbell	args.ucCRTC = radeon_crtc->crtc_id;
211254885Sdumbbell	args.ucEnable = state;
212254885Sdumbbell
213254885Sdumbbell	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
214254885Sdumbbell}
215254885Sdumbbell
216254885Sdumbbellstatic void atombios_blank_crtc(struct drm_crtc *crtc, int state)
217254885Sdumbbell{
218254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
219254885Sdumbbell	struct drm_device *dev = crtc->dev;
220254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
221254885Sdumbbell	int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC);
222254885Sdumbbell	BLANK_CRTC_PS_ALLOCATION args;
223254885Sdumbbell
224254885Sdumbbell	memset(&args, 0, sizeof(args));
225254885Sdumbbell
226254885Sdumbbell	args.ucCRTC = radeon_crtc->crtc_id;
227254885Sdumbbell	args.ucBlanking = state;
228254885Sdumbbell
229254885Sdumbbell	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
230254885Sdumbbell}
231254885Sdumbbell
232254885Sdumbbellstatic void atombios_powergate_crtc(struct drm_crtc *crtc, int state)
233254885Sdumbbell{
234254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
235254885Sdumbbell	struct drm_device *dev = crtc->dev;
236254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
237254885Sdumbbell	int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating);
238254885Sdumbbell	ENABLE_DISP_POWER_GATING_PARAMETERS_V2_1 args;
239254885Sdumbbell
240254885Sdumbbell	memset(&args, 0, sizeof(args));
241254885Sdumbbell
242254885Sdumbbell	args.ucDispPipeId = radeon_crtc->crtc_id;
243254885Sdumbbell	args.ucEnable = state;
244254885Sdumbbell
245254885Sdumbbell	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
246254885Sdumbbell}
247254885Sdumbbell
248254885Sdumbbellvoid atombios_crtc_dpms(struct drm_crtc *crtc, int mode)
249254885Sdumbbell{
250254885Sdumbbell	struct drm_device *dev = crtc->dev;
251254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
252254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
253254885Sdumbbell
254254885Sdumbbell	switch (mode) {
255254885Sdumbbell	case DRM_MODE_DPMS_ON:
256254885Sdumbbell		radeon_crtc->enabled = true;
257254885Sdumbbell		/* adjust pm to dpms changes BEFORE enabling crtcs */
258254885Sdumbbell		radeon_pm_compute_clocks(rdev);
259254885Sdumbbell		atombios_enable_crtc(crtc, ATOM_ENABLE);
260254885Sdumbbell		if (ASIC_IS_DCE3(rdev) && !ASIC_IS_DCE6(rdev))
261254885Sdumbbell			atombios_enable_crtc_memreq(crtc, ATOM_ENABLE);
262254885Sdumbbell		atombios_blank_crtc(crtc, ATOM_DISABLE);
263254885Sdumbbell		drm_vblank_post_modeset(dev, radeon_crtc->crtc_id);
264254885Sdumbbell		radeon_crtc_load_lut(crtc);
265254885Sdumbbell		break;
266254885Sdumbbell	case DRM_MODE_DPMS_STANDBY:
267254885Sdumbbell	case DRM_MODE_DPMS_SUSPEND:
268254885Sdumbbell	case DRM_MODE_DPMS_OFF:
269254885Sdumbbell		drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id);
270254885Sdumbbell		if (radeon_crtc->enabled)
271254885Sdumbbell			atombios_blank_crtc(crtc, ATOM_ENABLE);
272254885Sdumbbell		if (ASIC_IS_DCE3(rdev) && !ASIC_IS_DCE6(rdev))
273254885Sdumbbell			atombios_enable_crtc_memreq(crtc, ATOM_DISABLE);
274254885Sdumbbell		atombios_enable_crtc(crtc, ATOM_DISABLE);
275254885Sdumbbell		radeon_crtc->enabled = false;
276254885Sdumbbell		/* adjust pm to dpms changes AFTER disabling crtcs */
277254885Sdumbbell		radeon_pm_compute_clocks(rdev);
278254885Sdumbbell		break;
279254885Sdumbbell	}
280254885Sdumbbell}
281254885Sdumbbell
282254885Sdumbbellstatic void
283254885Sdumbbellatombios_set_crtc_dtd_timing(struct drm_crtc *crtc,
284254885Sdumbbell			     struct drm_display_mode *mode)
285254885Sdumbbell{
286254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
287254885Sdumbbell	struct drm_device *dev = crtc->dev;
288254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
289254885Sdumbbell	SET_CRTC_USING_DTD_TIMING_PARAMETERS args;
290254885Sdumbbell	int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming);
291254885Sdumbbell	u16 misc = 0;
292254885Sdumbbell
293254885Sdumbbell	memset(&args, 0, sizeof(args));
294254885Sdumbbell	args.usH_Size = cpu_to_le16(mode->crtc_hdisplay - (radeon_crtc->h_border * 2));
295254885Sdumbbell	args.usH_Blanking_Time =
296254885Sdumbbell		cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay + (radeon_crtc->h_border * 2));
297254885Sdumbbell	args.usV_Size = cpu_to_le16(mode->crtc_vdisplay - (radeon_crtc->v_border * 2));
298254885Sdumbbell	args.usV_Blanking_Time =
299254885Sdumbbell		cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay + (radeon_crtc->v_border * 2));
300254885Sdumbbell	args.usH_SyncOffset =
301254885Sdumbbell		cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay + radeon_crtc->h_border);
302254885Sdumbbell	args.usH_SyncWidth =
303254885Sdumbbell		cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start);
304254885Sdumbbell	args.usV_SyncOffset =
305254885Sdumbbell		cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay + radeon_crtc->v_border);
306254885Sdumbbell	args.usV_SyncWidth =
307254885Sdumbbell		cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start);
308254885Sdumbbell	args.ucH_Border = radeon_crtc->h_border;
309254885Sdumbbell	args.ucV_Border = radeon_crtc->v_border;
310254885Sdumbbell
311254885Sdumbbell	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
312254885Sdumbbell		misc |= ATOM_VSYNC_POLARITY;
313254885Sdumbbell	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
314254885Sdumbbell		misc |= ATOM_HSYNC_POLARITY;
315254885Sdumbbell	if (mode->flags & DRM_MODE_FLAG_CSYNC)
316254885Sdumbbell		misc |= ATOM_COMPOSITESYNC;
317254885Sdumbbell	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
318254885Sdumbbell		misc |= ATOM_INTERLACE;
319254885Sdumbbell	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
320254885Sdumbbell		misc |= ATOM_DOUBLE_CLOCK_MODE;
321254885Sdumbbell
322254885Sdumbbell	args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
323254885Sdumbbell	args.ucCRTC = radeon_crtc->crtc_id;
324254885Sdumbbell
325254885Sdumbbell	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
326254885Sdumbbell}
327254885Sdumbbell
328254885Sdumbbellstatic void atombios_crtc_set_timing(struct drm_crtc *crtc,
329254885Sdumbbell				     struct drm_display_mode *mode)
330254885Sdumbbell{
331254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
332254885Sdumbbell	struct drm_device *dev = crtc->dev;
333254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
334254885Sdumbbell	SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION args;
335254885Sdumbbell	int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing);
336254885Sdumbbell	u16 misc = 0;
337254885Sdumbbell
338254885Sdumbbell	memset(&args, 0, sizeof(args));
339254885Sdumbbell	args.usH_Total = cpu_to_le16(mode->crtc_htotal);
340254885Sdumbbell	args.usH_Disp = cpu_to_le16(mode->crtc_hdisplay);
341254885Sdumbbell	args.usH_SyncStart = cpu_to_le16(mode->crtc_hsync_start);
342254885Sdumbbell	args.usH_SyncWidth =
343254885Sdumbbell		cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start);
344254885Sdumbbell	args.usV_Total = cpu_to_le16(mode->crtc_vtotal);
345254885Sdumbbell	args.usV_Disp = cpu_to_le16(mode->crtc_vdisplay);
346254885Sdumbbell	args.usV_SyncStart = cpu_to_le16(mode->crtc_vsync_start);
347254885Sdumbbell	args.usV_SyncWidth =
348254885Sdumbbell		cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start);
349254885Sdumbbell
350254885Sdumbbell	args.ucOverscanRight = radeon_crtc->h_border;
351254885Sdumbbell	args.ucOverscanLeft = radeon_crtc->h_border;
352254885Sdumbbell	args.ucOverscanBottom = radeon_crtc->v_border;
353254885Sdumbbell	args.ucOverscanTop = radeon_crtc->v_border;
354254885Sdumbbell
355254885Sdumbbell	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
356254885Sdumbbell		misc |= ATOM_VSYNC_POLARITY;
357254885Sdumbbell	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
358254885Sdumbbell		misc |= ATOM_HSYNC_POLARITY;
359254885Sdumbbell	if (mode->flags & DRM_MODE_FLAG_CSYNC)
360254885Sdumbbell		misc |= ATOM_COMPOSITESYNC;
361254885Sdumbbell	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
362254885Sdumbbell		misc |= ATOM_INTERLACE;
363254885Sdumbbell	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
364254885Sdumbbell		misc |= ATOM_DOUBLE_CLOCK_MODE;
365254885Sdumbbell
366254885Sdumbbell	args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
367254885Sdumbbell	args.ucCRTC = radeon_crtc->crtc_id;
368254885Sdumbbell
369254885Sdumbbell	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
370254885Sdumbbell}
371254885Sdumbbell
372254885Sdumbbellstatic void atombios_disable_ss(struct radeon_device *rdev, int pll_id)
373254885Sdumbbell{
374254885Sdumbbell	u32 ss_cntl;
375254885Sdumbbell
376254885Sdumbbell	if (ASIC_IS_DCE4(rdev)) {
377254885Sdumbbell		switch (pll_id) {
378254885Sdumbbell		case ATOM_PPLL1:
379254885Sdumbbell			ss_cntl = RREG32(EVERGREEN_P1PLL_SS_CNTL);
380254885Sdumbbell			ss_cntl &= ~EVERGREEN_PxPLL_SS_EN;
381254885Sdumbbell			WREG32(EVERGREEN_P1PLL_SS_CNTL, ss_cntl);
382254885Sdumbbell			break;
383254885Sdumbbell		case ATOM_PPLL2:
384254885Sdumbbell			ss_cntl = RREG32(EVERGREEN_P2PLL_SS_CNTL);
385254885Sdumbbell			ss_cntl &= ~EVERGREEN_PxPLL_SS_EN;
386254885Sdumbbell			WREG32(EVERGREEN_P2PLL_SS_CNTL, ss_cntl);
387254885Sdumbbell			break;
388254885Sdumbbell		case ATOM_DCPLL:
389254885Sdumbbell		case ATOM_PPLL_INVALID:
390254885Sdumbbell			return;
391254885Sdumbbell		}
392254885Sdumbbell	} else if (ASIC_IS_AVIVO(rdev)) {
393254885Sdumbbell		switch (pll_id) {
394254885Sdumbbell		case ATOM_PPLL1:
395254885Sdumbbell			ss_cntl = RREG32(AVIVO_P1PLL_INT_SS_CNTL);
396254885Sdumbbell			ss_cntl &= ~1;
397254885Sdumbbell			WREG32(AVIVO_P1PLL_INT_SS_CNTL, ss_cntl);
398254885Sdumbbell			break;
399254885Sdumbbell		case ATOM_PPLL2:
400254885Sdumbbell			ss_cntl = RREG32(AVIVO_P2PLL_INT_SS_CNTL);
401254885Sdumbbell			ss_cntl &= ~1;
402254885Sdumbbell			WREG32(AVIVO_P2PLL_INT_SS_CNTL, ss_cntl);
403254885Sdumbbell			break;
404254885Sdumbbell		case ATOM_DCPLL:
405254885Sdumbbell		case ATOM_PPLL_INVALID:
406254885Sdumbbell			return;
407254885Sdumbbell		}
408254885Sdumbbell	}
409254885Sdumbbell}
410254885Sdumbbell
411254885Sdumbbell
412254885Sdumbbellunion atom_enable_ss {
413254885Sdumbbell	ENABLE_LVDS_SS_PARAMETERS lvds_ss;
414254885Sdumbbell	ENABLE_LVDS_SS_PARAMETERS_V2 lvds_ss_2;
415254885Sdumbbell	ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1;
416254885Sdumbbell	ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 v2;
417254885Sdumbbell	ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 v3;
418254885Sdumbbell};
419254885Sdumbbell
420254885Sdumbbellstatic void atombios_crtc_program_ss(struct radeon_device *rdev,
421254885Sdumbbell				     int enable,
422254885Sdumbbell				     int pll_id,
423254885Sdumbbell				     int crtc_id,
424254885Sdumbbell				     struct radeon_atom_ss *ss)
425254885Sdumbbell{
426254885Sdumbbell	unsigned i;
427254885Sdumbbell	int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL);
428254885Sdumbbell	union atom_enable_ss args;
429254885Sdumbbell
430254885Sdumbbell	if (!enable) {
431254885Sdumbbell		for (i = 0; i < rdev->num_crtc; i++) {
432254885Sdumbbell			if (rdev->mode_info.crtcs[i] &&
433254885Sdumbbell			    rdev->mode_info.crtcs[i]->enabled &&
434254885Sdumbbell			    i != crtc_id &&
435254885Sdumbbell			    pll_id == rdev->mode_info.crtcs[i]->pll_id) {
436254885Sdumbbell				/* one other crtc is using this pll don't turn
437254885Sdumbbell				 * off spread spectrum as it might turn off
438254885Sdumbbell				 * display on active crtc
439254885Sdumbbell				 */
440254885Sdumbbell				return;
441254885Sdumbbell			}
442254885Sdumbbell		}
443254885Sdumbbell	}
444254885Sdumbbell
445254885Sdumbbell	memset(&args, 0, sizeof(args));
446254885Sdumbbell
447254885Sdumbbell	if (ASIC_IS_DCE5(rdev)) {
448254885Sdumbbell		args.v3.usSpreadSpectrumAmountFrac = cpu_to_le16(0);
449254885Sdumbbell		args.v3.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
450254885Sdumbbell		switch (pll_id) {
451254885Sdumbbell		case ATOM_PPLL1:
452254885Sdumbbell			args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL;
453254885Sdumbbell			break;
454254885Sdumbbell		case ATOM_PPLL2:
455254885Sdumbbell			args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL;
456254885Sdumbbell			break;
457254885Sdumbbell		case ATOM_DCPLL:
458254885Sdumbbell			args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL;
459254885Sdumbbell			break;
460254885Sdumbbell		case ATOM_PPLL_INVALID:
461254885Sdumbbell			return;
462254885Sdumbbell		}
463254885Sdumbbell		args.v3.usSpreadSpectrumAmount = cpu_to_le16(ss->amount);
464254885Sdumbbell		args.v3.usSpreadSpectrumStep = cpu_to_le16(ss->step);
465254885Sdumbbell		args.v3.ucEnable = enable;
466254885Sdumbbell		if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK) || ASIC_IS_DCE61(rdev))
467254885Sdumbbell			args.v3.ucEnable = ATOM_DISABLE;
468254885Sdumbbell	} else if (ASIC_IS_DCE4(rdev)) {
469254885Sdumbbell		args.v2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
470254885Sdumbbell		args.v2.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
471254885Sdumbbell		switch (pll_id) {
472254885Sdumbbell		case ATOM_PPLL1:
473254885Sdumbbell			args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P1PLL;
474254885Sdumbbell			break;
475254885Sdumbbell		case ATOM_PPLL2:
476254885Sdumbbell			args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P2PLL;
477254885Sdumbbell			break;
478254885Sdumbbell		case ATOM_DCPLL:
479254885Sdumbbell			args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_DCPLL;
480254885Sdumbbell			break;
481254885Sdumbbell		case ATOM_PPLL_INVALID:
482254885Sdumbbell			return;
483254885Sdumbbell		}
484254885Sdumbbell		args.v2.usSpreadSpectrumAmount = cpu_to_le16(ss->amount);
485254885Sdumbbell		args.v2.usSpreadSpectrumStep = cpu_to_le16(ss->step);
486254885Sdumbbell		args.v2.ucEnable = enable;
487254885Sdumbbell		if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK) || ASIC_IS_DCE41(rdev))
488254885Sdumbbell			args.v2.ucEnable = ATOM_DISABLE;
489254885Sdumbbell	} else if (ASIC_IS_DCE3(rdev)) {
490254885Sdumbbell		args.v1.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
491254885Sdumbbell		args.v1.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
492254885Sdumbbell		args.v1.ucSpreadSpectrumStep = ss->step;
493254885Sdumbbell		args.v1.ucSpreadSpectrumDelay = ss->delay;
494254885Sdumbbell		args.v1.ucSpreadSpectrumRange = ss->range;
495254885Sdumbbell		args.v1.ucPpll = pll_id;
496254885Sdumbbell		args.v1.ucEnable = enable;
497254885Sdumbbell	} else if (ASIC_IS_AVIVO(rdev)) {
498254885Sdumbbell		if ((enable == ATOM_DISABLE) || (ss->percentage == 0) ||
499254885Sdumbbell		    (ss->type & ATOM_EXTERNAL_SS_MASK)) {
500254885Sdumbbell			atombios_disable_ss(rdev, pll_id);
501254885Sdumbbell			return;
502254885Sdumbbell		}
503254885Sdumbbell		args.lvds_ss_2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
504254885Sdumbbell		args.lvds_ss_2.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
505254885Sdumbbell		args.lvds_ss_2.ucSpreadSpectrumStep = ss->step;
506254885Sdumbbell		args.lvds_ss_2.ucSpreadSpectrumDelay = ss->delay;
507254885Sdumbbell		args.lvds_ss_2.ucSpreadSpectrumRange = ss->range;
508254885Sdumbbell		args.lvds_ss_2.ucEnable = enable;
509254885Sdumbbell	} else {
510254885Sdumbbell		if ((enable == ATOM_DISABLE) || (ss->percentage == 0) ||
511254885Sdumbbell		    (ss->type & ATOM_EXTERNAL_SS_MASK)) {
512254885Sdumbbell			atombios_disable_ss(rdev, pll_id);
513254885Sdumbbell			return;
514254885Sdumbbell		}
515254885Sdumbbell		args.lvds_ss.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
516254885Sdumbbell		args.lvds_ss.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
517254885Sdumbbell		args.lvds_ss.ucSpreadSpectrumStepSize_Delay = (ss->step & 3) << 2;
518254885Sdumbbell		args.lvds_ss.ucSpreadSpectrumStepSize_Delay |= (ss->delay & 7) << 4;
519254885Sdumbbell		args.lvds_ss.ucEnable = enable;
520254885Sdumbbell	}
521254885Sdumbbell	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
522254885Sdumbbell}
523254885Sdumbbell
524254885Sdumbbellunion adjust_pixel_clock {
525254885Sdumbbell	ADJUST_DISPLAY_PLL_PS_ALLOCATION v1;
526254885Sdumbbell	ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 v3;
527254885Sdumbbell};
528254885Sdumbbell
529254885Sdumbbellstatic u32 atombios_adjust_pll(struct drm_crtc *crtc,
530254885Sdumbbell			       struct drm_display_mode *mode)
531254885Sdumbbell{
532254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
533254885Sdumbbell	struct drm_device *dev = crtc->dev;
534254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
535254885Sdumbbell	struct drm_encoder *encoder = radeon_crtc->encoder;
536254885Sdumbbell	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
537254885Sdumbbell	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
538254885Sdumbbell	u32 adjusted_clock = mode->clock;
539254885Sdumbbell	int encoder_mode = atombios_get_encoder_mode(encoder);
540254885Sdumbbell	u32 dp_clock = mode->clock;
541254885Sdumbbell	int bpc = radeon_get_monitor_bpc(connector);
542254885Sdumbbell	bool is_duallink = radeon_dig_monitor_is_duallink(encoder, mode->clock);
543254885Sdumbbell
544254885Sdumbbell	/* reset the pll flags */
545254885Sdumbbell	radeon_crtc->pll_flags = 0;
546254885Sdumbbell
547254885Sdumbbell	if (ASIC_IS_AVIVO(rdev)) {
548254885Sdumbbell		if ((rdev->family == CHIP_RS600) ||
549254885Sdumbbell		    (rdev->family == CHIP_RS690) ||
550254885Sdumbbell		    (rdev->family == CHIP_RS740))
551254885Sdumbbell			radeon_crtc->pll_flags |= (/*RADEON_PLL_USE_FRAC_FB_DIV |*/
552254885Sdumbbell				RADEON_PLL_PREFER_CLOSEST_LOWER);
553254885Sdumbbell
554254885Sdumbbell		if (ASIC_IS_DCE32(rdev) && mode->clock > 200000)	/* range limits??? */
555254885Sdumbbell			radeon_crtc->pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
556254885Sdumbbell		else
557254885Sdumbbell			radeon_crtc->pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
558254885Sdumbbell
559254885Sdumbbell		if (rdev->family < CHIP_RV770)
560254885Sdumbbell			radeon_crtc->pll_flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP;
561254885Sdumbbell		/* use frac fb div on APUs */
562254885Sdumbbell		if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev))
563254885Sdumbbell			radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV;
564282199Sdumbbell		/* use frac fb div on RS780/RS880 */
565282199Sdumbbell		if ((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880))
566282199Sdumbbell			radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV;
567254885Sdumbbell		if (ASIC_IS_DCE32(rdev) && mode->clock > 165000)
568254885Sdumbbell			radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV;
569254885Sdumbbell	} else {
570254885Sdumbbell		radeon_crtc->pll_flags |= RADEON_PLL_LEGACY;
571254885Sdumbbell
572254885Sdumbbell		if (mode->clock > 200000)	/* range limits??? */
573254885Sdumbbell			radeon_crtc->pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
574254885Sdumbbell		else
575254885Sdumbbell			radeon_crtc->pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
576254885Sdumbbell	}
577254885Sdumbbell
578254885Sdumbbell	if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
579254885Sdumbbell	    (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)) {
580254885Sdumbbell		if (connector) {
581254885Sdumbbell			struct radeon_connector *radeon_connector = to_radeon_connector(connector);
582254885Sdumbbell			struct radeon_connector_atom_dig *dig_connector =
583254885Sdumbbell				radeon_connector->con_priv;
584254885Sdumbbell
585254885Sdumbbell			dp_clock = dig_connector->dp_clock;
586254885Sdumbbell		}
587254885Sdumbbell	}
588254885Sdumbbell
589254885Sdumbbell	/* use recommended ref_div for ss */
590254885Sdumbbell	if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
591254885Sdumbbell		if (radeon_crtc->ss_enabled) {
592254885Sdumbbell			if (radeon_crtc->ss.refdiv) {
593254885Sdumbbell				radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV;
594254885Sdumbbell				radeon_crtc->pll_reference_div = radeon_crtc->ss.refdiv;
595254885Sdumbbell				if (ASIC_IS_AVIVO(rdev))
596254885Sdumbbell					radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV;
597254885Sdumbbell			}
598254885Sdumbbell		}
599254885Sdumbbell	}
600254885Sdumbbell
601254885Sdumbbell	if (ASIC_IS_AVIVO(rdev)) {
602254885Sdumbbell		/* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */
603254885Sdumbbell		if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)
604254885Sdumbbell			adjusted_clock = mode->clock * 2;
605254885Sdumbbell		if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
606254885Sdumbbell			radeon_crtc->pll_flags |= RADEON_PLL_PREFER_CLOSEST_LOWER;
607254885Sdumbbell		if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
608254885Sdumbbell			radeon_crtc->pll_flags |= RADEON_PLL_IS_LCD;
609254885Sdumbbell	} else {
610254885Sdumbbell		if (encoder->encoder_type != DRM_MODE_ENCODER_DAC)
611254885Sdumbbell			radeon_crtc->pll_flags |= RADEON_PLL_NO_ODD_POST_DIV;
612254885Sdumbbell		if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS)
613254885Sdumbbell			radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV;
614254885Sdumbbell	}
615254885Sdumbbell
616254885Sdumbbell	/* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock
617254885Sdumbbell	 * accordingly based on the encoder/transmitter to work around
618254885Sdumbbell	 * special hw requirements.
619254885Sdumbbell	 */
620254885Sdumbbell	if (ASIC_IS_DCE3(rdev)) {
621254885Sdumbbell		union adjust_pixel_clock args;
622254885Sdumbbell		u8 frev, crev;
623254885Sdumbbell		int index;
624254885Sdumbbell
625254885Sdumbbell		index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll);
626254885Sdumbbell		if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
627254885Sdumbbell					   &crev))
628254885Sdumbbell			return adjusted_clock;
629254885Sdumbbell
630254885Sdumbbell		memset(&args, 0, sizeof(args));
631254885Sdumbbell
632254885Sdumbbell		switch (frev) {
633254885Sdumbbell		case 1:
634254885Sdumbbell			switch (crev) {
635254885Sdumbbell			case 1:
636254885Sdumbbell			case 2:
637254885Sdumbbell				args.v1.usPixelClock = cpu_to_le16(mode->clock / 10);
638254885Sdumbbell				args.v1.ucTransmitterID = radeon_encoder->encoder_id;
639254885Sdumbbell				args.v1.ucEncodeMode = encoder_mode;
640254885Sdumbbell				if (radeon_crtc->ss_enabled && radeon_crtc->ss.percentage)
641254885Sdumbbell					args.v1.ucConfig |=
642254885Sdumbbell						ADJUST_DISPLAY_CONFIG_SS_ENABLE;
643254885Sdumbbell
644254885Sdumbbell				atom_execute_table(rdev->mode_info.atom_context,
645254885Sdumbbell						   index, (uint32_t *)&args);
646254885Sdumbbell				adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10;
647254885Sdumbbell				break;
648254885Sdumbbell			case 3:
649254885Sdumbbell				args.v3.sInput.usPixelClock = cpu_to_le16(mode->clock / 10);
650254885Sdumbbell				args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id;
651254885Sdumbbell				args.v3.sInput.ucEncodeMode = encoder_mode;
652254885Sdumbbell				args.v3.sInput.ucDispPllConfig = 0;
653254885Sdumbbell				if (radeon_crtc->ss_enabled && radeon_crtc->ss.percentage)
654254885Sdumbbell					args.v3.sInput.ucDispPllConfig |=
655254885Sdumbbell						DISPPLL_CONFIG_SS_ENABLE;
656254885Sdumbbell				if (ENCODER_MODE_IS_DP(encoder_mode)) {
657254885Sdumbbell					args.v3.sInput.ucDispPllConfig |=
658254885Sdumbbell						DISPPLL_CONFIG_COHERENT_MODE;
659254885Sdumbbell					/* 16200 or 27000 */
660254885Sdumbbell					args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10);
661254885Sdumbbell				} else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
662254885Sdumbbell					struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
663254885Sdumbbell					if (encoder_mode == ATOM_ENCODER_MODE_HDMI)
664254885Sdumbbell						/* deep color support */
665254885Sdumbbell						args.v3.sInput.usPixelClock =
666254885Sdumbbell							cpu_to_le16((mode->clock * bpc / 8) / 10);
667254885Sdumbbell					if (dig->coherent_mode)
668254885Sdumbbell						args.v3.sInput.ucDispPllConfig |=
669254885Sdumbbell							DISPPLL_CONFIG_COHERENT_MODE;
670254885Sdumbbell					if (is_duallink)
671254885Sdumbbell						args.v3.sInput.ucDispPllConfig |=
672254885Sdumbbell							DISPPLL_CONFIG_DUAL_LINK;
673254885Sdumbbell				}
674254885Sdumbbell				if (radeon_encoder_get_dp_bridge_encoder_id(encoder) !=
675254885Sdumbbell				    ENCODER_OBJECT_ID_NONE)
676254885Sdumbbell					args.v3.sInput.ucExtTransmitterID =
677254885Sdumbbell						radeon_encoder_get_dp_bridge_encoder_id(encoder);
678254885Sdumbbell				else
679254885Sdumbbell					args.v3.sInput.ucExtTransmitterID = 0;
680254885Sdumbbell
681254885Sdumbbell				atom_execute_table(rdev->mode_info.atom_context,
682254885Sdumbbell						   index, (uint32_t *)&args);
683254885Sdumbbell				adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10;
684254885Sdumbbell				if (args.v3.sOutput.ucRefDiv) {
685254885Sdumbbell					radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV;
686254885Sdumbbell					radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV;
687254885Sdumbbell					radeon_crtc->pll_reference_div = args.v3.sOutput.ucRefDiv;
688254885Sdumbbell				}
689254885Sdumbbell				if (args.v3.sOutput.ucPostDiv) {
690254885Sdumbbell					radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV;
691254885Sdumbbell					radeon_crtc->pll_flags |= RADEON_PLL_USE_POST_DIV;
692254885Sdumbbell					radeon_crtc->pll_post_div = args.v3.sOutput.ucPostDiv;
693254885Sdumbbell				}
694254885Sdumbbell				break;
695254885Sdumbbell			default:
696254885Sdumbbell				DRM_ERROR("Unknown table version %d %d\n", frev, crev);
697254885Sdumbbell				return adjusted_clock;
698254885Sdumbbell			}
699254885Sdumbbell			break;
700254885Sdumbbell		default:
701254885Sdumbbell			DRM_ERROR("Unknown table version %d %d\n", frev, crev);
702254885Sdumbbell			return adjusted_clock;
703254885Sdumbbell		}
704254885Sdumbbell	}
705254885Sdumbbell	return adjusted_clock;
706254885Sdumbbell}
707254885Sdumbbell
708254885Sdumbbellunion set_pixel_clock {
709254885Sdumbbell	SET_PIXEL_CLOCK_PS_ALLOCATION base;
710254885Sdumbbell	PIXEL_CLOCK_PARAMETERS v1;
711254885Sdumbbell	PIXEL_CLOCK_PARAMETERS_V2 v2;
712254885Sdumbbell	PIXEL_CLOCK_PARAMETERS_V3 v3;
713254885Sdumbbell	PIXEL_CLOCK_PARAMETERS_V5 v5;
714254885Sdumbbell	PIXEL_CLOCK_PARAMETERS_V6 v6;
715254885Sdumbbell};
716254885Sdumbbell
717254885Sdumbbell/* on DCE5, make sure the voltage is high enough to support the
718254885Sdumbbell * required disp clk.
719254885Sdumbbell */
720254885Sdumbbellstatic void atombios_crtc_set_disp_eng_pll(struct radeon_device *rdev,
721254885Sdumbbell				    u32 dispclk)
722254885Sdumbbell{
723254885Sdumbbell	u8 frev, crev;
724254885Sdumbbell	int index;
725254885Sdumbbell	union set_pixel_clock args;
726254885Sdumbbell
727254885Sdumbbell	memset(&args, 0, sizeof(args));
728254885Sdumbbell
729254885Sdumbbell	index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
730254885Sdumbbell	if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
731254885Sdumbbell				   &crev))
732254885Sdumbbell		return;
733254885Sdumbbell
734254885Sdumbbell	switch (frev) {
735254885Sdumbbell	case 1:
736254885Sdumbbell		switch (crev) {
737254885Sdumbbell		case 5:
738254885Sdumbbell			/* if the default dcpll clock is specified,
739254885Sdumbbell			 * SetPixelClock provides the dividers
740254885Sdumbbell			 */
741254885Sdumbbell			args.v5.ucCRTC = ATOM_CRTC_INVALID;
742254885Sdumbbell			args.v5.usPixelClock = cpu_to_le16(dispclk);
743254885Sdumbbell			args.v5.ucPpll = ATOM_DCPLL;
744254885Sdumbbell			break;
745254885Sdumbbell		case 6:
746254885Sdumbbell			/* if the default dcpll clock is specified,
747254885Sdumbbell			 * SetPixelClock provides the dividers
748254885Sdumbbell			 */
749254885Sdumbbell			args.v6.ulDispEngClkFreq = cpu_to_le32(dispclk);
750254885Sdumbbell			if (ASIC_IS_DCE61(rdev))
751254885Sdumbbell				args.v6.ucPpll = ATOM_EXT_PLL1;
752254885Sdumbbell			else if (ASIC_IS_DCE6(rdev))
753254885Sdumbbell				args.v6.ucPpll = ATOM_PPLL0;
754254885Sdumbbell			else
755254885Sdumbbell				args.v6.ucPpll = ATOM_DCPLL;
756254885Sdumbbell			break;
757254885Sdumbbell		default:
758254885Sdumbbell			DRM_ERROR("Unknown table version %d %d\n", frev, crev);
759254885Sdumbbell			return;
760254885Sdumbbell		}
761254885Sdumbbell		break;
762254885Sdumbbell	default:
763254885Sdumbbell		DRM_ERROR("Unknown table version %d %d\n", frev, crev);
764254885Sdumbbell		return;
765254885Sdumbbell	}
766254885Sdumbbell	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
767254885Sdumbbell}
768254885Sdumbbell
769254885Sdumbbellstatic void atombios_crtc_program_pll(struct drm_crtc *crtc,
770254885Sdumbbell				      u32 crtc_id,
771254885Sdumbbell				      int pll_id,
772254885Sdumbbell				      u32 encoder_mode,
773254885Sdumbbell				      u32 encoder_id,
774254885Sdumbbell				      u32 clock,
775254885Sdumbbell				      u32 ref_div,
776254885Sdumbbell				      u32 fb_div,
777254885Sdumbbell				      u32 frac_fb_div,
778254885Sdumbbell				      u32 post_div,
779254885Sdumbbell				      int bpc,
780254885Sdumbbell				      bool ss_enabled,
781254885Sdumbbell				      struct radeon_atom_ss *ss)
782254885Sdumbbell{
783254885Sdumbbell	struct drm_device *dev = crtc->dev;
784254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
785254885Sdumbbell	u8 frev, crev;
786254885Sdumbbell	int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
787254885Sdumbbell	union set_pixel_clock args;
788254885Sdumbbell
789254885Sdumbbell	memset(&args, 0, sizeof(args));
790254885Sdumbbell
791254885Sdumbbell	if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
792254885Sdumbbell				   &crev))
793254885Sdumbbell		return;
794254885Sdumbbell
795254885Sdumbbell	switch (frev) {
796254885Sdumbbell	case 1:
797254885Sdumbbell		switch (crev) {
798254885Sdumbbell		case 1:
799254885Sdumbbell			if (clock == ATOM_DISABLE)
800254885Sdumbbell				return;
801254885Sdumbbell			args.v1.usPixelClock = cpu_to_le16(clock / 10);
802254885Sdumbbell			args.v1.usRefDiv = cpu_to_le16(ref_div);
803254885Sdumbbell			args.v1.usFbDiv = cpu_to_le16(fb_div);
804254885Sdumbbell			args.v1.ucFracFbDiv = frac_fb_div;
805254885Sdumbbell			args.v1.ucPostDiv = post_div;
806254885Sdumbbell			args.v1.ucPpll = pll_id;
807254885Sdumbbell			args.v1.ucCRTC = crtc_id;
808254885Sdumbbell			args.v1.ucRefDivSrc = 1;
809254885Sdumbbell			break;
810254885Sdumbbell		case 2:
811254885Sdumbbell			args.v2.usPixelClock = cpu_to_le16(clock / 10);
812254885Sdumbbell			args.v2.usRefDiv = cpu_to_le16(ref_div);
813254885Sdumbbell			args.v2.usFbDiv = cpu_to_le16(fb_div);
814254885Sdumbbell			args.v2.ucFracFbDiv = frac_fb_div;
815254885Sdumbbell			args.v2.ucPostDiv = post_div;
816254885Sdumbbell			args.v2.ucPpll = pll_id;
817254885Sdumbbell			args.v2.ucCRTC = crtc_id;
818254885Sdumbbell			args.v2.ucRefDivSrc = 1;
819254885Sdumbbell			break;
820254885Sdumbbell		case 3:
821254885Sdumbbell			args.v3.usPixelClock = cpu_to_le16(clock / 10);
822254885Sdumbbell			args.v3.usRefDiv = cpu_to_le16(ref_div);
823254885Sdumbbell			args.v3.usFbDiv = cpu_to_le16(fb_div);
824254885Sdumbbell			args.v3.ucFracFbDiv = frac_fb_div;
825254885Sdumbbell			args.v3.ucPostDiv = post_div;
826254885Sdumbbell			args.v3.ucPpll = pll_id;
827254885Sdumbbell			if (crtc_id == ATOM_CRTC2)
828254885Sdumbbell				args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC2;
829254885Sdumbbell			else
830254885Sdumbbell				args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC1;
831254885Sdumbbell			if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
832254885Sdumbbell				args.v3.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC;
833254885Sdumbbell			args.v3.ucTransmitterId = encoder_id;
834254885Sdumbbell			args.v3.ucEncoderMode = encoder_mode;
835254885Sdumbbell			break;
836254885Sdumbbell		case 5:
837254885Sdumbbell			args.v5.ucCRTC = crtc_id;
838254885Sdumbbell			args.v5.usPixelClock = cpu_to_le16(clock / 10);
839254885Sdumbbell			args.v5.ucRefDiv = ref_div;
840254885Sdumbbell			args.v5.usFbDiv = cpu_to_le16(fb_div);
841254885Sdumbbell			args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
842254885Sdumbbell			args.v5.ucPostDiv = post_div;
843254885Sdumbbell			args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */
844254885Sdumbbell			if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
845254885Sdumbbell				args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_REF_DIV_SRC;
846254885Sdumbbell			switch (bpc) {
847254885Sdumbbell			case 8:
848254885Sdumbbell			default:
849254885Sdumbbell				args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP;
850254885Sdumbbell				break;
851254885Sdumbbell			case 10:
852254885Sdumbbell				args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP;
853254885Sdumbbell				break;
854254885Sdumbbell			}
855254885Sdumbbell			args.v5.ucTransmitterID = encoder_id;
856254885Sdumbbell			args.v5.ucEncoderMode = encoder_mode;
857254885Sdumbbell			args.v5.ucPpll = pll_id;
858254885Sdumbbell			break;
859254885Sdumbbell		case 6:
860254885Sdumbbell			args.v6.ulDispEngClkFreq = cpu_to_le32(crtc_id << 24 | clock / 10);
861254885Sdumbbell			args.v6.ucRefDiv = ref_div;
862254885Sdumbbell			args.v6.usFbDiv = cpu_to_le16(fb_div);
863254885Sdumbbell			args.v6.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
864254885Sdumbbell			args.v6.ucPostDiv = post_div;
865254885Sdumbbell			args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */
866254885Sdumbbell			if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
867254885Sdumbbell				args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_REF_DIV_SRC;
868254885Sdumbbell			switch (bpc) {
869254885Sdumbbell			case 8:
870254885Sdumbbell			default:
871254885Sdumbbell				args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP;
872254885Sdumbbell				break;
873254885Sdumbbell			case 10:
874254885Sdumbbell				args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP;
875254885Sdumbbell				break;
876254885Sdumbbell			case 12:
877254885Sdumbbell				args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP;
878254885Sdumbbell				break;
879254885Sdumbbell			case 16:
880254885Sdumbbell				args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP;
881254885Sdumbbell				break;
882254885Sdumbbell			}
883254885Sdumbbell			args.v6.ucTransmitterID = encoder_id;
884254885Sdumbbell			args.v6.ucEncoderMode = encoder_mode;
885254885Sdumbbell			args.v6.ucPpll = pll_id;
886254885Sdumbbell			break;
887254885Sdumbbell		default:
888254885Sdumbbell			DRM_ERROR("Unknown table version %d %d\n", frev, crev);
889254885Sdumbbell			return;
890254885Sdumbbell		}
891254885Sdumbbell		break;
892254885Sdumbbell	default:
893254885Sdumbbell		DRM_ERROR("Unknown table version %d %d\n", frev, crev);
894254885Sdumbbell		return;
895254885Sdumbbell	}
896254885Sdumbbell
897254885Sdumbbell	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
898254885Sdumbbell}
899254885Sdumbbell
900254885Sdumbbellstatic bool atombios_crtc_prepare_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
901254885Sdumbbell{
902254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
903254885Sdumbbell	struct drm_device *dev = crtc->dev;
904254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
905254885Sdumbbell	struct radeon_encoder *radeon_encoder =
906254885Sdumbbell		to_radeon_encoder(radeon_crtc->encoder);
907254885Sdumbbell	int encoder_mode = atombios_get_encoder_mode(radeon_crtc->encoder);
908254885Sdumbbell
909254885Sdumbbell	radeon_crtc->bpc = 8;
910254885Sdumbbell	radeon_crtc->ss_enabled = false;
911254885Sdumbbell
912254885Sdumbbell	if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
913254885Sdumbbell	    (radeon_encoder_get_dp_bridge_encoder_id(radeon_crtc->encoder) != ENCODER_OBJECT_ID_NONE)) {
914254885Sdumbbell		struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
915254885Sdumbbell		struct drm_connector *connector =
916254885Sdumbbell			radeon_get_connector_for_encoder(radeon_crtc->encoder);
917254885Sdumbbell		struct radeon_connector *radeon_connector =
918254885Sdumbbell			to_radeon_connector(connector);
919254885Sdumbbell		struct radeon_connector_atom_dig *dig_connector =
920254885Sdumbbell			radeon_connector->con_priv;
921254885Sdumbbell		int dp_clock;
922254885Sdumbbell		radeon_crtc->bpc = radeon_get_monitor_bpc(connector);
923254885Sdumbbell
924254885Sdumbbell		switch (encoder_mode) {
925254885Sdumbbell		case ATOM_ENCODER_MODE_DP_MST:
926254885Sdumbbell		case ATOM_ENCODER_MODE_DP:
927254885Sdumbbell			/* DP/eDP */
928254885Sdumbbell			dp_clock = dig_connector->dp_clock / 10;
929254885Sdumbbell			if (ASIC_IS_DCE4(rdev))
930254885Sdumbbell				radeon_crtc->ss_enabled =
931254885Sdumbbell					radeon_atombios_get_asic_ss_info(rdev, &radeon_crtc->ss,
932254885Sdumbbell									 ASIC_INTERNAL_SS_ON_DP,
933254885Sdumbbell									 dp_clock);
934254885Sdumbbell			else {
935254885Sdumbbell				if (dp_clock == 16200) {
936254885Sdumbbell					radeon_crtc->ss_enabled =
937254885Sdumbbell						radeon_atombios_get_ppll_ss_info(rdev,
938254885Sdumbbell										 &radeon_crtc->ss,
939254885Sdumbbell										 ATOM_DP_SS_ID2);
940254885Sdumbbell					if (!radeon_crtc->ss_enabled)
941254885Sdumbbell						radeon_crtc->ss_enabled =
942254885Sdumbbell							radeon_atombios_get_ppll_ss_info(rdev,
943254885Sdumbbell											 &radeon_crtc->ss,
944254885Sdumbbell											 ATOM_DP_SS_ID1);
945254885Sdumbbell				} else
946254885Sdumbbell					radeon_crtc->ss_enabled =
947254885Sdumbbell						radeon_atombios_get_ppll_ss_info(rdev,
948254885Sdumbbell										 &radeon_crtc->ss,
949254885Sdumbbell										 ATOM_DP_SS_ID1);
950254885Sdumbbell			}
951254885Sdumbbell			break;
952254885Sdumbbell		case ATOM_ENCODER_MODE_LVDS:
953254885Sdumbbell			if (ASIC_IS_DCE4(rdev))
954254885Sdumbbell				radeon_crtc->ss_enabled =
955254885Sdumbbell					radeon_atombios_get_asic_ss_info(rdev,
956254885Sdumbbell									 &radeon_crtc->ss,
957254885Sdumbbell									 dig->lcd_ss_id,
958254885Sdumbbell									 mode->clock / 10);
959254885Sdumbbell			else
960254885Sdumbbell				radeon_crtc->ss_enabled =
961254885Sdumbbell					radeon_atombios_get_ppll_ss_info(rdev,
962254885Sdumbbell									 &radeon_crtc->ss,
963254885Sdumbbell									 dig->lcd_ss_id);
964254885Sdumbbell			break;
965254885Sdumbbell		case ATOM_ENCODER_MODE_DVI:
966254885Sdumbbell			if (ASIC_IS_DCE4(rdev))
967254885Sdumbbell				radeon_crtc->ss_enabled =
968254885Sdumbbell					radeon_atombios_get_asic_ss_info(rdev,
969254885Sdumbbell									 &radeon_crtc->ss,
970254885Sdumbbell									 ASIC_INTERNAL_SS_ON_TMDS,
971254885Sdumbbell									 mode->clock / 10);
972254885Sdumbbell			break;
973254885Sdumbbell		case ATOM_ENCODER_MODE_HDMI:
974254885Sdumbbell			if (ASIC_IS_DCE4(rdev))
975254885Sdumbbell				radeon_crtc->ss_enabled =
976254885Sdumbbell					radeon_atombios_get_asic_ss_info(rdev,
977254885Sdumbbell									 &radeon_crtc->ss,
978254885Sdumbbell									 ASIC_INTERNAL_SS_ON_HDMI,
979254885Sdumbbell									 mode->clock / 10);
980254885Sdumbbell			break;
981254885Sdumbbell		default:
982254885Sdumbbell			break;
983254885Sdumbbell		}
984254885Sdumbbell	}
985254885Sdumbbell
986254885Sdumbbell	/* adjust pixel clock as needed */
987254885Sdumbbell	radeon_crtc->adjusted_clock = atombios_adjust_pll(crtc, mode);
988254885Sdumbbell
989254885Sdumbbell	return true;
990254885Sdumbbell}
991254885Sdumbbell
992254885Sdumbbellstatic void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
993254885Sdumbbell{
994254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
995254885Sdumbbell	struct drm_device *dev = crtc->dev;
996254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
997254885Sdumbbell	struct radeon_encoder *radeon_encoder =
998254885Sdumbbell		to_radeon_encoder(radeon_crtc->encoder);
999254885Sdumbbell	u32 pll_clock = mode->clock;
1000254885Sdumbbell	u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0;
1001254885Sdumbbell	struct radeon_pll *pll;
1002254885Sdumbbell	int encoder_mode = atombios_get_encoder_mode(radeon_crtc->encoder);
1003254885Sdumbbell
1004254885Sdumbbell	switch (radeon_crtc->pll_id) {
1005254885Sdumbbell	case ATOM_PPLL1:
1006254885Sdumbbell		pll = &rdev->clock.p1pll;
1007254885Sdumbbell		break;
1008254885Sdumbbell	case ATOM_PPLL2:
1009254885Sdumbbell		pll = &rdev->clock.p2pll;
1010254885Sdumbbell		break;
1011254885Sdumbbell	case ATOM_DCPLL:
1012254885Sdumbbell	case ATOM_PPLL_INVALID:
1013254885Sdumbbell	default:
1014254885Sdumbbell		pll = &rdev->clock.dcpll;
1015254885Sdumbbell		break;
1016254885Sdumbbell	}
1017254885Sdumbbell
1018254885Sdumbbell	/* update pll params */
1019254885Sdumbbell	pll->flags = radeon_crtc->pll_flags;
1020254885Sdumbbell	pll->reference_div = radeon_crtc->pll_reference_div;
1021254885Sdumbbell	pll->post_div = radeon_crtc->pll_post_div;
1022254885Sdumbbell
1023254885Sdumbbell	if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
1024254885Sdumbbell		/* TV seems to prefer the legacy algo on some boards */
1025254885Sdumbbell		radeon_compute_pll_legacy(pll, radeon_crtc->adjusted_clock, &pll_clock,
1026254885Sdumbbell					  &fb_div, &frac_fb_div, &ref_div, &post_div);
1027254885Sdumbbell	else if (ASIC_IS_AVIVO(rdev))
1028254885Sdumbbell		radeon_compute_pll_avivo(pll, radeon_crtc->adjusted_clock, &pll_clock,
1029254885Sdumbbell					 &fb_div, &frac_fb_div, &ref_div, &post_div);
1030254885Sdumbbell	else
1031254885Sdumbbell		radeon_compute_pll_legacy(pll, radeon_crtc->adjusted_clock, &pll_clock,
1032254885Sdumbbell					  &fb_div, &frac_fb_div, &ref_div, &post_div);
1033254885Sdumbbell
1034254885Sdumbbell	atombios_crtc_program_ss(rdev, ATOM_DISABLE, radeon_crtc->pll_id,
1035254885Sdumbbell				 radeon_crtc->crtc_id, &radeon_crtc->ss);
1036254885Sdumbbell
1037254885Sdumbbell	atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
1038254885Sdumbbell				  encoder_mode, radeon_encoder->encoder_id, mode->clock,
1039254885Sdumbbell				  ref_div, fb_div, frac_fb_div, post_div,
1040254885Sdumbbell				  radeon_crtc->bpc, radeon_crtc->ss_enabled, &radeon_crtc->ss);
1041254885Sdumbbell
1042254885Sdumbbell	if (radeon_crtc->ss_enabled) {
1043254885Sdumbbell		/* calculate ss amount and step size */
1044254885Sdumbbell		if (ASIC_IS_DCE4(rdev)) {
1045254885Sdumbbell			u32 step_size;
1046254885Sdumbbell			u32 amount = (((fb_div * 10) + frac_fb_div) * radeon_crtc->ss.percentage) / 10000;
1047254885Sdumbbell			radeon_crtc->ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK;
1048254885Sdumbbell			radeon_crtc->ss.amount |= ((amount - (amount / 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) &
1049254885Sdumbbell				ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK;
1050254885Sdumbbell			if (radeon_crtc->ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD)
1051254885Sdumbbell				step_size = (4 * amount * ref_div * (radeon_crtc->ss.rate * 2048)) /
1052254885Sdumbbell					(125 * 25 * pll->reference_freq / 100);
1053254885Sdumbbell			else
1054254885Sdumbbell				step_size = (2 * amount * ref_div * (radeon_crtc->ss.rate * 2048)) /
1055254885Sdumbbell					(125 * 25 * pll->reference_freq / 100);
1056254885Sdumbbell			radeon_crtc->ss.step = step_size;
1057254885Sdumbbell		}
1058254885Sdumbbell
1059254885Sdumbbell		atombios_crtc_program_ss(rdev, ATOM_ENABLE, radeon_crtc->pll_id,
1060254885Sdumbbell					 radeon_crtc->crtc_id, &radeon_crtc->ss);
1061254885Sdumbbell	}
1062254885Sdumbbell}
1063254885Sdumbbell
1064254885Sdumbbellstatic int dce4_crtc_do_set_base(struct drm_crtc *crtc,
1065254885Sdumbbell				 struct drm_framebuffer *fb,
1066254885Sdumbbell				 int x, int y, int atomic)
1067254885Sdumbbell{
1068254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1069254885Sdumbbell	struct drm_device *dev = crtc->dev;
1070254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
1071254885Sdumbbell	struct radeon_framebuffer *radeon_fb;
1072254885Sdumbbell	struct drm_framebuffer *target_fb;
1073254885Sdumbbell	struct drm_gem_object *obj;
1074254885Sdumbbell	struct radeon_bo *rbo;
1075254885Sdumbbell	uint64_t fb_location;
1076254885Sdumbbell	uint32_t fb_format, fb_pitch_pixels, tiling_flags;
1077254885Sdumbbell	unsigned bankw, bankh, mtaspect, tile_split;
1078254885Sdumbbell	u32 fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE);
1079254885Sdumbbell	u32 tmp, viewport_w, viewport_h;
1080254885Sdumbbell	int r;
1081254885Sdumbbell
1082254885Sdumbbell	/* no fb bound */
1083254885Sdumbbell	if (!atomic && !crtc->fb) {
1084254885Sdumbbell		DRM_DEBUG_KMS("No FB bound\n");
1085254885Sdumbbell		return 0;
1086254885Sdumbbell	}
1087254885Sdumbbell
1088254885Sdumbbell	if (atomic) {
1089254885Sdumbbell		radeon_fb = to_radeon_framebuffer(fb);
1090254885Sdumbbell		target_fb = fb;
1091254885Sdumbbell	}
1092254885Sdumbbell	else {
1093254885Sdumbbell		radeon_fb = to_radeon_framebuffer(crtc->fb);
1094254885Sdumbbell		target_fb = crtc->fb;
1095254885Sdumbbell	}
1096254885Sdumbbell
1097254885Sdumbbell	/* If atomic, assume fb object is pinned & idle & fenced and
1098254885Sdumbbell	 * just update base pointers
1099254885Sdumbbell	 */
1100254885Sdumbbell	obj = radeon_fb->obj;
1101254885Sdumbbell	rbo = gem_to_radeon_bo(obj);
1102254885Sdumbbell	r = radeon_bo_reserve(rbo, false);
1103254885Sdumbbell	if (unlikely(r != 0))
1104254885Sdumbbell		return r;
1105254885Sdumbbell
1106254885Sdumbbell	if (atomic)
1107254885Sdumbbell		fb_location = radeon_bo_gpu_offset(rbo);
1108254885Sdumbbell	else {
1109254885Sdumbbell		r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
1110254885Sdumbbell		if (unlikely(r != 0)) {
1111254885Sdumbbell			radeon_bo_unreserve(rbo);
1112254885Sdumbbell			return -EINVAL;
1113254885Sdumbbell		}
1114254885Sdumbbell	}
1115254885Sdumbbell
1116254885Sdumbbell	radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
1117254885Sdumbbell	radeon_bo_unreserve(rbo);
1118254885Sdumbbell
1119254885Sdumbbell	switch (target_fb->bits_per_pixel) {
1120254885Sdumbbell	case 8:
1121254885Sdumbbell		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP) |
1122254885Sdumbbell			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED));
1123254885Sdumbbell		break;
1124254885Sdumbbell	case 15:
1125254885Sdumbbell		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) |
1126254885Sdumbbell			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB1555));
1127254885Sdumbbell		break;
1128254885Sdumbbell	case 16:
1129254885Sdumbbell		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) |
1130254885Sdumbbell			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565));
1131254885Sdumbbell#ifdef __BIG_ENDIAN
1132254885Sdumbbell		fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16);
1133254885Sdumbbell#endif
1134254885Sdumbbell		break;
1135254885Sdumbbell	case 24:
1136254885Sdumbbell	case 32:
1137254885Sdumbbell		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) |
1138254885Sdumbbell			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888));
1139254885Sdumbbell#ifdef __BIG_ENDIAN
1140254885Sdumbbell		fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32);
1141254885Sdumbbell#endif
1142254885Sdumbbell		break;
1143254885Sdumbbell	default:
1144254885Sdumbbell		DRM_ERROR("Unsupported screen depth %d\n",
1145254885Sdumbbell			  target_fb->bits_per_pixel);
1146254885Sdumbbell		return -EINVAL;
1147254885Sdumbbell	}
1148254885Sdumbbell
1149254885Sdumbbell	if (tiling_flags & RADEON_TILING_MACRO) {
1150254885Sdumbbell		if (rdev->family >= CHIP_TAHITI)
1151254885Sdumbbell			tmp = rdev->config.si.tile_config;
1152254885Sdumbbell		else if (rdev->family >= CHIP_CAYMAN)
1153254885Sdumbbell			tmp = rdev->config.cayman.tile_config;
1154254885Sdumbbell		else
1155254885Sdumbbell			tmp = rdev->config.evergreen.tile_config;
1156254885Sdumbbell
1157254885Sdumbbell		switch ((tmp & 0xf0) >> 4) {
1158254885Sdumbbell		case 0: /* 4 banks */
1159254885Sdumbbell			fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_4_BANK);
1160254885Sdumbbell			break;
1161254885Sdumbbell		case 1: /* 8 banks */
1162254885Sdumbbell		default:
1163254885Sdumbbell			fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_8_BANK);
1164254885Sdumbbell			break;
1165254885Sdumbbell		case 2: /* 16 banks */
1166254885Sdumbbell			fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_16_BANK);
1167254885Sdumbbell			break;
1168254885Sdumbbell		}
1169254885Sdumbbell
1170254885Sdumbbell		fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1);
1171254885Sdumbbell
1172254885Sdumbbell		evergreen_tiling_fields(tiling_flags, &bankw, &bankh, &mtaspect, &tile_split);
1173254885Sdumbbell		fb_format |= EVERGREEN_GRPH_TILE_SPLIT(tile_split);
1174254885Sdumbbell		fb_format |= EVERGREEN_GRPH_BANK_WIDTH(bankw);
1175254885Sdumbbell		fb_format |= EVERGREEN_GRPH_BANK_HEIGHT(bankh);
1176254885Sdumbbell		fb_format |= EVERGREEN_GRPH_MACRO_TILE_ASPECT(mtaspect);
1177254885Sdumbbell	} else if (tiling_flags & RADEON_TILING_MICRO)
1178254885Sdumbbell		fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1);
1179254885Sdumbbell
1180254885Sdumbbell	if ((rdev->family == CHIP_TAHITI) ||
1181254885Sdumbbell	    (rdev->family == CHIP_PITCAIRN))
1182254885Sdumbbell		fb_format |= SI_GRPH_PIPE_CONFIG(SI_ADDR_SURF_P8_32x32_8x16);
1183254885Sdumbbell	else if (rdev->family == CHIP_VERDE)
1184254885Sdumbbell		fb_format |= SI_GRPH_PIPE_CONFIG(SI_ADDR_SURF_P4_8x16);
1185254885Sdumbbell
1186254885Sdumbbell	switch (radeon_crtc->crtc_id) {
1187254885Sdumbbell	case 0:
1188254885Sdumbbell		WREG32(AVIVO_D1VGA_CONTROL, 0);
1189254885Sdumbbell		break;
1190254885Sdumbbell	case 1:
1191254885Sdumbbell		WREG32(AVIVO_D2VGA_CONTROL, 0);
1192254885Sdumbbell		break;
1193254885Sdumbbell	case 2:
1194254885Sdumbbell		WREG32(EVERGREEN_D3VGA_CONTROL, 0);
1195254885Sdumbbell		break;
1196254885Sdumbbell	case 3:
1197254885Sdumbbell		WREG32(EVERGREEN_D4VGA_CONTROL, 0);
1198254885Sdumbbell		break;
1199254885Sdumbbell	case 4:
1200254885Sdumbbell		WREG32(EVERGREEN_D5VGA_CONTROL, 0);
1201254885Sdumbbell		break;
1202254885Sdumbbell	case 5:
1203254885Sdumbbell		WREG32(EVERGREEN_D6VGA_CONTROL, 0);
1204254885Sdumbbell		break;
1205254885Sdumbbell	default:
1206254885Sdumbbell		break;
1207254885Sdumbbell	}
1208254885Sdumbbell
1209254885Sdumbbell	WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
1210254885Sdumbbell	       upper_32_bits(fb_location));
1211254885Sdumbbell	WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
1212254885Sdumbbell	       upper_32_bits(fb_location));
1213254885Sdumbbell	WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
1214254885Sdumbbell	       (u32)fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK);
1215254885Sdumbbell	WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
1216254885Sdumbbell	       (u32) fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK);
1217254885Sdumbbell	WREG32(EVERGREEN_GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format);
1218254885Sdumbbell	WREG32(EVERGREEN_GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap);
1219254885Sdumbbell
1220254885Sdumbbell	WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0);
1221254885Sdumbbell	WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);
1222254885Sdumbbell	WREG32(EVERGREEN_GRPH_X_START + radeon_crtc->crtc_offset, 0);
1223254885Sdumbbell	WREG32(EVERGREEN_GRPH_Y_START + radeon_crtc->crtc_offset, 0);
1224254885Sdumbbell	WREG32(EVERGREEN_GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width);
1225254885Sdumbbell	WREG32(EVERGREEN_GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height);
1226254885Sdumbbell
1227254885Sdumbbell	fb_pitch_pixels = target_fb->pitches[0] / (target_fb->bits_per_pixel / 8);
1228254885Sdumbbell	WREG32(EVERGREEN_GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels);
1229254885Sdumbbell	WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1);
1230254885Sdumbbell
1231254885Sdumbbell	WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset,
1232254885Sdumbbell	       target_fb->height);
1233254885Sdumbbell	x &= ~3;
1234254885Sdumbbell	y &= ~1;
1235254885Sdumbbell	WREG32(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset,
1236254885Sdumbbell	       (x << 16) | y);
1237254885Sdumbbell	viewport_w = crtc->mode.hdisplay;
1238254885Sdumbbell	viewport_h = (crtc->mode.vdisplay + 1) & ~1;
1239254885Sdumbbell	WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset,
1240254885Sdumbbell	       (viewport_w << 16) | viewport_h);
1241254885Sdumbbell
1242254885Sdumbbell	/* pageflip setup */
1243254885Sdumbbell	/* make sure flip is at vb rather than hb */
1244254885Sdumbbell	tmp = RREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset);
1245254885Sdumbbell	tmp &= ~EVERGREEN_GRPH_SURFACE_UPDATE_H_RETRACE_EN;
1246254885Sdumbbell	WREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, tmp);
1247254885Sdumbbell
1248254885Sdumbbell	/* set pageflip to happen anywhere in vblank interval */
1249254885Sdumbbell	WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0);
1250254885Sdumbbell
1251254885Sdumbbell	if (!atomic && fb && fb != crtc->fb) {
1252254885Sdumbbell		radeon_fb = to_radeon_framebuffer(fb);
1253254885Sdumbbell		rbo = gem_to_radeon_bo(radeon_fb->obj);
1254254885Sdumbbell		r = radeon_bo_reserve(rbo, false);
1255254885Sdumbbell		if (unlikely(r != 0))
1256254885Sdumbbell			return r;
1257254885Sdumbbell		radeon_bo_unpin(rbo);
1258254885Sdumbbell		radeon_bo_unreserve(rbo);
1259254885Sdumbbell	}
1260254885Sdumbbell
1261254885Sdumbbell	/* Bytes per pixel may have changed */
1262254885Sdumbbell	radeon_bandwidth_update(rdev);
1263254885Sdumbbell
1264254885Sdumbbell	return 0;
1265254885Sdumbbell}
1266254885Sdumbbell
1267254885Sdumbbellstatic int avivo_crtc_do_set_base(struct drm_crtc *crtc,
1268254885Sdumbbell				  struct drm_framebuffer *fb,
1269254885Sdumbbell				  int x, int y, int atomic)
1270254885Sdumbbell{
1271254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1272254885Sdumbbell	struct drm_device *dev = crtc->dev;
1273254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
1274254885Sdumbbell	struct radeon_framebuffer *radeon_fb;
1275254885Sdumbbell	struct drm_gem_object *obj;
1276254885Sdumbbell	struct radeon_bo *rbo;
1277254885Sdumbbell	struct drm_framebuffer *target_fb;
1278254885Sdumbbell	uint64_t fb_location;
1279254885Sdumbbell	uint32_t fb_format, fb_pitch_pixels, tiling_flags;
1280254885Sdumbbell	u32 fb_swap = R600_D1GRPH_SWAP_ENDIAN_NONE;
1281254885Sdumbbell	u32 tmp, viewport_w, viewport_h;
1282254885Sdumbbell	int r;
1283254885Sdumbbell
1284254885Sdumbbell	/* no fb bound */
1285254885Sdumbbell	if (!atomic && !crtc->fb) {
1286254885Sdumbbell		DRM_DEBUG_KMS("No FB bound\n");
1287254885Sdumbbell		return 0;
1288254885Sdumbbell	}
1289254885Sdumbbell
1290254885Sdumbbell	if (atomic) {
1291254885Sdumbbell		radeon_fb = to_radeon_framebuffer(fb);
1292254885Sdumbbell		target_fb = fb;
1293254885Sdumbbell	}
1294254885Sdumbbell	else {
1295254885Sdumbbell		radeon_fb = to_radeon_framebuffer(crtc->fb);
1296254885Sdumbbell		target_fb = crtc->fb;
1297254885Sdumbbell	}
1298254885Sdumbbell
1299254885Sdumbbell	obj = radeon_fb->obj;
1300254885Sdumbbell	rbo = gem_to_radeon_bo(obj);
1301254885Sdumbbell	r = radeon_bo_reserve(rbo, false);
1302254885Sdumbbell	if (unlikely(r != 0))
1303254885Sdumbbell		return r;
1304254885Sdumbbell
1305254885Sdumbbell	/* If atomic, assume fb object is pinned & idle & fenced and
1306254885Sdumbbell	 * just update base pointers
1307254885Sdumbbell	 */
1308254885Sdumbbell	if (atomic)
1309254885Sdumbbell		fb_location = radeon_bo_gpu_offset(rbo);
1310254885Sdumbbell	else {
1311254885Sdumbbell		r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
1312254885Sdumbbell		if (unlikely(r != 0)) {
1313254885Sdumbbell			radeon_bo_unreserve(rbo);
1314254885Sdumbbell			return -EINVAL;
1315254885Sdumbbell		}
1316254885Sdumbbell	}
1317254885Sdumbbell	radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
1318254885Sdumbbell	radeon_bo_unreserve(rbo);
1319254885Sdumbbell
1320254885Sdumbbell	switch (target_fb->bits_per_pixel) {
1321254885Sdumbbell	case 8:
1322254885Sdumbbell		fb_format =
1323254885Sdumbbell		    AVIVO_D1GRPH_CONTROL_DEPTH_8BPP |
1324254885Sdumbbell		    AVIVO_D1GRPH_CONTROL_8BPP_INDEXED;
1325254885Sdumbbell		break;
1326254885Sdumbbell	case 15:
1327254885Sdumbbell		fb_format =
1328254885Sdumbbell		    AVIVO_D1GRPH_CONTROL_DEPTH_16BPP |
1329254885Sdumbbell		    AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555;
1330254885Sdumbbell		break;
1331254885Sdumbbell	case 16:
1332254885Sdumbbell		fb_format =
1333254885Sdumbbell		    AVIVO_D1GRPH_CONTROL_DEPTH_16BPP |
1334254885Sdumbbell		    AVIVO_D1GRPH_CONTROL_16BPP_RGB565;
1335254885Sdumbbell#ifdef __BIG_ENDIAN
1336254885Sdumbbell		fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT;
1337254885Sdumbbell#endif
1338254885Sdumbbell		break;
1339254885Sdumbbell	case 24:
1340254885Sdumbbell	case 32:
1341254885Sdumbbell		fb_format =
1342254885Sdumbbell		    AVIVO_D1GRPH_CONTROL_DEPTH_32BPP |
1343254885Sdumbbell		    AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888;
1344254885Sdumbbell#ifdef __BIG_ENDIAN
1345254885Sdumbbell		fb_swap = R600_D1GRPH_SWAP_ENDIAN_32BIT;
1346254885Sdumbbell#endif
1347254885Sdumbbell		break;
1348254885Sdumbbell	default:
1349254885Sdumbbell		DRM_ERROR("Unsupported screen depth %d\n",
1350254885Sdumbbell			  target_fb->bits_per_pixel);
1351254885Sdumbbell		return -EINVAL;
1352254885Sdumbbell	}
1353254885Sdumbbell
1354254885Sdumbbell	if (rdev->family >= CHIP_R600) {
1355254885Sdumbbell		if (tiling_flags & RADEON_TILING_MACRO)
1356254885Sdumbbell			fb_format |= R600_D1GRPH_ARRAY_MODE_2D_TILED_THIN1;
1357254885Sdumbbell		else if (tiling_flags & RADEON_TILING_MICRO)
1358254885Sdumbbell			fb_format |= R600_D1GRPH_ARRAY_MODE_1D_TILED_THIN1;
1359254885Sdumbbell	} else {
1360254885Sdumbbell		if (tiling_flags & RADEON_TILING_MACRO)
1361254885Sdumbbell			fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE;
1362254885Sdumbbell
1363254885Sdumbbell		if (tiling_flags & RADEON_TILING_MICRO)
1364254885Sdumbbell			fb_format |= AVIVO_D1GRPH_TILED;
1365254885Sdumbbell	}
1366254885Sdumbbell
1367254885Sdumbbell	if (radeon_crtc->crtc_id == 0)
1368254885Sdumbbell		WREG32(AVIVO_D1VGA_CONTROL, 0);
1369254885Sdumbbell	else
1370254885Sdumbbell		WREG32(AVIVO_D2VGA_CONTROL, 0);
1371254885Sdumbbell
1372254885Sdumbbell	if (rdev->family >= CHIP_RV770) {
1373254885Sdumbbell		if (radeon_crtc->crtc_id) {
1374254885Sdumbbell			WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location));
1375254885Sdumbbell			WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location));
1376254885Sdumbbell		} else {
1377254885Sdumbbell			WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location));
1378254885Sdumbbell			WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location));
1379254885Sdumbbell		}
1380254885Sdumbbell	}
1381254885Sdumbbell	WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
1382254885Sdumbbell	       (u32) fb_location);
1383254885Sdumbbell	WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS +
1384254885Sdumbbell	       radeon_crtc->crtc_offset, (u32) fb_location);
1385254885Sdumbbell	WREG32(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format);
1386254885Sdumbbell	if (rdev->family >= CHIP_R600)
1387254885Sdumbbell		WREG32(R600_D1GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap);
1388254885Sdumbbell
1389254885Sdumbbell	WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0);
1390254885Sdumbbell	WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);
1391254885Sdumbbell	WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0);
1392254885Sdumbbell	WREG32(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, 0);
1393254885Sdumbbell	WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width);
1394254885Sdumbbell	WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height);
1395254885Sdumbbell
1396254885Sdumbbell	fb_pitch_pixels = target_fb->pitches[0] / (target_fb->bits_per_pixel / 8);
1397254885Sdumbbell	WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels);
1398254885Sdumbbell	WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1);
1399254885Sdumbbell
1400254885Sdumbbell	WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset,
1401254885Sdumbbell	       target_fb->height);
1402254885Sdumbbell	x &= ~3;
1403254885Sdumbbell	y &= ~1;
1404254885Sdumbbell	WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset,
1405254885Sdumbbell	       (x << 16) | y);
1406254885Sdumbbell	viewport_w = crtc->mode.hdisplay;
1407254885Sdumbbell	viewport_h = (crtc->mode.vdisplay + 1) & ~1;
1408254885Sdumbbell	WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset,
1409254885Sdumbbell	       (viewport_w << 16) | viewport_h);
1410254885Sdumbbell
1411254885Sdumbbell	/* pageflip setup */
1412254885Sdumbbell	/* make sure flip is at vb rather than hb */
1413254885Sdumbbell	tmp = RREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset);
1414254885Sdumbbell	tmp &= ~AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN;
1415254885Sdumbbell	WREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, tmp);
1416254885Sdumbbell
1417254885Sdumbbell	/* set pageflip to happen anywhere in vblank interval */
1418254885Sdumbbell	WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0);
1419254885Sdumbbell
1420254885Sdumbbell	if (!atomic && fb && fb != crtc->fb) {
1421254885Sdumbbell		radeon_fb = to_radeon_framebuffer(fb);
1422254885Sdumbbell		rbo = gem_to_radeon_bo(radeon_fb->obj);
1423254885Sdumbbell		r = radeon_bo_reserve(rbo, false);
1424254885Sdumbbell		if (unlikely(r != 0))
1425254885Sdumbbell			return r;
1426254885Sdumbbell		radeon_bo_unpin(rbo);
1427254885Sdumbbell		radeon_bo_unreserve(rbo);
1428254885Sdumbbell	}
1429254885Sdumbbell
1430254885Sdumbbell	/* Bytes per pixel may have changed */
1431254885Sdumbbell	radeon_bandwidth_update(rdev);
1432254885Sdumbbell
1433254885Sdumbbell	return 0;
1434254885Sdumbbell}
1435254885Sdumbbell
1436254885Sdumbbellint atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
1437254885Sdumbbell			   struct drm_framebuffer *old_fb)
1438254885Sdumbbell{
1439254885Sdumbbell	struct drm_device *dev = crtc->dev;
1440254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
1441254885Sdumbbell
1442254885Sdumbbell	if (ASIC_IS_DCE4(rdev))
1443254885Sdumbbell		return dce4_crtc_do_set_base(crtc, old_fb, x, y, 0);
1444254885Sdumbbell	else if (ASIC_IS_AVIVO(rdev))
1445254885Sdumbbell		return avivo_crtc_do_set_base(crtc, old_fb, x, y, 0);
1446254885Sdumbbell	else
1447254885Sdumbbell		return radeon_crtc_do_set_base(crtc, old_fb, x, y, 0);
1448254885Sdumbbell}
1449254885Sdumbbell
1450254885Sdumbbellint atombios_crtc_set_base_atomic(struct drm_crtc *crtc,
1451254885Sdumbbell                                  struct drm_framebuffer *fb,
1452254885Sdumbbell				  int x, int y, enum mode_set_atomic state)
1453254885Sdumbbell{
1454254885Sdumbbell       struct drm_device *dev = crtc->dev;
1455254885Sdumbbell       struct radeon_device *rdev = dev->dev_private;
1456254885Sdumbbell
1457254885Sdumbbell	if (ASIC_IS_DCE4(rdev))
1458254885Sdumbbell		return dce4_crtc_do_set_base(crtc, fb, x, y, 1);
1459254885Sdumbbell	else if (ASIC_IS_AVIVO(rdev))
1460254885Sdumbbell		return avivo_crtc_do_set_base(crtc, fb, x, y, 1);
1461254885Sdumbbell	else
1462254885Sdumbbell		return radeon_crtc_do_set_base(crtc, fb, x, y, 1);
1463254885Sdumbbell}
1464254885Sdumbbell
1465254885Sdumbbell/* properly set additional regs when using atombios */
1466254885Sdumbbellstatic void radeon_legacy_atom_fixup(struct drm_crtc *crtc)
1467254885Sdumbbell{
1468254885Sdumbbell	struct drm_device *dev = crtc->dev;
1469254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
1470254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1471254885Sdumbbell	u32 disp_merge_cntl;
1472254885Sdumbbell
1473254885Sdumbbell	switch (radeon_crtc->crtc_id) {
1474254885Sdumbbell	case 0:
1475254885Sdumbbell		disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL);
1476254885Sdumbbell		disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN;
1477254885Sdumbbell		WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl);
1478254885Sdumbbell		break;
1479254885Sdumbbell	case 1:
1480254885Sdumbbell		disp_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL);
1481254885Sdumbbell		disp_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN;
1482254885Sdumbbell		WREG32(RADEON_DISP2_MERGE_CNTL, disp_merge_cntl);
1483254885Sdumbbell		WREG32(RADEON_FP_H2_SYNC_STRT_WID,   RREG32(RADEON_CRTC2_H_SYNC_STRT_WID));
1484254885Sdumbbell		WREG32(RADEON_FP_V2_SYNC_STRT_WID,   RREG32(RADEON_CRTC2_V_SYNC_STRT_WID));
1485254885Sdumbbell		break;
1486254885Sdumbbell	}
1487254885Sdumbbell}
1488254885Sdumbbell
1489254885Sdumbbell/**
1490254885Sdumbbell * radeon_get_pll_use_mask - look up a mask of which pplls are in use
1491254885Sdumbbell *
1492254885Sdumbbell * @crtc: drm crtc
1493254885Sdumbbell *
1494254885Sdumbbell * Returns the mask of which PPLLs (Pixel PLLs) are in use.
1495254885Sdumbbell */
1496254885Sdumbbellstatic u32 radeon_get_pll_use_mask(struct drm_crtc *crtc)
1497254885Sdumbbell{
1498254885Sdumbbell	struct drm_device *dev = crtc->dev;
1499254885Sdumbbell	struct drm_crtc *test_crtc;
1500254885Sdumbbell	struct radeon_crtc *test_radeon_crtc;
1501254885Sdumbbell	u32 pll_in_use = 0;
1502254885Sdumbbell
1503254885Sdumbbell	list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
1504254885Sdumbbell		if (crtc == test_crtc)
1505254885Sdumbbell			continue;
1506254885Sdumbbell
1507254885Sdumbbell		test_radeon_crtc = to_radeon_crtc(test_crtc);
1508254885Sdumbbell		if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID)
1509254885Sdumbbell			pll_in_use |= (1 << test_radeon_crtc->pll_id);
1510254885Sdumbbell	}
1511254885Sdumbbell	return pll_in_use;
1512254885Sdumbbell}
1513254885Sdumbbell
1514254885Sdumbbell/**
1515254885Sdumbbell * radeon_get_shared_dp_ppll - return the PPLL used by another crtc for DP
1516254885Sdumbbell *
1517254885Sdumbbell * @crtc: drm crtc
1518254885Sdumbbell *
1519254885Sdumbbell * Returns the PPLL (Pixel PLL) used by another crtc/encoder which is
1520254885Sdumbbell * also in DP mode.  For DP, a single PPLL can be used for all DP
1521254885Sdumbbell * crtcs/encoders.
1522254885Sdumbbell */
1523254885Sdumbbellstatic int radeon_get_shared_dp_ppll(struct drm_crtc *crtc)
1524254885Sdumbbell{
1525254885Sdumbbell	struct drm_device *dev = crtc->dev;
1526254885Sdumbbell	struct drm_crtc *test_crtc;
1527254885Sdumbbell	struct radeon_crtc *test_radeon_crtc;
1528254885Sdumbbell
1529254885Sdumbbell	list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
1530254885Sdumbbell		if (crtc == test_crtc)
1531254885Sdumbbell			continue;
1532254885Sdumbbell		test_radeon_crtc = to_radeon_crtc(test_crtc);
1533254885Sdumbbell		if (test_radeon_crtc->encoder &&
1534254885Sdumbbell		    ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_radeon_crtc->encoder))) {
1535254885Sdumbbell			/* for DP use the same PLL for all */
1536254885Sdumbbell			if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID)
1537254885Sdumbbell				return test_radeon_crtc->pll_id;
1538254885Sdumbbell		}
1539254885Sdumbbell	}
1540254885Sdumbbell	return ATOM_PPLL_INVALID;
1541254885Sdumbbell}
1542254885Sdumbbell
1543254885Sdumbbell/**
1544254885Sdumbbell * radeon_get_shared_nondp_ppll - return the PPLL used by another non-DP crtc
1545254885Sdumbbell *
1546254885Sdumbbell * @crtc: drm crtc
1547254885Sdumbbell * @encoder: drm encoder
1548254885Sdumbbell *
1549254885Sdumbbell * Returns the PPLL (Pixel PLL) used by another non-DP crtc/encoder which can
1550254885Sdumbbell * be shared (i.e., same clock).
1551254885Sdumbbell */
1552254885Sdumbbellstatic int radeon_get_shared_nondp_ppll(struct drm_crtc *crtc)
1553254885Sdumbbell{
1554254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1555254885Sdumbbell	struct drm_device *dev = crtc->dev;
1556254885Sdumbbell	struct drm_crtc *test_crtc;
1557254885Sdumbbell	struct radeon_crtc *test_radeon_crtc;
1558254885Sdumbbell	u32 adjusted_clock, test_adjusted_clock;
1559254885Sdumbbell
1560254885Sdumbbell	adjusted_clock = radeon_crtc->adjusted_clock;
1561254885Sdumbbell
1562254885Sdumbbell	if (adjusted_clock == 0)
1563254885Sdumbbell		return ATOM_PPLL_INVALID;
1564254885Sdumbbell
1565254885Sdumbbell	list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
1566254885Sdumbbell		if (crtc == test_crtc)
1567254885Sdumbbell			continue;
1568254885Sdumbbell		test_radeon_crtc = to_radeon_crtc(test_crtc);
1569254885Sdumbbell		if (test_radeon_crtc->encoder &&
1570254885Sdumbbell		    !ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_radeon_crtc->encoder))) {
1571254885Sdumbbell			/* check if we are already driving this connector with another crtc */
1572254885Sdumbbell			if (test_radeon_crtc->connector == radeon_crtc->connector) {
1573254885Sdumbbell				/* if we are, return that pll */
1574254885Sdumbbell				if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID)
1575254885Sdumbbell					return test_radeon_crtc->pll_id;
1576254885Sdumbbell			}
1577254885Sdumbbell			/* for non-DP check the clock */
1578254885Sdumbbell			test_adjusted_clock = test_radeon_crtc->adjusted_clock;
1579254885Sdumbbell			if ((crtc->mode.clock == test_crtc->mode.clock) &&
1580254885Sdumbbell			    (adjusted_clock == test_adjusted_clock) &&
1581254885Sdumbbell			    (radeon_crtc->ss_enabled == test_radeon_crtc->ss_enabled) &&
1582254885Sdumbbell			    (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID))
1583254885Sdumbbell				return test_radeon_crtc->pll_id;
1584254885Sdumbbell		}
1585254885Sdumbbell	}
1586254885Sdumbbell	return ATOM_PPLL_INVALID;
1587254885Sdumbbell}
1588254885Sdumbbell
1589254885Sdumbbell/**
1590254885Sdumbbell * radeon_atom_pick_pll - Allocate a PPLL for use by the crtc.
1591254885Sdumbbell *
1592254885Sdumbbell * @crtc: drm crtc
1593254885Sdumbbell *
1594254885Sdumbbell * Returns the PPLL (Pixel PLL) to be used by the crtc.  For DP monitors
1595254885Sdumbbell * a single PPLL can be used for all DP crtcs/encoders.  For non-DP
1596254885Sdumbbell * monitors a dedicated PPLL must be used.  If a particular board has
1597254885Sdumbbell * an external DP PLL, return ATOM_PPLL_INVALID to skip PLL programming
1598254885Sdumbbell * as there is no need to program the PLL itself.  If we are not able to
1599254885Sdumbbell * allocate a PLL, return ATOM_PPLL_INVALID to skip PLL programming to
1600254885Sdumbbell * avoid messing up an existing monitor.
1601254885Sdumbbell *
1602254885Sdumbbell * Asic specific PLL information
1603254885Sdumbbell *
1604254885Sdumbbell * DCE 6.1
1605254885Sdumbbell * - PPLL2 is only available to UNIPHYA (both DP and non-DP)
1606254885Sdumbbell * - PPLL0, PPLL1 are available for UNIPHYB/C/D/E/F (both DP and non-DP)
1607254885Sdumbbell *
1608254885Sdumbbell * DCE 6.0
1609254885Sdumbbell * - PPLL0 is available to all UNIPHY (DP only)
1610254885Sdumbbell * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC
1611254885Sdumbbell *
1612254885Sdumbbell * DCE 5.0
1613254885Sdumbbell * - DCPLL is available to all UNIPHY (DP only)
1614254885Sdumbbell * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC
1615254885Sdumbbell *
1616254885Sdumbbell * DCE 3.0/4.0/4.1
1617254885Sdumbbell * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC
1618254885Sdumbbell *
1619254885Sdumbbell */
1620254885Sdumbbellstatic int radeon_atom_pick_pll(struct drm_crtc *crtc)
1621254885Sdumbbell{
1622254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1623254885Sdumbbell	struct drm_device *dev = crtc->dev;
1624254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
1625254885Sdumbbell	struct radeon_encoder *radeon_encoder =
1626254885Sdumbbell		to_radeon_encoder(radeon_crtc->encoder);
1627254885Sdumbbell	u32 pll_in_use;
1628254885Sdumbbell	int pll;
1629254885Sdumbbell
1630254885Sdumbbell	if (ASIC_IS_DCE61(rdev)) {
1631254885Sdumbbell		struct radeon_encoder_atom_dig *dig =
1632254885Sdumbbell			radeon_encoder->enc_priv;
1633254885Sdumbbell
1634254885Sdumbbell		if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY) &&
1635254885Sdumbbell		    (dig->linkb == false))
1636254885Sdumbbell			/* UNIPHY A uses PPLL2 */
1637254885Sdumbbell			return ATOM_PPLL2;
1638254885Sdumbbell		else if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) {
1639254885Sdumbbell			/* UNIPHY B/C/D/E/F */
1640254885Sdumbbell			if (rdev->clock.dp_extclk)
1641254885Sdumbbell				/* skip PPLL programming if using ext clock */
1642254885Sdumbbell				return ATOM_PPLL_INVALID;
1643254885Sdumbbell			else {
1644254885Sdumbbell				/* use the same PPLL for all DP monitors */
1645254885Sdumbbell				pll = radeon_get_shared_dp_ppll(crtc);
1646254885Sdumbbell				if (pll != ATOM_PPLL_INVALID)
1647254885Sdumbbell					return pll;
1648254885Sdumbbell			}
1649254885Sdumbbell		} else {
1650254885Sdumbbell			/* use the same PPLL for all monitors with the same clock */
1651254885Sdumbbell			pll = radeon_get_shared_nondp_ppll(crtc);
1652254885Sdumbbell			if (pll != ATOM_PPLL_INVALID)
1653254885Sdumbbell				return pll;
1654254885Sdumbbell		}
1655254885Sdumbbell		/* UNIPHY B/C/D/E/F */
1656254885Sdumbbell		pll_in_use = radeon_get_pll_use_mask(crtc);
1657254885Sdumbbell		if (!(pll_in_use & (1 << ATOM_PPLL0)))
1658254885Sdumbbell			return ATOM_PPLL0;
1659254885Sdumbbell		if (!(pll_in_use & (1 << ATOM_PPLL1)))
1660254885Sdumbbell			return ATOM_PPLL1;
1661254885Sdumbbell		DRM_ERROR("unable to allocate a PPLL\n");
1662254885Sdumbbell		return ATOM_PPLL_INVALID;
1663254885Sdumbbell	} else if (ASIC_IS_DCE4(rdev)) {
1664254885Sdumbbell		/* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock,
1665254885Sdumbbell		 * depending on the asic:
1666254885Sdumbbell		 * DCE4: PPLL or ext clock
1667254885Sdumbbell		 * DCE5: PPLL, DCPLL, or ext clock
1668254885Sdumbbell		 * DCE6: PPLL, PPLL0, or ext clock
1669254885Sdumbbell		 *
1670254885Sdumbbell		 * Setting ATOM_PPLL_INVALID will cause SetPixelClock to skip
1671254885Sdumbbell		 * PPLL/DCPLL programming and only program the DP DTO for the
1672254885Sdumbbell		 * crtc virtual pixel clock.
1673254885Sdumbbell		 */
1674254885Sdumbbell		if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) {
1675254885Sdumbbell			if (rdev->clock.dp_extclk)
1676254885Sdumbbell				/* skip PPLL programming if using ext clock */
1677254885Sdumbbell				return ATOM_PPLL_INVALID;
1678254885Sdumbbell			else if (ASIC_IS_DCE6(rdev))
1679254885Sdumbbell				/* use PPLL0 for all DP */
1680254885Sdumbbell				return ATOM_PPLL0;
1681254885Sdumbbell			else if (ASIC_IS_DCE5(rdev))
1682254885Sdumbbell				/* use DCPLL for all DP */
1683254885Sdumbbell				return ATOM_DCPLL;
1684254885Sdumbbell			else {
1685254885Sdumbbell				/* use the same PPLL for all DP monitors */
1686254885Sdumbbell				pll = radeon_get_shared_dp_ppll(crtc);
1687254885Sdumbbell				if (pll != ATOM_PPLL_INVALID)
1688254885Sdumbbell					return pll;
1689254885Sdumbbell			}
1690254885Sdumbbell		} else {
1691254885Sdumbbell			/* use the same PPLL for all monitors with the same clock */
1692254885Sdumbbell			pll = radeon_get_shared_nondp_ppll(crtc);
1693254885Sdumbbell			if (pll != ATOM_PPLL_INVALID)
1694254885Sdumbbell				return pll;
1695254885Sdumbbell		}
1696254885Sdumbbell		/* all other cases */
1697254885Sdumbbell		pll_in_use = radeon_get_pll_use_mask(crtc);
1698254885Sdumbbell		if (!(pll_in_use & (1 << ATOM_PPLL1)))
1699254885Sdumbbell			return ATOM_PPLL1;
1700254885Sdumbbell		if (!(pll_in_use & (1 << ATOM_PPLL2)))
1701254885Sdumbbell			return ATOM_PPLL2;
1702254885Sdumbbell		DRM_ERROR("unable to allocate a PPLL\n");
1703254885Sdumbbell		return ATOM_PPLL_INVALID;
1704254885Sdumbbell	} else {
1705254885Sdumbbell		/* on pre-R5xx asics, the crtc to pll mapping is hardcoded */
1706254885Sdumbbell		/* some atombios (observed in some DCE2/DCE3) code have a bug,
1707254885Sdumbbell		 * the matching btw pll and crtc is done through
1708254885Sdumbbell		 * PCLK_CRTC[1|2]_CNTL (0x480/0x484) but atombios code use the
1709254885Sdumbbell		 * pll (1 or 2) to select which register to write. ie if using
1710254885Sdumbbell		 * pll1 it will use PCLK_CRTC1_CNTL (0x480) and if using pll2
1711254885Sdumbbell		 * it will use PCLK_CRTC2_CNTL (0x484), it then use crtc id to
1712254885Sdumbbell		 * choose which value to write. Which is reverse order from
1713254885Sdumbbell		 * register logic. So only case that works is when pllid is
1714254885Sdumbbell		 * same as crtcid or when both pll and crtc are enabled and
1715254885Sdumbbell		 * both use same clock.
1716254885Sdumbbell		 *
1717254885Sdumbbell		 * So just return crtc id as if crtc and pll were hard linked
1718254885Sdumbbell		 * together even if they aren't
1719254885Sdumbbell		 */
1720254885Sdumbbell		return radeon_crtc->crtc_id;
1721254885Sdumbbell	}
1722254885Sdumbbell}
1723254885Sdumbbell
1724254885Sdumbbellvoid radeon_atom_disp_eng_pll_init(struct radeon_device *rdev)
1725254885Sdumbbell{
1726254885Sdumbbell	/* always set DCPLL */
1727254885Sdumbbell	if (ASIC_IS_DCE6(rdev))
1728254885Sdumbbell		atombios_crtc_set_disp_eng_pll(rdev, rdev->clock.default_dispclk);
1729254885Sdumbbell	else if (ASIC_IS_DCE4(rdev)) {
1730254885Sdumbbell		struct radeon_atom_ss ss;
1731254885Sdumbbell		bool ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &ss,
1732254885Sdumbbell								   ASIC_INTERNAL_SS_ON_DCPLL,
1733254885Sdumbbell								   rdev->clock.default_dispclk);
1734254885Sdumbbell		if (ss_enabled)
1735254885Sdumbbell			atombios_crtc_program_ss(rdev, ATOM_DISABLE, ATOM_DCPLL, -1, &ss);
1736254885Sdumbbell		/* XXX: DCE5, make sure voltage, dispclk is high enough */
1737254885Sdumbbell		atombios_crtc_set_disp_eng_pll(rdev, rdev->clock.default_dispclk);
1738254885Sdumbbell		if (ss_enabled)
1739254885Sdumbbell			atombios_crtc_program_ss(rdev, ATOM_ENABLE, ATOM_DCPLL, -1, &ss);
1740254885Sdumbbell	}
1741254885Sdumbbell
1742254885Sdumbbell}
1743254885Sdumbbell
1744254885Sdumbbellint atombios_crtc_mode_set(struct drm_crtc *crtc,
1745254885Sdumbbell			   struct drm_display_mode *mode,
1746254885Sdumbbell			   struct drm_display_mode *adjusted_mode,
1747254885Sdumbbell			   int x, int y, struct drm_framebuffer *old_fb)
1748254885Sdumbbell{
1749254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1750254885Sdumbbell	struct drm_device *dev = crtc->dev;
1751254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
1752254885Sdumbbell	struct radeon_encoder *radeon_encoder =
1753254885Sdumbbell		to_radeon_encoder(radeon_crtc->encoder);
1754254885Sdumbbell	bool is_tvcv = false;
1755254885Sdumbbell
1756254885Sdumbbell	if (radeon_encoder->active_device &
1757254885Sdumbbell	    (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT))
1758254885Sdumbbell		is_tvcv = true;
1759254885Sdumbbell
1760254885Sdumbbell	atombios_crtc_set_pll(crtc, adjusted_mode);
1761254885Sdumbbell
1762254885Sdumbbell	if (ASIC_IS_DCE4(rdev))
1763254885Sdumbbell		atombios_set_crtc_dtd_timing(crtc, adjusted_mode);
1764254885Sdumbbell	else if (ASIC_IS_AVIVO(rdev)) {
1765254885Sdumbbell		if (is_tvcv)
1766254885Sdumbbell			atombios_crtc_set_timing(crtc, adjusted_mode);
1767254885Sdumbbell		else
1768254885Sdumbbell			atombios_set_crtc_dtd_timing(crtc, adjusted_mode);
1769254885Sdumbbell	} else {
1770254885Sdumbbell		atombios_crtc_set_timing(crtc, adjusted_mode);
1771254885Sdumbbell		if (radeon_crtc->crtc_id == 0)
1772254885Sdumbbell			atombios_set_crtc_dtd_timing(crtc, adjusted_mode);
1773254885Sdumbbell		radeon_legacy_atom_fixup(crtc);
1774254885Sdumbbell	}
1775254885Sdumbbell	atombios_crtc_set_base(crtc, x, y, old_fb);
1776254885Sdumbbell	atombios_overscan_setup(crtc, mode, adjusted_mode);
1777254885Sdumbbell	atombios_scaler_setup(crtc);
1778254885Sdumbbell	return 0;
1779254885Sdumbbell}
1780254885Sdumbbell
1781254885Sdumbbellstatic bool atombios_crtc_mode_fixup(struct drm_crtc *crtc,
1782254885Sdumbbell				     const struct drm_display_mode *mode,
1783254885Sdumbbell				     struct drm_display_mode *adjusted_mode)
1784254885Sdumbbell{
1785254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1786254885Sdumbbell	struct drm_device *dev = crtc->dev;
1787254885Sdumbbell	struct drm_encoder *encoder;
1788254885Sdumbbell
1789254885Sdumbbell	/* assign the encoder to the radeon crtc to avoid repeated lookups later */
1790254885Sdumbbell	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
1791254885Sdumbbell		if (encoder->crtc == crtc) {
1792254885Sdumbbell			radeon_crtc->encoder = encoder;
1793254885Sdumbbell			radeon_crtc->connector = radeon_get_connector_for_encoder(encoder);
1794254885Sdumbbell			break;
1795254885Sdumbbell		}
1796254885Sdumbbell	}
1797254885Sdumbbell	if ((radeon_crtc->encoder == NULL) || (radeon_crtc->connector == NULL)) {
1798254885Sdumbbell		radeon_crtc->encoder = NULL;
1799254885Sdumbbell		radeon_crtc->connector = NULL;
1800254885Sdumbbell		return false;
1801254885Sdumbbell	}
1802254885Sdumbbell	if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode))
1803254885Sdumbbell		return false;
1804254885Sdumbbell	if (!atombios_crtc_prepare_pll(crtc, adjusted_mode))
1805254885Sdumbbell		return false;
1806254885Sdumbbell	/* pick pll */
1807254885Sdumbbell	radeon_crtc->pll_id = radeon_atom_pick_pll(crtc);
1808254885Sdumbbell	/* if we can't get a PPLL for a non-DP encoder, fail */
1809254885Sdumbbell	if ((radeon_crtc->pll_id == ATOM_PPLL_INVALID) &&
1810254885Sdumbbell	    !ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder)))
1811254885Sdumbbell		return false;
1812254885Sdumbbell
1813254885Sdumbbell	return true;
1814254885Sdumbbell}
1815254885Sdumbbell
1816254885Sdumbbellstatic void atombios_crtc_prepare(struct drm_crtc *crtc)
1817254885Sdumbbell{
1818254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1819254885Sdumbbell	struct drm_device *dev = crtc->dev;
1820254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
1821254885Sdumbbell
1822254885Sdumbbell	radeon_crtc->in_mode_set = true;
1823254885Sdumbbell
1824254885Sdumbbell	/* disable crtc pair power gating before programming */
1825254885Sdumbbell	if (ASIC_IS_DCE6(rdev))
1826254885Sdumbbell		atombios_powergate_crtc(crtc, ATOM_DISABLE);
1827254885Sdumbbell
1828254885Sdumbbell	atombios_lock_crtc(crtc, ATOM_ENABLE);
1829254885Sdumbbell	atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
1830254885Sdumbbell}
1831254885Sdumbbell
1832254885Sdumbbellstatic void atombios_crtc_commit(struct drm_crtc *crtc)
1833254885Sdumbbell{
1834254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1835254885Sdumbbell
1836254885Sdumbbell	atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
1837254885Sdumbbell	atombios_lock_crtc(crtc, ATOM_DISABLE);
1838254885Sdumbbell	radeon_crtc->in_mode_set = false;
1839254885Sdumbbell}
1840254885Sdumbbell
1841254885Sdumbbellstatic void atombios_crtc_disable(struct drm_crtc *crtc)
1842254885Sdumbbell{
1843254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1844254885Sdumbbell	struct drm_device *dev = crtc->dev;
1845254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
1846254885Sdumbbell	struct radeon_atom_ss ss;
1847254885Sdumbbell	int i;
1848254885Sdumbbell
1849254885Sdumbbell	atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
1850282199Sdumbbell	if (ASIC_IS_DCE6(rdev))
1851282199Sdumbbell		atombios_powergate_crtc(crtc, ATOM_ENABLE);
1852254885Sdumbbell
1853254885Sdumbbell	for (i = 0; i < rdev->num_crtc; i++) {
1854254885Sdumbbell		if (rdev->mode_info.crtcs[i] &&
1855254885Sdumbbell		    rdev->mode_info.crtcs[i]->enabled &&
1856254885Sdumbbell		    i != radeon_crtc->crtc_id &&
1857254885Sdumbbell		    radeon_crtc->pll_id == rdev->mode_info.crtcs[i]->pll_id) {
1858254885Sdumbbell			/* one other crtc is using this pll don't turn
1859254885Sdumbbell			 * off the pll
1860254885Sdumbbell			 */
1861254885Sdumbbell			goto done;
1862254885Sdumbbell		}
1863254885Sdumbbell	}
1864254885Sdumbbell
1865254885Sdumbbell	switch (radeon_crtc->pll_id) {
1866254885Sdumbbell	case ATOM_PPLL1:
1867254885Sdumbbell	case ATOM_PPLL2:
1868254885Sdumbbell		/* disable the ppll */
1869254885Sdumbbell		atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
1870254885Sdumbbell					  0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss);
1871254885Sdumbbell		break;
1872254885Sdumbbell	case ATOM_PPLL0:
1873254885Sdumbbell		/* disable the ppll */
1874254885Sdumbbell		if (ASIC_IS_DCE61(rdev))
1875254885Sdumbbell			atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
1876254885Sdumbbell						  0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss);
1877254885Sdumbbell		break;
1878254885Sdumbbell	default:
1879254885Sdumbbell		break;
1880254885Sdumbbell	}
1881254885Sdumbbelldone:
1882254885Sdumbbell	radeon_crtc->pll_id = ATOM_PPLL_INVALID;
1883254885Sdumbbell	radeon_crtc->adjusted_clock = 0;
1884254885Sdumbbell	radeon_crtc->encoder = NULL;
1885254885Sdumbbell	radeon_crtc->connector = NULL;
1886254885Sdumbbell}
1887254885Sdumbbell
1888254885Sdumbbellstatic const struct drm_crtc_helper_funcs atombios_helper_funcs = {
1889254885Sdumbbell	.dpms = atombios_crtc_dpms,
1890254885Sdumbbell	.mode_fixup = atombios_crtc_mode_fixup,
1891254885Sdumbbell	.mode_set = atombios_crtc_mode_set,
1892254885Sdumbbell	.mode_set_base = atombios_crtc_set_base,
1893254885Sdumbbell	.mode_set_base_atomic = atombios_crtc_set_base_atomic,
1894254885Sdumbbell	.prepare = atombios_crtc_prepare,
1895254885Sdumbbell	.commit = atombios_crtc_commit,
1896254885Sdumbbell	.load_lut = radeon_crtc_load_lut,
1897254885Sdumbbell	.disable = atombios_crtc_disable,
1898254885Sdumbbell};
1899254885Sdumbbell
1900254885Sdumbbellvoid radeon_atombios_init_crtc(struct drm_device *dev,
1901254885Sdumbbell			       struct radeon_crtc *radeon_crtc)
1902254885Sdumbbell{
1903254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
1904254885Sdumbbell
1905254885Sdumbbell	if (ASIC_IS_DCE4(rdev)) {
1906254885Sdumbbell		switch (radeon_crtc->crtc_id) {
1907254885Sdumbbell		case 0:
1908254885Sdumbbell		default:
1909254885Sdumbbell			radeon_crtc->crtc_offset = EVERGREEN_CRTC0_REGISTER_OFFSET;
1910254885Sdumbbell			break;
1911254885Sdumbbell		case 1:
1912254885Sdumbbell			radeon_crtc->crtc_offset = EVERGREEN_CRTC1_REGISTER_OFFSET;
1913254885Sdumbbell			break;
1914254885Sdumbbell		case 2:
1915254885Sdumbbell			radeon_crtc->crtc_offset = EVERGREEN_CRTC2_REGISTER_OFFSET;
1916254885Sdumbbell			break;
1917254885Sdumbbell		case 3:
1918254885Sdumbbell			radeon_crtc->crtc_offset = EVERGREEN_CRTC3_REGISTER_OFFSET;
1919254885Sdumbbell			break;
1920254885Sdumbbell		case 4:
1921254885Sdumbbell			radeon_crtc->crtc_offset = EVERGREEN_CRTC4_REGISTER_OFFSET;
1922254885Sdumbbell			break;
1923254885Sdumbbell		case 5:
1924254885Sdumbbell			radeon_crtc->crtc_offset = EVERGREEN_CRTC5_REGISTER_OFFSET;
1925254885Sdumbbell			break;
1926254885Sdumbbell		}
1927254885Sdumbbell	} else {
1928254885Sdumbbell		if (radeon_crtc->crtc_id == 1)
1929254885Sdumbbell			radeon_crtc->crtc_offset =
1930254885Sdumbbell				AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL;
1931254885Sdumbbell		else
1932254885Sdumbbell			radeon_crtc->crtc_offset = 0;
1933254885Sdumbbell	}
1934254885Sdumbbell	radeon_crtc->pll_id = ATOM_PPLL_INVALID;
1935254885Sdumbbell	radeon_crtc->adjusted_clock = 0;
1936254885Sdumbbell	radeon_crtc->encoder = NULL;
1937254885Sdumbbell	radeon_crtc->connector = NULL;
1938254885Sdumbbell	drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs);
1939254885Sdumbbell}
1940