1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright 2007-8 Advanced Micro Devices, Inc.
3*4882a593Smuzhiyun * Copyright 2008 Red Hat Inc.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Permission is hereby granted, free of charge, to any person obtaining a
6*4882a593Smuzhiyun * copy of this software and associated documentation files (the "Software"),
7*4882a593Smuzhiyun * to deal in the Software without restriction, including without limitation
8*4882a593Smuzhiyun * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9*4882a593Smuzhiyun * and/or sell copies of the Software, and to permit persons to whom the
10*4882a593Smuzhiyun * Software is furnished to do so, subject to the following conditions:
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * The above copyright notice and this permission notice shall be included in
13*4882a593Smuzhiyun * all copies or substantial portions of the Software.
14*4882a593Smuzhiyun *
15*4882a593Smuzhiyun * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*4882a593Smuzhiyun * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*4882a593Smuzhiyun * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18*4882a593Smuzhiyun * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19*4882a593Smuzhiyun * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20*4882a593Smuzhiyun * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21*4882a593Smuzhiyun * OTHER DEALINGS IN THE SOFTWARE.
22*4882a593Smuzhiyun *
23*4882a593Smuzhiyun * Authors: Dave Airlie
24*4882a593Smuzhiyun * Alex Deucher
25*4882a593Smuzhiyun */
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #include <drm/drm_crtc_helper.h>
28*4882a593Smuzhiyun #include <drm/drm_fb_helper.h>
29*4882a593Smuzhiyun #include <drm/drm_fixed.h>
30*4882a593Smuzhiyun #include <drm/drm_fourcc.h>
31*4882a593Smuzhiyun #include <drm/drm_vblank.h>
32*4882a593Smuzhiyun #include <drm/radeon_drm.h>
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun #include "atom.h"
35*4882a593Smuzhiyun #include "radeon.h"
36*4882a593Smuzhiyun
radeon_overscan_setup(struct drm_crtc * crtc,struct drm_display_mode * mode)37*4882a593Smuzhiyun static void radeon_overscan_setup(struct drm_crtc *crtc,
38*4882a593Smuzhiyun struct drm_display_mode *mode)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun struct drm_device *dev = crtc->dev;
41*4882a593Smuzhiyun struct radeon_device *rdev = dev->dev_private;
42*4882a593Smuzhiyun struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun WREG32(RADEON_OVR_CLR + radeon_crtc->crtc_offset, 0);
45*4882a593Smuzhiyun WREG32(RADEON_OVR_WID_LEFT_RIGHT + radeon_crtc->crtc_offset, 0);
46*4882a593Smuzhiyun WREG32(RADEON_OVR_WID_TOP_BOTTOM + radeon_crtc->crtc_offset, 0);
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun
radeon_legacy_rmx_mode_set(struct drm_crtc * crtc,struct drm_display_mode * mode)49*4882a593Smuzhiyun static void radeon_legacy_rmx_mode_set(struct drm_crtc *crtc,
50*4882a593Smuzhiyun struct drm_display_mode *mode)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun struct drm_device *dev = crtc->dev;
53*4882a593Smuzhiyun struct radeon_device *rdev = dev->dev_private;
54*4882a593Smuzhiyun struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
55*4882a593Smuzhiyun int xres = mode->hdisplay;
56*4882a593Smuzhiyun int yres = mode->vdisplay;
57*4882a593Smuzhiyun bool hscale = true, vscale = true;
58*4882a593Smuzhiyun int hsync_wid;
59*4882a593Smuzhiyun int vsync_wid;
60*4882a593Smuzhiyun int hsync_start;
61*4882a593Smuzhiyun int blank_width;
62*4882a593Smuzhiyun u32 scale, inc, crtc_more_cntl;
63*4882a593Smuzhiyun u32 fp_horz_stretch, fp_vert_stretch, fp_horz_vert_active;
64*4882a593Smuzhiyun u32 fp_h_sync_strt_wid, fp_crtc_h_total_disp;
65*4882a593Smuzhiyun u32 fp_v_sync_strt_wid, fp_crtc_v_total_disp;
66*4882a593Smuzhiyun struct drm_display_mode *native_mode = &radeon_crtc->native_mode;
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun fp_vert_stretch = RREG32(RADEON_FP_VERT_STRETCH) &
69*4882a593Smuzhiyun (RADEON_VERT_STRETCH_RESERVED |
70*4882a593Smuzhiyun RADEON_VERT_AUTO_RATIO_INC);
71*4882a593Smuzhiyun fp_horz_stretch = RREG32(RADEON_FP_HORZ_STRETCH) &
72*4882a593Smuzhiyun (RADEON_HORZ_FP_LOOP_STRETCH |
73*4882a593Smuzhiyun RADEON_HORZ_AUTO_RATIO_INC);
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun crtc_more_cntl = 0;
76*4882a593Smuzhiyun if ((rdev->family == CHIP_RS100) ||
77*4882a593Smuzhiyun (rdev->family == CHIP_RS200)) {
78*4882a593Smuzhiyun /* This is to workaround the asic bug for RMX, some versions
79*4882a593Smuzhiyun of BIOS dosen't have this register initialized correctly. */
80*4882a593Smuzhiyun crtc_more_cntl |= RADEON_CRTC_H_CUTOFF_ACTIVE_EN;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun fp_crtc_h_total_disp = ((((mode->crtc_htotal / 8) - 1) & 0x3ff)
85*4882a593Smuzhiyun | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16));
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8;
88*4882a593Smuzhiyun if (!hsync_wid)
89*4882a593Smuzhiyun hsync_wid = 1;
90*4882a593Smuzhiyun hsync_start = mode->crtc_hsync_start - 8;
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun fp_h_sync_strt_wid = ((hsync_start & 0x1fff)
93*4882a593Smuzhiyun | ((hsync_wid & 0x3f) << 16)
94*4882a593Smuzhiyun | ((mode->flags & DRM_MODE_FLAG_NHSYNC)
95*4882a593Smuzhiyun ? RADEON_CRTC_H_SYNC_POL
96*4882a593Smuzhiyun : 0));
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun fp_crtc_v_total_disp = (((mode->crtc_vtotal - 1) & 0xffff)
99*4882a593Smuzhiyun | ((mode->crtc_vdisplay - 1) << 16));
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start;
102*4882a593Smuzhiyun if (!vsync_wid)
103*4882a593Smuzhiyun vsync_wid = 1;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun fp_v_sync_strt_wid = (((mode->crtc_vsync_start - 1) & 0xfff)
106*4882a593Smuzhiyun | ((vsync_wid & 0x1f) << 16)
107*4882a593Smuzhiyun | ((mode->flags & DRM_MODE_FLAG_NVSYNC)
108*4882a593Smuzhiyun ? RADEON_CRTC_V_SYNC_POL
109*4882a593Smuzhiyun : 0));
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun fp_horz_vert_active = 0;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun if (native_mode->hdisplay == 0 ||
114*4882a593Smuzhiyun native_mode->vdisplay == 0) {
115*4882a593Smuzhiyun hscale = false;
116*4882a593Smuzhiyun vscale = false;
117*4882a593Smuzhiyun } else {
118*4882a593Smuzhiyun if (xres > native_mode->hdisplay)
119*4882a593Smuzhiyun xres = native_mode->hdisplay;
120*4882a593Smuzhiyun if (yres > native_mode->vdisplay)
121*4882a593Smuzhiyun yres = native_mode->vdisplay;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun if (xres == native_mode->hdisplay)
124*4882a593Smuzhiyun hscale = false;
125*4882a593Smuzhiyun if (yres == native_mode->vdisplay)
126*4882a593Smuzhiyun vscale = false;
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun switch (radeon_crtc->rmx_type) {
130*4882a593Smuzhiyun case RMX_FULL:
131*4882a593Smuzhiyun case RMX_ASPECT:
132*4882a593Smuzhiyun if (!hscale)
133*4882a593Smuzhiyun fp_horz_stretch |= ((xres/8-1) << 16);
134*4882a593Smuzhiyun else {
135*4882a593Smuzhiyun inc = (fp_horz_stretch & RADEON_HORZ_AUTO_RATIO_INC) ? 1 : 0;
136*4882a593Smuzhiyun scale = ((xres + inc) * RADEON_HORZ_STRETCH_RATIO_MAX)
137*4882a593Smuzhiyun / native_mode->hdisplay + 1;
138*4882a593Smuzhiyun fp_horz_stretch |= (((scale) & RADEON_HORZ_STRETCH_RATIO_MASK) |
139*4882a593Smuzhiyun RADEON_HORZ_STRETCH_BLEND |
140*4882a593Smuzhiyun RADEON_HORZ_STRETCH_ENABLE |
141*4882a593Smuzhiyun ((native_mode->hdisplay/8-1) << 16));
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun if (!vscale)
145*4882a593Smuzhiyun fp_vert_stretch |= ((yres-1) << 12);
146*4882a593Smuzhiyun else {
147*4882a593Smuzhiyun inc = (fp_vert_stretch & RADEON_VERT_AUTO_RATIO_INC) ? 1 : 0;
148*4882a593Smuzhiyun scale = ((yres + inc) * RADEON_VERT_STRETCH_RATIO_MAX)
149*4882a593Smuzhiyun / native_mode->vdisplay + 1;
150*4882a593Smuzhiyun fp_vert_stretch |= (((scale) & RADEON_VERT_STRETCH_RATIO_MASK) |
151*4882a593Smuzhiyun RADEON_VERT_STRETCH_ENABLE |
152*4882a593Smuzhiyun RADEON_VERT_STRETCH_BLEND |
153*4882a593Smuzhiyun ((native_mode->vdisplay-1) << 12));
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun break;
156*4882a593Smuzhiyun case RMX_CENTER:
157*4882a593Smuzhiyun fp_horz_stretch |= ((xres/8-1) << 16);
158*4882a593Smuzhiyun fp_vert_stretch |= ((yres-1) << 12);
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun crtc_more_cntl |= (RADEON_CRTC_AUTO_HORZ_CENTER_EN |
161*4882a593Smuzhiyun RADEON_CRTC_AUTO_VERT_CENTER_EN);
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun blank_width = (mode->crtc_hblank_end - mode->crtc_hblank_start) / 8;
164*4882a593Smuzhiyun if (blank_width > 110)
165*4882a593Smuzhiyun blank_width = 110;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun fp_crtc_h_total_disp = (((blank_width) & 0x3ff)
168*4882a593Smuzhiyun | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16));
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8;
171*4882a593Smuzhiyun if (!hsync_wid)
172*4882a593Smuzhiyun hsync_wid = 1;
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun fp_h_sync_strt_wid = ((((mode->crtc_hsync_start - mode->crtc_hblank_start) / 8) & 0x1fff)
175*4882a593Smuzhiyun | ((hsync_wid & 0x3f) << 16)
176*4882a593Smuzhiyun | ((mode->flags & DRM_MODE_FLAG_NHSYNC)
177*4882a593Smuzhiyun ? RADEON_CRTC_H_SYNC_POL
178*4882a593Smuzhiyun : 0));
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun fp_crtc_v_total_disp = (((mode->crtc_vblank_end - mode->crtc_vblank_start) & 0xffff)
181*4882a593Smuzhiyun | ((mode->crtc_vdisplay - 1) << 16));
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start;
184*4882a593Smuzhiyun if (!vsync_wid)
185*4882a593Smuzhiyun vsync_wid = 1;
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun fp_v_sync_strt_wid = ((((mode->crtc_vsync_start - mode->crtc_vblank_start) & 0xfff)
188*4882a593Smuzhiyun | ((vsync_wid & 0x1f) << 16)
189*4882a593Smuzhiyun | ((mode->flags & DRM_MODE_FLAG_NVSYNC)
190*4882a593Smuzhiyun ? RADEON_CRTC_V_SYNC_POL
191*4882a593Smuzhiyun : 0)));
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun fp_horz_vert_active = (((native_mode->vdisplay) & 0xfff) |
194*4882a593Smuzhiyun (((native_mode->hdisplay / 8) & 0x1ff) << 16));
195*4882a593Smuzhiyun break;
196*4882a593Smuzhiyun case RMX_OFF:
197*4882a593Smuzhiyun default:
198*4882a593Smuzhiyun fp_horz_stretch |= ((xres/8-1) << 16);
199*4882a593Smuzhiyun fp_vert_stretch |= ((yres-1) << 12);
200*4882a593Smuzhiyun break;
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun WREG32(RADEON_FP_HORZ_STRETCH, fp_horz_stretch);
204*4882a593Smuzhiyun WREG32(RADEON_FP_VERT_STRETCH, fp_vert_stretch);
205*4882a593Smuzhiyun WREG32(RADEON_CRTC_MORE_CNTL, crtc_more_cntl);
206*4882a593Smuzhiyun WREG32(RADEON_FP_HORZ_VERT_ACTIVE, fp_horz_vert_active);
207*4882a593Smuzhiyun WREG32(RADEON_FP_H_SYNC_STRT_WID, fp_h_sync_strt_wid);
208*4882a593Smuzhiyun WREG32(RADEON_FP_V_SYNC_STRT_WID, fp_v_sync_strt_wid);
209*4882a593Smuzhiyun WREG32(RADEON_FP_CRTC_H_TOTAL_DISP, fp_crtc_h_total_disp);
210*4882a593Smuzhiyun WREG32(RADEON_FP_CRTC_V_TOTAL_DISP, fp_crtc_v_total_disp);
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun
radeon_pll_wait_for_read_update_complete(struct drm_device * dev)213*4882a593Smuzhiyun static void radeon_pll_wait_for_read_update_complete(struct drm_device *dev)
214*4882a593Smuzhiyun {
215*4882a593Smuzhiyun struct radeon_device *rdev = dev->dev_private;
216*4882a593Smuzhiyun int i = 0;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun /* FIXME: Certain revisions of R300 can't recover here. Not sure of
219*4882a593Smuzhiyun the cause yet, but this workaround will mask the problem for now.
220*4882a593Smuzhiyun Other chips usually will pass at the very first test, so the
221*4882a593Smuzhiyun workaround shouldn't have any effect on them. */
222*4882a593Smuzhiyun for (i = 0;
223*4882a593Smuzhiyun (i < 10000 &&
224*4882a593Smuzhiyun RREG32_PLL(RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R);
225*4882a593Smuzhiyun i++);
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun
radeon_pll_write_update(struct drm_device * dev)228*4882a593Smuzhiyun static void radeon_pll_write_update(struct drm_device *dev)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun struct radeon_device *rdev = dev->dev_private;
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun while (RREG32_PLL(RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R);
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun WREG32_PLL_P(RADEON_PPLL_REF_DIV,
235*4882a593Smuzhiyun RADEON_PPLL_ATOMIC_UPDATE_W,
236*4882a593Smuzhiyun ~(RADEON_PPLL_ATOMIC_UPDATE_W));
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun
radeon_pll2_wait_for_read_update_complete(struct drm_device * dev)239*4882a593Smuzhiyun static void radeon_pll2_wait_for_read_update_complete(struct drm_device *dev)
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun struct radeon_device *rdev = dev->dev_private;
242*4882a593Smuzhiyun int i = 0;
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun /* FIXME: Certain revisions of R300 can't recover here. Not sure of
246*4882a593Smuzhiyun the cause yet, but this workaround will mask the problem for now.
247*4882a593Smuzhiyun Other chips usually will pass at the very first test, so the
248*4882a593Smuzhiyun workaround shouldn't have any effect on them. */
249*4882a593Smuzhiyun for (i = 0;
250*4882a593Smuzhiyun (i < 10000 &&
251*4882a593Smuzhiyun RREG32_PLL(RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R);
252*4882a593Smuzhiyun i++);
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun
radeon_pll2_write_update(struct drm_device * dev)255*4882a593Smuzhiyun static void radeon_pll2_write_update(struct drm_device *dev)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun struct radeon_device *rdev = dev->dev_private;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun while (RREG32_PLL(RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R);
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun WREG32_PLL_P(RADEON_P2PLL_REF_DIV,
262*4882a593Smuzhiyun RADEON_P2PLL_ATOMIC_UPDATE_W,
263*4882a593Smuzhiyun ~(RADEON_P2PLL_ATOMIC_UPDATE_W));
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun
radeon_compute_pll_gain(uint16_t ref_freq,uint16_t ref_div,uint16_t fb_div)266*4882a593Smuzhiyun static uint8_t radeon_compute_pll_gain(uint16_t ref_freq, uint16_t ref_div,
267*4882a593Smuzhiyun uint16_t fb_div)
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun unsigned int vcoFreq;
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun if (!ref_div)
272*4882a593Smuzhiyun return 1;
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun vcoFreq = ((unsigned)ref_freq * fb_div) / ref_div;
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun /*
277*4882a593Smuzhiyun * This is horribly crude: the VCO frequency range is divided into
278*4882a593Smuzhiyun * 3 parts, each part having a fixed PLL gain value.
279*4882a593Smuzhiyun */
280*4882a593Smuzhiyun if (vcoFreq >= 30000)
281*4882a593Smuzhiyun /*
282*4882a593Smuzhiyun * [300..max] MHz : 7
283*4882a593Smuzhiyun */
284*4882a593Smuzhiyun return 7;
285*4882a593Smuzhiyun else if (vcoFreq >= 18000)
286*4882a593Smuzhiyun /*
287*4882a593Smuzhiyun * [180..300) MHz : 4
288*4882a593Smuzhiyun */
289*4882a593Smuzhiyun return 4;
290*4882a593Smuzhiyun else
291*4882a593Smuzhiyun /*
292*4882a593Smuzhiyun * [0..180) MHz : 1
293*4882a593Smuzhiyun */
294*4882a593Smuzhiyun return 1;
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun
radeon_crtc_dpms(struct drm_crtc * crtc,int mode)297*4882a593Smuzhiyun static void radeon_crtc_dpms(struct drm_crtc *crtc, int mode)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
300*4882a593Smuzhiyun struct drm_device *dev = crtc->dev;
301*4882a593Smuzhiyun struct radeon_device *rdev = dev->dev_private;
302*4882a593Smuzhiyun uint32_t crtc_ext_cntl = 0;
303*4882a593Smuzhiyun uint32_t mask;
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun if (radeon_crtc->crtc_id)
306*4882a593Smuzhiyun mask = (RADEON_CRTC2_DISP_DIS |
307*4882a593Smuzhiyun RADEON_CRTC2_VSYNC_DIS |
308*4882a593Smuzhiyun RADEON_CRTC2_HSYNC_DIS |
309*4882a593Smuzhiyun RADEON_CRTC2_DISP_REQ_EN_B);
310*4882a593Smuzhiyun else
311*4882a593Smuzhiyun mask = (RADEON_CRTC_DISPLAY_DIS |
312*4882a593Smuzhiyun RADEON_CRTC_VSYNC_DIS |
313*4882a593Smuzhiyun RADEON_CRTC_HSYNC_DIS);
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun /*
316*4882a593Smuzhiyun * On all dual CRTC GPUs this bit controls the CRTC of the primary DAC.
317*4882a593Smuzhiyun * Therefore it is set in the DAC DMPS function.
318*4882a593Smuzhiyun * This is different for GPU's with a single CRTC but a primary and a
319*4882a593Smuzhiyun * TV DAC: here it controls the single CRTC no matter where it is
320*4882a593Smuzhiyun * routed. Therefore we set it here.
321*4882a593Smuzhiyun */
322*4882a593Smuzhiyun if (rdev->flags & RADEON_SINGLE_CRTC)
323*4882a593Smuzhiyun crtc_ext_cntl = RADEON_CRTC_CRT_ON;
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun switch (mode) {
326*4882a593Smuzhiyun case DRM_MODE_DPMS_ON:
327*4882a593Smuzhiyun radeon_crtc->enabled = true;
328*4882a593Smuzhiyun /* adjust pm to dpms changes BEFORE enabling crtcs */
329*4882a593Smuzhiyun radeon_pm_compute_clocks(rdev);
330*4882a593Smuzhiyun if (radeon_crtc->crtc_id)
331*4882a593Smuzhiyun WREG32_P(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_EN, ~(RADEON_CRTC2_EN | mask));
332*4882a593Smuzhiyun else {
333*4882a593Smuzhiyun WREG32_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_EN, ~(RADEON_CRTC_EN |
334*4882a593Smuzhiyun RADEON_CRTC_DISP_REQ_EN_B));
335*4882a593Smuzhiyun WREG32_P(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl, ~(mask | crtc_ext_cntl));
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun if (dev->num_crtcs > radeon_crtc->crtc_id)
338*4882a593Smuzhiyun drm_crtc_vblank_on(crtc);
339*4882a593Smuzhiyun radeon_crtc_load_lut(crtc);
340*4882a593Smuzhiyun break;
341*4882a593Smuzhiyun case DRM_MODE_DPMS_STANDBY:
342*4882a593Smuzhiyun case DRM_MODE_DPMS_SUSPEND:
343*4882a593Smuzhiyun case DRM_MODE_DPMS_OFF:
344*4882a593Smuzhiyun if (dev->num_crtcs > radeon_crtc->crtc_id)
345*4882a593Smuzhiyun drm_crtc_vblank_off(crtc);
346*4882a593Smuzhiyun if (radeon_crtc->crtc_id)
347*4882a593Smuzhiyun WREG32_P(RADEON_CRTC2_GEN_CNTL, mask, ~(RADEON_CRTC2_EN | mask));
348*4882a593Smuzhiyun else {
349*4882a593Smuzhiyun WREG32_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_DISP_REQ_EN_B, ~(RADEON_CRTC_EN |
350*4882a593Smuzhiyun RADEON_CRTC_DISP_REQ_EN_B));
351*4882a593Smuzhiyun WREG32_P(RADEON_CRTC_EXT_CNTL, mask, ~(mask | crtc_ext_cntl));
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun radeon_crtc->enabled = false;
354*4882a593Smuzhiyun /* adjust pm to dpms changes AFTER disabling crtcs */
355*4882a593Smuzhiyun radeon_pm_compute_clocks(rdev);
356*4882a593Smuzhiyun break;
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun
radeon_crtc_set_base(struct drm_crtc * crtc,int x,int y,struct drm_framebuffer * old_fb)360*4882a593Smuzhiyun int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
361*4882a593Smuzhiyun struct drm_framebuffer *old_fb)
362*4882a593Smuzhiyun {
363*4882a593Smuzhiyun return radeon_crtc_do_set_base(crtc, old_fb, x, y, 0);
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun
radeon_crtc_set_base_atomic(struct drm_crtc * crtc,struct drm_framebuffer * fb,int x,int y,enum mode_set_atomic state)366*4882a593Smuzhiyun int radeon_crtc_set_base_atomic(struct drm_crtc *crtc,
367*4882a593Smuzhiyun struct drm_framebuffer *fb,
368*4882a593Smuzhiyun int x, int y, enum mode_set_atomic state)
369*4882a593Smuzhiyun {
370*4882a593Smuzhiyun return radeon_crtc_do_set_base(crtc, fb, x, y, 1);
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun
radeon_crtc_do_set_base(struct drm_crtc * crtc,struct drm_framebuffer * fb,int x,int y,int atomic)373*4882a593Smuzhiyun int radeon_crtc_do_set_base(struct drm_crtc *crtc,
374*4882a593Smuzhiyun struct drm_framebuffer *fb,
375*4882a593Smuzhiyun int x, int y, int atomic)
376*4882a593Smuzhiyun {
377*4882a593Smuzhiyun struct drm_device *dev = crtc->dev;
378*4882a593Smuzhiyun struct radeon_device *rdev = dev->dev_private;
379*4882a593Smuzhiyun struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
380*4882a593Smuzhiyun struct drm_framebuffer *target_fb;
381*4882a593Smuzhiyun struct drm_gem_object *obj;
382*4882a593Smuzhiyun struct radeon_bo *rbo;
383*4882a593Smuzhiyun uint64_t base;
384*4882a593Smuzhiyun uint32_t crtc_offset, crtc_offset_cntl, crtc_tile_x0_y0 = 0;
385*4882a593Smuzhiyun uint32_t crtc_pitch, pitch_pixels;
386*4882a593Smuzhiyun uint32_t tiling_flags;
387*4882a593Smuzhiyun int format;
388*4882a593Smuzhiyun uint32_t gen_cntl_reg, gen_cntl_val;
389*4882a593Smuzhiyun int r;
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun DRM_DEBUG_KMS("\n");
392*4882a593Smuzhiyun /* no fb bound */
393*4882a593Smuzhiyun if (!atomic && !crtc->primary->fb) {
394*4882a593Smuzhiyun DRM_DEBUG_KMS("No FB bound\n");
395*4882a593Smuzhiyun return 0;
396*4882a593Smuzhiyun }
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun if (atomic)
399*4882a593Smuzhiyun target_fb = fb;
400*4882a593Smuzhiyun else
401*4882a593Smuzhiyun target_fb = crtc->primary->fb;
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun switch (target_fb->format->cpp[0] * 8) {
404*4882a593Smuzhiyun case 8:
405*4882a593Smuzhiyun format = 2;
406*4882a593Smuzhiyun break;
407*4882a593Smuzhiyun case 15: /* 555 */
408*4882a593Smuzhiyun format = 3;
409*4882a593Smuzhiyun break;
410*4882a593Smuzhiyun case 16: /* 565 */
411*4882a593Smuzhiyun format = 4;
412*4882a593Smuzhiyun break;
413*4882a593Smuzhiyun case 24: /* RGB */
414*4882a593Smuzhiyun format = 5;
415*4882a593Smuzhiyun break;
416*4882a593Smuzhiyun case 32: /* xRGB */
417*4882a593Smuzhiyun format = 6;
418*4882a593Smuzhiyun break;
419*4882a593Smuzhiyun default:
420*4882a593Smuzhiyun return false;
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun /* Pin framebuffer & get tilling informations */
424*4882a593Smuzhiyun obj = target_fb->obj[0];
425*4882a593Smuzhiyun rbo = gem_to_radeon_bo(obj);
426*4882a593Smuzhiyun retry:
427*4882a593Smuzhiyun r = radeon_bo_reserve(rbo, false);
428*4882a593Smuzhiyun if (unlikely(r != 0))
429*4882a593Smuzhiyun return r;
430*4882a593Smuzhiyun /* Only 27 bit offset for legacy CRTC */
431*4882a593Smuzhiyun r = radeon_bo_pin_restricted(rbo, RADEON_GEM_DOMAIN_VRAM, 1 << 27,
432*4882a593Smuzhiyun &base);
433*4882a593Smuzhiyun if (unlikely(r != 0)) {
434*4882a593Smuzhiyun radeon_bo_unreserve(rbo);
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun /* On old GPU like RN50 with little vram pining can fails because
437*4882a593Smuzhiyun * current fb is taking all space needed. So instead of unpining
438*4882a593Smuzhiyun * the old buffer after pining the new one, first unpin old one
439*4882a593Smuzhiyun * and then retry pining new one.
440*4882a593Smuzhiyun *
441*4882a593Smuzhiyun * As only master can set mode only master can pin and it is
442*4882a593Smuzhiyun * unlikely the master client will race with itself especialy
443*4882a593Smuzhiyun * on those old gpu with single crtc.
444*4882a593Smuzhiyun *
445*4882a593Smuzhiyun * We don't shutdown the display controller because new buffer
446*4882a593Smuzhiyun * will end up in same spot.
447*4882a593Smuzhiyun */
448*4882a593Smuzhiyun if (!atomic && fb && fb != crtc->primary->fb) {
449*4882a593Smuzhiyun struct radeon_bo *old_rbo;
450*4882a593Smuzhiyun unsigned long nsize, osize;
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun old_rbo = gem_to_radeon_bo(fb->obj[0]);
453*4882a593Smuzhiyun osize = radeon_bo_size(old_rbo);
454*4882a593Smuzhiyun nsize = radeon_bo_size(rbo);
455*4882a593Smuzhiyun if (nsize <= osize && !radeon_bo_reserve(old_rbo, false)) {
456*4882a593Smuzhiyun radeon_bo_unpin(old_rbo);
457*4882a593Smuzhiyun radeon_bo_unreserve(old_rbo);
458*4882a593Smuzhiyun fb = NULL;
459*4882a593Smuzhiyun goto retry;
460*4882a593Smuzhiyun }
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun return -EINVAL;
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
465*4882a593Smuzhiyun radeon_bo_unreserve(rbo);
466*4882a593Smuzhiyun if (tiling_flags & RADEON_TILING_MICRO)
467*4882a593Smuzhiyun DRM_ERROR("trying to scanout microtiled buffer\n");
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun /* if scanout was in GTT this really wouldn't work */
470*4882a593Smuzhiyun /* crtc offset is from display base addr not FB location */
471*4882a593Smuzhiyun radeon_crtc->legacy_display_base_addr = rdev->mc.vram_start;
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun base -= radeon_crtc->legacy_display_base_addr;
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun crtc_offset_cntl = 0;
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun pitch_pixels = target_fb->pitches[0] / target_fb->format->cpp[0];
478*4882a593Smuzhiyun crtc_pitch = DIV_ROUND_UP(pitch_pixels * target_fb->format->cpp[0] * 8,
479*4882a593Smuzhiyun target_fb->format->cpp[0] * 8 * 8);
480*4882a593Smuzhiyun crtc_pitch |= crtc_pitch << 16;
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun crtc_offset_cntl |= RADEON_CRTC_GUI_TRIG_OFFSET_LEFT_EN;
483*4882a593Smuzhiyun if (tiling_flags & RADEON_TILING_MACRO) {
484*4882a593Smuzhiyun if (ASIC_IS_R300(rdev))
485*4882a593Smuzhiyun crtc_offset_cntl |= (R300_CRTC_X_Y_MODE_EN |
486*4882a593Smuzhiyun R300_CRTC_MICRO_TILE_BUFFER_DIS |
487*4882a593Smuzhiyun R300_CRTC_MACRO_TILE_EN);
488*4882a593Smuzhiyun else
489*4882a593Smuzhiyun crtc_offset_cntl |= RADEON_CRTC_TILE_EN;
490*4882a593Smuzhiyun } else {
491*4882a593Smuzhiyun if (ASIC_IS_R300(rdev))
492*4882a593Smuzhiyun crtc_offset_cntl &= ~(R300_CRTC_X_Y_MODE_EN |
493*4882a593Smuzhiyun R300_CRTC_MICRO_TILE_BUFFER_DIS |
494*4882a593Smuzhiyun R300_CRTC_MACRO_TILE_EN);
495*4882a593Smuzhiyun else
496*4882a593Smuzhiyun crtc_offset_cntl &= ~RADEON_CRTC_TILE_EN;
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun if (tiling_flags & RADEON_TILING_MACRO) {
500*4882a593Smuzhiyun if (ASIC_IS_R300(rdev)) {
501*4882a593Smuzhiyun crtc_tile_x0_y0 = x | (y << 16);
502*4882a593Smuzhiyun base &= ~0x7ff;
503*4882a593Smuzhiyun } else {
504*4882a593Smuzhiyun int byteshift = target_fb->format->cpp[0] * 8 >> 4;
505*4882a593Smuzhiyun int tile_addr = (((y >> 3) * pitch_pixels + x) >> (8 - byteshift)) << 11;
506*4882a593Smuzhiyun base += tile_addr + ((x << byteshift) % 256) + ((y % 8) << 8);
507*4882a593Smuzhiyun crtc_offset_cntl |= (y % 16);
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun } else {
510*4882a593Smuzhiyun int offset = y * pitch_pixels + x;
511*4882a593Smuzhiyun switch (target_fb->format->cpp[0] * 8) {
512*4882a593Smuzhiyun case 8:
513*4882a593Smuzhiyun offset *= 1;
514*4882a593Smuzhiyun break;
515*4882a593Smuzhiyun case 15:
516*4882a593Smuzhiyun case 16:
517*4882a593Smuzhiyun offset *= 2;
518*4882a593Smuzhiyun break;
519*4882a593Smuzhiyun case 24:
520*4882a593Smuzhiyun offset *= 3;
521*4882a593Smuzhiyun break;
522*4882a593Smuzhiyun case 32:
523*4882a593Smuzhiyun offset *= 4;
524*4882a593Smuzhiyun break;
525*4882a593Smuzhiyun default:
526*4882a593Smuzhiyun return false;
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun base += offset;
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun base &= ~7;
532*4882a593Smuzhiyun
533*4882a593Smuzhiyun if (radeon_crtc->crtc_id == 1)
534*4882a593Smuzhiyun gen_cntl_reg = RADEON_CRTC2_GEN_CNTL;
535*4882a593Smuzhiyun else
536*4882a593Smuzhiyun gen_cntl_reg = RADEON_CRTC_GEN_CNTL;
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun gen_cntl_val = RREG32(gen_cntl_reg);
539*4882a593Smuzhiyun gen_cntl_val &= ~(0xf << 8);
540*4882a593Smuzhiyun gen_cntl_val |= (format << 8);
541*4882a593Smuzhiyun gen_cntl_val &= ~RADEON_CRTC_VSTAT_MODE_MASK;
542*4882a593Smuzhiyun WREG32(gen_cntl_reg, gen_cntl_val);
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun crtc_offset = (u32)base;
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun WREG32(RADEON_DISPLAY_BASE_ADDR + radeon_crtc->crtc_offset, radeon_crtc->legacy_display_base_addr);
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun if (ASIC_IS_R300(rdev)) {
549*4882a593Smuzhiyun if (radeon_crtc->crtc_id)
550*4882a593Smuzhiyun WREG32(R300_CRTC2_TILE_X0_Y0, crtc_tile_x0_y0);
551*4882a593Smuzhiyun else
552*4882a593Smuzhiyun WREG32(R300_CRTC_TILE_X0_Y0, crtc_tile_x0_y0);
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun WREG32(RADEON_CRTC_OFFSET_CNTL + radeon_crtc->crtc_offset, crtc_offset_cntl);
555*4882a593Smuzhiyun WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, crtc_offset);
556*4882a593Smuzhiyun WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch);
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun if (!atomic && fb && fb != crtc->primary->fb) {
559*4882a593Smuzhiyun rbo = gem_to_radeon_bo(fb->obj[0]);
560*4882a593Smuzhiyun r = radeon_bo_reserve(rbo, false);
561*4882a593Smuzhiyun if (unlikely(r != 0))
562*4882a593Smuzhiyun return r;
563*4882a593Smuzhiyun radeon_bo_unpin(rbo);
564*4882a593Smuzhiyun radeon_bo_unreserve(rbo);
565*4882a593Smuzhiyun }
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun /* Bytes per pixel may have changed */
568*4882a593Smuzhiyun radeon_bandwidth_update(rdev);
569*4882a593Smuzhiyun
570*4882a593Smuzhiyun return 0;
571*4882a593Smuzhiyun }
572*4882a593Smuzhiyun
radeon_set_crtc_timing(struct drm_crtc * crtc,struct drm_display_mode * mode)573*4882a593Smuzhiyun static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mode *mode)
574*4882a593Smuzhiyun {
575*4882a593Smuzhiyun struct drm_device *dev = crtc->dev;
576*4882a593Smuzhiyun struct radeon_device *rdev = dev->dev_private;
577*4882a593Smuzhiyun struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
578*4882a593Smuzhiyun const struct drm_framebuffer *fb = crtc->primary->fb;
579*4882a593Smuzhiyun struct drm_encoder *encoder;
580*4882a593Smuzhiyun int format;
581*4882a593Smuzhiyun int hsync_start;
582*4882a593Smuzhiyun int hsync_wid;
583*4882a593Smuzhiyun int vsync_wid;
584*4882a593Smuzhiyun uint32_t crtc_h_total_disp;
585*4882a593Smuzhiyun uint32_t crtc_h_sync_strt_wid;
586*4882a593Smuzhiyun uint32_t crtc_v_total_disp;
587*4882a593Smuzhiyun uint32_t crtc_v_sync_strt_wid;
588*4882a593Smuzhiyun bool is_tv = false;
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun DRM_DEBUG_KMS("\n");
591*4882a593Smuzhiyun list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
592*4882a593Smuzhiyun if (encoder->crtc == crtc) {
593*4882a593Smuzhiyun struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
594*4882a593Smuzhiyun if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) {
595*4882a593Smuzhiyun is_tv = true;
596*4882a593Smuzhiyun DRM_INFO("crtc %d is connected to a TV\n", radeon_crtc->crtc_id);
597*4882a593Smuzhiyun break;
598*4882a593Smuzhiyun }
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun }
601*4882a593Smuzhiyun
602*4882a593Smuzhiyun switch (fb->format->cpp[0] * 8) {
603*4882a593Smuzhiyun case 8:
604*4882a593Smuzhiyun format = 2;
605*4882a593Smuzhiyun break;
606*4882a593Smuzhiyun case 15: /* 555 */
607*4882a593Smuzhiyun format = 3;
608*4882a593Smuzhiyun break;
609*4882a593Smuzhiyun case 16: /* 565 */
610*4882a593Smuzhiyun format = 4;
611*4882a593Smuzhiyun break;
612*4882a593Smuzhiyun case 24: /* RGB */
613*4882a593Smuzhiyun format = 5;
614*4882a593Smuzhiyun break;
615*4882a593Smuzhiyun case 32: /* xRGB */
616*4882a593Smuzhiyun format = 6;
617*4882a593Smuzhiyun break;
618*4882a593Smuzhiyun default:
619*4882a593Smuzhiyun return false;
620*4882a593Smuzhiyun }
621*4882a593Smuzhiyun
622*4882a593Smuzhiyun crtc_h_total_disp = ((((mode->crtc_htotal / 8) - 1) & 0x3ff)
623*4882a593Smuzhiyun | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16));
624*4882a593Smuzhiyun
625*4882a593Smuzhiyun hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8;
626*4882a593Smuzhiyun if (!hsync_wid)
627*4882a593Smuzhiyun hsync_wid = 1;
628*4882a593Smuzhiyun hsync_start = mode->crtc_hsync_start - 8;
629*4882a593Smuzhiyun
630*4882a593Smuzhiyun crtc_h_sync_strt_wid = ((hsync_start & 0x1fff)
631*4882a593Smuzhiyun | ((hsync_wid & 0x3f) << 16)
632*4882a593Smuzhiyun | ((mode->flags & DRM_MODE_FLAG_NHSYNC)
633*4882a593Smuzhiyun ? RADEON_CRTC_H_SYNC_POL
634*4882a593Smuzhiyun : 0));
635*4882a593Smuzhiyun
636*4882a593Smuzhiyun /* This works for double scan mode. */
637*4882a593Smuzhiyun crtc_v_total_disp = (((mode->crtc_vtotal - 1) & 0xffff)
638*4882a593Smuzhiyun | ((mode->crtc_vdisplay - 1) << 16));
639*4882a593Smuzhiyun
640*4882a593Smuzhiyun vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start;
641*4882a593Smuzhiyun if (!vsync_wid)
642*4882a593Smuzhiyun vsync_wid = 1;
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun crtc_v_sync_strt_wid = (((mode->crtc_vsync_start - 1) & 0xfff)
645*4882a593Smuzhiyun | ((vsync_wid & 0x1f) << 16)
646*4882a593Smuzhiyun | ((mode->flags & DRM_MODE_FLAG_NVSYNC)
647*4882a593Smuzhiyun ? RADEON_CRTC_V_SYNC_POL
648*4882a593Smuzhiyun : 0));
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun if (radeon_crtc->crtc_id) {
651*4882a593Smuzhiyun uint32_t crtc2_gen_cntl;
652*4882a593Smuzhiyun uint32_t disp2_merge_cntl;
653*4882a593Smuzhiyun
654*4882a593Smuzhiyun /* if TV DAC is enabled for another crtc and keep it enabled */
655*4882a593Smuzhiyun crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL) & 0x00718080;
656*4882a593Smuzhiyun crtc2_gen_cntl |= ((format << 8)
657*4882a593Smuzhiyun | RADEON_CRTC2_VSYNC_DIS
658*4882a593Smuzhiyun | RADEON_CRTC2_HSYNC_DIS
659*4882a593Smuzhiyun | RADEON_CRTC2_DISP_DIS
660*4882a593Smuzhiyun | RADEON_CRTC2_DISP_REQ_EN_B
661*4882a593Smuzhiyun | ((mode->flags & DRM_MODE_FLAG_DBLSCAN)
662*4882a593Smuzhiyun ? RADEON_CRTC2_DBL_SCAN_EN
663*4882a593Smuzhiyun : 0)
664*4882a593Smuzhiyun | ((mode->flags & DRM_MODE_FLAG_CSYNC)
665*4882a593Smuzhiyun ? RADEON_CRTC2_CSYNC_EN
666*4882a593Smuzhiyun : 0)
667*4882a593Smuzhiyun | ((mode->flags & DRM_MODE_FLAG_INTERLACE)
668*4882a593Smuzhiyun ? RADEON_CRTC2_INTERLACE_EN
669*4882a593Smuzhiyun : 0));
670*4882a593Smuzhiyun
671*4882a593Smuzhiyun /* rs4xx chips seem to like to have the crtc enabled when the timing is set */
672*4882a593Smuzhiyun if ((rdev->family == CHIP_RS400) || (rdev->family == CHIP_RS480))
673*4882a593Smuzhiyun crtc2_gen_cntl |= RADEON_CRTC2_EN;
674*4882a593Smuzhiyun
675*4882a593Smuzhiyun disp2_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL);
676*4882a593Smuzhiyun disp2_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN;
677*4882a593Smuzhiyun
678*4882a593Smuzhiyun WREG32(RADEON_DISP2_MERGE_CNTL, disp2_merge_cntl);
679*4882a593Smuzhiyun WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
680*4882a593Smuzhiyun
681*4882a593Smuzhiyun WREG32(RADEON_FP_H2_SYNC_STRT_WID, crtc_h_sync_strt_wid);
682*4882a593Smuzhiyun WREG32(RADEON_FP_V2_SYNC_STRT_WID, crtc_v_sync_strt_wid);
683*4882a593Smuzhiyun } else {
684*4882a593Smuzhiyun uint32_t crtc_gen_cntl;
685*4882a593Smuzhiyun uint32_t crtc_ext_cntl;
686*4882a593Smuzhiyun uint32_t disp_merge_cntl;
687*4882a593Smuzhiyun
688*4882a593Smuzhiyun crtc_gen_cntl = RREG32(RADEON_CRTC_GEN_CNTL) & 0x00718000;
689*4882a593Smuzhiyun crtc_gen_cntl |= (RADEON_CRTC_EXT_DISP_EN
690*4882a593Smuzhiyun | (format << 8)
691*4882a593Smuzhiyun | RADEON_CRTC_DISP_REQ_EN_B
692*4882a593Smuzhiyun | ((mode->flags & DRM_MODE_FLAG_DBLSCAN)
693*4882a593Smuzhiyun ? RADEON_CRTC_DBL_SCAN_EN
694*4882a593Smuzhiyun : 0)
695*4882a593Smuzhiyun | ((mode->flags & DRM_MODE_FLAG_CSYNC)
696*4882a593Smuzhiyun ? RADEON_CRTC_CSYNC_EN
697*4882a593Smuzhiyun : 0)
698*4882a593Smuzhiyun | ((mode->flags & DRM_MODE_FLAG_INTERLACE)
699*4882a593Smuzhiyun ? RADEON_CRTC_INTERLACE_EN
700*4882a593Smuzhiyun : 0));
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun /* rs4xx chips seem to like to have the crtc enabled when the timing is set */
703*4882a593Smuzhiyun if ((rdev->family == CHIP_RS400) || (rdev->family == CHIP_RS480))
704*4882a593Smuzhiyun crtc_gen_cntl |= RADEON_CRTC_EN;
705*4882a593Smuzhiyun
706*4882a593Smuzhiyun crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL);
707*4882a593Smuzhiyun crtc_ext_cntl |= (RADEON_XCRT_CNT_EN |
708*4882a593Smuzhiyun RADEON_CRTC_VSYNC_DIS |
709*4882a593Smuzhiyun RADEON_CRTC_HSYNC_DIS |
710*4882a593Smuzhiyun RADEON_CRTC_DISPLAY_DIS);
711*4882a593Smuzhiyun
712*4882a593Smuzhiyun disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL);
713*4882a593Smuzhiyun disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN;
714*4882a593Smuzhiyun
715*4882a593Smuzhiyun WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl);
716*4882a593Smuzhiyun WREG32(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl);
717*4882a593Smuzhiyun WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl);
718*4882a593Smuzhiyun }
719*4882a593Smuzhiyun
720*4882a593Smuzhiyun if (is_tv)
721*4882a593Smuzhiyun radeon_legacy_tv_adjust_crtc_reg(encoder, &crtc_h_total_disp,
722*4882a593Smuzhiyun &crtc_h_sync_strt_wid, &crtc_v_total_disp,
723*4882a593Smuzhiyun &crtc_v_sync_strt_wid);
724*4882a593Smuzhiyun
725*4882a593Smuzhiyun WREG32(RADEON_CRTC_H_TOTAL_DISP + radeon_crtc->crtc_offset, crtc_h_total_disp);
726*4882a593Smuzhiyun WREG32(RADEON_CRTC_H_SYNC_STRT_WID + radeon_crtc->crtc_offset, crtc_h_sync_strt_wid);
727*4882a593Smuzhiyun WREG32(RADEON_CRTC_V_TOTAL_DISP + radeon_crtc->crtc_offset, crtc_v_total_disp);
728*4882a593Smuzhiyun WREG32(RADEON_CRTC_V_SYNC_STRT_WID + radeon_crtc->crtc_offset, crtc_v_sync_strt_wid);
729*4882a593Smuzhiyun
730*4882a593Smuzhiyun return true;
731*4882a593Smuzhiyun }
732*4882a593Smuzhiyun
radeon_set_pll(struct drm_crtc * crtc,struct drm_display_mode * mode)733*4882a593Smuzhiyun static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
734*4882a593Smuzhiyun {
735*4882a593Smuzhiyun struct drm_device *dev = crtc->dev;
736*4882a593Smuzhiyun struct radeon_device *rdev = dev->dev_private;
737*4882a593Smuzhiyun struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
738*4882a593Smuzhiyun struct drm_encoder *encoder;
739*4882a593Smuzhiyun uint32_t feedback_div = 0;
740*4882a593Smuzhiyun uint32_t frac_fb_div = 0;
741*4882a593Smuzhiyun uint32_t reference_div = 0;
742*4882a593Smuzhiyun uint32_t post_divider = 0;
743*4882a593Smuzhiyun uint32_t freq = 0;
744*4882a593Smuzhiyun uint8_t pll_gain;
745*4882a593Smuzhiyun bool use_bios_divs = false;
746*4882a593Smuzhiyun /* PLL registers */
747*4882a593Smuzhiyun uint32_t pll_ref_div = 0;
748*4882a593Smuzhiyun uint32_t pll_fb_post_div = 0;
749*4882a593Smuzhiyun uint32_t htotal_cntl = 0;
750*4882a593Smuzhiyun bool is_tv = false;
751*4882a593Smuzhiyun struct radeon_pll *pll;
752*4882a593Smuzhiyun
753*4882a593Smuzhiyun struct {
754*4882a593Smuzhiyun int divider;
755*4882a593Smuzhiyun int bitvalue;
756*4882a593Smuzhiyun } *post_div, post_divs[] = {
757*4882a593Smuzhiyun /* From RAGE 128 VR/RAGE 128 GL Register
758*4882a593Smuzhiyun * Reference Manual (Technical Reference
759*4882a593Smuzhiyun * Manual P/N RRG-G04100-C Rev. 0.04), page
760*4882a593Smuzhiyun * 3-17 (PLL_DIV_[3:0]).
761*4882a593Smuzhiyun */
762*4882a593Smuzhiyun { 1, 0 }, /* VCLK_SRC */
763*4882a593Smuzhiyun { 2, 1 }, /* VCLK_SRC/2 */
764*4882a593Smuzhiyun { 4, 2 }, /* VCLK_SRC/4 */
765*4882a593Smuzhiyun { 8, 3 }, /* VCLK_SRC/8 */
766*4882a593Smuzhiyun { 3, 4 }, /* VCLK_SRC/3 */
767*4882a593Smuzhiyun { 16, 5 }, /* VCLK_SRC/16 */
768*4882a593Smuzhiyun { 6, 6 }, /* VCLK_SRC/6 */
769*4882a593Smuzhiyun { 12, 7 }, /* VCLK_SRC/12 */
770*4882a593Smuzhiyun { 0, 0 }
771*4882a593Smuzhiyun };
772*4882a593Smuzhiyun
773*4882a593Smuzhiyun if (radeon_crtc->crtc_id)
774*4882a593Smuzhiyun pll = &rdev->clock.p2pll;
775*4882a593Smuzhiyun else
776*4882a593Smuzhiyun pll = &rdev->clock.p1pll;
777*4882a593Smuzhiyun
778*4882a593Smuzhiyun pll->flags = RADEON_PLL_LEGACY;
779*4882a593Smuzhiyun
780*4882a593Smuzhiyun if (mode->clock > 200000) /* range limits??? */
781*4882a593Smuzhiyun pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
782*4882a593Smuzhiyun else
783*4882a593Smuzhiyun pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
784*4882a593Smuzhiyun
785*4882a593Smuzhiyun list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
786*4882a593Smuzhiyun if (encoder->crtc == crtc) {
787*4882a593Smuzhiyun struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
788*4882a593Smuzhiyun
789*4882a593Smuzhiyun if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) {
790*4882a593Smuzhiyun is_tv = true;
791*4882a593Smuzhiyun break;
792*4882a593Smuzhiyun }
793*4882a593Smuzhiyun
794*4882a593Smuzhiyun if (encoder->encoder_type != DRM_MODE_ENCODER_DAC)
795*4882a593Smuzhiyun pll->flags |= RADEON_PLL_NO_ODD_POST_DIV;
796*4882a593Smuzhiyun if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) {
797*4882a593Smuzhiyun if (!rdev->is_atom_bios) {
798*4882a593Smuzhiyun struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
799*4882a593Smuzhiyun struct radeon_encoder_lvds *lvds = (struct radeon_encoder_lvds *)radeon_encoder->enc_priv;
800*4882a593Smuzhiyun if (lvds) {
801*4882a593Smuzhiyun if (lvds->use_bios_dividers) {
802*4882a593Smuzhiyun pll_ref_div = lvds->panel_ref_divider;
803*4882a593Smuzhiyun pll_fb_post_div = (lvds->panel_fb_divider |
804*4882a593Smuzhiyun (lvds->panel_post_divider << 16));
805*4882a593Smuzhiyun htotal_cntl = 0;
806*4882a593Smuzhiyun use_bios_divs = true;
807*4882a593Smuzhiyun }
808*4882a593Smuzhiyun }
809*4882a593Smuzhiyun }
810*4882a593Smuzhiyun pll->flags |= RADEON_PLL_USE_REF_DIV;
811*4882a593Smuzhiyun }
812*4882a593Smuzhiyun }
813*4882a593Smuzhiyun }
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun DRM_DEBUG_KMS("\n");
816*4882a593Smuzhiyun
817*4882a593Smuzhiyun if (!use_bios_divs) {
818*4882a593Smuzhiyun radeon_compute_pll_legacy(pll, mode->clock,
819*4882a593Smuzhiyun &freq, &feedback_div, &frac_fb_div,
820*4882a593Smuzhiyun &reference_div, &post_divider);
821*4882a593Smuzhiyun
822*4882a593Smuzhiyun for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
823*4882a593Smuzhiyun if (post_div->divider == post_divider)
824*4882a593Smuzhiyun break;
825*4882a593Smuzhiyun }
826*4882a593Smuzhiyun
827*4882a593Smuzhiyun if (!post_div->divider)
828*4882a593Smuzhiyun post_div = &post_divs[0];
829*4882a593Smuzhiyun
830*4882a593Smuzhiyun DRM_DEBUG_KMS("dc=%u, fd=%d, rd=%d, pd=%d\n",
831*4882a593Smuzhiyun (unsigned)freq,
832*4882a593Smuzhiyun feedback_div,
833*4882a593Smuzhiyun reference_div,
834*4882a593Smuzhiyun post_divider);
835*4882a593Smuzhiyun
836*4882a593Smuzhiyun pll_ref_div = reference_div;
837*4882a593Smuzhiyun #if defined(__powerpc__) && (0) /* TODO */
838*4882a593Smuzhiyun /* apparently programming this otherwise causes a hang??? */
839*4882a593Smuzhiyun if (info->MacModel == RADEON_MAC_IBOOK)
840*4882a593Smuzhiyun pll_fb_post_div = 0x000600ad;
841*4882a593Smuzhiyun else
842*4882a593Smuzhiyun #endif
843*4882a593Smuzhiyun pll_fb_post_div = (feedback_div | (post_div->bitvalue << 16));
844*4882a593Smuzhiyun
845*4882a593Smuzhiyun htotal_cntl = mode->htotal & 0x7;
846*4882a593Smuzhiyun
847*4882a593Smuzhiyun }
848*4882a593Smuzhiyun
849*4882a593Smuzhiyun pll_gain = radeon_compute_pll_gain(pll->reference_freq,
850*4882a593Smuzhiyun pll_ref_div & 0x3ff,
851*4882a593Smuzhiyun pll_fb_post_div & 0x7ff);
852*4882a593Smuzhiyun
853*4882a593Smuzhiyun if (radeon_crtc->crtc_id) {
854*4882a593Smuzhiyun uint32_t pixclks_cntl = ((RREG32_PLL(RADEON_PIXCLKS_CNTL) &
855*4882a593Smuzhiyun ~(RADEON_PIX2CLK_SRC_SEL_MASK)) |
856*4882a593Smuzhiyun RADEON_PIX2CLK_SRC_SEL_P2PLLCLK);
857*4882a593Smuzhiyun
858*4882a593Smuzhiyun if (is_tv) {
859*4882a593Smuzhiyun radeon_legacy_tv_adjust_pll2(encoder, &htotal_cntl,
860*4882a593Smuzhiyun &pll_ref_div, &pll_fb_post_div,
861*4882a593Smuzhiyun &pixclks_cntl);
862*4882a593Smuzhiyun }
863*4882a593Smuzhiyun
864*4882a593Smuzhiyun WREG32_PLL_P(RADEON_PIXCLKS_CNTL,
865*4882a593Smuzhiyun RADEON_PIX2CLK_SRC_SEL_CPUCLK,
866*4882a593Smuzhiyun ~(RADEON_PIX2CLK_SRC_SEL_MASK));
867*4882a593Smuzhiyun
868*4882a593Smuzhiyun WREG32_PLL_P(RADEON_P2PLL_CNTL,
869*4882a593Smuzhiyun RADEON_P2PLL_RESET
870*4882a593Smuzhiyun | RADEON_P2PLL_ATOMIC_UPDATE_EN
871*4882a593Smuzhiyun | ((uint32_t)pll_gain << RADEON_P2PLL_PVG_SHIFT),
872*4882a593Smuzhiyun ~(RADEON_P2PLL_RESET
873*4882a593Smuzhiyun | RADEON_P2PLL_ATOMIC_UPDATE_EN
874*4882a593Smuzhiyun | RADEON_P2PLL_PVG_MASK));
875*4882a593Smuzhiyun
876*4882a593Smuzhiyun WREG32_PLL_P(RADEON_P2PLL_REF_DIV,
877*4882a593Smuzhiyun pll_ref_div,
878*4882a593Smuzhiyun ~RADEON_P2PLL_REF_DIV_MASK);
879*4882a593Smuzhiyun
880*4882a593Smuzhiyun WREG32_PLL_P(RADEON_P2PLL_DIV_0,
881*4882a593Smuzhiyun pll_fb_post_div,
882*4882a593Smuzhiyun ~RADEON_P2PLL_FB0_DIV_MASK);
883*4882a593Smuzhiyun
884*4882a593Smuzhiyun WREG32_PLL_P(RADEON_P2PLL_DIV_0,
885*4882a593Smuzhiyun pll_fb_post_div,
886*4882a593Smuzhiyun ~RADEON_P2PLL_POST0_DIV_MASK);
887*4882a593Smuzhiyun
888*4882a593Smuzhiyun radeon_pll2_write_update(dev);
889*4882a593Smuzhiyun radeon_pll2_wait_for_read_update_complete(dev);
890*4882a593Smuzhiyun
891*4882a593Smuzhiyun WREG32_PLL(RADEON_HTOTAL2_CNTL, htotal_cntl);
892*4882a593Smuzhiyun
893*4882a593Smuzhiyun WREG32_PLL_P(RADEON_P2PLL_CNTL,
894*4882a593Smuzhiyun 0,
895*4882a593Smuzhiyun ~(RADEON_P2PLL_RESET
896*4882a593Smuzhiyun | RADEON_P2PLL_SLEEP
897*4882a593Smuzhiyun | RADEON_P2PLL_ATOMIC_UPDATE_EN));
898*4882a593Smuzhiyun
899*4882a593Smuzhiyun DRM_DEBUG_KMS("Wrote2: 0x%08x 0x%08x 0x%08x (0x%08x)\n",
900*4882a593Smuzhiyun (unsigned)pll_ref_div,
901*4882a593Smuzhiyun (unsigned)pll_fb_post_div,
902*4882a593Smuzhiyun (unsigned)htotal_cntl,
903*4882a593Smuzhiyun RREG32_PLL(RADEON_P2PLL_CNTL));
904*4882a593Smuzhiyun DRM_DEBUG_KMS("Wrote2: rd=%u, fd=%u, pd=%u\n",
905*4882a593Smuzhiyun (unsigned)pll_ref_div & RADEON_P2PLL_REF_DIV_MASK,
906*4882a593Smuzhiyun (unsigned)pll_fb_post_div & RADEON_P2PLL_FB0_DIV_MASK,
907*4882a593Smuzhiyun (unsigned)((pll_fb_post_div &
908*4882a593Smuzhiyun RADEON_P2PLL_POST0_DIV_MASK) >> 16));
909*4882a593Smuzhiyun
910*4882a593Smuzhiyun mdelay(50); /* Let the clock to lock */
911*4882a593Smuzhiyun
912*4882a593Smuzhiyun WREG32_PLL_P(RADEON_PIXCLKS_CNTL,
913*4882a593Smuzhiyun RADEON_PIX2CLK_SRC_SEL_P2PLLCLK,
914*4882a593Smuzhiyun ~(RADEON_PIX2CLK_SRC_SEL_MASK));
915*4882a593Smuzhiyun
916*4882a593Smuzhiyun WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl);
917*4882a593Smuzhiyun } else {
918*4882a593Smuzhiyun uint32_t pixclks_cntl;
919*4882a593Smuzhiyun
920*4882a593Smuzhiyun
921*4882a593Smuzhiyun if (is_tv) {
922*4882a593Smuzhiyun pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL);
923*4882a593Smuzhiyun radeon_legacy_tv_adjust_pll1(encoder, &htotal_cntl, &pll_ref_div,
924*4882a593Smuzhiyun &pll_fb_post_div, &pixclks_cntl);
925*4882a593Smuzhiyun }
926*4882a593Smuzhiyun
927*4882a593Smuzhiyun if (rdev->flags & RADEON_IS_MOBILITY) {
928*4882a593Smuzhiyun /* A temporal workaround for the occasional blanking on certain laptop panels.
929*4882a593Smuzhiyun This appears to related to the PLL divider registers (fail to lock?).
930*4882a593Smuzhiyun It occurs even when all dividers are the same with their old settings.
931*4882a593Smuzhiyun In this case we really don't need to fiddle with PLL registers.
932*4882a593Smuzhiyun By doing this we can avoid the blanking problem with some panels.
933*4882a593Smuzhiyun */
934*4882a593Smuzhiyun if ((pll_ref_div == (RREG32_PLL(RADEON_PPLL_REF_DIV) & RADEON_PPLL_REF_DIV_MASK)) &&
935*4882a593Smuzhiyun (pll_fb_post_div == (RREG32_PLL(RADEON_PPLL_DIV_3) &
936*4882a593Smuzhiyun (RADEON_PPLL_POST3_DIV_MASK | RADEON_PPLL_FB3_DIV_MASK)))) {
937*4882a593Smuzhiyun WREG32_P(RADEON_CLOCK_CNTL_INDEX,
938*4882a593Smuzhiyun RADEON_PLL_DIV_SEL,
939*4882a593Smuzhiyun ~(RADEON_PLL_DIV_SEL));
940*4882a593Smuzhiyun r100_pll_errata_after_index(rdev);
941*4882a593Smuzhiyun return;
942*4882a593Smuzhiyun }
943*4882a593Smuzhiyun }
944*4882a593Smuzhiyun
945*4882a593Smuzhiyun WREG32_PLL_P(RADEON_VCLK_ECP_CNTL,
946*4882a593Smuzhiyun RADEON_VCLK_SRC_SEL_CPUCLK,
947*4882a593Smuzhiyun ~(RADEON_VCLK_SRC_SEL_MASK));
948*4882a593Smuzhiyun WREG32_PLL_P(RADEON_PPLL_CNTL,
949*4882a593Smuzhiyun RADEON_PPLL_RESET
950*4882a593Smuzhiyun | RADEON_PPLL_ATOMIC_UPDATE_EN
951*4882a593Smuzhiyun | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN
952*4882a593Smuzhiyun | ((uint32_t)pll_gain << RADEON_PPLL_PVG_SHIFT),
953*4882a593Smuzhiyun ~(RADEON_PPLL_RESET
954*4882a593Smuzhiyun | RADEON_PPLL_ATOMIC_UPDATE_EN
955*4882a593Smuzhiyun | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN
956*4882a593Smuzhiyun | RADEON_PPLL_PVG_MASK));
957*4882a593Smuzhiyun
958*4882a593Smuzhiyun WREG32_P(RADEON_CLOCK_CNTL_INDEX,
959*4882a593Smuzhiyun RADEON_PLL_DIV_SEL,
960*4882a593Smuzhiyun ~(RADEON_PLL_DIV_SEL));
961*4882a593Smuzhiyun r100_pll_errata_after_index(rdev);
962*4882a593Smuzhiyun
963*4882a593Smuzhiyun if (ASIC_IS_R300(rdev) ||
964*4882a593Smuzhiyun (rdev->family == CHIP_RS300) ||
965*4882a593Smuzhiyun (rdev->family == CHIP_RS400) ||
966*4882a593Smuzhiyun (rdev->family == CHIP_RS480)) {
967*4882a593Smuzhiyun if (pll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) {
968*4882a593Smuzhiyun /* When restoring console mode, use saved PPLL_REF_DIV
969*4882a593Smuzhiyun * setting.
970*4882a593Smuzhiyun */
971*4882a593Smuzhiyun WREG32_PLL_P(RADEON_PPLL_REF_DIV,
972*4882a593Smuzhiyun pll_ref_div,
973*4882a593Smuzhiyun 0);
974*4882a593Smuzhiyun } else {
975*4882a593Smuzhiyun /* R300 uses ref_div_acc field as real ref divider */
976*4882a593Smuzhiyun WREG32_PLL_P(RADEON_PPLL_REF_DIV,
977*4882a593Smuzhiyun (pll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT),
978*4882a593Smuzhiyun ~R300_PPLL_REF_DIV_ACC_MASK);
979*4882a593Smuzhiyun }
980*4882a593Smuzhiyun } else
981*4882a593Smuzhiyun WREG32_PLL_P(RADEON_PPLL_REF_DIV,
982*4882a593Smuzhiyun pll_ref_div,
983*4882a593Smuzhiyun ~RADEON_PPLL_REF_DIV_MASK);
984*4882a593Smuzhiyun
985*4882a593Smuzhiyun WREG32_PLL_P(RADEON_PPLL_DIV_3,
986*4882a593Smuzhiyun pll_fb_post_div,
987*4882a593Smuzhiyun ~RADEON_PPLL_FB3_DIV_MASK);
988*4882a593Smuzhiyun
989*4882a593Smuzhiyun WREG32_PLL_P(RADEON_PPLL_DIV_3,
990*4882a593Smuzhiyun pll_fb_post_div,
991*4882a593Smuzhiyun ~RADEON_PPLL_POST3_DIV_MASK);
992*4882a593Smuzhiyun
993*4882a593Smuzhiyun radeon_pll_write_update(dev);
994*4882a593Smuzhiyun radeon_pll_wait_for_read_update_complete(dev);
995*4882a593Smuzhiyun
996*4882a593Smuzhiyun WREG32_PLL(RADEON_HTOTAL_CNTL, htotal_cntl);
997*4882a593Smuzhiyun
998*4882a593Smuzhiyun WREG32_PLL_P(RADEON_PPLL_CNTL,
999*4882a593Smuzhiyun 0,
1000*4882a593Smuzhiyun ~(RADEON_PPLL_RESET
1001*4882a593Smuzhiyun | RADEON_PPLL_SLEEP
1002*4882a593Smuzhiyun | RADEON_PPLL_ATOMIC_UPDATE_EN
1003*4882a593Smuzhiyun | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN));
1004*4882a593Smuzhiyun
1005*4882a593Smuzhiyun DRM_DEBUG_KMS("Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n",
1006*4882a593Smuzhiyun pll_ref_div,
1007*4882a593Smuzhiyun pll_fb_post_div,
1008*4882a593Smuzhiyun (unsigned)htotal_cntl,
1009*4882a593Smuzhiyun RREG32_PLL(RADEON_PPLL_CNTL));
1010*4882a593Smuzhiyun DRM_DEBUG_KMS("Wrote: rd=%d, fd=%d, pd=%d\n",
1011*4882a593Smuzhiyun pll_ref_div & RADEON_PPLL_REF_DIV_MASK,
1012*4882a593Smuzhiyun pll_fb_post_div & RADEON_PPLL_FB3_DIV_MASK,
1013*4882a593Smuzhiyun (pll_fb_post_div & RADEON_PPLL_POST3_DIV_MASK) >> 16);
1014*4882a593Smuzhiyun
1015*4882a593Smuzhiyun mdelay(50); /* Let the clock to lock */
1016*4882a593Smuzhiyun
1017*4882a593Smuzhiyun WREG32_PLL_P(RADEON_VCLK_ECP_CNTL,
1018*4882a593Smuzhiyun RADEON_VCLK_SRC_SEL_PPLLCLK,
1019*4882a593Smuzhiyun ~(RADEON_VCLK_SRC_SEL_MASK));
1020*4882a593Smuzhiyun
1021*4882a593Smuzhiyun if (is_tv)
1022*4882a593Smuzhiyun WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl);
1023*4882a593Smuzhiyun }
1024*4882a593Smuzhiyun }
1025*4882a593Smuzhiyun
radeon_crtc_mode_fixup(struct drm_crtc * crtc,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)1026*4882a593Smuzhiyun static bool radeon_crtc_mode_fixup(struct drm_crtc *crtc,
1027*4882a593Smuzhiyun const struct drm_display_mode *mode,
1028*4882a593Smuzhiyun struct drm_display_mode *adjusted_mode)
1029*4882a593Smuzhiyun {
1030*4882a593Smuzhiyun if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode))
1031*4882a593Smuzhiyun return false;
1032*4882a593Smuzhiyun return true;
1033*4882a593Smuzhiyun }
1034*4882a593Smuzhiyun
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)1035*4882a593Smuzhiyun static int radeon_crtc_mode_set(struct drm_crtc *crtc,
1036*4882a593Smuzhiyun struct drm_display_mode *mode,
1037*4882a593Smuzhiyun struct drm_display_mode *adjusted_mode,
1038*4882a593Smuzhiyun int x, int y, struct drm_framebuffer *old_fb)
1039*4882a593Smuzhiyun {
1040*4882a593Smuzhiyun struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1041*4882a593Smuzhiyun
1042*4882a593Smuzhiyun /* TODO TV */
1043*4882a593Smuzhiyun radeon_crtc_set_base(crtc, x, y, old_fb);
1044*4882a593Smuzhiyun radeon_set_crtc_timing(crtc, adjusted_mode);
1045*4882a593Smuzhiyun radeon_set_pll(crtc, adjusted_mode);
1046*4882a593Smuzhiyun radeon_overscan_setup(crtc, adjusted_mode);
1047*4882a593Smuzhiyun if (radeon_crtc->crtc_id == 0) {
1048*4882a593Smuzhiyun radeon_legacy_rmx_mode_set(crtc, adjusted_mode);
1049*4882a593Smuzhiyun } else {
1050*4882a593Smuzhiyun if (radeon_crtc->rmx_type != RMX_OFF) {
1051*4882a593Smuzhiyun /* FIXME: only first crtc has rmx what should we
1052*4882a593Smuzhiyun * do ?
1053*4882a593Smuzhiyun */
1054*4882a593Smuzhiyun DRM_ERROR("Mode need scaling but only first crtc can do that.\n");
1055*4882a593Smuzhiyun }
1056*4882a593Smuzhiyun }
1057*4882a593Smuzhiyun radeon_cursor_reset(crtc);
1058*4882a593Smuzhiyun return 0;
1059*4882a593Smuzhiyun }
1060*4882a593Smuzhiyun
radeon_crtc_prepare(struct drm_crtc * crtc)1061*4882a593Smuzhiyun static void radeon_crtc_prepare(struct drm_crtc *crtc)
1062*4882a593Smuzhiyun {
1063*4882a593Smuzhiyun struct drm_device *dev = crtc->dev;
1064*4882a593Smuzhiyun struct drm_crtc *crtci;
1065*4882a593Smuzhiyun
1066*4882a593Smuzhiyun /*
1067*4882a593Smuzhiyun * The hardware wedges sometimes if you reconfigure one CRTC
1068*4882a593Smuzhiyun * whilst another is running (see fdo bug #24611).
1069*4882a593Smuzhiyun */
1070*4882a593Smuzhiyun list_for_each_entry(crtci, &dev->mode_config.crtc_list, head)
1071*4882a593Smuzhiyun radeon_crtc_dpms(crtci, DRM_MODE_DPMS_OFF);
1072*4882a593Smuzhiyun }
1073*4882a593Smuzhiyun
radeon_crtc_commit(struct drm_crtc * crtc)1074*4882a593Smuzhiyun static void radeon_crtc_commit(struct drm_crtc *crtc)
1075*4882a593Smuzhiyun {
1076*4882a593Smuzhiyun struct drm_device *dev = crtc->dev;
1077*4882a593Smuzhiyun struct drm_crtc *crtci;
1078*4882a593Smuzhiyun
1079*4882a593Smuzhiyun /*
1080*4882a593Smuzhiyun * Reenable the CRTCs that should be running.
1081*4882a593Smuzhiyun */
1082*4882a593Smuzhiyun list_for_each_entry(crtci, &dev->mode_config.crtc_list, head) {
1083*4882a593Smuzhiyun if (crtci->enabled)
1084*4882a593Smuzhiyun radeon_crtc_dpms(crtci, DRM_MODE_DPMS_ON);
1085*4882a593Smuzhiyun }
1086*4882a593Smuzhiyun }
1087*4882a593Smuzhiyun
radeon_crtc_disable(struct drm_crtc * crtc)1088*4882a593Smuzhiyun static void radeon_crtc_disable(struct drm_crtc *crtc)
1089*4882a593Smuzhiyun {
1090*4882a593Smuzhiyun radeon_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
1091*4882a593Smuzhiyun if (crtc->primary->fb) {
1092*4882a593Smuzhiyun int r;
1093*4882a593Smuzhiyun struct radeon_bo *rbo;
1094*4882a593Smuzhiyun
1095*4882a593Smuzhiyun rbo = gem_to_radeon_bo(crtc->primary->fb->obj[0]);
1096*4882a593Smuzhiyun r = radeon_bo_reserve(rbo, false);
1097*4882a593Smuzhiyun if (unlikely(r))
1098*4882a593Smuzhiyun DRM_ERROR("failed to reserve rbo before unpin\n");
1099*4882a593Smuzhiyun else {
1100*4882a593Smuzhiyun radeon_bo_unpin(rbo);
1101*4882a593Smuzhiyun radeon_bo_unreserve(rbo);
1102*4882a593Smuzhiyun }
1103*4882a593Smuzhiyun }
1104*4882a593Smuzhiyun }
1105*4882a593Smuzhiyun
1106*4882a593Smuzhiyun static const struct drm_crtc_helper_funcs legacy_helper_funcs = {
1107*4882a593Smuzhiyun .dpms = radeon_crtc_dpms,
1108*4882a593Smuzhiyun .mode_fixup = radeon_crtc_mode_fixup,
1109*4882a593Smuzhiyun .mode_set = radeon_crtc_mode_set,
1110*4882a593Smuzhiyun .mode_set_base = radeon_crtc_set_base,
1111*4882a593Smuzhiyun .mode_set_base_atomic = radeon_crtc_set_base_atomic,
1112*4882a593Smuzhiyun .prepare = radeon_crtc_prepare,
1113*4882a593Smuzhiyun .commit = radeon_crtc_commit,
1114*4882a593Smuzhiyun .disable = radeon_crtc_disable,
1115*4882a593Smuzhiyun .get_scanout_position = radeon_get_crtc_scanout_position,
1116*4882a593Smuzhiyun };
1117*4882a593Smuzhiyun
1118*4882a593Smuzhiyun
radeon_legacy_init_crtc(struct drm_device * dev,struct radeon_crtc * radeon_crtc)1119*4882a593Smuzhiyun void radeon_legacy_init_crtc(struct drm_device *dev,
1120*4882a593Smuzhiyun struct radeon_crtc *radeon_crtc)
1121*4882a593Smuzhiyun {
1122*4882a593Smuzhiyun if (radeon_crtc->crtc_id == 1)
1123*4882a593Smuzhiyun radeon_crtc->crtc_offset = RADEON_CRTC2_H_TOTAL_DISP - RADEON_CRTC_H_TOTAL_DISP;
1124*4882a593Smuzhiyun drm_crtc_helper_add(&radeon_crtc->base, &legacy_helper_funcs);
1125*4882a593Smuzhiyun }
1126