[PATCH r128] Port to RandR

Connor Behan connor.behan at gmail.com
Sun Jun 1 13:03:42 PDT 2014


This rearranges the r128 code to use the Crtc and Ouput interfaces which
should make the driver easier to maintain in the long run. User visible
changes include DDC detection working in more cases and the ability to
have multiple monitors with DRI.

Some choices have been made to conserve memory. Modes can be switched up
to the highest resolution specified in xorg.conf. If this is 1024x768
for example, the front buffer will be 1024x768 instead of 1024x1024.
This means 90 and 270 degree rotations will not work. However, scalings,
reflections and 180 degree rotations can be set with the xrandr client
program.

Signed-off-by: Connor Behan <connor.behan at gmail.com>
---
 configure.ac      |    2 +-
 src/Makefile.am   |    3 +-
 src/r128.h        |   48 +-
 src/r128_crtc.c   |  476 ++++++++++++++++++++
 src/r128_cursor.c |  294 ++++++------
 src/r128_driver.c | 1287 +++++++++++------------------------------------------
 src/r128_output.c |  465 +++++++++++++++++++
 src/r128_probe.c  |    1 -
 src/r128_probe.h  |   79 ++++
 src/r128_video.c  |   17 +-
 10 files changed, 1479 insertions(+), 1193 deletions(-)
 create mode 100644 src/r128_crtc.c
 create mode 100644 src/r128_output.c

diff --git a/configure.ac b/configure.ac
index 56554ec..3cc3113 100644
--- a/configure.ac
+++ b/configure.ac
@@ -76,7 +76,7 @@ XORG_DRIVER_CHECK_EXT(XF86MISC, xf86miscproto)
 XORG_DRIVER_CHECK_EXT(DPMSExtension, xextproto)
 
 # Obtain compiler/linker options for the driver dependencies
-PKG_CHECK_MODULES(XORG, [xorg-server >= 1.2 xproto fontsproto $REQUIRED_MODULES])
+PKG_CHECK_MODULES(XORG, [xorg-server >= 1.3 xproto fontsproto $REQUIRED_MODULES])
 PKG_CHECK_MODULES(XEXT, [xextproto >= 7.0.99.1],
                   HAVE_XEXTPROTO_71="yes"; AC_DEFINE(HAVE_XEXTPROTO_71, 1, [xextproto 7.1 available]),
                   HAVE_XEXTPROTO_71="no")
diff --git a/src/Makefile.am b/src/Makefile.am
index 23e6c49..e4618ea 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -41,7 +41,8 @@ r128_drv_la_LDFLAGS = -module -avoid-version
 r128_drv_ladir = @moduledir@/drivers
 r128_drv_la_SOURCES = \
 	r128_accel.c r128_cursor.c r128_dga.c r128_driver.c \
-	r128_video.c r128_misc.c r128_probe.c $(R128_EXA_SRCS) $(R128_DRI_SRCS)
+	r128_video.c r128_misc.c r128_crtc.c r128_output.c r128_probe.c \
+	$(R128_EXA_SRCS) $(R128_DRI_SRCS)
 
 EXTRA_DIST = \
         compat-api.h \
diff --git a/src/r128.h b/src/r128.h
index ee0b1d4..fe757f8 100644
--- a/src/r128.h
+++ b/src/r128.h
@@ -74,6 +74,7 @@
 #endif
 
 #include "fb.h"
+#include "xf86Crtc.h"
 
 #include "compat-api.h"
 #include "atipcirename.h"
@@ -260,16 +261,6 @@ typedef struct {
     DisplayModePtr     mode;
 } R128FBLayout;
 
-typedef enum
-{
-    MT_NONE,
-    MT_CRT,
-    MT_LCD,
-    MT_DFP,
-    MT_CTV,
-    MT_STV
-} R128MonitorType;
-
 #ifdef USE_EXA
 struct r128_2d_state {
     Bool in_use;
@@ -523,10 +514,10 @@ typedef struct {
 
     Bool              isDFP;
     Bool              isPro2;
-    I2CBusPtr         pI2CBus;
-    CARD32            DDCReg;
+    Bool              DDC;
 
     Bool              VGAAccess;
+    R128BIOSConnector BiosConnector[R128_MAX_BIOS_CONNECTOR];
 
     /****** Added for dualhead support *******************/
     BOOL              HasCRTC2;     /* M3/M4 */
@@ -562,6 +553,39 @@ extern int         R128MinBits(int val);
 
 extern void        R128InitVideo(ScreenPtr pScreen);
 
+extern void        R128InitCommonRegisters(R128SavePtr save, R128InfoPtr info);
+extern void        R128InitFPRegisters(R128SavePtr orig, R128SavePtr save, DisplayModePtr mode, R128InfoPtr info);
+extern Bool        R128InitCrtcBase(xf86CrtcPtr crtc, R128SavePtr save, int x, int y);
+extern Bool        R128InitCrtcRegisters(ScrnInfoPtr pScrn, R128SavePtr save, DisplayModePtr mode, R128InfoPtr info);
+extern void        R128InitPLLRegisters(ScrnInfoPtr pScrn, R128SavePtr save, R128PLLPtr pll, double dot_clock);
+extern Bool        R128InitDDARegisters(ScrnInfoPtr pScrn, R128SavePtr save, R128PLLPtr pll, R128InfoPtr info, DisplayModePtr mode);
+extern Bool        R128InitCrtc2Base(xf86CrtcPtr crtc, R128SavePtr save, int x, int y);
+extern Bool        R128InitCrtc2Registers(ScrnInfoPtr pScrn, R128SavePtr save, DisplayModePtr mode, R128InfoPtr info);
+extern void        R128InitPLL2Registers(ScrnInfoPtr pScrn, R128SavePtr save, R128PLLPtr pll, double dot_clock);
+extern Bool        R128InitDDA2Registers(ScrnInfoPtr pScrn, R128SavePtr save, R128PLLPtr pll, R128InfoPtr info, DisplayModePtr mode);
+extern void        R128RestoreCommonRegisters(ScrnInfoPtr pScrn, R128SavePtr restore);
+extern void        R128RestoreFPRegisters(ScrnInfoPtr pScrn, R128SavePtr restore);
+extern void        R128RestoreCrtcRegisters(ScrnInfoPtr pScrn, R128SavePtr restore);
+extern void        R128RestorePLLRegisters(ScrnInfoPtr pScrn, R128SavePtr restore);
+extern void        R128RestoreDDARegisters(ScrnInfoPtr pScrn, R128SavePtr restore);
+extern void        R128RestoreCrtc2Registers(ScrnInfoPtr pScrn, R128SavePtr restore);
+extern void        R128RestorePLL2Registers(ScrnInfoPtr pScrn, R128SavePtr restore);
+extern void        R128RestoreDDA2Registers(ScrnInfoPtr pScrn, R128SavePtr restore);
+
+extern void        r128_crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg);
+extern void        r128_crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y);
+extern void        r128_crtc_show_cursor(xf86CrtcPtr crtc);
+extern void        r128_crtc_hide_cursor(xf86CrtcPtr crtc);
+extern void        r128_crtc_load_cursor_image(xf86CrtcPtr crtc, unsigned char *src);
+
+extern Bool        R128SetupConnectors(ScrnInfoPtr pScrn);
+extern Bool        R128AllocateControllers(ScrnInfoPtr pScrn, int mask);
+extern void        R128Blank(ScrnInfoPtr pScrn);
+extern void        R128Unblank(ScrnInfoPtr pScrn);
+extern void        R128DPMSSetOn(xf86OutputPtr output);
+extern void        R128DPMSSetOff(xf86OutputPtr output);
+extern DisplayModePtr R128ProbeOutputModes(xf86OutputPtr output);
+
 #ifdef R128DRI
 extern Bool        R128DRIScreenInit(ScreenPtr pScreen);
 extern void        R128DRICloseScreen(ScreenPtr pScreen);
