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
37254885Sdumbbellstatic void radeon_overscan_setup(struct drm_crtc *crtc,
38254885Sdumbbell				  struct drm_display_mode *mode)
39254885Sdumbbell{
40254885Sdumbbell	struct drm_device *dev = crtc->dev;
41254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
42254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
43254885Sdumbbell
44254885Sdumbbell	WREG32(RADEON_OVR_CLR + radeon_crtc->crtc_offset, 0);
45254885Sdumbbell	WREG32(RADEON_OVR_WID_LEFT_RIGHT + radeon_crtc->crtc_offset, 0);
46254885Sdumbbell	WREG32(RADEON_OVR_WID_TOP_BOTTOM + radeon_crtc->crtc_offset, 0);
47254885Sdumbbell}
48254885Sdumbbell
49254885Sdumbbellstatic void radeon_legacy_rmx_mode_set(struct drm_crtc *crtc,
50254885Sdumbbell				       struct drm_display_mode *mode)
51254885Sdumbbell{
52254885Sdumbbell	struct drm_device *dev = crtc->dev;
53254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
54254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
55254885Sdumbbell	int xres = mode->hdisplay;
56254885Sdumbbell	int yres = mode->vdisplay;
57254885Sdumbbell	bool hscale = true, vscale = true;
58254885Sdumbbell	int hsync_wid;
59254885Sdumbbell	int vsync_wid;
60254885Sdumbbell	int hsync_start;
61254885Sdumbbell	int blank_width;
62254885Sdumbbell	u32 scale, inc, crtc_more_cntl;
63254885Sdumbbell	u32 fp_horz_stretch, fp_vert_stretch, fp_horz_vert_active;
64254885Sdumbbell	u32 fp_h_sync_strt_wid, fp_crtc_h_total_disp;
65254885Sdumbbell	u32 fp_v_sync_strt_wid, fp_crtc_v_total_disp;
66254885Sdumbbell	struct drm_display_mode *native_mode = &radeon_crtc->native_mode;
67254885Sdumbbell
68254885Sdumbbell	fp_vert_stretch = RREG32(RADEON_FP_VERT_STRETCH) &
69254885Sdumbbell		(RADEON_VERT_STRETCH_RESERVED |
70254885Sdumbbell		 RADEON_VERT_AUTO_RATIO_INC);
71254885Sdumbbell	fp_horz_stretch = RREG32(RADEON_FP_HORZ_STRETCH) &
72254885Sdumbbell		(RADEON_HORZ_FP_LOOP_STRETCH |
73254885Sdumbbell		 RADEON_HORZ_AUTO_RATIO_INC);
74254885Sdumbbell
75254885Sdumbbell	crtc_more_cntl = 0;
76254885Sdumbbell	if ((rdev->family == CHIP_RS100) ||
77254885Sdumbbell	    (rdev->family == CHIP_RS200)) {
78254885Sdumbbell		/* This is to workaround the asic bug for RMX, some versions
79298955Spfg		   of BIOS doesn't have this register initialized correctly. */
80254885Sdumbbell		crtc_more_cntl |= RADEON_CRTC_H_CUTOFF_ACTIVE_EN;
81254885Sdumbbell	}
82254885Sdumbbell
83254885Sdumbbell
84254885Sdumbbell	fp_crtc_h_total_disp = ((((mode->crtc_htotal / 8) - 1) & 0x3ff)
85254885Sdumbbell				| ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16));
86254885Sdumbbell
87254885Sdumbbell	hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8;
88254885Sdumbbell	if (!hsync_wid)
89254885Sdumbbell		hsync_wid = 1;
90254885Sdumbbell	hsync_start = mode->crtc_hsync_start - 8;
91254885Sdumbbell
92254885Sdumbbell	fp_h_sync_strt_wid = ((hsync_start & 0x1fff)
93254885Sdumbbell			      | ((hsync_wid & 0x3f) << 16)
94254885Sdumbbell			      | ((mode->flags & DRM_MODE_FLAG_NHSYNC)
95254885Sdumbbell				 ? RADEON_CRTC_H_SYNC_POL
96254885Sdumbbell				 : 0));
97254885Sdumbbell
98254885Sdumbbell	fp_crtc_v_total_disp = (((mode->crtc_vtotal - 1) & 0xffff)
99254885Sdumbbell				| ((mode->crtc_vdisplay - 1) << 16));
100254885Sdumbbell
101254885Sdumbbell	vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start;
102254885Sdumbbell	if (!vsync_wid)
103254885Sdumbbell		vsync_wid = 1;
104254885Sdumbbell
105254885Sdumbbell	fp_v_sync_strt_wid = (((mode->crtc_vsync_start - 1) & 0xfff)
106254885Sdumbbell			      | ((vsync_wid & 0x1f) << 16)
107254885Sdumbbell			      | ((mode->flags & DRM_MODE_FLAG_NVSYNC)
108254885Sdumbbell				 ? RADEON_CRTC_V_SYNC_POL
109254885Sdumbbell				 : 0));
110254885Sdumbbell
111254885Sdumbbell	fp_horz_vert_active = 0;
112254885Sdumbbell
113254885Sdumbbell	if (native_mode->hdisplay == 0 ||
114254885Sdumbbell	    native_mode->vdisplay == 0) {
115254885Sdumbbell		hscale = false;
116254885Sdumbbell		vscale = false;
117254885Sdumbbell	} else {
118254885Sdumbbell		if (xres > native_mode->hdisplay)
119254885Sdumbbell			xres = native_mode->hdisplay;
120254885Sdumbbell		if (yres > native_mode->vdisplay)
121254885Sdumbbell			yres = native_mode->vdisplay;
122254885Sdumbbell
123254885Sdumbbell		if (xres == native_mode->hdisplay)
124254885Sdumbbell			hscale = false;
125254885Sdumbbell		if (yres == native_mode->vdisplay)
126254885Sdumbbell			vscale = false;
127254885Sdumbbell	}
128254885Sdumbbell
129254885Sdumbbell	switch (radeon_crtc->rmx_type) {
130254885Sdumbbell	case RMX_FULL:
131254885Sdumbbell	case RMX_ASPECT:
132254885Sdumbbell		if (!hscale)
133254885Sdumbbell			fp_horz_stretch |= ((xres/8-1) << 16);
134254885Sdumbbell		else {
135254885Sdumbbell			inc = (fp_horz_stretch & RADEON_HORZ_AUTO_RATIO_INC) ? 1 : 0;
136254885Sdumbbell			scale = ((xres + inc) * RADEON_HORZ_STRETCH_RATIO_MAX)
137254885Sdumbbell				/ native_mode->hdisplay + 1;
138254885Sdumbbell			fp_horz_stretch |= (((scale) & RADEON_HORZ_STRETCH_RATIO_MASK) |
139254885Sdumbbell					RADEON_HORZ_STRETCH_BLEND |
140254885Sdumbbell					RADEON_HORZ_STRETCH_ENABLE |
141254885Sdumbbell					((native_mode->hdisplay/8-1) << 16));
142254885Sdumbbell		}
143254885Sdumbbell
144254885Sdumbbell		if (!vscale)
145254885Sdumbbell			fp_vert_stretch |= ((yres-1) << 12);
146254885Sdumbbell		else {
147254885Sdumbbell			inc = (fp_vert_stretch & RADEON_VERT_AUTO_RATIO_INC) ? 1 : 0;
148254885Sdumbbell			scale = ((yres + inc) * RADEON_VERT_STRETCH_RATIO_MAX)
149254885Sdumbbell				/ native_mode->vdisplay + 1;
150254885Sdumbbell			fp_vert_stretch |= (((scale) & RADEON_VERT_STRETCH_RATIO_MASK) |
151254885Sdumbbell					RADEON_VERT_STRETCH_ENABLE |
152254885Sdumbbell					RADEON_VERT_STRETCH_BLEND |
153254885Sdumbbell					((native_mode->vdisplay-1) << 12));
154254885Sdumbbell		}
155254885Sdumbbell		break;
156254885Sdumbbell	case RMX_CENTER:
157254885Sdumbbell		fp_horz_stretch |= ((xres/8-1) << 16);
158254885Sdumbbell		fp_vert_stretch |= ((yres-1) << 12);
159254885Sdumbbell
160254885Sdumbbell		crtc_more_cntl |= (RADEON_CRTC_AUTO_HORZ_CENTER_EN |
161254885Sdumbbell				RADEON_CRTC_AUTO_VERT_CENTER_EN);
162254885Sdumbbell
163254885Sdumbbell		blank_width = (mode->crtc_hblank_end - mode->crtc_hblank_start) / 8;
164254885Sdumbbell		if (blank_width > 110)
165254885Sdumbbell			blank_width = 110;
166254885Sdumbbell
167254885Sdumbbell		fp_crtc_h_total_disp = (((blank_width) & 0x3ff)
168254885Sdumbbell				| ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16));
169254885Sdumbbell
170254885Sdumbbell		hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8;
171254885Sdumbbell		if (!hsync_wid)
172254885Sdumbbell			hsync_wid = 1;
173254885Sdumbbell
174254885Sdumbbell		fp_h_sync_strt_wid = ((((mode->crtc_hsync_start - mode->crtc_hblank_start) / 8) & 0x1fff)
175254885Sdumbbell				| ((hsync_wid & 0x3f) << 16)
176254885Sdumbbell				| ((mode->flags & DRM_MODE_FLAG_NHSYNC)
177254885Sdumbbell					? RADEON_CRTC_H_SYNC_POL
178254885Sdumbbell					: 0));
179254885Sdumbbell
180254885Sdumbbell		fp_crtc_v_total_disp = (((mode->crtc_vblank_end - mode->crtc_vblank_start) & 0xffff)
181254885Sdumbbell				| ((mode->crtc_vdisplay - 1) << 16));
182254885Sdumbbell
183254885Sdumbbell		vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start;
184254885Sdumbbell		if (!vsync_wid)
185254885Sdumbbell			vsync_wid = 1;
186254885Sdumbbell
187254885Sdumbbell		fp_v_sync_strt_wid = ((((mode->crtc_vsync_start - mode->crtc_vblank_start) & 0xfff)
188254885Sdumbbell					| ((vsync_wid & 0x1f) << 16)
189254885Sdumbbell					| ((mode->flags & DRM_MODE_FLAG_NVSYNC)
190254885Sdumbbell						? RADEON_CRTC_V_SYNC_POL
191254885Sdumbbell						: 0)));
192254885Sdumbbell
193254885Sdumbbell		fp_horz_vert_active = (((native_mode->vdisplay) & 0xfff) |
194254885Sdumbbell				(((native_mode->hdisplay / 8) & 0x1ff) << 16));
195254885Sdumbbell		break;
196254885Sdumbbell	case RMX_OFF:
197254885Sdumbbell	default:
198254885Sdumbbell		fp_horz_stretch |= ((xres/8-1) << 16);
199254885Sdumbbell		fp_vert_stretch |= ((yres-1) << 12);
200254885Sdumbbell		break;
201254885Sdumbbell	}
202254885Sdumbbell
203254885Sdumbbell	WREG32(RADEON_FP_HORZ_STRETCH,      fp_horz_stretch);
204254885Sdumbbell	WREG32(RADEON_FP_VERT_STRETCH,      fp_vert_stretch);
205254885Sdumbbell	WREG32(RADEON_CRTC_MORE_CNTL,       crtc_more_cntl);
206254885Sdumbbell	WREG32(RADEON_FP_HORZ_VERT_ACTIVE,  fp_horz_vert_active);
207254885Sdumbbell	WREG32(RADEON_FP_H_SYNC_STRT_WID,   fp_h_sync_strt_wid);
208254885Sdumbbell	WREG32(RADEON_FP_V_SYNC_STRT_WID,   fp_v_sync_strt_wid);
209254885Sdumbbell	WREG32(RADEON_FP_CRTC_H_TOTAL_DISP, fp_crtc_h_total_disp);
210254885Sdumbbell	WREG32(RADEON_FP_CRTC_V_TOTAL_DISP, fp_crtc_v_total_disp);
211254885Sdumbbell}
212254885Sdumbbell
213254885Sdumbbellstatic void radeon_pll_wait_for_read_update_complete(struct drm_device *dev)
214254885Sdumbbell{
215254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
216254885Sdumbbell	int i = 0;
217254885Sdumbbell
218254885Sdumbbell	/* FIXME: Certain revisions of R300 can't recover here.  Not sure of
219254885Sdumbbell	   the cause yet, but this workaround will mask the problem for now.
220254885Sdumbbell	   Other chips usually will pass at the very first test, so the
221254885Sdumbbell	   workaround shouldn't have any effect on them. */
222254885Sdumbbell	for (i = 0;
223254885Sdumbbell	     (i < 10000 &&
224254885Sdumbbell	      RREG32_PLL(RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R);
225254885Sdumbbell	     i++);
226254885Sdumbbell}
227254885Sdumbbell
228254885Sdumbbellstatic void radeon_pll_write_update(struct drm_device *dev)
229254885Sdumbbell{
230254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
231254885Sdumbbell
232254885Sdumbbell	while (RREG32_PLL(RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R);
233254885Sdumbbell
234254885Sdumbbell	WREG32_PLL_P(RADEON_PPLL_REF_DIV,
235254885Sdumbbell			   RADEON_PPLL_ATOMIC_UPDATE_W,
236254885Sdumbbell			   ~(RADEON_PPLL_ATOMIC_UPDATE_W));
237254885Sdumbbell}
238254885Sdumbbell
239254885Sdumbbellstatic void radeon_pll2_wait_for_read_update_complete(struct drm_device *dev)
240254885Sdumbbell{
241254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
242254885Sdumbbell	int i = 0;
243254885Sdumbbell
244254885Sdumbbell
245254885Sdumbbell	/* FIXME: Certain revisions of R300 can't recover here.  Not sure of
246254885Sdumbbell	   the cause yet, but this workaround will mask the problem for now.
247254885Sdumbbell	   Other chips usually will pass at the very first test, so the
248254885Sdumbbell	   workaround shouldn't have any effect on them. */
249254885Sdumbbell	for (i = 0;
250254885Sdumbbell	     (i < 10000 &&
251254885Sdumbbell	      RREG32_PLL(RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R);
252254885Sdumbbell	     i++);
253254885Sdumbbell}
254254885Sdumbbell
255254885Sdumbbellstatic void radeon_pll2_write_update(struct drm_device *dev)
256254885Sdumbbell{
257254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
258254885Sdumbbell
259254885Sdumbbell	while (RREG32_PLL(RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R);
260254885Sdumbbell
261254885Sdumbbell	WREG32_PLL_P(RADEON_P2PLL_REF_DIV,
262254885Sdumbbell			   RADEON_P2PLL_ATOMIC_UPDATE_W,
263254885Sdumbbell			   ~(RADEON_P2PLL_ATOMIC_UPDATE_W));
264254885Sdumbbell}
265254885Sdumbbell
266254885Sdumbbellstatic uint8_t radeon_compute_pll_gain(uint16_t ref_freq, uint16_t ref_div,
267254885Sdumbbell				       uint16_t fb_div)
268254885Sdumbbell{
269254885Sdumbbell	unsigned int vcoFreq;
270254885Sdumbbell
271254885Sdumbbell	if (!ref_div)
272254885Sdumbbell		return 1;
273254885Sdumbbell
274254885Sdumbbell	vcoFreq = ((unsigned)ref_freq * fb_div) / ref_div;
275254885Sdumbbell
276254885Sdumbbell	/*
277254885Sdumbbell	 * This is horribly crude: the VCO frequency range is divided into
278254885Sdumbbell	 * 3 parts, each part having a fixed PLL gain value.
279254885Sdumbbell	 */
280254885Sdumbbell	if (vcoFreq >= 30000)
281254885Sdumbbell		/*
282254885Sdumbbell		 * [300..max] MHz : 7
283254885Sdumbbell		 */
284254885Sdumbbell		return 7;
285254885Sdumbbell	else if (vcoFreq >= 18000)
286254885Sdumbbell		/*
287254885Sdumbbell		 * [180..300) MHz : 4
288254885Sdumbbell		 */
289254885Sdumbbell		return 4;
290254885Sdumbbell	else
291254885Sdumbbell		/*
292254885Sdumbbell		 * [0..180) MHz : 1
293254885Sdumbbell		 */
294254885Sdumbbell		return 1;
295254885Sdumbbell}
296254885Sdumbbell
297254885Sdumbbellstatic void radeon_crtc_dpms(struct drm_crtc *crtc, int mode)
298254885Sdumbbell{
299254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
300254885Sdumbbell	struct drm_device *dev = crtc->dev;
301254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
302254885Sdumbbell	uint32_t crtc_ext_cntl = 0;
303254885Sdumbbell	uint32_t mask;
304254885Sdumbbell
305254885Sdumbbell	if (radeon_crtc->crtc_id)
306254885Sdumbbell		mask = (RADEON_CRTC2_DISP_DIS |
307254885Sdumbbell			RADEON_CRTC2_VSYNC_DIS |
308254885Sdumbbell			RADEON_CRTC2_HSYNC_DIS |
309254885Sdumbbell			RADEON_CRTC2_DISP_REQ_EN_B);
310254885Sdumbbell	else
311254885Sdumbbell		mask = (RADEON_CRTC_DISPLAY_DIS |
312254885Sdumbbell			RADEON_CRTC_VSYNC_DIS |
313254885Sdumbbell			RADEON_CRTC_HSYNC_DIS);
314254885Sdumbbell
315254885Sdumbbell	/*
316254885Sdumbbell	 * On all dual CRTC GPUs this bit controls the CRTC of the primary DAC.
317254885Sdumbbell	 * Therefore it is set in the DAC DMPS function.
318254885Sdumbbell	 * This is different for GPU's with a single CRTC but a primary and a
319254885Sdumbbell	 * TV DAC: here it controls the single CRTC no matter where it is
320254885Sdumbbell	 * routed. Therefore we set it here.
321254885Sdumbbell	 */
322254885Sdumbbell	if (rdev->flags & RADEON_SINGLE_CRTC)
323254885Sdumbbell		crtc_ext_cntl = RADEON_CRTC_CRT_ON;
324254885Sdumbbell
325254885Sdumbbell	switch (mode) {
326254885Sdumbbell	case DRM_MODE_DPMS_ON:
327254885Sdumbbell		radeon_crtc->enabled = true;
328254885Sdumbbell		/* adjust pm to dpms changes BEFORE enabling crtcs */
329254885Sdumbbell		radeon_pm_compute_clocks(rdev);
330254885Sdumbbell		if (radeon_crtc->crtc_id)
331254885Sdumbbell			WREG32_P(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_EN, ~(RADEON_CRTC2_EN | mask));
332254885Sdumbbell		else {
333254885Sdumbbell			WREG32_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_EN, ~(RADEON_CRTC_EN |
334254885Sdumbbell									 RADEON_CRTC_DISP_REQ_EN_B));
335254885Sdumbbell			WREG32_P(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl, ~(mask | crtc_ext_cntl));
336254885Sdumbbell		}
337254885Sdumbbell		drm_vblank_post_modeset(dev, radeon_crtc->crtc_id);
338254885Sdumbbell		radeon_crtc_load_lut(crtc);
339254885Sdumbbell		break;
340254885Sdumbbell	case DRM_MODE_DPMS_STANDBY:
341254885Sdumbbell	case DRM_MODE_DPMS_SUSPEND:
342254885Sdumbbell	case DRM_MODE_DPMS_OFF:
343254885Sdumbbell		drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id);
344254885Sdumbbell		if (radeon_crtc->crtc_id)
345254885Sdumbbell			WREG32_P(RADEON_CRTC2_GEN_CNTL, mask, ~(RADEON_CRTC2_EN | mask));
346254885Sdumbbell		else {
347254885Sdumbbell			WREG32_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_DISP_REQ_EN_B, ~(RADEON_CRTC_EN |
348254885Sdumbbell										    RADEON_CRTC_DISP_REQ_EN_B));
349254885Sdumbbell			WREG32_P(RADEON_CRTC_EXT_CNTL, mask, ~(mask | crtc_ext_cntl));
350254885Sdumbbell		}
351254885Sdumbbell		radeon_crtc->enabled = false;
352254885Sdumbbell		/* adjust pm to dpms changes AFTER disabling crtcs */
353254885Sdumbbell		radeon_pm_compute_clocks(rdev);
354254885Sdumbbell		break;
355254885Sdumbbell	}
356254885Sdumbbell}
357254885Sdumbbell
358254885Sdumbbellint radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
359254885Sdumbbell			 struct drm_framebuffer *old_fb)
360254885Sdumbbell{
361254885Sdumbbell	return radeon_crtc_do_set_base(crtc, old_fb, x, y, 0);
362254885Sdumbbell}
363254885Sdumbbell
364254885Sdumbbellint radeon_crtc_set_base_atomic(struct drm_crtc *crtc,
365254885Sdumbbell				struct drm_framebuffer *fb,
366254885Sdumbbell				int x, int y, enum mode_set_atomic state)
367254885Sdumbbell{
368254885Sdumbbell	return radeon_crtc_do_set_base(crtc, fb, x, y, 1);
369254885Sdumbbell}
370254885Sdumbbell
371254885Sdumbbellint radeon_crtc_do_set_base(struct drm_crtc *crtc,
372254885Sdumbbell			 struct drm_framebuffer *fb,
373254885Sdumbbell			 int x, int y, int atomic)
374254885Sdumbbell{
375254885Sdumbbell	struct drm_device *dev = crtc->dev;
376254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
377254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
378254885Sdumbbell	struct radeon_framebuffer *radeon_fb;
379254885Sdumbbell	struct drm_framebuffer *target_fb;
380254885Sdumbbell	struct drm_gem_object *obj;
381254885Sdumbbell	struct radeon_bo *rbo;
382254885Sdumbbell	uint64_t base;
383254885Sdumbbell	uint32_t crtc_offset, crtc_offset_cntl, crtc_tile_x0_y0 = 0;
384254885Sdumbbell	uint32_t crtc_pitch, pitch_pixels;
385254885Sdumbbell	uint32_t tiling_flags;
386254885Sdumbbell	int format;
387254885Sdumbbell	uint32_t gen_cntl_reg, gen_cntl_val;
388254885Sdumbbell	int r;
389254885Sdumbbell
390254885Sdumbbell	DRM_DEBUG_KMS("\n");
391254885Sdumbbell	/* no fb bound */
392254885Sdumbbell	if (!atomic && !crtc->fb) {
393254885Sdumbbell		DRM_DEBUG_KMS("No FB bound\n");
394254885Sdumbbell		return 0;
395254885Sdumbbell	}
396254885Sdumbbell
397254885Sdumbbell	if (atomic) {
398254885Sdumbbell		radeon_fb = to_radeon_framebuffer(fb);
399254885Sdumbbell		target_fb = fb;
400254885Sdumbbell	}
401254885Sdumbbell	else {
402254885Sdumbbell		radeon_fb = to_radeon_framebuffer(crtc->fb);
403254885Sdumbbell		target_fb = crtc->fb;
404254885Sdumbbell	}
405254885Sdumbbell
406254885Sdumbbell	switch (target_fb->bits_per_pixel) {
407254885Sdumbbell	case 8:
408254885Sdumbbell		format = 2;
409254885Sdumbbell		break;
410254885Sdumbbell	case 15:      /*  555 */
411254885Sdumbbell		format = 3;
412254885Sdumbbell		break;
413254885Sdumbbell	case 16:      /*  565 */
414254885Sdumbbell		format = 4;
415254885Sdumbbell		break;
416254885Sdumbbell	case 24:      /*  RGB */
417254885Sdumbbell		format = 5;
418254885Sdumbbell		break;
419254885Sdumbbell	case 32:      /* xRGB */
420254885Sdumbbell		format = 6;
421254885Sdumbbell		break;
422254885Sdumbbell	default:
423254885Sdumbbell		return false;
424254885Sdumbbell	}
425254885Sdumbbell
426254885Sdumbbell	/* Pin framebuffer & get tilling informations */
427254885Sdumbbell	obj = radeon_fb->obj;
428254885Sdumbbell	rbo = gem_to_radeon_bo(obj);
429254885Sdumbbell	r = radeon_bo_reserve(rbo, false);
430254885Sdumbbell	if (unlikely(r != 0))
431254885Sdumbbell		return r;
432254885Sdumbbell	/* Only 27 bit offset for legacy CRTC */
433254885Sdumbbell	r = radeon_bo_pin_restricted(rbo, RADEON_GEM_DOMAIN_VRAM, 1 << 27,
434254885Sdumbbell				     &base);
435254885Sdumbbell	if (unlikely(r != 0)) {
436254885Sdumbbell		radeon_bo_unreserve(rbo);
437254885Sdumbbell		return -EINVAL;
438254885Sdumbbell	}
439254885Sdumbbell	radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
440254885Sdumbbell	radeon_bo_unreserve(rbo);
441254885Sdumbbell	if (tiling_flags & RADEON_TILING_MICRO)
442254885Sdumbbell		DRM_ERROR("trying to scanout microtiled buffer\n");
443254885Sdumbbell
444254885Sdumbbell	/* if scanout was in GTT this really wouldn't work */
445254885Sdumbbell	/* crtc offset is from display base addr not FB location */
446254885Sdumbbell	radeon_crtc->legacy_display_base_addr = rdev->mc.vram_start;
447254885Sdumbbell
448254885Sdumbbell	base -= radeon_crtc->legacy_display_base_addr;
449254885Sdumbbell
450254885Sdumbbell	crtc_offset_cntl = 0;
451254885Sdumbbell
452254885Sdumbbell	pitch_pixels = target_fb->pitches[0] / (target_fb->bits_per_pixel / 8);
453254885Sdumbbell	crtc_pitch  = (((pitch_pixels * target_fb->bits_per_pixel) +
454254885Sdumbbell			((target_fb->bits_per_pixel * 8) - 1)) /
455254885Sdumbbell		       (target_fb->bits_per_pixel * 8));
456254885Sdumbbell	crtc_pitch |= crtc_pitch << 16;
457254885Sdumbbell
458254885Sdumbbell	crtc_offset_cntl |= RADEON_CRTC_GUI_TRIG_OFFSET_LEFT_EN;
459254885Sdumbbell	if (tiling_flags & RADEON_TILING_MACRO) {
460254885Sdumbbell		if (ASIC_IS_R300(rdev))
461254885Sdumbbell			crtc_offset_cntl |= (R300_CRTC_X_Y_MODE_EN |
462254885Sdumbbell					     R300_CRTC_MICRO_TILE_BUFFER_DIS |
463254885Sdumbbell					     R300_CRTC_MACRO_TILE_EN);
464254885Sdumbbell		else
465254885Sdumbbell			crtc_offset_cntl |= RADEON_CRTC_TILE_EN;
466254885Sdumbbell	} else {
467254885Sdumbbell		if (ASIC_IS_R300(rdev))
468254885Sdumbbell			crtc_offset_cntl &= ~(R300_CRTC_X_Y_MODE_EN |
469254885Sdumbbell					      R300_CRTC_MICRO_TILE_BUFFER_DIS |
470254885Sdumbbell					      R300_CRTC_MACRO_TILE_EN);
471254885Sdumbbell		else
472254885Sdumbbell			crtc_offset_cntl &= ~RADEON_CRTC_TILE_EN;
473254885Sdumbbell	}
474254885Sdumbbell
475254885Sdumbbell	if (tiling_flags & RADEON_TILING_MACRO) {
476254885Sdumbbell		if (ASIC_IS_R300(rdev)) {
477254885Sdumbbell			crtc_tile_x0_y0 = x | (y << 16);
478254885Sdumbbell			base &= ~0x7ff;
479254885Sdumbbell		} else {
480254885Sdumbbell			int byteshift = target_fb->bits_per_pixel >> 4;
481254885Sdumbbell			int tile_addr = (((y >> 3) * pitch_pixels +  x) >> (8 - byteshift)) << 11;
482254885Sdumbbell			base += tile_addr + ((x << byteshift) % 256) + ((y % 8) << 8);
483254885Sdumbbell			crtc_offset_cntl |= (y % 16);
484254885Sdumbbell		}
485254885Sdumbbell	} else {
486254885Sdumbbell		int offset = y * pitch_pixels + x;
487254885Sdumbbell		switch (target_fb->bits_per_pixel) {
488254885Sdumbbell		case 8:
489254885Sdumbbell			offset *= 1;
490254885Sdumbbell			break;
491254885Sdumbbell		case 15:
492254885Sdumbbell		case 16:
493254885Sdumbbell			offset *= 2;
494254885Sdumbbell			break;
495254885Sdumbbell		case 24:
496254885Sdumbbell			offset *= 3;
497254885Sdumbbell			break;
498254885Sdumbbell		case 32:
499254885Sdumbbell			offset *= 4;
500254885Sdumbbell			break;
501254885Sdumbbell		default:
502254885Sdumbbell			return false;
503254885Sdumbbell		}
504254885Sdumbbell		base += offset;
505254885Sdumbbell	}
506254885Sdumbbell
507254885Sdumbbell	base &= ~7;
508254885Sdumbbell
509254885Sdumbbell	if (radeon_crtc->crtc_id == 1)
510254885Sdumbbell		gen_cntl_reg = RADEON_CRTC2_GEN_CNTL;
511254885Sdumbbell	else
512254885Sdumbbell		gen_cntl_reg = RADEON_CRTC_GEN_CNTL;
513254885Sdumbbell
514254885Sdumbbell	gen_cntl_val = RREG32(gen_cntl_reg);
515254885Sdumbbell	gen_cntl_val &= ~(0xf << 8);
516254885Sdumbbell	gen_cntl_val |= (format << 8);
517254885Sdumbbell	gen_cntl_val &= ~RADEON_CRTC_VSTAT_MODE_MASK;
518254885Sdumbbell	WREG32(gen_cntl_reg, gen_cntl_val);
519254885Sdumbbell
520254885Sdumbbell	crtc_offset = (u32)base;
521254885Sdumbbell
522254885Sdumbbell	WREG32(RADEON_DISPLAY_BASE_ADDR + radeon_crtc->crtc_offset, radeon_crtc->legacy_display_base_addr);
523254885Sdumbbell
524254885Sdumbbell	if (ASIC_IS_R300(rdev)) {
525254885Sdumbbell		if (radeon_crtc->crtc_id)
526254885Sdumbbell			WREG32(R300_CRTC2_TILE_X0_Y0, crtc_tile_x0_y0);
527254885Sdumbbell		else
528254885Sdumbbell			WREG32(R300_CRTC_TILE_X0_Y0, crtc_tile_x0_y0);
529254885Sdumbbell	}
530254885Sdumbbell	WREG32(RADEON_CRTC_OFFSET_CNTL + radeon_crtc->crtc_offset, crtc_offset_cntl);
531254885Sdumbbell	WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, crtc_offset);
532254885Sdumbbell	WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch);
533254885Sdumbbell
534254885Sdumbbell	if (!atomic && fb && fb != crtc->fb) {
535254885Sdumbbell		radeon_fb = to_radeon_framebuffer(fb);
536254885Sdumbbell		rbo = gem_to_radeon_bo(radeon_fb->obj);
537254885Sdumbbell		r = radeon_bo_reserve(rbo, false);
538254885Sdumbbell		if (unlikely(r != 0))
539254885Sdumbbell			return r;
540254885Sdumbbell		radeon_bo_unpin(rbo);
541254885Sdumbbell		radeon_bo_unreserve(rbo);
542254885Sdumbbell	}
543254885Sdumbbell
544254885Sdumbbell	/* Bytes per pixel may have changed */
545254885Sdumbbell	radeon_bandwidth_update(rdev);
546254885Sdumbbell
547254885Sdumbbell	return 0;
548254885Sdumbbell}
549254885Sdumbbell
550254885Sdumbbellstatic bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mode *mode)
551254885Sdumbbell{
552254885Sdumbbell	struct drm_device *dev = crtc->dev;
553254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
554254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
555254885Sdumbbell	struct drm_encoder *encoder;
556254885Sdumbbell	int format;
557254885Sdumbbell	int hsync_start;
558254885Sdumbbell	int hsync_wid;
559254885Sdumbbell	int vsync_wid;
560254885Sdumbbell	uint32_t crtc_h_total_disp;
561254885Sdumbbell	uint32_t crtc_h_sync_strt_wid;
562254885Sdumbbell	uint32_t crtc_v_total_disp;
563254885Sdumbbell	uint32_t crtc_v_sync_strt_wid;
564254885Sdumbbell	bool is_tv = false;
565254885Sdumbbell
566254885Sdumbbell	DRM_DEBUG_KMS("\n");
567254885Sdumbbell	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
568254885Sdumbbell		if (encoder->crtc == crtc) {
569254885Sdumbbell			struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
570254885Sdumbbell			if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) {
571254885Sdumbbell				is_tv = true;
572254885Sdumbbell				DRM_INFO("crtc %d is connected to a TV\n", radeon_crtc->crtc_id);
573254885Sdumbbell				break;
574254885Sdumbbell			}
575254885Sdumbbell		}
576254885Sdumbbell	}
577254885Sdumbbell
578254885Sdumbbell	switch (crtc->fb->bits_per_pixel) {
579254885Sdumbbell	case 8:
580254885Sdumbbell		format = 2;
581254885Sdumbbell		break;
582254885Sdumbbell	case 15:      /*  555 */
583254885Sdumbbell		format = 3;
584254885Sdumbbell		break;
585254885Sdumbbell	case 16:      /*  565 */
586254885Sdumbbell		format = 4;
587254885Sdumbbell		break;
588254885Sdumbbell	case 24:      /*  RGB */
589254885Sdumbbell		format = 5;
590254885Sdumbbell		break;
591254885Sdumbbell	case 32:      /* xRGB */
592254885Sdumbbell		format = 6;
593254885Sdumbbell		break;
594254885Sdumbbell	default:
595254885Sdumbbell		return false;
596254885Sdumbbell	}
597254885Sdumbbell
598254885Sdumbbell	crtc_h_total_disp = ((((mode->crtc_htotal / 8) - 1) & 0x3ff)
599254885Sdumbbell			     | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16));
600254885Sdumbbell
601254885Sdumbbell	hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8;
602254885Sdumbbell	if (!hsync_wid)
603254885Sdumbbell		hsync_wid = 1;
604254885Sdumbbell	hsync_start = mode->crtc_hsync_start - 8;
605254885Sdumbbell
606254885Sdumbbell	crtc_h_sync_strt_wid = ((hsync_start & 0x1fff)
607254885Sdumbbell				| ((hsync_wid & 0x3f) << 16)
608254885Sdumbbell				| ((mode->flags & DRM_MODE_FLAG_NHSYNC)
609254885Sdumbbell				   ? RADEON_CRTC_H_SYNC_POL
610254885Sdumbbell				   : 0));
611254885Sdumbbell
612254885Sdumbbell	/* This works for double scan mode. */
613254885Sdumbbell	crtc_v_total_disp = (((mode->crtc_vtotal - 1) & 0xffff)
614254885Sdumbbell			     | ((mode->crtc_vdisplay - 1) << 16));
615254885Sdumbbell
616254885Sdumbbell	vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start;
617254885Sdumbbell	if (!vsync_wid)
618254885Sdumbbell		vsync_wid = 1;
619254885Sdumbbell
620254885Sdumbbell	crtc_v_sync_strt_wid = (((mode->crtc_vsync_start - 1) & 0xfff)
621254885Sdumbbell				| ((vsync_wid & 0x1f) << 16)
622254885Sdumbbell				| ((mode->flags & DRM_MODE_FLAG_NVSYNC)
623254885Sdumbbell				   ? RADEON_CRTC_V_SYNC_POL
624254885Sdumbbell				   : 0));
625254885Sdumbbell
626254885Sdumbbell	if (radeon_crtc->crtc_id) {
627254885Sdumbbell		uint32_t crtc2_gen_cntl;
628254885Sdumbbell		uint32_t disp2_merge_cntl;
629254885Sdumbbell
630254885Sdumbbell		/* if TV DAC is enabled for another crtc and keep it enabled */
631254885Sdumbbell		crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL) & 0x00718080;
632254885Sdumbbell		crtc2_gen_cntl |= ((format << 8)
633254885Sdumbbell				   | RADEON_CRTC2_VSYNC_DIS
634254885Sdumbbell				   | RADEON_CRTC2_HSYNC_DIS
635254885Sdumbbell				   | RADEON_CRTC2_DISP_DIS
636254885Sdumbbell				   | RADEON_CRTC2_DISP_REQ_EN_B
637254885Sdumbbell				   | ((mode->flags & DRM_MODE_FLAG_DBLSCAN)
638254885Sdumbbell				      ? RADEON_CRTC2_DBL_SCAN_EN
639254885Sdumbbell				      : 0)
640254885Sdumbbell				   | ((mode->flags & DRM_MODE_FLAG_CSYNC)
641254885Sdumbbell				      ? RADEON_CRTC2_CSYNC_EN
642254885Sdumbbell				      : 0)
643254885Sdumbbell				   | ((mode->flags & DRM_MODE_FLAG_INTERLACE)
644254885Sdumbbell				      ? RADEON_CRTC2_INTERLACE_EN
645254885Sdumbbell				      : 0));
646254885Sdumbbell
647254885Sdumbbell		/* rs4xx chips seem to like to have the crtc enabled when the timing is set */
648254885Sdumbbell		if ((rdev->family == CHIP_RS400) || (rdev->family == CHIP_RS480))
649254885Sdumbbell			crtc2_gen_cntl |= RADEON_CRTC2_EN;
650254885Sdumbbell
651254885Sdumbbell		disp2_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL);
652254885Sdumbbell		disp2_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN;
653254885Sdumbbell
654254885Sdumbbell		WREG32(RADEON_DISP2_MERGE_CNTL, disp2_merge_cntl);
655254885Sdumbbell		WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
656254885Sdumbbell
657254885Sdumbbell		WREG32(RADEON_FP_H2_SYNC_STRT_WID, crtc_h_sync_strt_wid);
658254885Sdumbbell		WREG32(RADEON_FP_V2_SYNC_STRT_WID, crtc_v_sync_strt_wid);
659254885Sdumbbell	} else {
660254885Sdumbbell		uint32_t crtc_gen_cntl;
661254885Sdumbbell		uint32_t crtc_ext_cntl;
662254885Sdumbbell		uint32_t disp_merge_cntl;
663254885Sdumbbell
664254885Sdumbbell		crtc_gen_cntl = RREG32(RADEON_CRTC_GEN_CNTL) & 0x00718000;
665254885Sdumbbell		crtc_gen_cntl |= (RADEON_CRTC_EXT_DISP_EN
666254885Sdumbbell				 | (format << 8)
667254885Sdumbbell				 | RADEON_CRTC_DISP_REQ_EN_B
668254885Sdumbbell				 | ((mode->flags & DRM_MODE_FLAG_DBLSCAN)
669254885Sdumbbell				    ? RADEON_CRTC_DBL_SCAN_EN
670254885Sdumbbell				    : 0)
671254885Sdumbbell				 | ((mode->flags & DRM_MODE_FLAG_CSYNC)
672254885Sdumbbell				    ? RADEON_CRTC_CSYNC_EN
673254885Sdumbbell				    : 0)
674254885Sdumbbell				 | ((mode->flags & DRM_MODE_FLAG_INTERLACE)
675254885Sdumbbell				    ? RADEON_CRTC_INTERLACE_EN
676254885Sdumbbell				    : 0));
677254885Sdumbbell
678254885Sdumbbell		/* rs4xx chips seem to like to have the crtc enabled when the timing is set */
679254885Sdumbbell		if ((rdev->family == CHIP_RS400) || (rdev->family == CHIP_RS480))
680254885Sdumbbell			crtc_gen_cntl |= RADEON_CRTC_EN;
681254885Sdumbbell
682254885Sdumbbell		crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL);
683254885Sdumbbell		crtc_ext_cntl |= (RADEON_XCRT_CNT_EN |
684254885Sdumbbell				  RADEON_CRTC_VSYNC_DIS |
685254885Sdumbbell				  RADEON_CRTC_HSYNC_DIS |
686254885Sdumbbell				  RADEON_CRTC_DISPLAY_DIS);
687254885Sdumbbell
688254885Sdumbbell		disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL);
689254885Sdumbbell		disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN;
690254885Sdumbbell
691254885Sdumbbell		WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl);
692254885Sdumbbell		WREG32(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl);
693254885Sdumbbell		WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl);
694254885Sdumbbell	}
695254885Sdumbbell
696254885Sdumbbell	if (is_tv)
697254885Sdumbbell		radeon_legacy_tv_adjust_crtc_reg(encoder, &crtc_h_total_disp,
698254885Sdumbbell						 &crtc_h_sync_strt_wid, &crtc_v_total_disp,
699254885Sdumbbell						 &crtc_v_sync_strt_wid);
700254885Sdumbbell
701254885Sdumbbell	WREG32(RADEON_CRTC_H_TOTAL_DISP + radeon_crtc->crtc_offset, crtc_h_total_disp);
702254885Sdumbbell	WREG32(RADEON_CRTC_H_SYNC_STRT_WID + radeon_crtc->crtc_offset, crtc_h_sync_strt_wid);
703254885Sdumbbell	WREG32(RADEON_CRTC_V_TOTAL_DISP + radeon_crtc->crtc_offset, crtc_v_total_disp);
704254885Sdumbbell	WREG32(RADEON_CRTC_V_SYNC_STRT_WID + radeon_crtc->crtc_offset, crtc_v_sync_strt_wid);
705254885Sdumbbell
706254885Sdumbbell	return true;
707254885Sdumbbell}
708254885Sdumbbell
709254885Sdumbbellstatic void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
710254885Sdumbbell{
711254885Sdumbbell	struct drm_device *dev = crtc->dev;
712254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
713254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
714254885Sdumbbell	struct drm_encoder *encoder;
715254885Sdumbbell	uint32_t feedback_div = 0;
716254885Sdumbbell	uint32_t frac_fb_div = 0;
717254885Sdumbbell	uint32_t reference_div = 0;
718254885Sdumbbell	uint32_t post_divider = 0;
719254885Sdumbbell	uint32_t freq = 0;
720254885Sdumbbell	uint8_t pll_gain;
721254885Sdumbbell	bool use_bios_divs = false;
722254885Sdumbbell	/* PLL registers */
723254885Sdumbbell	uint32_t pll_ref_div = 0;
724254885Sdumbbell	uint32_t pll_fb_post_div = 0;
725254885Sdumbbell	uint32_t htotal_cntl = 0;
726254885Sdumbbell	bool is_tv = false;
727254885Sdumbbell	struct radeon_pll *pll;
728254885Sdumbbell
729254885Sdumbbell	struct {
730254885Sdumbbell		int divider;
731254885Sdumbbell		int bitvalue;
732254885Sdumbbell	} *post_div, post_divs[]   = {
733254885Sdumbbell		/* From RAGE 128 VR/RAGE 128 GL Register
734254885Sdumbbell		 * Reference Manual (Technical Reference
735254885Sdumbbell		 * Manual P/N RRG-G04100-C Rev. 0.04), page
736254885Sdumbbell		 * 3-17 (PLL_DIV_[3:0]).
737254885Sdumbbell		 */
738254885Sdumbbell		{  1, 0 },              /* VCLK_SRC                 */
739254885Sdumbbell		{  2, 1 },              /* VCLK_SRC/2               */
740254885Sdumbbell		{  4, 2 },              /* VCLK_SRC/4               */
741254885Sdumbbell		{  8, 3 },              /* VCLK_SRC/8               */
742254885Sdumbbell		{  3, 4 },              /* VCLK_SRC/3               */
743254885Sdumbbell		{ 16, 5 },              /* VCLK_SRC/16              */
744254885Sdumbbell		{  6, 6 },              /* VCLK_SRC/6               */
745254885Sdumbbell		{ 12, 7 },              /* VCLK_SRC/12              */
746254885Sdumbbell		{  0, 0 }
747254885Sdumbbell	};
748254885Sdumbbell
749254885Sdumbbell	if (radeon_crtc->crtc_id)
750254885Sdumbbell		pll = &rdev->clock.p2pll;
751254885Sdumbbell	else
752254885Sdumbbell		pll = &rdev->clock.p1pll;
753254885Sdumbbell
754254885Sdumbbell	pll->flags = RADEON_PLL_LEGACY;
755254885Sdumbbell
756254885Sdumbbell	if (mode->clock > 200000) /* range limits??? */
757254885Sdumbbell		pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
758254885Sdumbbell	else
759254885Sdumbbell		pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
760254885Sdumbbell
761254885Sdumbbell	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
762254885Sdumbbell		if (encoder->crtc == crtc) {
763254885Sdumbbell			struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
764254885Sdumbbell
765254885Sdumbbell			if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) {
766254885Sdumbbell				is_tv = true;
767254885Sdumbbell				break;
768254885Sdumbbell			}
769254885Sdumbbell
770254885Sdumbbell			if (encoder->encoder_type != DRM_MODE_ENCODER_DAC)
771254885Sdumbbell				pll->flags |= RADEON_PLL_NO_ODD_POST_DIV;
772254885Sdumbbell			if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) {
773254885Sdumbbell				if (!rdev->is_atom_bios) {
774254885Sdumbbell					struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
775254885Sdumbbell					struct radeon_encoder_lvds *lvds = (struct radeon_encoder_lvds *)radeon_encoder->enc_priv;
776254885Sdumbbell					if (lvds) {
777254885Sdumbbell						if (lvds->use_bios_dividers) {
778254885Sdumbbell							pll_ref_div = lvds->panel_ref_divider;
779254885Sdumbbell							pll_fb_post_div   = (lvds->panel_fb_divider |
780254885Sdumbbell									     (lvds->panel_post_divider << 16));
781254885Sdumbbell							htotal_cntl  = 0;
782254885Sdumbbell							use_bios_divs = true;
783254885Sdumbbell						}
784254885Sdumbbell					}
785254885Sdumbbell				}
786254885Sdumbbell				pll->flags |= RADEON_PLL_USE_REF_DIV;
787254885Sdumbbell			}
788254885Sdumbbell		}
789254885Sdumbbell	}
790254885Sdumbbell
791254885Sdumbbell	DRM_DEBUG_KMS("\n");
792254885Sdumbbell
793254885Sdumbbell	if (!use_bios_divs) {
794254885Sdumbbell		radeon_compute_pll_legacy(pll, mode->clock,
795254885Sdumbbell					  &freq, &feedback_div, &frac_fb_div,
796254885Sdumbbell					  &reference_div, &post_divider);
797254885Sdumbbell
798254885Sdumbbell		for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
799254885Sdumbbell			if (post_div->divider == post_divider)
800254885Sdumbbell				break;
801254885Sdumbbell		}
802254885Sdumbbell
803254885Sdumbbell		if (!post_div->divider)
804254885Sdumbbell			post_div = &post_divs[0];
805254885Sdumbbell
806254885Sdumbbell		DRM_DEBUG_KMS("dc=%u, fd=%d, rd=%d, pd=%d\n",
807254885Sdumbbell			  (unsigned)freq,
808254885Sdumbbell			  feedback_div,
809254885Sdumbbell			  reference_div,
810254885Sdumbbell			  post_divider);
811254885Sdumbbell
812254885Sdumbbell		pll_ref_div   = reference_div;
813254885Sdumbbell#if defined(__powerpc__) && (0) /* TODO */
814254885Sdumbbell		/* apparently programming this otherwise causes a hang??? */
815254885Sdumbbell		if (info->MacModel == RADEON_MAC_IBOOK)
816254885Sdumbbell			pll_fb_post_div = 0x000600ad;
817254885Sdumbbell		else
818254885Sdumbbell#endif
819254885Sdumbbell			pll_fb_post_div     = (feedback_div | (post_div->bitvalue << 16));
820254885Sdumbbell
821254885Sdumbbell		htotal_cntl    = mode->htotal & 0x7;
822254885Sdumbbell
823254885Sdumbbell	}
824254885Sdumbbell
825254885Sdumbbell	pll_gain = radeon_compute_pll_gain(pll->reference_freq,
826254885Sdumbbell					   pll_ref_div & 0x3ff,
827254885Sdumbbell					   pll_fb_post_div & 0x7ff);
828254885Sdumbbell
829254885Sdumbbell	if (radeon_crtc->crtc_id) {
830254885Sdumbbell		uint32_t pixclks_cntl = ((RREG32_PLL(RADEON_PIXCLKS_CNTL) &
831254885Sdumbbell					  ~(RADEON_PIX2CLK_SRC_SEL_MASK)) |
832254885Sdumbbell					 RADEON_PIX2CLK_SRC_SEL_P2PLLCLK);
833254885Sdumbbell
834254885Sdumbbell		if (is_tv) {
835254885Sdumbbell			radeon_legacy_tv_adjust_pll2(encoder, &htotal_cntl,
836254885Sdumbbell						     &pll_ref_div, &pll_fb_post_div,
837254885Sdumbbell						     &pixclks_cntl);
838254885Sdumbbell		}
839254885Sdumbbell
840254885Sdumbbell		WREG32_PLL_P(RADEON_PIXCLKS_CNTL,
841254885Sdumbbell			     RADEON_PIX2CLK_SRC_SEL_CPUCLK,
842254885Sdumbbell			     ~(RADEON_PIX2CLK_SRC_SEL_MASK));
843254885Sdumbbell
844254885Sdumbbell		WREG32_PLL_P(RADEON_P2PLL_CNTL,
845254885Sdumbbell			     RADEON_P2PLL_RESET
846254885Sdumbbell			     | RADEON_P2PLL_ATOMIC_UPDATE_EN
847254885Sdumbbell			     | ((uint32_t)pll_gain << RADEON_P2PLL_PVG_SHIFT),
848254885Sdumbbell			     ~(RADEON_P2PLL_RESET
849254885Sdumbbell			       | RADEON_P2PLL_ATOMIC_UPDATE_EN
850254885Sdumbbell			       | RADEON_P2PLL_PVG_MASK));
851254885Sdumbbell
852254885Sdumbbell		WREG32_PLL_P(RADEON_P2PLL_REF_DIV,
853254885Sdumbbell			     pll_ref_div,
854254885Sdumbbell			     ~RADEON_P2PLL_REF_DIV_MASK);
855254885Sdumbbell
856254885Sdumbbell		WREG32_PLL_P(RADEON_P2PLL_DIV_0,
857254885Sdumbbell			     pll_fb_post_div,
858254885Sdumbbell			     ~RADEON_P2PLL_FB0_DIV_MASK);
859254885Sdumbbell
860254885Sdumbbell		WREG32_PLL_P(RADEON_P2PLL_DIV_0,
861254885Sdumbbell			     pll_fb_post_div,
862254885Sdumbbell			     ~RADEON_P2PLL_POST0_DIV_MASK);
863254885Sdumbbell
864254885Sdumbbell		radeon_pll2_write_update(dev);
865254885Sdumbbell		radeon_pll2_wait_for_read_update_complete(dev);
866254885Sdumbbell
867254885Sdumbbell		WREG32_PLL(RADEON_HTOTAL2_CNTL, htotal_cntl);
868254885Sdumbbell
869254885Sdumbbell		WREG32_PLL_P(RADEON_P2PLL_CNTL,
870254885Sdumbbell			     0,
871254885Sdumbbell			     ~(RADEON_P2PLL_RESET
872254885Sdumbbell			       | RADEON_P2PLL_SLEEP
873254885Sdumbbell			       | RADEON_P2PLL_ATOMIC_UPDATE_EN));
874254885Sdumbbell
875254885Sdumbbell		DRM_DEBUG_KMS("Wrote2: 0x%08x 0x%08x 0x%08x (0x%08x)\n",
876254885Sdumbbell			  (unsigned)pll_ref_div,
877254885Sdumbbell			  (unsigned)pll_fb_post_div,
878254885Sdumbbell			  (unsigned)htotal_cntl,
879254885Sdumbbell			  RREG32_PLL(RADEON_P2PLL_CNTL));
880254885Sdumbbell		DRM_DEBUG_KMS("Wrote2: rd=%u, fd=%u, pd=%u\n",
881254885Sdumbbell			  (unsigned)pll_ref_div & RADEON_P2PLL_REF_DIV_MASK,
882254885Sdumbbell			  (unsigned)pll_fb_post_div & RADEON_P2PLL_FB0_DIV_MASK,
883254885Sdumbbell			  (unsigned)((pll_fb_post_div &
884254885Sdumbbell				      RADEON_P2PLL_POST0_DIV_MASK) >> 16));
885254885Sdumbbell
886280183Sdumbbell		mdelay(50); /* Let the clock to lock */
887254885Sdumbbell
888254885Sdumbbell		WREG32_PLL_P(RADEON_PIXCLKS_CNTL,
889254885Sdumbbell			     RADEON_PIX2CLK_SRC_SEL_P2PLLCLK,
890254885Sdumbbell			     ~(RADEON_PIX2CLK_SRC_SEL_MASK));
891254885Sdumbbell
892254885Sdumbbell		WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl);
893254885Sdumbbell	} else {
894254885Sdumbbell		uint32_t pixclks_cntl;
895254885Sdumbbell
896254885Sdumbbell
897254885Sdumbbell		if (is_tv) {
898254885Sdumbbell			pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL);
899254885Sdumbbell			radeon_legacy_tv_adjust_pll1(encoder, &htotal_cntl, &pll_ref_div,
900254885Sdumbbell						     &pll_fb_post_div, &pixclks_cntl);
901254885Sdumbbell		}
902254885Sdumbbell
903254885Sdumbbell		if (rdev->flags & RADEON_IS_MOBILITY) {
904254885Sdumbbell			/* A temporal workaround for the occasional blanking on certain laptop panels.
905254885Sdumbbell			   This appears to related to the PLL divider registers (fail to lock?).
906254885Sdumbbell			   It occurs even when all dividers are the same with their old settings.
907254885Sdumbbell			   In this case we really don't need to fiddle with PLL registers.
908254885Sdumbbell			   By doing this we can avoid the blanking problem with some panels.
909254885Sdumbbell			*/
910254885Sdumbbell			if ((pll_ref_div == (RREG32_PLL(RADEON_PPLL_REF_DIV) & RADEON_PPLL_REF_DIV_MASK)) &&
911254885Sdumbbell			    (pll_fb_post_div == (RREG32_PLL(RADEON_PPLL_DIV_3) &
912254885Sdumbbell						 (RADEON_PPLL_POST3_DIV_MASK | RADEON_PPLL_FB3_DIV_MASK)))) {
913254885Sdumbbell				WREG32_P(RADEON_CLOCK_CNTL_INDEX,
914254885Sdumbbell					 RADEON_PLL_DIV_SEL,
915254885Sdumbbell					 ~(RADEON_PLL_DIV_SEL));
916254885Sdumbbell				r100_pll_errata_after_index(rdev);
917254885Sdumbbell				return;
918254885Sdumbbell			}
919254885Sdumbbell		}
920254885Sdumbbell
921254885Sdumbbell		WREG32_PLL_P(RADEON_VCLK_ECP_CNTL,
922254885Sdumbbell			     RADEON_VCLK_SRC_SEL_CPUCLK,
923254885Sdumbbell			     ~(RADEON_VCLK_SRC_SEL_MASK));
924254885Sdumbbell		WREG32_PLL_P(RADEON_PPLL_CNTL,
925254885Sdumbbell			     RADEON_PPLL_RESET
926254885Sdumbbell			     | RADEON_PPLL_ATOMIC_UPDATE_EN
927254885Sdumbbell			     | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN
928254885Sdumbbell			     | ((uint32_t)pll_gain << RADEON_PPLL_PVG_SHIFT),
929254885Sdumbbell			     ~(RADEON_PPLL_RESET
930254885Sdumbbell			       | RADEON_PPLL_ATOMIC_UPDATE_EN
931254885Sdumbbell			       | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN
932254885Sdumbbell			       | RADEON_PPLL_PVG_MASK));
933254885Sdumbbell
934254885Sdumbbell		WREG32_P(RADEON_CLOCK_CNTL_INDEX,
935254885Sdumbbell			 RADEON_PLL_DIV_SEL,
936254885Sdumbbell			 ~(RADEON_PLL_DIV_SEL));
937254885Sdumbbell		r100_pll_errata_after_index(rdev);
938254885Sdumbbell
939254885Sdumbbell		if (ASIC_IS_R300(rdev) ||
940254885Sdumbbell		    (rdev->family == CHIP_RS300) ||
941254885Sdumbbell		    (rdev->family == CHIP_RS400) ||
942254885Sdumbbell		    (rdev->family == CHIP_RS480)) {
943254885Sdumbbell			if (pll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) {
944254885Sdumbbell				/* When restoring console mode, use saved PPLL_REF_DIV
945254885Sdumbbell				 * setting.
946254885Sdumbbell				 */
947254885Sdumbbell				WREG32_PLL_P(RADEON_PPLL_REF_DIV,
948254885Sdumbbell					     pll_ref_div,
949254885Sdumbbell					     0);
950254885Sdumbbell			} else {
951254885Sdumbbell				/* R300 uses ref_div_acc field as real ref divider */
952254885Sdumbbell				WREG32_PLL_P(RADEON_PPLL_REF_DIV,
953254885Sdumbbell					     (pll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT),
954254885Sdumbbell					     ~R300_PPLL_REF_DIV_ACC_MASK);
955254885Sdumbbell			}
956254885Sdumbbell		} else
957254885Sdumbbell			WREG32_PLL_P(RADEON_PPLL_REF_DIV,
958254885Sdumbbell				     pll_ref_div,
959254885Sdumbbell				     ~RADEON_PPLL_REF_DIV_MASK);
960254885Sdumbbell
961254885Sdumbbell		WREG32_PLL_P(RADEON_PPLL_DIV_3,
962254885Sdumbbell			     pll_fb_post_div,
963254885Sdumbbell			     ~RADEON_PPLL_FB3_DIV_MASK);
964254885Sdumbbell
965254885Sdumbbell		WREG32_PLL_P(RADEON_PPLL_DIV_3,
966254885Sdumbbell			     pll_fb_post_div,
967254885Sdumbbell			     ~RADEON_PPLL_POST3_DIV_MASK);
968254885Sdumbbell
969254885Sdumbbell		radeon_pll_write_update(dev);
970254885Sdumbbell		radeon_pll_wait_for_read_update_complete(dev);
971254885Sdumbbell
972254885Sdumbbell		WREG32_PLL(RADEON_HTOTAL_CNTL, htotal_cntl);
973254885Sdumbbell
974254885Sdumbbell		WREG32_PLL_P(RADEON_PPLL_CNTL,
975254885Sdumbbell			     0,
976254885Sdumbbell			     ~(RADEON_PPLL_RESET
977254885Sdumbbell			       | RADEON_PPLL_SLEEP
978254885Sdumbbell			       | RADEON_PPLL_ATOMIC_UPDATE_EN
979254885Sdumbbell			       | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN));
980254885Sdumbbell
981254885Sdumbbell		DRM_DEBUG_KMS("Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n",
982254885Sdumbbell			  pll_ref_div,
983254885Sdumbbell			  pll_fb_post_div,
984254885Sdumbbell			  (unsigned)htotal_cntl,
985254885Sdumbbell			  RREG32_PLL(RADEON_PPLL_CNTL));
986254885Sdumbbell		DRM_DEBUG_KMS("Wrote: rd=%d, fd=%d, pd=%d\n",
987254885Sdumbbell			  pll_ref_div & RADEON_PPLL_REF_DIV_MASK,
988254885Sdumbbell			  pll_fb_post_div & RADEON_PPLL_FB3_DIV_MASK,
989254885Sdumbbell			  (pll_fb_post_div & RADEON_PPLL_POST3_DIV_MASK) >> 16);
990254885Sdumbbell
991280183Sdumbbell		mdelay(50); /* Let the clock to lock */
992254885Sdumbbell
993254885Sdumbbell		WREG32_PLL_P(RADEON_VCLK_ECP_CNTL,
994254885Sdumbbell			     RADEON_VCLK_SRC_SEL_PPLLCLK,
995254885Sdumbbell			     ~(RADEON_VCLK_SRC_SEL_MASK));
996254885Sdumbbell
997254885Sdumbbell		if (is_tv)
998254885Sdumbbell			WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl);
999254885Sdumbbell	}
1000254885Sdumbbell}
1001254885Sdumbbell
1002254885Sdumbbellstatic bool radeon_crtc_mode_fixup(struct drm_crtc *crtc,
1003254885Sdumbbell				   const struct drm_display_mode *mode,
1004254885Sdumbbell				   struct drm_display_mode *adjusted_mode)
1005254885Sdumbbell{
1006254885Sdumbbell	if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode))
1007254885Sdumbbell		return false;
1008254885Sdumbbell	return true;
1009254885Sdumbbell}
1010254885Sdumbbell
1011254885Sdumbbellstatic int radeon_crtc_mode_set(struct drm_crtc *crtc,
1012254885Sdumbbell				 struct drm_display_mode *mode,
1013254885Sdumbbell				 struct drm_display_mode *adjusted_mode,
1014254885Sdumbbell				 int x, int y, struct drm_framebuffer *old_fb)
1015254885Sdumbbell{
1016254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1017254885Sdumbbell
1018254885Sdumbbell	/* TODO TV */
1019254885Sdumbbell	radeon_crtc_set_base(crtc, x, y, old_fb);
1020254885Sdumbbell	radeon_set_crtc_timing(crtc, adjusted_mode);
1021254885Sdumbbell	radeon_set_pll(crtc, adjusted_mode);
1022254885Sdumbbell	radeon_overscan_setup(crtc, adjusted_mode);
1023254885Sdumbbell	if (radeon_crtc->crtc_id == 0) {
1024254885Sdumbbell		radeon_legacy_rmx_mode_set(crtc, adjusted_mode);
1025254885Sdumbbell	} else {
1026254885Sdumbbell		if (radeon_crtc->rmx_type != RMX_OFF) {
1027254885Sdumbbell			/* FIXME: only first crtc has rmx what should we
1028254885Sdumbbell			 * do ?
1029254885Sdumbbell			 */
1030254885Sdumbbell			DRM_ERROR("Mode need scaling but only first crtc can do that.\n");
1031254885Sdumbbell		}
1032254885Sdumbbell	}
1033254885Sdumbbell	return 0;
1034254885Sdumbbell}
1035254885Sdumbbell
1036254885Sdumbbellstatic void radeon_crtc_prepare(struct drm_crtc *crtc)
1037254885Sdumbbell{
1038254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1039254885Sdumbbell	struct drm_device *dev = crtc->dev;
1040254885Sdumbbell	struct drm_crtc *crtci;
1041254885Sdumbbell
1042254885Sdumbbell	radeon_crtc->in_mode_set = true;
1043254885Sdumbbell	/*
1044254885Sdumbbell	* The hardware wedges sometimes if you reconfigure one CRTC
1045254885Sdumbbell	* whilst another is running (see fdo bug #24611).
1046254885Sdumbbell	*/
1047254885Sdumbbell	list_for_each_entry(crtci, &dev->mode_config.crtc_list, head)
1048254885Sdumbbell		radeon_crtc_dpms(crtci, DRM_MODE_DPMS_OFF);
1049254885Sdumbbell}
1050254885Sdumbbell
1051254885Sdumbbellstatic void radeon_crtc_commit(struct drm_crtc *crtc)
1052254885Sdumbbell{
1053254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1054254885Sdumbbell	struct drm_device *dev = crtc->dev;
1055254885Sdumbbell	struct drm_crtc *crtci;
1056254885Sdumbbell
1057254885Sdumbbell	/*
1058254885Sdumbbell	* Reenable the CRTCs that should be running.
1059254885Sdumbbell	*/
1060254885Sdumbbell	list_for_each_entry(crtci, &dev->mode_config.crtc_list, head) {
1061254885Sdumbbell		if (crtci->enabled)
1062254885Sdumbbell			radeon_crtc_dpms(crtci, DRM_MODE_DPMS_ON);
1063254885Sdumbbell	}
1064254885Sdumbbell	radeon_crtc->in_mode_set = false;
1065254885Sdumbbell}
1066254885Sdumbbell
1067254885Sdumbbellstatic const struct drm_crtc_helper_funcs legacy_helper_funcs = {
1068254885Sdumbbell	.dpms = radeon_crtc_dpms,
1069254885Sdumbbell	.mode_fixup = radeon_crtc_mode_fixup,
1070254885Sdumbbell	.mode_set = radeon_crtc_mode_set,
1071254885Sdumbbell	.mode_set_base = radeon_crtc_set_base,
1072254885Sdumbbell	.mode_set_base_atomic = radeon_crtc_set_base_atomic,
1073254885Sdumbbell	.prepare = radeon_crtc_prepare,
1074254885Sdumbbell	.commit = radeon_crtc_commit,
1075254885Sdumbbell	.load_lut = radeon_crtc_load_lut,
1076254885Sdumbbell};
1077254885Sdumbbell
1078254885Sdumbbell
1079254885Sdumbbellvoid radeon_legacy_init_crtc(struct drm_device *dev,
1080254885Sdumbbell			       struct radeon_crtc *radeon_crtc)
1081254885Sdumbbell{
1082254885Sdumbbell	if (radeon_crtc->crtc_id == 1)
1083254885Sdumbbell		radeon_crtc->crtc_offset = RADEON_CRTC2_H_TOTAL_DISP - RADEON_CRTC_H_TOTAL_DISP;
1084254885Sdumbbell	drm_crtc_helper_add(&radeon_crtc->base, &legacy_helper_funcs);
1085254885Sdumbbell}
1086