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