diff --git a/src/r128_crtc.c b/src/r128_crtc.c
new file mode 100644
index 0000000..35e1fee
--- /dev/null
+++ b/src/r128_crtc.c
@@ -0,0 +1,476 @@
+/*
+ * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and
+ *                VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation on the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR
+ * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+#include "xf86.h"
+#include "xf86Modes.h"
+
+#include "r128.h"
+#include "r128_probe.h"
+#include "r128_reg.h"
+
+static void r128_crtc_load_lut(xf86CrtcPtr crtc);
+
+static void r128_crtc_dpms(xf86CrtcPtr crtc, int mode)
+{
+    int mask;
+    ScrnInfoPtr pScrn = crtc->scrn;
+    R128InfoPtr info = R128PTR(pScrn);
+    unsigned char *R128MMIO = info->MMIO;
+    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
+
+    /* XXX: The HSYNC and VSYNC bits for CRTC2 don't exist on the r128? */
+    mask = r128_crtc->crtc_id ? R128_CRTC2_DISP_DIS : (R128_CRTC_DISPLAY_DIS | R128_CRTC_HSYNC_DIS | R128_CRTC_VSYNC_DIS);
+
+    switch (mode) {
+    case DPMSModeOn:
+        if (r128_crtc->crtc_id) {
+            OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~mask);
+        } else {
+            OUTREGP(R128_CRTC_EXT_CNTL, 0, ~mask);
+        }
+        break;
+    case DPMSModeStandby:
+        if (r128_crtc->crtc_id) {
+            OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_DISP_DIS, ~mask);
+        } else {
+            OUTREGP(R128_CRTC_EXT_CNTL, (R128_CRTC_DISPLAY_DIS | R128_CRTC_HSYNC_DIS), ~mask);
+        }
+        break;
+    case DPMSModeSuspend:
+        if (r128_crtc->crtc_id) {
+            OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_DISP_DIS, ~mask);
+        } else {
+            OUTREGP(R128_CRTC_EXT_CNTL, (R128_CRTC_DISPLAY_DIS | R128_CRTC_VSYNC_DIS), ~mask);
+        }
+        break;
+    case DPMSModeOff:
+        if (r128_crtc->crtc_id) {
+            OUTREGP(R128_CRTC2_GEN_CNTL, mask, ~mask);
+        } else {
+            OUTREGP(R128_CRTC_EXT_CNTL, mask, ~mask);
+        }
+        break;
+    }
+
+    if (mode != DPMSModeOff)
+        r128_crtc_load_lut(crtc);
+}
+
+void r128_crtc_load_lut(xf86CrtcPtr crtc)
+{
+    ScrnInfoPtr pScrn = crtc->scrn;
+    R128InfoPtr info = R128PTR(pScrn);
+    unsigned char *R128MMIO = info->MMIO;
+    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
+    int i;
+
+    if (!crtc->enabled)
+        return;
+
+    PAL_SELECT(r128_crtc->crtc_id);
+
+    for (i = 0; i < 256; i++) {
+        OUTPAL(i, r128_crtc->lut_r[i], r128_crtc->lut_g[i], r128_crtc->lut_b[i]);
+    }
+}
+
+static Bool r128_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode, DisplayModePtr adjusted_mode)
+{
+    return TRUE;
+}
+
+static void r128_crtc_mode_prepare(xf86CrtcPtr crtc)
+{
+    r128_crtc_dpms(crtc, DPMSModeOff);
+}
+
+static void r128_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode, DisplayModePtr adjusted_mode, int x, int y)
+{
+    ScrnInfoPtr pScrn = crtc->scrn;
+    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
+    R128InfoPtr info = R128PTR(pScrn);
+    R128OutputType otype = OUTPUT_NONE;
+
+    double dot_clock = adjusted_mode->Clock / 1000.0;
+    int i;
+
+    if (r128_crtc->cursor_offset) r128_crtc_hide_cursor(crtc);
+    xf86PrintModeline(pScrn->scrnIndex, adjusted_mode);
+    R128InitCommonRegisters(&info->ModeReg, info);
+
+    for (i = 0; i < xf86_config->num_output; i++) {
+        xf86OutputPtr output = xf86_config->output[i];
+        R128OutputPrivatePtr r128_output = output->driver_private;
+
+        if (output->crtc == crtc)
+            otype = r128_output->type;
+    }
+
+    switch (r128_crtc->crtc_id) {
+    case 0:
+        R128InitCrtcRegisters(pScrn, &info->ModeReg, adjusted_mode, info);
+	R128InitCrtcBase(crtc, &info->ModeReg, x, y);
+        if (dot_clock) {
+            R128InitPLLRegisters(pScrn, &info->ModeReg, &info->pll, dot_clock);
+            R128InitDDARegisters(pScrn, &info->ModeReg, &info->pll, info, adjusted_mode);
+        } else {
+            info->ModeReg.ppll_ref_div         = info->SavedReg.ppll_ref_div;
+            info->ModeReg.ppll_div_3           = info->SavedReg.ppll_div_3;
+            info->ModeReg.htotal_cntl          = info->SavedReg.htotal_cntl;
+            info->ModeReg.dda_config           = info->SavedReg.dda_config;
+            info->ModeReg.dda_on_off           = info->SavedReg.dda_on_off;
+        }
+        break;
+    case 1:
+        R128InitCrtc2Registers(pScrn, &info->ModeReg, adjusted_mode, info);
+	R128InitCrtc2Base(crtc, &info->ModeReg, x, y);
+        if (dot_clock) {
+            R128InitPLL2Registers(pScrn, &info->ModeReg, &info->pll, dot_clock);
+            R128InitDDA2Registers(pScrn, &info->ModeReg, &info->pll, info, adjusted_mode);
+        }
+        break;
+    }
+
+    if (otype == OUTPUT_DVI || otype == OUTPUT_LVDS)
+        R128InitFPRegisters(&info->SavedReg, &info->ModeReg, adjusted_mode, info);
+    R128RestoreCommonRegisters(pScrn, &info->ModeReg);
+
+    switch (r128_crtc->crtc_id) {
+    case 0:
+        R128RestoreDDARegisters(pScrn, &info->ModeReg);
+        R128RestoreCrtcRegisters(pScrn, &info->ModeReg);
+        R128RestorePLLRegisters(pScrn, &info->ModeReg);
+        break;
+    case 1:
+        R128RestoreDDA2Registers(pScrn, &info->ModeReg);
+        R128RestoreCrtc2Registers(pScrn, &info->ModeReg);
+        R128RestorePLL2Registers(pScrn, &info->ModeReg);
+	break;
+    }
+
+    if (otype == OUTPUT_DVI || otype == OUTPUT_LVDS)
+        R128RestoreFPRegisters(pScrn, &info->ModeReg);
+
+    /* XXX: InitFPRegisters looks similar to radeon's InitRMXRegisters so
+     * maybe it should be called from mode_set in the output code.
+     */
+    if (r128_crtc->cursor_offset) r128_crtc_show_cursor(crtc);
+}
+
+static void r128_crtc_mode_commit(xf86CrtcPtr crtc)
+{
+    r128_crtc_dpms(crtc, DPMSModeOn);
+}
+
+static void r128_crtc_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue, int size)
+{
+    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
+    int i;
+
+    for (i = 0; i < 256; i++) {
+        r128_crtc->lut_r[i] = red[i] >> 8;
+        r128_crtc->lut_g[i] = green[i] >> 8;
+        r128_crtc->lut_b[i] = blue[i] >> 8;
+    }
+
+    r128_crtc_load_lut(crtc);
+}
+
+static Bool r128_crtc_lock(xf86CrtcPtr crtc)
+{
+    ScrnInfoPtr   pScrn   = crtc->scrn;
+    ScreenPtr     pScreen = xf86ScrnToScreen(pScrn);
+    R128InfoPtr   info    = R128PTR(pScrn);
+
+#ifdef HAVE_XAA_H
+    if (info->accel) info->accel->Sync(pScrn);
+#endif
+#ifdef USE_EXA
+    if (info->ExaDriver) exaWaitSync(pScreen);
+#endif
+
+    return FALSE;
+}
+
+static void r128_crtc_unlock(xf86CrtcPtr crtc)
+{
+    ScrnInfoPtr   pScrn   = crtc->scrn;
+    ScreenPtr     pScreen = xf86ScrnToScreen(pScrn);
+    R128InfoPtr   info    = R128PTR(pScrn);
+
+#ifdef HAVE_XAA_H
+    if (info->accel) info->accel->Sync(pScrn);
+#endif
+#ifdef USE_EXA
+    if (info->ExaDriver) exaWaitSync(pScreen);
+#endif
+}
+
+#ifdef HAVE_XAA_H
+static FBLinearPtr r128_xf86AllocateOffscreenLinear(ScreenPtr pScreen, int length, int granularity,
+                                                MoveLinearCallbackProcPtr moveCB,
+                                                RemoveLinearCallbackProcPtr removeCB,
+                                                pointer privData)
+{
+    FBLinearPtr linear;
+    int max_size;
+
+    linear = xf86AllocateOffscreenLinear(pScreen, length, granularity, moveCB, removeCB, privData);
+    if (linear != NULL) return linear;
+
+    /* The above allocation did not succeed, so purge unlocked stuff and try again. */
+    xf86QueryLargestOffscreenLinear(pScreen, &max_size, granularity, PRIORITY_EXTREME);
+
+    if (max_size < length) return NULL;
+    xf86PurgeUnlockedOffscreenAreas(pScreen);
+
+    linear = xf86AllocateOffscreenLinear(pScreen, length, granularity, moveCB, removeCB, privData);
+    return linear;
+}
+#endif
+
+static void *r128_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
+{
+    ScrnInfoPtr   pScrn   = crtc->scrn;
+    ScreenPtr     pScreen = xf86ScrnToScreen(pScrn);
+    R128InfoPtr   info    = R128PTR(pScrn);
+
+    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
+    unsigned long rotate_offset = 0;
+    unsigned long rotate_pitch;
+    int cpp = pScrn->bitsPerPixel / 8;
+    int align = 4096;
+    int size;
+
+    rotate_pitch = pScrn->displayWidth * cpp;
+    size = rotate_pitch * height;
+
+#ifdef USE_EXA
+    if (info->ExaDriver) {
+        assert(r128_crtc->rotate_mem_exa == NULL);
+        r128_crtc->rotate_mem_exa = exaOffscreenAlloc(pScreen, size, align, TRUE, NULL, NULL);
+
+        if (r128_crtc->rotate_mem_exa == NULL) {
+	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+		       "Couldn't allocate shadow memory for rotated CRTC\n");
+	    return NULL;
+	}
+
+        rotate_offset = r128_crtc->rotate_mem_exa->offset;
+    }
+#endif
+#ifdef HAVE_XAA_H
+    if (info->accel) {
+        size = (size + cpp - 1) / cpp;
+        align = (align + cpp - 1) / cpp;
+
+        assert(r128_crtc->rotate_mem_xaa == NULL);
+        r128_crtc->rotate_mem_xaa = r128_xf86AllocateOffscreenLinear(pScreen, size, align, NULL, NULL, NULL);
+
+        if (r128_crtc->rotate_mem_exa == NULL) {
+	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+		       "Couldn't allocate shadow memory for rotated CRTC\n");
+	    return NULL;
+	}
+
+        rotate_offset = r128_crtc->rotate_mem_xaa->offset * cpp;
+    }
+#endif
+
+    /* If allocations failed or if there was no accel. */
+    if (rotate_offset == 0)
+        return NULL;
+
+    return info->FB + rotate_offset;
+}
+
+static PixmapPtr r128_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
+{
+    ScrnInfoPtr pScrn = crtc->scrn;
+    PixmapPtr rotate_pixmap;
+    unsigned long rotate_pitch;
+    int cpp = pScrn->bitsPerPixel / 8;
+
+    if (!data) data = r128_crtc_shadow_allocate(crtc, width, height);
+
+    rotate_pitch = pScrn->displayWidth * cpp;
+    rotate_pixmap = GetScratchPixmapHeader(xf86ScrnToScreen(pScrn),
+                                           width, height,
+                                           pScrn->depth,
+                                           pScrn->bitsPerPixel,
+                                           rotate_pitch,
+                                           data);
+
+    if (rotate_pixmap == NULL) {
+        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+                   "Couldn't allocate shadow memory for rotated CRTC\n");
+        return NULL;
+    }
+
+    return rotate_pixmap;
+}
+
+static void r128_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
+{
+    ScrnInfoPtr   pScrn   = crtc->scrn;
+    ScreenPtr     pScreen = xf86ScrnToScreen(pScrn);
+    R128InfoPtr   info    = R128PTR(pScrn);
+
+    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
+
+    if (rotate_pixmap) FreeScratchPixmapHeader(rotate_pixmap);
+
+    if (data) {
+#ifdef USE_EXA
+        if (info->ExaDriver && r128_crtc->rotate_mem_exa != NULL) {
+            exaOffscreenFree(pScreen, r128_crtc->rotate_mem_exa);
+	    r128_crtc->rotate_mem_exa = NULL;
+        }
+#endif
+#ifdef HAVE_XAA_H
+        if (info->accel) {
+            xf86FreeOffscreenLinear(r128_crtc->rotate_mem_xaa);
+            r128_crtc->rotate_mem_xaa = NULL;
+        }
+#endif
+    }
+}
+
+static const xf86CrtcFuncsRec r128_crtc_funcs = {
+    .dpms = r128_crtc_dpms,
+    .save = NULL,
+    .restore = NULL,
+    .mode_fixup = r128_crtc_mode_fixup,
+    .prepare = r128_crtc_mode_prepare,
+    .mode_set = r128_crtc_mode_set,
+    .commit = r128_crtc_mode_commit,
+    .gamma_set = r128_crtc_gamma_set,
+    .lock = r128_crtc_lock,
+    .unlock = r128_crtc_unlock,
+    .shadow_create = r128_crtc_shadow_create,
+    .shadow_allocate = r128_crtc_shadow_allocate,
+    .shadow_destroy = r128_crtc_shadow_destroy,
+    .set_cursor_colors = r128_crtc_set_cursor_colors,
+    .set_cursor_position = r128_crtc_set_cursor_position,
+    .show_cursor = r128_crtc_show_cursor,
+    .hide_cursor = r128_crtc_hide_cursor,
+    .load_cursor_image = r128_crtc_load_cursor_image,
+    .destroy = NULL,
+};
+
+Bool R128AllocateControllers(ScrnInfoPtr pScrn, int mask)
+{
+    R128EntPtr pR128Ent = R128EntPriv(pScrn);
+    R128InfoPtr info = R128PTR(pScrn);
+
+    if (mask & 1) {
+        if (pR128Ent->Controller[0])
+            return TRUE;
+
+        pR128Ent->pCrtc[0] = xf86CrtcCreate(pScrn, &r128_crtc_funcs);
+        if (!pR128Ent->pCrtc[0])
+            return FALSE;
+
+        pR128Ent->Controller[0] = xnfcalloc(sizeof(R128CrtcPrivateRec), 1);
+        if (!pR128Ent->Controller[0])
+            return FALSE;
+
+        pR128Ent->pCrtc[0]->driver_private = pR128Ent->Controller[0];
+        pR128Ent->Controller[0]->crtc_id = 0;
+    }
+
+    if (mask & 2) {
+        if (!info->HasCRTC2)
+            return TRUE;
+
+        pR128Ent->pCrtc[1] = xf86CrtcCreate(pScrn, &r128_crtc_funcs);
+        if (!pR128Ent->pCrtc[1])
+            return FALSE;
+
+        pR128Ent->Controller[1] = xnfcalloc(sizeof(R128CrtcPrivateRec), 1);
+        if (!pR128Ent->Controller[1]) {
+            free(pR128Ent->Controller[0]);
+            return FALSE;
+        }
+
+        pR128Ent->pCrtc[1]->driver_private = pR128Ent->Controller[1];
+        pR128Ent->Controller[1]->crtc_id = 1;
+    }
+
+    return TRUE;
+}
+
+void R128Blank(ScrnInfoPtr pScrn)
+{
+    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+    xf86OutputPtr output;
+    xf86CrtcPtr crtc;
+    int o, c;
+
+    for (c = 0; c < xf86_config->num_crtc; c++) {
+        crtc = xf86_config->crtc[c];
+        for (o = 0; o < xf86_config->num_output; o++) {
+            output = xf86_config->output[o];
+            if (output->crtc != crtc)
+                continue;
+
+            output->funcs->dpms(output, DPMSModeOff);
+        }
+        crtc->funcs->dpms(crtc, DPMSModeOff);
+    }
+}
+
+void R128Unblank(ScrnInfoPtr pScrn)
+{
+    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+    xf86OutputPtr output;
+    xf86CrtcPtr crtc;
+    int o, c;
+
+    for (c = 0; c < xf86_config->num_crtc; c++) {
+        crtc = xf86_config->crtc[c];
+        if (!crtc->enabled)
+            continue;
+        crtc->funcs->dpms(crtc, DPMSModeOn);
+        for (o = 0; o < xf86_config->num_output; o++) {
+            output = xf86_config->output[o];
+            if (output->crtc != crtc)
+                continue;
+
+            output->funcs->dpms(output, DPMSModeOn);
+        }
+    }
+}
diff --git a/src/r128_cursor.c b/src/r128_cursor.c
index b76913c..ad6752f 100644
--- a/src/r128_cursor.c
+++ b/src/r128_cursor.c
@@ -59,6 +59,9 @@
 #include "exa.h"
 #endif
 
+#define CURSOR_WIDTH    64
+#define CURSOR_HEIGHT   64
+
 #if X_BYTE_ORDER == X_BIG_ENDIAN
 #define P_SWAP32( a , b )                \
        ((char *)a)[0] = ((char *)b)[3];  \
@@ -73,84 +76,121 @@
        ((char *)a)[3] = ((char *)b)[2]
 #endif
 
+void r128_crtc_show_cursor(xf86CrtcPtr crtc)
+{
+    ScrnInfoPtr pScrn = crtc->scrn;
+    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
+    R128InfoPtr info = R128PTR(pScrn);
+    unsigned char *R128MMIO = info->MMIO;
+    int crtc_id = r128_crtc->crtc_id;
+
+    switch (crtc_id) {
+    case 0:
+        OUTREGP(R128_CRTC_GEN_CNTL, R128_CRTC_CUR_EN, ~R128_CRTC_CUR_EN);
+        break;
+    case 1:
+        OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_CUR_EN, ~R128_CRTC2_CUR_EN);
+        break;
+    default:
+        return;
+    }
+}
 
-/* Set cursor foreground and background colors. */
-static void R128SetCursorColors(ScrnInfoPtr pScrn, int bg, int fg)
+void r128_crtc_hide_cursor(xf86CrtcPtr crtc)
 {
-    R128InfoPtr   info      = R128PTR(pScrn);
+    ScrnInfoPtr pScrn = crtc->scrn;
+    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
+    R128InfoPtr info = R128PTR(pScrn);
     unsigned char *R128MMIO = info->MMIO;
+    int crtc_id = r128_crtc->crtc_id;
 
-    if(info->IsSecondary)
-    {
+    switch (crtc_id) {
+    case 0:
+        OUTREGP(R128_CRTC_GEN_CNTL, 0, ~R128_CRTC_CUR_EN);
+        break;
+    case 1:
+        OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~R128_CRTC2_CUR_EN);
+        break;
+    default:
+        return;
+    }
+}
+
+void r128_crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
+{
+    ScrnInfoPtr pScrn = crtc->scrn;
+    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
+    R128InfoPtr info = R128PTR(pScrn);
+    unsigned char *R128MMIO = info->MMIO;
+    int crtc_id = r128_crtc->crtc_id;
+
+    switch (crtc_id) {
+    case 0:
+        OUTREG(R128_CUR_CLR0, bg);
+        OUTREG(R128_CUR_CLR1, fg);
+        break;
+    case 1:
         OUTREG(R128_CUR2_CLR0, bg);
         OUTREG(R128_CUR2_CLR1, fg);
-    }
-    else
-    {
-    	OUTREG(R128_CUR_CLR0, bg);
-    	OUTREG(R128_CUR_CLR1, fg);
+        break;
+    default:
+        return;
     }
 }
 
-/* Set cursor position to (x,y) with offset into cursor bitmap at
-   (xorigin,yorigin). */
-static void R128SetCursorPosition(ScrnInfoPtr pScrn, int x, int y)
+void r128_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
 {
-    R128InfoPtr           info      = R128PTR(pScrn);
-    unsigned char         *R128MMIO = info->MMIO;
-    xf86CursorInfoPtr     cursor    = info->cursor;
-    int                   xorigin   = 0;
-    int                   yorigin   = 0;
-    int                   total_y   = pScrn->frameY1 - pScrn->frameY0;
-
-    if (x < 0)                        xorigin = -x;
-    if (y < 0)                        yorigin = -y;
-    if (y > total_y)                  y       = total_y;
-    if (info->Flags & V_DBLSCAN)      y       *= 2;
-    if (xorigin >= cursor->MaxWidth)  xorigin = cursor->MaxWidth - 1;
-    if (yorigin >= cursor->MaxHeight) yorigin = cursor->MaxHeight - 1;
-
-    if(!info->IsSecondary)
-    {
-    	OUTREG(R128_CUR_HORZ_VERT_OFF,  R128_CUR_LOCK | (xorigin << 16) | yorigin);
-    	OUTREG(R128_CUR_HORZ_VERT_POSN, (R128_CUR_LOCK
-				     | ((xorigin ? 0 : x) << 16)
-				     | (yorigin ? 0 : y)));
-    	OUTREG(R128_CUR_OFFSET,         info->cursor_start + yorigin * 16);
-    } 
-    else 
-    {
-        OUTREG(R128_CUR2_HORZ_VERT_OFF,  (R128_CUR2_LOCK
-				       | (xorigin << 16)
-				       | yorigin));
-        OUTREG(R128_CUR2_HORZ_VERT_POSN, (R128_CUR2_LOCK
-				       | ((xorigin ? 0 : x) << 16)
-				       | (yorigin ? 0 : y)));
-        OUTREG(R128_CUR2_OFFSET,         
-			info->cursor_start + pScrn->fbOffset + yorigin * 16);
+    ScrnInfoPtr           pScrn         = crtc->scrn;
+    R128InfoPtr           info          = R128PTR(pScrn);
+    R128CrtcPrivatePtr    r128_crtc     = crtc->driver_private;
+    unsigned char         *R128MMIO     = info->MMIO;
+    int                   crtc_id       = r128_crtc->crtc_id;
+
+    int xorigin = 0, yorigin = 0;
+    DisplayModePtr mode = &crtc->mode;
+
+    if (x < 0) xorigin = -x + 1;
+    if (y < 0) yorigin = -y + 1;
+    if (xorigin >= CURSOR_WIDTH)  xorigin = CURSOR_WIDTH - 1;
+    if (yorigin >= CURSOR_HEIGHT) yorigin = CURSOR_HEIGHT - 1;
+
+    if (mode->Flags & V_INTERLACE)
+        y /= 2;
+    else if (mode->Flags & V_DBLSCAN)
+        y *= 2;
+
+    if(crtc_id == 0) {
+        OUTREG(R128_CUR_HORZ_VERT_OFF, (R128_CUR_LOCK | (xorigin << 16) | yorigin));
+        OUTREG(R128_CUR_HORZ_VERT_POSN, (R128_CUR_LOCK | ((xorigin ? 0 : x) << 16) | (yorigin ? 0 : y)));
+        OUTREG(R128_CUR_OFFSET, r128_crtc->cursor_offset + pScrn->fbOffset + yorigin * 16);
+    } else if (crtc_id == 1) {
+        OUTREG(R128_CUR2_HORZ_VERT_OFF, (R128_CUR2_LOCK | (xorigin << 16) | yorigin));
+        OUTREG(R128_CUR2_HORZ_VERT_POSN, (R128_CUR2_LOCK | ((xorigin ? 0 : x) << 16) | (yorigin ? 0 : y)));
+        OUTREG(R128_CUR2_OFFSET, r128_crtc->cursor_offset + pScrn->fbOffset + yorigin * 16);
     }
 }
 
-/* Copy cursor image from `image' to video memory.  R128SetCursorPosition
-   will be called after this, so we can ignore xorigin and yorigin. */
-static void R128LoadCursorImage(ScrnInfoPtr pScrn, unsigned char *image)
+void r128_crtc_load_cursor_image(xf86CrtcPtr crtc, unsigned char *src)
 {
+    ScrnInfoPtr pScrn = crtc->scrn;
+    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
+    int crtc_id = r128_crtc->crtc_id;
+
+
     R128InfoPtr   info      = R128PTR(pScrn);
     unsigned char *R128MMIO = info->MMIO;
-    CARD32        *s        = (pointer)image;
-    CARD32        *d        = (pointer)((CARD8*)info->FB + info->cursor_start);
+    CARD32        *s        = (pointer)src;
+    CARD32        *d        = (pointer)(info->FB + r128_crtc->cursor_offset + pScrn->fbOffset);
+    CARD32        save1     = 0;
+    CARD32        save2     = 0;
     int           y;
-    CARD32        save;
 
-    if(!info->IsSecondary)
-    {
-    	save = INREG(R128_CRTC_GEN_CNTL);
-    	OUTREG(R128_CRTC_GEN_CNTL, save & (CARD32)~R128_CRTC_CUR_EN);
-    }
-    else
-    {
-        save = INREG(R128_CRTC2_GEN_CNTL);
-        OUTREG(R128_CRTC2_GEN_CNTL, save & (CARD32)~R128_CRTC2_CUR_EN);
+    if (crtc_id == 0) {
+	save1 = INREG(R128_CRTC_GEN_CNTL);
+	OUTREG(R128_CRTC_GEN_CNTL, save1 & (CARD32)~R128_CRTC_CUR_EN);
+    } else if (crtc_id == 1) {
+	save2 = INREG(R128_CRTC2_GEN_CNTL);
+	OUTREG(R128_CRTC2_GEN_CNTL, save2 & (CARD32)~R128_CRTC2_CUR_EN);
     }
 
 #if X_BYTE_ORDER == X_BIG_ENDIAN
@@ -197,59 +237,10 @@ static void R128LoadCursorImage(ScrnInfoPtr pScrn, unsigned char *image)
     }
 #endif
 
-    /* Set the area after the cursor to be all transparent so that we
-       won't display corrupted cursors on the screen */
-    for (y = 0; y < 64; y++) {
-	*d++ = 0xffffffff; /* The AND bits */
-	*d++ = 0xffffffff;
-	*d++ = 0x00000000; /* The XOR bits */
-	*d++ = 0x00000000;
-    }
-
-
-    if(!info->IsSecondary)
-    	OUTREG(R128_CRTC_GEN_CNTL, save);
+    if (crtc_id == 0)
+	OUTREG(R128_CRTC_GEN_CNTL, save1);
     else
-        OUTREG(R128_CRTC2_GEN_CNTL, save);
-
-}
-
-/* Hide hardware cursor. */
-static void R128HideCursor(ScrnInfoPtr pScrn)
-{
-    R128InfoPtr   info      = R128PTR(pScrn);
-    unsigned char *R128MMIO = info->MMIO;
-
-     if(info->IsSecondary)
-        OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~R128_CRTC2_CUR_EN);
-     else
-    	OUTREGP(R128_CRTC_GEN_CNTL, 0, ~R128_CRTC_CUR_EN);
-}
-
-/* Show hardware cursor. */
-static void R128ShowCursor(ScrnInfoPtr pScrn)
-{
-    R128InfoPtr   info      = R128PTR(pScrn);
-    unsigned char *R128MMIO = info->MMIO;
-
-    if(info->IsSecondary)
-    {
-         OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_CUR_EN,
-               ~R128_CRTC2_CUR_EN);
-    }
-    else
-    {
-    	OUTREGP(R128_CRTC_GEN_CNTL, R128_CRTC_CUR_EN, ~R128_CRTC_CUR_EN);
-    }
-}
-
-/* Determine if hardware cursor is in use. */
-static Bool R128UseHWCursor(ScreenPtr pScreen, CursorPtr pCurs)
-{
-    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
-    R128InfoPtr info  = R128PTR(pScrn);
-
-    return info->cursor_start ? TRUE : FALSE;
+        OUTREG(R128_CRTC2_GEN_CNTL, save2);
 }
 
 /* Initialize hardware cursor support. */
