1771fe6b9SJerome Glisse /*
2771fe6b9SJerome Glisse * Copyright 2007-8 Advanced Micro Devices, Inc.
3771fe6b9SJerome Glisse * Copyright 2008 Red Hat Inc.
4771fe6b9SJerome Glisse *
5771fe6b9SJerome Glisse * Permission is hereby granted, free of charge, to any person obtaining a
6771fe6b9SJerome Glisse * copy of this software and associated documentation files (the "Software"),
7771fe6b9SJerome Glisse * to deal in the Software without restriction, including without limitation
8771fe6b9SJerome Glisse * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9771fe6b9SJerome Glisse * and/or sell copies of the Software, and to permit persons to whom the
10771fe6b9SJerome Glisse * Software is furnished to do so, subject to the following conditions:
11771fe6b9SJerome Glisse *
12771fe6b9SJerome Glisse * The above copyright notice and this permission notice shall be included in
13771fe6b9SJerome Glisse * all copies or substantial portions of the Software.
14771fe6b9SJerome Glisse *
15771fe6b9SJerome Glisse * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16771fe6b9SJerome Glisse * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17771fe6b9SJerome Glisse * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18771fe6b9SJerome Glisse * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19771fe6b9SJerome Glisse * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20771fe6b9SJerome Glisse * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21771fe6b9SJerome Glisse * OTHER DEALINGS IN THE SOFTWARE.
22771fe6b9SJerome Glisse *
23771fe6b9SJerome Glisse * Authors: Dave Airlie
24771fe6b9SJerome Glisse * Alex Deucher
25771fe6b9SJerome Glisse */
26f9183127SSam Ravnborg
2768adac5eSBen Skeggs #include <drm/drm_fixed.h>
28f9183127SSam Ravnborg #include <drm/drm_fourcc.h>
29720cf96dSVille Syrjälä #include <drm/drm_framebuffer.h>
30*f7d17cd4SThomas Zimmermann #include <drm/drm_modeset_helper_vtables.h>
31f9183127SSam Ravnborg #include <drm/drm_vblank.h>
32f9183127SSam Ravnborg #include <drm/radeon_drm.h>
33f9183127SSam Ravnborg
344ce001abSDave Airlie #include "atom.h"
35f9183127SSam Ravnborg #include "radeon.h"
36771fe6b9SJerome Glisse
radeon_overscan_setup(struct drm_crtc * crtc,struct drm_display_mode * mode)376b02af1cSAlex Deucher static void radeon_overscan_setup(struct drm_crtc *crtc,
386b02af1cSAlex Deucher struct drm_display_mode *mode)
396b02af1cSAlex Deucher {
406b02af1cSAlex Deucher struct drm_device *dev = crtc->dev;
416b02af1cSAlex Deucher struct radeon_device *rdev = dev->dev_private;
426b02af1cSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
436b02af1cSAlex Deucher
446b02af1cSAlex Deucher WREG32(RADEON_OVR_CLR + radeon_crtc->crtc_offset, 0);
456b02af1cSAlex Deucher WREG32(RADEON_OVR_WID_LEFT_RIGHT + radeon_crtc->crtc_offset, 0);
466b02af1cSAlex Deucher WREG32(RADEON_OVR_WID_TOP_BOTTOM + radeon_crtc->crtc_offset, 0);
476b02af1cSAlex Deucher }
486b02af1cSAlex Deucher
radeon_legacy_rmx_mode_set(struct drm_crtc * crtc,struct drm_display_mode * mode)49c93bb85bSJerome Glisse static void radeon_legacy_rmx_mode_set(struct drm_crtc *crtc,
50310a82c8SAlex Deucher struct drm_display_mode *mode)
51c93bb85bSJerome Glisse {
52c93bb85bSJerome Glisse struct drm_device *dev = crtc->dev;
53c93bb85bSJerome Glisse struct radeon_device *rdev = dev->dev_private;
54c93bb85bSJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
55c93bb85bSJerome Glisse int xres = mode->hdisplay;
56c93bb85bSJerome Glisse int yres = mode->vdisplay;
57c93bb85bSJerome Glisse bool hscale = true, vscale = true;
58c93bb85bSJerome Glisse int hsync_wid;
59c93bb85bSJerome Glisse int vsync_wid;
60c93bb85bSJerome Glisse int hsync_start;
61c93bb85bSJerome Glisse int blank_width;
62c93bb85bSJerome Glisse u32 scale, inc, crtc_more_cntl;
63c93bb85bSJerome Glisse u32 fp_horz_stretch, fp_vert_stretch, fp_horz_vert_active;
64c93bb85bSJerome Glisse u32 fp_h_sync_strt_wid, fp_crtc_h_total_disp;
65c93bb85bSJerome Glisse u32 fp_v_sync_strt_wid, fp_crtc_v_total_disp;
66de2103e4SAlex Deucher struct drm_display_mode *native_mode = &radeon_crtc->native_mode;
67c93bb85bSJerome Glisse
68c93bb85bSJerome Glisse fp_vert_stretch = RREG32(RADEON_FP_VERT_STRETCH) &
69c93bb85bSJerome Glisse (RADEON_VERT_STRETCH_RESERVED |
70c93bb85bSJerome Glisse RADEON_VERT_AUTO_RATIO_INC);
71c93bb85bSJerome Glisse fp_horz_stretch = RREG32(RADEON_FP_HORZ_STRETCH) &
72c93bb85bSJerome Glisse (RADEON_HORZ_FP_LOOP_STRETCH |
73c93bb85bSJerome Glisse RADEON_HORZ_AUTO_RATIO_INC);
74c93bb85bSJerome Glisse
75c93bb85bSJerome Glisse crtc_more_cntl = 0;
76c93bb85bSJerome Glisse if ((rdev->family == CHIP_RS100) ||
77c93bb85bSJerome Glisse (rdev->family == CHIP_RS200)) {
78c93bb85bSJerome Glisse /* This is to workaround the asic bug for RMX, some versions
79c93bb85bSJerome Glisse of BIOS dosen't have this register initialized correctly. */
80c93bb85bSJerome Glisse crtc_more_cntl |= RADEON_CRTC_H_CUTOFF_ACTIVE_EN;
81c93bb85bSJerome Glisse }
82c93bb85bSJerome Glisse
83c93bb85bSJerome Glisse
84c93bb85bSJerome Glisse fp_crtc_h_total_disp = ((((mode->crtc_htotal / 8) - 1) & 0x3ff)
85c93bb85bSJerome Glisse | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16));
86c93bb85bSJerome Glisse
87c93bb85bSJerome Glisse hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8;
88c93bb85bSJerome Glisse if (!hsync_wid)
89c93bb85bSJerome Glisse hsync_wid = 1;
90c93bb85bSJerome Glisse hsync_start = mode->crtc_hsync_start - 8;
91c93bb85bSJerome Glisse
92c93bb85bSJerome Glisse fp_h_sync_strt_wid = ((hsync_start & 0x1fff)
93c93bb85bSJerome Glisse | ((hsync_wid & 0x3f) << 16)
94c93bb85bSJerome Glisse | ((mode->flags & DRM_MODE_FLAG_NHSYNC)
95c93bb85bSJerome Glisse ? RADEON_CRTC_H_SYNC_POL
96c93bb85bSJerome Glisse : 0));
97c93bb85bSJerome Glisse
98c93bb85bSJerome Glisse fp_crtc_v_total_disp = (((mode->crtc_vtotal - 1) & 0xffff)
99c93bb85bSJerome Glisse | ((mode->crtc_vdisplay - 1) << 16));
100c93bb85bSJerome Glisse
101c93bb85bSJerome Glisse vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start;
102c93bb85bSJerome Glisse if (!vsync_wid)
103c93bb85bSJerome Glisse vsync_wid = 1;
104c93bb85bSJerome Glisse
105c93bb85bSJerome Glisse fp_v_sync_strt_wid = (((mode->crtc_vsync_start - 1) & 0xfff)
106c93bb85bSJerome Glisse | ((vsync_wid & 0x1f) << 16)
107c93bb85bSJerome Glisse | ((mode->flags & DRM_MODE_FLAG_NVSYNC)
108c93bb85bSJerome Glisse ? RADEON_CRTC_V_SYNC_POL
109c93bb85bSJerome Glisse : 0));
110c93bb85bSJerome Glisse
111c93bb85bSJerome Glisse fp_horz_vert_active = 0;
112c93bb85bSJerome Glisse
113de2103e4SAlex Deucher if (native_mode->hdisplay == 0 ||
114de2103e4SAlex Deucher native_mode->vdisplay == 0) {
115c93bb85bSJerome Glisse hscale = false;
116c93bb85bSJerome Glisse vscale = false;
117c93bb85bSJerome Glisse } else {
118de2103e4SAlex Deucher if (xres > native_mode->hdisplay)
119de2103e4SAlex Deucher xres = native_mode->hdisplay;
120de2103e4SAlex Deucher if (yres > native_mode->vdisplay)
121de2103e4SAlex Deucher yres = native_mode->vdisplay;
122c93bb85bSJerome Glisse
123de2103e4SAlex Deucher if (xres == native_mode->hdisplay)
124c93bb85bSJerome Glisse hscale = false;
125de2103e4SAlex Deucher if (yres == native_mode->vdisplay)
126c93bb85bSJerome Glisse vscale = false;
127c93bb85bSJerome Glisse }
128c93bb85bSJerome Glisse
129c93bb85bSJerome Glisse switch (radeon_crtc->rmx_type) {
130c93bb85bSJerome Glisse case RMX_FULL:
131c93bb85bSJerome Glisse case RMX_ASPECT:
132c93bb85bSJerome Glisse if (!hscale)
133c93bb85bSJerome Glisse fp_horz_stretch |= ((xres/8-1) << 16);
134c93bb85bSJerome Glisse else {
135c93bb85bSJerome Glisse inc = (fp_horz_stretch & RADEON_HORZ_AUTO_RATIO_INC) ? 1 : 0;
136c93bb85bSJerome Glisse scale = ((xres + inc) * RADEON_HORZ_STRETCH_RATIO_MAX)
137de2103e4SAlex Deucher / native_mode->hdisplay + 1;
138c93bb85bSJerome Glisse fp_horz_stretch |= (((scale) & RADEON_HORZ_STRETCH_RATIO_MASK) |
139c93bb85bSJerome Glisse RADEON_HORZ_STRETCH_BLEND |
140c93bb85bSJerome Glisse RADEON_HORZ_STRETCH_ENABLE |
141de2103e4SAlex Deucher ((native_mode->hdisplay/8-1) << 16));
142c93bb85bSJerome Glisse }
143c93bb85bSJerome Glisse
144c93bb85bSJerome Glisse if (!vscale)
145c93bb85bSJerome Glisse fp_vert_stretch |= ((yres-1) << 12);
146c93bb85bSJerome Glisse else {
147c93bb85bSJerome Glisse inc = (fp_vert_stretch & RADEON_VERT_AUTO_RATIO_INC) ? 1 : 0;
148c93bb85bSJerome Glisse scale = ((yres + inc) * RADEON_VERT_STRETCH_RATIO_MAX)
149de2103e4SAlex Deucher / native_mode->vdisplay + 1;
150c93bb85bSJerome Glisse fp_vert_stretch |= (((scale) & RADEON_VERT_STRETCH_RATIO_MASK) |
151c93bb85bSJerome Glisse RADEON_VERT_STRETCH_ENABLE |
152c93bb85bSJerome Glisse RADEON_VERT_STRETCH_BLEND |
153de2103e4SAlex Deucher ((native_mode->vdisplay-1) << 12));
154c93bb85bSJerome Glisse }
155c93bb85bSJerome Glisse break;
156c93bb85bSJerome Glisse case RMX_CENTER:
157c93bb85bSJerome Glisse fp_horz_stretch |= ((xres/8-1) << 16);
158c93bb85bSJerome Glisse fp_vert_stretch |= ((yres-1) << 12);
159c93bb85bSJerome Glisse
160c93bb85bSJerome Glisse crtc_more_cntl |= (RADEON_CRTC_AUTO_HORZ_CENTER_EN |
161c93bb85bSJerome Glisse RADEON_CRTC_AUTO_VERT_CENTER_EN);
162c93bb85bSJerome Glisse
163c93bb85bSJerome Glisse blank_width = (mode->crtc_hblank_end - mode->crtc_hblank_start) / 8;
164c93bb85bSJerome Glisse if (blank_width > 110)
165c93bb85bSJerome Glisse blank_width = 110;
166c93bb85bSJerome Glisse
167c93bb85bSJerome Glisse fp_crtc_h_total_disp = (((blank_width) & 0x3ff)
168c93bb85bSJerome Glisse | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16));
169c93bb85bSJerome Glisse
170c93bb85bSJerome Glisse hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8;
171c93bb85bSJerome Glisse if (!hsync_wid)
172c93bb85bSJerome Glisse hsync_wid = 1;
173c93bb85bSJerome Glisse
174c93bb85bSJerome Glisse fp_h_sync_strt_wid = ((((mode->crtc_hsync_start - mode->crtc_hblank_start) / 8) & 0x1fff)
175c93bb85bSJerome Glisse | ((hsync_wid & 0x3f) << 16)
176c93bb85bSJerome Glisse | ((mode->flags & DRM_MODE_FLAG_NHSYNC)
177c93bb85bSJerome Glisse ? RADEON_CRTC_H_SYNC_POL
178c93bb85bSJerome Glisse : 0));
179c93bb85bSJerome Glisse
180c93bb85bSJerome Glisse fp_crtc_v_total_disp = (((mode->crtc_vblank_end - mode->crtc_vblank_start) & 0xffff)
181c93bb85bSJerome Glisse | ((mode->crtc_vdisplay - 1) << 16));
182c93bb85bSJerome Glisse
183c93bb85bSJerome Glisse vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start;
184c93bb85bSJerome Glisse if (!vsync_wid)
185c93bb85bSJerome Glisse vsync_wid = 1;
186c93bb85bSJerome Glisse
187c93bb85bSJerome Glisse fp_v_sync_strt_wid = ((((mode->crtc_vsync_start - mode->crtc_vblank_start) & 0xfff)
188c93bb85bSJerome Glisse | ((vsync_wid & 0x1f) << 16)
189c93bb85bSJerome Glisse | ((mode->flags & DRM_MODE_FLAG_NVSYNC)
190c93bb85bSJerome Glisse ? RADEON_CRTC_V_SYNC_POL
191c93bb85bSJerome Glisse : 0)));
192c93bb85bSJerome Glisse
193de2103e4SAlex Deucher fp_horz_vert_active = (((native_mode->vdisplay) & 0xfff) |
194de2103e4SAlex Deucher (((native_mode->hdisplay / 8) & 0x1ff) << 16));
195c93bb85bSJerome Glisse break;
196c93bb85bSJerome Glisse case RMX_OFF:
197c93bb85bSJerome Glisse default:
198c93bb85bSJerome Glisse fp_horz_stretch |= ((xres/8-1) << 16);
199c93bb85bSJerome Glisse fp_vert_stretch |= ((yres-1) << 12);
200c93bb85bSJerome Glisse break;
201c93bb85bSJerome Glisse }
202c93bb85bSJerome Glisse
203c93bb85bSJerome Glisse WREG32(RADEON_FP_HORZ_STRETCH, fp_horz_stretch);
204c93bb85bSJerome Glisse WREG32(RADEON_FP_VERT_STRETCH, fp_vert_stretch);
205c93bb85bSJerome Glisse WREG32(RADEON_CRTC_MORE_CNTL, crtc_more_cntl);
206c93bb85bSJerome Glisse WREG32(RADEON_FP_HORZ_VERT_ACTIVE, fp_horz_vert_active);
207c93bb85bSJerome Glisse WREG32(RADEON_FP_H_SYNC_STRT_WID, fp_h_sync_strt_wid);
208c93bb85bSJerome Glisse WREG32(RADEON_FP_V_SYNC_STRT_WID, fp_v_sync_strt_wid);
209c93bb85bSJerome Glisse WREG32(RADEON_FP_CRTC_H_TOTAL_DISP, fp_crtc_h_total_disp);
210c93bb85bSJerome Glisse WREG32(RADEON_FP_CRTC_V_TOTAL_DISP, fp_crtc_v_total_disp);
211c93bb85bSJerome Glisse }
212c93bb85bSJerome Glisse
radeon_pll_wait_for_read_update_complete(struct drm_device * dev)213771fe6b9SJerome Glisse static void radeon_pll_wait_for_read_update_complete(struct drm_device *dev)
214771fe6b9SJerome Glisse {
215771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private;
216771fe6b9SJerome Glisse int i = 0;
217771fe6b9SJerome Glisse
218771fe6b9SJerome Glisse /* FIXME: Certain revisions of R300 can't recover here. Not sure of
219771fe6b9SJerome Glisse the cause yet, but this workaround will mask the problem for now.
220771fe6b9SJerome Glisse Other chips usually will pass at the very first test, so the
221771fe6b9SJerome Glisse workaround shouldn't have any effect on them. */
222771fe6b9SJerome Glisse for (i = 0;
223771fe6b9SJerome Glisse (i < 10000 &&
224771fe6b9SJerome Glisse RREG32_PLL(RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R);
225771fe6b9SJerome Glisse i++);
226771fe6b9SJerome Glisse }
227771fe6b9SJerome Glisse
radeon_pll_write_update(struct drm_device * dev)228771fe6b9SJerome Glisse static void radeon_pll_write_update(struct drm_device *dev)
229771fe6b9SJerome Glisse {
230771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private;
231771fe6b9SJerome Glisse
232771fe6b9SJerome Glisse while (RREG32_PLL(RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R);
233771fe6b9SJerome Glisse
234771fe6b9SJerome Glisse WREG32_PLL_P(RADEON_PPLL_REF_DIV,
235771fe6b9SJerome Glisse RADEON_PPLL_ATOMIC_UPDATE_W,
236771fe6b9SJerome Glisse ~(RADEON_PPLL_ATOMIC_UPDATE_W));
237771fe6b9SJerome Glisse }
238771fe6b9SJerome Glisse
radeon_pll2_wait_for_read_update_complete(struct drm_device * dev)239771fe6b9SJerome Glisse static void radeon_pll2_wait_for_read_update_complete(struct drm_device *dev)
240771fe6b9SJerome Glisse {
241771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private;
242771fe6b9SJerome Glisse int i = 0;
243771fe6b9SJerome Glisse
244771fe6b9SJerome Glisse
245771fe6b9SJerome Glisse /* FIXME: Certain revisions of R300 can't recover here. Not sure of
246771fe6b9SJerome Glisse the cause yet, but this workaround will mask the problem for now.
247771fe6b9SJerome Glisse Other chips usually will pass at the very first test, so the
248771fe6b9SJerome Glisse workaround shouldn't have any effect on them. */
249771fe6b9SJerome Glisse for (i = 0;
250771fe6b9SJerome Glisse (i < 10000 &&
251771fe6b9SJerome Glisse RREG32_PLL(RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R);
252771fe6b9SJerome Glisse i++);
253771fe6b9SJerome Glisse }
254771fe6b9SJerome Glisse
radeon_pll2_write_update(struct drm_device * dev)255771fe6b9SJerome Glisse static void radeon_pll2_write_update(struct drm_device *dev)
256771fe6b9SJerome Glisse {
257771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private;
258771fe6b9SJerome Glisse
259771fe6b9SJerome Glisse while (RREG32_PLL(RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R);
260771fe6b9SJerome Glisse
261771fe6b9SJerome Glisse WREG32_PLL_P(RADEON_P2PLL_REF_DIV,
262771fe6b9SJerome Glisse RADEON_P2PLL_ATOMIC_UPDATE_W,
263771fe6b9SJerome Glisse ~(RADEON_P2PLL_ATOMIC_UPDATE_W));
264771fe6b9SJerome Glisse }
265771fe6b9SJerome Glisse
radeon_compute_pll_gain(uint16_t ref_freq,uint16_t ref_div,uint16_t fb_div)266771fe6b9SJerome Glisse static uint8_t radeon_compute_pll_gain(uint16_t ref_freq, uint16_t ref_div,
267771fe6b9SJerome Glisse uint16_t fb_div)
268771fe6b9SJerome Glisse {
269771fe6b9SJerome Glisse unsigned int vcoFreq;
270771fe6b9SJerome Glisse
271771fe6b9SJerome Glisse if (!ref_div)
272771fe6b9SJerome Glisse return 1;
273771fe6b9SJerome Glisse
2740537398bSAlex Deucher vcoFreq = ((unsigned)ref_freq * fb_div) / ref_div;
275771fe6b9SJerome Glisse
276771fe6b9SJerome Glisse /*
277771fe6b9SJerome Glisse * This is horribly crude: the VCO frequency range is divided into
278771fe6b9SJerome Glisse * 3 parts, each part having a fixed PLL gain value.
279771fe6b9SJerome Glisse */
280771fe6b9SJerome Glisse if (vcoFreq >= 30000)
281771fe6b9SJerome Glisse /*
282771fe6b9SJerome Glisse * [300..max] MHz : 7
283771fe6b9SJerome Glisse */
284771fe6b9SJerome Glisse return 7;
285771fe6b9SJerome Glisse else if (vcoFreq >= 18000)
286771fe6b9SJerome Glisse /*
287771fe6b9SJerome Glisse * [180..300) MHz : 4
288771fe6b9SJerome Glisse */
289771fe6b9SJerome Glisse return 4;
290771fe6b9SJerome Glisse else
291771fe6b9SJerome Glisse /*
292771fe6b9SJerome Glisse * [0..180) MHz : 1
293771fe6b9SJerome Glisse */
294771fe6b9SJerome Glisse return 1;
295771fe6b9SJerome Glisse }
296771fe6b9SJerome Glisse
radeon_crtc_dpms(struct drm_crtc * crtc,int mode)2971109ca09SLauri Kasanen static void radeon_crtc_dpms(struct drm_crtc *crtc, int mode)
298771fe6b9SJerome Glisse {
299771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
300771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev;
301771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private;
302f8c4d701SEgbert Eich uint32_t crtc_ext_cntl = 0;
303771fe6b9SJerome Glisse uint32_t mask;
304771fe6b9SJerome Glisse
305771fe6b9SJerome Glisse if (radeon_crtc->crtc_id)
3068de21525SAlex Deucher mask = (RADEON_CRTC2_DISP_DIS |
307771fe6b9SJerome Glisse RADEON_CRTC2_VSYNC_DIS |
308771fe6b9SJerome Glisse RADEON_CRTC2_HSYNC_DIS |
309771fe6b9SJerome Glisse RADEON_CRTC2_DISP_REQ_EN_B);
310771fe6b9SJerome Glisse else
311771fe6b9SJerome Glisse mask = (RADEON_CRTC_DISPLAY_DIS |
312771fe6b9SJerome Glisse RADEON_CRTC_VSYNC_DIS |
313771fe6b9SJerome Glisse RADEON_CRTC_HSYNC_DIS);
314771fe6b9SJerome Glisse
315f8c4d701SEgbert Eich /*
316f8c4d701SEgbert Eich * On all dual CRTC GPUs this bit controls the CRTC of the primary DAC.
317f8c4d701SEgbert Eich * Therefore it is set in the DAC DMPS function.
318f8c4d701SEgbert Eich * This is different for GPU's with a single CRTC but a primary and a
319f8c4d701SEgbert Eich * TV DAC: here it controls the single CRTC no matter where it is
320f8c4d701SEgbert Eich * routed. Therefore we set it here.
321f8c4d701SEgbert Eich */
322f8c4d701SEgbert Eich if (rdev->flags & RADEON_SINGLE_CRTC)
323f8c4d701SEgbert Eich crtc_ext_cntl = RADEON_CRTC_CRT_ON;
324f8c4d701SEgbert Eich
325771fe6b9SJerome Glisse switch (mode) {
326771fe6b9SJerome Glisse case DRM_MODE_DPMS_ON:
327d7311171SAlex Deucher radeon_crtc->enabled = true;
328d7311171SAlex Deucher /* adjust pm to dpms changes BEFORE enabling crtcs */
329d7311171SAlex Deucher radeon_pm_compute_clocks(rdev);
330771fe6b9SJerome Glisse if (radeon_crtc->crtc_id)
3318de21525SAlex Deucher WREG32_P(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_EN, ~(RADEON_CRTC2_EN | mask));
332771fe6b9SJerome Glisse else {
333771fe6b9SJerome Glisse WREG32_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_EN, ~(RADEON_CRTC_EN |
334771fe6b9SJerome Glisse RADEON_CRTC_DISP_REQ_EN_B));
335f8c4d701SEgbert Eich WREG32_P(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl, ~(mask | crtc_ext_cntl));
336771fe6b9SJerome Glisse }
3375e916a3aSMichel Dänzer if (dev->num_crtcs > radeon_crtc->crtc_id)
3385c9ac115SGustavo Padovan drm_crtc_vblank_on(crtc);
3397ed220d7SMichel Dänzer radeon_crtc_load_lut(crtc);
340771fe6b9SJerome Glisse break;
341771fe6b9SJerome Glisse case DRM_MODE_DPMS_STANDBY:
342771fe6b9SJerome Glisse case DRM_MODE_DPMS_SUSPEND:
343771fe6b9SJerome Glisse case DRM_MODE_DPMS_OFF:
3445e916a3aSMichel Dänzer if (dev->num_crtcs > radeon_crtc->crtc_id)
3455c9ac115SGustavo Padovan drm_crtc_vblank_off(crtc);
346771fe6b9SJerome Glisse if (radeon_crtc->crtc_id)
3478de21525SAlex Deucher WREG32_P(RADEON_CRTC2_GEN_CNTL, mask, ~(RADEON_CRTC2_EN | mask));
348771fe6b9SJerome Glisse else {
349771fe6b9SJerome Glisse WREG32_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_DISP_REQ_EN_B, ~(RADEON_CRTC_EN |
350771fe6b9SJerome Glisse RADEON_CRTC_DISP_REQ_EN_B));
351f8c4d701SEgbert Eich WREG32_P(RADEON_CRTC_EXT_CNTL, mask, ~(mask | crtc_ext_cntl));
352771fe6b9SJerome Glisse }
353a48b9b4eSAlex Deucher radeon_crtc->enabled = false;
354d7311171SAlex Deucher /* adjust pm to dpms changes AFTER disabling crtcs */
355d7311171SAlex Deucher radeon_pm_compute_clocks(rdev);
356771fe6b9SJerome Glisse break;
357771fe6b9SJerome Glisse }
358771fe6b9SJerome Glisse }
359771fe6b9SJerome Glisse
radeon_crtc_set_base(struct drm_crtc * crtc,int x,int y,struct drm_framebuffer * old_fb)360771fe6b9SJerome Glisse int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
361771fe6b9SJerome Glisse struct drm_framebuffer *old_fb)
362771fe6b9SJerome Glisse {
3634dd19b0dSChris Ball return radeon_crtc_do_set_base(crtc, old_fb, x, y, 0);
3644dd19b0dSChris Ball }
3654dd19b0dSChris Ball
radeon_crtc_set_base_atomic(struct drm_crtc * crtc,struct drm_framebuffer * fb,int x,int y,enum mode_set_atomic state)3664dd19b0dSChris Ball int radeon_crtc_set_base_atomic(struct drm_crtc *crtc,
3674dd19b0dSChris Ball struct drm_framebuffer *fb,
36821c74a8eSJason Wessel int x, int y, enum mode_set_atomic state)
3694dd19b0dSChris Ball {
3704dd19b0dSChris Ball return radeon_crtc_do_set_base(crtc, fb, x, y, 1);
3714dd19b0dSChris Ball }
3724dd19b0dSChris Ball
radeon_crtc_do_set_base(struct drm_crtc * crtc,struct drm_framebuffer * fb,int x,int y,int atomic)3734dd19b0dSChris Ball int radeon_crtc_do_set_base(struct drm_crtc *crtc,
3744dd19b0dSChris Ball struct drm_framebuffer *fb,
3754dd19b0dSChris Ball int x, int y, int atomic)
3764dd19b0dSChris Ball {
377771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev;
378771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private;
379771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
3804dd19b0dSChris Ball struct drm_framebuffer *target_fb;
381771fe6b9SJerome Glisse struct drm_gem_object *obj;
3824c788679SJerome Glisse struct radeon_bo *rbo;
383771fe6b9SJerome Glisse uint64_t base;
384771fe6b9SJerome Glisse uint32_t crtc_offset, crtc_offset_cntl, crtc_tile_x0_y0 = 0;
385771fe6b9SJerome Glisse uint32_t crtc_pitch, pitch_pixels;
386e024e110SDave Airlie uint32_t tiling_flags;
38741456df2SDave Airlie int format;
38841456df2SDave Airlie uint32_t gen_cntl_reg, gen_cntl_val;
3894c788679SJerome Glisse int r;
390771fe6b9SJerome Glisse
391d9fdaafbSDave Airlie DRM_DEBUG_KMS("\n");
3922de3b484SJerome Glisse /* no fb bound */
393f4510a27SMatt Roper if (!atomic && !crtc->primary->fb) {
394d9fdaafbSDave Airlie DRM_DEBUG_KMS("No FB bound\n");
3952de3b484SJerome Glisse return 0;
3962de3b484SJerome Glisse }
397771fe6b9SJerome Glisse
3989a0f0c9dSDaniel Stone if (atomic)
3994dd19b0dSChris Ball target_fb = fb;
4009a0f0c9dSDaniel Stone else
401f4510a27SMatt Roper target_fb = crtc->primary->fb;
402771fe6b9SJerome Glisse
403272725c7SVille Syrjälä switch (target_fb->format->cpp[0] * 8) {
40441456df2SDave Airlie case 8:
40541456df2SDave Airlie format = 2;
40641456df2SDave Airlie break;
40741456df2SDave Airlie case 15: /* 555 */
40841456df2SDave Airlie format = 3;
40941456df2SDave Airlie break;
41041456df2SDave Airlie case 16: /* 565 */
41141456df2SDave Airlie format = 4;
41241456df2SDave Airlie break;
41341456df2SDave Airlie case 24: /* RGB */
41441456df2SDave Airlie format = 5;
41541456df2SDave Airlie break;
41641456df2SDave Airlie case 32: /* xRGB */
41741456df2SDave Airlie format = 6;
41841456df2SDave Airlie break;
41941456df2SDave Airlie default:
42041456df2SDave Airlie return false;
42141456df2SDave Airlie }
42241456df2SDave Airlie
4234c788679SJerome Glisse /* Pin framebuffer & get tilling informations */
4249a0f0c9dSDaniel Stone obj = target_fb->obj[0];
4257e4d15d9SDaniel Vetter rbo = gem_to_radeon_bo(obj);
42697b6ff6bSJerome Glisse retry:
4274c788679SJerome Glisse r = radeon_bo_reserve(rbo, false);
4284c788679SJerome Glisse if (unlikely(r != 0))
4294c788679SJerome Glisse return r;
4300349af70SMichel Dänzer /* Only 27 bit offset for legacy CRTC */
4310349af70SMichel Dänzer r = radeon_bo_pin_restricted(rbo, RADEON_GEM_DOMAIN_VRAM, 1 << 27,
4320349af70SMichel Dänzer &base);
4334c788679SJerome Glisse if (unlikely(r != 0)) {
4344c788679SJerome Glisse radeon_bo_unreserve(rbo);
43597b6ff6bSJerome Glisse
43697b6ff6bSJerome Glisse /* On old GPU like RN50 with little vram pining can fails because
43797b6ff6bSJerome Glisse * current fb is taking all space needed. So instead of unpining
43897b6ff6bSJerome Glisse * the old buffer after pining the new one, first unpin old one
43997b6ff6bSJerome Glisse * and then retry pining new one.
44097b6ff6bSJerome Glisse *
44197b6ff6bSJerome Glisse * As only master can set mode only master can pin and it is
44297b6ff6bSJerome Glisse * unlikely the master client will race with itself especialy
44397b6ff6bSJerome Glisse * on those old gpu with single crtc.
44497b6ff6bSJerome Glisse *
44597b6ff6bSJerome Glisse * We don't shutdown the display controller because new buffer
44697b6ff6bSJerome Glisse * will end up in same spot.
44797b6ff6bSJerome Glisse */
448f4510a27SMatt Roper if (!atomic && fb && fb != crtc->primary->fb) {
44997b6ff6bSJerome Glisse struct radeon_bo *old_rbo;
45097b6ff6bSJerome Glisse unsigned long nsize, osize;
45197b6ff6bSJerome Glisse
452a110dfe3SDaniel Stone old_rbo = gem_to_radeon_bo(fb->obj[0]);
45397b6ff6bSJerome Glisse osize = radeon_bo_size(old_rbo);
45497b6ff6bSJerome Glisse nsize = radeon_bo_size(rbo);
45597b6ff6bSJerome Glisse if (nsize <= osize && !radeon_bo_reserve(old_rbo, false)) {
45697b6ff6bSJerome Glisse radeon_bo_unpin(old_rbo);
45797b6ff6bSJerome Glisse radeon_bo_unreserve(old_rbo);
45897b6ff6bSJerome Glisse fb = NULL;
45997b6ff6bSJerome Glisse goto retry;
46097b6ff6bSJerome Glisse }
46197b6ff6bSJerome Glisse }
462771fe6b9SJerome Glisse return -EINVAL;
463771fe6b9SJerome Glisse }
4644c788679SJerome Glisse radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
4654c788679SJerome Glisse radeon_bo_unreserve(rbo);
4664c788679SJerome Glisse if (tiling_flags & RADEON_TILING_MICRO)
4674c788679SJerome Glisse DRM_ERROR("trying to scanout microtiled buffer\n");
4684c788679SJerome Glisse
4694162338aSDave Airlie /* if scanout was in GTT this really wouldn't work */
4704162338aSDave Airlie /* crtc offset is from display base addr not FB location */
471d594e46aSJerome Glisse radeon_crtc->legacy_display_base_addr = rdev->mc.vram_start;
4724162338aSDave Airlie
4734162338aSDave Airlie base -= radeon_crtc->legacy_display_base_addr;
4744162338aSDave Airlie
475771fe6b9SJerome Glisse crtc_offset_cntl = 0;
476771fe6b9SJerome Glisse
477272725c7SVille Syrjälä pitch_pixels = target_fb->pitches[0] / target_fb->format->cpp[0];
478272725c7SVille Syrjälä crtc_pitch = DIV_ROUND_UP(pitch_pixels * target_fb->format->cpp[0] * 8,
479272725c7SVille Syrjälä target_fb->format->cpp[0] * 8 * 8);
480771fe6b9SJerome Glisse crtc_pitch |= crtc_pitch << 16;
481771fe6b9SJerome Glisse
482c640e8caSDave Airlie crtc_offset_cntl |= RADEON_CRTC_GUI_TRIG_OFFSET_LEFT_EN;
483e024e110SDave Airlie if (tiling_flags & RADEON_TILING_MACRO) {
484771fe6b9SJerome Glisse if (ASIC_IS_R300(rdev))
485771fe6b9SJerome Glisse crtc_offset_cntl |= (R300_CRTC_X_Y_MODE_EN |
486771fe6b9SJerome Glisse R300_CRTC_MICRO_TILE_BUFFER_DIS |
487771fe6b9SJerome Glisse R300_CRTC_MACRO_TILE_EN);
488771fe6b9SJerome Glisse else
489771fe6b9SJerome Glisse crtc_offset_cntl |= RADEON_CRTC_TILE_EN;
490771fe6b9SJerome Glisse } else {
491771fe6b9SJerome Glisse if (ASIC_IS_R300(rdev))
492771fe6b9SJerome Glisse crtc_offset_cntl &= ~(R300_CRTC_X_Y_MODE_EN |
493771fe6b9SJerome Glisse R300_CRTC_MICRO_TILE_BUFFER_DIS |
494771fe6b9SJerome Glisse R300_CRTC_MACRO_TILE_EN);
495771fe6b9SJerome Glisse else
496771fe6b9SJerome Glisse crtc_offset_cntl &= ~RADEON_CRTC_TILE_EN;
497771fe6b9SJerome Glisse }
498771fe6b9SJerome Glisse
499e024e110SDave Airlie if (tiling_flags & RADEON_TILING_MACRO) {
500771fe6b9SJerome Glisse if (ASIC_IS_R300(rdev)) {
501771fe6b9SJerome Glisse crtc_tile_x0_y0 = x | (y << 16);
502771fe6b9SJerome Glisse base &= ~0x7ff;
503771fe6b9SJerome Glisse } else {
504272725c7SVille Syrjälä int byteshift = target_fb->format->cpp[0] * 8 >> 4;
505e024e110SDave Airlie int tile_addr = (((y >> 3) * pitch_pixels + x) >> (8 - byteshift)) << 11;
506771fe6b9SJerome Glisse base += tile_addr + ((x << byteshift) % 256) + ((y % 8) << 8);
507771fe6b9SJerome Glisse crtc_offset_cntl |= (y % 16);
508771fe6b9SJerome Glisse }
509771fe6b9SJerome Glisse } else {
510771fe6b9SJerome Glisse int offset = y * pitch_pixels + x;
511272725c7SVille Syrjälä switch (target_fb->format->cpp[0] * 8) {
51241456df2SDave Airlie case 8:
51341456df2SDave Airlie offset *= 1;
51441456df2SDave Airlie break;
515771fe6b9SJerome Glisse case 15:
516771fe6b9SJerome Glisse case 16:
517771fe6b9SJerome Glisse offset *= 2;
518771fe6b9SJerome Glisse break;
519771fe6b9SJerome Glisse case 24:
520771fe6b9SJerome Glisse offset *= 3;
521771fe6b9SJerome Glisse break;
522771fe6b9SJerome Glisse case 32:
523771fe6b9SJerome Glisse offset *= 4;
524771fe6b9SJerome Glisse break;
525771fe6b9SJerome Glisse default:
526771fe6b9SJerome Glisse return false;
527771fe6b9SJerome Glisse }
528771fe6b9SJerome Glisse base += offset;
529771fe6b9SJerome Glisse }
530771fe6b9SJerome Glisse
531771fe6b9SJerome Glisse base &= ~7;
532771fe6b9SJerome Glisse
53341456df2SDave Airlie if (radeon_crtc->crtc_id == 1)
53441456df2SDave Airlie gen_cntl_reg = RADEON_CRTC2_GEN_CNTL;
53541456df2SDave Airlie else
53641456df2SDave Airlie gen_cntl_reg = RADEON_CRTC_GEN_CNTL;
53741456df2SDave Airlie
53841456df2SDave Airlie gen_cntl_val = RREG32(gen_cntl_reg);
53941456df2SDave Airlie gen_cntl_val &= ~(0xf << 8);
54041456df2SDave Airlie gen_cntl_val |= (format << 8);
541c640e8caSDave Airlie gen_cntl_val &= ~RADEON_CRTC_VSTAT_MODE_MASK;
54241456df2SDave Airlie WREG32(gen_cntl_reg, gen_cntl_val);
54341456df2SDave Airlie
544771fe6b9SJerome Glisse crtc_offset = (u32)base;
545771fe6b9SJerome Glisse
5464162338aSDave Airlie WREG32(RADEON_DISPLAY_BASE_ADDR + radeon_crtc->crtc_offset, radeon_crtc->legacy_display_base_addr);
547771fe6b9SJerome Glisse
548771fe6b9SJerome Glisse if (ASIC_IS_R300(rdev)) {
549771fe6b9SJerome Glisse if (radeon_crtc->crtc_id)
550771fe6b9SJerome Glisse WREG32(R300_CRTC2_TILE_X0_Y0, crtc_tile_x0_y0);
551771fe6b9SJerome Glisse else
552771fe6b9SJerome Glisse WREG32(R300_CRTC_TILE_X0_Y0, crtc_tile_x0_y0);
553771fe6b9SJerome Glisse }
554771fe6b9SJerome Glisse WREG32(RADEON_CRTC_OFFSET_CNTL + radeon_crtc->crtc_offset, crtc_offset_cntl);
555771fe6b9SJerome Glisse WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, crtc_offset);
556771fe6b9SJerome Glisse WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch);
557771fe6b9SJerome Glisse
558f4510a27SMatt Roper if (!atomic && fb && fb != crtc->primary->fb) {
559a110dfe3SDaniel Stone rbo = gem_to_radeon_bo(fb->obj[0]);
5604c788679SJerome Glisse r = radeon_bo_reserve(rbo, false);
5614c788679SJerome Glisse if (unlikely(r != 0))
5624c788679SJerome Glisse return r;
5634c788679SJerome Glisse radeon_bo_unpin(rbo);
5644c788679SJerome Glisse radeon_bo_unreserve(rbo);
565771fe6b9SJerome Glisse }
566f30f37deSMichel Dänzer
567f30f37deSMichel Dänzer /* Bytes per pixel may have changed */
568f30f37deSMichel Dänzer radeon_bandwidth_update(rdev);
569f30f37deSMichel Dänzer
570771fe6b9SJerome Glisse return 0;
571771fe6b9SJerome Glisse }
572771fe6b9SJerome Glisse
radeon_set_crtc_timing(struct drm_crtc * crtc,struct drm_display_mode * mode)573771fe6b9SJerome Glisse static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mode *mode)
574771fe6b9SJerome Glisse {
575771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev;
576771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private;
577771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
578489f3267SVille Syrjälä const struct drm_framebuffer *fb = crtc->primary->fb;
5794ce001abSDave Airlie struct drm_encoder *encoder;
580771fe6b9SJerome Glisse int format;
581771fe6b9SJerome Glisse int hsync_start;
582771fe6b9SJerome Glisse int hsync_wid;
583771fe6b9SJerome Glisse int vsync_wid;
584771fe6b9SJerome Glisse uint32_t crtc_h_total_disp;
585771fe6b9SJerome Glisse uint32_t crtc_h_sync_strt_wid;
586771fe6b9SJerome Glisse uint32_t crtc_v_total_disp;
587771fe6b9SJerome Glisse uint32_t crtc_v_sync_strt_wid;
5884ce001abSDave Airlie bool is_tv = false;
589771fe6b9SJerome Glisse
590d9fdaafbSDave Airlie DRM_DEBUG_KMS("\n");
5914ce001abSDave Airlie list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
5924ce001abSDave Airlie if (encoder->crtc == crtc) {
5934ce001abSDave Airlie struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
5944ce001abSDave Airlie if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) {
5954ce001abSDave Airlie is_tv = true;
5964ce001abSDave Airlie DRM_INFO("crtc %d is connected to a TV\n", radeon_crtc->crtc_id);
5974ce001abSDave Airlie break;
5984ce001abSDave Airlie }
5994ce001abSDave Airlie }
6004ce001abSDave Airlie }
601771fe6b9SJerome Glisse
602272725c7SVille Syrjälä switch (fb->format->cpp[0] * 8) {
60341456df2SDave Airlie case 8:
60441456df2SDave Airlie format = 2;
60541456df2SDave Airlie break;
606771fe6b9SJerome Glisse case 15: /* 555 */
607771fe6b9SJerome Glisse format = 3;
608771fe6b9SJerome Glisse break;
609771fe6b9SJerome Glisse case 16: /* 565 */
610771fe6b9SJerome Glisse format = 4;
611771fe6b9SJerome Glisse break;
612771fe6b9SJerome Glisse case 24: /* RGB */
613771fe6b9SJerome Glisse format = 5;
614771fe6b9SJerome Glisse break;
615771fe6b9SJerome Glisse case 32: /* xRGB */
616771fe6b9SJerome Glisse format = 6;
617771fe6b9SJerome Glisse break;
618771fe6b9SJerome Glisse default:
619771fe6b9SJerome Glisse return false;
620771fe6b9SJerome Glisse }
621771fe6b9SJerome Glisse
622771fe6b9SJerome Glisse crtc_h_total_disp = ((((mode->crtc_htotal / 8) - 1) & 0x3ff)
623771fe6b9SJerome Glisse | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16));
624771fe6b9SJerome Glisse
625771fe6b9SJerome Glisse hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8;
626771fe6b9SJerome Glisse if (!hsync_wid)
627771fe6b9SJerome Glisse hsync_wid = 1;
628771fe6b9SJerome Glisse hsync_start = mode->crtc_hsync_start - 8;
629771fe6b9SJerome Glisse
630771fe6b9SJerome Glisse crtc_h_sync_strt_wid = ((hsync_start & 0x1fff)
631771fe6b9SJerome Glisse | ((hsync_wid & 0x3f) << 16)
632771fe6b9SJerome Glisse | ((mode->flags & DRM_MODE_FLAG_NHSYNC)
633771fe6b9SJerome Glisse ? RADEON_CRTC_H_SYNC_POL
634771fe6b9SJerome Glisse : 0));
635771fe6b9SJerome Glisse
636771fe6b9SJerome Glisse /* This works for double scan mode. */
637771fe6b9SJerome Glisse crtc_v_total_disp = (((mode->crtc_vtotal - 1) & 0xffff)
638771fe6b9SJerome Glisse | ((mode->crtc_vdisplay - 1) << 16));
639771fe6b9SJerome Glisse
640771fe6b9SJerome Glisse vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start;
641771fe6b9SJerome Glisse if (!vsync_wid)
642771fe6b9SJerome Glisse vsync_wid = 1;
643771fe6b9SJerome Glisse
644771fe6b9SJerome Glisse crtc_v_sync_strt_wid = (((mode->crtc_vsync_start - 1) & 0xfff)
645771fe6b9SJerome Glisse | ((vsync_wid & 0x1f) << 16)
646771fe6b9SJerome Glisse | ((mode->flags & DRM_MODE_FLAG_NVSYNC)
647771fe6b9SJerome Glisse ? RADEON_CRTC_V_SYNC_POL
648771fe6b9SJerome Glisse : 0));
649771fe6b9SJerome Glisse
650771fe6b9SJerome Glisse if (radeon_crtc->crtc_id) {
651771fe6b9SJerome Glisse uint32_t crtc2_gen_cntl;
652771fe6b9SJerome Glisse uint32_t disp2_merge_cntl;
653771fe6b9SJerome Glisse
654ee2215f0SJerome Glisse /* if TV DAC is enabled for another crtc and keep it enabled */
655ee2215f0SJerome Glisse crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL) & 0x00718080;
656771fe6b9SJerome Glisse crtc2_gen_cntl |= ((format << 8)
657771fe6b9SJerome Glisse | RADEON_CRTC2_VSYNC_DIS
658771fe6b9SJerome Glisse | RADEON_CRTC2_HSYNC_DIS
659771fe6b9SJerome Glisse | RADEON_CRTC2_DISP_DIS
660771fe6b9SJerome Glisse | RADEON_CRTC2_DISP_REQ_EN_B
661771fe6b9SJerome Glisse | ((mode->flags & DRM_MODE_FLAG_DBLSCAN)
662771fe6b9SJerome Glisse ? RADEON_CRTC2_DBL_SCAN_EN
663771fe6b9SJerome Glisse : 0)
664771fe6b9SJerome Glisse | ((mode->flags & DRM_MODE_FLAG_CSYNC)
665771fe6b9SJerome Glisse ? RADEON_CRTC2_CSYNC_EN
666771fe6b9SJerome Glisse : 0)
667771fe6b9SJerome Glisse | ((mode->flags & DRM_MODE_FLAG_INTERLACE)
668771fe6b9SJerome Glisse ? RADEON_CRTC2_INTERLACE_EN
669771fe6b9SJerome Glisse : 0));
670771fe6b9SJerome Glisse
671d805f50aSAlex Deucher /* rs4xx chips seem to like to have the crtc enabled when the timing is set */
672d805f50aSAlex Deucher if ((rdev->family == CHIP_RS400) || (rdev->family == CHIP_RS480))
673d805f50aSAlex Deucher crtc2_gen_cntl |= RADEON_CRTC2_EN;
674d805f50aSAlex Deucher
675771fe6b9SJerome Glisse disp2_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL);
676771fe6b9SJerome Glisse disp2_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN;
677771fe6b9SJerome Glisse
678771fe6b9SJerome Glisse WREG32(RADEON_DISP2_MERGE_CNTL, disp2_merge_cntl);
679771fe6b9SJerome Glisse WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
6801b4d7d75SAlex Deucher
6811b4d7d75SAlex Deucher WREG32(RADEON_FP_H2_SYNC_STRT_WID, crtc_h_sync_strt_wid);
6821b4d7d75SAlex Deucher WREG32(RADEON_FP_V2_SYNC_STRT_WID, crtc_v_sync_strt_wid);
683771fe6b9SJerome Glisse } else {
684771fe6b9SJerome Glisse uint32_t crtc_gen_cntl;
685771fe6b9SJerome Glisse uint32_t crtc_ext_cntl;
686771fe6b9SJerome Glisse uint32_t disp_merge_cntl;
687771fe6b9SJerome Glisse
688ee2215f0SJerome Glisse crtc_gen_cntl = RREG32(RADEON_CRTC_GEN_CNTL) & 0x00718000;
689ee2215f0SJerome Glisse crtc_gen_cntl |= (RADEON_CRTC_EXT_DISP_EN
690771fe6b9SJerome Glisse | (format << 8)
691771fe6b9SJerome Glisse | RADEON_CRTC_DISP_REQ_EN_B
692771fe6b9SJerome Glisse | ((mode->flags & DRM_MODE_FLAG_DBLSCAN)
693771fe6b9SJerome Glisse ? RADEON_CRTC_DBL_SCAN_EN
694771fe6b9SJerome Glisse : 0)
695771fe6b9SJerome Glisse | ((mode->flags & DRM_MODE_FLAG_CSYNC)
696771fe6b9SJerome Glisse ? RADEON_CRTC_CSYNC_EN
697771fe6b9SJerome Glisse : 0)
698771fe6b9SJerome Glisse | ((mode->flags & DRM_MODE_FLAG_INTERLACE)
699771fe6b9SJerome Glisse ? RADEON_CRTC_INTERLACE_EN
700771fe6b9SJerome Glisse : 0));
701771fe6b9SJerome Glisse
702d805f50aSAlex Deucher /* rs4xx chips seem to like to have the crtc enabled when the timing is set */
703d805f50aSAlex Deucher if ((rdev->family == CHIP_RS400) || (rdev->family == CHIP_RS480))
704d805f50aSAlex Deucher crtc_gen_cntl |= RADEON_CRTC_EN;
705d805f50aSAlex Deucher
706771fe6b9SJerome Glisse crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL);
707771fe6b9SJerome Glisse crtc_ext_cntl |= (RADEON_XCRT_CNT_EN |
708771fe6b9SJerome Glisse RADEON_CRTC_VSYNC_DIS |
709771fe6b9SJerome Glisse RADEON_CRTC_HSYNC_DIS |
710771fe6b9SJerome Glisse RADEON_CRTC_DISPLAY_DIS);
711771fe6b9SJerome Glisse
712771fe6b9SJerome Glisse disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL);
713771fe6b9SJerome Glisse disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN;
714771fe6b9SJerome Glisse
715771fe6b9SJerome Glisse WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl);
716771fe6b9SJerome Glisse WREG32(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl);
717771fe6b9SJerome Glisse WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl);
718771fe6b9SJerome Glisse }
719771fe6b9SJerome Glisse
7204ce001abSDave Airlie if (is_tv)
7214ce001abSDave Airlie radeon_legacy_tv_adjust_crtc_reg(encoder, &crtc_h_total_disp,
7224ce001abSDave Airlie &crtc_h_sync_strt_wid, &crtc_v_total_disp,
7234ce001abSDave Airlie &crtc_v_sync_strt_wid);
7244ce001abSDave Airlie
725771fe6b9SJerome Glisse WREG32(RADEON_CRTC_H_TOTAL_DISP + radeon_crtc->crtc_offset, crtc_h_total_disp);
726771fe6b9SJerome Glisse WREG32(RADEON_CRTC_H_SYNC_STRT_WID + radeon_crtc->crtc_offset, crtc_h_sync_strt_wid);
727771fe6b9SJerome Glisse WREG32(RADEON_CRTC_V_TOTAL_DISP + radeon_crtc->crtc_offset, crtc_v_total_disp);
728771fe6b9SJerome Glisse WREG32(RADEON_CRTC_V_SYNC_STRT_WID + radeon_crtc->crtc_offset, crtc_v_sync_strt_wid);
729771fe6b9SJerome Glisse
730771fe6b9SJerome Glisse return true;
731771fe6b9SJerome Glisse }
732771fe6b9SJerome Glisse
radeon_set_pll(struct drm_crtc * crtc,struct drm_display_mode * mode)733771fe6b9SJerome Glisse static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
734771fe6b9SJerome Glisse {
735771fe6b9SJerome Glisse struct drm_device *dev = crtc->dev;
736771fe6b9SJerome Glisse struct radeon_device *rdev = dev->dev_private;
737771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
738771fe6b9SJerome Glisse struct drm_encoder *encoder;
739771fe6b9SJerome Glisse uint32_t feedback_div = 0;
740771fe6b9SJerome Glisse uint32_t frac_fb_div = 0;
741771fe6b9SJerome Glisse uint32_t reference_div = 0;
742771fe6b9SJerome Glisse uint32_t post_divider = 0;
743771fe6b9SJerome Glisse uint32_t freq = 0;
744771fe6b9SJerome Glisse uint8_t pll_gain;
745771fe6b9SJerome Glisse bool use_bios_divs = false;
746771fe6b9SJerome Glisse /* PLL registers */
747771fe6b9SJerome Glisse uint32_t pll_ref_div = 0;
748771fe6b9SJerome Glisse uint32_t pll_fb_post_div = 0;
749771fe6b9SJerome Glisse uint32_t htotal_cntl = 0;
7504ce001abSDave Airlie bool is_tv = false;
751771fe6b9SJerome Glisse struct radeon_pll *pll;
752771fe6b9SJerome Glisse
753771fe6b9SJerome Glisse struct {
754771fe6b9SJerome Glisse int divider;
755771fe6b9SJerome Glisse int bitvalue;
756771fe6b9SJerome Glisse } *post_div, post_divs[] = {
757771fe6b9SJerome Glisse /* From RAGE 128 VR/RAGE 128 GL Register
758771fe6b9SJerome Glisse * Reference Manual (Technical Reference
759771fe6b9SJerome Glisse * Manual P/N RRG-G04100-C Rev. 0.04), page
760771fe6b9SJerome Glisse * 3-17 (PLL_DIV_[3:0]).
761771fe6b9SJerome Glisse */
762771fe6b9SJerome Glisse { 1, 0 }, /* VCLK_SRC */
763771fe6b9SJerome Glisse { 2, 1 }, /* VCLK_SRC/2 */
764771fe6b9SJerome Glisse { 4, 2 }, /* VCLK_SRC/4 */
765771fe6b9SJerome Glisse { 8, 3 }, /* VCLK_SRC/8 */
766771fe6b9SJerome Glisse { 3, 4 }, /* VCLK_SRC/3 */
767771fe6b9SJerome Glisse { 16, 5 }, /* VCLK_SRC/16 */
768771fe6b9SJerome Glisse { 6, 6 }, /* VCLK_SRC/6 */
769771fe6b9SJerome Glisse { 12, 7 }, /* VCLK_SRC/12 */
770771fe6b9SJerome Glisse { 0, 0 }
771771fe6b9SJerome Glisse };
772771fe6b9SJerome Glisse
773771fe6b9SJerome Glisse if (radeon_crtc->crtc_id)
774771fe6b9SJerome Glisse pll = &rdev->clock.p2pll;
775771fe6b9SJerome Glisse else
776771fe6b9SJerome Glisse pll = &rdev->clock.p1pll;
777771fe6b9SJerome Glisse
778fc10332bSAlex Deucher pll->flags = RADEON_PLL_LEGACY;
779771fe6b9SJerome Glisse
7805480f727SDave Airlie if (mode->clock > 200000) /* range limits??? */
7815480f727SDave Airlie pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
7825480f727SDave Airlie else
7835480f727SDave Airlie pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
7845480f727SDave Airlie
785771fe6b9SJerome Glisse list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
786771fe6b9SJerome Glisse if (encoder->crtc == crtc) {
7874ce001abSDave Airlie struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
7884ce001abSDave Airlie
7894ce001abSDave Airlie if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) {
7904ce001abSDave Airlie is_tv = true;
7914ce001abSDave Airlie break;
7924ce001abSDave Airlie }
7934ce001abSDave Airlie
794771fe6b9SJerome Glisse if (encoder->encoder_type != DRM_MODE_ENCODER_DAC)
795fc10332bSAlex Deucher pll->flags |= RADEON_PLL_NO_ODD_POST_DIV;
796771fe6b9SJerome Glisse if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) {
7974c4f5413SAlex Deucher if (!rdev->is_atom_bios) {
798771fe6b9SJerome Glisse struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
799771fe6b9SJerome Glisse struct radeon_encoder_lvds *lvds = (struct radeon_encoder_lvds *)radeon_encoder->enc_priv;
800771fe6b9SJerome Glisse if (lvds) {
801771fe6b9SJerome Glisse if (lvds->use_bios_dividers) {
802771fe6b9SJerome Glisse pll_ref_div = lvds->panel_ref_divider;
803771fe6b9SJerome Glisse pll_fb_post_div = (lvds->panel_fb_divider |
804771fe6b9SJerome Glisse (lvds->panel_post_divider << 16));
805771fe6b9SJerome Glisse htotal_cntl = 0;
806771fe6b9SJerome Glisse use_bios_divs = true;
807771fe6b9SJerome Glisse }
808771fe6b9SJerome Glisse }
809771fe6b9SJerome Glisse }
810fc10332bSAlex Deucher pll->flags |= RADEON_PLL_USE_REF_DIV;
811771fe6b9SJerome Glisse }
812771fe6b9SJerome Glisse }
8134c4f5413SAlex Deucher }
814771fe6b9SJerome Glisse
815d9fdaafbSDave Airlie DRM_DEBUG_KMS("\n");
816771fe6b9SJerome Glisse
817771fe6b9SJerome Glisse if (!use_bios_divs) {
818f523f74eSAlex Deucher radeon_compute_pll_legacy(pll, mode->clock,
819771fe6b9SJerome Glisse &freq, &feedback_div, &frac_fb_div,
820fc10332bSAlex Deucher &reference_div, &post_divider);
821771fe6b9SJerome Glisse
822771fe6b9SJerome Glisse for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
823771fe6b9SJerome Glisse if (post_div->divider == post_divider)
824771fe6b9SJerome Glisse break;
825771fe6b9SJerome Glisse }
826771fe6b9SJerome Glisse
827771fe6b9SJerome Glisse if (!post_div->divider)
828771fe6b9SJerome Glisse post_div = &post_divs[0];
829771fe6b9SJerome Glisse
830d9fdaafbSDave Airlie DRM_DEBUG_KMS("dc=%u, fd=%d, rd=%d, pd=%d\n",
831771fe6b9SJerome Glisse (unsigned)freq,
832771fe6b9SJerome Glisse feedback_div,
833771fe6b9SJerome Glisse reference_div,
834771fe6b9SJerome Glisse post_divider);
835771fe6b9SJerome Glisse
836771fe6b9SJerome Glisse pll_ref_div = reference_div;
837771fe6b9SJerome Glisse #if defined(__powerpc__) && (0) /* TODO */
838771fe6b9SJerome Glisse /* apparently programming this otherwise causes a hang??? */
839771fe6b9SJerome Glisse if (info->MacModel == RADEON_MAC_IBOOK)
840771fe6b9SJerome Glisse pll_fb_post_div = 0x000600ad;
841771fe6b9SJerome Glisse else
842771fe6b9SJerome Glisse #endif
843771fe6b9SJerome Glisse pll_fb_post_div = (feedback_div | (post_div->bitvalue << 16));
844771fe6b9SJerome Glisse
845771fe6b9SJerome Glisse htotal_cntl = mode->htotal & 0x7;
846771fe6b9SJerome Glisse
847771fe6b9SJerome Glisse }
848771fe6b9SJerome Glisse
849771fe6b9SJerome Glisse pll_gain = radeon_compute_pll_gain(pll->reference_freq,
850771fe6b9SJerome Glisse pll_ref_div & 0x3ff,
851771fe6b9SJerome Glisse pll_fb_post_div & 0x7ff);
852771fe6b9SJerome Glisse
853771fe6b9SJerome Glisse if (radeon_crtc->crtc_id) {
854771fe6b9SJerome Glisse uint32_t pixclks_cntl = ((RREG32_PLL(RADEON_PIXCLKS_CNTL) &
855771fe6b9SJerome Glisse ~(RADEON_PIX2CLK_SRC_SEL_MASK)) |
856771fe6b9SJerome Glisse RADEON_PIX2CLK_SRC_SEL_P2PLLCLK);
857771fe6b9SJerome Glisse
8584ce001abSDave Airlie if (is_tv) {
8594ce001abSDave Airlie radeon_legacy_tv_adjust_pll2(encoder, &htotal_cntl,
8604ce001abSDave Airlie &pll_ref_div, &pll_fb_post_div,
8614ce001abSDave Airlie &pixclks_cntl);
8624ce001abSDave Airlie }
8634ce001abSDave Airlie
864771fe6b9SJerome Glisse WREG32_PLL_P(RADEON_PIXCLKS_CNTL,
865771fe6b9SJerome Glisse RADEON_PIX2CLK_SRC_SEL_CPUCLK,
866771fe6b9SJerome Glisse ~(RADEON_PIX2CLK_SRC_SEL_MASK));
867771fe6b9SJerome Glisse
868771fe6b9SJerome Glisse WREG32_PLL_P(RADEON_P2PLL_CNTL,
869771fe6b9SJerome Glisse RADEON_P2PLL_RESET
870771fe6b9SJerome Glisse | RADEON_P2PLL_ATOMIC_UPDATE_EN
871771fe6b9SJerome Glisse | ((uint32_t)pll_gain << RADEON_P2PLL_PVG_SHIFT),
872771fe6b9SJerome Glisse ~(RADEON_P2PLL_RESET
873771fe6b9SJerome Glisse | RADEON_P2PLL_ATOMIC_UPDATE_EN
874771fe6b9SJerome Glisse | RADEON_P2PLL_PVG_MASK));
875771fe6b9SJerome Glisse
876771fe6b9SJerome Glisse WREG32_PLL_P(RADEON_P2PLL_REF_DIV,
877771fe6b9SJerome Glisse pll_ref_div,
878771fe6b9SJerome Glisse ~RADEON_P2PLL_REF_DIV_MASK);
879771fe6b9SJerome Glisse
880771fe6b9SJerome Glisse WREG32_PLL_P(RADEON_P2PLL_DIV_0,
881771fe6b9SJerome Glisse pll_fb_post_div,
882771fe6b9SJerome Glisse ~RADEON_P2PLL_FB0_DIV_MASK);
883771fe6b9SJerome Glisse
884771fe6b9SJerome Glisse WREG32_PLL_P(RADEON_P2PLL_DIV_0,
885771fe6b9SJerome Glisse pll_fb_post_div,
886771fe6b9SJerome Glisse ~RADEON_P2PLL_POST0_DIV_MASK);
887771fe6b9SJerome Glisse
888771fe6b9SJerome Glisse radeon_pll2_write_update(dev);
889771fe6b9SJerome Glisse radeon_pll2_wait_for_read_update_complete(dev);
890771fe6b9SJerome Glisse
891771fe6b9SJerome Glisse WREG32_PLL(RADEON_HTOTAL2_CNTL, htotal_cntl);
892771fe6b9SJerome Glisse
893771fe6b9SJerome Glisse WREG32_PLL_P(RADEON_P2PLL_CNTL,
894771fe6b9SJerome Glisse 0,
895771fe6b9SJerome Glisse ~(RADEON_P2PLL_RESET
896771fe6b9SJerome Glisse | RADEON_P2PLL_SLEEP
897771fe6b9SJerome Glisse | RADEON_P2PLL_ATOMIC_UPDATE_EN));
898771fe6b9SJerome Glisse
899d9fdaafbSDave Airlie DRM_DEBUG_KMS("Wrote2: 0x%08x 0x%08x 0x%08x (0x%08x)\n",
900771fe6b9SJerome Glisse (unsigned)pll_ref_div,
901771fe6b9SJerome Glisse (unsigned)pll_fb_post_div,
902771fe6b9SJerome Glisse (unsigned)htotal_cntl,
903771fe6b9SJerome Glisse RREG32_PLL(RADEON_P2PLL_CNTL));
904d9fdaafbSDave Airlie DRM_DEBUG_KMS("Wrote2: rd=%u, fd=%u, pd=%u\n",
905771fe6b9SJerome Glisse (unsigned)pll_ref_div & RADEON_P2PLL_REF_DIV_MASK,
906771fe6b9SJerome Glisse (unsigned)pll_fb_post_div & RADEON_P2PLL_FB0_DIV_MASK,
907771fe6b9SJerome Glisse (unsigned)((pll_fb_post_div &
908771fe6b9SJerome Glisse RADEON_P2PLL_POST0_DIV_MASK) >> 16));
909771fe6b9SJerome Glisse
910771fe6b9SJerome Glisse mdelay(50); /* Let the clock to lock */
911771fe6b9SJerome Glisse
912771fe6b9SJerome Glisse WREG32_PLL_P(RADEON_PIXCLKS_CNTL,
913771fe6b9SJerome Glisse RADEON_PIX2CLK_SRC_SEL_P2PLLCLK,
914771fe6b9SJerome Glisse ~(RADEON_PIX2CLK_SRC_SEL_MASK));
915771fe6b9SJerome Glisse
916771fe6b9SJerome Glisse WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl);
917771fe6b9SJerome Glisse } else {
9184ce001abSDave Airlie uint32_t pixclks_cntl;
9194ce001abSDave Airlie
9204ce001abSDave Airlie
9214ce001abSDave Airlie if (is_tv) {
9224ce001abSDave Airlie pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL);
9234ce001abSDave Airlie radeon_legacy_tv_adjust_pll1(encoder, &htotal_cntl, &pll_ref_div,
9244ce001abSDave Airlie &pll_fb_post_div, &pixclks_cntl);
9254ce001abSDave Airlie }
9264ce001abSDave Airlie
927771fe6b9SJerome Glisse if (rdev->flags & RADEON_IS_MOBILITY) {
92883e61f71SJustin P. Mattock /* A temporal workaround for the occasional blanking on certain laptop panels.
929771fe6b9SJerome Glisse This appears to related to the PLL divider registers (fail to lock?).
930771fe6b9SJerome Glisse It occurs even when all dividers are the same with their old settings.
931771fe6b9SJerome Glisse In this case we really don't need to fiddle with PLL registers.
932771fe6b9SJerome Glisse By doing this we can avoid the blanking problem with some panels.
933771fe6b9SJerome Glisse */
934771fe6b9SJerome Glisse if ((pll_ref_div == (RREG32_PLL(RADEON_PPLL_REF_DIV) & RADEON_PPLL_REF_DIV_MASK)) &&
935771fe6b9SJerome Glisse (pll_fb_post_div == (RREG32_PLL(RADEON_PPLL_DIV_3) &
936771fe6b9SJerome Glisse (RADEON_PPLL_POST3_DIV_MASK | RADEON_PPLL_FB3_DIV_MASK)))) {
937771fe6b9SJerome Glisse WREG32_P(RADEON_CLOCK_CNTL_INDEX,
938771fe6b9SJerome Glisse RADEON_PLL_DIV_SEL,
939771fe6b9SJerome Glisse ~(RADEON_PLL_DIV_SEL));
940771fe6b9SJerome Glisse r100_pll_errata_after_index(rdev);
941771fe6b9SJerome Glisse return;
942771fe6b9SJerome Glisse }
943771fe6b9SJerome Glisse }
944771fe6b9SJerome Glisse
945771fe6b9SJerome Glisse WREG32_PLL_P(RADEON_VCLK_ECP_CNTL,
946771fe6b9SJerome Glisse RADEON_VCLK_SRC_SEL_CPUCLK,
947771fe6b9SJerome Glisse ~(RADEON_VCLK_SRC_SEL_MASK));
948771fe6b9SJerome Glisse WREG32_PLL_P(RADEON_PPLL_CNTL,
949771fe6b9SJerome Glisse RADEON_PPLL_RESET
950771fe6b9SJerome Glisse | RADEON_PPLL_ATOMIC_UPDATE_EN
951771fe6b9SJerome Glisse | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN
952771fe6b9SJerome Glisse | ((uint32_t)pll_gain << RADEON_PPLL_PVG_SHIFT),
953771fe6b9SJerome Glisse ~(RADEON_PPLL_RESET
954771fe6b9SJerome Glisse | RADEON_PPLL_ATOMIC_UPDATE_EN
955771fe6b9SJerome Glisse | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN
956771fe6b9SJerome Glisse | RADEON_PPLL_PVG_MASK));
957771fe6b9SJerome Glisse
958771fe6b9SJerome Glisse WREG32_P(RADEON_CLOCK_CNTL_INDEX,
959771fe6b9SJerome Glisse RADEON_PLL_DIV_SEL,
960771fe6b9SJerome Glisse ~(RADEON_PLL_DIV_SEL));
961771fe6b9SJerome Glisse r100_pll_errata_after_index(rdev);
962771fe6b9SJerome Glisse
963771fe6b9SJerome Glisse if (ASIC_IS_R300(rdev) ||
964771fe6b9SJerome Glisse (rdev->family == CHIP_RS300) ||
965771fe6b9SJerome Glisse (rdev->family == CHIP_RS400) ||
966771fe6b9SJerome Glisse (rdev->family == CHIP_RS480)) {
967771fe6b9SJerome Glisse if (pll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) {
968771fe6b9SJerome Glisse /* When restoring console mode, use saved PPLL_REF_DIV
969771fe6b9SJerome Glisse * setting.
970771fe6b9SJerome Glisse */
971771fe6b9SJerome Glisse WREG32_PLL_P(RADEON_PPLL_REF_DIV,
972771fe6b9SJerome Glisse pll_ref_div,
973771fe6b9SJerome Glisse 0);
974771fe6b9SJerome Glisse } else {
975771fe6b9SJerome Glisse /* R300 uses ref_div_acc field as real ref divider */
976771fe6b9SJerome Glisse WREG32_PLL_P(RADEON_PPLL_REF_DIV,
977771fe6b9SJerome Glisse (pll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT),
978771fe6b9SJerome Glisse ~R300_PPLL_REF_DIV_ACC_MASK);
979771fe6b9SJerome Glisse }
980771fe6b9SJerome Glisse } else
981771fe6b9SJerome Glisse WREG32_PLL_P(RADEON_PPLL_REF_DIV,
982771fe6b9SJerome Glisse pll_ref_div,
983771fe6b9SJerome Glisse ~RADEON_PPLL_REF_DIV_MASK);
984771fe6b9SJerome Glisse
985771fe6b9SJerome Glisse WREG32_PLL_P(RADEON_PPLL_DIV_3,
986771fe6b9SJerome Glisse pll_fb_post_div,
987771fe6b9SJerome Glisse ~RADEON_PPLL_FB3_DIV_MASK);
988771fe6b9SJerome Glisse
989771fe6b9SJerome Glisse WREG32_PLL_P(RADEON_PPLL_DIV_3,
990771fe6b9SJerome Glisse pll_fb_post_div,
991771fe6b9SJerome Glisse ~RADEON_PPLL_POST3_DIV_MASK);
992771fe6b9SJerome Glisse
993771fe6b9SJerome Glisse radeon_pll_write_update(dev);
994771fe6b9SJerome Glisse radeon_pll_wait_for_read_update_complete(dev);
995771fe6b9SJerome Glisse
996771fe6b9SJerome Glisse WREG32_PLL(RADEON_HTOTAL_CNTL, htotal_cntl);
997771fe6b9SJerome Glisse
998771fe6b9SJerome Glisse WREG32_PLL_P(RADEON_PPLL_CNTL,
999771fe6b9SJerome Glisse 0,
1000771fe6b9SJerome Glisse ~(RADEON_PPLL_RESET
1001771fe6b9SJerome Glisse | RADEON_PPLL_SLEEP
1002771fe6b9SJerome Glisse | RADEON_PPLL_ATOMIC_UPDATE_EN
1003771fe6b9SJerome Glisse | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN));
1004771fe6b9SJerome Glisse
1005d9fdaafbSDave Airlie DRM_DEBUG_KMS("Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n",
1006771fe6b9SJerome Glisse pll_ref_div,
1007771fe6b9SJerome Glisse pll_fb_post_div,
1008771fe6b9SJerome Glisse (unsigned)htotal_cntl,
1009771fe6b9SJerome Glisse RREG32_PLL(RADEON_PPLL_CNTL));
1010d9fdaafbSDave Airlie DRM_DEBUG_KMS("Wrote: rd=%d, fd=%d, pd=%d\n",
1011771fe6b9SJerome Glisse pll_ref_div & RADEON_PPLL_REF_DIV_MASK,
1012771fe6b9SJerome Glisse pll_fb_post_div & RADEON_PPLL_FB3_DIV_MASK,
1013771fe6b9SJerome Glisse (pll_fb_post_div & RADEON_PPLL_POST3_DIV_MASK) >> 16);
1014771fe6b9SJerome Glisse
1015771fe6b9SJerome Glisse mdelay(50); /* Let the clock to lock */
1016771fe6b9SJerome Glisse
1017771fe6b9SJerome Glisse WREG32_PLL_P(RADEON_VCLK_ECP_CNTL,
1018771fe6b9SJerome Glisse RADEON_VCLK_SRC_SEL_PPLLCLK,
1019771fe6b9SJerome Glisse ~(RADEON_VCLK_SRC_SEL_MASK));
1020771fe6b9SJerome Glisse
10214ce001abSDave Airlie if (is_tv)
10224ce001abSDave Airlie WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl);
1023771fe6b9SJerome Glisse }
1024771fe6b9SJerome Glisse }
1025771fe6b9SJerome Glisse
radeon_crtc_mode_fixup(struct drm_crtc * crtc,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)1026771fe6b9SJerome Glisse static bool radeon_crtc_mode_fixup(struct drm_crtc *crtc,
1027e811f5aeSLaurent Pinchart const struct drm_display_mode *mode,
1028771fe6b9SJerome Glisse struct drm_display_mode *adjusted_mode)
1029771fe6b9SJerome Glisse {
1030c93bb85bSJerome Glisse if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode))
1031c93bb85bSJerome Glisse return false;
1032771fe6b9SJerome Glisse return true;
1033771fe6b9SJerome Glisse }
1034771fe6b9SJerome Glisse
radeon_crtc_mode_set(struct drm_crtc * crtc,struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode,int x,int y,struct drm_framebuffer * old_fb)1035771fe6b9SJerome Glisse static int radeon_crtc_mode_set(struct drm_crtc *crtc,
1036771fe6b9SJerome Glisse struct drm_display_mode *mode,
1037771fe6b9SJerome Glisse struct drm_display_mode *adjusted_mode,
1038771fe6b9SJerome Glisse int x, int y, struct drm_framebuffer *old_fb)
1039771fe6b9SJerome Glisse {
1040c93bb85bSJerome Glisse struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1041771fe6b9SJerome Glisse
1042771fe6b9SJerome Glisse /* TODO TV */
1043771fe6b9SJerome Glisse radeon_crtc_set_base(crtc, x, y, old_fb);
1044771fe6b9SJerome Glisse radeon_set_crtc_timing(crtc, adjusted_mode);
1045771fe6b9SJerome Glisse radeon_set_pll(crtc, adjusted_mode);
10466b02af1cSAlex Deucher radeon_overscan_setup(crtc, adjusted_mode);
1047c93bb85bSJerome Glisse if (radeon_crtc->crtc_id == 0) {
1048310a82c8SAlex Deucher radeon_legacy_rmx_mode_set(crtc, adjusted_mode);
1049c93bb85bSJerome Glisse } else {
1050c93bb85bSJerome Glisse if (radeon_crtc->rmx_type != RMX_OFF) {
1051c93bb85bSJerome Glisse /* FIXME: only first crtc has rmx what should we
1052c93bb85bSJerome Glisse * do ?
1053c93bb85bSJerome Glisse */
1054c93bb85bSJerome Glisse DRM_ERROR("Mode need scaling but only first crtc can do that.\n");
1055c93bb85bSJerome Glisse }
1056c93bb85bSJerome Glisse }
10576d3759faSMichel Dänzer radeon_cursor_reset(crtc);
1058771fe6b9SJerome Glisse return 0;
1059771fe6b9SJerome Glisse }
1060771fe6b9SJerome Glisse
radeon_crtc_prepare(struct drm_crtc * crtc)1061771fe6b9SJerome Glisse static void radeon_crtc_prepare(struct drm_crtc *crtc)
1062771fe6b9SJerome Glisse {
1063ec51efa9SPierre Ossman struct drm_device *dev = crtc->dev;
1064ec51efa9SPierre Ossman struct drm_crtc *crtci;
1065ec51efa9SPierre Ossman
1066ec51efa9SPierre Ossman /*
1067ec51efa9SPierre Ossman * The hardware wedges sometimes if you reconfigure one CRTC
1068ec51efa9SPierre Ossman * whilst another is running (see fdo bug #24611).
1069ec51efa9SPierre Ossman */
1070ec51efa9SPierre Ossman list_for_each_entry(crtci, &dev->mode_config.crtc_list, head)
1071ec51efa9SPierre Ossman radeon_crtc_dpms(crtci, DRM_MODE_DPMS_OFF);
1072771fe6b9SJerome Glisse }
1073771fe6b9SJerome Glisse
radeon_crtc_commit(struct drm_crtc * crtc)1074771fe6b9SJerome Glisse static void radeon_crtc_commit(struct drm_crtc *crtc)
1075771fe6b9SJerome Glisse {
1076ec51efa9SPierre Ossman struct drm_device *dev = crtc->dev;
1077ec51efa9SPierre Ossman struct drm_crtc *crtci;
1078ec51efa9SPierre Ossman
1079ec51efa9SPierre Ossman /*
1080ec51efa9SPierre Ossman * Reenable the CRTCs that should be running.
1081ec51efa9SPierre Ossman */
1082ec51efa9SPierre Ossman list_for_each_entry(crtci, &dev->mode_config.crtc_list, head) {
1083ec51efa9SPierre Ossman if (crtci->enabled)
1084ec51efa9SPierre Ossman radeon_crtc_dpms(crtci, DRM_MODE_DPMS_ON);
1085ec51efa9SPierre Ossman }
1086771fe6b9SJerome Glisse }
1087771fe6b9SJerome Glisse
radeon_crtc_disable(struct drm_crtc * crtc)1088520a8718SIlija Hadzic static void radeon_crtc_disable(struct drm_crtc *crtc)
1089520a8718SIlija Hadzic {
1090520a8718SIlija Hadzic radeon_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
1091f4510a27SMatt Roper if (crtc->primary->fb) {
1092520a8718SIlija Hadzic int r;
1093520a8718SIlija Hadzic struct radeon_bo *rbo;
1094520a8718SIlija Hadzic
1095a110dfe3SDaniel Stone rbo = gem_to_radeon_bo(crtc->primary->fb->obj[0]);
1096520a8718SIlija Hadzic r = radeon_bo_reserve(rbo, false);
1097520a8718SIlija Hadzic if (unlikely(r))
1098520a8718SIlija Hadzic DRM_ERROR("failed to reserve rbo before unpin\n");
1099520a8718SIlija Hadzic else {
1100520a8718SIlija Hadzic radeon_bo_unpin(rbo);
1101520a8718SIlija Hadzic radeon_bo_unreserve(rbo);
1102520a8718SIlija Hadzic }
1103520a8718SIlija Hadzic }
1104520a8718SIlija Hadzic }
1105520a8718SIlija Hadzic
1106771fe6b9SJerome Glisse static const struct drm_crtc_helper_funcs legacy_helper_funcs = {
1107771fe6b9SJerome Glisse .dpms = radeon_crtc_dpms,
1108771fe6b9SJerome Glisse .mode_fixup = radeon_crtc_mode_fixup,
1109771fe6b9SJerome Glisse .mode_set = radeon_crtc_mode_set,
1110771fe6b9SJerome Glisse .mode_set_base = radeon_crtc_set_base,
11114dd19b0dSChris Ball .mode_set_base_atomic = radeon_crtc_set_base_atomic,
1112771fe6b9SJerome Glisse .prepare = radeon_crtc_prepare,
1113771fe6b9SJerome Glisse .commit = radeon_crtc_commit,
111427b4118dSThomas Zimmermann .disable = radeon_crtc_disable,
111527b4118dSThomas Zimmermann .get_scanout_position = radeon_get_crtc_scanout_position,
1116771fe6b9SJerome Glisse };
1117771fe6b9SJerome Glisse
1118771fe6b9SJerome Glisse
radeon_legacy_init_crtc(struct drm_device * dev,struct radeon_crtc * radeon_crtc)1119771fe6b9SJerome Glisse void radeon_legacy_init_crtc(struct drm_device *dev,
1120771fe6b9SJerome Glisse struct radeon_crtc *radeon_crtc)
1121771fe6b9SJerome Glisse {
1122771fe6b9SJerome Glisse if (radeon_crtc->crtc_id == 1)
1123771fe6b9SJerome Glisse radeon_crtc->crtc_offset = RADEON_CRTC2_H_TOTAL_DISP - RADEON_CRTC_H_TOTAL_DISP;
1124771fe6b9SJerome Glisse drm_crtc_helper_add(&radeon_crtc->base, &legacy_helper_funcs);
1125771fe6b9SJerome Glisse }
1126