1e3d74329Smrg/*
2e3d74329Smrg * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and
3e3d74329Smrg *                VA Linux Systems Inc., Fremont, California.
4e3d74329Smrg *
5e3d74329Smrg * All Rights Reserved.
6e3d74329Smrg *
7e3d74329Smrg * Permission is hereby granted, free of charge, to any person obtaining
8e3d74329Smrg * a copy of this software and associated documentation files (the
9e3d74329Smrg * "Software"), to deal in the Software without restriction, including
10e3d74329Smrg * without limitation on the rights to use, copy, modify, merge,
11e3d74329Smrg * publish, distribute, sublicense, and/or sell copies of the Software,
12e3d74329Smrg * and to permit persons to whom the Software is furnished to do so,
13e3d74329Smrg * subject to the following conditions:
14e3d74329Smrg *
15e3d74329Smrg * The above copyright notice and this permission notice (including the
16e3d74329Smrg * next paragraph) shall be included in all copies or substantial
17e3d74329Smrg * portions of the Software.
18e3d74329Smrg *
19e3d74329Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20e3d74329Smrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21e3d74329Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22e3d74329Smrg * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR
23e3d74329Smrg * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24e3d74329Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25e3d74329Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26e3d74329Smrg * DEALINGS IN THE SOFTWARE.
27e3d74329Smrg */
28e3d74329Smrg
29e3d74329Smrg#ifdef HAVE_CONFIG_H
30e3d74329Smrg#include "config.h"
31e3d74329Smrg#endif
32e3d74329Smrg
33e3d74329Smrg#include <string.h>
34e3d74329Smrg#include <stdio.h>
35e3d74329Smrg
36e3d74329Smrg#include "xf86.h"
37e3d74329Smrg#include "xf86Modes.h"
38a56d54acSmrg
39a56d54acSmrg#ifdef HAVE_XEXTPROTO_71
40e3d74329Smrg#include "X11/extensions/dpmsconst.h"
41a56d54acSmrg#else
42a56d54acSmrg#define DPMS_SERVER
43a56d54acSmrg#include "X11/extensions/dpms.h"
44a56d54acSmrg#endif
45e3d74329Smrg
46e3d74329Smrg#include "r128.h"
47e3d74329Smrg#include "r128_probe.h"
48e3d74329Smrg#include "r128_reg.h"
49e3d74329Smrg
50cd241713Smrg
51cd241713Smrg#ifndef MAX
52cd241713Smrg#define MAX(a,b) ((a)>(b)?(a):(b))
53cd241713Smrg#endif
54cd241713Smrg
55cd241713Smrg
56cd241713Smrg/* Define CRTC registers for requested video mode. */
57cd241713SmrgBool R128InitCrtcRegisters(xf86CrtcPtr crtc, R128SavePtr save, DisplayModePtr mode)
58cd241713Smrg{
59cd241713Smrg    ScrnInfoPtr pScrn = crtc->scrn;
60cd241713Smrg    R128InfoPtr info  = R128PTR(pScrn);
61cd241713Smrg    xf86OutputPtr output = R128FirstOutput(crtc);
62cd241713Smrg    R128OutputPrivatePtr r128_output = output->driver_private;
63cd241713Smrg
64cd241713Smrg    int    format;
65cd241713Smrg    int    hsync_start;
66cd241713Smrg    int    hsync_wid;
67cd241713Smrg    int    hsync_fudge;
68cd241713Smrg    int    vsync_wid;
69cd241713Smrg    int    hsync_fudge_default[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 };
70cd241713Smrg    int    hsync_fudge_fp[]      = { 0x12, 0x11, 0x09, 0x09, 0x05, 0x05 };
71cd241713Smrg//   int    hsync_fudge_fp_crt[]  = { 0x12, 0x10, 0x08, 0x08, 0x04, 0x04 };
72cd241713Smrg
73cd241713Smrg    switch (info->CurrentLayout.pixel_code) {
74cd241713Smrg    case 4:  format = 1; break;
75cd241713Smrg    case 8:  format = 2; break;
76cd241713Smrg    case 15: format = 3; break;      /*  555 */
77cd241713Smrg    case 16: format = 4; break;      /*  565 */
78cd241713Smrg    case 24: format = 5; break;      /*  RGB */
79cd241713Smrg    case 32: format = 6; break;      /* xRGB */
80cd241713Smrg    default:
81cd241713Smrg    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
82cd241713Smrg           "Unsupported pixel depth (%d)\n",
83cd241713Smrg           info->CurrentLayout.bitsPerPixel);
84cd241713Smrg    return FALSE;
85cd241713Smrg    }
86cd241713Smrg
87cd241713Smrg    if (r128_output->MonType == MT_LCD || r128_output->MonType == MT_DFP)
88cd241713Smrg    hsync_fudge = hsync_fudge_fp[format-1];
89cd241713Smrg    else
90cd241713Smrg        hsync_fudge = hsync_fudge_default[format-1];
91cd241713Smrg
92cd241713Smrg    save->crtc_gen_cntl = (R128_CRTC_EXT_DISP_EN
93cd241713Smrg              | R128_CRTC_EN
94cd241713Smrg              | (format << 8)
95cd241713Smrg              | ((mode->Flags & V_DBLSCAN)
96cd241713Smrg                 ? R128_CRTC_DBL_SCAN_EN
97cd241713Smrg                 : 0)
98cd241713Smrg              | ((mode->Flags & V_INTERLACE)
99cd241713Smrg                 ? R128_CRTC_INTERLACE_EN
100cd241713Smrg                 : 0)
101cd241713Smrg              | ((mode->Flags & V_CSYNC)
102cd241713Smrg                 ? R128_CRTC_CSYNC_EN
103cd241713Smrg                 : 0));
104cd241713Smrg
105cd241713Smrg    if (r128_output->MonType == MT_LCD || r128_output->MonType == MT_DFP)
106cd241713Smrg        save->crtc_gen_cntl &= ~(R128_CRTC_DBL_SCAN_EN | R128_CRTC_INTERLACE_EN);
107cd241713Smrg
108cd241713Smrg    save->crtc_ext_cntl |= R128_VGA_ATI_LINEAR | R128_XCRT_CNT_EN;
109cd241713Smrg
110cd241713Smrg    save->crtc_h_total_disp = ((((mode->CrtcHTotal / 8) - 1) & 0xffff)
111cd241713Smrg                  | (((mode->CrtcHDisplay / 8) - 1) << 16));
112cd241713Smrg
113cd241713Smrg    hsync_wid = (mode->CrtcHSyncEnd - mode->CrtcHSyncStart) / 8;
114cd241713Smrg    if (!hsync_wid)       hsync_wid = 1;
115cd241713Smrg    if (hsync_wid > 0x3f) hsync_wid = 0x3f;
116cd241713Smrg
117cd241713Smrg    hsync_start = mode->CrtcHSyncStart - 8 + hsync_fudge;
118cd241713Smrg
119cd241713Smrg    save->crtc_h_sync_strt_wid = ((hsync_start & 0xfff)
120cd241713Smrg                 | (hsync_wid << 16)
121cd241713Smrg                 | ((mode->Flags & V_NHSYNC)
122cd241713Smrg                    ? R128_CRTC_H_SYNC_POL
123cd241713Smrg                    : 0));
124cd241713Smrg
125cd241713Smrg#if 1
126cd241713Smrg                /* This works for double scan mode. */
127cd241713Smrg    save->crtc_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff)
128cd241713Smrg                  | ((mode->CrtcVDisplay - 1) << 16));
129cd241713Smrg#else
130cd241713Smrg                /* This is what cce/nbmode.c example code
131cd241713Smrg                   does -- is this correct? */
132cd241713Smrg    save->crtc_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff)
133cd241713Smrg                  | ((mode->CrtcVDisplay
134cd241713Smrg                  * ((mode->Flags & V_DBLSCAN) ? 2 : 1) - 1)
135cd241713Smrg                 << 16));
136cd241713Smrg#endif
137cd241713Smrg
138cd241713Smrg    vsync_wid = mode->CrtcVSyncEnd - mode->CrtcVSyncStart;
139cd241713Smrg    if (!vsync_wid)       vsync_wid = 1;
140cd241713Smrg    if (vsync_wid > 0x1f) vsync_wid = 0x1f;
141cd241713Smrg
142cd241713Smrg    save->crtc_v_sync_strt_wid = (((mode->CrtcVSyncStart - 1) & 0xfff)
143cd241713Smrg                 | (vsync_wid << 16)
144cd241713Smrg                 | ((mode->Flags & V_NVSYNC)
145cd241713Smrg                    ? R128_CRTC_V_SYNC_POL
146cd241713Smrg                    : 0));
147cd241713Smrg    save->crtc_pitch       = info->CurrentLayout.displayWidth / 8;
148cd241713Smrg
149cd241713Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
150cd241713Smrg                        "Pitch = %d bytes (virtualX = %d, "
151cd241713Smrg                        "displayWidth = %d)\n",
152cd241713Smrg                        save->crtc_pitch, pScrn->virtualX,
153cd241713Smrg                        info->CurrentLayout.displayWidth));
154cd241713Smrg
155cd241713Smrg#if X_BYTE_ORDER == X_BIG_ENDIAN
156cd241713Smrg    /* Change the endianness of the aperture */
157cd241713Smrg    switch (info->CurrentLayout.pixel_code) {
158cd241713Smrg    case 15:
159cd241713Smrg    case 16: save->config_cntl |= APER_0_BIG_ENDIAN_16BPP_SWAP; break;
160cd241713Smrg    case 32: save->config_cntl |= APER_0_BIG_ENDIAN_32BPP_SWAP; break;
161cd241713Smrg    default: break;
162cd241713Smrg    }
163cd241713Smrg#endif
164cd241713Smrg
165cd241713Smrg    return TRUE;
166cd241713Smrg}
167cd241713Smrg
168cd241713Smrg/* Define CRTC2 registers for requested video mode. */
169cd241713SmrgBool R128InitCrtc2Registers(xf86CrtcPtr crtc, R128SavePtr save, DisplayModePtr mode)
170cd241713Smrg{
171cd241713Smrg    ScrnInfoPtr pScrn = crtc->scrn;
172cd241713Smrg    R128InfoPtr info  = R128PTR(pScrn);
173cd241713Smrg
174cd241713Smrg    int    format;
175cd241713Smrg    int    hsync_start;
176cd241713Smrg    int    hsync_wid;
177cd241713Smrg    int    hsync_fudge;
178cd241713Smrg    int    vsync_wid;
179cd241713Smrg    int    hsync_fudge_default[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 };
180cd241713Smrg
181cd241713Smrg    switch (info->CurrentLayout.pixel_code) {
182cd241713Smrg    case 4:  format = 1; break;
183cd241713Smrg    case 8:  format = 2; break;
184cd241713Smrg    case 15: format = 3; break;      /*  555 */
185cd241713Smrg    case 16: format = 4; break;      /*  565 */
186cd241713Smrg    case 24: format = 5; break;      /*  RGB */
187cd241713Smrg    case 32: format = 6; break;      /* xRGB */
188cd241713Smrg    default:
189cd241713Smrg    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
190cd241713Smrg           "Unsupported pixel depth (%d)\n", info->CurrentLayout.bitsPerPixel);
191cd241713Smrg    return FALSE;
192cd241713Smrg    }
193cd241713Smrg
194cd241713Smrg    hsync_fudge = hsync_fudge_default[format-1];
195cd241713Smrg
196cd241713Smrg    save->crtc2_gen_cntl = (R128_CRTC2_EN
197cd241713Smrg              | (format << 8)
198cd241713Smrg              | ((mode->Flags & V_DBLSCAN)
199cd241713Smrg                 ? R128_CRTC2_DBL_SCAN_EN
200cd241713Smrg                 : 0));
201cd241713Smrg/*
202cd241713Smrg    save->crtc2_gen_cntl &= ~R128_CRTC_EXT_DISP_EN;
203cd241713Smrg    save->crtc2_gen_cntl |= (1 << 21);
204cd241713Smrg*/
205cd241713Smrg    save->crtc2_h_total_disp = ((((mode->CrtcHTotal / 8) - 1) & 0xffff)
206cd241713Smrg                  | (((mode->CrtcHDisplay / 8) - 1) << 16));
207cd241713Smrg
208cd241713Smrg    hsync_wid = (mode->CrtcHSyncEnd - mode->CrtcHSyncStart) / 8;
209cd241713Smrg    if (!hsync_wid)       hsync_wid = 1;
210cd241713Smrg    if (hsync_wid > 0x3f) hsync_wid = 0x3f;
211cd241713Smrg
212cd241713Smrg    hsync_start = mode->CrtcHSyncStart - 8 + hsync_fudge;
213cd241713Smrg
214cd241713Smrg    save->crtc2_h_sync_strt_wid = ((hsync_start & 0xfff)
215cd241713Smrg                 | (hsync_wid << 16)
216cd241713Smrg                 | ((mode->Flags & V_NHSYNC)
217cd241713Smrg                    ? R128_CRTC2_H_SYNC_POL
218cd241713Smrg                    : 0));
219cd241713Smrg
220cd241713Smrg#if 1
221cd241713Smrg                /* This works for double scan mode. */
222cd241713Smrg    save->crtc2_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff)
223cd241713Smrg                  | ((mode->CrtcVDisplay - 1) << 16));
224cd241713Smrg#else
225cd241713Smrg                /* This is what cce/nbmode.c example code
226cd241713Smrg                   does -- is this correct? */
227cd241713Smrg    save->crtc2_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff)
228cd241713Smrg                  | ((mode->CrtcVDisplay
229cd241713Smrg                  * ((mode->Flags & V_DBLSCAN) ? 2 : 1) - 1)
230cd241713Smrg                 << 16));
231cd241713Smrg#endif
232cd241713Smrg
233cd241713Smrg    vsync_wid = mode->CrtcVSyncEnd - mode->CrtcVSyncStart;
234cd241713Smrg    if (!vsync_wid)       vsync_wid = 1;
235cd241713Smrg    if (vsync_wid > 0x1f) vsync_wid = 0x1f;
236cd241713Smrg
237cd241713Smrg    save->crtc2_v_sync_strt_wid = (((mode->CrtcVSyncStart - 1) & 0xfff)
238cd241713Smrg                 | (vsync_wid << 16)
239cd241713Smrg                 | ((mode->Flags & V_NVSYNC)
240cd241713Smrg                    ? R128_CRTC2_V_SYNC_POL
241cd241713Smrg                    : 0));
242cd241713Smrg    save->crtc2_pitch       = info->CurrentLayout.displayWidth / 8;
243cd241713Smrg
244cd241713Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
245cd241713Smrg                        "Pitch = %d bytes (virtualX = %d, "
246cd241713Smrg                        "displayWidth = %d)\n",
247cd241713Smrg                        save->crtc2_pitch, pScrn->virtualX,
248cd241713Smrg                        info->CurrentLayout.displayWidth));
249cd241713Smrg    return TRUE;
250cd241713Smrg}
251cd241713Smrg
252cd241713Smrg/* Write CRTC registers. */
253cd241713Smrgvoid R128RestoreCrtcRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
254cd241713Smrg{
255cd241713Smrg    R128InfoPtr   info      = R128PTR(pScrn);
256cd241713Smrg    unsigned char *R128MMIO = info->MMIO;
257cd241713Smrg
258cd241713Smrg    OUTREG(R128_CRTC_GEN_CNTL,        restore->crtc_gen_cntl);
259cd241713Smrg
260cd241713Smrg    OUTREGP(R128_CRTC_EXT_CNTL, restore->crtc_ext_cntl,
261cd241713Smrg        R128_CRTC_VSYNC_DIS | R128_CRTC_HSYNC_DIS | R128_CRTC_DISPLAY_DIS);
262cd241713Smrg
263cd241713Smrg    OUTREG(R128_CRTC_H_TOTAL_DISP,    restore->crtc_h_total_disp);
264cd241713Smrg    OUTREG(R128_CRTC_H_SYNC_STRT_WID, restore->crtc_h_sync_strt_wid);
265cd241713Smrg    OUTREG(R128_CRTC_V_TOTAL_DISP,    restore->crtc_v_total_disp);
266cd241713Smrg    OUTREG(R128_CRTC_V_SYNC_STRT_WID, restore->crtc_v_sync_strt_wid);
267cd241713Smrg    OUTREG(R128_CRTC_OFFSET,          restore->crtc_offset);
268cd241713Smrg    OUTREG(R128_CRTC_OFFSET_CNTL,     restore->crtc_offset_cntl);
269cd241713Smrg    OUTREG(R128_CRTC_PITCH,           restore->crtc_pitch);
270cd241713Smrg}
271cd241713Smrg
272cd241713Smrg/* Write CRTC2 registers. */
273cd241713Smrgvoid R128RestoreCrtc2Registers(ScrnInfoPtr pScrn, R128SavePtr restore)
274cd241713Smrg{
275cd241713Smrg    R128InfoPtr info        = R128PTR(pScrn);
276cd241713Smrg    unsigned char *R128MMIO = info->MMIO;
277cd241713Smrg
278cd241713Smrg    OUTREGP(R128_CRTC2_GEN_CNTL, restore->crtc2_gen_cntl,
279cd241713Smrg        R128_CRTC2_DISP_DIS);
280cd241713Smrg
281cd241713Smrg    OUTREG(R128_CRTC2_H_TOTAL_DISP,    restore->crtc2_h_total_disp);
282cd241713Smrg    OUTREG(R128_CRTC2_H_SYNC_STRT_WID, restore->crtc2_h_sync_strt_wid);
283cd241713Smrg    OUTREG(R128_CRTC2_V_TOTAL_DISP,    restore->crtc2_v_total_disp);
284cd241713Smrg    OUTREG(R128_CRTC2_V_SYNC_STRT_WID, restore->crtc2_v_sync_strt_wid);
285cd241713Smrg    OUTREG(R128_CRTC2_OFFSET,          restore->crtc2_offset);
286cd241713Smrg    OUTREG(R128_CRTC2_OFFSET_CNTL,     restore->crtc2_offset_cntl);
287cd241713Smrg    OUTREG(R128_CRTC2_PITCH,           restore->crtc2_pitch);
288cd241713Smrg}
289cd241713Smrg
290cd241713Smrgstatic Bool R128InitCrtcBase(xf86CrtcPtr crtc, R128SavePtr save, int x, int y)
291cd241713Smrg{
292cd241713Smrg    ScrnInfoPtr pScrn = crtc->scrn;
293cd241713Smrg    R128InfoPtr info  = R128PTR(pScrn);
294cd241713Smrg    int offset = y * info->CurrentLayout.displayWidth + x;
295cd241713Smrg    int Base = pScrn->fbOffset;
296cd241713Smrg
297cd241713Smrg    switch (info->CurrentLayout.pixel_code) {
298cd241713Smrg    case 15:
299cd241713Smrg    case 16: offset *= 2; break;
300cd241713Smrg    case 24: offset *= 3; break;
301cd241713Smrg    case 32: offset *= 4; break;
302cd241713Smrg    }
303cd241713Smrg    Base += offset;
304cd241713Smrg
305cd241713Smrg    if (crtc->rotatedData != NULL)
306cd241713Smrg        Base = pScrn->fbOffset + (char *)crtc->rotatedData - (char *)info->FB;
307cd241713Smrg
308cd241713Smrg    Base &= ~7;                 /* 3 lower bits are always 0 */
309cd241713Smrg    if (info->CurrentLayout.pixel_code == 24)
310cd241713Smrg    Base += 8 * (Base % 3); /* Must be multiple of 8 and 3 */
311cd241713Smrg
312cd241713Smrg    save->crtc_offset = Base;
313cd241713Smrg    save->crtc_offset_cntl = 0;
314cd241713Smrg
315cd241713Smrg    return TRUE;
316cd241713Smrg}
317cd241713Smrg
318cd241713Smrgstatic Bool R128InitCrtc2Base(xf86CrtcPtr crtc, R128SavePtr save, int x, int y)
319cd241713Smrg{
320cd241713Smrg    ScrnInfoPtr pScrn = crtc->scrn;
321cd241713Smrg    R128InfoPtr info  = R128PTR(pScrn);
322cd241713Smrg    int offset = y * info->CurrentLayout.displayWidth + x;
323cd241713Smrg    int Base = pScrn->fbOffset;
324cd241713Smrg
325cd241713Smrg    switch (info->CurrentLayout.pixel_code) {
326cd241713Smrg    case 15:
327cd241713Smrg    case 16: offset *= 2; break;
328cd241713Smrg    case 24: offset *= 3; break;
329cd241713Smrg    case 32: offset *= 4; break;
330cd241713Smrg    }
331cd241713Smrg    Base += offset;
332cd241713Smrg
333cd241713Smrg    if (crtc->rotatedData != NULL)
334cd241713Smrg        Base = pScrn->fbOffset + (char *)crtc->rotatedData - (char *)info->FB;
335cd241713Smrg
336cd241713Smrg    Base &= ~7;                 /* 3 lower bits are always 0 */
337cd241713Smrg    if (info->CurrentLayout.pixel_code == 24)
338cd241713Smrg    Base += 8 * (Base % 3); /* Must be multiple of 8 and 3 */
339cd241713Smrg
340cd241713Smrg    save->crtc2_offset = Base;
341cd241713Smrg    save->crtc2_offset_cntl = 0;
342cd241713Smrg
343cd241713Smrg    return TRUE;
344cd241713Smrg}
345cd241713Smrg
346cd241713Smrg/* Define PLL registers for requested video mode. */
347cd241713Smrgstatic void R128InitPLLRegisters(xf86CrtcPtr crtc, R128SavePtr save,
348cd241713Smrg                R128PLLPtr pll, double dot_clock)
349cd241713Smrg{
350cd241713Smrg#if R128_DEBUG
351cd241713Smrg    ScrnInfoPtr pScrn  = crtc->scrn;
352cd241713Smrg#endif
353cd241713Smrg    unsigned long freq = dot_clock * 100;
354cd241713Smrg    struct {
355cd241713Smrg    int divider;
356cd241713Smrg    int bitvalue;
357cd241713Smrg    } *post_div,
358cd241713Smrg      post_divs[]   = {
359cd241713Smrg                /* From RAGE 128 VR/RAGE 128 GL Register
360cd241713Smrg                   Reference Manual (Technical Reference
361cd241713Smrg                   Manual P/N RRG-G04100-C Rev. 0.04), page
362cd241713Smrg                   3-17 (PLL_DIV_[3:0]).  */
363cd241713Smrg    {  1, 0 },              /* VCLK_SRC                 */
364cd241713Smrg    {  2, 1 },              /* VCLK_SRC/2               */
365cd241713Smrg    {  4, 2 },              /* VCLK_SRC/4               */
366cd241713Smrg    {  8, 3 },              /* VCLK_SRC/8               */
367cd241713Smrg
368cd241713Smrg    {  3, 4 },              /* VCLK_SRC/3               */
369cd241713Smrg                /* bitvalue = 5 is reserved */
370cd241713Smrg    {  6, 6 },              /* VCLK_SRC/6               */
371cd241713Smrg    { 12, 7 },              /* VCLK_SRC/12              */
372cd241713Smrg    {  0, 0 }
373cd241713Smrg    };
374cd241713Smrg
375cd241713Smrg    if (freq > pll->max_pll_freq)      freq = pll->max_pll_freq;
376cd241713Smrg    if (freq * 12 < pll->min_pll_freq) freq = pll->min_pll_freq / 12;
377cd241713Smrg
378cd241713Smrg    for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
379cd241713Smrg    save->pll_output_freq = post_div->divider * freq;
380cd241713Smrg    if (save->pll_output_freq >= pll->min_pll_freq
381cd241713Smrg        && save->pll_output_freq <= pll->max_pll_freq) break;
382cd241713Smrg    }
383cd241713Smrg
384cd241713Smrg    save->dot_clock_freq = freq;
385cd241713Smrg    save->feedback_div   = R128Div(pll->reference_div * save->pll_output_freq,
386cd241713Smrg                   pll->reference_freq);
387cd241713Smrg    save->post_div       = post_div->divider;
388cd241713Smrg
389cd241713Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
390cd241713Smrg                        "dc=%d, of=%d, fd=%d, pd=%d\n",
391cd241713Smrg                        save->dot_clock_freq,
392cd241713Smrg                        save->pll_output_freq,
393cd241713Smrg                        save->feedback_div,
394cd241713Smrg                        save->post_div));
395cd241713Smrg
396cd241713Smrg    save->ppll_ref_div   = pll->reference_div;
397cd241713Smrg    save->ppll_div_3     = (save->feedback_div | (post_div->bitvalue << 16));
398cd241713Smrg    save->htotal_cntl    = 0;
399cd241713Smrg
400cd241713Smrg}
401cd241713Smrg
402cd241713Smrg/* Define PLL2 registers for requested video mode. */
403cd241713Smrgvoid R128InitPLL2Registers(xf86CrtcPtr crtc, R128SavePtr save,
404cd241713Smrg                   R128PLLPtr pll, double dot_clock)
405cd241713Smrg{
406cd241713Smrg#if R128_DEBUG
407cd241713Smrg    ScrnInfoPtr pScrn  = crtc->scrn;
408cd241713Smrg#endif
409cd241713Smrg    unsigned long freq = dot_clock * 100;
410cd241713Smrg    struct {
411cd241713Smrg    int divider;
412cd241713Smrg    int bitvalue;
413cd241713Smrg    } *post_div,
414cd241713Smrg      post_divs[]   = {
415cd241713Smrg                /* From RAGE 128 VR/RAGE 128 GL Register
416cd241713Smrg                   Reference Manual (Technical Reference
417cd241713Smrg                   Manual P/N RRG-G04100-C Rev. 0.04), page
418cd241713Smrg                   3-17 (PLL_DIV_[3:0]).  */
419cd241713Smrg    {  1, 0 },              /* VCLK_SRC                 */
420cd241713Smrg    {  2, 1 },              /* VCLK_SRC/2               */
421cd241713Smrg    {  4, 2 },              /* VCLK_SRC/4               */
422cd241713Smrg    {  8, 3 },              /* VCLK_SRC/8               */
423cd241713Smrg
424cd241713Smrg    {  3, 4 },              /* VCLK_SRC/3               */
425cd241713Smrg                /* bitvalue = 5 is reserved */
426cd241713Smrg    {  6, 6 },              /* VCLK_SRC/6               */
427cd241713Smrg    { 12, 7 },              /* VCLK_SRC/12              */
428cd241713Smrg    {  0, 0 }
429cd241713Smrg    };
430cd241713Smrg
431cd241713Smrg    if (freq > pll->max_pll_freq)      freq = pll->max_pll_freq;
432cd241713Smrg    if (freq * 12 < pll->min_pll_freq) freq = pll->min_pll_freq / 12;
433cd241713Smrg
434cd241713Smrg    for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
435cd241713Smrg    save->pll_output_freq_2 = post_div->divider * freq;
436cd241713Smrg    if (save->pll_output_freq_2 >= pll->min_pll_freq
437cd241713Smrg        && save->pll_output_freq_2 <= pll->max_pll_freq) break;
438cd241713Smrg    }
439cd241713Smrg
440cd241713Smrg    save->dot_clock_freq_2 = freq;
441cd241713Smrg    save->feedback_div_2   = R128Div(pll->reference_div
442cd241713Smrg                     * save->pll_output_freq_2,
443cd241713Smrg                     pll->reference_freq);
444cd241713Smrg    save->post_div_2       = post_div->divider;
445cd241713Smrg
446cd241713Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
447cd241713Smrg                        "dc=%d, of=%d, fd=%d, pd=%d\n",
448cd241713Smrg                        save->dot_clock_freq_2,
449cd241713Smrg                        save->pll_output_freq_2,
450cd241713Smrg                        save->feedback_div_2,
451cd241713Smrg                        save->post_div_2));
452cd241713Smrg
453cd241713Smrg    save->p2pll_ref_div   = pll->reference_div;
454cd241713Smrg    save->p2pll_div_0    = (save->feedback_div_2 | (post_div->bitvalue<<16));
455cd241713Smrg    save->htotal_cntl2    = 0;
456cd241713Smrg}
457cd241713Smrg
458cd241713Smrgstatic void R128PLLWaitForReadUpdateComplete(ScrnInfoPtr pScrn)
459cd241713Smrg{
460cd241713Smrg    while (INPLL(pScrn, R128_PPLL_REF_DIV) & R128_PPLL_ATOMIC_UPDATE_R);
461cd241713Smrg}
462cd241713Smrg
463cd241713Smrgstatic void R128PLLWriteUpdate(ScrnInfoPtr pScrn)
464cd241713Smrg{
465cd241713Smrg    R128InfoPtr   info      = R128PTR(pScrn);
466cd241713Smrg    unsigned char *R128MMIO = info->MMIO;
467cd241713Smrg
468cd241713Smrg    while (INPLL(pScrn, R128_PPLL_REF_DIV) & R128_PPLL_ATOMIC_UPDATE_R);
469cd241713Smrg
470cd241713Smrg    OUTPLLP(pScrn, R128_PPLL_REF_DIV, R128_PPLL_ATOMIC_UPDATE_W,
471cd241713Smrg        ~R128_PPLL_ATOMIC_UPDATE_W);
472cd241713Smrg
473cd241713Smrg}
474cd241713Smrg
475cd241713Smrgstatic void R128PLL2WaitForReadUpdateComplete(ScrnInfoPtr pScrn)
476cd241713Smrg{
477cd241713Smrg    while (INPLL(pScrn, R128_P2PLL_REF_DIV) & R128_P2PLL_ATOMIC_UPDATE_R);
478cd241713Smrg}
479cd241713Smrg
480cd241713Smrgstatic void R128PLL2WriteUpdate(ScrnInfoPtr pScrn)
481cd241713Smrg{
482cd241713Smrg    R128InfoPtr  info       = R128PTR(pScrn);
483cd241713Smrg    unsigned char *R128MMIO = info->MMIO;
484cd241713Smrg
485cd241713Smrg    while (INPLL(pScrn, R128_P2PLL_REF_DIV) & R128_P2PLL_ATOMIC_UPDATE_R);
486cd241713Smrg
487cd241713Smrg    OUTPLLP(pScrn, R128_P2PLL_REF_DIV,
488cd241713Smrg        R128_P2PLL_ATOMIC_UPDATE_W,
489cd241713Smrg        ~(R128_P2PLL_ATOMIC_UPDATE_W));
490cd241713Smrg}
491cd241713Smrg
492cd241713Smrg/* Write PLL registers. */
493cd241713Smrgvoid R128RestorePLLRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
494cd241713Smrg{
495cd241713Smrg    R128InfoPtr   info      = R128PTR(pScrn);
496cd241713Smrg    unsigned char *R128MMIO = info->MMIO;
497cd241713Smrg
498cd241713Smrg
499cd241713Smrg    OUTPLLP(pScrn, R128_VCLK_ECP_CNTL,
500cd241713Smrg        R128_VCLK_SRC_SEL_CPUCLK,
501cd241713Smrg        ~(R128_VCLK_SRC_SEL_MASK));
502cd241713Smrg
503cd241713Smrg    OUTPLLP(pScrn,
504cd241713Smrg        R128_PPLL_CNTL,
505cd241713Smrg        R128_PPLL_RESET
506cd241713Smrg        | R128_PPLL_ATOMIC_UPDATE_EN
507cd241713Smrg        | R128_PPLL_VGA_ATOMIC_UPDATE_EN,
508cd241713Smrg        ~(R128_PPLL_RESET
509cd241713Smrg          | R128_PPLL_ATOMIC_UPDATE_EN
510cd241713Smrg          | R128_PPLL_VGA_ATOMIC_UPDATE_EN));
511cd241713Smrg
512cd241713Smrg    OUTREGP(R128_CLOCK_CNTL_INDEX, R128_PLL_DIV_SEL, ~(R128_PLL_DIV_SEL));
513cd241713Smrg
514cd241713Smrg/*        R128PLLWaitForReadUpdateComplete(pScrn);*/
515cd241713Smrg    OUTPLLP(pScrn, R128_PPLL_REF_DIV,
516cd241713Smrg        restore->ppll_ref_div, ~R128_PPLL_REF_DIV_MASK);
517cd241713Smrg/*        R128PLLWriteUpdate(pScrn);
518cd241713Smrg
519cd241713Smrg        R128PLLWaitForReadUpdateComplete(pScrn);*/
520cd241713Smrg    OUTPLLP(pScrn, R128_PPLL_DIV_3,
521cd241713Smrg        restore->ppll_div_3, ~R128_PPLL_FB3_DIV_MASK);
522cd241713Smrg/*    R128PLLWriteUpdate(pScrn);*/
523cd241713Smrg    OUTPLLP(pScrn, R128_PPLL_DIV_3,
524cd241713Smrg        restore->ppll_div_3, ~R128_PPLL_POST3_DIV_MASK);
525cd241713Smrg
526cd241713Smrg    R128PLLWriteUpdate(pScrn);
527cd241713Smrg    R128PLLWaitForReadUpdateComplete(pScrn);
528cd241713Smrg
529cd241713Smrg    OUTPLLP(pScrn, R128_PPLL_DIV_0,
530cd241713Smrg        restore->ppll_div_0, ~R128_PPLL_FB0_DIV_MASK);
531cd241713Smrg/*    R128PLLWriteUpdate(pScrn);*/
532cd241713Smrg    OUTPLLP(pScrn, R128_PPLL_DIV_0,
533cd241713Smrg        restore->ppll_div_0, ~R128_PPLL_POST0_DIV_MASK);
534cd241713Smrg
535cd241713Smrg    R128PLLWriteUpdate(pScrn);
536cd241713Smrg    R128PLLWaitForReadUpdateComplete(pScrn);
537cd241713Smrg
538cd241713Smrg    OUTPLL(R128_HTOTAL_CNTL, restore->htotal_cntl);
539cd241713Smrg/*    R128PLLWriteUpdate(pScrn);*/
540cd241713Smrg
541cd241713Smrg    OUTPLLP(pScrn, R128_PPLL_CNTL, 0, ~(R128_PPLL_RESET
542cd241713Smrg                    | R128_PPLL_SLEEP
543cd241713Smrg                    | R128_PPLL_ATOMIC_UPDATE_EN
544cd241713Smrg                    | R128_PPLL_VGA_ATOMIC_UPDATE_EN));
545cd241713Smrg
546cd241713Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
547cd241713Smrg                        "Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n",
548cd241713Smrg                        restore->ppll_ref_div,
549cd241713Smrg                        restore->ppll_div_3,
550cd241713Smrg                        restore->htotal_cntl,
551cd241713Smrg                        INPLL(pScrn, R128_PPLL_CNTL)));
552cd241713Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
553cd241713Smrg                        "Wrote: rd=%d, fd=%d, pd=%d\n",
554cd241713Smrg                        restore->ppll_ref_div & R128_PPLL_REF_DIV_MASK,
555cd241713Smrg                        restore->ppll_div_3 & R128_PPLL_FB3_DIV_MASK,
556cd241713Smrg                        (restore->ppll_div_3 &
557cd241713Smrg                                R128_PPLL_POST3_DIV_MASK) >> 16));
558cd241713Smrg
559cd241713Smrg    usleep(5000); /* let the clock lock */
560cd241713Smrg
561cd241713Smrg    OUTPLLP(pScrn, R128_VCLK_ECP_CNTL,
562cd241713Smrg        R128_VCLK_SRC_SEL_PPLLCLK,
563cd241713Smrg        ~(R128_VCLK_SRC_SEL_MASK));
564cd241713Smrg
565cd241713Smrg}
566cd241713Smrg
567cd241713Smrg/* Write PLL2 registers. */
568cd241713Smrgvoid R128RestorePLL2Registers(ScrnInfoPtr pScrn, R128SavePtr restore)
569cd241713Smrg{
570cd241713Smrg    R128InfoPtr info        = R128PTR(pScrn);
571cd241713Smrg    unsigned char *R128MMIO = info->MMIO;
572cd241713Smrg
573cd241713Smrg    OUTPLLP(pScrn, R128_V2CLK_VCLKTV_CNTL,
574cd241713Smrg        R128_V2CLK_SRC_SEL_CPUCLK,
575cd241713Smrg        ~R128_V2CLK_SRC_SEL_MASK);
576cd241713Smrg
577cd241713Smrg    OUTPLLP(pScrn,
578cd241713Smrg        R128_P2PLL_CNTL,
579cd241713Smrg        R128_P2PLL_RESET
580cd241713Smrg        | R128_P2PLL_ATOMIC_UPDATE_EN
581cd241713Smrg        | R128_P2PLL_VGA_ATOMIC_UPDATE_EN,
582cd241713Smrg        ~(R128_P2PLL_RESET
583cd241713Smrg          | R128_P2PLL_ATOMIC_UPDATE_EN
584cd241713Smrg          | R128_P2PLL_VGA_ATOMIC_UPDATE_EN));
585cd241713Smrg
586cd241713Smrg#if 1
587cd241713Smrg    OUTREGP(R128_CLOCK_CNTL_INDEX, 0, R128_PLL2_DIV_SEL_MASK);
588cd241713Smrg#endif
589cd241713Smrg
590cd241713Smrg        /*R128PLL2WaitForReadUpdateComplete(pScrn);*/
591cd241713Smrg
592cd241713Smrg    OUTPLLP(pScrn, R128_P2PLL_REF_DIV, restore->p2pll_ref_div, ~R128_P2PLL_REF_DIV_MASK);
593cd241713Smrg
594cd241713Smrg/*        R128PLL2WriteUpdate(pScrn);
595cd241713Smrg    R128PLL2WaitForReadUpdateComplete(pScrn);*/
596cd241713Smrg
597cd241713Smrg    OUTPLLP(pScrn, R128_P2PLL_DIV_0,
598cd241713Smrg            restore->p2pll_div_0, ~R128_P2PLL_FB0_DIV_MASK);
599cd241713Smrg
600cd241713Smrg/*    R128PLL2WriteUpdate(pScrn);
601cd241713Smrg    R128PLL2WaitForReadUpdateComplete(pScrn);*/
602cd241713Smrg
603cd241713Smrg    OUTPLLP(pScrn, R128_P2PLL_DIV_0,
604cd241713Smrg            restore->p2pll_div_0, ~R128_P2PLL_POST0_DIV_MASK);
605cd241713Smrg
606cd241713Smrg    R128PLL2WriteUpdate(pScrn);
607cd241713Smrg    R128PLL2WaitForReadUpdateComplete(pScrn);
608cd241713Smrg
609cd241713Smrg    OUTPLL(R128_HTOTAL2_CNTL, restore->htotal_cntl2);
610cd241713Smrg
611cd241713Smrg/*        R128PLL2WriteUpdate(pScrn);*/
612cd241713Smrg
613cd241713Smrg    OUTPLLP(pScrn, R128_P2PLL_CNTL, 0, ~(R128_P2PLL_RESET
614cd241713Smrg                    | R128_P2PLL_SLEEP
615cd241713Smrg                    | R128_P2PLL_ATOMIC_UPDATE_EN
616cd241713Smrg                    | R128_P2PLL_VGA_ATOMIC_UPDATE_EN));
617cd241713Smrg
618cd241713Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
619cd241713Smrg                        "Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n",
620cd241713Smrg                        restore->p2pll_ref_div,
621cd241713Smrg                        restore->p2pll_div_0,
622cd241713Smrg                        restore->htotal_cntl2,
623cd241713Smrg                        INPLL(pScrn, R128_P2PLL_CNTL)));
624cd241713Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
625cd241713Smrg                        "Wrote: rd=%d, fd=%d, pd=%d\n",
626cd241713Smrg                        restore->p2pll_ref_div & R128_P2PLL_REF_DIV_MASK,
627cd241713Smrg                        restore->p2pll_div_0 & R128_P2PLL_FB0_DIV_MASK,
628cd241713Smrg                        (restore->p2pll_div_0 &
629cd241713Smrg                                R128_P2PLL_POST0_DIV_MASK) >>16));
630cd241713Smrg
631cd241713Smrg    usleep(5000); /* Let the clock to lock */
632cd241713Smrg
633cd241713Smrg    OUTPLLP(pScrn, R128_V2CLK_VCLKTV_CNTL,
634cd241713Smrg        R128_V2CLK_SRC_SEL_P2PLLCLK,
635cd241713Smrg        ~R128_V2CLK_SRC_SEL_MASK);
636cd241713Smrg
637cd241713Smrg}
638cd241713Smrg
639cd241713Smrg/* Define DDA registers for requested video mode. */
640cd241713SmrgBool R128InitDDARegisters(xf86CrtcPtr crtc, R128SavePtr save,
641cd241713Smrg                 R128PLLPtr pll, DisplayModePtr mode)
642cd241713Smrg{
643cd241713Smrg    ScrnInfoPtr pScrn = crtc->scrn;
644cd241713Smrg    R128InfoPtr info  = R128PTR(pScrn);
645cd241713Smrg    xf86OutputPtr output = R128FirstOutput(crtc);
646cd241713Smrg    R128OutputPrivatePtr r128_output = output->driver_private;
647cd241713Smrg
648cd241713Smrg    int         DisplayFifoWidth = 128;
649cd241713Smrg    int         DisplayFifoDepth = 32;
650cd241713Smrg    int         XclkFreq;
651cd241713Smrg    int         VclkFreq;
652cd241713Smrg    int         XclksPerTransfer;
653cd241713Smrg    int         XclksPerTransferPrecise;
654cd241713Smrg    int         UseablePrecision;
655cd241713Smrg    int         Roff;
656cd241713Smrg    int         Ron;
657cd241713Smrg
658cd241713Smrg    XclkFreq = pll->xclk;
659cd241713Smrg
660cd241713Smrg    VclkFreq = R128Div(pll->reference_freq * save->feedback_div,
661cd241713Smrg               pll->reference_div * save->post_div);
662cd241713Smrg
663cd241713Smrg    if (info->isDFP && !info->isPro2 && r128_output->PanelXRes > 0) {
664cd241713Smrg        if (r128_output->PanelXRes != mode->CrtcHDisplay)
665cd241713Smrg            VclkFreq = (VclkFreq * mode->CrtcHDisplay) / r128_output->PanelXRes;
666cd241713Smrg    }
667cd241713Smrg
668cd241713Smrg    XclksPerTransfer = R128Div(XclkFreq * DisplayFifoWidth,
669cd241713Smrg                   VclkFreq * (info->CurrentLayout.pixel_bytes * 8));
670cd241713Smrg
671cd241713Smrg    UseablePrecision = R128MinBits(XclksPerTransfer) + 1;
672cd241713Smrg
673cd241713Smrg    XclksPerTransferPrecise = R128Div((XclkFreq * DisplayFifoWidth)
674cd241713Smrg                      << (11 - UseablePrecision),
675cd241713Smrg                      VclkFreq * (info->CurrentLayout.pixel_bytes * 8));
676cd241713Smrg
677cd241713Smrg    Roff  = XclksPerTransferPrecise * (DisplayFifoDepth - 4);
678cd241713Smrg
679cd241713Smrg    Ron   = (4 * info->ram->MB
680cd241713Smrg         + 3 * MAX(info->ram->Trcd - 2, 0)
681cd241713Smrg         + 2 * info->ram->Trp
682cd241713Smrg         + info->ram->Twr
683cd241713Smrg         + info->ram->CL
684cd241713Smrg         + info->ram->Tr2w
685cd241713Smrg         + XclksPerTransfer) << (11 - UseablePrecision);
686cd241713Smrg
687cd241713Smrg    if (Ron + info->ram->Rloop >= Roff) {
688cd241713Smrg    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
689cd241713Smrg           "(Ron = %d) + (Rloop = %d) >= (Roff = %d)\n",
690cd241713Smrg           Ron, info->ram->Rloop, Roff);
691cd241713Smrg    return FALSE;
692cd241713Smrg    }
693cd241713Smrg
694cd241713Smrg    save->dda_config = (XclksPerTransferPrecise
695cd241713Smrg            | (UseablePrecision << 16)
696cd241713Smrg            | (info->ram->Rloop << 20));
697cd241713Smrg
698cd241713Smrg    save->dda_on_off = (Ron << 16) | Roff;
699cd241713Smrg
700cd241713Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
701cd241713Smrg                        "XclkFreq = %d; VclkFreq = %d; "
7028ce07328Smrg                        "per = %d, %d (usable = %d)\n",
703cd241713Smrg                        XclkFreq,
704cd241713Smrg                        VclkFreq,
705cd241713Smrg                        XclksPerTransfer,
706cd241713Smrg                        XclksPerTransferPrecise,
707cd241713Smrg                        UseablePrecision));
708cd241713Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
709cd241713Smrg                        "Roff = %d, Ron = %d, Rloop = %d\n",
710cd241713Smrg                        Roff, Ron, info->ram->Rloop));
711cd241713Smrg
712cd241713Smrg    return TRUE;
713cd241713Smrg}
714cd241713Smrg
715cd241713Smrg/* Define DDA2 registers for requested video mode. */
716cd241713SmrgBool R128InitDDA2Registers(xf86CrtcPtr crtc, R128SavePtr save,
717cd241713Smrg                 R128PLLPtr pll, DisplayModePtr mode)
718cd241713Smrg{
719cd241713Smrg    ScrnInfoPtr pScrn = crtc->scrn;
720cd241713Smrg    R128InfoPtr info  = R128PTR(pScrn);
721cd241713Smrg    xf86OutputPtr output = R128FirstOutput(crtc);
722cd241713Smrg    R128OutputPrivatePtr r128_output = output->driver_private;
723cd241713Smrg
724cd241713Smrg    int         DisplayFifoWidth = 128;
725cd241713Smrg    int         DisplayFifoDepth = 32;
726cd241713Smrg    int         XclkFreq;
727cd241713Smrg    int         VclkFreq;
728cd241713Smrg    int         XclksPerTransfer;
729cd241713Smrg    int         XclksPerTransferPrecise;
730cd241713Smrg    int         UseablePrecision;
731cd241713Smrg    int         Roff;
732cd241713Smrg    int         Ron;
733cd241713Smrg
734cd241713Smrg    XclkFreq = pll->xclk;
735cd241713Smrg
736cd241713Smrg    VclkFreq = R128Div(pll->reference_freq * save->feedback_div_2,
737cd241713Smrg               pll->reference_div * save->post_div_2);
738cd241713Smrg
739cd241713Smrg    if (info->isDFP && !info->isPro2 && r128_output->PanelXRes > 0) {
740cd241713Smrg        if (r128_output->PanelXRes != mode->CrtcHDisplay)
741cd241713Smrg            VclkFreq = (VclkFreq * mode->CrtcHDisplay) / r128_output->PanelXRes;
742cd241713Smrg    }
743cd241713Smrg
744cd241713Smrg    XclksPerTransfer = R128Div(XclkFreq * DisplayFifoWidth,
745cd241713Smrg                   VclkFreq * (info->CurrentLayout.pixel_bytes * 8));
746cd241713Smrg
747cd241713Smrg    UseablePrecision = R128MinBits(XclksPerTransfer) + 1;
748cd241713Smrg
749cd241713Smrg    XclksPerTransferPrecise = R128Div((XclkFreq * DisplayFifoWidth)
750cd241713Smrg                      << (11 - UseablePrecision),
751cd241713Smrg                      VclkFreq * (info->CurrentLayout.pixel_bytes * 8));
752cd241713Smrg
753cd241713Smrg    Roff  = XclksPerTransferPrecise * (DisplayFifoDepth - 4);
754cd241713Smrg
755cd241713Smrg    Ron   = (4 * info->ram->MB
756cd241713Smrg         + 3 * MAX(info->ram->Trcd - 2, 0)
757cd241713Smrg         + 2 * info->ram->Trp
758cd241713Smrg         + info->ram->Twr
759cd241713Smrg         + info->ram->CL
760cd241713Smrg         + info->ram->Tr2w
761cd241713Smrg         + XclksPerTransfer) << (11 - UseablePrecision);
762cd241713Smrg
763cd241713Smrg
764cd241713Smrg    if (Ron + info->ram->Rloop >= Roff) {
765cd241713Smrg    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
766cd241713Smrg           "(Ron = %d) + (Rloop = %d) >= (Roff = %d)\n",
767cd241713Smrg           Ron, info->ram->Rloop, Roff);
768cd241713Smrg    return FALSE;
769cd241713Smrg    }
770cd241713Smrg
771cd241713Smrg    save->dda2_config = (XclksPerTransferPrecise
772cd241713Smrg            | (UseablePrecision << 16)
773cd241713Smrg            | (info->ram->Rloop << 20));
774cd241713Smrg
775cd241713Smrg    /*save->dda2_on_off = (Ron << 16) | Roff;*/
776cd241713Smrg    /* shift most be 18 otherwise there's corruption on crtc2 */
777cd241713Smrg    save->dda2_on_off = (Ron << 18) | Roff;
778cd241713Smrg
779cd241713Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
780cd241713Smrg                        "XclkFreq = %d; VclkFreq = %d; "
7818ce07328Smrg                        "per = %d, %d (usable = %d)\n",
782cd241713Smrg                        XclkFreq,
783cd241713Smrg                        VclkFreq,
784cd241713Smrg                        XclksPerTransfer,
785cd241713Smrg                        XclksPerTransferPrecise,
786cd241713Smrg                        UseablePrecision));
787cd241713Smrg    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
788cd241713Smrg                        "Roff = %d, Ron = %d, Rloop = %d\n",
789cd241713Smrg                        Roff, Ron, info->ram->Rloop));
790cd241713Smrg
791cd241713Smrg    return TRUE;
792cd241713Smrg}
793cd241713Smrg
794e3d74329Smrgstatic void r128_crtc_load_lut(xf86CrtcPtr crtc);
795e3d74329Smrg
796e3d74329Smrgstatic void r128_crtc_dpms(xf86CrtcPtr crtc, int mode)
797e3d74329Smrg{
798e3d74329Smrg    int mask;
799e3d74329Smrg    ScrnInfoPtr pScrn = crtc->scrn;
800e3d74329Smrg    R128InfoPtr info = R128PTR(pScrn);
801e3d74329Smrg    unsigned char *R128MMIO = info->MMIO;
802e3d74329Smrg    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
803e3d74329Smrg
804e3d74329Smrg    /* XXX: The HSYNC and VSYNC bits for CRTC2 don't exist on the r128? */
805e3d74329Smrg    mask = r128_crtc->crtc_id ? R128_CRTC2_DISP_DIS : (R128_CRTC_DISPLAY_DIS | R128_CRTC_HSYNC_DIS | R128_CRTC_VSYNC_DIS);
806e3d74329Smrg
807e3d74329Smrg    switch (mode) {
808e3d74329Smrg    case DPMSModeOn:
809e3d74329Smrg        if (r128_crtc->crtc_id) {
810e3d74329Smrg            OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~mask);
811e3d74329Smrg        } else {
812e3d74329Smrg            OUTREGP(R128_CRTC_EXT_CNTL, 0, ~mask);
813e3d74329Smrg        }
814e3d74329Smrg        break;
815e3d74329Smrg    case DPMSModeStandby:
816e3d74329Smrg        if (r128_crtc->crtc_id) {
817e3d74329Smrg            OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_DISP_DIS, ~mask);
818e3d74329Smrg        } else {
819e3d74329Smrg            OUTREGP(R128_CRTC_EXT_CNTL, (R128_CRTC_DISPLAY_DIS | R128_CRTC_HSYNC_DIS), ~mask);
820e3d74329Smrg        }
821e3d74329Smrg        break;
822e3d74329Smrg    case DPMSModeSuspend:
823e3d74329Smrg        if (r128_crtc->crtc_id) {
824e3d74329Smrg            OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_DISP_DIS, ~mask);
825e3d74329Smrg        } else {
826e3d74329Smrg            OUTREGP(R128_CRTC_EXT_CNTL, (R128_CRTC_DISPLAY_DIS | R128_CRTC_VSYNC_DIS), ~mask);
827e3d74329Smrg        }
828e3d74329Smrg        break;
829e3d74329Smrg    case DPMSModeOff:
830e3d74329Smrg        if (r128_crtc->crtc_id) {
831e3d74329Smrg            OUTREGP(R128_CRTC2_GEN_CNTL, mask, ~mask);
832e3d74329Smrg        } else {
833e3d74329Smrg            OUTREGP(R128_CRTC_EXT_CNTL, mask, ~mask);
834e3d74329Smrg        }
835e3d74329Smrg        break;
836e3d74329Smrg    }
837e3d74329Smrg
838e3d74329Smrg    if (mode != DPMSModeOn) {
839e3d74329Smrg        if (r128_crtc->crtc_id) {
840e3d74329Smrg            OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~R128_CRTC2_EN);
841e3d74329Smrg        } else {
842e3d74329Smrg            OUTREGP(R128_CRTC_GEN_CNTL, 0, ~R128_CRTC_EN);
843e3d74329Smrg        }
844e3d74329Smrg    } else {
845e3d74329Smrg        if (r128_crtc->crtc_id) {
846e3d74329Smrg            OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_EN, ~R128_CRTC2_EN);
847e3d74329Smrg        } else {
848e3d74329Smrg            OUTREGP(R128_CRTC_GEN_CNTL, R128_CRTC_EN, ~R128_CRTC_EN);
849e3d74329Smrg        }
850e3d74329Smrg    }
851e3d74329Smrg
852e3d74329Smrg    if (mode != DPMSModeOff)
853e3d74329Smrg        r128_crtc_load_lut(crtc);
854e3d74329Smrg}
855e3d74329Smrg
856e3d74329Smrgvoid r128_crtc_load_lut(xf86CrtcPtr crtc)
857e3d74329Smrg{
858e3d74329Smrg    ScrnInfoPtr pScrn = crtc->scrn;
859e3d74329Smrg    R128InfoPtr info = R128PTR(pScrn);
860e3d74329Smrg    unsigned char *R128MMIO = info->MMIO;
861e3d74329Smrg    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
862e3d74329Smrg    int i;
863e3d74329Smrg
864e3d74329Smrg    if (!crtc->enabled)
865e3d74329Smrg        return;
866e3d74329Smrg
867e3d74329Smrg    PAL_SELECT(r128_crtc->crtc_id);
868e3d74329Smrg
869e3d74329Smrg    for (i = 0; i < 256; i++) {
870e3d74329Smrg        OUTPAL(i, r128_crtc->lut_r[i], r128_crtc->lut_g[i], r128_crtc->lut_b[i]);
871e3d74329Smrg    }
872e3d74329Smrg}
873e3d74329Smrg
874e3d74329Smrgstatic Bool r128_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode, DisplayModePtr adjusted_mode)
875e3d74329Smrg{
876e3d74329Smrg    return TRUE;
877e3d74329Smrg}
878e3d74329Smrg
879e3d74329Smrgstatic void r128_crtc_mode_prepare(xf86CrtcPtr crtc)
880e3d74329Smrg{
881e3d74329Smrg    r128_crtc_dpms(crtc, DPMSModeOff);
882e3d74329Smrg}
883e3d74329Smrg
884e3d74329Smrgstatic void r128_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode, DisplayModePtr adjusted_mode, int x, int y)
885e3d74329Smrg{
886e3d74329Smrg    ScrnInfoPtr pScrn = crtc->scrn;
887e3d74329Smrg    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
888e3d74329Smrg    R128InfoPtr info = R128PTR(pScrn);
889e3d74329Smrg    double dot_clock = adjusted_mode->Clock / 1000.0;
890e3d74329Smrg
891e3d74329Smrg    if (r128_crtc->cursor_offset) r128_crtc_hide_cursor(crtc);
892e3d74329Smrg    xf86PrintModeline(pScrn->scrnIndex, adjusted_mode);
893e3d74329Smrg    R128InitCommonRegisters(&info->ModeReg, info);
894e3d74329Smrg
895e3d74329Smrg    switch (r128_crtc->crtc_id) {
896e3d74329Smrg    case 0:
897e3d74329Smrg        R128InitCrtcRegisters(crtc, &info->ModeReg, adjusted_mode);
898e3d74329Smrg	R128InitCrtcBase(crtc, &info->ModeReg, x, y);
899e3d74329Smrg        if (dot_clock) {
900e3d74329Smrg            R128InitPLLRegisters(crtc, &info->ModeReg, &info->pll, dot_clock);
901e3d74329Smrg            R128InitDDARegisters(crtc, &info->ModeReg, &info->pll, adjusted_mode);
902e3d74329Smrg        } else {
903e3d74329Smrg            info->ModeReg.ppll_ref_div         = info->SavedReg.ppll_ref_div;
904e3d74329Smrg            info->ModeReg.ppll_div_3           = info->SavedReg.ppll_div_3;
905e3d74329Smrg            info->ModeReg.htotal_cntl          = info->SavedReg.htotal_cntl;
906e3d74329Smrg            info->ModeReg.dda_config           = info->SavedReg.dda_config;
907e3d74329Smrg            info->ModeReg.dda_on_off           = info->SavedReg.dda_on_off;
908e3d74329Smrg        }
909e3d74329Smrg        break;
910e3d74329Smrg    case 1:
911e3d74329Smrg        R128InitCrtc2Registers(crtc, &info->ModeReg, adjusted_mode);
912e3d74329Smrg	R128InitCrtc2Base(crtc, &info->ModeReg, x, y);
913e3d74329Smrg        if (dot_clock) {
914e3d74329Smrg            R128InitPLL2Registers(crtc, &info->ModeReg, &info->pll, dot_clock);
915e3d74329Smrg            R128InitDDA2Registers(crtc, &info->ModeReg, &info->pll, adjusted_mode);
916e3d74329Smrg        }
917e3d74329Smrg        break;
918e3d74329Smrg    }
919e3d74329Smrg
920e3d74329Smrg    R128RestoreCommonRegisters(pScrn, &info->ModeReg);
921e3d74329Smrg
922e3d74329Smrg    switch (r128_crtc->crtc_id) {
923e3d74329Smrg    case 0:
924e3d74329Smrg        R128RestoreDDARegisters(pScrn, &info->ModeReg);
925e3d74329Smrg        R128RestoreCrtcRegisters(pScrn, &info->ModeReg);
926e3d74329Smrg        R128RestorePLLRegisters(pScrn, &info->ModeReg);
927e3d74329Smrg        break;
928e3d74329Smrg    case 1:
929e3d74329Smrg        R128RestoreDDA2Registers(pScrn, &info->ModeReg);
930e3d74329Smrg        R128RestoreCrtc2Registers(pScrn, &info->ModeReg);
931e3d74329Smrg        R128RestorePLL2Registers(pScrn, &info->ModeReg);
932e3d74329Smrg	break;
933e3d74329Smrg    }
934e3d74329Smrg
935e3d74329Smrg    if (r128_crtc->cursor_offset) r128_crtc_show_cursor(crtc);
936e3d74329Smrg}
937e3d74329Smrg
938e3d74329Smrgstatic void r128_crtc_mode_commit(xf86CrtcPtr crtc)
939e3d74329Smrg{
940e3d74329Smrg    r128_crtc_dpms(crtc, DPMSModeOn);
941e3d74329Smrg}
942e3d74329Smrg
943e3d74329Smrgstatic void r128_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green, uint16_t *blue, int size)
944e3d74329Smrg{
945e3d74329Smrg    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
946e3d74329Smrg    int i;
947e3d74329Smrg
948e3d74329Smrg    for (i = 0; i < 256; i++) {
949e3d74329Smrg        r128_crtc->lut_r[i] = red[i] >> 8;
950e3d74329Smrg        r128_crtc->lut_g[i] = green[i] >> 8;
951e3d74329Smrg        r128_crtc->lut_b[i] = blue[i] >> 8;
952e3d74329Smrg    }
953e3d74329Smrg
954e3d74329Smrg    r128_crtc_load_lut(crtc);
955e3d74329Smrg}
956e3d74329Smrg
957e3d74329Smrgstatic Bool r128_crtc_lock(xf86CrtcPtr crtc)
958e3d74329Smrg{
959e3d74329Smrg    ScrnInfoPtr   pScrn   = crtc->scrn;
960e3d74329Smrg    ScreenPtr     pScreen = xf86ScrnToScreen(pScrn);
961e3d74329Smrg    R128InfoPtr   info    = R128PTR(pScrn);
962e3d74329Smrg
963e3d74329Smrg#ifdef HAVE_XAA_H
964e3d74329Smrg    if (info->accel) info->accel->Sync(pScrn);
965e3d74329Smrg#endif
966e3d74329Smrg#ifdef USE_EXA
967e3d74329Smrg    if (info->ExaDriver) exaWaitSync(pScreen);
968e3d74329Smrg#endif
969e3d74329Smrg
970e3d74329Smrg    return FALSE;
971e3d74329Smrg}
972e3d74329Smrg
973e3d74329Smrgstatic void r128_crtc_unlock(xf86CrtcPtr crtc)
974e3d74329Smrg{
975e3d74329Smrg    ScrnInfoPtr   pScrn   = crtc->scrn;
976e3d74329Smrg    ScreenPtr     pScreen = xf86ScrnToScreen(pScrn);
977e3d74329Smrg    R128InfoPtr   info    = R128PTR(pScrn);
978e3d74329Smrg
979e3d74329Smrg#ifdef HAVE_XAA_H
980e3d74329Smrg    if (info->accel) info->accel->Sync(pScrn);
981e3d74329Smrg#endif
982e3d74329Smrg#ifdef USE_EXA
983e3d74329Smrg    if (info->ExaDriver) exaWaitSync(pScreen);
984e3d74329Smrg#endif
985e3d74329Smrg}
986e3d74329Smrg
987e3d74329Smrgstatic void *r128_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
988e3d74329Smrg{
989e3d74329Smrg    ScrnInfoPtr   pScrn   = crtc->scrn;
990e3d74329Smrg    R128InfoPtr   info    = R128PTR(pScrn);
991e3d74329Smrg
992e3d74329Smrg    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
993e3d74329Smrg    unsigned long rotate_offset = 0;
994e3d74329Smrg    unsigned long rotate_pitch;
995e3d74329Smrg    int cpp = pScrn->bitsPerPixel / 8;
996e3d74329Smrg    int align = 4096;
997e3d74329Smrg    int size;
998e3d74329Smrg
999e3d74329Smrg    rotate_pitch = pScrn->displayWidth * cpp;
1000e3d74329Smrg    size = rotate_pitch * height;
1001e3d74329Smrg    rotate_offset = R128AllocateMemory(pScrn, &(r128_crtc->rotate_mem), size, align, TRUE);
1002e3d74329Smrg
1003e3d74329Smrg    /* If allocations failed or if there was no accel. */
1004e3d74329Smrg    if (rotate_offset == 0)
1005e3d74329Smrg        return NULL;
1006e3d74329Smrg
1007e3d74329Smrg    return info->FB + rotate_offset;
1008e3d74329Smrg}
1009e3d74329Smrg
1010e3d74329Smrgstatic PixmapPtr r128_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
1011e3d74329Smrg{
1012e3d74329Smrg    ScrnInfoPtr pScrn = crtc->scrn;
1013e3d74329Smrg    PixmapPtr rotate_pixmap;
1014e3d74329Smrg    unsigned long rotate_pitch;
1015e3d74329Smrg    int cpp = pScrn->bitsPerPixel / 8;
1016e3d74329Smrg
1017e3d74329Smrg    if (!data) data = r128_crtc_shadow_allocate(crtc, width, height);
1018e3d74329Smrg
1019e3d74329Smrg    rotate_pitch = pScrn->displayWidth * cpp;
1020e3d74329Smrg    rotate_pixmap = GetScratchPixmapHeader(xf86ScrnToScreen(pScrn),
1021e3d74329Smrg                                           width, height,
1022e3d74329Smrg                                           pScrn->depth,
1023e3d74329Smrg                                           pScrn->bitsPerPixel,
1024e3d74329Smrg                                           rotate_pitch,
1025e3d74329Smrg                                           data);
1026e3d74329Smrg
1027e3d74329Smrg    if (rotate_pixmap == NULL) {
1028e3d74329Smrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1029e3d74329Smrg                   "Couldn't allocate shadow memory for rotated CRTC\n");
1030e3d74329Smrg        return NULL;
1031e3d74329Smrg    }
1032e3d74329Smrg
1033e3d74329Smrg    return rotate_pixmap;
1034e3d74329Smrg}
1035e3d74329Smrg
1036e3d74329Smrgstatic void r128_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
1037e3d74329Smrg{
1038e3d74329Smrg    ScrnInfoPtr   pScrn   = crtc->scrn;
1039e3d74329Smrg    ScreenPtr     pScreen = xf86ScrnToScreen(pScrn);
1040e3d74329Smrg    R128InfoPtr   info    = R128PTR(pScrn);
1041e3d74329Smrg
1042e3d74329Smrg    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
1043e3d74329Smrg
1044e3d74329Smrg    if (rotate_pixmap) FreeScratchPixmapHeader(rotate_pixmap);
1045e3d74329Smrg
1046e3d74329Smrg    if (data && r128_crtc->rotate_mem != NULL) {
1047e3d74329Smrg#ifdef USE_EXA
1048e3d74329Smrg        if (info->ExaDriver)
1049e3d74329Smrg            exaOffscreenFree(pScreen, (ExaOffscreenArea *) r128_crtc->rotate_mem);
1050e3d74329Smrg#endif
1051e3d74329Smrg#ifdef HAVE_XAA_H
1052e3d74329Smrg        if (info->accel)
1053e3d74329Smrg            xf86FreeOffscreenLinear((FBLinearPtr) r128_crtc->rotate_mem);
1054e3d74329Smrg#endif
1055e3d74329Smrg        r128_crtc->rotate_mem = NULL;
1056e3d74329Smrg    }
1057e3d74329Smrg}
1058e3d74329Smrg
1059e3d74329Smrgstatic const xf86CrtcFuncsRec r128_crtc_funcs = {
1060e3d74329Smrg    .dpms = r128_crtc_dpms,
1061e3d74329Smrg    .save = NULL,
1062e3d74329Smrg    .restore = NULL,
1063e3d74329Smrg    .mode_fixup = r128_crtc_mode_fixup,
1064e3d74329Smrg    .prepare = r128_crtc_mode_prepare,
1065e3d74329Smrg    .mode_set = r128_crtc_mode_set,
1066e3d74329Smrg    .commit = r128_crtc_mode_commit,
1067e3d74329Smrg    .gamma_set = r128_crtc_gamma_set,
1068e3d74329Smrg    .lock = r128_crtc_lock,
1069e3d74329Smrg    .unlock = r128_crtc_unlock,
1070e3d74329Smrg    .shadow_create = r128_crtc_shadow_create,
1071e3d74329Smrg    .shadow_allocate = r128_crtc_shadow_allocate,
1072e3d74329Smrg    .shadow_destroy = r128_crtc_shadow_destroy,
1073e3d74329Smrg    .set_cursor_colors = r128_crtc_set_cursor_colors,
1074e3d74329Smrg    .set_cursor_position = r128_crtc_set_cursor_position,
1075e3d74329Smrg    .show_cursor = r128_crtc_show_cursor,
1076e3d74329Smrg    .hide_cursor = r128_crtc_hide_cursor,
1077e3d74329Smrg    .load_cursor_image = r128_crtc_load_cursor_image,
1078e3d74329Smrg    .destroy = NULL,
1079e3d74329Smrg};
1080e3d74329Smrg
1081e3d74329SmrgBool R128AllocateControllers(ScrnInfoPtr pScrn)
1082e3d74329Smrg{
1083e3d74329Smrg    R128EntPtr pR128Ent = R128EntPriv(pScrn);
1084e3d74329Smrg
1085e3d74329Smrg    if (pR128Ent->Controller[0])
1086e3d74329Smrg        return TRUE;
1087e3d74329Smrg
1088e3d74329Smrg    pR128Ent->pCrtc[0] = xf86CrtcCreate(pScrn, &r128_crtc_funcs);
1089e3d74329Smrg    if (!pR128Ent->pCrtc[0])
1090e3d74329Smrg        return FALSE;
1091e3d74329Smrg
1092e3d74329Smrg    pR128Ent->Controller[0] = xnfcalloc(sizeof(R128CrtcPrivateRec), 1);
1093e3d74329Smrg    if (!pR128Ent->Controller[0])
1094e3d74329Smrg        return FALSE;
1095e3d74329Smrg
1096e3d74329Smrg    pR128Ent->pCrtc[0]->driver_private = pR128Ent->Controller[0];
1097e3d74329Smrg    pR128Ent->Controller[0]->crtc_id = 0;
1098e3d74329Smrg
1099e3d74329Smrg    if (!pR128Ent->HasCRTC2)
1100e3d74329Smrg        return TRUE;
1101e3d74329Smrg
1102e3d74329Smrg    pR128Ent->pCrtc[1] = xf86CrtcCreate(pScrn, &r128_crtc_funcs);
1103e3d74329Smrg    if (!pR128Ent->pCrtc[1])
1104e3d74329Smrg        return FALSE;
1105e3d74329Smrg
1106e3d74329Smrg    pR128Ent->Controller[1] = xnfcalloc(sizeof(R128CrtcPrivateRec), 1);
1107e3d74329Smrg    if (!pR128Ent->Controller[1]) {
1108e3d74329Smrg        free(pR128Ent->Controller[0]);
1109e3d74329Smrg        return FALSE;
1110e3d74329Smrg    }
1111e3d74329Smrg
1112e3d74329Smrg    pR128Ent->pCrtc[1]->driver_private = pR128Ent->Controller[1];
1113e3d74329Smrg    pR128Ent->Controller[1]->crtc_id = 1;
1114e3d74329Smrg
1115e3d74329Smrg    return TRUE;
1116e3d74329Smrg}
1117e3d74329Smrg
1118e3d74329Smrgvoid R128Blank(ScrnInfoPtr pScrn)
1119e3d74329Smrg{
1120e3d74329Smrg    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1121e3d74329Smrg    xf86OutputPtr output;
1122e3d74329Smrg    xf86CrtcPtr crtc;
1123e3d74329Smrg    int o, c;
1124e3d74329Smrg
1125e3d74329Smrg    for (c = 0; c < xf86_config->num_crtc; c++) {
1126e3d74329Smrg        crtc = xf86_config->crtc[c];
1127e3d74329Smrg        for (o = 0; o < xf86_config->num_output; o++) {
1128e3d74329Smrg            output = xf86_config->output[o];
1129e3d74329Smrg            if (output->crtc != crtc)
1130e3d74329Smrg                continue;
1131e3d74329Smrg
1132e3d74329Smrg            output->funcs->dpms(output, DPMSModeOff);
1133e3d74329Smrg        }
1134e3d74329Smrg        crtc->funcs->dpms(crtc, DPMSModeOff);
1135e3d74329Smrg    }
1136e3d74329Smrg}
1137e3d74329Smrg
1138e3d74329Smrgvoid R128Unblank(ScrnInfoPtr pScrn)
1139e3d74329Smrg{
1140e3d74329Smrg    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1141e3d74329Smrg    xf86OutputPtr output;
1142e3d74329Smrg    xf86CrtcPtr crtc;
1143e3d74329Smrg    int o, c;
1144e3d74329Smrg
1145e3d74329Smrg    for (c = 0; c < xf86_config->num_crtc; c++) {
1146e3d74329Smrg        crtc = xf86_config->crtc[c];
1147e3d74329Smrg        if (!crtc->enabled)
1148e3d74329Smrg            continue;
1149e3d74329Smrg        crtc->funcs->dpms(crtc, DPMSModeOn);
1150e3d74329Smrg        for (o = 0; o < xf86_config->num_output; o++) {
1151e3d74329Smrg            output = xf86_config->output[o];
1152e3d74329Smrg            if (output->crtc != crtc)
1153e3d74329Smrg                continue;
1154e3d74329Smrg
1155e3d74329Smrg            output->funcs->dpms(output, DPMSModeOn);
1156e3d74329Smrg        }
1157e3d74329Smrg    }
1158e3d74329Smrg}
1159