@@ -257,77 +248,72 @@ Bool R128CursorInit(ScreenPtr pScreen)
 {
     ScrnInfoPtr           pScrn   = xf86ScreenToScrn(pScreen);
     R128InfoPtr           info    = R128PTR(pScrn);
-    xf86CursorInfoPtr     cursor;
     FBAreaPtr             fbarea  = NULL;
 #ifdef USE_EXA
     ExaOffscreenArea*	  osArea  = NULL;
 #else
     void*		  osArea  = NULL;
 #endif
+    xf86CrtcConfigPtr     xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+    CARD32                cursor_offset = 0;
+    int                   cpp = info->CurrentLayout.pixel_bytes;
     int                   width;
+    int                   width_bytes;
     int                   height;
     int                   size;
+    int                   size_bytes;
+    int                   c;
 
-    int                   cpp = info->CurrentLayout.pixel_bytes;
-
-    if (!(cursor = info->cursor = xf86CreateCursorInfoRec())) return FALSE;
-
-    cursor->MaxWidth          = 64;
-    cursor->MaxHeight         = 64;
-    cursor->Flags             = (HARDWARE_CURSOR_TRUECOLOR_AT_8BPP
-				 | HARDWARE_CURSOR_SHOW_TRANSPARENT
-				 | HARDWARE_CURSOR_UPDATE_UNHIDDEN
-#if X_BYTE_ORDER == X_LITTLE_ENDIAN
-				 | HARDWARE_CURSOR_BIT_ORDER_MSBFIRST
-#endif
-				 | HARDWARE_CURSOR_INVERT_MASK
-				 | HARDWARE_CURSOR_AND_SOURCE_WITH_MASK
-				 | HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64
-				 | HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK);
-
-    cursor->SetCursorColors   = R128SetCursorColors;
-    cursor->SetCursorPosition = R128SetCursorPosition;
-    cursor->LoadCursorImage   = R128LoadCursorImage;
-    cursor->HideCursor        = R128HideCursor;
-    cursor->ShowCursor        = R128ShowCursor;
-    cursor->UseHWCursor       = R128UseHWCursor;
-
-    size                      = (cursor->MaxWidth/4) * cursor->MaxHeight;
+    size                      = CURSOR_WIDTH * CURSOR_HEIGHT / 4;
+    size_bytes                = size * 2;
     width                     = pScrn->displayWidth;
-    height                    = (size*2 + 1023) / pScrn->displayWidth;
+    width_bytes               = width * (pScrn->bitsPerPixel / 8);
+    height                    = ((size_bytes * xf86_config->num_crtc) + width_bytes - 1) / width_bytes;
 
     if(!info->useEXA) {
 	fbarea = xf86AllocateOffscreenArea(pScreen, width, height,
 					   16, NULL, NULL, NULL);
 
-	if (fbarea) {
-	    info->cursor_start    = R128_ALIGN((fbarea->box.x1
-					    + width * fbarea->box.y1)
-					    * cpp, 16);
-	    info->cursor_end      = info->cursor_start + size;
-	}
+	if (fbarea)
+	    cursor_offset = R128_ALIGN((fbarea->box.x1 + width * fbarea->box.y1) * cpp, 16);
     }
 #ifdef USE_EXA
     else {
 	osArea = exaOffscreenAlloc(pScreen, width * height, 16,
 				   TRUE, NULL, NULL);
 
-	if (osArea) {
-	    info->cursor_start	  = osArea->offset;
-	    info->cursor_end	  = osArea->offset + osArea->size;
-	}
+	if (osArea)
+	    cursor_offset = osArea->offset;
     }
 #endif
 
     if ((!info->useEXA && !fbarea) || (info->useEXA && !osArea)) {
-	info->cursor_start    = 0;
 	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
 		   "Hardware cursor disabled"
 		   " due to insufficient offscreen memory\n");
+        return FALSE;
+    } else {
+        for (c = 0; c < xf86_config->num_crtc; c++) {
+            xf86CrtcPtr crtc = xf86_config->crtc[c];
+	    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
+
+            r128_crtc->cursor_offset = cursor_offset + (c * size);
+            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		       "Will use %d kb for hardware cursor %d at offset 0x%08x\n",
+		       (size_bytes * xf86_config->num_crtc) / 1024, c,
+		       (unsigned int)r128_crtc->cursor_offset);
+        }
     }
 
-    R128TRACE(("R128CursorInit (0x%08x-0x%08x)\n",
-	       info->cursor_start, info->cursor_end));
-
-    return xf86InitCursor(pScreen, cursor);
+    return xf86_cursors_init(pScreen, CURSOR_WIDTH, CURSOR_HEIGHT,
+			     (HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
+			      HARDWARE_CURSOR_AND_SOURCE_WITH_MASK |
+			      HARDWARE_CURSOR_SHOW_TRANSPARENT |
+			      HARDWARE_CURSOR_UPDATE_UNHIDDEN |
+#if X_BYTE_ORDER == X_LITTLE_ENDIAN
+			      HARDWARE_CURSOR_BIT_ORDER_MSBFIRST |
+#endif
+			      HARDWARE_CURSOR_INVERT_MASK |
+			      HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK |
+			      HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64));
 }
diff --git a/src/r128_driver.c b/src/r128_driver.c
index f425c3b..9205328 100644
--- a/src/r128_driver.c
+++ b/src/r128_driver.c
@@ -84,6 +84,7 @@
 				/* X and server generic header files */
 #include "xf86.h"
 #include "xf86_OSproc.h"
+#include "xf86RandR12.h"
 #if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6
 #include "xf86RAC.h"
 #include "xf86Resources.h"
@@ -119,11 +120,6 @@ static Bool R128CloseScreen(CLOSE_SCREEN_ARGS_DECL);
 static Bool R128SaveScreen(ScreenPtr pScreen, int mode);
 static void R128Save(ScrnInfoPtr pScrn);
 static void R128Restore(ScrnInfoPtr pScrn);
-static Bool R128ModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode);
-static void R128DisplayPowerManagementSet(ScrnInfoPtr pScrn,
-					  int PowerManagementMode, int flags);
-static void R128DisplayPowerManagementSetLCD(ScrnInfoPtr pScrn,
-					  int PowerManagementMode, int flags);
 
 typedef enum {
   OPTION_NOACCEL,
@@ -258,6 +254,7 @@ static Bool R128MapMMIO(ScrnInfoPtr pScrn)
 				   info->PciTag,
 				   info->MMIOAddr,
 				   R128_MMIOSIZE);
+        if (!info->MMIO) return FALSE;
 #else
 	int err = pci_device_map_range(info->PciInfo,
 				       info->MMIOAddr,
@@ -274,7 +271,6 @@ static Bool R128MapMMIO(ScrnInfoPtr pScrn)
 #endif
     }
 
-    if (!info->MMIO) return FALSE;
     return TRUE;
 }
 
@@ -402,78 +398,6 @@ void R128WaitForVerticalSync(ScrnInfoPtr pScrn)
     }
 }
 
-/* Blank screen. */
-static void R128Blank(ScrnInfoPtr pScrn)
-{
-    R128InfoPtr   info      = R128PTR(pScrn);
-    unsigned char *R128MMIO = info->MMIO;
-
-    if(!info->IsSecondary)
-    {
-        switch(info->DisplayType)
-        {
-        case MT_LCD:
-            OUTREGP(R128_LVDS_GEN_CNTL, R128_LVDS_DISPLAY_DIS,
-                 ~R128_LVDS_DISPLAY_DIS);
-	    break;
-        case MT_CRT:
-            OUTREGP(R128_CRTC_EXT_CNTL, R128_CRTC_DISPLAY_DIS, ~R128_CRTC_DISPLAY_DIS);
-	    break;
-        case MT_DFP:
-            OUTREGP(R128_FP_GEN_CNTL, R128_FP_BLANK_DIS, ~R128_FP_BLANK_DIS);
-	    break;
-        case MT_NONE:
-        default:
-           break;
-        }
-    }
-    else
-    {
-        OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_DISP_DIS, ~R128_CRTC2_DISP_DIS);
-    }
-}
-
-/* Unblank screen. */
-static void R128Unblank(ScrnInfoPtr pScrn)
-{
-    R128InfoPtr   info      = R128PTR(pScrn);
-    unsigned char *R128MMIO = info->MMIO;
-
-    if(!info->IsSecondary)
-    {
-        switch(info->DisplayType)
-        {
-        case MT_LCD:
-            OUTREGP(R128_LVDS_GEN_CNTL, 0,
-                 ~R128_LVDS_DISPLAY_DIS);
-	    break;
-        case MT_CRT:
-            OUTREGP(R128_CRTC_EXT_CNTL, 0, ~R128_CRTC_DISPLAY_DIS);
-	    break;
-        case MT_DFP:
-            OUTREGP(R128_FP_GEN_CNTL, 0, ~R128_FP_BLANK_DIS);
-	    break;
-        case MT_NONE:
-        default:
-            break;
-        }
-    }
-    else
-    {
-        switch(info->DisplayType)
-        {
-        case MT_LCD:
-        case MT_DFP:
-        case MT_CRT:
-            OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~R128_CRTC2_DISP_DIS);
-            break;
-        case MT_NONE:
-        default:
-            break;
-        }
-    }
-}
-
 /* Compute log base 2 of val. */
 int R128MinBits(int val)
 {
@@ -1058,9 +982,9 @@ static Bool R128PreInitConfig(ScrnInfoPtr pScrn)
 	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
 		     "Option \"Display\" ignored "
 		     "(framebuffer device determines display type)\n");
-	else if (info->IsPrimary || info->IsSecondary)
+	else if (!Display)
 	    info->BIOSDisplay = R128_DUALHEAD;
-	else if (!Display || !xf86NameCmp(Display, "FP"))
+	else if (!xf86NameCmp(Display, "FP"))
 	    info->BIOSDisplay = R128_BIOS_DISPLAY_FP;
 	else if (!xf86NameCmp(Display, "BIOS"))
 	    info->BIOSDisplay = INREG8(R128_BIOS_5_SCRATCH);
@@ -1079,9 +1003,6 @@ static Bool R128PreInitConfig(ScrnInfoPtr pScrn)
 	info->BIOSDisplay     = R128_BIOS_DISPLAY_CRT;
     }
 
-    R128MMIO                  = NULL;
-    R128UnmapMMIO(pScrn);
-
 				/* RAM */
     switch (info->MemCntl & 0x3) {
     case 0:                     /* SDR SGRAM 1:1 */
@@ -1256,6 +1177,7 @@ static Bool R128PreInitDDC(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10)
 #endif
 
     if (!xf86LoadSubModule(pScrn, "ddc")) return FALSE;
+    if (!xf86LoadSubModule(pScrn, "i2c")) return FALSE;
 
 #if defined(__powerpc__) || defined(__alpha__) || defined(__sparc__)
     /* Int10 is broken on PPC and some Alphas */
@@ -1281,468 +1203,6 @@ static Bool R128PreInitGamma(ScrnInfoPtr pScrn)
     return TRUE;
 }
 
