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