-static void
-R128I2CGetBits(I2CBusPtr b, int *Clock, int *data)
-{
-    ScrnInfoPtr   pScrn       = xf86Screens[b->scrnIndex];
-    R128InfoPtr info = R128PTR(pScrn);
-    unsigned long val;
-    unsigned char *R128MMIO = info->MMIO;
-
-    /* Get the result. */
-    val = INREG(info->DDCReg);
-    *Clock = (val & R128_GPIO_MONID_Y_3) != 0;
-    *data  = (val & R128_GPIO_MONID_Y_0) != 0;
-
-}
-
-static void
-R128I2CPutBits(I2CBusPtr b, int Clock, int data)
-{
-    ScrnInfoPtr   pScrn       = xf86Screens[b->scrnIndex];
-    R128InfoPtr info = R128PTR(pScrn);
-    unsigned long val;
-    unsigned char *R128MMIO = info->MMIO;
-
-    val = INREG(info->DDCReg)
-              & ~(CARD32)(R128_GPIO_MONID_EN_0 | R128_GPIO_MONID_EN_3);
-    val |= (Clock ? 0:R128_GPIO_MONID_EN_3);
-    val |= (data ? 0:R128_GPIO_MONID_EN_0);
-    OUTREG(info->DDCReg, val);
-}
-
-
-static Bool
-R128I2cInit(ScrnInfoPtr pScrn)
-{
-    R128InfoPtr info = R128PTR(pScrn);
-    if ( !xf86LoadSubModule(pScrn, "i2c") ) {
-        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-            "Failed to load i2c module\n");
-		return FALSE;
-    }
-
-    info->pI2CBus = xf86CreateI2CBusRec();
-    if(!info->pI2CBus) return FALSE;
-
-    info->pI2CBus->BusName    = "DDC";
-    info->pI2CBus->scrnIndex  = pScrn->scrnIndex;
-    info->DDCReg = R128_GPIO_MONID;
-    info->pI2CBus->I2CPutBits = R128I2CPutBits;
-    info->pI2CBus->I2CGetBits = R128I2CGetBits;
-    info->pI2CBus->AcknTimeout = 5;
-
-    if (!xf86I2CBusInit(info->pI2CBus)) {
-        return FALSE;
-    }
-    return TRUE;
-}
-
-/* return TRUE is a DFP is indeed connected to a DVI port */
-static Bool R128GetDFPInfo(ScrnInfoPtr pScrn)
-{
-    R128InfoPtr info  = R128PTR(pScrn);
-    int i;
-    xf86MonPtr MonInfo = NULL;
-    xf86MonPtr ddc;
-    unsigned char *R128MMIO = info->MMIO;
-
-    if(!R128I2cInit(pScrn)){
-        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-                  "I2C initialization failed!\n");
-    }
-
-    OUTREG(info->DDCReg, (INREG(info->DDCReg)
-           | R128_GPIO_MONID_MASK_0 | R128_GPIO_MONID_MASK_3));
-
-    OUTREG(info->DDCReg, INREG(info->DDCReg)
-           & ~(CARD32)(R128_GPIO_MONID_A_0 | R128_GPIO_MONID_A_3));
-
-    MonInfo = xf86DoEDID_DDC2(XF86_SCRN_ARG(pScrn), info->pI2CBus);
-    if(!MonInfo) {
-        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-                   "No DFP detected\n");
-        return FALSE;
-    }
-    xf86SetDDCproperties(pScrn, MonInfo);
-    ddc = pScrn->monitor->DDC;
-
-    for(i=0; i<4; i++)
-    {
-        if((ddc->det_mon[i].type == 0) &&
-	  (ddc->det_mon[i].section.d_timings.h_active > 0) &&
-	  (ddc->det_mon[i].section.d_timings.v_active > 0))
-        {
-            info->PanelXRes =
-                ddc->det_mon[i].section.d_timings.h_active;
-            info->PanelYRes =
-                ddc->det_mon[i].section.d_timings.v_active;
-
-            info->HOverPlus =
-                ddc->det_mon[i].section.d_timings.h_sync_off;
-            info->HSyncWidth =
-                ddc->det_mon[i].section.d_timings.h_sync_width;
-            info->HBlank =
-                ddc->det_mon[i].section.d_timings.h_blanking;
-            info->VOverPlus =
-                ddc->det_mon[i].section.d_timings.v_sync_off;
-            info->VSyncWidth =
-                ddc->det_mon[i].section.d_timings.v_sync_width;
-            info->VBlank =
-                ddc->det_mon[i].section.d_timings.v_blanking;
-        }
-    }
-    return TRUE;
-}
-
-
-static void R128SetSyncRangeFromEdid(ScrnInfoPtr pScrn, int flag)
-{
-    int i;
-    xf86MonPtr ddc = pScrn->monitor->DDC;
-    if(flag)  /*HSync*/
-    {
-        for(i=0; i<4; i++)
-        {
-            if(ddc->det_mon[i].type == DS_RANGES)
-            {
-                pScrn->monitor->nHsync = 1;
-                pScrn->monitor->hsync[0].lo =
-                    ddc->det_mon[i].section.ranges.min_h;
-                pScrn->monitor->hsync[0].hi =
-                    ddc->det_mon[i].section.ranges.max_h;
-                return;
-            }
-        }
-        /*if no sync ranges detected in detailed timing table,
-          let's try to derive them from supported VESA modes
-          Are we doing too much here!!!?
-        **/
-        i = 0;
-        if(ddc->timings1.t1 & 0x02) /*800x600 at 56*/
-        {
-            pScrn->monitor->hsync[i].lo =
-                pScrn->monitor->hsync[i].hi = 35.2;
-            i++;
-        }
-        if(ddc->timings1.t1 & 0x04) /*640x480 at 75*/
-        {
-            pScrn->monitor->hsync[i].lo =
-                pScrn->monitor->hsync[i].hi = 37.5;
-            i++;
-        }
-        if((ddc->timings1.t1 & 0x08) || (ddc->timings1.t1 & 0x01))
-        {
-            pScrn->monitor->hsync[i].lo =
-                pScrn->monitor->hsync[i].hi = 37.9;
-            i++;
-        }
-        if(ddc->timings1.t2 & 0x40)
-        {
-            pScrn->monitor->hsync[i].lo =
-                pScrn->monitor->hsync[i].hi = 46.9;
-            i++;
-        }
-        if((ddc->timings1.t2 & 0x80) || (ddc->timings1.t2 & 0x08))
-        {
-            pScrn->monitor->hsync[i].lo =
-                pScrn->monitor->hsync[i].hi = 48.1;
-            i++;
-        }
-        if(ddc->timings1.t2 & 0x04)
-        {
-            pScrn->monitor->hsync[i].lo =
-                pScrn->monitor->hsync[i].hi = 56.5;
-            i++;
-        }
-        if(ddc->timings1.t2 & 0x02)
-        {
-            pScrn->monitor->hsync[i].lo =
-                pScrn->monitor->hsync[i].hi = 60.0;
-            i++;
-        }
-        if(ddc->timings1.t2 & 0x01)
-        {
-            pScrn->monitor->hsync[i].lo =
-                pScrn->monitor->hsync[i].hi = 64.0;
-            i++;
-        }
-        pScrn->monitor->nHsync = i;
-    }
-    else      /*Vrefresh*/
-    {
-        for(i=0; i<4; i++)
-        {
-            if(ddc->det_mon[i].type == DS_RANGES)
-            {
-                pScrn->monitor->nVrefresh = 1;
-                pScrn->monitor->vrefresh[0].lo =
-                    ddc->det_mon[i].section.ranges.min_v;
-                pScrn->monitor->vrefresh[0].hi =
-                    ddc->det_mon[i].section.ranges.max_v;
-                return;
-            }
-        }
-        i = 0;
-        if(ddc->timings1.t1 & 0x02) /*800x600 at 56*/
-        {
-            pScrn->monitor->vrefresh[i].lo =
-                pScrn->monitor->vrefresh[i].hi = 56;
-            i++;
-        }
-        if((ddc->timings1.t1 & 0x01) || (ddc->timings1.t2 & 0x08))
-        {
-            pScrn->monitor->vrefresh[i].lo =
-                pScrn->monitor->vrefresh[i].hi = 60;
-            i++;
-        }
-        if(ddc->timings1.t2 & 0x04)
-        {
-            pScrn->monitor->vrefresh[i].lo =
-                pScrn->monitor->vrefresh[i].hi = 70;
-            i++;
-        }
-        if((ddc->timings1.t1 & 0x08) || (ddc->timings1.t2 & 0x80))
-        {
-            pScrn->monitor->vrefresh[i].lo =
-                pScrn->monitor->vrefresh[i].hi = 72;
-            i++;
-        }
-        if((ddc->timings1.t1 & 0x04) || (ddc->timings1.t2 & 0x40)
-           || (ddc->timings1.t2 & 0x02) || (ddc->timings1.t2 & 0x01))
-        {
-            pScrn->monitor->vrefresh[i].lo =
-                pScrn->monitor->vrefresh[i].hi = 75;
-            i++;
-        }
-        pScrn->monitor->nVrefresh = i;
-    }
-}
-
-/***********
-   free's xf86ValidateModes routine deosn't work well with DFPs
-   here is our own validation routine. All modes between
-   640<=XRes<=MaxRes and 480<=YRes<=MaxYRes will be permitted.
-   NOTE: RageProII doesn't support rmx, can only work with the
-         standard modes the monitor can support (scale).
-************/
-
-static int R128ValidateFPModes(ScrnInfoPtr pScrn)
-{
-    int i, j, count=0, width, height;
-    R128InfoPtr info = R128PTR(pScrn);
-    DisplayModePtr last = NULL, new = NULL, first = NULL;
-    xf86MonPtr ddc;
-
-    /* Free any allocated modes during configuration. We don't need them*/
-    while (pScrn->modes)
-    {
-	    xf86DeleteMode(&pScrn->modes, pScrn->modes);
-    }
-    while (pScrn->modePool)
-    {
-	    xf86DeleteMode(&pScrn->modePool, pScrn->modePool);
-    }
-
-    pScrn->virtualX = pScrn->display->virtualX;
-    pScrn->virtualY = pScrn->display->virtualY;
-
-    /* If no mode specified in config, we use native resolution*/
-    if(!pScrn->display->modes[0])
-    {
-        pScrn->display->modes[0] = xnfalloc(16);
-        sprintf(pScrn->display->modes[0], "%dx%d",
-               info->PanelXRes, info->PanelYRes);
-    }
-
-    for(i=0; pScrn->display->modes[i] != NULL; i++)
-    {
-        if (sscanf(pScrn->display->modes[i], "%dx%d", &width, &height) == 2)
-        {
-
-            if(width < 640 || width > info->PanelXRes ||
-               height < 480 || height > info->PanelYRes)
-            {
-                xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
-                    "Mode %s is out of range.\n"
-                    "Valid mode should be between 640x480-%dx%d\n",
-                    pScrn->display->modes[i], info->PanelXRes, info->PanelYRes);
-                continue;
-            }
-
-            new = xnfcalloc(1, sizeof(DisplayModeRec));
-            new->prev = last;
-            new->name = xnfalloc(strlen(pScrn->display->modes[i]) + 1);
-            strcpy(new->name, pScrn->display->modes[i]);
-            new->HDisplay = new->CrtcHDisplay = width;
-            new->VDisplay = new->CrtcVDisplay = height;
-
-            ddc = pScrn->monitor->DDC;
-            for(j=0; j<DET_TIMINGS; j++)
-            {
-                /*We use native mode clock only*/
-                if(ddc->det_mon[j].type == 0){
-                    new->Clock = ddc->det_mon[j].section.d_timings.clock / 1000;
-                    break;
-                }
-            }
-
-            if(new->prev) new->prev->next = new;
-            last = new;
-            if(!first) first = new;
-            pScrn->display->virtualX =
-            pScrn->virtualX = MAX(pScrn->virtualX, width);
-            pScrn->display->virtualY =
-            pScrn->virtualY = MAX(pScrn->virtualY, height);
-            count++;
-        }
-        else
-        {
-            xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
-                "Mode name %s is invalid\n", pScrn->display->modes[i]);
-            continue;
-        }
-   }
-
-   if(last)
-   {
-       last->next = first;
-       first->prev = last;
-       pScrn->modes = first;
-
-       /*FIXME: May need to validate line pitch here*/
-       {
-           int dummy = 0;
-           switch(pScrn->depth / 8)
-           {
-              case 1:
-                  dummy = 128 - pScrn->virtualX % 128;
-                  break;
-              case 2:
-                  dummy = 32 - pScrn->virtualX % 32;
-                  break;
-              case 3:
-              case 4:
-                  dummy = 16 - pScrn->virtualX % 16;
-           }
-           pScrn->displayWidth = pScrn->virtualX + dummy;
-       }
-
-   }
-
-   return count;
-}
-
-
-/* This is called by R128PreInit to validate modes and compute parameters
-   for all of the valid modes. */
-static Bool R128PreInitModes(ScrnInfoPtr pScrn)
-{
-    R128InfoPtr   info = R128PTR(pScrn);
-    ClockRangePtr clockRanges;
-    int           modesFound;
-
-    if(info->isDFP) {
-        R128MapMem(pScrn);
-        info->BIOSDisplay = R128_BIOS_DISPLAY_FP;
-        /* validate if DFP really connected. */
-        if(!R128GetDFPInfo(pScrn)) {
-            info->isDFP = FALSE;
-            info->BIOSDisplay = R128_BIOS_DISPLAY_CRT;
-        } else if(!info->isPro2) {
-            /* RageProII doesn't support rmx, we can't use native-mode
-               stretching for other non-native modes. It will rely on
-               whatever VESA modes monitor can support. */
-            modesFound = R128ValidateFPModes(pScrn);
-            if(modesFound < 1) {
-                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-                     "No valid mode found for this DFP/LCD\n");
-                 R128UnmapMem(pScrn);
-                 return FALSE;
-
-            }
-        }
-        R128UnmapMem(pScrn);
-    }
-
-    if(!info->isDFP || info->isPro2) {
-				/* Get mode information */
-        pScrn->progClock                   = TRUE;
-        clockRanges                        = xnfcalloc(sizeof(*clockRanges), 1);
-        clockRanges->next                  = NULL;
-        clockRanges->minClock              = info->pll.min_pll_freq;
-        clockRanges->maxClock              = info->pll.max_pll_freq * 10;
-        clockRanges->clockIndex            = -1;
-        if (info->HasPanelRegs || info->isDFP) {
-            clockRanges->interlaceAllowed  = FALSE;
-            clockRanges->doubleScanAllowed = FALSE;
-        } else {
-            clockRanges->interlaceAllowed  = TRUE;
-            clockRanges->doubleScanAllowed = TRUE;
-        }
-
-        if(pScrn->monitor->DDC) {
-        /*if we still don't know sync range yet, let's try EDID.
-          Note that, since we can have dual heads, the Xconfigurator
-          may not be able to probe both monitors correctly through
-          vbe probe function (R128ProbeDDC). Here we provide an
-          additional way to auto-detect sync ranges if they haven't
-          been added to XF86Config manually.
-        **/
-            if(pScrn->monitor->nHsync <= 0)
-                R128SetSyncRangeFromEdid(pScrn, 1);
-            if(pScrn->monitor->nVrefresh <= 0)
-                R128SetSyncRangeFromEdid(pScrn, 0);
-        }
-
-        modesFound = xf86ValidateModes(pScrn,
-				   pScrn->monitor->Modes,
-				   pScrn->display->modes,
-				   clockRanges,
-				   NULL,        /* linePitches */
-				   8 * 64,      /* minPitch */
-				   8 * 1024,    /* maxPitch */
-/*
- * ATI docs say pitchInc must be 8 * 64, but this doesn't permit a pitch of
- * 800 bytes, which is known to work on the Rage128 LF on clamshell iBooks
- */
-				   8 * 32,      /* pitchInc */
-				   128,         /* minHeight */
-				   2048,        /* maxHeight */
-				   pScrn->display->virtualX,
-				   pScrn->display->virtualY,
-				   info->FbMapSize,
-				   LOOKUP_BEST_REFRESH);
-
-        if (modesFound < 1 && info->FBDev) {
-		fbdevHWUseBuildinMode(pScrn);
-		pScrn->displayWidth = fbdevHWGetLineLength(pScrn)/(pScrn->bitsPerPixel/8);
-		modesFound = 1;
-        }
-
-        if (modesFound == -1) return FALSE;
-        xf86PruneDriverModes(pScrn);
-        if (!modesFound || !pScrn->modes) {
-            xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
-            return FALSE;
-        }
-        xf86SetCrtcForModes(pScrn, 0);
-    }
-				/* Set DPI */
-    pScrn->currentMode = pScrn->modes;
-    xf86PrintModes(pScrn);
-
-    xf86SetDpi(pScrn, 0, 0);
-
-				/* Get ScreenInit function */
-    if (!xf86LoadSubModule(pScrn, "fb")) return FALSE;
-
-    info->CurrentLayout.displayWidth = pScrn->displayWidth;
-    info->CurrentLayout.mode = pScrn->currentMode;
-
-    return TRUE;
-}
-
 /* This is called by R128PreInit to initialize the hardware cursor. */
 static Bool R128PreInitCursor(ScrnInfoPtr pScrn)
 {
@@ -1885,6 +1345,43 @@ static Bool R128PreInitDRI(ScrnInfoPtr pScrn)
 }
 #endif
 
+static Bool R128PreInitControllers(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10)
+{
+    R128InfoPtr info = R128PTR(pScrn);
+    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
+    int i;
+    int mask;
+    int found = 0;
+
+    if (info->IsPrimary)
+        mask = 1;
+    else if (info->IsSecondary)
+        mask = 2;
+    else
+        mask = 3;
+
+    if (!R128GetBIOSParameters(pScrn, pInt10))
+        return FALSE;
+
+    if (!R128GetPLLParameters(pScrn))
+        return FALSE;
+
+    if (!R128AllocateControllers(pScrn, mask))
+        return FALSE;
+
+    if (!R128SetupConnectors(pScrn))
+        return FALSE;
+
+    for (i = 0; i < config->num_output; i++) {
+        xf86OutputPtr output = config->output[i];
+
+        output->status = (*output->funcs->detect) (output);
+        if (output->status == XF86OutputStatusConnected)
+            found++;
+    }
+    return !!found;
+}
+
 static void
 R128ProbeDDC(ScrnInfoPtr pScrn, int indx)
 {
@@ -1899,6 +1396,17 @@ R128ProbeDDC(ScrnInfoPtr pScrn, int indx)
 #endif
 }
 
+static Bool R128CRTCResize(ScrnInfoPtr pScrn, int width, int height)
+{
+    pScrn->virtualX = width;
+    pScrn->virtualY = height;
+    return TRUE;
+}
+
+static const xf86CrtcConfigFuncsRec R128CRTCResizeFuncs = {
+    R128CRTCResize
+};
+
 /* R128PreInit is called once at server startup. */
 Bool R128PreInit(ScrnInfoPtr pScrn, int flags)
 {
@@ -1976,6 +1484,9 @@ Bool R128PreInit(ScrnInfoPtr pScrn, int flags)
 #endif
     pScrn->monitor     = pScrn->confScreen->monitor;
 
+    /* Allocate an xf86CrtcConfig */
+    xf86CrtcConfigInit(pScrn, &R128CRTCResizeFuncs);
+
     if (!R128PreInitVisual(pScrn))    goto fail;
 
 				/* We can't do this until we have a
@@ -2016,8 +1527,6 @@ Bool R128PreInit(ScrnInfoPtr pScrn, int flags)
                "module load skipped\n");
 #endif
 
-
-
     if (!R128PreInitWeight(pScrn))    goto fail;
 
     if(xf86GetOptValInteger(info->Options, OPTION_VIDEO_KEY, &(info->videoKey))) {
@@ -2053,20 +1562,30 @@ Bool R128PreInit(ScrnInfoPtr pScrn, int flags)
     }
 
     if (!info->FBDev)
-	if (!R128PreInitInt10(pScrn, &pInt10)) goto fail;
-
-    if (!R128PreInitConfig(pScrn))             goto fail;
+	if (!R128PreInitInt10(pScrn, &pInt10))  goto fail;
 
-    if (!R128GetBIOSParameters(pScrn, pInt10)) goto fail;
+    if (!R128PreInitConfig(pScrn))              goto fail;
 
-    if (!R128GetPLLParameters(pScrn))          goto fail;
+    xf86CrtcSetSizeRange(pScrn, 320, 200, 4096, 4096);
 
     /* Don't fail on this one */
-    R128PreInitDDC(pScrn, pInt10);
+    info->DDC = R128PreInitDDC(pScrn, pInt10);
 
-    if (!R128PreInitGamma(pScrn))              goto fail;
+    if (!R128PreInitControllers(pScrn, pInt10)) goto fail;
+
+    if (!xf86InitialConfiguration(pScrn, TRUE)) {
+        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n");
+        goto fail;
+    }
+    pScrn->displayWidth = (pScrn->virtualX + 63) & ~63;
 
-    if (!R128PreInitModes(pScrn))              goto fail;
+    /* Set display resolution */
+    xf86SetDpi(pScrn, 0, 0);
+
+    /* Get ScreenInit function */
+    if (!xf86LoadSubModule(pScrn, "fb")) return FALSE;
+
+    if (!R128PreInitGamma(pScrn))              goto fail;
 
     if (!R128PreInitCursor(pScrn))             goto fail;
 
@@ -2074,6 +1593,18 @@ Bool R128PreInit(ScrnInfoPtr pScrn, int flags)
     if (!R128PreInitDRI(pScrn))                goto fail;
 #endif
 
+    info->CurrentLayout.displayWidth = pScrn->displayWidth;
+
+    if (!xf86RandR12PreInit(pScrn)) {
+        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "RandR initialization failure\n");
+        goto fail;
+    }
+
+    if (pScrn->modes == NULL) {
+        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n");
+        goto fail;
+    }
+
 				/* Free the video bios (if applicable) */
     if (info->VBIOS) {
 	free(info->VBIOS);
@@ -2084,6 +1615,9 @@ Bool R128PreInit(ScrnInfoPtr pScrn, int flags)
     if (pInt10)
 	xf86FreeInt10(pInt10);
 
+    if (info->MMIO) R128UnmapMMIO(pScrn);
+    info->MMIO = NULL;
+
     xf86DrvMsg(pScrn->scrnIndex, X_NOTICE,
 	"For information on using the multimedia capabilities\n\tof this"
 	" adapter, please see http://gatos.sf.net.\n");
@@ -2116,56 +1650,66 @@ static void R128LoadPalette(ScrnInfoPtr pScrn, int numColors,
 			    int *indices, LOCO *colors, VisualPtr pVisual)
 {
     R128InfoPtr   info      = R128PTR(pScrn);
-    unsigned char *R128MMIO = info->MMIO;
-    int           i, j;
-    int           idx;
-    unsigned char r, g, b;
-
-    /* If the second monitor is connected, we also 
-       need to deal with the secondary palette*/
-    if (info->IsSecondary) j = 1;
-    else j = 0;
-    
-    PAL_SELECT(j);
+    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+    int i, j;
+    int c, index;
+    CARD16 lut_r[256], lut_g[256], lut_b[256];
+
+    for (c = 0; c < xf86_config->num_crtc; c++) {
+        xf86CrtcPtr crtc = xf86_config->crtc[c];
+        R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
+
+        for (i = 0 ; i < 256; i++) {
+            lut_r[i] = r128_crtc->lut_r[i] << 8;
+            lut_g[i] = r128_crtc->lut_g[i] << 8;
+            lut_b[i] = r128_crtc->lut_b[i] << 8;
+        }
 
+        switch (info->CurrentLayout.depth) {
+        case 15:
+            for (i = 0; i < numColors; i++) {
+                index = indices[i];
+                for (j = 0; j < 8; j++) {
+                    lut_r[index * 8 + j] = colors[index].red << 8;
+                    lut_g[index * 8 + j] = colors[index].green << 8;
+                    lut_b[index * 8 + j] = colors[index].blue << 8;
+                }
+            }
+        case 16:
+            for (i = 0; i < numColors; i++) {
+                index = indices[i];
+
+                /* XXX: The old version of R128LoadPalette did not do this and
+                 * the old version of RADEONLoadPalette has a comment asking why.
+                 */
+                if (i <= 31) {
+                    for (j = 0; j < 8; j++) {
+                        lut_r[index * 8 + j] = colors[index].red << 8;
+                        lut_b[index * 8 + j] = colors[index].blue << 8;
+                    }
+                }
 
-    /* Select palette 0 (main CRTC) if using FP-enabled chip */
-    /*if (info->HasPanelRegs || info->isDFP) PAL_SELECT(0);*/
+                for (j = 0; j < 4; j++) {
+                    lut_g[index * 4 + j] = colors[index].green << 8;
+                }
+            }
+        default:
+            for (i = 0; i < numColors; i++) {
+                index = indices[i];
+                lut_r[index] = colors[index].red << 8;
+                lut_g[index] = colors[index].green << 8;
+                lut_b[index] = colors[index].blue << 8;
+            }
+            break;
+        }
 
-    if (info->CurrentLayout.depth == 15) {
-	/* 15bpp mode.  This sends 32 values. */
-	for (i = 0; i < numColors; i++) {
-	    idx = indices[i];
-	    r   = colors[idx].red;
-	    g   = colors[idx].green;
-	    b   = colors[idx].blue;
-	    OUTPAL(idx * 8, r, g, b);
-	}
-    }
-    else if (info->CurrentLayout.depth == 16) {
-	/* 16bpp mode.  This sends 64 values. */
-				/* There are twice as many green values as
-				   there are values for red and blue.  So,
-				   we take each red and blue pair, and
-				   combine it with each of the two green
-				   values. */
-	for (i = 0; i < numColors; i++) {
-	    idx = indices[i];
-	    r   = colors[idx / 2].red;
-	    g   = colors[idx].green;
-	    b   = colors[idx / 2].blue;
-	    OUTPAL(idx * 4, r, g, b);
-	}
-    }
-    else {
-	/* 8bpp mode.  This sends 256 values. */
-	for (i = 0; i < numColors; i++) {
-	    idx = indices[i];
-	    r   = colors[idx].red;
-	    b   = colors[idx].blue;
-	    g   = colors[idx].green;
-	    OUTPAL(idx, r, g, b);
-	}
+        /* Make the change through RandR */
+#ifdef RANDR_12_INTERFACE
+        if (crtc->randr_crtc)
+            RRCrtcGammaSet(crtc->randr_crtc, lut_r, lut_g, lut_b);
+        else
+#endif
+        crtc->funcs->gamma_set(crtc, lut_r, lut_g, lut_b, 256);
     }
 }
 
@@ -2296,14 +1840,6 @@ Bool R128ScreenInit(SCREEN_INIT_ARGS_DECL)
     info->PaletteSavedOnVT = FALSE;
 
     R128Save(pScrn);
-    if (info->FBDev) {
-	if (!fbdevHWModeInit(pScrn, pScrn->currentMode)) return FALSE;
-    } else {
-	if (!R128ModeInit(pScrn, pScrn->currentMode)) return FALSE;
-    }
-
-    R128SaveScreen(pScreen, SCREEN_SAVER_ON);
-    pScrn->AdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
 
 				/* Visual setup */
     miClearVisualTypes();
@@ -2701,6 +2237,19 @@ Bool R128ScreenInit(SCREEN_INIT_ARGS_DECL)
 #endif
     }
 
+    pScrn->vtSema = TRUE;
+    /* xf86CrtcRotate accesses pScrn->pScreen */
+    pScrn->pScreen = pScreen;
+
+    if (info->FBDev) {
+	if (!fbdevHWModeInit(pScrn, pScrn->currentMode)) return FALSE;
+    } else {
+	if (!xf86SetDesiredModes(pScrn)) return FALSE;
+    }
+
+    R128SaveScreen(pScreen, SCREEN_SAVER_ON);
+    //pScrn->AdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
+
 				/* DGA setup */
     R128DGAInit(pScreen);
 
@@ -2737,28 +2286,11 @@ Bool R128ScreenInit(SCREEN_INIT_ARGS_DECL)
 	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using software cursor\n");
     }
 
-				/* Colormap setup */
-    if (!miCreateDefColormap(pScreen)) return FALSE;
-    if (!xf86HandleColormaps(pScreen, 256, info->dac6bits ? 6 : 8,
-			     (info->FBDev ? fbdevHWLoadPaletteWeak() :
-			     R128LoadPalette), NULL,
-			     CMAP_PALETTED_TRUECOLOR
-			     | CMAP_RELOAD_ON_MODE_SWITCH
-#if 0 /* This option messes up text mode! (eich at suse.de) */
-			     | CMAP_LOAD_EVEN_IF_OFFSCREEN
-#endif
-			     )) return FALSE;
-
     /* DPMS setup - FIXME: also for mirror mode in non-fbdev case? - Michel */
     if (info->FBDev)
 	xf86DPMSInit(pScreen, fbdevHWDPMSSetWeak(), 0);
-
-    else {
-	if (info->DisplayType == MT_LCD)
-	    xf86DPMSInit(pScreen, R128DisplayPowerManagementSetLCD, 0);
-	else
-	    xf86DPMSInit(pScreen, R128DisplayPowerManagementSet, 0);
-    }
+    else
+        xf86DPMSInit(pScreen, xf86DPMSSet, 0);
 
     if (!info->IsSecondary)
 	R128InitVideo(pScreen);
@@ -2793,11 +2325,25 @@ Bool R128ScreenInit(SCREEN_INIT_ARGS_DECL)
     info->BlockHandler = pScreen->BlockHandler;
     pScreen->BlockHandler = R128BlockHandler;
 
+    if (!xf86CrtcScreenInit(pScreen)) return FALSE;
+
+				/* Colormap setup */
+    if (!miCreateDefColormap(pScreen)) return FALSE;
+    if (!xf86HandleColormaps(pScreen, 256, info->dac6bits ? 6 : 8,
+			     (info->FBDev ? fbdevHWLoadPaletteWeak() :
+			     R128LoadPalette), NULL,
+			     CMAP_PALETTED_TRUECOLOR
+			     | CMAP_RELOAD_ON_MODE_SWITCH
+#if 0 /* This option messes up text mode! (eich at suse.de) */
+			     | CMAP_LOAD_EVEN_IF_OFFSCREEN
+#endif
+			     )) return FALSE;
+
     return TRUE;
 }
 
 /* Write common registers (initialized to 0). */
-static void R128RestoreCommonRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
+void R128RestoreCommonRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
 {
     R128InfoPtr   info      = R128PTR(pScrn);
     unsigned char *R128MMIO = info->MMIO;
@@ -2821,7 +2367,7 @@ static void R128RestoreCommonRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
 }
 
 /* Write CRTC registers. */
-static void R128RestoreCrtcRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
+void R128RestoreCrtcRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
 {
     R128InfoPtr   info      = R128PTR(pScrn);
     unsigned char *R128MMIO = info->MMIO;
@@ -2844,7 +2390,7 @@ static void R128RestoreCrtcRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
 }
 
 /* Write CRTC2 registers. */
-static void R128RestoreCrtc2Registers(ScrnInfoPtr pScrn,
+void R128RestoreCrtc2Registers(ScrnInfoPtr pScrn,
 				       R128SavePtr restore)
 {
     R128InfoPtr info        = R128PTR(pScrn);
@@ -2863,7 +2409,7 @@ static void R128RestoreCrtc2Registers(ScrnInfoPtr pScrn,
 }
 
 /* Write flat panel registers */
-static void R128RestoreFPRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
+void R128RestoreFPRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
 {
     R128InfoPtr   info      = R128PTR(pScrn);
     unsigned char *R128MMIO = info->MMIO;
@@ -2936,7 +2482,7 @@ static void R128PLL2WriteUpdate(ScrnInfoPtr pScrn)
 }
 
 /* Write PLL registers. */
-static void R128RestorePLLRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
+void R128RestorePLLRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
 {
     R128InfoPtr   info      = R128PTR(pScrn);
     unsigned char *R128MMIO = info->MMIO;
@@ -2999,7 +2545,7 @@ static void R128RestorePLLRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
 }
 
 /* Write PLL2 registers. */
-static void R128RestorePLL2Registers(ScrnInfoPtr pScrn, R128SavePtr restore)
+void R128RestorePLL2Registers(ScrnInfoPtr pScrn, R128SavePtr restore)
 {
     R128InfoPtr info        = R128PTR(pScrn);
     unsigned char *R128MMIO = info->MMIO;
@@ -3068,7 +2614,7 @@ static void R128RestorePLL2Registers(ScrnInfoPtr pScrn, R128SavePtr restore)
 }
 
 /* Write DDA registers. */
-static void R128RestoreDDARegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
+void R128RestoreDDARegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
 {
     R128InfoPtr   info      = R128PTR(pScrn);
     unsigned char *R128MMIO = info->MMIO;
@@ -3078,7 +2624,7 @@ static void R128RestoreDDARegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
 }
 
 /* Write DDA registers. */
-static void R128RestoreDDA2Registers(ScrnInfoPtr pScrn, R128SavePtr restore)
+void R128RestoreDDA2Registers(ScrnInfoPtr pScrn, R128SavePtr restore)
 {
     R128InfoPtr   info      = R128PTR(pScrn);
     unsigned char *R128MMIO = info->MMIO;
@@ -3087,126 +2633,6 @@ static void R128RestoreDDA2Registers(ScrnInfoPtr pScrn, R128SavePtr restore)
     OUTREG(R128_DDA2_ON_OFF, restore->dda2_on_off);
 }
 
-/* Write palette data. */
-static void R128RestorePalette(ScrnInfoPtr pScrn, R128SavePtr restore)
-{
-    R128InfoPtr   info      = R128PTR(pScrn);
-    unsigned char *R128MMIO = info->MMIO;
-    int           i;
-
-    if (!restore->palette_valid) return;
-
-    PAL_SELECT(1);
-    OUTPAL_START(0);
-    for (i = 0; i < 256; i++) {
-	R128WaitForFifo(pScrn, 32); /* delay */
-	OUTPAL_NEXT_CARD32(restore->palette2[i]);
-    }
-
-    PAL_SELECT(0);
-    OUTPAL_START(0);
-    for (i = 0; i < 256; i++) {
-	R128WaitForFifo(pScrn, 32); /* delay */
-	OUTPAL_NEXT_CARD32(restore->palette[i]);
-    }
-
-}
-
-/* Write out state to define a new video mode.  */
-static void R128RestoreMode(ScrnInfoPtr pScrn, R128SavePtr restore)
-{
-    R128InfoPtr info = R128PTR(pScrn);
-    DevUnion* pPriv;
-    R128EntPtr pR128Ent;
-    static R128SaveRec restore0;
-
-    R128TRACE(("R128RestoreMode(%p)\n", restore));
-    if(!info->HasCRTC2)
-    {
-    	R128RestoreCommonRegisters(pScrn, restore);
-        R128RestoreDDARegisters(pScrn, restore);
-    	R128RestoreCrtcRegisters(pScrn, restore);
-        if((info->DisplayType == MT_DFP) || 
-           (info->DisplayType == MT_LCD))
-        {
-	    R128RestoreFPRegisters(pScrn, restore);
-        }
-        R128RestorePLLRegisters(pScrn, restore);
-        return;
-    }       
-    
-    pPriv = xf86GetEntityPrivate(pScrn->entityList[0], 
-                   getR128EntityIndex());
-    pR128Ent = pPriv->ptr;
-   
-
-    /*****
-      When changing mode with Dual-head card (VE/M6), care must
-      be taken for the special order in setting registers. CRTC2 has
-      to be set before changing CRTC_EXT register.
-      In the dual-head setup, X server calls this routine twice with
-      primary and secondary pScrn pointers respectively. The calls
-      can come with different order. Regardless the order of X server issuing 
-      the calls, we have to ensure we set registers in the right order!!! 
-      Otherwise we may get a blank screen.
-    *****/
-
-    if(info->IsSecondary)
-    {
-	if (!pR128Ent->RestorePrimary  && !info->SwitchingMode)
-	    R128RestoreCommonRegisters(pScrn, restore);
-        R128RestoreDDA2Registers(pScrn, restore);
-        R128RestoreCrtc2Registers(pScrn, restore);        
-        R128RestorePLL2Registers(pScrn, restore);
-        
-	if(info->SwitchingMode) return;
-
-        pR128Ent->IsSecondaryRestored = TRUE;
-
-        if(pR128Ent->RestorePrimary)
-        {
-            R128InfoPtr info0 = R128PTR(pR128Ent->pPrimaryScrn); 
-            pR128Ent->RestorePrimary = FALSE;
-
-            R128RestoreCrtcRegisters(pScrn, &restore0);
-            if((info0->DisplayType == MT_DFP) || 
-               (info0->DisplayType == MT_LCD))
-            {
-                R128RestoreFPRegisters(pScrn, &restore0);
-            }
-            
-            R128RestorePLLRegisters(pScrn, &restore0);   
-            pR128Ent->IsSecondaryRestored = FALSE;
-
-        }
-    }
-    else
-    {
-	if (!pR128Ent->IsSecondaryRestored)
-            R128RestoreCommonRegisters(pScrn, restore);
-        R128RestoreDDARegisters(pScrn, restore);
-        if(!pR128Ent->HasSecondary || pR128Ent->IsSecondaryRestored
-            || info->SwitchingMode)
-        {
-	    pR128Ent->IsSecondaryRestored = FALSE;
-            R128RestoreCrtcRegisters(pScrn, restore);
-            if((info->DisplayType == MT_DFP) || 
-               (info->DisplayType == MT_LCD))
-            {
-               R128RestoreFPRegisters(pScrn, restore);
-            }
-            R128RestorePLLRegisters(pScrn, restore);   
-        }
-        else
-        {
-            memcpy(&restore0, restore, sizeof(restore0));
-            pR128Ent->RestorePrimary = TRUE;
-        }
-    }
-
-    R128RestorePalette(pScrn, restore);
-}
-
 /* Read common registers. */
 static void R128SaveCommonRegisters(ScrnInfoPtr pScrn, R128SavePtr save)
 {
@@ -3450,9 +2876,19 @@ static void R128Restore(ScrnInfoPtr pScrn)
         OUTREG(R128_CLOCK_CNTL_INDEX, restore->clock_cntl_index);
         OUTREG(R128_GEN_RESET_CNTL,   restore->gen_reset_cntl);
         OUTREG(R128_DP_DATATYPE,      restore->dp_datatype);
+
+        R128RestoreCommonRegisters(pScrn, restore);
+        if (info->HasCRTC2) {
+            R128RestoreDDA2Registers(pScrn, restore);
+            R128RestoreCrtc2Registers(pScrn, restore);
+            R128RestorePLL2Registers(pScrn, restore);
+        }
+        R128RestoreDDARegisters(pScrn, restore);
+        R128RestoreCrtcRegisters(pScrn, restore);
+        R128RestorePLLRegisters(pScrn, restore);
+        R128RestoreFPRegisters(pScrn, restore);
     }
 
-    R128RestoreMode(pScrn, restore);
 #ifdef WITH_VGAHW
     if (info->VGAAccess) {
         vgaHWPtr hwp = VGAHWPTR(pScrn);
@@ -3492,7 +2928,7 @@ static void R128Restore(ScrnInfoPtr pScrn)
 }
 
 /* Define common registers for requested video mode. */
-static void R128InitCommonRegisters(R128SavePtr save, R128InfoPtr info)
+void R128InitCommonRegisters(R128SavePtr save, R128InfoPtr info)
 {
     save->ovr_clr            = 0;
     save->ovr_wid_left_right = 0;
@@ -3518,8 +2954,64 @@ static void R128InitCommonRegisters(R128SavePtr save, R128InfoPtr info)
 	save->bus_cntl |= R128_BUS_RD_DISCARD_EN | R128_BUS_RD_ABORT_EN;
 }
 
+Bool R128InitCrtcBase(xf86CrtcPtr crtc, R128SavePtr save, int x, int y)
+{
+    ScrnInfoPtr pScrn = crtc->scrn;
+    R128InfoPtr info  = R128PTR(pScrn);
+    int offset = y * info->CurrentLayout.displayWidth + x;
+    int Base = pScrn->fbOffset;
+
+    switch (info->CurrentLayout.pixel_code) {
+    case 15:
+    case 16: offset *= 2; break;
+    case 24: offset *= 3; break;
+    case 32: offset *= 4; break;
+    }
+    Base += offset;
+
+    if (crtc->rotatedData != NULL)
+        Base = pScrn->fbOffset + (char *)crtc->rotatedData - (char *)info->FB;
+
+    Base &= ~7;                 /* 3 lower bits are always 0 */
+    if (info->CurrentLayout.pixel_code == 24)
+	Base += 8 * (Base % 3); /* Must be multiple of 8 and 3 */
+
+    save->crtc_offset = Base;
+    save->crtc_offset_cntl = 0;
+
+    return TRUE;
+}
+
+Bool R128InitCrtc2Base(xf86CrtcPtr crtc, R128SavePtr save, int x, int y)
+{
+    ScrnInfoPtr pScrn = crtc->scrn;
+    R128InfoPtr info  = R128PTR(pScrn);
+    int offset = y * info->CurrentLayout.displayWidth + x;
+    int Base = pScrn->fbOffset;
+
+    switch (info->CurrentLayout.pixel_code) {
+    case 15:
+    case 16: offset *= 2; break;
+    case 24: offset *= 3; break;
+    case 32: offset *= 4; break;
+    }
+    Base += offset;
+
+    if (crtc->rotatedData != NULL)
+        Base = pScrn->fbOffset + (char *)crtc->rotatedData - (char *)info->FB;
+
+    Base &= ~7;                 /* 3 lower bits are always 0 */
+    if (info->CurrentLayout.pixel_code == 24)
+	Base += 8 * (Base % 3); /* Must be multiple of 8 and 3 */
+
+    save->crtc2_offset = Base;
+    save->crtc2_offset_cntl = 0;
+
+    return TRUE;
+}
+
 /* Define CRTC registers for requested video mode. */
-static Bool R128InitCrtcRegisters(ScrnInfoPtr pScrn, R128SavePtr save,
+Bool R128InitCrtcRegisters(ScrnInfoPtr pScrn, R128SavePtr save,
 				  DisplayModePtr mode, R128InfoPtr info)
 {
     int    format;
@@ -3633,8 +3125,6 @@ static Bool R128InitCrtcRegisters(ScrnInfoPtr pScrn, R128SavePtr save,
 				 | ((mode->Flags & V_NVSYNC)
 				    ? R128_CRTC_V_SYNC_POL
 				    : 0));
-    save->crtc_offset      = 0;
-    save->crtc_offset_cntl = 0;
     save->crtc_pitch       = info->CurrentLayout.displayWidth / 8;
 
     R128TRACE(("Pitch = %d bytes (virtualX = %d, displayWidth = %d)\n",
@@ -3654,7 +3144,7 @@ static Bool R128InitCrtcRegisters(ScrnInfoPtr pScrn, R128SavePtr save,
 }
 
 /* Define CRTC2 registers for requested video mode. */
-static Bool R128InitCrtc2Registers(ScrnInfoPtr pScrn, R128SavePtr save,
+Bool R128InitCrtc2Registers(ScrnInfoPtr pScrn, R128SavePtr save,
 				  DisplayModePtr mode, R128InfoPtr info)
 {
     int    format;
@@ -3727,10 +3217,6 @@ static Bool R128InitCrtc2Registers(ScrnInfoPtr pScrn, R128SavePtr save,
 				 | ((mode->Flags & V_NVSYNC)
 				    ? R128_CRTC2_V_SYNC_POL
 				    : 0));
-
-    save->crtc2_offset      = 0;
-    save->crtc2_offset_cntl = 0;
-
     save->crtc2_pitch       = info->CurrentLayout.displayWidth / 8;
 	
     R128TRACE(("Pitch = %d bytes (virtualX = %d, displayWidth = %d)\n",
@@ -3740,7 +3226,7 @@ static Bool R128InitCrtc2Registers(ScrnInfoPtr pScrn, R128SavePtr save,
 }
 
 /* Define CRTC registers for requested video mode. */
-static void R128InitFPRegisters(R128SavePtr orig, R128SavePtr save,
+void R128InitFPRegisters(R128SavePtr orig, R128SavePtr save,
 				DisplayModePtr mode, R128InfoPtr info)
 {
     int   xres = mode->CrtcHDisplay;
@@ -3853,7 +3339,7 @@ static void R128InitFPRegisters(R128SavePtr orig, R128SavePtr save,
 }
 
 /* Define PLL registers for requested video mode. */
-static void R128InitPLLRegisters(ScrnInfoPtr pScrn, R128SavePtr save,
+void R128InitPLLRegisters(ScrnInfoPtr pScrn, R128SavePtr save,
 				R128PLLPtr pll, double dot_clock)
 {
     unsigned long freq = dot_clock * 100;
@@ -3905,7 +3391,7 @@ static void R128InitPLLRegisters(ScrnInfoPtr pScrn, R128SavePtr save,
 }
 
 /* Define PLL2 registers for requested video mode. */
-static void R128InitPLL2Registers(ScrnInfoPtr pScrn, R128SavePtr save,
+void R128InitPLL2Registers(ScrnInfoPtr pScrn, R128SavePtr save,
 				   R128PLLPtr pll, double dot_clock)
 {
     unsigned long freq = dot_clock * 100;
@@ -3957,7 +3443,7 @@ static void R128InitPLL2Registers(ScrnInfoPtr pScrn, R128SavePtr save,
 }
 
 /* Define DDA registers for requested video mode. */
-static Bool R128InitDDARegisters(ScrnInfoPtr pScrn, R128SavePtr save,
+Bool R128InitDDARegisters(ScrnInfoPtr pScrn, R128SavePtr save,
 				 R128PLLPtr pll, R128InfoPtr info,
                                  DisplayModePtr mode)
 {
@@ -4026,7 +3512,7 @@ static Bool R128InitDDARegisters(ScrnInfoPtr pScrn, R128SavePtr save,
 }
 
 /* Define DDA2 registers for requested video mode. */
-static Bool R128InitDDA2Registers(ScrnInfoPtr pScrn, R128SavePtr save,
+Bool R128InitDDA2Registers(ScrnInfoPtr pScrn, R128SavePtr save,
 				 R128PLLPtr pll, R128InfoPtr info,
                                  DisplayModePtr mode)
 {
@@ -4106,122 +3592,6 @@ static void R128InitPalette(R128SavePtr save)
 }
 #endif
 
-/* Define registers for a requested video mode. */
-static Bool R128Init(ScrnInfoPtr pScrn, DisplayModePtr mode, R128SavePtr save)
-{
-    R128InfoPtr info      = R128PTR(pScrn);
-    double      dot_clock = mode->Clock/1000.0;
-
-#if R128_DEBUG
-    ErrorF("%-12.12s %7.2f  %4d %4d %4d %4d  %4d %4d %4d %4d (%d,%d)",
-	   mode->name,
-	   dot_clock,
-
-	   mode->HDisplay,
-	   mode->HSyncStart,
-	   mode->HSyncEnd,
-	   mode->HTotal,
-
-	   mode->VDisplay,
-	   mode->VSyncStart,
-	   mode->VSyncEnd,
-	   mode->VTotal,
-	   pScrn->depth,
-	   pScrn->bitsPerPixel);
-    if (mode->Flags & V_DBLSCAN)   ErrorF(" D");
-    if (mode->Flags & V_CSYNC)     ErrorF(" C");
-    if (mode->Flags & V_INTERLACE) ErrorF(" I");
-    if (mode->Flags & V_PHSYNC)    ErrorF(" +H");
-    if (mode->Flags & V_NHSYNC)    ErrorF(" -H");
-    if (mode->Flags & V_PVSYNC)    ErrorF(" +V");
-    if (mode->Flags & V_NVSYNC)    ErrorF(" -V");
-    ErrorF("\n");
-    ErrorF("%-12.12s %7.2f  %4d %4d %4d %4d  %4d %4d %4d %4d (%d,%d)",
-	   mode->name,
-	   dot_clock,
-
-	   mode->CrtcHDisplay,
-	   mode->CrtcHSyncStart,
-	   mode->CrtcHSyncEnd,
-	   mode->CrtcHTotal,
-
-	   mode->CrtcVDisplay,
-	   mode->CrtcVSyncStart,
-	   mode->CrtcVSyncEnd,
-	   mode->CrtcVTotal,
-	   pScrn->depth,
-	   pScrn->bitsPerPixel);
-    if (mode->Flags & V_DBLSCAN)   ErrorF(" D");
-    if (mode->Flags & V_CSYNC)     ErrorF(" C");
-    if (mode->Flags & V_INTERLACE) ErrorF(" I");
-    if (mode->Flags & V_PHSYNC)    ErrorF(" +H");
-    if (mode->Flags & V_NHSYNC)    ErrorF(" -H");
-    if (mode->Flags & V_PVSYNC)    ErrorF(" +V");
-    if (mode->Flags & V_NVSYNC)    ErrorF(" -V");
-    ErrorF("\n");
-#endif
-
-    info->Flags = mode->Flags;
-
-    if(info->IsSecondary)
-    {
-        if (!R128InitCrtc2Registers(pScrn, save, 
-             pScrn->currentMode,info)) 
-            return FALSE;
-        R128InitPLL2Registers(pScrn, save, &info->pll, dot_clock);
-        if (!R128InitDDA2Registers(pScrn, save, &info->pll, info, mode))
-	    return FALSE;
-    }
-    else
-    {
-        R128InitCommonRegisters(save, info);
-        if(!R128InitCrtcRegisters(pScrn, save, mode, info)) 
-            return FALSE;
-        if(dot_clock) 
-        {
-            R128InitPLLRegisters(pScrn, save, &info->pll, dot_clock);
-            if (!R128InitDDARegisters(pScrn, save, &info->pll, info, mode))
-	        return FALSE;
-        }
-        else
-        {
-            save->ppll_ref_div         = info->SavedReg.ppll_ref_div;
-            save->ppll_div_3           = info->SavedReg.ppll_div_3;
-            save->htotal_cntl          = info->SavedReg.htotal_cntl;
-            save->dda_config           = info->SavedReg.dda_config;
-            save->dda_on_off           = info->SavedReg.dda_on_off;
-        }
-        /* not used for now */
-        /*if (!info->PaletteSavedOnVT) RADEONInitPalette(save);*/
-    }
-
-    if (((info->DisplayType == MT_DFP) || 
-        (info->DisplayType == MT_LCD)))
-    {
-        R128InitFPRegisters(&info->SavedReg, save, mode, info);
-    }
-
-    R128TRACE(("R128Init returns %p\n", save));
-    return TRUE;
-}
-
-/* Initialize a new mode. */
-static Bool R128ModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
-{
-    R128InfoPtr info      = R128PTR(pScrn);
-
-    if (!R128Init(pScrn, mode, &info->ModeReg)) return FALSE;
-				/* FIXME?  DRILock/DRIUnlock here? */
-    pScrn->vtSema = TRUE;
-    R128Blank(pScrn);
-    R128RestoreMode(pScrn, &info->ModeReg);
-    R128Unblank(pScrn);
-
-    info->CurrentLayout.mode = mode;
-
-    return TRUE;
-}
-
 static Bool R128SaveScreen(ScreenPtr pScreen, int mode)
 {
     ScrnInfoPtr   pScrn = xf86ScreenToScrn(pScreen);
@@ -4252,7 +3622,7 @@ Bool R128SwitchMode(SWITCH_MODE_ARGS_DECL)
     Bool ret;
 
     info->SwitchingMode = TRUE;
-    ret = R128ModeInit(pScrn, mode);
+    ret = xf86SetSingleMode(pScrn, mode, RR_Rotate_0);
     info->SwitchingMode = FALSE;
     return ret;
 }
@@ -4379,10 +3749,16 @@ Bool R128EnterVT(VT_FUNC_ARGS_DECL)
     R128InfoPtr info  = R128PTR(pScrn);
 
     R128TRACE(("R128EnterVT\n"));
+
+    pScrn->vtSema = TRUE;
     if (info->FBDev) {
         if (!fbdevHWEnterVT(VT_FUNC_ARGS)) return FALSE;
-    } else
-        if (!R128ModeInit(pScrn, pScrn->currentMode)) return FALSE;
+    } else {
+        if (!xf86SetDesiredModes(pScrn)) return FALSE;
+    }
+
+    //if (!R128ModeInit(pScrn, pScrn->currentMode)) return FALSE;
+
     if (info->accelOn)
 	R128EngineInit(pScrn);
 
@@ -4399,7 +3775,7 @@ Bool R128EnterVT(VT_FUNC_ARGS_DECL)
 #endif
 
     info->PaletteSavedOnVT = FALSE;
-    pScrn->AdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
+    //pScrn->AdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
 
     return TRUE;
 }
@@ -4504,130 +3880,3 @@ void R128FreeScreen(FREE_SCREEN_ARGS_DECL)
 #endif
     R128FreeRec(pScrn);
 }
-
-/* Sets VESA Display Power Management Signaling (DPMS) Mode.  */
-static void R128DisplayPowerManagementSet(ScrnInfoPtr pScrn,
-					  int PowerManagementMode, int flags)
-{
-    R128InfoPtr   info      = R128PTR(pScrn);
-    unsigned char *R128MMIO = info->MMIO;
-    int           mask      = (R128_CRTC_DISPLAY_DIS
-			       | R128_CRTC_HSYNC_DIS
-			       | R128_CRTC_VSYNC_DIS);
-    int             mask2     = R128_CRTC2_DISP_DIS;
-
-    switch (PowerManagementMode) {
-    case DPMSModeOn:
-	/* Screen: On; HSync: On, VSync: On */
-	if (info->IsSecondary)
-		OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~mask2);
-	else
-		OUTREGP(R128_CRTC_EXT_CNTL, 0, ~mask);
-	break;
-    case DPMSModeStandby:
-	/* Screen: Off; HSync: Off, VSync: On */
-	if (info->IsSecondary)
-		OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_DISP_DIS, ~mask2);
-	    else
-		OUTREGP(R128_CRTC_EXT_CNTL,
-			R128_CRTC_DISPLAY_DIS | R128_CRTC_HSYNC_DIS, ~mask);
-	break;
-    case DPMSModeSuspend:
-	/* Screen: Off; HSync: On, VSync: Off */
-	if (info->IsSecondary)
-		OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_DISP_DIS, ~mask2);
-	else 
-		OUTREGP(R128_CRTC_EXT_CNTL,
-			R128_CRTC_DISPLAY_DIS | R128_CRTC_VSYNC_DIS, ~mask);
-	break;
-    case DPMSModeOff:
-	/* Screen: Off; HSync: Off, VSync: Off */
-	if (info->IsSecondary)
-		OUTREGP(R128_CRTC2_GEN_CNTL, mask2, ~mask2);
-	else
-		OUTREGP(R128_CRTC_EXT_CNTL, mask, ~mask);
-	break;
-    }
-    if(info->isDFP) {
-	switch (PowerManagementMode) {
-	case DPMSModeOn:
-	    OUTREG(R128_FP_GEN_CNTL, INREG(R128_FP_GEN_CNTL) | (R128_FP_FPON | R128_FP_TDMS_EN));
-	    break;
-	case DPMSModeStandby:
-	case DPMSModeSuspend:
-	case DPMSModeOff:
-	    OUTREG(R128_FP_GEN_CNTL, INREG(R128_FP_GEN_CNTL) & ~(R128_FP_FPON | R128_FP_TDMS_EN));
-	    break;
-	}
-    }
-}
-
-static int r128_set_backlight_enable(ScrnInfoPtr pScrn, int on);
-
-static void R128DisplayPowerManagementSetLCD(ScrnInfoPtr pScrn,
-					  int PowerManagementMode, int flags)
-{
-    R128InfoPtr   info      = R128PTR(pScrn);
-    unsigned char *R128MMIO = info->MMIO;
-    int           mask      = R128_LVDS_DISPLAY_DIS;
-
-    switch (PowerManagementMode) {
-    case DPMSModeOn:
-	/* Screen: On; HSync: On, VSync: On */
-	OUTREGP(R128_LVDS_GEN_CNTL, 0, ~mask);
-        r128_set_backlight_enable(pScrn, 1);
-	break;
-    case DPMSModeStandby:
-	/* Fall through */
-    case DPMSModeSuspend:
-	/* Fall through */
-	break;
-    case DPMSModeOff:
-	/* Screen: Off; HSync: Off, VSync: Off */
-	OUTREGP(R128_LVDS_GEN_CNTL, mask, ~mask);
-        r128_set_backlight_enable(pScrn, 0);
-	break;
-    }
-}
-
-static int r128_set_backlight_enable(ScrnInfoPtr pScrn, int on)
-{
-        R128InfoPtr info        = R128PTR(pScrn);
-        unsigned char *R128MMIO = info->MMIO;
-	unsigned int lvds_gen_cntl = INREG(R128_LVDS_GEN_CNTL);
-
-	lvds_gen_cntl |= (/*R128_LVDS_BL_MOD_EN |*/ R128_LVDS_BLON);
-	if (on) {
-		lvds_gen_cntl |= R128_LVDS_DIGON;
-		if (!(lvds_gen_cntl & R128_LVDS_ON)) {
-			lvds_gen_cntl &= ~R128_LVDS_BLON;
-			OUTREG(R128_LVDS_GEN_CNTL, lvds_gen_cntl);
-			(void)INREG(R128_LVDS_GEN_CNTL);
-			usleep(10000);
-			lvds_gen_cntl |= R128_LVDS_BLON;
-			OUTREG(R128_LVDS_GEN_CNTL, lvds_gen_cntl);
-		}
-#if 0
-		lvds_gen_cntl &= ~R128_LVDS_BL_MOD_LEVEL_MASK;
-		lvds_gen_cntl |= (0xFF /* backlight_conv[level] */ <<
-				  R128_LVDS_BL_MOD_LEVEL_SHIFT);
-#endif
-		lvds_gen_cntl |= (R128_LVDS_ON | R128_LVDS_EN);
-		lvds_gen_cntl &= ~R128_LVDS_DISPLAY_DIS;
-	} else {
-#if 0
-		lvds_gen_cntl &= ~R128_LVDS_BL_MOD_LEVEL_MASK;
-		lvds_gen_cntl |= (0xFF /* backlight_conv[0] */ <<
-				  R128_LVDS_BL_MOD_LEVEL_SHIFT);
-#endif
-		lvds_gen_cntl |= R128_LVDS_DISPLAY_DIS;
-		OUTREG(R128_LVDS_GEN_CNTL, lvds_gen_cntl);
-		usleep(10);
-		lvds_gen_cntl &= ~(R128_LVDS_ON | R128_LVDS_EN | R128_LVDS_BLON
-				   | R128_LVDS_DIGON);
-	}
-
-	OUTREG(R128_LVDS_GEN_CNTL, lvds_gen_cntl);
-
-	return 0;
-}
diff --git a/src/r128_output.c b/src/r128_output.c
new file mode 100644
index 0000000..00d552f
--- /dev/null
+++ b/src/r128_output.c
@@ -0,0 +1,465 @@
+/*
+ * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and
+ *                VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation on the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR
+ * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+#include "xf86.h"
+#include "xf86Modes.h"
+
+#include "r128.h"
+#include "r128_probe.h"
+#include "r128_reg.h"
+
+static void R128ConnectorFindMonitor(ScrnInfoPtr pScrn, xf86OutputPtr output);
+
+static void r128_dpms(xf86OutputPtr output, int mode)
+{
+    switch(mode) {
+    case DPMSModeOn:
+        R128DPMSSetOn(output);
+        break;
+    case DPMSModeStandby:
+    case DPMSModeSuspend:
+    case DPMSModeOff:
+        R128DPMSSetOff(output);
+        break;
+    }
+}
+
+static void r128_save(xf86OutputPtr output)
+{
+}
+
+static void r128_restore(xf86OutputPtr output)
+{
+}
+
+static int r128_mode_valid(xf86OutputPtr output, DisplayModePtr mode)
+{
+    return MODE_OK;
+}
+
+static Bool r128_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode)
+{
+    return TRUE;
+}
+
+static void r128_mode_prepare(xf86OutputPtr output)
+{
+    r128_dpms(output, DPMSModeOff);
+}
+
+static void r128_mode_set(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode)
+{
+}
+
+static void r128_mode_commit(xf86OutputPtr output)
+{
+    r128_dpms(output, DPMSModeOn);
+}
+
+static xf86OutputStatus r128_detect(xf86OutputPtr output)
+{
+    ScrnInfoPtr pScrn = output->scrn;
+    R128OutputPrivatePtr r128_output = output->driver_private;
+
+    r128_output->MonType = MT_UNKNOWN;
+    R128ConnectorFindMonitor(pScrn, output);
+
+    if (r128_output->MonType == MT_UNKNOWN) {
+        output->subpixel_order = SubPixelUnknown;
+        return XF86OutputStatusUnknown;
+    } else if (r128_output->MonType == MT_NONE) {
+        output->subpixel_order = SubPixelUnknown;
+        return XF86OutputStatusDisconnected;
+    } else {
+        switch(r128_output->MonType) {
+        case MT_LCD:
+        case MT_DFP:
+            output->subpixel_order = SubPixelHorizontalRGB;
+            break;
+        default:
+            output->subpixel_order = SubPixelNone;
+            break;
+        }
+
+        return XF86OutputStatusConnected;
+    }
+}
+
+static DisplayModePtr r128_get_modes(xf86OutputPtr output)
+{
+    DisplayModePtr modes;
+    modes = R128ProbeOutputModes(output);
+    return modes;
+}
+
+static void r128_destroy(xf86OutputPtr output)
+{
+    if (output->driver_private)
+        free(output->driver_private);
+}
+
+static const xf86OutputFuncsRec r128_output_funcs = {
+    .dpms = r128_dpms,
+    .save = r128_save,
+    .restore = r128_restore,
+    .mode_valid = r128_mode_valid,
+    .mode_fixup = r128_mode_fixup,
+    .prepare = r128_mode_prepare,
+    .mode_set = r128_mode_set,
+    .commit = r128_mode_commit,
+    .detect = r128_detect,
+    .get_modes = r128_get_modes,
+    .destroy = r128_destroy,
+};
+
+void R128DPMSSetOn(xf86OutputPtr output)
+{
+    ScrnInfoPtr pScrn = output->scrn;
+    R128InfoPtr info = R128PTR(pScrn);
+    unsigned char *R128MMIO = info->MMIO;
+    R128OutputPrivatePtr r128_output = output->driver_private;
+    R128MonitorType MonType = r128_output->MonType;
+
+    switch(MonType) {
+    case MT_LCD:
+        OUTREGP(R128_LVDS_GEN_CNTL, R128_LVDS_BLON, ~R128_LVDS_BLON);
+        usleep(info->PanelPwrDly * 1000);
+        OUTREGP(R128_LVDS_GEN_CNTL, R128_LVDS_ON, ~R128_LVDS_ON);
+        break;
+    case MT_DFP:
+        OUTREGP(R128_FP_GEN_CNTL, (R128_FP_FPON | R128_FP_TDMS_EN), ~(R128_FP_FPON | R128_FP_TDMS_EN));
+        break;
+    default:
+        break;
+    }
+}
+
+void R128DPMSSetOff(xf86OutputPtr output)
+{
+    ScrnInfoPtr pScrn = output->scrn;
+    R128InfoPtr info = R128PTR(pScrn);
+    unsigned char *R128MMIO = info->MMIO;
+    R128OutputPrivatePtr r128_output = output->driver_private;
+    R128MonitorType MonType = r128_output->MonType;
+
+    switch(MonType) {
+    case MT_LCD:
+        OUTREGP(R128_LVDS_GEN_CNTL, 0, ~(R128_LVDS_BLON | R128_LVDS_ON));
+        break;
+    case MT_DFP:
+        OUTREGP(R128_FP_GEN_CNTL, 0, ~(R128_FP_FPON | R128_FP_TDMS_EN));
+        break;
+    default:
+        break;
+    }
+}
+
+static R128MonitorType R128DisplayDDCConnected(xf86OutputPtr output)
+{
+    ScrnInfoPtr pScrn = output->scrn;
+    R128InfoPtr info = R128PTR(pScrn);
+    unsigned char *R128MMIO = info->MMIO;
+    R128OutputPrivatePtr r128_output = output->driver_private;
+
+    R128MonitorType MonType = MT_NONE;
+    xf86MonPtr *MonInfo = &output->MonInfo;
+    CARD32 mask1, mask2;
+
+    if (r128_output->type == OUTPUT_LVDS) {
+        return MT_LCD;
+    } else if (r128_output->type == OUTPUT_VGA) {
+        mask1 = R128_GPIO_MONID_MASK_1 | R128_GPIO_MONID_MASK_3;
+        mask2 = R128_GPIO_MONID_A_1    | R128_GPIO_MONID_A_3;
+    } else {
+        mask1 = R128_GPIO_MONID_MASK_0 | R128_GPIO_MONID_MASK_3;
+        mask2 = R128_GPIO_MONID_A_0    | R128_GPIO_MONID_A_3;
+    }
+
+    if (r128_output->pI2CBus) {
+        R128I2CBusPtr pR128I2CBus = &(r128_output->ddc_i2c);
+	
+	/* XXX: Radeon does something here to appease old monitors. */
+	OUTREG(pR128I2CBus->ddc_reg, INREG(pR128I2CBus->ddc_reg)  |  mask1);
+	OUTREG(pR128I2CBus->ddc_reg, INREG(pR128I2CBus->ddc_reg)  & ~mask2);
+	*MonInfo = xf86DoEDID_DDC2(XF86_SCRN_ARG(pScrn), r128_output->pI2CBus);
+    } else {
+        xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "DDC2/I2C is not properly initialized\n");
+        return MT_NONE;
+    }
+
+    if (*MonInfo) {
+        if (r128_output->type == OUTPUT_VGA) {
+            MonType = MT_CRT;
+        } else {
+            if ((*MonInfo)->rawData[0x14] & 0x80)
+                MonType = MT_DFP;
+            else
+                MonType = MT_CRT;
+	}
+    }
+
+    return MonType;
+}
+
+static void R128ConnectorFindMonitor(ScrnInfoPtr pScrn, xf86OutputPtr output)
+{
+    R128OutputPrivatePtr r128_output = output->driver_private;
+
+    /* XXX: We should figure out how the DAC and BIOS scratch registers work
+     * to handle the non-DDC case. */
+    if (r128_output->MonType == MT_UNKNOWN)
+        r128_output->MonType = R128DisplayDDCConnected(output);
+}
+
+DisplayModePtr R128ProbeOutputModes(xf86OutputPtr output)
+{
+    ScrnInfoPtr pScrn = output->scrn;
+    R128OutputPrivatePtr r128_output = output->driver_private;
+    DisplayModePtr modes = NULL;
+    DisplayModePtr mode;
+    xf86MonPtr edid_mon;
+
+    if (r128_output->pI2CBus) {
+        edid_mon = xf86OutputGetEDID(output, r128_output->pI2CBus);
+        xf86OutputSetEDID(output, edid_mon);
+        modes = xf86OutputGetEDIDModes(output);
+    }
+
+    /* Letting this function return NULL would be a bad idea. With old cards
+     * like r128, users often specify a small resolution in order to get DRI.
+     * If the X server has to guess modes, the list it comes up with includes
+     * high resolutions.
+     */
+    if (!modes)
+        modes = xf86GetDefaultModes();
+
+    for (mode = modes; mode != NULL; mode = mode->next) {
+	xf86SetModeCrtc(mode, INTERLACE_HALVE_V);
+	if (mode->status == MODE_OK)
+            mode->status = R128ValidMode(XF86_SCRN_ARG(pScrn), mode, TRUE, MODECHECK_FINAL);
+    }
+
+    xf86ValidateModesUserConfig(pScrn, modes);
+    xf86PruneInvalidModes(pScrn, &modes, FALSE);
+
+    return modes;
+}
+
+static xf86OutputPtr R128OutputCreate(ScrnInfoPtr pScrn, const char *name, int i)
+{
+    char buf[32];
+    sprintf(buf, name, i);
+    return xf86OutputCreate(pScrn, &r128_output_funcs, buf);
+}
+
+static void R128I2CGetBits(I2CBusPtr b, int *Clock, int *data)
+{
+    ScrnInfoPtr   pScrn       = xf86Screens[b->scrnIndex];
+    R128InfoPtr   info        = R128PTR(pScrn);
+    unsigned long val;
+    unsigned char *R128MMIO   = info->MMIO;
+    R128I2CBusPtr pR128I2CBus = b->DriverPrivate.ptr;
+
+    /* Get the result. */
+    val = INREG(pR128I2CBus->ddc_reg);
+    *Clock = (val & pR128I2CBus->get_clk_mask)  != 0;
+    *data  = (val & pR128I2CBus->get_data_mask) != 0;
+}
+
+static void R128I2CPutBits(I2CBusPtr b, int Clock, int data)
+{
+    ScrnInfoPtr   pScrn       = xf86Screens[b->scrnIndex];
+    R128InfoPtr   info        = R128PTR(pScrn);
+    unsigned long val;
+    unsigned char *R128MMIO   = info->MMIO;
+    R128I2CBusPtr pR128I2CBus = b->DriverPrivate.ptr;
+
+    val = INREG(pR128I2CBus->ddc_reg)
+              & ~(CARD32)(pR128I2CBus->put_clk_mask | pR128I2CBus->put_data_mask);
+    val |= (Clock ? 0 : pR128I2CBus->put_clk_mask);
+    val |= (data  ? 0 : pR128I2CBus->put_data_mask);
+    OUTREG(pR128I2CBus->ddc_reg, val);
+}
+
+static Bool R128I2CInit(xf86OutputPtr output, I2CBusPtr *bus_ptr, char *name)
+{
+    ScrnInfoPtr pScrn = output->scrn;
+    R128OutputPrivatePtr r128_output = output->driver_private;
+    R128I2CBusPtr pR128I2CBus = &(r128_output->ddc_i2c);
+    I2CBusPtr pI2CBus;
+
+    pI2CBus = xf86CreateI2CBusRec();
+    if(!pI2CBus) return FALSE;
+
+    pI2CBus->BusName     = name;
+    pI2CBus->scrnIndex   = pScrn->scrnIndex;
+    pI2CBus->I2CPutBits  = R128I2CPutBits;
+    pI2CBus->I2CGetBits  = R128I2CGetBits;
+    pI2CBus->AcknTimeout = 5;
+
+    pI2CBus->DriverPrivate.ptr = (pointer)pR128I2CBus;
+    if (!xf86I2CBusInit(pI2CBus)) return FALSE;
+
+    *bus_ptr = pI2CBus;
+    return TRUE;
+}
+
+void R128SetOutputType(ScrnInfoPtr pScrn, R128OutputPrivatePtr r128_output)
+{
+    R128OutputType output = OUTPUT_NONE;
+
+    switch (r128_output->ConnectorType) {
+    case CONNECTOR_VGA:
+        output = OUTPUT_VGA;
+        break;
+    case CONNECTOR_LVDS:
+        output = OUTPUT_LVDS;
+        break;
+    case CONNECTOR_DVI_D:
+    case CONNECTOR_DVI_I:
+    case CONNECTOR_DVI_A:
+        output = OUTPUT_DVI;
+        break;
+    default:
+        output = OUTPUT_NONE;
+    }
+
+    r128_output->type = output;
+}
+
+void R128SetupGenericConnectors(ScrnInfoPtr pScrn)
+{
+    R128InfoPtr info = R128PTR(pScrn);
+
+    if (!info->HasCRTC2 && !info->isDFP) {
+        info->BiosConnector[0].ConnectorType = CONNECTOR_VGA;
+        info->BiosConnector[0].valid = TRUE;
+        return;
+    } else if (!info->HasCRTC2) {
+        info->BiosConnector[0].ConnectorType = CONNECTOR_DVI_D;
+	info->BiosConnector[0].valid = TRUE;
+	return;
+    }
+
+    info->BiosConnector[0].ConnectorType = CONNECTOR_LVDS;
+    info->BiosConnector[0].valid = TRUE;
+
+    info->BiosConnector[1].ConnectorType = CONNECTOR_VGA;
+    info->BiosConnector[1].valid = TRUE;
+}
+
+Bool R128SetupConnectors(ScrnInfoPtr pScrn)
+{
+    R128InfoPtr info = R128PTR(pScrn);
+    xf86OutputPtr output;
+    int num_vga = 0;
+    int num_dvi = 0;
+    int i;
+
+    for (i = 0; i < R128_MAX_BIOS_CONNECTOR; i++) {
+        info->BiosConnector[i].valid = FALSE;
+        info->BiosConnector[i].ConnectorType = CONNECTOR_NONE;
+    }
+
+    /* XXX: Can we make R128GetConnectorInfoFromBIOS()? */
+    R128SetupGenericConnectors(pScrn);
+
+    for (i = 0; i < R128_MAX_BIOS_CONNECTOR; i++) {
+        if (info->BiosConnector[i].valid) {
+            if ((info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_D) ||
+                (info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_I) ||
+                (info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_A)) {
+                num_dvi++;
+            } else if (info->BiosConnector[i].ConnectorType == CONNECTOR_VGA) {
+                num_vga++;
+            }
+        }
+    }
+
+    for (i = 0; i < R128_MAX_BIOS_CONNECTOR; i++) {
+        if (info->BiosConnector[i].valid) {
+	    R128I2CBusRec i2c;
+            R128OutputPrivatePtr r128_output;
+            R128ConnectorType conntype = info->BiosConnector[i].ConnectorType;
+
+            if (conntype == CONNECTOR_NONE)
+                continue;
+
+            r128_output = xnfcalloc(sizeof(R128OutputPrivateRec), 1);
+            if (!r128_output) return FALSE;
+
+            r128_output->MonType = MT_UNKNOWN;
+            r128_output->ConnectorType = conntype;
+            r128_output->num = i;
+
+            if (conntype == CONNECTOR_LVDS) {
+                output = R128OutputCreate(pScrn, "LVDS", 0);
+            } else if (conntype == CONNECTOR_VGA) {
+                output = R128OutputCreate(pScrn, "VGA-%d", --num_vga);
+            } else {
+                output = R128OutputCreate(pScrn, "DVI-%d", --num_dvi);
+            }
+
+            if (!output) return FALSE;
+            output->interlaceAllowed = TRUE;
+            output->doubleScanAllowed = TRUE;
+            output->driver_private = r128_output;
+	    output->possible_clones = 0;
+	    if (conntype == CONNECTOR_LVDS || !info->HasCRTC2)
+	        output->possible_crtcs = 1;
+	    else
+	        output->possible_crtcs = 2;
+
+            if (conntype != CONNECTOR_LVDS && info->DDC) {
+		i2c.ddc_reg      = R128_GPIO_MONID;
+		i2c.put_clk_mask = R128_GPIO_MONID_EN_3;
+		i2c.get_clk_mask = R128_GPIO_MONID_Y_3;
+		if (conntype == CONNECTOR_VGA) {
+		    i2c.put_data_mask = R128_GPIO_MONID_EN_1;
+		    i2c.get_data_mask = R128_GPIO_MONID_Y_1;
+		} else {
+		    i2c.put_data_mask = R128_GPIO_MONID_EN_0;
+		    i2c.get_data_mask = R128_GPIO_MONID_Y_0;
+		}
+		r128_output->ddc_i2c = i2c;
+		R128I2CInit(output, &r128_output->pI2CBus, output->name);
+	    }
+
+            R128SetOutputType(pScrn, r128_output);
+        }
+    }
+
+    return TRUE;
+}
diff --git a/src/r128_probe.c b/src/r128_probe.c
index 12e0c1c..e623bc9 100644
--- a/src/r128_probe.c
+++ b/src/r128_probe.c
@@ -48,7 +48,6 @@
 #include "xf86Resources.h"
 #endif
 
-#include "compat-api.h"
 #include "r128_probe.h"
 
 #ifndef XSERVER_LIBPCIACCESS
diff --git a/src/r128_probe.h b/src/r128_probe.h
index 7b55e71..f521a13 100644
--- a/src/r128_probe.h
+++ b/src/r128_probe.h
@@ -37,6 +37,15 @@
 #define _R128_PROBE_H_ 1
 
 #include "xf86str.h"
+#include "xf86DDC.h"
+#include "randrstr.h"
+#include "xf86Crtc.h"
+
+#include "compat-api.h"
+
+#ifdef USE_EXA
+#include "exa.h"
+#endif
 
 /* Chip definitions */
 #define PCI_VENDOR_ATI			0x1002
@@ -90,6 +99,73 @@
 
 extern DriverRec R128;
 
+typedef enum
+{
+    MT_UNKNOWN = -1,
+    MT_NONE    = 0,
+    MT_CRT     = 1,
+    MT_LCD     = 2,
+    MT_DFP     = 3,
+    MT_CTV     = 4,
+    MT_STV     = 5
+} R128MonitorType;
+
+typedef enum
+{
+    CONNECTOR_NONE,
+    CONNECTOR_VGA,
+    CONNECTOR_DVI_I,
+    CONNECTOR_DVI_D,
+    CONNECTOR_DVI_A,
+    CONNECTOR_LVDS
+} R128ConnectorType;
+
+typedef enum
+{
+    OUTPUT_NONE,
+    OUTPUT_VGA,
+    OUTPUT_DVI,
+    OUTPUT_LVDS
+} R128OutputType;
+
+typedef struct {
+    CARD32 ddc_reg;
+    CARD32 put_clk_mask;
+    CARD32 put_data_mask;
+    CARD32 get_clk_mask;
+    CARD32 get_data_mask;
+} R128I2CBusRec, *R128I2CBusPtr;
+
+typedef struct _R128CrtcPrivateRec {
+#ifdef HAVE_XAA_H
+    FBLinearPtr rotate_mem_xaa;
+#endif
+#ifdef USE_EXA
+    ExaOffscreenArea *rotate_mem_exa;
+#endif
+    int crtc_id;
+    CARD32 cursor_offset;
+    /* Lookup table values to be set when the CRTC is enabled */
+    CARD8 lut_r[256], lut_g[256], lut_b[256];
+} R128CrtcPrivateRec, *R128CrtcPrivatePtr;
+
+typedef struct {
+    R128ConnectorType ConnectorType;
+    Bool valid;
+} R128BIOSConnector;
+
+typedef struct _R128OutputPrivateRec {
+    int num;
+    R128OutputType type;
+    R128ConnectorType ConnectorType;
+    R128MonitorType MonType;
+    I2CBusPtr pI2CBus;
+    R128I2CBusRec ddc_i2c;
+} R128OutputPrivateRec, *R128OutputPrivatePtr;
+
+#define R128_MAX_CRTC 2
+#define R128_MAX_BIOS_CONNECTOR 2
+
 typedef struct
 {
     Bool IsDRIEnabled;
@@ -101,6 +177,9 @@ typedef struct
     Bool IsSecondaryRestored;
     Bool RestorePrimary;
 
+    xf86CrtcPtr pCrtc[R128_MAX_CRTC];
+    R128CrtcPrivatePtr Controller[R128_MAX_CRTC];
+
     ScrnInfoPtr pSecondaryScrn;    
     ScrnInfoPtr pPrimaryScrn;
 } R128EntRec, *R128EntPtr;
diff --git a/src/r128_video.c b/src/r128_video.c
index dccaa42..6439a24 100644
--- a/src/r128_video.c
+++ b/src/r128_video.c
@@ -226,7 +226,7 @@ R128SetupImageVideo(ScreenPtr pScreen)
 	return NULL;
 
     adapt->type = XvWindowMask | XvInputMask | XvImageMask;
-    adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
+    adapt->flags = VIDEO_OVERLAID_IMAGES /*| VIDEO_CLIP_TO_VIEWPORT*/;
     adapt->name = "ATI Rage128 Video Overlay";
     adapt->nEncodings = 1;
     adapt->pEncodings = &DummyEncoding;
@@ -849,6 +849,13 @@ R128PutImage(
    int top, left, npixels, nlines;
    BoxRec dstBox;
    CARD32 tmp;
+
+   /* Currently, the video is only visible on the first monitor.
+    * In the future we could try to make this smarter, or just implement
+    * textured video. */
+   xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+   xf86CrtcPtr crtc = xf86_config->crtc[0];
+
 #if X_BYTE_ORDER == X_BIG_ENDIAN
    unsigned char *R128MMIO = info->MMIO;
    CARD32 config_cntl = INREG(R128_CONFIG_CNTL);
@@ -893,10 +900,10 @@ R128PutImage(
 			     clipBoxes, width, height))
 	return Success;
 
-   dstBox.x1 -= pScrn->frameX0;
-   dstBox.x2 -= pScrn->frameX0;
-   dstBox.y1 -= pScrn->frameY0;
-   dstBox.y2 -= pScrn->frameY0;
+   dstBox.x1 -= crtc->x;
+   dstBox.x2 -= crtc->x;
+   dstBox.y1 -= crtc->y;
+   dstBox.y2 -= crtc->y;
 
    switch(id) {
    case FOURCC_YV12:
-- 
1.9.3



More information about the xorg-driver-ati mailing list